GCC-3.4.6源代码学习笔记(138)

5.12.5.2.2.2.1.3.8. 完成派生类的RECORD_TYPE – 补充缺少的方法 以前学习C++时,书本告诉我们如果你不为一个类定义构造函数的话,编译器会以自己的方式为你产生,连带的可能还有析构函数,拷贝构造函数及赋值操作符。下面就是这个地方,编译器补充所缺少的方法。 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 } 在代码中,TYPE_HAS_NONTRIVIAL_DESTRUCTOR为类型设置,如果其某些数据成员定义了析构函数。事实上,如果一个类的所有成员都没有定义析构函数,这样的类被称为具有一个平凡析构函数(trival destructor),编译器不会为其定义析构函数;否则,编译器应该定义析构函数,在其中为定义了析构函数的成员调用这些析构函数。构造函数的产生与此类似。不过对于拷贝构造函数及赋值操作符,只要用户没有定义,它们就会被编译器产生。看到2646行的check_for_override亦应用于该隐含的析构函数来获取其属性。 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 } 这段代码对我们来说相当熟悉。本质上产生这些“人造”( artificial)方法与处理用户定义的方法没有什么不一样,除了它们设置了DECL_ARTIFICIAL标记。对于1036到1045行的代码,可以参考第一个例子中关于解析构造函数的章节。 看到这些“人造”方法所能抛出的异常是,那些被基类构造函数及类成员构造函数所抛出的异常。函数synthesize_exception_spec把这些异常合并起来作为该构造函数可能抛出的异常集合。类似的还有拷贝构造函数及析构函数。注意到如果一个函数在声明时没有限定异常,那么它可抛出任意类型的异常。 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 } 函数locate_ctor类似于locate_dtor及locate_copy那样工作,我们只把它作为例子。它只是在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 } 进一步的,如果这些“人造”方法被记录在deferred_fns中,那么对它们的编译将在编译的末尾执行。 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_fns) 1128 VARRAY_TREE_INIT (deferred_fns, 32, "deferred_fns"); 1129 1130 VARRAY_PUSH_TREE (deferred_fns, fn); 1131 } 记得下面的access_decls由check_field_decls来填充用于USING_DECL。在类中,using指示只能访问基类的成员,如下面的例子: 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 } 在进入clone_constructors_and_destructors之前,需要做一些解释。在上面为了保持简洁,我们跳过了“SmallObject”构造函数的具现,不过对于构造函数及析构函数的一个特殊的处理值得一看。这个特殊的处理由maybe_retrofit_in_chrg来完成,应用在虚拟继承的类上。语法规定,不管有多少个派生类的实例,它们都共享单个虚拟基类的实例。因此在构造函数及析构函数中需要额外的参数来控制虚拟基类实例的产生(即下面的in-charge参数)。注意到236~237行的条件,没有虚拟继承的类不使用in-charge参数。下面的basetype是this指针指向的类型。而在272行,产生了更新后的构造函数及析构函数定义。 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 } 由于虚拟基类的存在,并且在构建派生类实例时,所有从该虚拟基类派生的基类成分(包括派生类自己)只能共享一个该虚拟基类的成分(比较非虚拟继承,每个由该基类派生的基类成分都有属于自己的该基类的成分);那么在该派生树中,必须有一个类来负责虚拟基类的构建及析构。通常这由派生程度最高的类负责。例如: class A {…}; class B: public virtual A {…}; 在由A,B构成的派生树中,毫无疑问B要负责A的构造及析构。而, class C: public B, B1 {…}; 则是C负责A的构造及析构,而B则卸任了。因为每人都有机会,每个虚拟基类的派生类(直接或间接)都需要为每个构造函数及析构函数准备如下两种变体。 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 } 下列变体将被构建: complete_ctor_identifier:构建虚拟基类的构造函数名。 base_ctor_identifier:不构建虚拟基类的构造函数名。 complete_dtor_identifier:析构虚拟基类的析构函数名。 base_dtor_identifier:不析构虚拟基类的析构函数名。 deleting_dtor_identifier:析构虚拟基类,然后删除整个对象的析构函数名。 注意clone_function_decl构建的变体将链入上面的fns中(通过OVL_NEXT可能会访问到),而下面的DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P具有定义: “(DECL_CONSTRUCTOR_P (NODE) && !DECL_CLONED_FUNCTION_P (NODE))” 并且3930~3931行条件过滤了变体的情况(即克隆函数),因此3934行的IF块处理非变体构造函数,而3945行的ELSE块处理非变体析构函数。同时在这里clone_function_decl的参数update_method_vec_p为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 } 删除一个指向派生类的基类指针,通常会闹出大乱子,除非基类的析构函数被声明为virtual(满足3958行的条件),这时可以正确删除派生类对象。注意这里并没有真正给出变体的定义,其实最重要的是complete_dtor_identifier这些标识符,它们将告诉编译器应该如何组合构造函数及析构函数的调用。 看到在下面的3827行,对于base_dtor_identifier,永远也不要把它定义为virtual,即便析构函数本身是virtual的。在后面在章节中会看到,从虚拟基类派生的派生类使用所谓的VTT(virtual virtual table,虚虚表),基类的所有虚方法及虚基类的调用都要通过VTT,因此调用这些基类构造函数时要传进VTT使vptr指向VTT的某一处。而3852行的build_method_type_directly是构建与构造函数声明匹配的函数类型,因此之前不得不费尽心思移走编译器添加的“人工”参数(参见maybe_retrofit_in_chrg)。在3839行的TYPE_METHOD_BASETYPE返回的是this指针所指向的类型,this指针会在build_method_type_directly中加入,故先行移去。 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 } 在上面3865行的IF块中,in-charge参数已经不再需要,因为负责处理虚拟基类的派生类需要提供VTT。显然对于complete_[cd]tor_identifier,它是不带VTT的,而对于base_[cd]tor_identifier则是需要VTT这个额外的参数。注意这里处理的是DECL_ARGUMENTS,它表示对调用时刻实参的要求。3896及3897行的代码为这些变体产生RTL代码,注意这些变体只有声明没有定义,但编译器明白它们的含义。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值