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

这里要解释一下什么是 thunk 。下面的段落摘自 GCC 源代码中的注释。

Thunk 是一个普通 FUNCTION_DECL 的一个替代入口( an alternate entry )。普通 FUNCTION_DECL 的地址由 DECL_INITIAL 给出,它总是一个操作数是一个 FUNCTION_DECL ADDR_EXPR 。这个 thunk 的任务是,或者在把控制权转给这个 FUNCTION_DECL 之前调整相应的 this 指针,或者调用 FUNCTION_DECL 并且调整返回的值。注意,结果指针调整 thunk 必须执行对被 thunk 函数的一次调用,(或者通过向被 thunk 函数传入一些不可见的参数,使函数返回前执行调整,来实现)。

Thunk 可能执行以下某个,或所有的操作:

Ÿ           调整 this 或者结果指针一个偏移常量。

Ÿ           通过在 vtable 中查找的 vcall vbase 偏移,调整 this 或者结果指针。

一个 this 指针调整 thunk 把基类转换到派生类,因而加上偏移。一个结果指针调整 thunk 把派生类转换到基类,因而减去偏移。如果要执行这两个操作,那么首先为 this 指针执行调整,最后执行结果指针调整。

这个调整常量由 THUNK_FIXED_OFFSET 给出。如果要求 vcall vbase 偏移,就使用 THUNK_VIRTUAL_OFFSET 。对于 this 指针调整 thunk ,它是进入 vtable vcall 偏移。对于结果指针调整 thunk ,它是要转换到的虚拟基类的 binfo 。使用这个 binfo vbase 偏移。

可以有等效的协变( equivalent covariant thunk 。这些是各自不同的虚拟协变( virtual covariant thunk ,它们的 vbase 偏移恰好具有相同的值。 THUNK_ALIAS 被用来选出规范的 thunk ,它上面将附着所有这个 this 指针的调整 thunk

考虑以下例子:

A *pc = new C;

pc->f();

记住这里有一个隐含的“ const this* ”参数,而对于上面的 f ,这个隐含的参数是“ const C* ”;不过被用作隐含参数的 pc 被声明作 A* ,编译器需要把 pc 调整为“ const C* ”。这里需要 thunk ,因为 A 是虚拟基类,正如我们在之前章节看到的,虚拟基类通常布置在类的末尾,除非它是主要基类。这意味着虚拟基类在派生类中可能有不同的偏移。后面我们将看到对于非虚拟的主要基类(它必须含有 vtable ),就没有这样的麻烦,因为这个基类总是布置在派生类中偏移为 0 的位置。

2131 行的 virtual_offset NULL 的情形下,这意味着定义 fn 的基类没有虚拟基类。那么进一步通过 same_type_ignoring_top_level_qualifiers_p 检查两个函数返回值的类型是否相同,这个函数比较两个类型的主要变体( TYPE_MAIN_VARIANT ),即忽略 cv- 限定词。如果这两个类型不是相同的,派生类( over_return )的虚函数返回的类型必须派生自基类( base_return )的虚函数返回的类型。这种情形要求结果调整 thunk 。因此在 2164 行的 FOR 循环确认 base_return over_return 的基类。如果属实,接着检查 base_return 是否还是某个虚拟基类的基类。

现在如果 base_return 是在某个虚拟基类的基类(那么 thunk_binfo 被包含在 virtual_offset ) ,或者它不是在派生类的头部;要相应计算 fixed_offset 。注意到在通过 layout_class_type 的处理后,所有的 BINFO_OFFSET 都是从当前类的开头开始计算。

现在对于 A B1::f ,在 2130 2131 行获得的 fixed_offset 0 ),及 virtual_offset A )都不是 NULL 。那么 2131 行的 virtual_offset 被更新为类 C 中的 A (参见 copy_base_binfos CLASSTYPE_VBASECLASSES 的扩展)。

如果 fixed_offset virtual_offset 是所期望的,由 2206 make_thunk 的准备一个 thunk this_adjusting 表示这是一个 this 指针还是结果指针调整 thunk 。注意到这里构建的 thunk 是一个结果指针调整 thunk

 

100    tree

101    make_thunk (tree function, bool this_adjusting,                                          in method.c

102               tree fixed_offset, tree virtual_offset)

