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

来源:互联网 发布:思科网络认证考试 编辑:程序博客网 时间:2024/05/20 02:30

5.12.3.2.1.1.2.1.    构建对自己的引用

2082行,根据ISO-IEC-14882-2003的要求,函数build_self_reference构建了一个对自己的伪引用,使得Derived::Base(及A::A)能够工作

“类名亦加入类作用域本身。出于访问检查的目的,加入的类名被视为公有成员名。”

 

6290 void

6291 build_self_reference (void)                                                                         in class.c

6292 {

6293   tree name = constructor_name (current_class_type);

6294   tree value = build_lang_decl (TYPE_DECL, name, current_class_type);

6295   tree saved_cas;

6296

6297   DECL_NONLOCAL (value) = 1;

6298   DECL_CONTEXT (value) = current_class_type;

6299   DECL_ARTIFICIAL (value) = 1;

6300   SET_DECL_SELF_REFERENCE_P (value);

6301

6302   if (processing_template_decl)

6303     value = push_template_decl (value);

6304

6305   saved_cas = current_access_specifier;

6306   current_access_specifier = access_public_node;

6307   finish_member_declaration (value);

6308   current_access_specifier = saved_cas;

6309 }

 

constructor_name负责为类获取正确的名字。它需要考虑模板特化的命名。

 

1792 tree

1793 constructor_name (tree type)                                                               in name-lookup.c

1794 {

1795   tree name;

1796   name = constructor_name_full (type);

1797   if (IDENTIFIER_TEMPLATE (name))

1798     name = IDENTIFIER_TEMPLATE (name);

1799   return name;

1800 }

 

这里我们把名字“SingleThreaded”给予这个类,constructor_name_full把对应的标识符节点返回给我们。

 

1777 tree

1778 constructor_name_full (tree type)                                                         in name-lookup.c

1779 {

1780   type = TYPE_MAIN_VARIANT (type);

1781   if (CLASS_TYPE_P (type) && TYPE_WAS_ANONYMOUS (type)

1782       && TYPE_HAS_CONSTRUCTOR (type))

1783     return DECL_NAME (OVL_CURRENT (CLASSTYPE_CONSTRUCTORS (type)));

1784   else

1785     return TYPE_IDENTIFIER (type);

1786 }

 

看到在上面6306行,公有的访问属性被赋予了这个引用,然后它被作为类成员加入。注意到参数decl包含了build_lang_decl由分配的lang_specific节点,这使得DECL_LANG_SPECIFIC返回非空值。而它的DECL_CONTEXT域表示其声明所在的作用域。这里在6298行,这是它自己本身。

5.12.3.2.1.1.2.2.    为自己的引用构建TEMPLATE_DECL

作为一个模板类,在build_self_reference6302行,processing_template_parms是非0值,表示模板声明尚未结束。

 

3048 tree

3049 push_template_decl (tree decl)                                                                           in pt.c

3050 {

3051   return push_template_decl_real (decl, 0);

3052 }

 

这次当进入push_template_decl_real时,下面获取的ctx是类模板的RECORD_TYPE,它在build_self_reference中被设为该TYPE_DECL的上下文。 而现在current_binding_level 指向类的作用域,因而下面的primary0

 

2770 tree

2771 push_template_decl_real (tree decl, int is_friend)                                                in pt.c

2772 {

2773   tree tmpl;

2774   tree args;

2775   tree info;

2776   tree ctx;

2777   int primary;

2778   int is_partial;

2779   int new_template_p = 0;

2780

2781   /* See if this is a partial specialization.  */

2782   is_partial = (DECL_IMPLICIT_TYPEDEF_P (decl)

2783        && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE

2784        && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)));

2785

2786   is_friend |= (TREE_CODE (decl) == FUNCTION_DECL && DECL_FRIEND_P (decl));

2787

2788   if (is_friend)

2789     /* For a friend, we want the context of the friend function, not

2790       the type of which it is a friend.  */

2791     ctx = DECL_CONTEXT (decl);

2792   else if (CP_DECL_CONTEXT (decl)

2793         && TREE_CODE (CP_DECL_CONTEXT (decl)) != NAMESPACE_DECL)

