Studying note of GCC-3.4.6 source (138)

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.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
for Policy and Practice, 2018, 17(2): 179-195. In this article, Victor Wang Chen Neo examines the implementation of school-based curriculum development (SBCD) in Singapore. SBCD is a process where schools are given greater autonomy to develop and implement their own curriculum, rather than following a standardized national curriculum. The author begins by providing an overview of the history of curriculum development in Singapore, and how the shift towards SBCD came about. He then presents the findings of a study that he conducted, which involved interviews with school leaders who had implemented SBCD in their schools. The author identifies several factors that influenced the successful implementation of SBCD in these schools. These include strong leadership, a clear vision and direction for the school, and a focus on student learning and development. The author also highlights the importance of teacher training and support, as well as collaboration and communication among all stakeholders involved in the curriculum development process. However, the author also notes some challenges that schools face when implementing SBCD. These include a lack of resources, such as time and funding, as well as the need to balance autonomy with accountability to ensure that the curriculum developed meets national standards. Overall, the author suggests that SBCD has the potential to improve the quality of education in Singapore by allowing schools to tailor their curriculum to the needs and interests of their students. However, he also calls for continued support and guidance from the government to ensure that schools are able to implement SBCD effectively.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值