103    {

104      HOST_WIDE_INT d;

105      tree thunk;

106     

107      my_friendly_assert (TREE_CODE (function) == FUNCTION_DECL, 20021025);

108      /* We can have this thunks to covariant thunks, but not vice versa.  */

109      my_friendly_assert (!DECL_THIS_THUNK_P (function), 20021127);

110       my_friendly_assert (!DECL_RESULT_THUNK_P (function) || this_adjusting,

111                       20031123);

112      

113       /* Scale the VIRTUAL_OFFSET to be in terms of bytes.  */

114       if (this_adjusting && virtual_offset)

115          virtual_offset

116           = size_binop (MULT_EXPR,

117                    virtual_offset,

118                    convert (ssizetype,

119                            TYPE_SIZE_UNIT (vtable_entry_type)));

120     

121      d = tree_low_cst (fixed_offset, 0);

122     

123      /* See if we already have the thunk in question. For this_adjusting

124        thunks VIRTUAL_OFFSET will be an INTEGER_CST, for covariant thunks it

125        will be a BINFO.  */

126      for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk))

127        if (DECL_THIS_THUNK_P (thunk) == this_adjusting

128           && THUNK_FIXED_OFFSET (thunk) == d

129           && !virtual_offset == !THUNK_VIRTUAL_OFFSET (thunk)

130           && (!virtual_offset

131                || (this_adjusting

132                    ? tree_int_cst_equal (THUNK_VIRTUAL_OFFSET (thunk),

133                                     virtual_offset)

134                    : THUNK_VIRTUAL_OFFSET (thunk) == virtual_offset)))

135          return thunk;

136     

137      /* All thunks must be created before FUNCTION is actually emitted;

138        the ABI requires that all thunks be emitted together with the

139        function to which they transfer control.  */

140      my_friendly_assert (!TREE_ASM_WRITTEN (function), 20021025);

141      /* Likewise, we can only be adding thunks to a function declared in

142         the class currently being laid out.  */

143      my_friendly_assert (TYPE_SIZE (DECL_CONTEXT (function))

144                       && TYPE_BEING_DEFINED (DECL_CONTEXT (function)),

145                       20031211);

146   

147      thunk = build_decl (FUNCTION_DECL, NULL_TREE, TREE_TYPE (function));

148      DECL_LANG_SPECIFIC (thunk) = DECL_LANG_SPECIFIC (function);

149      cxx_dup_lang_specific_decl (thunk);

150      DECL_THUNKS (thunk) = NULL_TREE;

151     

152      DECL_CONTEXT (thunk) = DECL_CONTEXT (function);

153      TREE_READONLY (thunk) = TREE_READONLY (function);

154      TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (function);

155      TREE_PUBLIC (thunk) = TREE_PUBLIC (function);

156      if (flag_weak )

157        comdat_linkage (thunk);

158      SET_DECL_THUNK_P (thunk, this_adjusting);

159      THUNK_TARGET (thunk) = function;

160      THUNK_FIXED_OFFSET (thunk) = d;

161      THUNK_VIRTUAL_OFFSET (thunk) = virtual_offset;

162      THUNK_ALIAS (thunk) = NULL_TREE;

163     

164      /* The thunk itself is not a constructor or destructor, even if

165        the thing it is thunking to is.  */

166      DECL_INTERFACE_KNOWN (thunk) = 1;

167      DECL_NOT_REALLY_EXTERN (thunk) = 1;

168      DECL_SAVED_FUNCTION_DATA (thunk) = NULL;

169      DECL_DESTRUCTOR_P (thunk) = 0;

170      DECL_CONSTRUCTOR_P (thunk) = 0;

171      /* And neither is it a clone.  */

172      DECL_CLONED_FUNCTION (thunk) = NULL_TREE;

173      DECL_EXTERNAL (thunk) = 1;

174      DECL_ARTIFICIAL (thunk) = 1;

175      /* Even if this thunk is a member of a local class, we don't

176        need a static chain.  */

177      DECL_NO_STATIC_CHAIN (thunk) = 1;

178      /* The THUNK is not a pending inline, even if the FUNCTION is.  */

179      DECL_PENDING_INLINE_P (thunk) = 0;

180      DECL_INLINE (thunk) = 0;

181      DECL_DECLARED_INLINE_P (thunk) = 0;

182      /* Nor has it been deferred.  */