2794     /* In the case of a virtual function, we want the class in which

2795       it is defined.  */

2796     ctx = CP_DECL_CONTEXT (decl);

2797   else

2798     /* Otherwise, if we're currently defining some class, the DECL

2799       is assumed to be a member of the class.  */

2800     ctx = current_scope ();

2801

2802   if (ctx && TREE_CODE (ctx) == NAMESPACE_DECL)

2803     ctx = NULL_TREE;

2804

2805   if (!DECL_CONTEXT (decl))

2806     DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);

2807

2808   /* See if this is a primary template.  */

2809   primary = template_parm_scope_p ();

2810

2811   if (primary)

2812   {

        

2852   }

2853

2854   /* Check to see that the rules regarding the use of default

2855     arguments are not being violated.  */

2856   check_default_tmpl_args (decl, current_template_parms,

2857                        primary, is_partial);

2858

2859   if (is_partial)

2860     return process_partial_specialization (decl);

2861

2862   args = current_template_args ();

2863

2864   if (!ctx

2865       || TREE_CODE (ctx) == FUNCTION_DECL

2866       || (CLASS_TYPE_P (ctx) && TYPE_BEING_DEFINED (ctx))

2867       || (is_friend && !DECL_TEMPLATE_INFO (decl)))

2868   {

2869     if (DECL_LANG_SPECIFIC (decl)

2870          && DECL_TEMPLATE_INFO (decl)

2871         && DECL_TI_TEMPLATE (decl))

2872       tmpl = DECL_TI_TEMPLATE (decl);

2873     /* If DECL is a TYPE_DECL for a class-template, then there won't

2874       be DECL_LANG_SPECIFIC. The information equivalent to

2875       DECL_TEMPLATE_INFO is found in TYPE_TEMPLATE_INFO instead.  */

2876     else if (DECL_IMPLICIT_TYPEDEF_P (decl)

2877           && TYPE_TEMPLATE_INFO (TREE_TYPE (decl))

2878           && TYPE_TI_TEMPLATE (TREE_TYPE (decl)))

2879     {

          

2888     }

2889     else

2890     {

2891       tmpl = build_template_decl (decl, current_template_parms);

2892       new_template_p = 1;

2893

2894       if (DECL_LANG_SPECIFIC (decl)

2895          && DECL_TEMPLATE_SPECIALIZATION (decl))

2896       {

             

2902       }

2903     }

2904   }

      

2997   DECL_TEMPLATE_RESULT (tmpl) = decl;

2998   TREE_TYPE (tmpl) = TREE_TYPE (decl);

      

3031   info = tree_cons (tmpl, args, NULL_TREE);

3032

3033   if (DECL_IMPLICIT_TYPEDEF_P (decl))

3034   {

        

3041   }

3042   else if (DECL_LANG_SPECIFIC (decl))

3043     DECL_TEMPLATE_INFO (decl) = info;

3044

3045   return DECL_TEMPLATE_RESULT (tmpl);

3046 }

 

该类的定义正在被处理,因此上面2866行的条件满足;但因为decl是新创建的,其DECL_TEMPLATE_INFODECL_IMPLICIT_TYPEDEF_P项还没设置,在2889行的ELSE 块被执行以创建另一个TEMPLATE_DECL

 

点此打开

60:创建对自己的引用—第一步

5.12.3.2.1.1.2.3.    作为成员加入类域

作为最后一步,这个对自己的引用被加入为类成员,成员与类之间的关系将被设立。

 

2089 void

2090 finish_member_declaration (tree decl)                                                         in semantics.c

