grokdeclarator (continue)
8163 {
8164 tree decl;
8165
8166 if (decl_context == PARM)
8167 {
8168 decl = cp_build_parm_decl (declarator, type);
8169
8170 bad_specifiers (decl, "parameter", virtualp, quals != NULL_TREE,
8171 inlinep, friendp, raises != NULL_TREE);
8172 }
8173 else if (decl_context == FIELD)
8174 {
8175 /* The C99 flexible array extension. */
8176 if (!staticp && TREE_CODE (type) == ARRAY_TYPE
8177 && TYPE_DOMAIN (type) == NULL_TREE)
8178 {
8179 tree itype = compute_array_index_type (dname, integer_zero_node);
8180 type = build_cplus_array_type (TREE_TYPE (type), itype);
8181 }
8182
8183 if (type == error_mark_node)
8184 {
8185 /* Happens when declaring arrays of sizes which
8186 are error_mark_node, for example. */
8187 decl = NULL_TREE;
8188 }
8189 else if (in_namespace && !friendp)
8190 {
8191 /* Something like struct S { int N::j; }; */
8192 error ("invalid use of `::'");
8193 decl = NULL_TREE;
8194 }
8195 else if (TREE_CODE (type) == FUNCTION_TYPE)
8196 {
8197 int publicp = 0;
8198 tree function_context;
8199
8200 /* We catch the others as conflicts with the builtin
8201 typedefs. */
8202 if (friendp && declarator == ridpointers [(int) RID_SIGNED])
8203 {
8204 error ("function `%D' cannot be declared friend",
8205 declarator);
8206 friendp = 0;
8207 }
8208
8209 if (friendp == 0)
8210 {
8211 if (ctype == NULL_TREE)
8212 ctype = current_class_type ;
8213
8214 if (ctype == NULL_TREE)
8215 {
8216 error ("can't make `%D' into a method -- not in a class",
8217 declarator);
8218 return void_type_node;
8219 }
8220
8221 /* ``A union may [ ... ] not [ have ] virtual functions.''
8222 ARM 9.5 */
8223 if (virtualp && TREE_CODE (ctype) == UNION_TYPE)
8224 {
8225 error ("function `%D' declared virtual inside a union",
8226 declarator);
8227 return void_type_node;
8228 }
8229
8230 if (NEW_DELETE_OPNAME_P (declarator))
8231 {
8232 if (virtualp)
8233 {
8234 error ("`%D' cannot be declared virtual, since it is always static",
8235 declarator);
8236 virtualp = 0;
8237 }
8238 }
8239 else if (staticp < 2)
8240 type = build_method_type_directly (ctype,
8241 TREE_TYPE (type),
8242 TYPE_ARG_TYPES (type));
8243 }
8244
8245 /* Tell grokfndecl if it needs to set TREE_PUBLIC on the node. */
8246 function_context = (ctype != NULL_TREE) ?
8247 decl_function_context (TYPE_MAIN_DECL (ctype)) : NULL_TREE;
8248 publicp = (! friendp || ! staticp)
8249 && function_context == NULL_TREE;
8250 decl = grokfndecl (ctype, type,
8251 TREE_CODE (declarator) != TEMPLATE_ID_EXPR
8252 ? declarator : dname,
8253 parms,
8254 declarator,
8255 virtualp, flags, quals, raises,
8256 friendp ? -1 : 0, friendp, publicp, inlinep,
8257 funcdef_flag, template_count, in_namespace);
8258 if (decl == NULL_TREE)
8259 return decl;
8260 #if 0
8261 /* This clobbers the attrs stored in `decl' from `attrlist'. */
8262 /* The decl and setting of decl_attr is also turned off. */
8263 decl = build_decl_attribute_variant (decl, decl_attr);
8264 #endif
在中间树中,该类的非静态方法应该是 METHOD_TYPE 。对于方法,正如我们所了解的, this 是隐含的参数指向这个方法所要操纵的对象。下面的 build_pointer_type 则是创建这个隐含的 this 。注意到,作为副作用,在 7601 行所构建的 FUNCTION_TYPE 节点被丢弃(它将随后被 GC 回收)。
3902 tree
3903 build_method_type_directly (tree basetype, in tree.c
3904 tree rettype,
3905 tree argtypes)
3906 {
3907 tree t;
3908 tree ptype;
3909 int hashcode;
3910
3911 /* Make a node of the sort we want. */
3912 t = make_node (METHOD_TYPE);
3913
3914 TYPE_METHOD_BASETYPE (t) = TYPE_MAIN_VARIANT (basetype);
3915 TREE_TYPE (t) = rettype;
3916 ptype = build_pointer_type (basetype);
3917
3918 /* The actual arglist for this function includes a "hidden" argument
3919 which is "this". Put it into the list of argument types. */
3920 argtypes = tree_cons (NULL_TREE, ptype, argtypes);
3921 TYPE_ARG_TYPES (t) = argtypes;
3922
3923 /* If we already have such a type, use the old one and free this one.
3924 Note that it also frees up the above cons cell if found. */
3925 hashcode = TYPE_HASH (basetype) + TYPE_HASH (rettype) +
3926 type_hash_list (argtypes);
3927
3928 t = type_hash_canon (hashcode, t);
3929
3930 if (!COMPLETE_TYPE_P (t))
3931 layout_type (t);
3932
3933 return t;
3934 }
在 8247 行,如果 decl 的封闭( enclosing )域不是 FUNCTION_DECL , decl_funtion_context 返回 NULL_TREE ,否则就是这个 FUNCTION_DECL 。而现在 decl 是 current_class_type ,它是结构体“ Lock ”的 TYPE_DECL 。
4392 tree
4393 decl_function_context (tree decl) in tree.c
4394 {
4395 tree context;
4396
4397 if (TREE_CODE (decl) == ERROR_MARK)
4398 return 0;
4399
4400 if (TREE_CODE (decl) == SAVE_EXPR)
4401 context = SAVE_EXPR_CONTEXT (decl);
4402
4403 /* C++ virtual functions use DECL_CONTEXT for the class of the vtable
4404 where we look up the function at runtime. Such functions always take
4405 a first argument of type 'pointer to real context'.
4406
4407 C++ should really be fixed to use DECL_CONTEXT for the real context,
4408 and use something else for the "virtual context". */
4409 else if (TREE_CODE (decl) == FUNCTION_DECL && DECL_VINDEX (decl))
4410 context
4411 = TYPE_MAIN_VARIANT
4412 (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)))));
4413 else
4414 context = DECL_CONTEXT (decl);
4415
4416 while (context && TREE_CODE (context) != FUNCTION_DECL)
4417 {
4418 if (TREE_CODE (context) == BLOCK)
4419 context = BLOCK_SUPERCONTEXT (context);
4420 else
4421 context = get_containing_scope (context);
4422 }
4423
4424 return context;
4425 }
而在进入封闭域栈时,除了 *_DECL 可能还会遇到 *_TYPE ,通过 get_containing_scope 获取相应的封闭上下文。
4383 tree
4384 get_containing_scope (tree t) in tree.c
4385 {
4386 return (TYPE_P (t) ? TYPE_CONTEXT (t) : DECL_CONTEXT (t));
4387 }
结果在 8248 行, publicp 是 1 ,它表示该声明的可见性仅取决于包含它的类。
那么对于 8250 行 grokfndecl 的调用,其参数的值为: ctype ( current_class_type ), type (在 8240 行的 METHOD_TYPE 节点), parms ( NULL_TREE ), virtualp ( 0 ), flags ( NO_SPECIAL ), quals ( NULL_TREE ), raises ( NULL_TREE ), check ( 0 ), friendp ( 0 ), publicp ( 1 ), inlinep ( 0 ), funcdef_flag ( -1 ), template_count ( 0 ), in_namespace ( NULL_TREE) 。
5582 static tree
5583 grokfndecl (tree ctype, in decl.c
5584 tree type,
5585 tree declarator,
5586 tree parms,
5587 tree orig_declarator,
5588 int virtualp,
5589 enum overload_flags flags,
5590 tree quals,
5591 tree raises,
5592 int check,
5593 int friendp,
5594 int publicp,
5595 int inlinep,
5596 int funcdef_flag,
5597 int template_count,
5598 tree in_namespace)
5599 {
5600 tree decl;
5601 int staticp = ctype && TREE_CODE (type) == FUNCTION_TYPE;
5602 int has_default_arg = 0;
5603 tree t;
5604
5605 if (raises)
5606 type = build_exception_variant (type, raises);
5607
5608 decl = build_lang_decl (FUNCTION_DECL, declarator, type);
5609 DECL_ARGUMENTS (decl) = parms;
5610 /* Propagate volatile out from type to decl. */
5611 if (TYPE_VOLATILE (type))
5612 TREE_THIS_VOLATILE (decl) = 1;
5613
5614 /* If this decl has namespace scope, set that up. */
5615 if (in_namespace)
5616 set_decl_namespace (decl, in_namespace, friendp);
5617 else if (!ctype)
5618 DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);
5619
5620 /* `main' and builtins have implicit 'C' linkage. */
5621 if ((MAIN_NAME_P (declarator)
5622 || (IDENTIFIER_LENGTH (declarator) > 10
5623 && IDENTIFIER_POINTER (declarator)[0] == '_'
5624 && IDENTIFIER_POINTER (declarator)[1] == '_'
5625 && strncmp (IDENTIFIER_POINTER (declarator)+2, "builtin_", 8) == 0))
5626 && current_lang_name == lang_name_cplusplus
5627 && ctype == NULL_TREE
5628 /* NULL_TREE means global namespace. */
5629 && DECL_CONTEXT (decl) == NULL_TREE)
5630 SET_DECL_LANGUAGE (decl, lang_c);
5631
5632 /* Should probably propagate const out from type to decl I bet (mrs). */
5633 if (staticp)
5634 {
5635 DECL_STATIC_FUNCTION_P (decl) = 1;
5636 DECL_CONTEXT (decl) = ctype;
5637 }
5638
5639 if (ctype)
5640 DECL_CONTEXT (decl) = ctype;
5641
5642 if (ctype == NULL_TREE && DECL_MAIN_P (decl))
5643 {
5644 if (processing_template_decl)
5645 error ("cannot declare `::main' to be a template");
5646 if (inlinep)
5647 error ("cannot declare `::main' to be inline");
5648 if (!publicp)
5649 error ("cannot declare `::main' to be static");
5650 if (!same_type_p (TREE_TYPE (TREE_TYPE (decl)),
5651 integer_type_node))
5652 error ("`main' must return `int'");
5653 inlinep = 0;
5654 publicp = 1;
5655 }
5656
5657 /* Members of anonymous types and local classes have no linkage; make
5658 them internal. */
5659 /* FIXME what if it gets a name from typedef? */
5660 if (ctype && (TYPE_ANONYMOUS_P (ctype)
5661 || decl_function_context (TYPE_MAIN_DECL (ctype))))
5662 publicp = 0;
5663
5664 if (publicp)
5665 {
5666 /* [basic.link]: A name with no linkage (notably, the name of a class
5667 or enumeration declared in a local scope) shall not be used to
5668 declare an entity with linkage.
5669
5670 Only check this for public decls for now. See core 319, 389. */
5671 t = no_linkage_check (TREE_TYPE (decl));
5672 if (t)
5673 {
5674 if (TYPE_ANONYMOUS_P (t))
5675 {
5676 if (DECL_EXTERN_C_P (decl))
5677 /* Allow this; it's pretty common in C. */;
5678 else
5679 {
5680 pedwarn ("non-local function `%#D' uses anonymous type",
5681 decl);
5682 if (DECL_ORIGINAL_TYPE (TYPE_NAME (t)))
5683 cp_pedwarn_at ("/
5684 `%#D' does not refer to the unqualified type, so it is not used for linkage",
5685 TYPE_NAME (t));
5686 }
5687 }
5688 else
5689 pedwarn ("non-local function `%#D' uses local type `%T'",
5690 decl, t);
5691 }
5692 }
5693
5694 TREE_PUBLIC (decl) = publicp;
5695 if (! publicp)
5696 {
5697 DECL_INTERFACE_KNOWN (decl) = 1;
5698 DECL_NOT_REALLY_EXTERN (decl) = 1;
5699 }
5700
5701 /* If the declaration was declared inline, mark it as such. */
5702 if (inlinep)
5703 DECL_DECLARED_INLINE_P (decl) = 1;
5704 /* We inline functions that are explicitly declared inline, or, when
5705 the user explicitly asks us to, all functions. */
5706 if (DECL_DECLARED_INLINE_P (decl)
5707 || (flag_inline_trees == 2 && !DECL_INLINE (decl) && funcdef_flag))
5708 DECL_INLINE (decl) = 1;
5709
5710 DECL_EXTERNAL (decl) = 1;
5711 if (quals != NULL_TREE && TREE_CODE (type) == FUNCTION_TYPE)
5712 {
5713 error ("%smember function `%D' cannot have `%T' method qualifier",
5714 (ctype ? "static " : "non-"), decl, TREE_VALUE (quals));
5715 quals = NULL_TREE;
5716 }
5717
5718 if (IDENTIFIER_OPNAME_P (DECL_NAME (decl)))
5719 grok_op_properties (decl, /*complain=*/ true);
5720
5721 if (ctype && decl_function_context (decl))
5722 DECL_NO_STATIC_CHAIN (decl) = 1;
5723
5724 for (t = TYPE_ARG_TYPES (TREE_TYPE (decl)); t; t = TREE_CHAIN (t))
5725 if (TREE_PURPOSE (t)
5726 && TREE_CODE (TREE_PURPOSE (t)) == DEFAULT_ARG)
5727 {
5728 has_default_arg = 1;
5729 break ;
5730 }
5731
5732 if (friendp
5733 && TREE_CODE (orig_declarator) == TEMPLATE_ID_EXPR)
5734 {
...
5786 }
5787
5788 if (funcdef_flag)
5789 /* Make the init_value nonzero so pushdecl knows this is not
5790 tentative. error_mark_node is replaced later with the BLOCK. */
5791 DECL_INITIAL (decl) = error_mark_node;
5792
5793 if (TYPE_NOTHROW_P (type) || nothrow_libfn_p (decl))
5794 TREE_NOTHROW (decl) = 1;
5795
5796 /* Caller will do the rest of this. */
5797 if (check < 0)
5798 return decl;
5799
5800 if (flags == NO_SPECIAL && ctype && constructor_name_p (declarator, ctype))
5801 DECL_CONSTRUCTOR_P (decl) = 1;
5802
5803 /* Function gets the ugly name, field gets the nice one. This call
5804 may change the type of the function (because of default
5805 parameters)! */
5806 if (ctype != NULL_TREE)
5807 grokclassfn (ctype, decl, flags, quals);
在调用 grokclassfn 之前,中间树对应的部分如下。
( 点此打开 )
图 68 :“ Lock ”构造函数的 FUNCTION_DECL —第一步
虽然已经创建了 METHOD_TYPE 节点,但它可能不完全是所要求的,因为这个类型节点没有考虑限定词及属性。而且那个隐含的 this 参数应该是一个指针常量。
303 void
304 grokclassfn (tree ctype, tree function, enum overload_flags flags, tree quals) in decl2.c
305 {
306 tree fn_name = DECL_NAME (function);
307 int this_quals = TYPE_UNQUALIFIED;
308
309 /* Even within an `extern "C"' block, members get C++ linkage. See
310 [dcl.link] for details. */
311 SET_DECL_LANGUAGE (function, lang_cplusplus);
312
313 if (fn_name == NULL_TREE)
314 {
315 error ("name missing for member function");
316 fn_name = get_identifier ("<anonymous>");
317 DECL_NAME (function) = fn_name;
318 }
319
320 if (quals)
321 this_quals = grok_method_quals (ctype, function, quals);
322
323 if (TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE)
324 {
325 /* Must add the class instance variable up front. */
326 /* Right now we just make this a pointer. But later
327 we may wish to make it special. */
328 tree type = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (function)));
329 tree qual_type;
330 tree parm;
331
332 /* The `this' parameter is implicitly `const'; it cannot be
333 assigned to. */
334 this_quals |= TYPE_QUAL_CONST;
335 qual_type = cp_build_qualified_type (type, this_quals);
336 parm = build_artificial_parm (this_identifier, qual_type);
337 c_apply_type_quals_to_decl (this_quals, parm);
338 TREE_CHAIN (parm) = DECL_ARGUMENTS (function);
339 DECL_ARGUMENTS (function) = parm;
340 }
341
342 DECL_CONTEXT (function) = ctype;
343
344 if (flags == DTOR_FLAG)
345 DECL_DESTRUCTOR_P (function) = 1;
346
347 if (flags == DTOR_FLAG || DECL_CONSTRUCTOR_P (function))
348 maybe_retrofit_in_chrg (function);
349 }
上面的参数 function 是先前所创建的 FUNCTION_DECL 节点。而 TREE_TYPE 从这个节点返回对应的 METHOD_TYPE 节点。虽然已经为类构建了 this 指针,不过这个隐含的参数应该是一个指针常量—其引用对象不能更换(这个非常量指针也是需要的,作为非限定类型,前端要求它出现在限定类型链表的头部)。因此 cp_build_qualified_type 从非限定类型构建要求的限定类型。
196 tree
197 build_artificial_parm (tree name, tree type) in decl2.c
198 {
199 tree parm = cp_build_parm_decl (name, type);
200 DECL_ARTIFICIAL (parm) = 1;
201 /* All our artificial parms are implicitly `const'; they cannot be
202 avsigned to. */
203 TREE_READONLY (parm) = 1;
204 return parm;
205 }
同样注意在 336 行, this_identifier 是表示 this 指针的全局标识符(它仅是名字“ this ”)。
182 tree
183 cp_build_parm_decl (tree name, tree type) in decl2.c
184 {
185 tree parm = build_decl (PARM_DECL, name, type);
186 /* DECL_ARG_TYPE is only used by the back end and the back end never
187 sees templates. */
188 if (!processing_template_decl )
189 DECL_ARG_TYPE (parm) = type_passed_as (type);
190 return parm;
191 }
在这里, processing_template_decl 仍然为非 0 值,因为我们还在一个类模板里( class “ SingleThreaded ”),因此仅创建了 PARM_DECL 节点,但没有进一步的处理。同样当从 grokclassfn 返回, maybe_retrofit_in_chrg 不做任何事,因为 processing_template_decl 是非 0 值。现在中间树看起来就像:
( 点此打开 )
图 69 :“ Lock ”构造函数的 FUNCTION_DECL —第二步
下面,对于普通的模板声明(即,非具现,非特化),函数 check_explicit_specialization 不做实质的事情。
grokfndecl (continue)
5809 decl = check_explicit_specialization (orig_declarator, decl,
5810 template_count,
5811 2 * (funcdef_flag != 0) +
5812 4 * (friendp != 0));
5813 if (decl == error_mark_node)
5814 return NULL_TREE;
5815
5816 if (ctype != NULL_TREE
5817 && (! TYPE_FOR_JAVA (ctype) || check_java_method (decl))
5818 && check)
5819 {
…
5865 }
5866
5867 if (DECL_CONSTRUCTOR_P (decl) && !grok_ctor_properties (ctype, decl))
5868 return NULL_TREE;
5869
5870 if (ctype == NULL_TREE || check)
5871 return decl;
5872
5873 if (virtualp)
5874 DECL_VIRTUAL_P (decl) = 1;
5875
5876 return decl;
5877 }
在离开 grokfndecl 之前,还需要一些检查。对于构造函数,它不能是 X(X) 的形式,因为如果不慎对自己赋值将导致无限递归。在 5867 行, grok_ctor_properties 进行这个检查。
grokdeclarator (continue)
8266 /* [class.conv.ctor]
8267
8268 A constructor declared without the function-specifier
8269 explicit that can be called with a single parameter
8270 specifies a conversion from the type of its first
8271 parameter to the type of its class. Such a constructor
8272 is called a converting constructor. */
8273 if (explicitp == 2)
8274 DECL_NONCONVERTING_P (decl) = 1;
8275 else if (DECL_CONSTRUCTOR_P (decl))
8276 {
8277 /* The constructor can be called with exactly one
8278 parameter if there is at least one parameter, and
8279 any subsequent parameters have default arguments.
8280 Ignore any compiler-added parms. */
8281 tree arg_types = FUNCTION_FIRST_USER_PARMTYPE (decl);
8282
8283 if (arg_types == void_list_node
8284 || (arg_types
8285 && TREE_CHAIN (arg_types)
8286 && TREE_CHAIN (arg_types) != void_list_node
8287 && !TREE_PURPOSE (TREE_CHAIN (arg_types))))
8288 DECL_NONCONVERTING_P (decl) = 1;
8289 }
8290 }
…
8548 }
8549
8550 my_friendly_assert (!RIDBIT_SETP (RID_MUTABLE, specbits), 19990927);
8551
8552 /* Record `register' declaration for warnings on &
8553 and in case doing stupid register allocation. */
8554
8555 if (RIDBIT_SETP (RID_REGISTER, specbits))
8556 DECL_REGISTER (decl) = 1;
8557
8558 if (RIDBIT_SETP (RID_EXTERN, specbits))
8559 DECL_THIS_EXTERN (decl) = 1;
8560
8561 if (RIDBIT_SETP (RID_STATIC, specbits))
8562 DECL_THIS_STATIC (decl) = 1;
8563
8564 /* Record constancy and volatility. There's no need to do this
8565 when processing a template; we'll do this for the instantiated
8566 declaration based on the type of DECL. */
8567 if (!processing_template_decl )
8568 c_apply_type_quals_to_decl (type_quals, decl);
8569
8570 return decl;
8571 }
8572 }
我们知道,带有参数的构造函数可以被用作转换操作符,除非它被声明为“ explict ”。而且只有构造函数可被声明为“ explicit ”,如果 explicitp 为 2 ,则表示其使用没问题。能用作转换构造函数的构造函数必须带有至少一个参数,而且除第一个参数外,其他参数需要具有缺省值。
现在我们已经构建了方法的树节点,但其设置尚未完成。因此在 start_method 的余下部分,它为构造函数完成节点的设置。注意 fndecl 是由 grokdeclarator 构建的 FUNCTION_DECL 节点。
start_method (continue)
11051 if (fndecl == error_mark_node)
11052 return error_mark_node;
11053
11054 if (fndecl == NULL || TREE_CODE (fndecl) != FUNCTION_DECL)
11055 {
11056 error ("invalid member function declaration");
11057 return error_mark_node;
11058 }
11059
11060 if (attrlist)
11061 cplus_decl_attributes (&fndecl, attrlist, 0);
11062
11063 /* Pass friends other than inline friend functions back. */
11064 if (fndecl == void_type_node)
11065 return fndecl;
11066
11067 if (DECL_IN_AGGR_P (fndecl))
11068 {
11069 if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (fndecl)) != current_class_type )
11070 {
11071 if (DECL_CONTEXT (fndecl)
11072 && TREE_CODE( DECL_CONTEXT (fndecl)) != NAMESPACE_DECL)
11073 error ("`%D' is already defined in class `%T'", fndecl,
11074 DECL_CONTEXT (fndecl));
11075 }
11076 return void_type_node;
11077 }
11078
11079 check_template_shadow (fndecl);
11080
11081 DECL_DECLARED_INLINE_P (fndecl) = 1;
11082 if (flag_default_inline)
11083 DECL_INLINE (fndecl) = 1;
11084
11085 /* We process method specializations in finish_struct_1. */
11086 if (processing_template_decl && !DECL_TEMPLATE_SPECIALIZATION (fndecl))
11087 {
11088 fndecl = push_template_decl (fndecl);
11089 if (fndecl == error_mark_node)
11090 return fndecl;
11091 }
11092
11093 if (! DECL_FRIEND_P (fndecl))
11094 {
11095 if (TREE_CHAIN (fndecl))
11096 {
11097 fndecl = copy_node (fndecl);
11098 TREE_CHAIN (fndecl) = NULL_TREE;
11099 }
11100 grok_special_member_properties (fndecl);
11101 }
11102
11103 cp_finish_decl (fndecl, NULL_TREE, NULL_TREE, 0);
11104
11105 /* Make a place for the parms. */
11106 begin_scope (sk_function_parms, fndecl);
11107
11108 DECL_IN_AGGR_P (fndecl) = 1;
11109 return fndecl;
11110 }
因为我们仍然在类模板中,所以它需要检查该声明符是否会屏蔽模板参数。在 15224 行的 DECL_TEMPLATE_SPECIALIZATION 检查 DECL_USE_TEMPLATE 域是否等于 2 (这表示显式特化)。毫无疑问,在这里,这个构造函数也被视为一个模板声明,因为它被包含在一个类模板中。在前面的章节中我们多次看过 push_template_decl ,注意到因为不是直接包含在域 sk_template_parms 中,在 push_template_decl_real 的局部变量 primary 是 false 。当从 push_template_decl 返回时,中间树加入了以下的节点。
( 点此打开 )
图 70 :“ Lock ”构造函数的 FUNCTION_DECL —第三步
在成功地创建了相应的 TEMPLATE_DECL 并把它加入到上下文环境中,包含类节点的某些标记需要相应地设置。
8900 void grok_special_member_properties (tree decl) in decl.c
8901 {
8902 if (!DECL_NONSTATIC_MEMBER_FUNCTION_P(decl))
8903 ; /* Not special. */
8904 else if (DECL_CONSTRUCTOR_P (decl))
8905 {
8906 int ctor = copy_fn_p (decl);
8907
8908 if (ctor > 0)
8909 {
8910 /* [class.copy]
8911
8912 A non-template constructor for class X is a copy
8913 constructor if its first parameter is of type X&, const
8914 X&, volatile X& or const volatile X&, and either there
8915 are no other parameters or else all other parameters have
8916 default arguments. */
8917 TYPE_HAS_INIT_REF (DECL_CONTEXT (decl)) = 1;
8918 if (ctor > 1)
8919 TYPE_HAS_CONST_INIT_REF (DECL_CONTEXT (decl)) = 1;
8920 }
8921 else if (sufficient_parms_p (FUNCTION_FIRST_USER_PARMTYPE (decl)))
8922 TYPE_HAS_DEFAULT_CONSTRUCTOR (DECL_CONTEXT (decl)) = 1;
8923 }
8924 else if (DECL_OVERLOADED_OPERATOR_P (decl) == NOP_EXPR)
8925 {
…
8942 }
8943 }
上面在 8906 行, copy_fn_p 检查 decl 是否是拷贝构造函数或赋值操作符,如果它都不是,则返回 0 。那么 FUNCTION_FIRST_USER_PARMTYPE 获取第一个非人造的参数(也即跳过参数 const this* )。
983 #define FUNCTION_FIRST_USER_PARMTYPE (NODE) / in cp-tree.h
984 skip_artificial_parms_for ((NODE), TYPE_ARG_TYPES (TREE_TYPE (NODE)))
上面的图清除地解释了 skip_artificial_parms_for 的行为。注意到只有从虚基类派生的类, DECL_HAS_IN_CHARGE_PARM_P 及 DECL_HAS_VTT_PARM_P 才可能返回非 0 值。
1061 tree
1062 skip_artificial_parms_for (tree fn, tree list) in method.c
1063 {
1064 if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
1065 list = TREE_CHAIN (list);
1066 else
1067 return list;
1068
1069 if (DECL_HAS_IN_CHARGE_PARM_P (fn))
1070 list = TREE_CHAIN (list);
1071 if (DECL_HAS_VTT_PARM_P (fn))
1072 list = TREE_CHAIN (list);
1073 return list;
1074 }
注意,非可变参数的 FUNCTION_DECL 的参数链表必须由 void_list_node 结尾。
398 bool
399 sufficient_parms_p (tree parmlist) in call.c
400 {
401 for (; parmlist && parmlist != void_list_node;
402 parmlist = TREE_CHAIN (parmlist))
403 if (!TREE_PURPOSE (parmlist))
404 return false;
405 return true;
406 }
然后在 start_method 中, cp_finish_decl 通过向节点中置入行号及初始值(如果有的话)完成对声明的处理。不过,因为在类模板中,该函数仅设置了 FUNCTION_DECL 节点的标记 DECL_INITIALIZED_IN_CLASS_P 。
另外,在 15244 行, begin_scope 使得 FUNCTION_DECL 成为了当前的作用域(绑定域)。在这一步,中间树看起来如下:
( 点此打开 )
图 71 :“ Lock ”构造函数的 FUNCTION_DECL —完成