183      DECL_DEFERRED_FN (thunk) = 0;

184     

185      /* Add it to the list of thunks associated with FUNCTION.  */

186      TREE_CHAIN (thunk) = DECL_THUNKS (function);

187      DECL_THUNKS (function) = thunk;

188   

189      return thunk;

190    }

 

Thunk 本身是一个 FUNCTION_DECL 。注意到它是匿名而且是“人造的”。而代表固定偏移( fixed offset )的值被保存在 THUNK_FIXED_OFFSET 中。另外,这个 thunk 被应用到指定的虚函数(更准确一些,返回类型);它被链接入虚函数节点的 DECL_THUNKS

记得下面的 b 是由 get_primary_binfo 得到的,定义了指定函数的派生程度最高的主要基类,在我们的例子中是 C B1 binfo 。在 2218 行的 FOR 循环派生自当前类中 b 的派生程度最高的虚拟基类,如果存在这样的基类的话。这里我们得到的 virtual_base NULL 。看到在 2236 行,如果 overrider_fn 不等于 overrider_target ,这表示存在用于重载函数的一个 thunk ,同时如果没有找到虚拟的派生类,则进一步检查是否有虚拟主要基类。如果找到虚拟主要基类,这意味着以下的类结构:

t1

而如果找到了派生的虚拟基类,类结构则如下:

t2

Thunk 由上面的代码产生,并且 delta vcall offset 由下面的代码确定。对于我们的例子 A 中的带有 thunk B::f 2236 行的条件不满足。 delta 将是 0 C – A )。

 

update_vtable_entry_for_fn (continue)

 

2212     /* Assume that we will produce a thunk that convert all the way to

2213       the final overrider, and not to an intermediate virtual base.  */

2214     virtual_base = NULL_TREE;

2215  

2216     /* See if we can convert to an intermediate virtual base first, and then

2217       use the vcall offset located there to finish the conversion.  */

2218     for (; b; b = BINFO_INHERITANCE_CHAIN (b))

2219     {

2220       /* If we find the final overrider, then we can stop

2221         walking.  */

2222       if (same_type_p (BINFO_TYPE (b),

2223                      BINFO_TYPE (TREE_VALUE (overrider))))

2224         break ;

2225  

2226       /* If we find a virtual base, and we haven't yet found the

2227          overrider, then there is a virtual base between the

2228          declaring base (first_defn) and the final overrider.  */

2229       if (TREE_VIA_VIRTUAL (b))

2230       {

2231          virtual_base = b;

2232          break ;

2233       }

2234     }

2235  

2236     if (overrider_fn != overrider_target && !virtual_base)

2237     {

2238       /* The ABI specifies that a covariant thunk includes a mangling

2239          for a this pointer adjustment. This-adjusting thunks that

2240          override a function from a virtual base have a vcall

2241          adjustment. When the virtual base in question is a primary

2242          virtual base, we know the adjustments are zero, (and in the

2243         non-covariant case, we would not use the thunk).

2244          Unfortunately we didn't notice this could happen, when

2245          designing the ABI and so never mandated that such a covariant

2246          thunk should be emitted. Because we must use the ABI mandated

2247          name, we must continue searching from the binfo where we

2248          found the most recent definition of the function, towards the

2249          primary binfo which first introduced the function into the

2250          vtable. If that enters a virtual base, we must use a vcall

2251          this-adjusting thunk. Bleah! */

2252       tree probe = first_defn;

2253  

2254       while ((probe = get_primary_binfo (probe))

2255             && (unsigned) list_length (BINFO_VIRTUALS (probe)) > ix)

2256         if (TREE_VIA_VIRTUAL (probe))

2257           virtual_base = probe;

2258        

2259       if (virtual_base)

2260         /* Even if we find a virtual base, the correct delta is

2261            between the overrider and the binfo we're building a vtable

2262            for.  */

2263         goto virtual_covariant;

2264     }

2265    

2266     /* Compute the constant adjustment to the `this' pointer. The

2267      `this' pointer, when this function is called, will point at BINFO

2268      (or one of its primary bases, which are at the same offset).  */

2269     if (virtual_base)

2270        /* The `this' pointer needs to be adjusted from the declaration to

2271         the nearest virtual base.  */

