5.12.5.2.2.2.1.3.8. Finish the derived RECORD_TYPE – fill up missing methods
Once studied C++, the text book told me if you didn’t define constructor for a class, the compiler may generate it for you in its own way, together with may destructor, copy constructor, and assignment operator. Below is the place, the compiler fills up the missing methods.
2629 static void
2630 add_implicitly_declared_members (tree t, in class.c
2631 int cant_have_default_ctor,
2632 int cant_have_const_cctor,
2633 int cant_have_const_assignment)
2634 {
2635 tree default_fn;
2636 tree implicit_fns = NULL_TREE;
2637 tree virtual_dtor = NULL_TREE;
2638 tree *f;
2639
2640 ++adding_implicit_members ;
2641
2642 /* Destructor. */
2643 if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) && !TYPE_HAS_DESTRUCTOR (t))
2644 {
2645 default_fn = implicitly_declare_fn (sfk_destructor, t, /*const_p=*/ 0);
2646 check_for_override (default_fn, t);
2647
2648 /* If we couldn't make it work, then pretend we didn't need it. */
2649 if (default_fn == void_type_node)
2650 TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = 0;
2651 else
2652 {
2653 TREE_CHAIN (default_fn) = implicit_fns;
2654 implicit_fns = default_fn;
2655
2656 if (DECL_VINDEX (default_fn))
2657 virtual_dtor = default_fn;
2658 }
2659 }
2660 else
2661 /* Any non-implicit destructor is non-trivial. */
2662 TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) |= TYPE_HAS_DESTRUCTOR (t);
2663
2664 /* Default constructor. */
2665 if (! TYPE_HAS_CONSTRUCTOR (t) && ! cant_have_default_ctor)
2666 {
2667 default_fn = implicitly_declare_fn (sfk_constructor, t, /*const_p=*/ 0);
2668 TREE_CHAIN (default_fn) = implicit_fns;
2669 implicit_fns = default_fn;
2670 }
2671
2672 /* Copy constructor. */
2673 if (! TYPE_HAS_INIT_REF (t) && ! TYPE_FOR_JAVA (t))
2674 {
2675 /* ARM 12.18: You get either X(X&) or X(const X&), but
2676 not both. --Chip */
2677 default_fn
2678 = implicitly_declare_fn (sfk_copy_constructor, t,
2679 /*const_p=*/ !cant_have_const_cctor);
2680 TREE_CHAIN (default_fn) = implicit_fns;
2681 implicit_fns = default_fn;
2682 }
2683
2684 /* Assignment operator. */
2685 if (! TYPE_HAS_ASSIGN_REF (t) && ! TYPE_FOR_JAVA (t))
2686 {
2687 default_fn
2688 = implicitly_declare_fn (sfk_assignment_operator, t,
2689 /*const_p=*/ !cant_have_const_assignment);
2690 TREE_CHAIN (default_fn) = implicit_fns;
2691 implicit_fns = default_fn;
2692 }
2693
2694 /* Now, hook all of the new functions on to TYPE_METHODS,
2695 and add them to the CLASSTYPE_METHOD_VEC. */
2696 for (f = &implicit_fns; *f; f = &TREE_CHAIN (*f))
2697 {
2698 add_method (t, *f, /*error_p=*/ 0);
2699 maybe_add_class_template_decl_list (current_class_type , *f, /*friend_p=*/ 0);
2700 }
2701 if (abi_version_at_least (2))
2702 /* G++ 3.2 put the implicit destructor at the *beginning* of the
2703 list, which cause the destructor to be emitted in an incorrect
2704 location in the vtable. */
2705 TYPE_METHODS (t) = chainon (TYPE_METHODS (t), implicit_fns);
2706 else
2707 {
2708 if (warn_abi && virtual_dtor)
2709 warning ("vtable layout for class `%T' may not be ABI-compliant "
2710 "and may change in a future version of GCC due to implicit "
2711 "virtual destructor",
2712 t);
2713 *f = TYPE_METHODS (t);
2714 TYPE_METHODS (t) = implicit_fns;
2715 }
2716
2717 --adding_implicit_members ;
2718 }
In the code, TYPE_HAS_NONTRIVIAL_DESTRUCTOR is set for the type, if certain its data member has destructor defined. In fact, if all members of a class haven’t destructors defined, such class is said has a trival destructor, and no destructor needs be generated by the compiler; otherwise, the compiler should generate the destructor inside which invokes destructors for members defining them. And similarly, is the generation of the constructor. Nevertheless for copy constructor and assignment operator, they would be generated as long as no defined by user. See that check_for_override at line 2646 is also applied for the implicit destructor to catch the possible implicit virtual property.
974 tree
975 implicitly_declare_fn (special_function_kind kind, tree type, bool const_p) in method.c
976 {
977 tree declspecs = NULL_TREE;
978 tree fn, args = NULL_TREE;
979 tree raises = empty_except_spec;
980 bool retref = false;
981 bool has_parm = false;
982 tree name = constructor_name (type);
983
984 switch (kind)
985 {
986 case sfk_destructor:
987 /* Destructor. */
988 name = build_nt (BIT_NOT_EXPR, name);
989 args = void_list_node;
990 raises = synthesize_exception_spec (type, &locate_dtor, 0);
991 break ;
992
993 case sfk_constructor:
994 /* Default constructor. */
995 args = void_list_node;
996 raises = synthesize_exception_spec (type, &locate_ctor , 0);
997 break ;
998
999 case sfk_copy_constructor:
1000 case sfk_assignment_operator:
1001 {
1002 struct copy_data data;
1003 tree argtype = type;
1004
1005 has_parm = true;
1006 data.name = NULL;
1007 data.quals = 0;
1008 if (kind == sfk_assignment_operator)
1009 {
1010 retref = true;
1011 declspecs = build_tree_list (NULL_TREE, type);
1012
1013 name = ansi_assopname (NOP_EXPR);
1014 data.name = name;
1015 }
1016 if (const_p)
1017 {
1018 data.quals = TYPE_QUAL_CONST;
1019 argtype = build_qualified_type (argtype, TYPE_QUAL_CONST);
1020 }
1021
1022 argtype = build_reference_type (argtype);
1023 args = build_tree_list (hash_tree_chain (argtype, NULL_TREE),
1024 get_identifier ("_ctor_arg"));
1025 args = tree_cons (NULL_TREE, args, void_list_node);
1026
1027 raises = synthesize_exception_spec (type, &locate_copy, &data);
1028 break ;
1029 }
1030 default :
1031 abort ();
1032 }
1033
1034 TREE_PARMLIST (args) = 1;
1035
1036 {
1037 tree declarator = make_call_declarator (name, args, NULL_TREE, raises);
1038
1039 if (retref)
1040 declarator = build_nt (ADDR_EXPR, declarator);
1041
1042 fn = grokfield (declarator, declspecs, NULL_TREE, NULL_TREE, NULL_TREE);
1043 if (has_parm)
1044 TREE_USED (FUNCTION_FIRST_USER_PARM (fn)) = 1;
1045 }
1046
1047 my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 20000408);
1048
1049 DECL_ARTIFICIAL (fn) = 1;
1050 DECL_NOT_REALLY_EXTERN (fn) = 1;
1051 DECL_DECLARED_INLINE_P (fn) = 1;
1052 DECL_INLINE (fn) = 1;
1053 defer_fn (fn);
1054
1055 return fn;
1056 }
The code is quite familiar to us. It is no different to generate these artificial methods than that explicitly defined by user in nature, except they have DECL_ARTIFICIAL flag set. For the code from line 1036 to 1045, can refer to the section about parsing constructor in first example.
See that the exceptions that these artificial methods can throw are those that thrown by constructor of base classes, and those thrown by constructor of the class members. Routine synthesize_exception_spec merges all these exceptions as the possible exceptions for this constructor. Similar is the copy operation and destructor. Notice that if a function is declared without specifying exception can throw exception of any kind.
825 static tree
826 synthesize_exception_spec (tree type, tree (*extractor) (tree, void*), in method.c
827 void *client)
828 {
829 tree raises = empty_except_spec;
830 tree fields = TYPE_FIELDS (type);
831 int i, n_bases = CLASSTYPE_N_BASECLASSES (type);
832 tree binfos = TYPE_BINFO_BASETYPES (type);
833
834 for (i = 0; i != n_bases; i++)
835 {
836 tree base = BINFO_TYPE (TREE_VEC_ELT (binfos, i));
837 tree fn = (*extractor) (base, client);
838 if (fn)
839 {
840 tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
841
842 raises = merge_exception_specifiers (raises, fn_raises);
843 }
844 }
845 for (; fields; fields = TREE_CHAIN (fields))
846 {
847 tree type = TREE_TYPE (fields);
848 tree fn;
849
850 if (TREE_CODE (fields) != FIELD_DECL || DECL_ARTIFICIAL (fields))
851 continue ;
852 while (TREE_CODE (type) == ARRAY_TYPE)
853 type = TREE_TYPE (type);
854 if (!CLASS_TYPE_P (type))
855 continue ;
856
857 fn = (*extractor) (type, client);
858 if (fn)
859 {
860 tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
861
862 raises = merge_exception_specifiers (raises, fn_raises);
863 }
864 }
865 return raises;
866 }
Routine locate_ctor works similarly as locate_dtor and locate_copy , we just take it as the example. It just finds out the corresponding methods in type .
884 static tree
885 locate_ctor (tree type, void *client ATTRIBUTE_UNUSED) in method.c
886 {
887 tree fns;
888
889 if (!TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
890 return NULL_TREE;
891
892 fns = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type),
893 CLASSTYPE_CONSTRUCTOR_SLOT);
894 for (; fns; fns = OVL_NEXT (fns))
895 {
896 tree fn = OVL_CURRENT (fns);
897 tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn));
898
899 parms = skip_artificial_parms_for (fn, parms);
900
901 if (sufficient_parms_p (parms))
902 return fn;
903 }
904 return NULL_TREE;
905 }
Further these artificial methods are recorded within deferred_fns , then their translations would be taken at the end of the compilation.
1120 void
1121 defer_fn (tree fn) in decl2.c
1122 {
1123 if (DECL_DEFERRED_FN (fn))
1124 return ;
1125 DECL_DEFERRED_FN (fn) = 1;
1126 DECL_DEFER_OUTPUT (fn) = 1;
1127 if (!deferred_fn s)
1128 VARRAY_TREE_INIT (deferred_fns , 32, "deferred_fns");
1129
1130 VARRAY_PUSH_TREE (deferred_fns , fn);
1131 }
Remember that access_decls below is filled by check_field_decls for USING_DECL. In class, using directive can only access member of base class, as below example:
class A {
protected :
void a();
};
class B: public A {
public :
using A::a;
};
check_bases_and_members (continue)
4208 /* Create the in-charge and not-in-charge variants of constructors
4209 and destructors. */
4210 clone_constructors_and_destructors (t);
4211
4212 /* Process the using-declarations. */
4213 for (; access_decls; access_decls = TREE_CHAIN (access_decls))
4214 handle_using_decl (TREE_VALUE (access_decls), t);
4215
4216 /* Build and sort the CLASSTYPE_METHOD_VEC. */
4217 finish_struct_methods (t);
4218
4219 /* Figure out whether or not we will need a cookie when dynamically
4220 allocating an array of this type. */
4221 TYPE_LANG_SPECIFIC (t)->u.c.vec_new_uses_cookie
4222 = type_requires_array_cookie (t);
4223 }
Before going ahead with clone_constructors_and_destructors , something needs explain. We skip the detail of instantiation of constructor of “SmallObject” in above for keeping concise; however a special treatment for the constructor and destructor worthes a look upon. This special treatment is executed by maybe_retrofit_in_chrg which applied for class of virtual derivation. Provided by grammar, single instance of virtual base class is shared among instances of derived classes no matter how many they are. So need extra argument in the constructor and destructor to control its generation (i.e, in-charge parameter below). Pay attention to condition in line 236 ~ 237, class without virtual base doesn’t use in-charge parameter. Below basetype refers to the type pointed by the this pointer. Then at line 272, the updated definitions of constructor and destructor are created.
220 void
221 maybe_retrofit_in_chrg (tree fn) in decl2.c
222 {
223 tree basetype, arg_types, parms, parm, fntype;
224
225 /* If we've already add the in-charge parameter don't do it again. */
226 if (DECL_HAS_IN_CHARGE_PARM_P (fn))
227 return ;
228
229 /* When processing templates we can't know, in general, whether or
230 not we're going to have virtual baseclasses. */
231 if (processing_template_decl)
232 return ;
233
234 /* We don't need an in-charge parameter for constructors that don't
235 have virtual bases. */
236 if (DECL_CONSTRUCTOR_P (fn)
237 && !TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn)))
238 return ;
239
240 arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn));
241 basetype = TREE_TYPE (TREE_VALUE (arg_types));
242 arg_types = TREE_CHAIN (arg_types);
243
244 parms = TREE_CHAIN (DECL_ARGUMENTS (fn));
245
246 /* If this is a subobject constructor or destructor, our caller will
247 pass us a pointer to our VTT. */
248 if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn)))
249 {
250 parm = build_artificial_parm (vtt_parm_identifier , vtt_parm_type);
251
252 /* First add it to DECL_ARGUMENTS between 'this' and the real args... */
253 TREE_CHAIN (parm) = parms;
254 parms = parm;
255
256 /* ...and then to TYPE_ARG_TYPES. */
257 arg_types = hash_tree_chain (vtt_parm_type, arg_types);
258
259 DECL_HAS_VTT_PARM_P (fn) = 1;
260 }
261
262 /* Then add the in-charge parm (before the VTT parm). */
263 parm = build_artificial_parm (in_charge_identifier , integer_type_node);
264 TREE_CHAIN (parm) = parms;
265 parms = parm;
266 arg_types = hash_tree_chain (integer_type_node, arg_types);
267
268 /* Insert our new parameter(s) into the list. */
269 TREE_CHAIN (DECL_ARGUMENTS (fn)) = parms;
270
271 /* And rebuild the function type. */
272 fntype = build_method_type_directly (basetype, TREE_TYPE (TREE_TYPE (fn)),
273 arg_types);
274 if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)))
275 fntype = build_exception_variant (fntype,
276 TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)));
277 TREE_TYPE (fn) = fntype;
278
279 /* Now we've got the in-charge parameter. */
280 DECL_HAS_IN_CHARGE_PARM_P (fn) = 1;
281 }
With virtual base, and in the creating instance of derived, all bases derived from the virtual base (including the derived itself) should only share single the virutal base (compared withnon-virtual derivation, all bases derived from the base have their own copy of the base). So within the derivation tree, there must be one class to take charge of creating and destroying the virtual base. Usually, it is the class most derived. For example:
class A {…};
class B: public virtual A {…};
in the tree constructed by A and B, no doubt B is responsible for creating and destorying A. But,
class C: public B, B1 {…};
it is C in charge of A, and B is discharged. As everyone has the chance, every class derives from virtual base (directly or indirectly) needs following two variants of every constructor and destructor.
4502 static void
4503 clone_constructors_and_destructors (tree t) in class.c
4504 {
4505 tree fns;
4506
4507 /* If for some reason we don't have a CLASSTYPE_METHOD_VEC, we bail
4508 out now. */
4509 if (!CLASSTYPE_METHOD_VEC (t))
4510 return ;
4511
4512 for (fns = CLASSTYPE_CONSTRUCTORS (t); fns; fns = OVL_NEXT (fns))
4513 clone_function_decl (OVL_CURRENT (fns), /*update_method_vec_p=*/ 1);
4514 for (fns = CLASSTYPE_DESTRUCTORS (t); fns; fns = OVL_NEXT (fns))
4515 clone_function_decl (OVL_CURRENT (fns), /*update_method_vec_p=*/ 1);
4516 }
Following variant would be created:
complete_ctor_identifier : the name of a constructor that constructs virtual base classes.
base_ctor_identifier : the name of a constructor that does not construct virtual base classes.
complete_dtor_identifier : the name of a destructor that destroys virtual base classes.
base_dtor_identifier : the name of a destructor that does not destroy virtual base classes.
deleting_dtor_identifier : the name of a destructor that destroys virtual base classes, and then deletes the entire object.
Note that variants built by clone_function_decl will be linked into above fns (maybe visited via OVL_NEXT), and DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P below has definition:
“(DECL_CONSTRUCTOR_P (NODE) && !DECL_CLONED_FUNCTION_P (NODE))”
Condtion at line 3930 ~ 3931 filters out the variants (i.e., cloned function), thus IF block at line 3934 handles non-variant constructors, ELSE block at line 3945 handles non-variant desctructors. And here argument update_method_vec_p of clone_function_decl is 1.
3924 void
3925 clone_function_decl (tree fn, int update_method_vec_p) in class.c
3926 {
3927 tree clone;
3928
3929 /* Avoid inappropriate cloning. */
3930 if (TREE_CHAIN (fn)
3931 && DECL_CLONED_FUNCTION (TREE_CHAIN (fn)))
3932 return ;
3933
3934 if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn))
3935 {
3936 /* For each constructor, we need two variants: an in-charge version
3937 and a not-in-charge version. */
3938 clone = build_clone (fn, complete_ctor_identifier );
3939 if (update_method_vec_p)
3940 add_method (DECL_CONTEXT (clone), clone, /*error_p=*/ 0);
3941 clone = build_clone (fn, base_ctor_identifier );
3942 if (update_method_vec_p)
3943 add_method (DECL_CONTEXT (clone), clone, /*error_p=*/ 0);
3944 }
3945 else
3946 {
3947 my_friendly_assert (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn), 20000411);
3948
3949 /* For each destructor, we need three variants: an in-charge
3950 version, a not-in-charge version, and an in-charge deleting
3951 version. We clone the deleting version first because that
3952 means it will go second on the TYPE_METHODS list -- and that
3953 corresponds to the correct layout order in the virtual
3954 function table.
3955
3956 For a non-virtual destructor, we do not build a deleting
3957 destructor. */
3958 if (DECL_VIRTUAL_P (fn))
3959 {
3960 clone = build_clone (fn, deleting_dtor_identifier );
3961 if (update_method_vec_p)
3962 add_method (DECL_CONTEXT (clone), clone, /*error_p=*/ 0);
3963 }
3964 clone = build_clone (fn, complete_dtor_identifier );
3965 if (update_method_vec_p)
3966 add_method (DECL_CONTEXT (clone), clone, /*error_p=*/ 0);
3967 clone = build_clone (fn, base_dtor_identifier );
3968 if (update_method_vec_p)
3969 add_method (DECL_CONTEXT (clone), clone, /*error_p=*/ 0);
3970 }
3971
3972 /* Note that this is an abstract function that is never emitted. */
3973 DECL_ABSTRACT (fn) = 1;
3974 }
Deleting a pointer of base class which pointing to an instance of the derived, generally will cause big trouble, unless the destructor of the base is declared as virtual (condition at line 3958), by which instance of the derived can be deleted correctly. Note here doesn’t give the definitions for the variants, in fact the most important thing is complete_dtor_identifier and such, they will tell the compiler how to combines invoking of the constructors or the destructors.
See line 3827 below, for base_dtor_identifier , never define it as virtual, even the destructor iteself is virtual. In later sections we can see that the derived of virtual base has VTT (virtual virtual table), invoking virtual method of bases and referring virtual bases should via VTT, so VTT should be passed in the bases’ constructor and set its vptr pointing to certain position of VTT. At line 3852, build_method_type_directly builds method type matching the declaration, so needs remove the “artifical” parameters added by the compiler first (see maybe_retrofit_in_chrg ). At line 3839, TYPE_METHOD_BASETYPE returns the type pointed by this pointer, which will be added in build_method_type_directly , so need removed also.
3802 static tree
3803 build_clone (tree fn, tree name) in class.c
3804 {
3805 tree parms;
3806 tree clone;
3807
3808 /* Copy the function. */
3809 clone = copy_decl (fn);
3810 /* Remember where this function came from. */
3811 DECL_CLONED_FUNCTION (clone) = fn;
3812 DECL_ABSTRACT_ORIGIN (clone) = fn;
3813 /* Reset the function name. */
3814 DECL_NAME (clone) = name;
3815 SET_DECL_ASSEMBLER_NAME (clone, NULL_TREE);
3816 /* There's no pending inline data for this function. */
3817 DECL_PENDING_INLINE_INFO (clone) = NULL;
3818 DECL_PENDING_INLINE_P (clone) = 0;
3819 /* And it hasn't yet been deferred. */
3820 DECL_DEFERRED_FN (clone) = 0;
3821
3822 /* The base-class destructor is not virtual. */
3823 if (name == base_dtor_identifier )
3824 {
3825 DECL_VIRTUAL_P (clone) = 0;
3826 if (TREE_CODE (clone) != TEMPLATE_DECL)
3827 DECL_VINDEX (clone) = NULL_TREE;
3828 }
3829
3830 /* If there was an in-charge parameter, drop it from the function
3831 type. */
3832 if (DECL_HAS_IN_CHARGE_PARM_P (clone))
3833 {
3834 tree basetype;
3835 tree parmtypes;
3836 tree exceptions;
3837
3838 exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (clone));
3839 basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (clone));
3840 parmtypes = TYPE_ARG_TYPES (TREE_TYPE (clone));
3841 /* Skip the `this' parameter. */
3842 parmtypes = TREE_CHAIN (parmtypes);
3843 /* Skip the in-charge parameter. */
3844 parmtypes = TREE_CHAIN (parmtypes);
3845 /* And the VTT parm, in a complete [cd]tor. */
3846 if (DECL_HAS_VTT_PARM_P (fn)
3847 && ! DECL_NEEDS_VTT_PARM_P (clone))
3848 parmtypes = TREE_CHAIN (parmtypes);
3849 /* If this is subobject constructor or destructor, add the vtt
3850 parameter. */
3851 TREE_TYPE (clone)
3852 = build_method_type_directly (basetype,
3853 TREE_TYPE (TREE_TYPE (clone)),
3854 parmtypes);
3855 if (exceptions)
3856 TREE_TYPE (clone) = build_exception_variant (TREE_TYPE (clone),
3857 exceptions);
3858 TREE_TYPE (clone)
3859 = cp_build_type_attribute_variant (TREE_TYPE (clone),
3860 TYPE_ATTRIBUTES (TREE_TYPE (fn)));
3861 }
3862
3863 /* Copy the function parameters. But, DECL_ARGUMENTS on a TEMPLATE_DECL
3864 aren't function parameters; those are the template parameters. */
3865 if (TREE_CODE (clone) != TEMPLATE_DECL)
3866 {
3867 DECL_ARGUMENTS (clone) = copy_list (DECL_ARGUMENTS (clone));
3868 /* Remove the in-charge parameter. */
3869 if (DECL_HAS_IN_CHARGE_PARM_P (clone))
3870 {
3871 TREE_CHAIN (DECL_ARGUMENTS (clone))
3872 = TREE_CHAIN (TREE_CHAIN (DECL_ARGUMENTS (clone)));
3873 DECL_HAS_IN_CHARGE_PARM_P (clone) = 0;
3874 }
3875 /* And the VTT parm, in a complete [cd]tor. */
3876 if (DECL_HAS_VTT_PARM_P (fn))
3877 {
3878 if (DECL_NEEDS_VTT_PARM_P (clone))
3879 DECL_HAS_VTT_PARM_P (clone) = 1;
3880 else
3881 {
3882 TREE_CHAIN (DECL_ARGUMENTS (clone))
3883 = TREE_CHAIN (TREE_CHAIN (DECL_ARGUMENTS (clone)));
3884 DECL_HAS_VTT_PARM_P (clone) = 0;
3885 }
3886 }
3887
3888 for (parms = DECL_ARGUMENTS (clone); parms; parms = TREE_CHAIN (parms))
3889 {
3890 DECL_CONTEXT (parms) = clone;
3891 cxx_dup_lang_specific_decl (parms);
3892 }
3893 }
3894
3895 /* Create the RTL for this function. */
3896 SET_DECL_RTL (clone, NULL_RTX);
3897 rest_of_decl_compilation (clone, NULL, /*top_level=*/ 1, at_eof );
3898
3899 /* Make it easy to find the CLONE given the FN. */
3900 TREE_CHAIN (clone) = TREE_CHAIN (fn);
3901 TREE_CHAIN (fn) = clone;
3902
3903 /* If this is a template, handle the DECL_TEMPLATE_RESULT as well. */
3904 if (TREE_CODE (clone) == TEMPLATE_DECL)
3905 {
3906 tree result;
3907
3908 DECL_TEMPLATE_RESULT (clone)
3909 = build_clone (DECL_TEMPLATE_RESULT (clone), name);
3910 result = DECL_TEMPLATE_RESULT (clone);
3911 DECL_TEMPLATE_INFO (result) = copy_node (DECL_TEMPLATE_INFO (result));
3912 DECL_TI_TEMPLATE (result) = clone;
3913 }
3914 else if (DECL_DEFERRED_FN (fn))
3915 defer_fn (clone);
3916
3917 return clone;
3918 }
In IF block at line 3865 above, in-charge parameter isn’t needed any more, as the derived handling virtual base should offer VTT. Obviously, for complete_[cd]tor_identifier , it doesn’t take VTT as parameter, but for base_[cd]tor_identifier , it needs VTT in its parameters. Note that here it processes DECL_ARGUMENTS, which indicates the requirement for arguments at invocation. Code at line 3896, 3897 generates RTL code for these variants, see that there is only declaration but no definition for variants, but the compiler knows their meanings.