5.12.3.2.1.1.3.6.1. 退出嵌套类
进一步的,当“消化”掉了类末尾的“ ; ”的时候,它表示我们将要退出类的作用域,并重新进入包含它的作用域。这个操作由 5257 行的 popclass 执行。
5564 void
5565 popclass (void) in class.c
5566 {
5567 poplevel_class ();
5568 pop_class_decls ();
5569
5570 current_class_depth --;
5571 current_class_name = current_class_stack [current_class_depth ].name;
5572 current_class_type = current_class_stack [current_class_depth ].type;
5573 current_access_specifier = current_class_stack [current_class_depth ].access;
5574 if (current_class_stack [current_class_depth ].names_used)
5575 splay_tree_delete (current_class_stack [current_class_depth ].names_used);
5576 }
在 poplevel_class 中,看到当我们从类栈中退出时, previous_class_type 及 previous_class_values 缓存了最顶层的类,因为它可能会被 pushclass 重用。不过,对于非顶层的类,缓存它们并不合适,只能是释放在该类中声明的标识符的关系。考虑以下的例子:
// Global scope
int j;
class A
{
public :
int j;
typedef int inner_type;
class B {
int j;
inner_type k; // inner_type is A:: inner_type
public :
int get_j() const {
return j; // should return B::j
}
inner_type get_k() const { return k; }
};
int get_j() const {
return j; // should return A::j
}
};
int get_j() {
return j; // should return ::j
}
变量 j 声明在全局名字空间,类 A 及类 B 里。但是,在前端中,用于 j 的标识符节点必须是唯一的,因此这 3 个定义应该绑定在这个唯一的节点。然而,根据名字查找的规则,所使用的 j 可以根据当前绑定域来确定。例如,在上面例子中,在类 B 中查找 inner_type 将最终在类 A 中查找出定义。可是通常这样的查找相当的复杂。而如果在进入一个作用域时,我们更新标识符的定义,许多查找是可以避免的。这就是域 IDENTIFIER_CLASS_VALUE 的目的——记录标识符当前的定义。
2581 void
2582 poplevel_class (void) in name-lookup.c
2583 {
2584 struct cp_binding_level *level = class_binding_level;
2585 tree shadowed;
2586
2587 timevar_push (TV_NAME_LOOKUP);
2588 my_friendly_assert (level != 0, 354);
2589
2590 /* If we're leaving a toplevel class, don't bother to do the setting
2591 of IDENTIFIER_CLASS_VALUE to NULL_TREE, since first of all this slot
2592 shouldn't even be used when current_class_type isn't set, and second,
2593 if we don't touch it here, we're able to use the cache effect if the
2594 next time we're entering a class scope, it is the same class. */
2595 if (current_class_depth != 1)
2596 {
2597 struct cp_binding_level* b;
2598
2599 /* Clear out our IDENTIFIER_CLASS_VALUEs. */
2600 for (shadowed = level->class_shadowed;
2601 shadowed;
2602 shadowed = TREE_CHAIN (shadowed))
2603 IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (shadowed)) = NULL_TREE;
2604
2605 /* Find the next enclosing class, and recreate
2606 IDENTIFIER_CLASS_VALUEs appropriate for that class. */
2607 b = level->level_chain;
2608 while (b && b->kind != sk_class)
2609 b = b->level_chain;
2610
2611 if (b)
2612 for (shadowed = b->class_shadowed;
2613 shadowed;
2614 shadowed = TREE_CHAIN (shadowed))
2615 {
2616 cxx_binding *binding;
2617
2618 binding = IDENTIFIER_BINDING (TREE_PURPOSE (shadowed));
2619 while (binding && binding->scope != b)
2620 binding = binding->previous;
2621
2622 if (binding)
2623 IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (shadowed))
2624 = binding->value;
2625 }
2626 }
2627 else
2628 /* Remember to save what IDENTIFIER's were bound in this scope so we
2629 can recover from cache misses. */
2630 {
2631 previous_class_type = current_class_type ;
2632 previous_class_values = class_binding_level->class_shadowed;
2633 }
2634 for (shadowed = level->type_shadowed;
2635 shadowed;
2636 shadowed = TREE_CHAIN (shadowed))
2637 SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (shadowed), TREE_VALUE (shadowed));
2638
2639 /* Remove the bindings for all of the class-level declarations. */
2640 for (shadowed = level->class_shadowed;
2641 shadowed;
2642 shadowed = TREE_CHAIN (shadowed))
2643 pop_binding (TREE_PURPOSE (shadowed), TREE_TYPE (shadowed));
2644
2645 /* Now, pop out of the binding level which we created up in the
2646 `pushlevel_class' routine. */
2647 if (ENABLE_SCOPE_CHECKING)
2648 is_class_level = 1;
2649
2650 leave_scope ();
2651 timevar_pop (TV_NAME_LOOKUP);
2652 }
显然。上面从 2600 到 2603 行,清除在类中声明的标识符伴随的定义 / 声明符。进一步的,如果类里的这个标识符屏蔽了外部同名的标识符,类节点的 type_shadowed 域将记录被屏蔽的定义 / 声明符,在上面 2643 行的 FOR 循环中恢复这些被屏蔽的定义。
因为从类域退出,其中声明的标识符在当前域不再可见,除非使用 nested-name-specifier ,由 pop_binding 移除标识符中导向该类的 cxx_binding 节点,它是 push_binding 的相反的过程。
376 void
377 pop_binding (tree id, tree decl) in name-lookup.c
378 {
379 cxx_binding *binding;
380
381 if (id == NULL_TREE)
382 /* It's easiest to write the loops that call this function without
383 checking whether or not the entities involved have names. We
384 get here for such an entity. */
385 return ;
386
387 /* Get the innermost binding for ID. */
388 binding = IDENTIFIER_BINDING (id);
389
390 /* The name should be bound. */
391 my_friendly_assert (binding != NULL, 0);
392
393 /* The DECL will be either the ordinary binding or the type
394 binding for this identifier. Remove that binding. */
395 if (binding->value == decl)
396 binding->value = NULL_TREE;
397 else if (binding->type == decl)
398 binding->type = NULL_TREE;
399 else
400 abort ();
401
402 if (!binding->value && !binding->type)
403 {
404 /* We're completely done with the innermost binding for this
405 identifier. Unhook it from the list of bindings. */
406 IDENTIFIER_BINDING (id) = binding->previous;
407
408 /* Add it to the free list. */
409 cxx_binding_free (binding);
410 }
411 }
注意到最里层的绑定对象永远位于标识符 bindings 域链表的头部,这个绑定对象由 388 行的 IDENTIFIER_BINDING 获得。
同样当进入该类时,在其派生网络中缓存类所声明的域可以加速在指定类里的查找,尤其对于大的类。这由 pushclass 中的 push_class_decls 完成,因此当离开时,缓存的数据将由 pop_class_decls 从 search_stack 中释放。
2323 void
2324 pop_class_decls (void) in search.c
2325 {
2326 /* We haven't pushed a search level when dealing with cached classes,
2327 so we'd better not try to pop it. */
2328 if (search_stack )
2329 search_stack = pop_search_level (search_stack );
2330 }
更进一步的,代表这个类作用域的 cxx_scope 对象也应该从这棵以全局名字空间作用域作为根节点的中间树中移除,因为这个类的成员在全局名字空间中不可见。如果前端没有开启 ENABLE_SCOPE_CHECKING ,这个释放的 cxx_scopes 对象在 leave_scope 中被链入 free_binding_level ,并且能够在 begin_scope 中重用。如果这个开关没有打开, leave_scope 将留下如下的 free_binding_level 。
图 85 :由 leave_scope 释放的 cxx_scope
在由 finish_struct 完成解析后,如果该类是通过 elaberator-type-specifier 指定的,例如:“ A::B::f ”,在 11926 行 pop_p 指向域“ A::B:: ”,这个域已经有了相应的 cxx_scope 对象,并且链入了以全局名字空间作用域作为根节点的中间树中。当遇到结尾的“ ; ”,这意味着马上要退出当前的作用域。那么作用域 A 及 B ,相似地要出树里移除。
我们已经看到并且缓存了结构体“ Lock ”的内联函数的定义,但是它们还没有得到处理。不过,考虑以下的例子:
struct A {
struct B { void f() { sizeof (A); } };
};
在 B 定义的末尾展开内联函数 f 是不可行的。合适的地点是在 A 的末尾——这个最外层的类。这也是为什么所有的内联函数,不管它们嫡属于哪个类,都缓存到 parser 的 unparsed_functions_queues 里。
因此在 cp_parser_class_specifier 的剩余代码中,仅是从访问控制栈中弹出用于结构体“ Lock ”的访问控制块。
cp_parser_class_specifier (continue)
11928 /* If this class is not itself within the scope of another class,
11929 then we need to parse the bodies of all of the queued function
11930 definitions. Note that the queued functions defined in a class
11931 are not always processed immediately following the
11932 class-specifier for that class. Consider:
11933
11934 struct A {
11935 struct B { void f() { sizeof (A); } };
11936 };
11937
11938 If `f' were processed before the processing of `A' were
11939 completed, there would be no way to compute the size of `A'.
11940 Note that the nesting we are interested in here is lexical --
11941 not the semantic nesting given by TYPE_CONTEXT. In particular,
11942 for:
11943
11944 struct A { struct B; };
11945 struct A::B { void f() { } };
11946
11947 there is no need to delay the parsing of `A::B::f'. */
11948 if (--parser->num_classes_being_defined == 0)
11949 {
…
11996 }
11997
11998 /* Put back any saved access checks. */
11999 pop_deferring_access_checks ();
12000
12001 /* Restore the count of active template-parameter-lists. */
12002 parser->num_template_parameter_lists
12003 = saved_num_template_parameter_lists;
12004
12005 return type;
12006 }
那么在最后,中间树看起来如下,上面返回的 type 指向其中的 RECORD_TYPE 节点。
( 点此打开 )
图 86 :退出结构体 Lock 的时刻
5.12.3.2.1.1.3.6.1. 完成方法成员的解析
从 cp_parser_class_specifier 返回到 cp_parser_type_specifier , type_spec 此时指向对应的 RECORD_TYPE 节点,而 declares_class_or_enum 被设置为 2 ,如果为它提供了内存。接着回到 cp_parser_decl_specifier_seq ,注意到结尾的“ ; ”并没有被“消化”。因此函数立即结束(使用 GCC 时,如果在类定义中缺少了“ ; ”,你可能会得到许多错误,因为 cp_parser_decl_specifier_seq 继续作为 decl-specifier-seq 解析),作为结果,对 RECORD_TYPE 节点的引用被保存在 decl_specs 并返回。
那么回到 cp_parser_member_declaration ,下面的代码会得到执行。
cp_parser_member_declaration (continue)
12513 if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
12514 {
12515 /* If there was no decl-specifier-seq, and the next token is a
12516 `;', then we have something like:
12517
12518 struct S { ; };
12519
12520 [class.mem]
12521
12522 Each member-declaration shall declare at least one member
12523 name of the class. */
12524 if (!decl_specifiers)
12525 {
12526 if (pedantic )
12527 pedwarn ("extra semicolon");
12528 }
12529 else
12530 {
12531 tree type;
12532
12533 /* See if this declaration is a friend. */
12534 friend_p = cp_parser_friend_p (decl_specifiers);
12535 /* If there were decl-specifiers, check to see if there was
12536 a class-declaration. */
12537 type = check_tag_decl (decl_specifiers);
12538 /* Nested classes have already been added to the class, but
12539 a `friend' needs to be explicitly registered. */
12540 if (friend_p)
12541 {
…
12581 }
12582 /* If there is no TYPE, an error message will already have
12583 been issued. */
12584 else if (!type)
12585 ;
12586 /* An anonymous aggregate has to be handled specially; such
12587 a declaration really declares a data member (with a
12588 particular type), as opposed to a nested class. */
12589 else if (ANON_AGGR_TYPE_P (type))
12590 {
12591 /* Remove constructors and such from TYPE, now that we
12592 know it is an anonymous aggregate. */
12593 fixup_anonymous_aggr (type);
12594 /* And make the corresponding data member. */
12595 decl = build_decl (FIELD_DECL, NULL_TREE, type);
12596 /* Add it to the class. */
12597 finish_member_declaration (decl);
12598 }
12599 else
12600 cp_parser_check_access_in_redeclaration (TYPE_NAME (type));
12601 }
12602 }
…
12814 cp_parser_require (parser, CPP_SEMICOLON, "`;'");
12815 }
来到这里,整个 decl-specifier-seq 已经被解析了,对它我们现在有更清晰的看法。是时候来挑剔其中自相矛盾的部分了,比如:在声明中使用了 1 个以上的类型。
3474 tree
3475 check_tag_decl (tree declspecs) in decl.c
3476 {
3477 int found_type = 0;
3478 int saw_friend = 0;
3479 int saw_typedef = 0;
3480 tree ob_modifier = NULL_TREE;
3481 tree link;
3482 /* If a class, struct, or enum type is declared by the DECLSPECS
3483 (i.e, if a class-specifier, enum-specifier, or non-typename
3484 elaborated-type-specifier appears in the DECLSPECS),
3485 DECLARED_TYPE is set to the corresponding type. */
3486 tree declared_type = NULL_TREE;
3487 bool error_p = false;
3488
3489 for (link = declspecs; link; link = TREE_CHAIN (link))
3490 {
3491 tree value = TREE_VALUE (link);
3492
3493 if (TYPE_P (value) || TREE_CODE (value) == TYPE_DECL
3494 || (TREE_CODE (value) == IDENTIFIER_NODE
3495 && is_typename_at_global_scope (value)))
3496 {
3497 ++found_type;
3498
3499 if (found_type == 2 && TREE_CODE (value) == IDENTIFIER_NODE)
3500 {
3501 if (! in_system_header )
3502 pedwarn ("redeclaration of C++ built-in type `%T'", value);
3503 return NULL_TREE;
3504 }
3505
3506 if (TYPE_P (value)
3507 && ((TREE_CODE (value) != TYPENAME_TYPE && IS_AGGR_TYPE (value))
3508 || TREE_CODE (value) == ENUMERAL_TYPE))
3509 {
3510 my_friendly_assert (TYPE_MAIN_DECL (value) != NULL_TREE, 261);
3511 declared_type = value;
3512 }
3513 }
3514 else if (value == ridpointers [(int) RID_TYPEDEF])
3515 saw_typedef = 1;
3516 else if (value == ridpointers [(int) RID_FRIEND])
3517 {
3518 if (current_class_type == NULL_TREE
3519 || current_scope () != current_class_type )
3520 ob_modifier = value;
3521 else
3522 saw_friend = 1;
3523 }
3524 else if (value == ridpointers [(int) RID_STATIC]
3525 || value == ridpointers [(int) RID_EXTERN]
3526 || value == ridpointers [(int) RID_AUTO]
3527 || value == ridpointers [(int) RID_REGISTER]
3528 || value == ridpointers [(int) RID_INLINE]
3529 || value == ridpointers [(int) RID_VIRTUAL]
3530 || value == ridpointers [(int) RID_CONST]
3531 || value == ridpointers [(int) RID_VOLATILE]
3532 || value == ridpointers [(int) RID_EXPLICIT]
3533 || value == ridpointers [(int) RID_THREAD])
3534 ob_modifier = value;
3535 else if (value == error_mark_node)
3536 error_p = true;
3537 }
3538
3539 if (found_type > 1)
3540 error ("multiple types in one declaration");
3541
3542 if (declared_type == NULL_TREE && ! saw_friend && !error_p)
3543 pedwarn ("declaration does not declare anything");
3544 /* Check for an anonymous union. */
3545 else if (declared_type && IS_AGGR_TYPE_CODE (TREE_CODE (declared_type))
3546 && TYPE_ANONYMOUS_P (declared_type))
3547 {
3548 /* 7/3 In a simple-declaration, the optional init-declarator-list
3549 can be omitted only when declaring a class (clause 9) or
3550 enumeration (7.2), that is, when the decl-specifier-seq contains
3551 either a class-specifier, an elaborated-type-specifier with
3552 a class-key (9.1), or an enum-specifier. In these cases and
3553 whenever a class-specifier or enum-specifier is present in the
3554 decl-specifier-seq, the identifiers in these specifiers are among
3555 the names being declared by the declaration (as class-name,
3556 enum-names, or enumerators, depending on the syntax). In such
3557 cases, and except for the declaration of an unnamed bit-field (9.6),
3558 the decl-specifier-seq shall introduce one or more names into the
3559 program, or shall redeclare a name introduced by a previous
3560 declaration. [Example:
3561 enum { }; // ill-formed
3562 typedef class { }; // ill-formed
3563 --end example] */
3564 if (saw_typedef)
3565 {
3566 error ("missing type-name in typedef-declaration");
3567 return NULL_TREE;
3568 }
3569 /* Anonymous unions are objects, so they can have specifiers. */ ;
3570 SET_ANON_AGGR_TYPE_P (declared_type);
3571
3572 if (TREE_CODE (declared_type) != UNION_TYPE && pedantic
3573 && !in_system_header )
3574 pedwarn ("ISO C++ prohibits anonymous structs");
3575 }
3576
3577 else if (ob_modifier)
3578 {
3579 if (ob_modifier == ridpointers [(int) RID_INLINE]
3580 || ob_modifier == ridpointers [(int) RID_VIRTUAL])
3581 error ("`%D' can only be specified for functions", ob_modifier);
3582 else if (ob_modifier == ridpointers [(int) RID_FRIEND])
3583 error ("`%D' can only be specified inside a class", ob_modifier);
3584 else if (ob_modifier == ridpointers [(int) RID_EXPLICIT])
3585 error ("`%D' can only be specified for constructors",
3586 ob_modifier);
3587 else
3588 error ("`%D' can only be specified for objects and functions",
3589 ob_modifier);
3590 }
3591
3592 return declared_type;
3593 }
注意如果关键字的使用合法,在此处其含义应该已经反映在声明符节点的标记中,不应该还有表示这些关键字的节点。一旦出现,即意味着错误,由 3577 行的代码块处理。无论如何,该函数返回代表所声明类型的节点。对于由 check_tag_decl 返回的类型,如果它不是匿名类,需要检查 decl 是否使用了与原声明不同的访问说明符来重新声明。这适用于嵌套类及嵌套类模板,并由下面的函数执行。
15282 static void cp_parser_check_access_in_redeclaration (tree decl) in parser.c
15283 {
15284 if (!CLASS_TYPE_P (TREE_TYPE (decl)))
15285 return ;
15286
15287 if ((TREE_PRIVATE (decl)
15288 != (current_access_specifier == access_private_node))
15289 || (TREE_PROTECTED (decl)
15290 != (current_access_specifier == access_protected_node)))
15291 error ("%D redeclared with different access", decl);
15292 }