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

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 already issued an error.  */

153        return NULL_TREE;

154      else if (!COMPLETE_TYPE_P (type))

155      {

156        cxx_incomplete_type_diagnostic (value, type, diag_type);

157        return NULL_TREE;

158      }

159      else

160        return type;

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 our base classes are set up, enter the scope of the

5459       class, so that name lookups into base classes, etc. will work

5460       correctly. This is precisely analogous to what we do in

5461       begin_class_definition when defining an ordinary non-template

5462       class.  */

5463     pushclass (type);

5464  

5465     /* Now members are processed 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 the member is a class template, then -- even after

5486             substituition -- there may be dependent types in the

5487             template argument list for the class. We increment

5488             PROCESSING_TEMPLATE_DECL so that dependent_type_p, as

5489             that function will assume that no types are dependent

5490             when outside of a template.  */

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 class nested within a template class.)

5506                  This behavior is required for

5507                  maybe_process_partial_specialization to work

5508                  correctly, but is not accurate in this case;

5509                  the TAG is not an instantiation of anything.

5510                  (The corresponding TEMPLATE_DECL is an

5511                  instantiation, but the TYPE is not.) */

5512               CLASSTYPE_USE_TEMPLATE (newtag) = 0;

5513  

5514             /* Now, we call pushtag to put this NEWTAG into the scope of

5515               TYPE. We first set up the IDENTIFIER_TYPE_VALUE to avoid

5516               pushtag calling push_template_decl. We don't have to do

5517               this for enums because it 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 new TYPE_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 error message reporting. Since we

5549               called push_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. If R is invalid, then it is

5578                 replaced by error_mark_node so that it will not be

5579                 added to TYPE_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 is a TYPE_DECL for a class-scoped ENUMERAL_TYPE,

5592               such a thing will already have been added to the field

5593               list by tsubst_enum in finish_member_declaration in the

5594               CLASSTYPE_NESTED_UTDS case 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 new CLASSTYPE_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 call to 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             /* Trick make_friend_class into realizing that the friend

5635               we're adding is a template, not an ordinary class. It's

5636               important that we use make_friend_class since it will

5637               perform some error-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 new DECL_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 and line number information to whatever is given for

5664       the class itself. This puts error messages involving generated

5665       implicit functions at a predictable point, and the same point

5666       that would be used for non-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. The TREE_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 was previously laid out as a forward reference,

5018       make sure we lay it out again.  */

5019     TYPE_SIZE (t) = NULL_TREE;

5020     CLASSTYPE_PRIMARY_BINFO (t) = NULL_TREE;

5021  

5022     fixup_inline_methods (t);

5023    

5024     /* Make assumptions about 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-class semantic processing: checking the validity of the

5031       bases and members and add implicitly 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 member functions.  */

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 we are not allowed to generate a default constructor

4149       for this case.  */

4150     int cant_have_default_ctor;

4151     /* Nonzero if the implicitly generated copy constructor should take

4152       a non-const reference argument.  */

4153     int cant_have_const_ctor;

4154     /* Nonzero if the the implicitly generated assignment operator

4155       should take a non-const reference argument.  */

4156     int no_const_asn_ref;

4157     tree access_decls;

4158  

4159     /* By default, we use 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 the base-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 aggregate cannot 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 out what base we're looking at.  */

1133       base_binfo = TREE_VEC_ELT (binfos, i);

1134       basetype = TREE_TYPE (base_binfo);

1135  

1136       /* If the type of basetype 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 base type is of incomplete type. It is

1143           probably best to pretend that 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 of virtual functions but non-virtual

1156         dtor is handled in finish_struct_1.  */

1157       if (warn_ecpp && ! TYPE_POLYMORPHIC_P (basetype)

1158          && TYPE_HAS_DESTRUCTOR (basetype))

1159         warning ("base class `%#T' has a non-virtual destructor",

1160                  basetype);

1161  

1162       /* If the base class doesn't have copy constructors or

1163         assignment operators that take const references, then the

1164         derived class cannot have such 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, if the base class doesn't have a default

1172         constructor, then the derived class won't have an

1173         automatically generated default 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 virtual base 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 if there 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           /* Remember we've seen one.  */

1194           seen_non_virtual_nearly_empty_base_p = 1;

1195       }

1196       else if (!is_empty_class (basetype))

1197         /* If the base class is not empty or nearly empty, then this

1198           class cannot be nearly empty.  */

1199         CLASSTYPE_NEARLY_EMPTY_P (t) = 0;

1200  

1201       /* A lot of properties 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 值,如果基类没有使用引用常量的赋值操作符。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值