2272       delta = size_diffop (convert (ssizetype, BINFO_OFFSET (virtual_base)),

2273                        convert (ssizetype, BINFO_OFFSET (first_defn)));

2274     else if (lost)

2275       /* If the nearest definition is in a lost primary, we don't need an

2276         entry in our vtable. Except possibly in a constructor vtable,

2277         if we happen to get our primary back. In that case, the offset

2278         will be zero, as it will be a primary base.  */

2279       delta = size_zero_node;

2280     else

2281        /* The `this' pointer needs to be adjusted from pointing to

2282         BINFO to pointing at the base where the final overrider

2283         appears.  */

2284   virtual_covariant:

2285       delta = size_diffop (convert (ssizetype,

2286                        BINFO_OFFSET (TREE_VALUE (overrider))),

2287                        convert (ssizetype, BINFO_OFFSET (binfo)));

2288  

2289     modify_vtable_entry (t, binfo, overrider_fn, delta, virtuals);

2290  

2291     if (virtual_base)

2292       BV_VCALL_INDEX (*virtuals)

2293         = get_vcall_index (overrider_target, BINFO_TYPE (virtual_base));

2294   }

 

对于虚拟基类,在构建派生程度最高的类的 vtable 时(参见下一节 VTT 的构建),有一入口称作 vcall 偏移( vcall offset )的,记录了从虚拟基类到最后定义重载的类的偏移。这个偏移将也被虚函数用来调整 this 指针,它被保存入 BV_VCALL_INDEX 域。

2293 行, get_vcall_index 检查并获取这个 vcall 偏移,它被保存在该虚拟基类对应类型 binfo CLASSTYPE_VCALL_INDICES 域(这个数据由下一节中的 finish_vtbls 产生)。

 

2051   static tree

2052   get_vcall_index (tree fn, tree type)                                                            in class.c

2053   {

2054     tree v;

2055  

2056     for (v = CLASSTYPE_VCALL_INDICES (type); v; v = TREE_CHAIN (v))

2057       if ((DECL_DESTRUCTOR_P (fn) && DECL_DESTRUCTOR_P (TREE_PURPOSE (v)))

2058          || same_signature_p (fn, TREE_PURPOSE (v)))

2059         break ;

2060  

2061     /* There should always be an appropriate index.  */

2062     my_friendly_assert (v, 20021103);

2063  

2064     return TREE_VALUE (v);

2065   }

 

记得在 2274 行的 lost 仅能在包含虚拟主要基类的基类中出现,这个虚拟基类也被用作当前类的主要基类,因此其偏移为 0 。而 modify_vtable_entry 把这个调整量记录在 BV_DELTA 。特别地,这里的参数 fndecl update_vtable_entry_for_fn 中的 overrider_fn ,它是最后出现的重载。看到它被填入定义了该虚函数的基类的相应的 vtable 入口,以确保正确的函数能得到调用。

 

683    static void

684    modify_vtable_entry (tree t,                                                                     in class.c

685                      tree binfo,

686                      tree fndecl,

687                      tree delta,

688                      tree *virtuals)

689    {

690      tree v;

691   

692      v = *virtuals;

693   

694      if (fndecl != BV_FN (v)

695          || !tree_int_cst_equal (delta, BV_DELTA (v)))

696      {

697        /* We need a new vtable for BINFO.  */

698        if (make_new_vtable (t, binfo))

699        {

700          /* If we really did make a new vtable, we also made a copy

701            of the BINFO_VIRTUALS list. Now, we have to find the

702            corresponding entry in that list.  */

703          *virtuals = BINFO_VIRTUALS (binfo);

704          while (BV_FN (*virtuals) != BV_FN (v))

705            *virtuals = TREE_CHAIN (*virtuals);

706          v = *virtuals;

707        }

708   

709        BV_DELTA (v) = delta;

710        BV_VCALL_INDEX (v) = NULL_TREE;

711         BV_FN (v) = fndecl;

712      }

713    }

 

