When finishing handling of B1, build_vcall_and_vbase_vtbl_entries returns to the invocation of handling class C. This time build_vbase_offset_vtbl_entries does nothing, as base A has been processed with BINFO_VTABLE_PATH_MARKED set. And in build_vcall_offset_vtbl_entries , vid->generate_vcall_entries is set in false for class C, and vid->vbase is set to binfo of C. Below call stack would be involved.
build_vcall_and_vbase_vtbl_entries: for C
build_vcall_offset_vtbl_entries: for C
add_vcall_offset_vtbl_entries_r: for C
add_vcall_offset_vtbl_entries_r: for B1
add_vcall_offset_vtbl_entries_r: for A
add_vcall_offset_vtbl_entries_1: for B1
add_vcall_offset: for B1
add_vcall_offset_vtbl_entries_1: for C
add_vcall_offset: for C
add_vcall_offset_vtbl_entries_r: for B2
add_vcall_offset_vtbl_entries_r: for A
add_vcall_offset_vtbl_entries_1: for B2
add_vcall_offset: for B2
In above call stack, add_vcall_offset_vtbl_entries_r first recurses for C’s A, but it does nothing as condition at line 7680 satisified. In following add_vcall_offset , vid->fns now holds virtual functions seen above, so same_signature_p at line 7805 returns true for B1’s virtual, and exits the function at line 7810. After returning from add_vcall_offset_vtbl_entries_r handling B1, invoking add_vcall_offset_vtbl_entries_1 for C. Similiarly, same_signature_p returns true for C’s virtual. Then add_vcall_offset_vtbl_entries_r at line 7698 is recursed for B2 (the non-primary base), it’s original primary base A is filtered out by conidtion at line 7680, also in add_vcall_offset , same_signature_p returns true for B2’s virtual.
When exitting from build_vcall_and_vbase_vtbl_entries for C, we will get following vtable initializers and CLASSTYPE_VCALL_INDICES.
In above figure, in the chain of CLASSTYPE_VCALL_INDICES, value field of node A::f is -3; it coordinate with A::f given in chain of last_init.
Back build_vtbl_initializer , it is still handling C.
build_vtbl_initializer (continue)
7378 /* If the target requires padding between data entries, add that now. */
7379 if (TARGET_VTABLE_DATA_ENTRY_DISTANCE > 1)
7380 {
…
7395 }
7396
7397 if (non_fn_entries_p)
7398 *non_fn_entries_p = list_length (vid.inits);
7399
7400 /* Go through all the ordinary virtual functions, building up
7401 initializers. */
7402 vfun_inits = NULL_TREE;
7403 for (v = BINFO_VIRTUALS (orig_binfo); v; v = TREE_CHAIN (v))
7404 {
7405 tree delta;
7406 tree vcall_index;
7407 tree fn, fn_original;
7408 tree init = NULL_TREE;
7409
7410 fn = BV_FN (v);
7411 fn_original = fn;
7412 if (DECL_THUNK_P (fn))
7413 {
7414 if (!DECL_NAME (fn))
7415 finish_thunk (fn);
7416 if (THUNK_ALIAS (fn))
7417 {
7418 fn = THUNK_ALIAS (fn);
7419 BV_FN (v) = fn;
7420 }
7421 fn_original = THUNK_TARGET (fn);
7422 }
7423
7424 /* If the only definition of this function signature along our
7425 primary base chain is from a lost primary, this vtable slot will
7426 never be used, so just zero it out. This is important to avoid
7427 requiring extra thunks which cannot be generated with the function.
7428
7429 We first check this in update_vtable_entry_for_fn, so we handle
7430 restored primary bases properly; we also need to do it here so we
7431 zero out unused slots in ctor vtables, rather than filling themff
7432 with erroneous values (though harmless, apart from relocation
7433 costs). */
7434 for (b = binfo; ; b = get_primary_binfo (b))
7435 {
7436 /* We found a defn before a lost primary; go ahead as normal. */
7437 if (look_for_overrides_here (BINFO_TYPE (b), fn_original))
7438 break ;
7439
7440 /* The nearest definition is from a lost primary; clear the
7441 slot. */
7442 if (BINFO_LOST_PRIMARY_P (b))
7443 {
7444 init = size_zero_node;
7445 break ;
7446 }
7447 }
7448
7449 if (! init)
7450 {
7451 /* Pull the offset for `this', and the function to call, out of
7452 the list. */
7453 delta = BV_DELTA (v);
7454 vcall_index = BV_VCALL_INDEX (v);
7455
7456 my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727);
7457 my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);
7458
7459 /* You can't call an abstract virtual function; it's abstract.
7460 So, we replace these functions with __pure_virtual. */
7461 if (DECL_PURE_VIRTUAL_P (fn_original))
7462 fn = abort_fndecl;
7463 else if (!integer_zerop (delta) || vcall_index)
7464 {
7465 fn = make_thunk (fn, /*this_adjusting=*/ 1, delta, vcall_index);
7466 if (!DECL_NAME (fn))
7467 finish_thunk (fn);
7468 }
7469 /* Take the address of the function, considering it to be of an
7470 appropriate generic type. */
7471 init = build1 (ADDR_EXPR, vfunc_ptr_type_node , fn);
7472 /* The address of a function can't change. */
7473 TREE_CONSTANT (init) = 1;
7474 }
7475
7476 /* And add it to the chain of initializers. */
7477 if (TARGET_VTABLE_USES_DESCRIPTORS)
7478 {
…
7493 }
7494 else
7495 vfun_inits = tree_cons (NULL_TREE, init, vfun_inits);
7496 }
7497
7498 /* The initializers for virtual functions were built up in reverse
7499 order; straighten them out now. */
7450 vfun_inits = nreverse (vfun_inits);
7451
7452 /* The negative offset initializers are also in reverse order. */
7453 vid.inits = nreverse (vid.inits);
7454
7455 /* Chain the two together. */
7456 return chainon (vid.inits, vfun_inits);
7457 }
Above orig_binfo comes from current class, whose BINFO_VIRTUALS has been process by update_vtable_entry_for_fn (see previous section). Virtuals in BINFO_VIRTUALS can be a thunk, which is constructed in update_vtable_entry_for_fn , and only of result-adjustmnet. Here it is constructing this-adjustment thunk, and information BV_DELTA, BV_VCALL_INDEX (from CLASSTYPE_VCALL_INDICES of the virtual base. Above can see C also prepared it for future being virtual base) is also collected by update_vtable_entry_for_fn .
Now all thunks are still anonymous. In the front-end, that indicates the thunk is incomplete.
194 void
195 finish_thunk (tree thunk) in method.c
196 {
197 tree function, name;
198 tree fixed_offset = ssize_int (THUNK_FIXED_OFFSET (thunk));
199 tree virtual_offset = THUNK_VIRTUAL_OFFSET (thunk);
200
201 my_friendly_assert (!DECL_NAME (thunk) && DECL_THUNK_P (thunk), 20021127);
202 if (virtual_offset && DECL_RESULT_THUNK_P (thunk))
203 virtual_offset = BINFO_VPTR_FIELD (virtual_offset);
204 function = THUNK_TARGET (thunk);
205 name = mangle_thunk (function, DECL_THIS_THUNK_P (thunk),
206 fixed_offset, virtual_offset);
207
208 /* We can end up with declarations of (logically) different
209 covariant thunks, that do identical adjustments. The two thunks
210 will be adjusting between within different hierarchies, which
211 happen to have the same layout. We must nullify one of them to
212 refer to the other. */
213 if (DECL_RESULT_THUNK_P (thunk))
214 {
215 tree cov_probe;
216
217 for (cov_probe = DECL_THUNKS (function);
218 cov_probe; cov_probe = TREE_CHAIN (cov_probe))
219 if (DECL_NAME (cov_probe) == name)
220 {
221 my_friendly_assert (!DECL_THUNKS (thunk), 20031023);
222 THUNK_ALIAS (thunk) = (THUNK_ALIAS (cov_probe)
223 ? THUNK_ALIAS (cov_probe) : cov_probe);
224 break ;
225 }
226 }
227
228 DECL_NAME (thunk) = name;
229 SET_DECL_ASSEMBLER_NAME (thunk, name);
230 }
THUNK_VIRTUAL_OFFSET, for this-adjusting thunk, it is the number of bytes to be added to the vtable to find the vcall offset; for a result adjusting thunk, it is the binfo of the relevant virtual base. BINFO_VPTR_FIELD at line 203 is an INTEGER_CST giving an offset into the vtable where the offset to the virtual base can be found. So for result adjusting thunk, needs treatment at line 203 to get the offset of the virtual base. At line 205, mangle_thunk returns the mangled name for the thunk (at section beginning, we have seen examples of thunk’s mangled name). After setting the name with the thunk, it can be regarded as finished. As thunk’s name is constructed by its action, it’s possible there exists thunk of same name, at which treats the thunk built later as the alias of the former one, they share the same thunk function.
dfs_accumulate_vtbl_inits (continue)
7285 /* Figure out the position to which the VPTR should point. */
7286 vtbl = TREE_PURPOSE (l);
7287 vtbl = build1 (ADDR_EXPR,
7288 vtbl_ptr_type_node ,
7289 vtbl);
7290 TREE_CONSTANT (vtbl) = 1;
7291 index = size_binop (PLUS_EXPR,
7292 size_int (non_fn_entries),
7293 size_int (list_length (TREE_VALUE (l))));
7294 index = size_binop (MULT_EXPR,
7295 TYPE_SIZE_UNIT (vtable_entry_type),
7296 index);
7297 vtbl = build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, index);
7298 TREE_CONSTANT (vtbl) = 1;
7299 }
7300
7301 if (ctor_vtbl_p)
7302 /* For a construction vtable, we can't overwrite BINFO_VTABLE.
7303 So, we make a TREE_LIST. Later, dfs_fixup_binfo_vtbls will
7304 straighten this out. */
7305 BINFO_VTABLE (binfo) = tree_cons (rtti_binfo, vtbl, BINFO_VTABLE (binfo));
7306 else if (BINFO_PRIMARY_P (binfo) && TREE_VIA_VIRTUAL (binfo))
7307 inits = NULL_TREE;
7308 else
7309 /* For an ordinary vtable, set BINFO_VTABLE. */
7310 BINFO_VTABLE (binfo) = vtbl;
7311
7312 return inits;
7313 }
Back to dfs_accumulate_vtbl_inits , note that we are still handling class C. above l is list in finish_vtbls , in its TREE_PURPOSE is the TYPE_BINFO_VTABLE (vtable saved in the binfo of the type, which is VAR_DECL generated by build_primary_vtable ). And originally, TREE_VALUE of l is NULL (but at line 7185 in accumulate_vtbl_inits , it chains l with the list returned by dfs_accumulate_vtbl_inits ). See that non_fn_entries records the number of entries of negative index. So it can know where to begin the entries visible to programmer.
When returns back to accumulate_vtbl_inits , after chaining into list in finish_vtt , we get following figure (remember in create_vtable_ptr , every virtual function has an extra node generated with 0 delta).
Next, in accumulate_vtbl_inits , at line 7195, in FOR block, binfo B1 within C is not handled as its BINFO_NEW_VTABLE_MARKED unset (see dfs_accumulate_vtbl_inits line 7273). While for B2 in C, it has secondary vtable generated, so passes the line successfully. At that time, ctor_vtbl_p is false, binfo from class B2, orig_binfo from B2 in C, and rtti_binfo is C’s binfo, it undergoes similar processing as that for C above. Then when back finish_vtbls , A in C is processed by accumulate_vtbl_inits at line 6780, in which ctor_vtbl_p is still false. But this A hasn’t flag BINFO_NEW_VTABLE_MARKED set, so exits dfs_accumulate_vtbl_inits immediately.
So before invoking initialize_vtable at line 6784, list is given in below figure.
(Click here for open )
Figure 117 : initializer for vtable
Above B1 and A don’t have their part of vtable as they share the same part with C.
In below function, now argument inits is the chain referred by value slot of list in above figure. This chain holds all initializers for class C’s vtable. Note that at last vtbl at line 7297 in dfs_accumulate_vtbl_inits , points to the start point of vtable of specified class which is a PLUS_EXPR of vtbl+4 for C, vtbl+8 for base B2.
6789 static void
6790 initialize_vtable (tree binfo, tree inits) in class.c
6791 {
6792 tree decl;
6793
6794 layout_vtable_decl (binfo, list_length (inits));
6795 decl = get_vtbl_decl_for_binfo (binfo);
6796 initialize_array (decl, inits);
6797 dump_vtable (BINFO_TYPE (binfo), binfo, decl);
6798 }
Originally in build_vtable , vtable is created as type of vtbl_type_node which is the array of type vtable_entry_type with empty dimension. Now the size of the array is settled down, we can create the exact type by layout_vtable_decl .
1778 static void
1779 layout_vtable_decl (tree binfo, int n) in class.c
1780 {
1781 tree atype;
1782 tree vtable;
1783
1784 atype = build_cplus_array_type (vtable_entry_type ,
1785 build_index_type (size_int (n - 1)));
1786 layout_type (atype);
1787
1788 /* We may have to grow the vtable. */
1789 vtable = get_vtbl_decl_for_binfo (binfo);
1790 if (!same_type_p (TREE_TYPE (vtable), atype))
1791 {
1792 TREE_TYPE (vtable) = atype;
1793 DECL_SIZE (vtable) = DECL_SIZE_UNIT (vtable) = NULL_TREE;
1794 layout_decl (vtable, 0);
1795 }
1796 }
So at line 6795, the vtable VAR_DECL fetched has correct type defined. And it is passed as argument decl in below function.
6803 static void
6804 initialize_array (tree decl, tree inits) in class.c
6805 {
6806 tree context;
6807
6808 context = DECL_CONTEXT (decl);
6809 DECL_CONTEXT (decl) = NULL_TREE;
6810 DECL_INITIAL (decl) = build_constructor (NULL_TREE, inits);
6811 TREE_HAS_CONSTRUCTOR (DECL_INITIAL (decl)) = 1;
6812 cp_finish_decl (decl, DECL_INITIAL (decl), NULL_TREE, 0);
6813 DECL_CONTEXT (decl) = context;
6814 }
See node of CONSTRUCTOR is built for initializing this VAR_DECL. Note that this node has empty type field (it is treated as unknown).
444 tree
445 build_constructor (tree type, tree vals) in tree.c
446 {
447 tree c = make_node (CONSTRUCTOR);
448 TREE_TYPE (c) = type;
449 CONSTRUCTOR_ELTS (c) = vals;
450
451 /* ??? May not be necessary. Mirrors what build does. */
452 if (vals)
453 {
454 TREE_SIDE_EFFECTS (c) = TREE_SIDE_EFFECTS (vals);
455 TREE_READONLY (c) = TREE_READONLY (vals);
456 TREE_CONSTANT (c) = TREE_CONSTANT (vals);
457 }
458 else
459 TREE_CONSTANT (c) = 0; /* safe side */
460
461 return c;
462 }
Being a VAR_DECL, it is completed by cp_finish_decl . Note that we are still within another cp_finish_decl for the template instantiation of SmallObject.
4768 void
4769 cp_finish_decl (tree decl, tree init, tree asmspec_tree, int flags) in decl.c
4770 {
4771 tree type;
4772 tree ttype = NULL_TREE;
4773 tree cleanup;
4774 const char *asmspec = NULL;
4775 int was_readonly = 0;
4776 bool var_definition_p = false;
4777
4778 if (decl == error_mark_node)
4779 return ;
4780 else if (! decl)
4781 {
4782 if (init)
4783 error ("assignment (not initialization) in declaration");
4784 return ;
4785 }
4786
4787 my_friendly_assert (TREE_CODE (decl) != RESULT_DECL, 20030619);
4788
4789 /* Assume no cleanup is required. */
4790 cleanup = NULL_TREE;
4791
4792 /* If a name was specified, get the string. */
4793 if (global_scope_p (current_binding_level ))
4794 asmspec_tree = maybe_apply_renaming_pragma (decl, asmspec_tree);
4795 if (asmspec_tree)
4796 asmspec = TREE_STRING_POINTER (asmspec_tree);
4797
4798 if (init && TREE_CODE (init) == NAMESPACE_DECL)
4799 {
4800 error ("cannot initialize `%D' to namespace `%D'",
4802 decl, init);
4803 init = NULL_TREE;
4804 }
4805
4806 if (current_class_type
4807 && CP_DECL_CONTEXT (decl) == current_class_type
4808 && TYPE_BEING_DEFINED (current_class_type )
4809 && (DECL_INITIAL (decl) || init))
4810 DECL_INITIALIZED_IN_CLASS_P (decl) = 1;
4811
4812 if (TREE_CODE (decl) == VAR_DECL
4813 && DECL_CONTEXT (decl)
4814 && TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL
4815 && DECL_CONTEXT (decl) != current_namespace
4816 && init)
4817 {
4818 /* Leave the namespace of the object. */
4819 pop_decl_namespace ();
4820 }
4821
4822 type = TREE_TYPE (decl);
4823
4824 if (type == error_mark_node)
4825 goto finish_end0;
4826
4827 if (TYPE_HAS_MUTABLE_P (type))
4828 TREE_READONLY (decl) = 0;
4829
4830 if (processing_template_decl )
4831 {
…
4842 }
4843
4844 /* Parameters are handled by store_parm_decls, not cp_finish_decl. */
4845 my_friendly_assert (TREE_CODE (decl) != PARM_DECL, 19990828);
4846
4847 /* Take care of TYPE_DECLs up front. */
4848 if (TREE_CODE (decl) == TYPE_DECL)
4849 {
…
4868 }
4869
4870 if (TREE_CODE (decl) != FUNCTION_DECL)
4871 ttype = target_type (type);
4872
4873
4874 /* Currently, GNU C++ puts constants in text space, making them
4875 impossible to initialize. In the future, one would hope for
4876 an operating system which understood the difference between
4877 initialization and the running of a program. */
4878 if (! DECL_EXTERNAL (decl) && TREE_READONLY (decl))
4879 {
4880 was_readonly = 1;
4881 if (TYPE_NEEDS_CONSTRUCTING (type)
4882 || TREE_CODE (type) == REFERENCE_TYPE)
4883 TREE_READONLY (decl) = 0;
4884 }
4885
4886 if (TREE_CODE (decl) == VAR_DECL)
4887 {
4888 /* Only PODs can have thread-local storage. Other types may require
4889 various kinds of non-trivial initialization. */
4890 if (DECL_THREAD_LOCAL (decl) && !pod_type_p (TREE_TYPE (decl)))
4891 error ("`%D' cannot be thread-local because it has non-POD type `%T'",
4892 decl, TREE_TYPE (decl));
4893 /* Convert the initializer to the type of DECL, if we have not
4894 already initialized DECL. */
4895 if (!DECL_INITIALIZED_P (decl)
4896 /* If !DECL_EXTERNAL then DECL is being defined. In the
4897 case of a static data member initialized inside the
4898 class-specifier, there can be an initializer even if DECL
4899 is *not* defined. */
4900 && (!DECL_EXTERNAL (decl) || init))
4901 {
4902 init = check_initializer (decl, init, flags, &cleanup);
4903 /* Thread-local storage cannot be dynamically initialized. */
4904 if (DECL_THREAD_LOCAL (decl) && init)
4905 {
4906 error ("`%D' is thread-local and so cannot be dynamically "
4907 "initialized", decl);
4908 init = NULL_TREE;
4909 }
4910 if (DECL_EXTERNAL (decl) && init)
4911 {
4912 /* The static data member cannot be initialized by a
4913 non-constant when being declared. */
4914 error ("`%D' cannot be initialized by a non-constant expression"
4915 " when being declared", decl);
4916 DECL_INITIALIZED_IN_CLASS_P (decl) = 0;
4917 init = NULL_TREE;
4918 }
4919
4920 /* Handle:
4921
4922 [dcl.init]
4923
4924 The memory occupied by any object of static storage
4925 duration is zero-initialized at program startup before
4926 any other initialization takes place.
4927
4928 We cannot create an appropriate initializer until after
4929 the type of DECL is finalized. If DECL_INITIAL is set,
4930 then the DECL is statically initialized, and any
4931 necessary zero-initialization has already been performed. */
4932 if (TREE_STATIC (decl) && !DECL_INITIAL (decl))
4933 DECL_INITIAL (decl) = build_zero_init (TREE_TYPE (decl),
4934 /*nelts=*/ NULL_TREE,
4935 /*static_storage_p=*/ true);
4936 /* Remember that the initialization for this variable has
4937 taken place. */
4938 DECL_INITIALIZED_P (decl) = 1;
4939 /* This declaration is the definition of this variable,
4940 unless we are initializing a static data member within
4941 the class specifier. */
4942 if (!DECL_EXTERNAL (decl))
4943 var_definition_p = true;
4944 }
…
4951 }
Before entering the function, we clean DELC_CONTEXT of decl . At line 4794, maybe_apply_renaming_pragma is only useful for Solaris and Tru64 UNIX system for compatibility with the system headers.