5.12.5.2.2.2.1.3.10. 完成派生类的 RECORD_TYPE – 构建 vtable
记得在 determine_primary_base 中,如果我们找到一个主要基类,我们只是记住它的 vtable (记住它必须有 vtable ,否则我们不会有主要基类),现在我们需要属于自己的 vtable 。注意 5057 到 5064 行的断言,它们可以帮助我们尽早地发现不一致的情况。
finish_struct_1 (continue)
5051 /* Make sure that we get our own copy of the vfield FIELD_DECL. */
5052 vfield = TYPE_VFIELD (t);
5053 if (vfield && CLASSTYPE_HAS_PRIMARY_BASE_P (t))
5054 {
5055 tree primary = CLASSTYPE_PRIMARY_BINFO (t);
5056
5057 my_friendly_assert (same_type_p (DECL_FIELD_CONTEXT (vfield),
5058 BINFO_TYPE (primary)),
5059 20010726);
5060 /* The vtable better be at the start. */
5061 my_friendly_assert (integer_zerop (DECL_FIELD_OFFSET (vfield)),
5062 20010726);
5063 my_friendly_assert (integer_zerop (BINFO_OFFSET (primary)),
5064 20010726);
5065
5066 vfield = copy_decl (vfield);
5067 DECL_FIELD_CONTEXT (vfield) = t;
5068 TYPE_VFIELD (t) = vfield;
5069 }
5070 else
5071 my_friendly_assert (!vfield || DECL_FIELD_CONTEXT (vfield) == t, 20010726);
5072
5073 virtuals = modify_all_vtables (t, nreverse (virtuals));
5074
5075 /* If we created a new vtbl pointer for this class, add it to the
5076 list. */
5077 if (TYPE_VFIELD (t) && !CLASSTYPE_HAS_PRIMARY_BASE_P (t))
5078 CLASSTYPE_VFIELDS (t)
5079 = chainon (CLASSTYPE_VFIELDS (t), build_tree_list (NULL_TREE, t));
记得上面的 virtuals 记录了 t 中的虚函数,如果有的话。但它是倒序的,所以用 nreverse 先恢复次序。注意到 t 是当前类,而且在调用 dfs_walk 时,它被传作 data 。而 virtuals 通过遍历 TYPE_METHOD 链选出虚函数来构建其内容(参见 create_vtable_ptr ),那么当前类的 binfo 的 BINFO_VIRTUAL 是什么呢?在 set_primary_base 里,当确定了主要基类时,当前类的 TYPE_BINFO_VIRTUALS 被设置为主要基类的 TYPE_BINFO_VIRTUALS ( TYPE_BINFO_VIRTUALS (t) 被定义为 BINFO_VIRTUALS (TYPE_BINFO (t)) )。那么, B1 (主要基类)的 TYPE_BINFO_VIRTUALS 又是什么呢?一开始,它从 A (参见这一节开头的例 1 和例 2 )的 TYPE_BINFO_VIRTUALS 得到其内容。
让我们回到更早一些时候,在那时类 A 正在完成。毫无疑问,一开始, A 具有空的 TYPE_BINFO_VIRTUALS 。对这个类型,下面的 dfs_modify_vtables 不做任何事,而接着 modify_all_vtables 把 A::f 返回作 virtuals 。接着回到下面的 finish_struct_1 部分,在 5086 行,通过 build_primary_vtable 为 A 构建了主 vtable ,在 5106 行其 TYPE_BINFO_VIRTUALS 包含了 A::f 。
因此,在完成 B1 时,其 TYPE_BINFO_VIRTUALS 也是包含了 A 的部分,即 A::f 。然后在下面的 dfs_modify_vtables 中的 2314 行,为 A 准备了次要的( secondary )。注意到 dfs_modify_vtables 在派生树中( B1 为根),由下至上地访问基类的 binfo ,因此第一个得到处理的是 B1 中的 A 。在后面可以看到, A::f 为 B1::f 所替代,并且带有一个 thunk 。接着处理 B1 本身, B1 的 A::f 同样被带有一个 thunk 的 B1::f 所替代( 2 个替代的地点不同,前者在 A 的次要 vtable ,后者在 B1 的主 vtable )。在下面的 modify_all_vtables ,因为 vrituals 中 B1::f 的 DECL_VINDEX 不是 error_mark_node (参见 check_for_override , error_mark_node 表示该函数不是一个重载),而现在 BINFO_VIRTUALS (B1) 包含了带 thunk 的 B1::f ,而且因为 value_member 当且仅当 fn 与链中某个实体的地址相同时返回 true ,因此在 virutals 中的 B1::f 被保留,并在 5106 添加到 B1 的 TYPE_BINFO_VIRTUALS 末尾。从而该链表中包含了带 thunk 的 B1::f ,其后是 B1::f (不带 thunk )。
现在轮到处理 C ,我们知道在 C 的 TYPE_BINFO_VIRTUALS 中,包含了带有结果指针调整 thunk 的 B1::f ,其后是 B1::f ;同样 C 持有 B1 到 binfo 的拷贝。下面我们将结合代码,仔细地查看这一过程。
2344 static tree
2345 modify_all_vtables (tree t, tree virtuals) in class.c
2346 {
2347 tree binfo = TYPE_BINFO (t);
2348 tree *fnsp;
2349
2350 /* Update all of the vtables. */
2351 dfs_walk (binfo, dfs_modify_vtables , unmarkedp , t);
2352 dfs_walk (binfo, dfs_unmark, markedp, t);
2353
2354 /* Add virtual functions not already in our primary vtable. These
2355 will be both those introduced by this class, and those overridden
2356 from secondary bases. It does not include virtuals merely
2357 inherited from secondary bases. */
2358 for (fnsp = &virtuals; *fnsp; )
2359 {
2360 tree fn = TREE_VALUE (*fnsp);
2361
2362 if (!value_member (fn, BINFO_VIRTUALS (binfo))
2363 || DECL_VINDEX (fn) == error_mark_node)
2364 {
2365 /* We don't need to adjust the `this' pointer when
2366 calling this function. */
2367 BV_DELTA (*fnsp) = integer_zero_node;
2368 BV_VCALL_INDEX (*fnsp) = NULL_TREE;
2369
2370 /* This is a function not already in our vtable. Keep it. */
2371 fnsp = &TREE_CHAIN (*fnsp);
2372 }
2373 else
2374 /* We've already got an entry for this function. Skip it. */
2375 *fnsp = TREE_CHAIN (*fnsp);
2376 }
2377
2378 return virtuals;
2379 }
函数 dfs_modfiy_vtables 在 dfs_walk 遍历派生树时,以后序次序执行。注意到该函数总是返回 NULL 来强制完整的遍历,并且在遍历过程中得到处理的是虚拟基类或非主要基类,如果当前类没有 vtable ( CLASSTYPE_VFIELDS ,它可能由 determine_primary_base 设置)也不在处理之列。对于例 1 和例 2 ,类 C , B2 和 A 在这里将被以 A , B2 ,然后 C 的次序处理。同样需要强调的是,当处理 A 时,所有的改变都发生在 C 里 A 的 binfo 拷贝中;而当处理 B2 时,改变也仅限于 C 里 B2 的 binfo 拷贝中;两者的处理实际上与 B1 的处理十分类似。下面我们只看 C 的处理过程,记住在 2319 行, C 的 BINFO_VIRTUALS 包含了带有 thunk (从 A 到 B1 的 this 指针调整( this-adjustment )及结果调整( result-adjustment ))的 B::f 。
2298 static tree
2299 dfs_modify_vtables (tree binfo, void* data) in class.c
2300 {
2301 if (/* There's no need to modify the vtable for a non-virtual
2302 primary base; we're not going to use that vtable anyhow.
2303 We do still need to do this for virtual primary bases, as they
2304 could become non-primary in a construction vtable. */
2305 (!BINFO_PRIMARY_P (binfo) || TREE_VIA_VIRTUAL (binfo))
2306 /* Similarly, a base without a vtable needs no modification. */
2307 && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
2308 {
2309 tree t = (tree) data;
2310 tree virtuals;
2311 tree old_virtuals;
2312 unsigned ix;
2313
2314 make_new_vtable (t, binfo);
2315
2316 /* Now, go through each of the virtual functions in the virtual
2317 function table for BINFO. Find the final overrider, and
2318 update the BINFO_VIRTUALS list appropriately. */
2319 for (ix = 0, virtuals = BINFO_VIRTUALS (binfo),
2320 old_virtuals = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (binfo)));
2321 virtuals;
2322 ix++, virtuals = TREE_CHAIN (virtuals),
2323 old_virtuals = TREE_CHAIN (old_virtuals))
2324 update_vtable_entry_for_fn (t,
2325 binfo,
2326 BV_FN (old_virtuals),
2327 &virtuals, ix);
2328 }
2329
2330 BINFO_MARKED (binfo) = 1;
2331
2332 return NULL_TREE;
2333 }
注意到参数 t 在过程不改变,总是指向正在完成的当前类。而 binfo 是当前访问的基类。首先,根据需要构建 vtable 。在这里为 A , B2 及 C 构建 vtable 。
658 static int
659 make_new_vtable (tree t, tree binfo) in class.c
660 {
661 if (binfo == TYPE_BINFO (t))
662 /* In this case, it is *type*'s vtable we are modifying. We start
663 with the approximation that its vtable is that of the
664 immediate base class. */
665 /* ??? This actually passes TYPE_BINFO (t), not the primary base binfo,
666 since we've updated DECL_CONTEXT (TYPE_VFIELD (t)) by now. */
667 return build_primary_vtable (TYPE_BINFO (DECL_CONTEXT (TYPE_VFIELD (t))),
668 t);
669 else
670 /* This is our very own copy of `basetype' to play with. Later,
671 we will fill in all the virtual functions that override the
672 virtual functions in these base classes which are not defined
673 by the current type. */
674 return build_secondary_vtable (binfo);
675 }
对于 A 及 B2 ,因为它们的 binfo 不同于 TYPE_BINFO (C) , build_secondary_vtable 被调用。并且因为这些 binfo 中的虚函数是从对应类的 binfo 中借来的(参见 xref_basetypes 中的 copy_base_binfos )。现在是时候拥有自己那一份了。
634 static int
635 build_secondary_vtable (tree binfo) in class.c
636 {
637 if (BINFO_NEW_VTABLE_MARKED (binfo))
638 /* We already created a vtable for this base. There's no need to
639 do it again. */
640 return 0;
641
642 /* Remember that we've created a vtable for this BINFO, so that we
643 don't try to do so again. */
644 SET_BINFO_NEW_VTABLE_MARKED (binfo);
645
646 /* Make fresh virtual list, so we can smash it later. */
647 BINFO_VIRTUALS (binfo) = copy_virtuals (binfo);
648
649 /* Secondary vtables are laid out as part of the same structure as
650 the primary vtable. */
651 BINFO_VTABLE (binfo) = NULL_TREE;
652 return 1;
653 }
BV_VCALL_INDEX 如果不是 NULL ,保存了 vtable 的索引,在该位置是调用这个虚函数时所需要的 vcall 偏移量(通过把这个值加到 this 指针上)。它需要被清除以准备重新索引。
562 static tree
563 copy_virtuals (tree binfo) in class.c
564 {
565 tree copies;
566 tree t;
567
568 copies = copy_list (BINFO_VIRTUALS (binfo));
569 for (t = copies; t; t = TREE_CHAIN (t))
570 BV_VCALL_INDEX (t) = NULL_TREE;
571
572 return copies;
573 }
而对于类 C , build_primary_vtable 被调用,因为此处的参数 binfo 就是 C 的 binfo 。记得 C 现在仍然使用其主要基类的 TYPE_BINFO_VTABLE 和 TYPE_BINFO_VIRTUALS ,现在它需要属于自己的那一份。
581 static int
582 build_primary_vtable (tree binfo, tree type) in class.c
583 {
584 tree decl;
585 tree virtuals;
586
587 decl = get_vtable_decl (type, /*complete=*/ 0);
588
589 if (binfo)
590 {
591 if (BINFO_NEW_VTABLE_MARKED (binfo))
592 /* We have already created a vtable for this base, so there's
593 no need to do it again. */
594 return 0;
595
596 virtuals = copy_virtuals (binfo);
597 TREE_TYPE (decl) = TREE_TYPE (get_vtbl_decl_for_binfo (binfo));
598 DECL_SIZE (decl) = TYPE_SIZE (TREE_TYPE (decl));
599 DECL_SIZE_UNIT (decl) = TYPE_SIZE_UNIT (TREE_TYPE (decl));
600 }
601 else
602 {
603 my_friendly_assert (TREE_TYPE (decl) == vtbl_type_node, 20000118);
604 virtuals = NULL_TREE;
605 }
606
607 #ifdef GATHER_STATISTICS
608 n_vtables += 1;
609 n_vtable_elems += list_length (virtuals);
610 #endif
611
612 /* Initialize the association list for this type, based
613 on our first approximation. */
614 TYPE_BINFO_VTABLE (type) = decl;
615 TYPE_BINFO_VIRTUALS (type) = virtuals;
616 SET_BINFO_NEW_VTABLE_MARKED (TYPE_BINFO (type));
617 return 1;
618 }
如果 vtable 已经被创建,它保存在 CLASSTYPE_VTABLES 域;否则这个域就是空的。参数 complete 如果是非 0 值,则表示完成在这个函数中创建的 vtable 的定义——通过调用 cp_finish_decl ,我们当前正在这个函数中完成模板类“ SmallObject ”具现。
539 tree
540 get_vtable_decl (tree type, int complete) in class.c
541 {
542 tree decl;
543
544 if (CLASSTYPE_VTABLES (type))
545 return CLASSTYPE_VTABLES (type);
546
547 decl = build_vtable (type, get_vtable_name (type), vtbl_type_node );
548 CLASSTYPE_VTABLES (type) = decl;
549
550 if (complete)
551 {
552 DECL_EXTERNAL (decl) = 1;
553 cp_finish_decl (decl, NULL_TREE, NULL_TREE, 0);
554 }
555
556 return decl;
557 }
Vtable 应该为该类型的所有实例共享(基类是例外,看到其 BINFO_VTABLE 在 build_secondary_vtable 中创建),因此它应该被创建为静态数据成员。上面的 get_vtable_name 获取 vtable 的修饰名(例 1 及例 2 GCC 的输出给出了修饰名的一些例子),而 vtbl_type_node 具有 vtable_entry_type 类型的数组常量类型(在 cxx_init_decl_processing 中构建)。
506 static tree
507 build_vtable (tree class_type, tree name, tree vtable_type) in class.c
508 {
509 tree decl;
510
511 decl = build_lang_decl (VAR_DECL, name, vtable_type);
512 /* vtable names are already mangled; give them their DECL_ASSEMBLER_NAME
513 now to avoid confusion in mangle_decl. */
514 SET_DECL_ASSEMBLER_NAME (decl, name);
515 DECL_CONTEXT (decl) = class_type;
516 DECL_ARTIFICIAL (decl) = 1;
517 TREE_STATIC (decl) = 1;
518 TREE_READONLY (decl) = 1;
519 DECL_VIRTUAL_P (decl) = 1;
520 DECL_ALIGN (decl) = TARGET_VTABLE_ENTRY_ALIGN;
521 DECL_VTABLE_OR_VTT_P (decl) = 1;
522
523 /* At one time the vtable info was grabbed 2 words at a time. This
524 fails on sparc unless you have 8-byte alignment. (tiemann) */
525 DECL_ALIGN (decl) = MAX (TYPE_ALIGN (double_type_node),
526 DECL_ALIGN (decl));
527
528 import_export_vtable (decl, class_type, 0);
529
530 return decl;
531 }
在 528 行, import_export_vtable 为构建的 VARL_DECL 设置了 TREE_PUBLIC 及 DECL_EXTERNAL 。注意到在 build_primary_vtable 的 614 行, TYPE_BINFO_VIRTUALS 获取作为其参数的类的 binfo 的 BINFO_VIRTUALS 。
在 build_primary_vtabl 的 597 行, get_vtbl_decl_for_binfo 获取对应 binfo 的 vtable 的 VAR_DECL 。
6446 tree
6447 get_vtbl_decl_for_binfo (tree binfo) in class.c
6448 {
6449 tree decl;
6450
6451 decl = BINFO_VTABLE (binfo);
6452 if (decl && TREE_CODE (decl) == PLUS_EXPR)
6453 {
6454 my_friendly_assert (TREE_CODE (TREE_OPERAND (decl, 0)) == ADDR_EXPR,
6455 2000403);
6456 decl = TREE_OPERAND (TREE_OPERAND (decl, 0), 0);
6457 }
6458 if (decl)
6459 my_friendly_assert (TREE_CODE (decl) == VAR_DECL, 20000403);
6460 return decl;
6461 }
现在回到 dfs_modify_vtables ,注意 virtuals 及 orig_virtuals ; virtuals 来自当前类派生树中的 binfo ,而 orig_virtuals 来自基类对应类型中的 binfo 。现在它们是不同的,因为相应的 BINFO_VIRTUALS 在上面已经被拷贝了。
那么对于每个定义在该类中的虚函数,必需的 thunk 及其所携带的调整信息将被在 update_vtable_entry_for_fn 中计算并记录。
2071 static void
2072 update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals, in class.c
2073 unsigned ix)
2074 {
2075 tree b;
2076 tree overrider;
2077 tree delta;
2078 tree virtual_base;
2079 tree first_defn;
2080 tree overrider_fn, overrider_target;
2081 tree target_fn = DECL_THUNK_P (fn) ? THUNK_TARGET (fn) : fn;
2082 tree over_return, base_return;
2083 bool lost = false;
2084
2085 /* Find the nearest primary base (possibly binfo itself) which defines
2086 this function; this is the class the caller will convert to when
2087 calling FN through BINFO. */
2088 for (b = binfo; ; b = get_primary_binfo (b))
2089 {
2090 my_friendly_assert (b, 20021227);
2091 if (look_for_overrides_here (BINFO_TYPE (b), target_fn))
2092 break ;
2093
2094 /* The nearest definition is from a lost primary. */
2095 if (BINFO_LOST_PRIMARY_P (b))
2096 lost = true;
2097 }
2098 first_defn = b;
2099
2100 /* Find the final overrider. */
2101 overrider = find_final_overrider (TYPE_BINFO (t), b, target_fn);
2102 if (overrider == error_mark_node)
2103 {
2104 error ("no unique final overrider for `%D' in `%T'", target_fn, t);
2105 return ;
2106 }
2107 overrider_target = overrider_fn = TREE_PURPOSE (overrider);
因为 dfs_modify_vtables 在 dfs_walk_real 中被用作 postfn ,在派生树中它从底部开始处理基类,即首先是非派生类的基类。这个次序对于虚拟主要基类来说是重要的(但非虚拟主要基类不要求这个次序,因为每个派生类都有自己的基类 binfo 拷贝)。
因此对于类 C , dfs_modify_vtables 首先处理 C 中的 A 的 binfo 。在上面 2088 行的 FOR 循环中,对于指定的函数(即,带有 thunk 的 B1::f ),它进入这个指定基类的主要基类链,并选出定义了这个函数的最靠近的主要基类。对于我们例子中的带有 thunk 的 B1::f ,找出的 b 是 B1 ,并且 lost 是 false 。
当调用 find_final_overrider 时,注意到如果函数正在被处理的是一个 thunk ,需要提取真正的函数,并由下面的 fn 所指向。这里 fn 指向 C 中属于 A 的 B1::f 。
1194 static tree
1195 find_final_overrider (tree derived, tree binfo, tree fn) in class.c
1196 {
1197 find_final_overrider_data ffod;
1198 count_depth_data cd;
1199
1200 /* Getting this right is a little tricky. This is valid:
1201
1202 struct S { virtual void f (); };
1203 struct T { virtual void f (); };
1204 struct U : public S, public T { };
1205
1206 even though calling `f' in `U' is ambiguous. But,
1207
1208 struct R { virtual void f(); };
1209 struct S : virtual public R { virtual void f (); };
1210 struct T : virtual public R { virtual void f (); };
1211 struct U : public S, public T { };
1212
1213 is not -- there's no way to decide whether to put `S::f' or
1214 `T::f' in the vtable for `R'.
1215
1216 The solution is to look at all paths to BINFO. If we find
1217 different overriders along any two, then there is a problem. */
1218 if (DECL_THUNK_P (fn))
1219 fn = THUNK_TARGET (fn);
1220
1221 /* Determine the depth of the hierarchy. */
1222 cd.depth = 0;
1223 cd.max_depth = 0;
1224 dfs_walk (derived, dfs_depth_post , dfs_depth_q , &cd);
1225
1226 ffod.fn = fn;
1227 ffod.declaring_base = binfo;
1228 ffod.most_derived_type = BINFO_TYPE (derived);
1229 ffod.candidates = NULL_TREE;
1230 ffod.vpath_list = (tree *) xcalloc (cd.max_depth, sizeof (tree));
1231 ffod.vpath = ffod.vpath_list;
1232
1233 dfs_walk_real (derived,
1234 dfs_find_final_overrider ,
1235 dfs_find_final_overrider_post ,
1236 dfs_find_final_overrider_q ,
1237 &ffod);
1238
1239 free (ffod.vpath_list);
1240
1241 /* If there was no winner, issue an error message. */
1242 if (!ffod.candidates || TREE_CHAIN (ffod.candidates))
1243 return error_mark_node;
1244
1245 return ffod.candidates;
1246 }
具有类型 count_depth_data 的变量 cd 用在派生树的遍历过程。其类型定义如下。
1856 typedef struct count_depth_data { in class.c
1857 /* The depth of the current subobject, with "1" as the depth of the
1858 most derived object in the hierarchy. */
1859 size_t depth;
1860 /* The maximum depth found so far. */
1861 size_t max_depth;
1862 } count_depth_data ;
在 dfs_walk_real 中,函数 dfs_depth_q 被用作参数 qfn ,它自顶向下执行计算该类的派生层数( find_final_overrider 的参数 derived 在这里,是当前类,即 C )。
1886 static tree
1887 dfs_depth_q (tree derived, int i, void *data) in class.c
1888 {
1889 count_depth_data *cd = (count_depth_data *) data;
1890 cd->depth++;
1891 return BINFO_BASETYPE (derived, i);
1892 }
而 dfs_depth_post 在 dfs_walk_real 中作为参数 postfn ,它自底向上执行,趋向顶端派生程度最高的类。它在自顶向下访问树的过程中所作的记录里,找出最大派生层数。
1886 static tree
1887 dfs_depth_post (tree binfo ATTRIBUTE_UNUSED, void *data) in class.c
1888 {
1889 count_depth_data *cd = (count_depth_data *) data;
1890 if (cd->depth > cd->max_depth)
1891 cd->max_depth = cd->depth;
1892 cd->depth--;
1893 return NULL_TREE;
1894 }
看到在 1230 行, cd 的这个 max_depth 域被用作中 vpath_list 的维度, ffod 的类型是下面的 find_final_overrider_data 。
1893 typedef struct find_final_overrider_data_s { in class.c
1894 /* The function for which we are trying to find a final overrider. */
1895 tree fn;
1896 /* The base class in which the function was declared. */
1897 tree declaring_base;
1898 /* The most derived class in the hierarchy. */
1899 tree most_derived_type;
1900 /* The candidate overriders. */
1901 tree candidates;
1902 /* Each entry in this array is the next-most-derived class for a
1903 virtual base class along the current path. */
1904 tree *vpath_list;
1905 /* A pointer one past the top of the VPATH_LIST. */
1906 tree *vpath;
1907 } find_final_overrider_data ;
在内层的遍历中, dfs_find_final_overrider 被用作 dfs_walk_real 中的 prefn ,它将以前序次序执行,并且如果它返回非 0 值,将中止遍历。注意到参数 binfo 是 find_final_overrider 中的变量 derived ,并且作为 data 传入的 ffod 的 declaring_base 域最初是被 dfs_modify_vtables 当前以后序访问的基类的 binfo ,而 most_derived_type 域则指向派生程度最高的类(当前类)。
1955 static tree
1956 dfs_find_final_overrider (tree binfo, void* data) in class.c
1957 {
1958 find_final_overrider_data *ffod = (find_final_overrider_data *) data;
1959
1960 if (binfo == ffod->declaring_base)
1961 dfs_find_final_overrider_1 (binfo, ffod->vpath, ffod);
1962
1963 return NULL_TREE;
1964 }
注意到在内层遍历中, dfs_find_final_overrider 是以前序执行的,而 dfs_modify_vtables ,在外层遍历中,是以后序执行,并且 binfo 是正在被内层遍历访问的基类,而 data 记录了在运行内层遍历那一点上外层遍历的快照。因此当内层前序遍历运行到它被触发的那一点时,执行 dfs_find_final_overrider_1 。
不过在 1960 行的条件最终满足前, dfs_find_final_overrider_q 为每个遭遇的基类所执行。
1966 static tree
1967 dfs_find_final_overrider_q (tree derived, int ix, void *data) in class.c
1968 {
1969 tree binfo = BINFO_BASETYPE (derived, ix);
1970 find_final_overrider_data *ffod = (find_final_overrider_data *) data;
1971
1972 if (TREE_VIA_VIRTUAL (binfo))
1973 *ffod->vpath++ = derived;
1974
1975 return binfo;
1976 }
正如我们所期望的,被分析的虚拟基类被按照它们出现的次序来记录在 ffod 的 vpath 中。因此当离开这个基类时,它应该被 dfs_find_final_overrider_post 移除。
1978 static tree
1979 dfs_find_final_overrider_post (tree binfo, void *data) in class.c
1980 {
1981 find_final_overrider_data *ffod = (find_final_overrider_data *) data;
1982
1983 if (TREE_VIA_VIRTUAL (binfo))
1984 ffod->vpath--;
1985
1986 return NULL_TREE;
1987 }
在 dfs_find_final_overrider_1 中,参数 binfo 是在这次内层遍历中正在访问的基类,而 ffod 的 declaring_base 是在外层遍历中正在访问的 binfo ,在这个 binfo 中我们正在确定由 ffod 的 fn 所指定的虚函数的正确的重载版本。而现在 binfo 与 declaring_base 是相同的。
1905 static bool
1906 dfs_find_final_overrider_1 (tree binfo, in class.c
1907 tree *vpath,
1908 find_final_overrider_data *ffod)
1909 {
1910 tree method;
1911
1912 /* If BINFO is not the most derived type, try a more derived class.
1913 A definition there will overrider a definition here. */
1914 if (!same_type_p (BINFO_TYPE (binfo), ffod->most_derived_type))
1915 {
1916 tree derived;
1917
1918 if (TREE_VIA_VIRTUAL (binfo))
1919 derived = *--vpath;
1920 else
1921 derived = BINFO_INHERITANCE_CHAIN (binfo);
1922 if (dfs_find_final_overrider_1 (derived, vpath, ffod))
1923 return true;
1924 }
1925
1926 method = look_for_overrides_here (BINFO_TYPE (binfo), ffod->fn);
1927 if (method)
1928 {
1929 tree *candidate = &ffod->candidates;
1930
1931 /* Remove any candidates overridden by this new function. */
1932 while (*candidate)
1933 {
1934 /* If *CANDIDATE overrides METHOD, then METHOD
1935 cannot override anything else on the list. */
1936 if (base_derived_from (TREE_VALUE (*candidate), binfo))
1937 return true;
1938 /* If METHOD overrides *CANDIDATE, remove *CANDIDATE. */
1939 if (base_derived_from (binfo, TREE_VALUE (*candidate)))
1940 *candidate = TREE_CHAIN (*candidate);
1941 else
1942 candidate = &TREE_CHAIN (*candidate);
1943 }
1944
1945 /* Add the new function. */
1946 ffod->candidates = tree_cons (method, binfo, ffod->candidates);
1947 return true;
1948 }
1949
1950 return false;
1951 }
注意上面 1922 行的递归调用,该函数给了派生程度最高的类比基类更高的优先级。因此在 base_derived_from 的帮助下,它能找出重载了这个函数的派生程度最高的基类。 base_derived_from 确定了它从那里派生来的。
1836 static bool
1837 base_derived_from (tree derived, tree base) in class.c
1838 {
1839 tree probe;
1840
1841 for (probe = base; probe; probe = BINFO_INHERITANCE_CHAIN (probe))
1842 {
1843 if (probe == derived)
1844 return true;
1845 else if (TREE_VIA_VIRTUAL (probe))
1846 /* If we meet a virtual base, we can't follow the inheritance
1847 any more. See if the complete type of DERIVED contains
1848 such a virtual base. */
1849 return purpose_member (BINFO_TYPE (probe),
1850 CLASSTYPE_VBASECLASSES (BINFO_TYPE (derived)))
1851 != NULL_TREE;
1852 }
1853 return false;
1854 }
这个来自派生程度最高的基类中的虚函数被赋予下面的 overrider_target 。对于我们的例子 A 中带有 thunk 的 B::f , overrider_target 获得的是 C::f 。现在对于这个例子,我们有, target_fn : B* B::f() , overrider_target : C* C::f() 。记住这个 A 中的 B::f 具有一个结果调整的 thunk ,其中 virutal-offset 是: B1 中的 A , fix-offset 是: 0 ( A -> B1 )。
看到如果该 thunk 包含了 virtual-offset ,它应该来自以 2140 行的 over_return 为根节点的派生树中。因此我们可以得到正确的虚拟基类偏移( virtual offset )。
update_vtable_entry_for_fn (continue)
2109 /* Check for adjusting covariant return types. */
2110 over_return = TREE_TYPE (TREE_TYPE (overrider_target));
2111 base_return = TREE_TYPE (TREE_TYPE (target_fn));
2112
2113 if (POINTER_TYPE_P (over_return)
2114 && TREE_CODE (over_return) == TREE_CODE (base_return)
2115 && CLASS_TYPE_P (TREE_TYPE (over_return))
2116 && CLASS_TYPE_P (TREE_TYPE (base_return)))
2117 {
2118 /* If FN is a covariant thunk, we must figure out the adjustment
2119 to the final base FN was converting to. As OVERRIDER_TARGET might
2120 also be converting to the return type of FN, we have to
2121 combine the two conversions here. */
2122 tree fixed_offset, virtual_offset;
2123
2124 over_return = TREE_TYPE (over_return);
2125 base_return = TREE_TYPE (base_return);
2126
2127 if (DECL_THUNK_P (fn))
2128 {
2129 my_friendly_assert (DECL_RESULT_THUNK_P (fn), 20031211);
2130 fixed_offset = ssize_int (THUNK_FIXED_OFFSET (fn));
2131 virtual_offset = THUNK_VIRTUAL_OFFSET (fn);
2132 }
2133 else
2134 fixed_offset = virtual_offset = NULL_TREE;
2135
2136 if (virtual_offset)
2137 /* Find the equivalent binfo within the return type of the
2138 overriding function. We will want the vbase offset from
2139 there. */
2140 virtual_offset =
2141 TREE_VALUE (purpose_member
2142 (BINFO_TYPE (virtual_offset),
2143 CLASSTYPE_VBASECLASSES (over_return)));
2144 else if (!same_type_ignoring_top_level_qualifiers_p
2145 (over_return, base_return))
2146 {
2147 /* There was no existing virtual thunk (which takes
2148 precedence). So find the binfo of the base function's
2149 return type within the overriding function's return type.
2150 We cannot call lookup base here, because we're inside a
2151 dfs_walk, and will therefore clobber the BINFO_MARKED
2152 flags. Fortunately we know the covariancy is valid (it
2153 has already been checked), so we can just iterate along
2154 the binfos, which have been chained in inheritance graph
2155 order. Of course it is lame that we have to repeat the
2156 search here anyway -- we should really be caching pieces
2157 of the vtable and avoiding this repeated work. */
2158 tree thunk_binfo, base_binfo;
2159
2160 /* Find the base binfo within the overriding function's
2161 return type. We will always find a thunk_binfo, except
2162 when the covariancy is invalid (which we will have
2163 already diagnosed). */
2164 for (base_binfo = TYPE_BINFO (base_return),
2165 thunk_binfo = TYPE_BINFO (over_return);
2166 thunk_binfo;
2167 thunk_binfo = TREE_CHAIN (thunk_binfo))
2168 if (same_type_p (BINFO_TYPE (thunk_binfo),
2169 BINFO_TYPE (base_binfo)))
2170 break ;
2171
2172 /* See if virtual inheritance is involved. */
2173 for (virtual_offset = thunk_binfo;
2174 virtual_offset;
2175 virtual_offset = BINFO_INHERITANCE_CHAIN (virtual_offset))
2176 if (TREE_VIA_VIRTUAL (virtual_offset))
2177 break ;
2178
2179 if (virtual_offset
2180 || (thunk_binfo && !BINFO_OFFSET_ZEROP (thunk_binfo)))
2181 {
2182 tree offset = convert (ssizetype, BINFO_OFFSET (thunk_binfo));
2183
2184 if (virtual_offset)
2185 {
2186 /* We convert via virtual base. Adjust the fixed
2187 offset to be from there. */
2188 offset = size_diffop
2189 (offset, convert
2190 (ssizetype, BINFO_OFFSET (virtual_offset)));
2191 }
2192 if (fixed_offset)
2193 /* There was an existing fixed offset, this must be
2194 from the base just converted to, and the base the
2195 FN was thunking to. */
2196 fixed_offset = size_binop (PLUS_EXPR, fixed_offset, offset);
2197 else
2198 fixed_offset = offset;
2199 }
2200 }
2201
2202 if (fixed_offset || virtual_offset)
2203 /* Replace the overriding function with a covariant thunk. We
2204 will emit the overriding function in its own slot as
2205 well. */
2206 overrider_fn = make_thunk (overrider_target, /*this_adjusting=*/ 0,
2207 fixed_offset, virtual_offset);
2208 }
2209 else
2210 my_friendly_assert (!DECL_THUNK_P (fn), 20021231);