如果 694 行的条件满足,这意味着 fndecl 是重载函数或者 thunk ;而如果 695 行条件满足,这表示需要更新其 BV_DETLA 。这三种情况( 694 695 行条件同时成立)意味着需要更新 vtable 中对应的项,首先看一下必须的 vtable 是否准备好了。如果 vtable 之前已经准备好了,这个 binfo 设置 BINFO_NEW_VTABLE_MARKED 标记,而 make_new_vtable 将返回 0 。对于我们的例子类 C ,它将会进入这个函数 3 次,依次是 A B2 C 。它们都在 dfs_modify_vtables 中调用过 make_new_vtable ,而且参数 virtuals 就是来自对应基类的 binfo ,因此只要直接更新就可以。同时注意到 find_final_overrider 会检查是否存在二义性,比如,在 C 中移走,通过 C 调用 f 将导致二义性。

处理了基类 A 之后,接着在 modify_all_vtables 中的 dfs_walk ,攀升到 B1 (因为我们依照 C à B1 à A )。因为 B1 是一个非虚拟的主要基类, dfs_modify_vtables 跳过了它(注意到,结果没有调用 make_new_vtable ,而 binfo BINFO_NEW_VTABLE_MARKED 没有设置)。接着下一个对象是 B2 ,这个基类的处理与我们已经看到的相似。最后轮到 C 。记得 BINFO_VIRTUALS (C) 包含的带有 thunk B1::f ,与 C 里的 A 所包含的 B1::f 是一样的,后面跟着 B1::f 。这里对于这个 B1::f 得到与 C A B1::f 一样,为带有 thunk virual-offset C A fix-offset 0 )的 C::f delta 0 )。然后对于接着的 B1::f ,将得到不带 thunk C::f ,因为 B1 C 的非虚拟主要基类。

从遍历退出后,记得 virtuals C TYPE_METHOD 获取其内容,即: C::f 。而现在在 BINFO_VIRTUALS (C) 里是: 1 C::f ,具有 thunk virtual-offset C 中的 A fix-offset 0 ); 2 C::f 。因此在 modify_all_vtables 中, C::f virtuals 中移去, virtuals 现在是空的。

 

finish_struct_1 (continue)

 

5081     /* If necessary, create the primary vtable for this class.  */

5082     if (virtuals || TYPE_CONTAINS_VPTR_P (t))

5083     {

5084        /* We must enter these virtuals into the table.  */

5085       if (!CLASSTYPE_HAS_PRIMARY_BASE_P (t))

5086         build_primary_vtable (NULL_TREE, t);

5087       else if (! BINFO_NEW_VTABLE_MARKED (TYPE_BINFO (t)))

5088         /* Here we know enough to change the type of our virtual

5089           function table, but we will wait until later this function.  */

5090         build_primary_vtable (CLASSTYPE_PRIMARY_BINFO (t), t);

5091     }

5092  

5093     if (TYPE_CONTAINS_VPTR_P (t))

5094     {

5095       int vindex;

5096       tree fn;

5097  

5098       if (TYPE_BINFO_VTABLE (t))

5099         my_friendly_assert (DECL_VIRTUAL_P (TYPE_BINFO_VTABLE (t)),

5100                          20000116);

5101       if (!CLASSTYPE_HAS_PRIMARY_BASE_P (t))

5102         my_friendly_assert (TYPE_BINFO_VIRTUALS (t) == NULL_TREE,

5103                          20000116);

5104  

5105       /* Add entries for virtual functions introduced by this class.  */

5106       TYPE_BINFO_VIRTUALS (t) = chainon (TYPE_BINFO_VIRTUALS (t), virtuals);

5107  

5108       /* Set DECL_VINDEX for all functions declared in this class.  */

5109       for (vindex = 0, fn = BINFO_VIRTUALS (TYPE_BINFO (t));

5110            fn;

5111            fn = TREE_CHAIN (fn),

5112                vindex += (TARGET_VTABLE_USES_DESCRIPTORS

5113                          ? TARGET_VTABLE_USES_DESCRIPTORS : 1))

5114       {

5115         tree fndecl = BV_FN (fn);

5116  

5117         if (DECL_THUNK_P (fndecl))

5118           /* A thunk. We should never be calling this entry directly

5119             from this vtable -- we'd use the entry for the non

5120             thunk base function.  */

5121           DECL_VINDEX (fndecl) = NULL_TREE;

5122         else if (TREE_CODE (DECL_VINDEX (fndecl)) != INTEGER_CST)

5123           DECL_VINDEX (fndecl) = build_shared_int_cst (vindex);

5124       }

5125     }

5126  

5127     finish_struct_bits (t);

 