2091 {

       

2103   /* Set up access control for DECL.  */

2104   TREE_PRIVATE (decl)

2105     = (current_access_specifier == access_private_node);

2106   TREE_PROTECTED (decl)

2107     = (current_access_specifier == access_protected_node);

2108   if (TREE_CODE (decl) == TEMPLATE_DECL)

2109   {

2110     TREE_PRIVATE (DECL_TEMPLATE_RESULT (decl)) = TREE_PRIVATE (decl);

2111     TREE_PROTECTED (DECL_TEMPLATE_RESULT (decl)) = TREE_PROTECTED (decl);

2112   }

2113

2114   /* Mark the DECL as a member of the current class.  */

2115   DECL_CONTEXT (decl) = current_class_type;

2116

2117   /* [dcl.link]

2118

2119      A C language linkage is ignored for the names of class members

2120      and the member function type of class member functions.  */

2121   if (DECL_LANG_SPECIFIC (decl) && DECL_LANGUAGE (decl) == lang_c)

2122     SET_DECL_LANGUAGE (decl, lang_cplusplus);

2123

2124   /* Put functions on the TYPE_METHODS list and everything else on the

2125     TYPE_FIELDS list. Note that these are built up in reverse order.

2126    We reverse them (to obtain declaration order) in finish_struct.  */

2127   if (TREE_CODE (decl) == FUNCTION_DECL

2128       || DECL_FUNCTION_TEMPLATE_P (decl))

2129   {

         

2139   }

2140   /* Enter the DECL into the scope of the class.  */

2141   else if ((TREE_CODE (decl) == USING_DECL && TREE_TYPE (decl))

2142          || pushdecl_class_level (decl))

2143   {

2144     /* All TYPE_DECLs go at the end of TYPE_FIELDS. Ordinary fields

2145       go at the beginning. The reason is that lookup_field_1

2146       searches the list in order, and we want a field name to

2147       override a type name so that the "struct stat hack" will

2148       work. In particular:

2149

2150         struct S { enum E { }; int E } s;

2151         s.E = 3;

2152

2153       is valid. In addition, the FIELD_DECLs must be maintained in

2154       declaration order so that class layout works as expected.

2155       However, we don't need that order until class layout, so we

2156       save a little time by putting FIELD_DECLs on in reverse order

2157       here, and then reversing them in finish_struct_1. (We could

2158       also keep a pointer to the correct insertion points in the

2159       list.)  */

2160

2161     if (TREE_CODE (decl) == TYPE_DECL)

2162       TYPE_FIELDS (current_class_type)

2163           = chainon (TYPE_FIELDS (current_class_type), decl);

2164     else

2165     {

2166       TREE_CHAIN (decl) = TYPE_FIELDS (current_class_type);

2167       TYPE_FIELDS (current_class_type) = decl;

2168     }

2169

2170     maybe_add_class_template_decl_list (current_class_type, decl,

2171                                    /*friend_p=*/0);

2172   }

2173 }

 

对自己的引用不是一个方法的声明,也不是using声明,因此它需要由在2142行的pushdecl_class_level加入为成员。在27482763之间的代码处理匿名union,根据ISO-IEC-14882-2003,应该遵从以下规则:

一个union具有形式

union { member-specification } ;

它定义了一个匿名类型的匿名对象。一个匿名unionmember-specification只能定义非静态数据成员(嵌套类型及函数不能被声明在一个匿名union里)。一个匿名union里的成员的名字,必须区别于该匿名union声明所在作用域中的,其他项的名字。出于名字查找的目的,在匿名union的定义后,该匿名union的成员被视为定义在该匿名union声明所在作用域中。例如:

void f()

{

union { int a; char* p; };

a = 1;

// ...

p = "Jennifer";

// ...

}

在这里ap就像普通(非成员)变量那样使用,不过因为它们是union的成员,它们拥有相同的地址。

声明在一个具名名字空间或全局名字空间的匿名union,应该被声明为静态。声明在一个块作用域(block scope)的匿名union应该被声明具有,作为一个块局部变量所允许的,储存类别(storage class),或不指定储存类别。在一个类域中声明的匿名union不允许使用存储类别。一个匿名union不能具有privateprotected成员(条款11)。一个匿名union也不能具有函数成员。

 

 

2729 bool

2730 pushdecl_class_level (tree x)                                                               in name-lookup.c

