这里要解释一下什么是 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 ,同时如果没有找到虚拟的派生类,则进一步检查是否有虚拟主要基类。如果找到虚拟主要基类,这意味着以下的类结构:
而如果找到了派生的虚拟基类,类结构则如下:
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 ,则表示该类需要非平凡的析构函数。一个析构函数是平凡的,如果它是一个隐含声明的析构函数(即用户未声明),并且如果:
- 类的所有直接基类都具有平凡析构函数,
- 类的所有非静态数据成员都是类类型(或者类类型的数组),每个类具有平凡析构函数。