那么在 finish_struct_1 5106 行, virtuals 是生存下来的,声明在类 t 的虚函数。把它们添加到 TYPE_BINFO_VIRTUALS 中,形成完整的列表。

5112 行,如果在 vtable 的项里使用的是函数描述符( function descriptor ),就会定义 TARGET_VTABLE_USES_DESCRIPTORS ,它表示了描述符的字大小(通常是 2 )。默认的, C++ 编译器在 vtable 项里使用函数地址。直到现在 DECL_VINDEX 依然指向,这个 FUNCTION_DECL 作为虚函数,将要替换的一个基类中的 FUNCTION_DECL 。是时候把这个指针换作 INTEGER_CST 了。在 GCC 中,小于 256 的整形常量都是共享的,它们保存在全局数组 shared_int_cache 里。

 

1409   static void

1410   finish_struct_bits (tree t)                                                                          in class.c

1411   {

1412     int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (t);

1413  

1414     /* Fix up variants (if any).  */

1415     tree variants = TYPE_NEXT_VARIANT (t);

1416     while (variants)

1417     {

1418       /* These fields are in the _TYPE part of the node, not in

1419         the TYPE_LANG_SPECIFIC component, so they are not shared.  */

1420       TYPE_HAS_CONSTRUCTOR (variants) = TYPE_HAS_CONSTRUCTOR (t);

1421       TYPE_HAS_DESTRUCTOR (variants) = TYPE_HAS_DESTRUCTOR (t);

1422       TYPE_NEEDS_CONSTRUCTING (variants) = TYPE_NEEDS_CONSTRUCTING (t);

1423       TYPE_HAS_NONTRIVIAL_DESTRUCTOR (variants)

1424            = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t);

1425  

1426       TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (variants)

1427            = TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (t);

1428       TYPE_POLYMORPHIC_P (variants) = TYPE_POLYMORPHIC_P (t);

1429       TYPE_USES_VIRTUAL_BASECLASSES (variants) = TYPE_USES_VIRTUAL_BASECLASSES (t);

1430       /* Copy whatever these are holding today.  */

1431       TYPE_MIN_VALUE (variants) = TYPE_MIN_VALUE (t);

1432       TYPE_MAX_VALUE (variants) = TYPE_MAX_VALUE (t);

1433       TYPE_FIELDS (variants) = TYPE_FIELDS (t);

1434       TYPE_SIZE (variants) = TYPE_SIZE (t);

1435       TYPE_SIZE_UNIT (variants) = TYPE_SIZE_UNIT (t);

1436       variants = TYPE_NEXT_VARIANT (variants);

1437     }

1438  

1439     if (n_baseclasses && TYPE_POLYMORPHIC_P (t))

1440        /* For a class w/o baseclasses, `finish_struct' has set

1441         CLASS_TYPE_ABSTRACT_VIRTUALS correctly (by

1442         definition). Similarly for a class whose base classes do not

1443         have vtables. When neither of these is true, we might have

1444         removed abstract virtuals (by providing a definition), added

1445         some (by declaring new ones), or redeclared ones from a base

1446         class. We need to recalculate what's really an abstract virtual

1447         at this point (by looking in the vtables).  */

1448       get_pure_virtuals (t);

1449  

1450     if (n_baseclasses)

1451     {

1452       /* Notice whether this class has type conversion functions defined.  */

1453       tree binfo = TYPE_BINFO (t);

1454       tree binfos = BINFO_BASETYPES (binfo);

1455       tree basetype;

1456  

1457       for (i = n_baseclasses-1; i >= 0; i--)

1458       {

1459         basetype = BINFO_TYPE (TREE_VEC_ELT (binfos, i));

1460  

1461         TYPE_HAS_CONVERSION (t) |= TYPE_HAS_CONVERSION (basetype);

1462       }

1463     }

1464  

1465     /* If this type has a copy constructor or a destructor, force its mode to

1466       be BLKmode, and force its TREE_ADDRESSABLE bit to be nonzero. This

1467       will cause it to be passed by invisible reference and prevent it from

1468       being returned in a register.  */

1469     if (! TYPE_HAS_TRIVIAL_INIT_REF (t) || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))

1470     {

1471       tree variants;

1472       DECL_MODE (TYPE_MAIN_DECL (t)) = BLKmode;

1473       for (variants = t; variants; variants = TYPE_NEXT_VARIANT (variants))

1474       {

1475         TYPE_MODE (variants) = BLKmode;

1476         TREE_ADDRESSABLE (variants) = 1;

1477       }

1478     }