2731 {

2732   tree name;

2733   bool is_valid = true;

2734

2735   timevar_push (TV_NAME_LOOKUP);

2736   /* Get the name of X.  */

2737   if (TREE_CODE (x) == OVERLOAD)

2738     name = DECL_NAME (get_first_fn (x));

2739   else

2740     name = DECL_NAME (x);

2741

2742   if (name)

2743   {

2744     is_valid = push_class_level_binding (name, x);

2745     if (TREE_CODE (x) == TYPE_DECL)

2746       set_identifier_type_value (name, x);

2747   }

2748   else if (ANON_AGGR_TYPE_P (TREE_TYPE (x)))

2749   {

        

2763   }

2764   timevar_pop (TV_NAME_LOOKUP);

2765

2766   return is_valid;

2767 }

 

使用下面的函数,我们尝试把具有名字name的声明x加入当前类域中。这里xname都来自对自己的引用所生成的TYPE_DECL节点。

 

2772 bool

2773 push_class_level_binding (tree name, tree x)                                         in name-lookup.c

2774 {

2775   cxx_binding *binding;

2776

2777   timevar_push (TV_NAME_LOOKUP);

2778   /* The class_binding_level will be NULL if x is a template

2779     parameter name in a member template.  */

2780   if (!class_binding_level)

2781     POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, true);

2782

2783   /* Make sure that this new member does not have the same name

2784     as a template parameter.  */

2785   if (TYPE_BEING_DEFINED (current_class_type))

2786     check_template_shadow (x);

2787

2788   /* [class.mem]

2789

2790      If T is the name of a class, then each of the following shall

2791      have a name different from T:

2792

2793      -- every static data member of class T;

2794

2795      -- every member of class T that is itself a type;

2796

2797      -- every enumerator of every member of class T that is an

2798        enumerated type;

2799

2800      -- every member of every anonymous union that is a member of

2801        class T.

2802

2803      (Non-static data members were also forbidden to have the same

2804      name as T until TC1.)  */

2805   if ((TREE_CODE (x) == VAR_DECL

2806        || TREE_CODE (x) == CONST_DECL

2807        || (TREE_CODE (x) == TYPE_DECL

2808          && !DECL_SELF_REFERENCE_P (x))

2809        || DECL_CLASS_TEMPLATE_P (x)

2810        /* A data member of an anonymous union.  */

2811        || (TREE_CODE (x) == FIELD_DECL

2812          && DECL_CONTEXT (x) != current_class_type))

2813          && DECL_NAME (x) == constructor_name (current_class_type))

2814   {

        

2822   }

 

作为一个模板类,其类定义绑定在作用域sk_template_parms中(在图SingleThreaded为当前作用域,我们可以看到类域的对象的level_chain指向sk_template_parms,不过sk_template_parmsnames域并不像通常的作用域,它没有包括该类的定义,这体现了模板参数与类定义间的特殊关系)。在sk_template_parms作用域内,是模板参数;显然,如果在类中我们声明一个同名的成员,它将屏蔽相应的模板参数。

语法规定,模板参数不能在其作用域内被重新声明(包括嵌套作用域中)。函数check_template_shadow检查是否有这个错误。

 

2063 void

2064 check_template_shadow (tree decl)                                                                    in pt.c

2065 {

2066   tree olddecl;

2067

2068   /* If we're not in a template, we can't possibly shadow a template

2069     parameter.  */

2070   if (!current_template_parms)

2071     return;

2072

2073  /* Figure out what we're shadowing.  */

2074   if (TREE_CODE (decl) == OVERLOAD)

2075     decl = OVL_CURRENT (decl);

2076   olddecl = IDENTIFIER_VALUE (DECL_NAME (decl));

2077

2078   /* If there's no previous binding for this name, we're not shadowing

2079     anything, let alone a template parameter.  */

2080   if (!olddecl)

2081     return;

2082

2083  /* If we're not shadowing a template parameter, we're done. Note

2084     that OLDDECL might be an OVERLOAD (or perhaps even an

2085     ERROR_MARK), so we can't just blithely assume it to be a _DECL

2086     node.  */

2087   if (!DECL_P (olddecl) || !DECL_TEMPLATE_PARM_P (olddecl))

2088     return;

2089

2090  /* We check for decl != olddecl to avoid bogus errors for using a

2091     name inside a class. We check TPFI to avoid duplicate errors for

2092     inline member templates.  */

2093   if (decl == olddecl

2094       || TEMPLATE_PARMS_FOR_INLINE (current_template_parms))

2095     return;

2096

2097   cp_error_at ("declaration of `%#D'", decl);

2098   cp_error_at (" shadows template parm `%#D'", olddecl);

2099 }

 

