GCC-3.4.6源代码学习笔记 (105)

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

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 }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值