But what’s thunk? Following paragraphs are extracted from comment in the source of GCC.
A thunk is an alternate entry point for an ordinary FUNCTION_DECL. The address of the ordinary FUNCTION_DECL is given by the DECL_INITIAL, which is always an ADDR_EXPR whose operand is a FUNCTION_DECL. The job of the thunk is to either adjust the this pointer before transferring control to the FUNCTION_DECL, or call FUNCTION_DECL and then adjust the result value. Note, the result pointer adjusting thunk must perform a call to the thunked function, (or be implemented via passing some invisible parameter to the thunked function, which is modified to perform the adjustment just before returning). A thunk may perform either, or both, of the following operations: Adjust the this or result pointer by a constant offset. Adjust the this or result pointer by looking up a vcall or vbase offset in the vtable. A this pointer adjusting thunk converts from a base to a derived class, and hence adds the offsets. A result pointer adjusting thunk converts from a derived class to a base, and hence subtracts the offsets. If both operations are performed, then the constant adjustment is performed first for this pointer adjustment and last for the result pointer adjustment. The constant adjustment is given by THUNK_FIXED_OFFSET. If the vcall or vbase offset is required, THUNK_VIRTUAL_OFFSET is used. For this pointer adjusting thunks, it is the vcall offset into the vtable. For result pointer adjusting thunk, it is the binfo of the virtual base to convert to. Use that binfo's vbase offset. It is possible to have equivalent covariant thunks. These are distinct virtual covariant thunks whose vbase offsets happen to have the same value. THUNK_ALIAS is used to pick one as the canonical thunk, which will get all the this pointer adjusting thunks attached to it. |
Consider following example:
A *pc = new C;
pc->f();
Remember that there is an implicit parameter of “const this*”, and for f above, this implicit parameter is “const C*”; however pc used as the implicit parameter is declared as “A*”, the compiler needs adjust pc to “const C*”. Here, thunk is needed, because A is virtual base, as we have seen in former sections, virtual base usually laid out at the tail of the class unless it is primary base. That means virtual base may have different offsets in derived classes. Later we will see for non-virtual primary base (it must contain vtable), there is no such trouble, as this base always laid out at 0 offset in derived class.
In case virtual_offset at line 2131 is NULL, it means the base defining fn hasn’t virtual base. It then further checks if the type of the returned value of both functions are the same by same_type_ignoring_top_level_qualifiers_p which indicated by its name, compares the main variant (TYPE_MAIN_VARIANT) of both types (that is ignores cv-qualifier). If these two types are not the same, the type returned by the virtual function of the derived type (over_return ) must derive from the type returned by the virtual function of the base (base_return ). It is the case require result adjusting thunk. So FOR loop at line 2164, it ensures base_return is the base of over_return . If so, following, checks if base_return is also the base of certain virtual base too.
Now if base_return is base of a virtual base (that is thunk_binfo is contained in virtual_offset ), or it is not placed at head of derived class; it calculates the fixed_offset accordingly. Notice that after handling by layout_class_type , all BINFO_OFFSET is from the beginning of the current class type.
Now for B1::f of A, fixed_offset (0) and virtual_offset (A) gotten at line 2130 and 2131 are not NULL. Then virtual_offset at line 2131 is updated to A in class C (see copy_base_binfos for extending CLASSTYPE_VBASECLASSES).
If fixed_offset or virtual_offset is epxected, a thunk is prepared by make_thunk at line 2206; this_adjusting indicates whether it is a this or result adjusting thunk. Note that thunk created here is a result adjustment one.
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 is itself a FUNCTION_DECL. Note that it is nameless and artificial. And the value of fixed offset is set in THUNK_FIXED_OFFSET. Further this thunk is applied to the specified virtual function (more precisely, the returned type); it is linked by DECL_THUNKS of the node of the virtual function.
Remember below b is the nearest primary base which defines the function and gotten by get_primary_binfo , it is binfo of B1 for C in our example. At line 2218, the FOR block fetches the closest virtual class deriving from b in current class type if there is. Here we get virtual_base as NULL. See at line 2236, if overrider_fn is not equal to overrider_target , it means there is a thunk for the overrider, and if no virtual derived class is found, it further checks if there is any primary virtual base. If primary virtual base is found, that means following class structure:
And if virtual derived class is found, the class structure should be:
Thunk is generated by above code, and delta and vcall offset are determined by following code. For our example B::f with thunk in A, condition at line 2236 is not satisfied. And delta would be 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 }
For virtual base, in construction vtable of the most derived class (see next section for building VTT), there is an entry called vcall offset to record the offset from the virtual base to this final overriding class. This offset will be also used by virtual functions to adjust the this pointer, and saved within field BV_VCALL_INDEX.
At line 2293, get_vcall_index checks and fetches this vcall offset, which stored in field CLASSTYPE_VCALL_INDICES of the binfo of the class of the virtual base (this data is generated by finish_vtbls in following section).
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 }
Remember lost at line 2274 can only be found for base containing virtual primary base, and the virtual base is also the primary base in current type, which has offset 0. And modify_vtable_entry records this adjustment within BV_DELTA. Especially, argument fndecl here is the overrider_fn in update_vtable_entry_for_fn , which is the final overrider. See it is filled into the corresponding vtable entry in the bases that defined the virtual to ensure correct function to be invoked.
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 }
If condition at line 694 is satisfied, it means fndecl is overrided or thunk; and if condition at line 695 is satisfied, it indicates BV_DETLA needs update. These 3 situations (includes case 694, 695 line condition both satisfied) mean need to update corresponding entry in vtable, so first see if vtable is ready or not. If vtable is ready before, the binfo has BINFO_NEW_VTABLE_MARKED set, and make_new_vtable returns 0. For our example Class C, it will enter the function 3 times, by A, B2 and C in order. They all invoked make_new_vtable in dfs_modify_vtables , and argument virtuals came from binfo of this base, so direct update is all. Also note that find_final_overrider will check if ambiguous exists, for example, removing f in C, then calling f via C is ambiguous.
After handling base A, dfs_walk in modify_all_vtables , then climbs up to B1 (as we come in order C à B1 à A). As B1 is a non-virtual primary base, dfs_modify_vtables skips this type (note that make_new_vtable is not invoked as result, and BINFO_NEW_VTABLE_MARKED in the binfo is unset). Then next object is B2, the handling of this base is similar with what we have seen. At last, we arrive at C. Remember BINFO_VIRTUALS (C) contains B1::f with thunk exactly the same as that in A in C, which followed by B1::f. Here for this first function, it is replaced by C::f (delta : 0) with thunk with virual-offset: A in C, fix-offset: 0. Then for B1::f next, it will get C::f without thunk as result as it is the non-virtual primary base for C.
Finially after exitting the walk, remember there virtuals gets its content from TYPE_METHOD of C, which is C::f. And now in BINFO_VIRTUALS (C) are, 1) C::f with thunk of virtual-offset (A in C), fix-offset (0); 2) C::f. So in modify_all_vtables , C::f is removed from virtuals , which is now empty.
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);
Then at line 5106 in finish_struct_1 , virtuals are virtual functions declared within class t and survived. Appending them to TYPE_BINFO_VIRTUALS forms the complete list.
At line 5112, TARGET_VTABLE_USES_DESCRIPTORS is defined if function descriptors are used in the vtable entries and it says how many words wide the descriptor is (normally 2). By default, the C++ compiler will use function addresses in the vtable entries. Till now DECL_VINDEX still points to a FUNCTION_DECL in a base class which is the FUNCTION_DECL this FUNCTION_DECL will replace as a virtual function. It is time to change the pointer to an INTEGER_CST. In GCC, integer constant less than 256 is shared and kept within global array 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 }
As we have finished layout of the class, we can synchronize the node of cv-qualifier variant. At line 1439, TYPE_POLYMORPHIC_P set for the type that overrides a vritual function of base. Routine get_pure_virtuals fetches all pure virtuals of non-primary base (the most derived class is also non-primary base, whose vtable contains virtual functions of bases along the primary base path). Remember that pure virtual function has been bound with the final overrider if it has been overrided in 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 }
All pure virtual functions are put into CLASSTYPE_PURE_VIRTUALS field of current class (then if CLASSTYPE_PURE_VIRTUALS is not empty, this type can’t be instantiated).
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 }
Next, if base defines convertor, then it can be used by the derived. At line 1469, if TYPE_HAS_TRIVIAL_INIT_REF is nonzero, means copy initialization of this type can use a bitwise copy. And if TYPE_HAS_NONTRIVIAL_DESTRUCTOR is nonzero, means this type does not have a trivial destructor. A destructor is trivial if it is an implicitly declared destructor and if:
- all of the direct base classes of its class have trivial destructors,
- for all of the non-static data members of its class that are of class type (or array thereof), each such class has a trivial destructor.