这里类的标识符节点还没有设定其bindings域,因此在2076行的IDENTIFIER_VALUE返回NULL

 

push_class_level_binding (continue)

 

2824   /* If this declaration shadows a declaration from an enclosing

2825     class, then we will need to restore IDENTIFIER_CLASS_VALUE when

2826     we leave this class. Record the shadowed declaration here.  */

2827   binding = IDENTIFIER_BINDING (name);

2828   if (binding && binding->value)

2829   {

        

2878   }

2879

2880   /* If we didn't replace an existing binding, put the binding on the

2881     stack of bindings for the identifier, and update the shadowed list.  */

2882   if (push_class_binding (name, x))

2883   {

2884     class_binding_level->class_shadowed

2885               = tree_cons (name, NULL,

2886                         class_binding_level->class_shadowed);

2887     /* Record the value we are binding NAME to so that we can know

2888       what to pop later.  */

2889     TREE_TYPE (class_binding_level->class_shadowed) = x;

2890     POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, true);

2891  }

2892

2893   POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, false);

2894 }

 

因为IDENTIFIER_VALUE在这里返回NULL,在上面就跳到2882行执行push_class_binding

 

2657 int

2658 push_class_binding (tree id, tree decl)                                                         in name-lookup.c

2659 {

2660   int result = 1;

2661   cxx_binding *binding = IDENTIFIER_BINDING (id);

2662   tree context;

2663

2664   timevar_push (TV_NAME_LOOKUP);

2665   /* Note that we declared this value so that we can issue an error if

2666     this is an invalid redeclaration of a name already used for some

2667     other purpose.  */

2668   note_name_declared_in_class (id, decl);

2669

2670   if (binding && binding->scope == class_binding_level)

2671     /* Supplement the existing binding.  */

2672     result = supplement_binding (IDENTIFIER_BINDING (id), decl);

2673   else

2674     /* Create a new binding.  */

2675     push_binding (id, decl, class_binding_level);

 

对于每个缓存的项,都需要检查是否是有效的声明。而对于每个类,都有一个伴随的splay树来记录在该类中使用过的名字。

 

6415 void

6416 note_name_declared_in_class (tree name, tree decl)                                      in class.c

6417 {

6418   splay_tree names_used;

6419   splay_tree_node n;

6420

6421   /* Look to see if we ever used this name.  */

6422   names_used

6423     = current_class_stack[current_class_depth - 1].names_used;

6424   if (!names_used)

6425     return;

6426

6427   n = splay_tree_lookup (names_used, (splay_tree_key) name);

6428   if (n)

6429   {

6430     /* [basic.scope.class]

6431  

6432       A name N used in a class S shall refer to the same declaration

6433       in its context and when re-evaluated in the completed scope of

6434       S.  */

6435     error ("declaration of `%#D'", decl);

6436     cp_error_at ("changes meaning of `%D' from `%+#D'",

6437                DECL_NAME (OVL_CURRENT (decl)),

6438                (tree) n->value);

6439   }

6440 }

 

上面current_class_stacknames_used域是splay树的根节点,用于记录每个类的域声明。在插入新域之前,要通过上面的这个函数来确认相同的名字之前没有被使用过。【3】给出了例子:

typedef int c;

enum { i = 1 };

class X {

char v[i]; // error: i refers to ::i but when reevaluated is X::i

int f() { return sizeof(c); } // OK: X::c

char c;

enum { i = 2 };

};

上面的声明char v[i]将被note_name_declared_in_class作为错误捕捉。这是因为,类数据成员的解析处理是顺序进行的,假若调换声明char v[i]enum { i=2 }char v[i]的含义就不同了。【3】把这种情况定义为病态程序。而对类内联方法的分析,是在解析完类声明结尾的“};”后,才进行。因此上面的“f()”方法的不受影响。

而上面2670行的条件则是检查重复声明的情况。对于新的定义,一个cxx_binding记录了这个绑定信息。

 

