GCC-3.4.6源代码学习笔记(135)
来源:互联网 发布:sql 的not in中的为空 编辑:程序博客网 时间:2024/06/03 19:28
5.12.5.2.2.2.1.3.2. 具现基类——完成
在处理完所有的基类后(基类被串接起来),在instantiate_class_template的5452行,调用xref_basetype来填充其binfo部分,其中实参ref是派生类的RECORD_TYPE,而base_list包含了基类的RECORD_TYPE,及其访问属性。
基类的RECORD_TYPE是尚未完成的,因为其type域是空的,因此它需要首先通过在xref_basetype 9645行的complete_type_or_else来完成这个域。
4210 #define complete_type_or_else(T,V)(complete_type_or_diagnostic ((T), (V), 0))
147 tree
148 complete_type_or_diagnostic (tree type,tree value, int diag_type) in typeck.c
149 {
150 type = complete_type (type);
151 if (type == error_mark_node)
152 /* We alreadyissued an error. */
153 returnNULL_TREE;
154 else if (!COMPLETE_TYPE_P (type))
155 {
156 cxx_incomplete_type_diagnostic (value,type, diag_type);
157 returnNULL_TREE;
158 }
159 else
160 returntype;
161 }
看到在函数的开头,complete_type被递归调用(我们从为派生类调用的complete_type中来到这里)。在complete_type中,为基类亦调用了instantiate_class_template来对其具现。如果基类亦是从某个模板类派生,这个过程亦为该基类重复。直到找到最底层的模板类(我们现在只看到具现模板类的前半部分,在后半部分模板类要调用finish_struct来完成RECORD_TYPE节点),或者最底层非模板类(这样的类型已经调用过finish_struct,其RECORD_TYPE节点已经完成处理)。在这里我们跳过在complete_type中基类处理的细节,假定之后其RECORD_TYPE已经完成处理。
xref_basetype的细节可以参考前面的章节,对于我们的例子,执行深拷贝,因为基类是一个RECORD_TYPE节点。我们得到如下的布局。
(点此打开)
5.12.5.2.2.2.1.3.3. 完成派生类的RECORD_TYPE – 成员的替代
现在基类的具现体已经就绪,并且该派生类的binfo也已设置,接下来需要填入该类的成员,因为这里的type 是一个对应具现体的空的RECORD_TYPE。进一步的派生类中的某些成员可能依赖于模板参数,它们也需要进行实参替换。如何产生这些类型值得了解。该处理函数虽然长,但相当明白。
instantiate_class_template (continue)
5458 /* Now that ourbase classes are set up, enter the scope of the
5459 class, so that name lookupsinto base classes, etc. will work
5460 correctly. This is preciselyanalogous to what we do in
5461 begin_class_definition whendefining an ordinary non-template
5462 class. */
5463 pushclass (type);
5464
5465 /* Now members areprocessed in the order of declaration. */
5466 for (member =CLASSTYPE_DECL_LIST (pattern);
5467 member; member = TREE_CHAIN (member))
5468 {
5469 tree t = TREE_VALUE (member);
5470
5471 if (TREE_PURPOSE (member))
5472 {
5473 if (TYPE_P (t))
5474 {
5475 /* Build new CLASSTYPE_NESTED_UTDS. */
5476
5477 tree tag = t;
5478 tree name = TYPE_IDENTIFIER (tag);
5479 tree newtag;
5480 bool class_template_p;
5481
5482 class_template_p = (TREE_CODE (tag) !=ENUMERAL_TYPE
5483 &&TYPE_LANG_SPECIFIC (tag)
5484 &&CLASSTYPE_IS_TEMPLATE (tag));
5485 /* If themember is a class template, then -- even after
5486 substituition -- theremay be dependent types in the
5487 template argument listfor the class. We increment
5488 PROCESSING_TEMPLATE_DECLso that dependent_type_p, as
5489 that function willassume that no types are dependent
5490 when outside of atemplate. */
5491 if (class_template_p)
5492 ++processing_template_decl;
5493 newtag = tsubst (tag, args, tf_error,NULL_TREE);
5494 if (class_template_p)
5495 --processing_template_decl;
5496 if (newtag == error_mark_node)
5497 continue;
5498
5499 if (TREE_CODE (newtag) !=ENUMERAL_TYPE)
5500 {
5501 if (class_template_p)
5502 /*Unfortunately, lookup_template_class sets
5503 CLASSTYPE_IMPLICIT_INSTANTIATION for a partial
5504 instantiation(i.e., for the type of a member
5505 template classnested within a template class.)
5506 This behavior isrequired for
5507 maybe_process_partial_specialization to work
5508 correctly, but isnot accurate in this case;
5509 the TAG is not aninstantiation of anything.
5510 (The correspondingTEMPLATE_DECL is an
5511 instantiation, butthe TYPE is not.) */
5512 CLASSTYPE_USE_TEMPLATE (newtag) =0;
5513
5514 /* Now, wecall pushtag to put this NEWTAG into the scope of
5515 TYPE. We first set upthe IDENTIFIER_TYPE_VALUE to avoid
5516 pushtag callingpush_template_decl. We don't have to do
5517 this for enums becauseit will already have been done in
5518 tsubst_enum. */
5519 if (name)
5520 SET_IDENTIFIER_TYPE_VALUE (name,newtag);
5521 pushtag (name,newtag, /*globalize=*/0);
5522 }
5523 } // end if (TYPE_P (t))
5524 else if (TREE_CODE (t) == FUNCTION_DECL
5525 || DECL_FUNCTION_TEMPLATE_P (t))
5526 {
5527 /* Build newTYPE_METHODS. */
5528 tree r;
5529
5530 if (TREE_CODE (t) == TEMPLATE_DECL)
5531 ++processing_template_decl;
5532 r = tsubst (t, args, tf_error,NULL_TREE);
5533 if (TREE_CODE (t) == TEMPLATE_DECL)
5534 --processing_template_decl;
5535 set_current_access_from_decl (r);
5536 grok_special_member_properties (r);
5537 finish_member_declaration(r);
5538 }
5539 else
5540 {
5541 /* Build new TYPE_FIELDS. */
5542
5543 if (TREE_CODE (t) != CONST_DECL)
5544 {
5545 tree r;
5546
5547 /* The the file and line for this declaration,to
5548 assist in errormessage reporting. Since we
5549 calledpush_tinst_level above, we don't need to
5550 restore these. */
5551 input_location = DECL_SOURCE_LOCATION (t);
5552
5553 if (TREE_CODE (t) == TEMPLATE_DECL)
5554 ++processing_template_decl;
5555 r = tsubst (t, args, tf_error |tf_warning, NULL_TREE);
5556 if (TREE_CODE (t) == TEMPLATE_DECL)
5557 --processing_template_decl;
5558 if (TREE_CODE (r) == VAR_DECL)
5559 {
5560 tree init;
5561
5562 if (DECL_INITIALIZED_IN_CLASS_P(r))
5563 init = tsubst_expr (DECL_INITIAL(t), args,
5564 tf_error |tf_warning, NULL_TREE);
5565 else
5566 init = NULL_TREE;
5567
5568 finish_static_data_member_decl
5569 (r, init, /*asmspec_tree=*/NULL_TREE, /*flags=*/0);
5570
5571 if (DECL_INITIALIZED_IN_CLASS_P(r))
5572 check_static_variable_definition(r, TREE_TYPE (r));
5573 }
5574 else if (TREE_CODE (r) == FIELD_DECL)
5575 {
5576 /*Determine whether R has a valid type and can be
5577 completed later. IfR is invalid, then it is
5578 replaced byerror_mark_node so that it will not be
5579 added toTYPE_FIELDS. */
5580 tree rtype = TREE_TYPE (r);
5581 if(can_complete_type_without_circularity (rtype))
5582 complete_type(rtype);
5583
5584 if (!COMPLETE_TYPE_P (rtype))
5585 {
5586 cxx_incomplete_type_error (r,rtype);
5587 r = error_mark_node;
5588 }
5589 }
5590
5591 /* If it isa TYPE_DECL for a class-scoped ENUMERAL_TYPE,
5592 such a thing willalready have been added to the field
5593 list by tsubst_enum infinish_member_declaration in the
5594 CLASSTYPE_NESTED_UTDScase above. */
5595 if (!(TREE_CODE (r) == TYPE_DECL
5596 && TREE_CODE (TREE_TYPE(r)) == ENUMERAL_TYPE
5597 && DECL_ARTIFICIAL (r)))
5598 {
5599 set_current_access_from_decl (r);
5600 finish_member_declaration(r);
5601 }
5602 }
5603 }
5604 } // if (TREE_PURPOSE (member))
5605 else
5606 {
5607 if (TYPE_P (t) || DECL_CLASS_TEMPLATE_P(t))
5608 {
5609 /* Build newCLASSTYPE_FRIEND_CLASSES. */
5610
5611 tree friend_type = t;
5612 tree new_friend_type;
5613
5614 if (TREE_CODE (friend_type) ==TEMPLATE_DECL)
5615 new_friend_type = tsubst_friend_class(friend_type, args);
5616 else if (uses_template_parms(friend_type))
5617 new_friend_type = tsubst(friend_type, args,
5618 tf_error |tf_warning, NULL_TREE);
5619 else if (CLASSTYPE_USE_TEMPLATE(friend_type))
5620 new_friend_type = friend_type;
5621 else
5622 {
5623 tree ns = decl_namespace_context (TYPE_MAIN_DECL(friend_type));
5624
5625 /* The callto xref_tag_from_type does injection for friend
5626 classes. */
5627 push_nested_namespace(ns);
5628 new_friend_type =
5629 xref_tag_from_type (friend_type,NULL_TREE, 1);
5630 pop_nested_namespace (ns);
5631 }
5632
5633 if (TREE_CODE (friend_type) ==TEMPLATE_DECL)
5634 /* Trickmake_friend_class into realizing that the friend
5635 we're adding is atemplate, not an ordinary class. It's
5636 important that we usemake_friend_class since it will
5637 perform someerror-checking and output cross-reference
5638 information. */
5639 ++processing_template_decl;
5640
5641 if (new_friend_type != error_mark_node)
5642 make_friend_class (type,new_friend_type,
5643 /*complain=*/false);
5644
5645 if (TREE_CODE (friend_type) ==TEMPLATE_DECL)
5646 --processing_template_decl;
5647 }
5648 else
5649 {
5650 /* Build newDECL_FRIENDLIST. */
5651 tree r;
5652
5653 if (TREE_CODE (t) == TEMPLATE_DECL)
5654 ++processing_template_decl;
5655 r = tsubst_friend_function (t, args);
5656 if (TREE_CODE (t) == TEMPLATE_DECL)
5657 --processing_template_decl;
5658 add_friend (type, r, /*complain=*/false);
5659 }
5660 }
5661 }
5662
5663 /* Set the file andline number information to whatever is given for
5664 the class itself. This putserror messages involving generated
5665 implicit functions at apredictable point, and the same point
5666 that would be used fornon-template classes. */
5667 typedecl = TYPE_MAIN_DECL (type);
5668 input_location = DECL_SOURCE_LOCATION (typedecl);
5669
5670 unreverse_member_declarations(type);
5671 finish_struct_1(type);
注意到在该类中声明的成员被CLASSTYPE_DECL_LIST域以tree_list节点的形式记录起来。在这些tree_list节点中,TREE_PURPOSE域记录了其所属的类(如果是友元声明则是NULL),而TREE_VALUE域保存了声明本身。
在前面的章节中看到,在模板类中声明的实体亦被视为模板声明,连同产生TEMPLATE_DECL。在具现的过程中,模板实参将替换模板形参。
5.12.5.2.2.2.1.3.4. 完成派生类的RECORD_TYPE – 修正内联方法
因为模板类的具现对应的RECORD_TYPE是一个普通的类,在5671行必须调用finish_struct_1来完成其定义。
4997 void
4998 finish_struct_1 (tree t) in class.c
4999 {
5001 tree x;
5002 /* A TREE_LIST. TheTREE_VALUE of each node is a FUNCTION_DECL. */
5003 tree virtuals = NULL_TREE;
5004 int n_fields = 0;
5005 tree vfield;
5006
5007 if (COMPLETE_TYPE_P (t))
5008 {
5009 if (IS_AGGR_TYPE (t))
5010 error ("redefinition of `%#T'",t);
5011 else
5012 abort ();
5013 popclass ();
5014 return;
5015 }
5016
5017 /* If this type waspreviously laid out as a forward reference,
5018 make sure we lay it outagain. */
5019 TYPE_SIZE (t) = NULL_TREE;
5020 CLASSTYPE_PRIMARY_BINFO (t) = NULL_TREE;
5021
5022 fixup_inline_methods(t);
5023
5024 /* Make assumptionsabout the class; we'll reset the flags if
5025 necessary. */
5026 CLASSTYPE_EMPTY_P (t) = 1;
5027 CLASSTYPE_NEARLY_EMPTY_P (t) = 1;
5028 CLASSTYPE_CONTAINS_EMPTY_CLASS_P (t) = 0;
5029
5030 /* Do end-of-classsemantic processing: checking the validity of the
5031 bases and members and addimplicitly generated methods. */
5032 check_bases_and_members(t);
同样,记得对于内联方法,在对应的FUNCTION_DECL节点中,其template_info域填充有模板信息。上面的成员替换为成员正确地进行了实参替换,但是某些关系尚未相应地更新。
4323 static void
4324 fixup_inline_methods (tree type) in class.
4325 {
4326 tree method = TYPE_METHODS (type);
4327
4328 if (method && TREE_CODE (method) ==TREE_VEC)
4329 {
4330 if (TREE_VEC_ELT (method, 1))
4331 method = TREE_VEC_ELT (method, 1);
4332 else if (TREE_VEC_ELT (method, 0))
4333 method = TREE_VEC_ELT (method, 0);
4334 else
4335 method = TREE_VEC_ELT (method, 2);
4336 }
4337
4338 /* Do inline memberfunctions. */
4339 for (;method; method = TREE_CHAIN (method))
4340 fixup_pending_inline(method);
4341
4342 /* Do friends. */
4343 for (method =CLASSTYPE_INLINE_FRIENDS (type);
4344 method;
4345 method = TREE_CHAIN (method))
4346 fixup_pending_inline (TREE_VALUE (method));
4347 CLASSTYPE_INLINE_FRIENDS (type) = NULL_TREE;
4348 }
记得内联方法的函数体被缓存在DECL_PENDING_INLINE_INFO中。在具现时,内联方法的实参已经被替换入其函数体,但其context域并未触及,在完成替换后,需要为内联方法将其更新(构建的新节点)。
4306 static void
4307 fixup_pending_inline (tree fn) in class.
4308 {
4309 if (DECL_PENDING_INLINE_INFO (fn))
4310 {
4311 tree args = DECL_ARGUMENTS (fn);
4312 while(args)
4313 {
4314 DECL_CONTEXT (args) = fn;
4315 args = TREE_CHAIN (args);
4316 }
4317 }
4318 }
5.12.5.2.2.2.1.3.5. 完成派生类的RECORD_TYPE – 验证基类
在这一点上,基类及成员的实参替换被恰当地完成了,不过没有对模板的具现进行类级别的语义检查。这个语义检查应尽快进行。这里就是尽早执行语义检查的点。
4145 static void
4146 check_bases_and_members (tree t) in class.c
4147 {
4148 /* Nonzero if weare not allowed to generate a default constructor
4149 for this case. */
4150 int cant_have_default_ctor;
4151 /* Nonzero if theimplicitly generated copy constructor should take
4152 a non-const reference argument. */
4153 int cant_have_const_ctor;
4154 /* Nonzero if thethe implicitly generated assignment operator
4155 should take a non-constreference argument. */
4156 int no_const_asn_ref;
4157 tree access_decls;
4158
4159 /* By default, weuse const reference arguments and generate default
4160 constructors. */
4161 cant_have_default_ctor = 0;
4162 cant_have_const_ctor = 0;
4163 no_const_asn_ref = 0;
4164
4165 /* Check all thebase-classes. */
4166 check_bases (t,&cant_have_default_ctor, &cant_have_const_ctor,
4167 &no_const_asn_ref);
如果模板类包含(派生)基类(记得基类也可以是模板类,比如我们的“SmallObject”),是时候检查派生类与基类间是否有不符合的地方。
1109 static void
1110 check_bases (tree t, in class.c
1111 int* cant_have_default_ctor_p,
1112 int* cant_have_const_ctor_p,
1113 int* no_const_asn_ref_p)
1114 {
1115 int n_baseclasses;
1116 int i;
1117 int seen_non_virtual_nearly_empty_base_p;
1118 tree binfos;
1119
1120 binfos = TYPE_BINFO_BASETYPES (t);
1121 n_baseclasses = CLASSTYPE_N_BASECLASSES (t);
1122 seen_non_virtual_nearly_empty_base_p = 0;
1123
1124 /* An aggregatecannot have baseclasses. */
1125 CLASSTYPE_NON_AGGREGATE (t) |= (n_baseclasses != 0);
1126
1127 for (i = 0; i < n_baseclasses; ++i)
1128 {
1129 tree base_binfo;
1130 tree basetype;
1131
1132 /* Figure outwhat base we're looking at. */
1133 base_binfo = TREE_VEC_ELT (binfos, i);
1134 basetype = TREE_TYPE (base_binfo);
1135
1136 /* If the type ofbasetype is incomplete, then we already
1137 complained about that fact(and we should have fixed it up as
1138 well). */
1139 if (!COMPLETE_TYPE_P (basetype))
1140 {
1141 int j;
1142 /* The basetype is of incomplete type. It is
1143 probably best to pretendthat it does not
1144 exist. */
1145 if (i == n_baseclasses-1)
1146 TREE_VEC_ELT (binfos, i) = NULL_TREE;
1147 TREE_VEC_LENGTH (binfos) -= 1;
1148 n_baseclasses -= 1;
1149 for (j = i; j+1 < n_baseclasses; j++)
1150 TREE_VEC_ELT (binfos, j) = TREE_VEC_ELT (binfos, j+1);
1151 continue;
1152 }
1153
1154 /* Effective C++rule 14. We only need to check TYPE_POLYMORPHIC_P
1155 here because the case ofvirtual functions but non-virtual
1156 dtor is handled infinish_struct_1. */
1157 if (warn_ecpp && ! TYPE_POLYMORPHIC_P(basetype)
1158 && TYPE_HAS_DESTRUCTOR(basetype))
1159 warning ("base class `%#T' has anon-virtual destructor",
1160 basetype);
1161
1162 /* If the baseclass doesn't have copy constructors or
1163 assignment operators thattake const references, then the
1164 derived class cannot havesuch a member automatically
1165 generated. */
1166 if (! TYPE_HAS_CONST_INIT_REF (basetype))
1167 *cant_have_const_ctor_p = 1;
1168 if (TYPE_HAS_ASSIGN_REF (basetype)
1169 && !TYPE_HAS_CONST_ASSIGN_REF(basetype))
1170 *no_const_asn_ref_p = 1;
1171 /* Similarly, ifthe base class doesn't have a default
1172 constructor, then the derivedclass won't have an
1173 automatically generateddefault constructor. */
1174 if (TYPE_HAS_CONSTRUCTOR (basetype)
1175 && !TYPE_HAS_DEFAULT_CONSTRUCTOR (basetype))
1176 {
1177 *cant_have_default_ctor_p = 1;
1178 if (! TYPE_HAS_CONSTRUCTOR (t))
1179 pedwarn ("base`%T' with only non-default constructor in class without a constructor",
1180 basetype);
1181 }
1182
1183 if (TREE_VIA_VIRTUAL (base_binfo))
1184 /* A virtualbase does not effect nearly emptiness. */
1185 ;
1186 else if (CLASSTYPE_NEARLY_EMPTY_P(basetype))
1187 {
1188 if (seen_non_virtual_nearly_empty_base_p)
1189 /* And ifthere is more than one nearly empty base, then the
1190 derived class is not nearly empty either. */
1191 CLASSTYPE_NEARLY_EMPTY_P (t) = 0;
1192 else
1193 /* Rememberwe've seen one. */
1194 seen_non_virtual_nearly_empty_base_p =1;
1195 }
1196 else if (!is_empty_class (basetype))
1197 /* If the baseclass is not empty or nearly empty, then this
1198 class cannot be nearlyempty. */
1199 CLASSTYPE_NEARLY_EMPTY_P (t) = 0;
1200
1201 /* A lot ofproperties from the bases also apply to the derived
1202 class. */
1203 TYPE_NEEDS_CONSTRUCTING(t) |= TYPE_NEEDS_CONSTRUCTING (basetype);
1204 TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
1205 |= TYPE_HAS_NONTRIVIAL_DESTRUCTOR(basetype);
1206 TYPE_HAS_COMPLEX_ASSIGN_REF (t)
1207 |= TYPE_HAS_COMPLEX_ASSIGN_REF (basetype);
1208 TYPE_HAS_COMPLEX_INIT_REF(t) |= TYPE_HAS_COMPLEX_INIT_REF (basetype);
1209 TYPE_POLYMORPHIC_P (t) |=TYPE_POLYMORPHIC_P (basetype);
1210 CLASSTYPE_CONTAINS_EMPTY_CLASS_P (t)
1211 |= CLASSTYPE_CONTAINS_EMPTY_CLASS_P(basetype);
1212 }
1213 }
在该次调用的实参中,cant_have_default_ctor是非0值,如果基类没有缺省构造函数;cant_have_const_ctor是非0值,如果基类没有使用引用常量的拷贝构造函数,而no_const_asn_ref是非0值,如果基类没有使用引用常量的赋值操作符。
- GCC-3.4.6源代码学习笔记(135)
- GCC-3.4.6源代码学习笔记 (100)
- GCC-3.4.6源代码学习笔记 (101)
- GCC-3.4.6源代码学习笔记 (102)
- GCC-3.4.6源代码学习笔记 (103)
- GCC-3.4.6源代码学习笔记 (104)
- GCC-3.4.6源代码学习笔记 (105)
- GCC-3.4.6源代码学习笔记 (106)
- GCC-3.4.6源代码学习笔记(166)
- GCC-3.4.6源代码学习笔记
- GCC-3.4.6源代码学习笔记(6)
- GCC-3.4.6源代码学习笔记(1)
- GCC-3.4.6源代码学习笔记(2)
- GCC-3.4.6源代码学习笔记(3)
- GCC-3.4.6源代码学习笔记(4)
- GCC-3.4.6源代码学习笔记(5)
- GCC-3.4.6源代码学习笔记(7)
- GCC-3.4.6源代码学习笔记(8)
- [转]高效存储技术研究
- mac.Eclipse编码utf-8和php语法高亮。
- dojo之ValidationTextbox
- maven 常用命令和plugin
- 按着步骤来,学习Android NDK入门很简单
- GCC-3.4.6源代码学习笔记(135)
- arduino基本知识
- 实现无session集群的负载均衡
- 近期项目总结之随机数
- 运行时动态创建报表(二)他山之石
- Linux内核设计与实现读书笔记(6)-下半部和推后执行的工作
- Studying note of GCC-3.4.6 source (135)
- 参数传递
- 小儿科备忘一下