1479   }

 

因为我们已经完成类的布局,可以同步不同 cv 限定词变种的节点。在 1439 行,重载了基类虚函数的类设置了 TYPE_POLYMORPHIC_P 标记。函数 get_pure_virtuals 提取了非主要基类的纯虚函数(当前派生程度最高的类也是非主要基类,它的 vtable 中包含了主要基类路径中所有重要基类的虚函数)。记得如果被重载了,纯虚函数在 update_vtable_entry_for_fn 中,与最后的重载绑定在一起。

 

1965   void

1966   get_pure_virtuals (tree type)                                                                     in search.c

1967   {

1968     tree vbases;

1969  

1970     /* Clear the CLASSTYPE_PURE_VIRTUALS list; whatever is already there

1971       is going to be overridden.  */

1972     CLASSTYPE_PURE_VIRTUALS (type) = NULL_TREE;

1973     /* Now, run through all the bases which are not primary bases, and

1974       collect the pure virtual functions. We look at the vtable in

1975       each class to determine what pure virtual functions are present.

1976       (A primary base is not interesting because the derived class of

1977       which it is a primary base will contain vtable entries for the

1978       pure virtuals in the base class.  */

1979     dfs_walk (TYPE_BINFO (type), dfs_get_pure_virtuals , unmarkedp , type);

1980     dfs_walk (TYPE_BINFO (type), dfs_unmark, markedp, type);

1981  

1982     /* Put the pure virtuals in dfs order.  */

1983     CLASSTYPE_PURE_VIRTUALS (type) = nreverse (CLASSTYPE_PURE_VIRTUALS (type));

1984  

1985     for (vbases = CLASSTYPE_VBASECLASSES (type);

1986         vbases;

1987         vbases = TREE_CHAIN (vbases))

1988     {

1989       tree virtuals;

1990  

1991       for (virtuals = BINFO_VIRTUALS (TREE_VALUE (vbases));

1992           virtuals;

1993           virtuals = TREE_CHAIN (virtuals))

1994       {

1995         tree base_fndecl = BV_FN (virtuals);

1996         if (DECL_NEEDS_FINAL_OVERRIDER_P (base_fndecl))

1997           error ("`%#D' needs a final overrider", base_fndecl);

1998       }

1999     }

2000   }

 

所有的纯虚函数被放入当前类的 CLASSTYPE_PURE_VIRTUALS 域(那么如果 CLASSTYPE_PURE_VIRTUALS 不是空,这个类型就不能实例化)。

 

1937   static tree

1938   dfs_get_pure_virtuals (tree binfo, void *data)                                             in search.c

1939   {

1940     tree type = (tree) data;

1941  

1942     /* We're not interested in primary base classes; the derived class

1943       of which they are a primary base will contain the information we

1944       need.  */

1945     if (!BINFO_PRIMARY_P (binfo))

1946     {

1947       tree virtuals;

1948        

1949       for (virtuals = BINFO_VIRTUALS (binfo);

1950           virtuals;

1951           virtuals = TREE_CHAIN (virtuals))

1952         if (DECL_PURE_VIRTUAL_P (BV_FN (virtuals)))

1953           CLASSTYPE_PURE_VIRTUALS (type)

1954               = tree_cons (NULL_TREE, BV_FN (virtuals),

1955                            CLASSTYPE_PURE_VIRTUALS (type));

1956     }

1957    

1958     BINFO_MARKED (binfo) = 1;

1959  

1960     return NULL_TREE;

1961   }

 

接下来,如果基类定义了转换操作符,那么这个转换操作符亦可用于派生类。 1469 行的 TYPE_HAS_TRIVIAL_INIT_REF 如果是非 0 值,表示可以使用按位拷贝进行拷贝操作。而 TYPE_HAS_NONTRIVIAL_DESTRUCTOR 如果非 0 ,则表示该类需要非平凡的析构函数。一个析构函数是平凡的,如果它是一个隐含声明的析构函数(即用户未声明),并且如果:

- 类的所有直接基类都具有平凡析构函数,

- 类的所有非静态数据成员都是类类型(或者类类型的数组),每个类具有平凡析构函数。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值