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

来源:互联网 发布:sql 的not in中的为空 编辑:程序博客网 时间:2024/06/03 19:28

5.12.5.2.2.2.1.3.2.           具现基类——完成

在处理完所有的基类后(基类被串接起来),在instantiate_class_template5452行,调用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值,如果基类没有使用引用常量的赋值操作符。

 

原创粉丝点击