358  static void

359  push_binding (tree id, tree decl, cxx_scope* level)                                in name-lookup.c

360  {

361    cxx_binding *binding = cxx_binding_make (decl, NULL);

362 

363    /* Now, fill in the binding information.  */

364    binding->previous = IDENTIFIER_BINDING (id);

365    binding->scope = level;

366    INHERITED_VALUE_BINDING_P (binding) = 0;

367    LOCAL_BINDING_P (binding) = (level != class_binding_level);

368 

369    /* And put it on the front of the list of bindings for ID.  */

370    IDENTIFIER_BINDING (id) = binding;

371  }

 

如果非空,域IDENTIFIER_CLASS_VALUE是一个tree_list,它记录了类中所声明的所有成员。不过在push_binding中所构建的cxx_bindingvalue域是空的(因为它不是重载方法),因此下面的代码不作任何事,返回result 1

 

push_class_binding (continue)

 

2677   /* Update the IDENTIFIER_CLASS_VALUE for this ID to be the

2678     class-level declaration. Note that we do not use DECL here

2679     because of the possibility of the `struct stat' hack; if DECL is

2680     a class-name or enum-name we might prefer a field-name, or some

2681     such.  */

2682   IDENTIFIER_CLASS_VALUE (id) = IDENTIFIER_BINDING (id)->value;

2683

2684   /* If this is a binding from a base class, mark it as such.  */

2685   binding = IDENTIFIER_BINDING (id);

2686   if (binding->value == decl && TREE_CODE (decl) != TREE_LIST)

2687   {

2688     if (TREE_CODE (decl) == OVERLOAD)

2689       context = CP_DECL_CONTEXT (OVL_CURRENT (decl));

2690     else

2691     {

2692       my_friendly_assert (DECL_P (decl), 0);

2693       context = context_for_name_lookup (decl);

2694     }

2695

2696     if (is_properly_derived_from (current_class_type, context))

2697       INHERITED_VALUE_BINDING_P (binding) = 1;

2698     else

2699       INHERITED_VALUE_BINDING_P (binding) = 0;

2700   }

2701   else if (binding->value == decl)

2702     /* We only encounter a TREE_LIST when push_class_decls detects an

2703       ambiguity. Such an ambiguity can be overridden by a definition

2704       in this class.  */

2705     INHERITED_VALUE_BINDING_P (binding) = 1;

2706

2707   POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, result);

2708 }

 

因为push_class_binding在的2882行返回1,该成员被串入class_shadowed链表,该链表保存该类所声明的成员。最后push_class_level_binding返回true

返回pushdecl_class_level2744行,变量x是一个TYPE_DECL(参考build_lang_decl),进一步的绑定结构由set_identifier_type_value构建。在这一步,标识符节点的type域被更新为指向类的RECORD_TYPE节点,同时type域的原始值(global_type_node)被保存在相应的cxx_binding节点的type_shadowed域里。

 

点此打开

61:创建对自己的引用—第二步

注意IDENTIFIER_NODE和“SingleThreaded”的cxx_scope对象的变化是相配合的。在pushdecl_class_levelfinish_member_declaration返回1后,这个对自己的引用被串接入类的域声明链表(即RECORD_TYPEvalues域)的末尾。

接着maybe_add_class_template_decl_list被执行。对于类模板,CLASSTYPE_DECL_LIST是一个依声明次序用于所有数据成员,函数及友元的tree_list。其中的每个节点的TREE_PURPOSE,对于友元是NULL_TREE,而对于类模板则是其RECORD_TYPE

 

2583 void

2584 maybe_add_class_template_decl_list (tree type, tree t, int friend_p)               in class.c

2585 {

2586   /* Save some memory by not creating TREE_LIST if TYPE is not template.  */

2587   if (CLASSTYPE_TEMPLATE_INFO (type))

2588     CLASSTYPE_DECL_LIST (type)

2589       = tree_cons (friend_p ? NULL_TREE : type,

2590                  t, CLASSTYPE_DECL_LIST (type));

2591 }

 

点此打开

62:创建对自己的引用—第三步

原创粉丝点击