diff options
-rw-r--r-- | gnu/egcs/gcc/cp/decl.c | 617 |
1 files changed, 368 insertions, 249 deletions
diff --git a/gnu/egcs/gcc/cp/decl.c b/gnu/egcs/gcc/cp/decl.c index c60acc7b80d..4b6770d15ac 100644 --- a/gnu/egcs/gcc/cp/decl.c +++ b/gnu/egcs/gcc/cp/decl.c @@ -188,6 +188,8 @@ static tree record_builtin_java_type PROTO((const char *, int)); static const char *tag_name PROTO((enum tag_types code)); static void find_class_binding_level PROTO((void)); static struct binding_level *innermost_nonclass_level PROTO((void)); +static void finish_dtor PROTO((void)); +static void finish_ctor PROTO((int)); static tree poplevel_class PROTO((void)); static void warn_about_implicit_typename_lookup PROTO((tree, tree)); static int walk_namespaces_r PROTO((tree, walk_namespaces_fn, void *)); @@ -335,6 +337,15 @@ tree __ptr_desc_array_type, __attr_dec_array_type, __func_desc_array_type; tree __ptmf_desc_array_type, __ptmd_desc_array_type; #endif +/* This is the identifier __vlist. */ +tree vlist_identifier; + +/* This is the type _Vlist = vtable_entry_type**. */ +tree vlist_type_node; + +/* A null pointer of type _Vlist. */ +tree vlist_zero_node; + /* Indicates that there is a type value in some namespace, although that is not necessarily in scope at the moment. */ @@ -6283,6 +6294,7 @@ init_decl_processing () this_identifier = get_identifier (THIS_NAME); in_charge_identifier = get_identifier (IN_CHARGE_NAME); + vlist_identifier = get_identifier (VLIST_NAME); ctor_identifier = get_identifier (CTOR_NAME); dtor_identifier = get_identifier (DTOR_NAME); pfn_identifier = get_identifier (VTABLE_PFN_NAME); @@ -6510,6 +6522,7 @@ init_decl_processing () #if 0 record_builtin_type (RID_MAX, NULL_PTR, ptr_type_node); #endif + endlink = void_list_node; int_endlink = tree_cons (NULL_TREE, integer_type_node, endlink); double_endlink = tree_cons (NULL_TREE, double_type_node, endlink); @@ -6849,6 +6862,16 @@ init_decl_processing () layout_type (vtbl_ptr_type_node); record_builtin_type (RID_MAX, NULL_PTR, vtbl_ptr_type_node); + if (flag_vtable_thunks) + { + /* We need vlists only when using thunks; otherwise leave them + as NULL_TREE. That way, it doesn't get into the way of the + mangling. */ + vlist_type_node = build_pointer_type (vtbl_ptr_type_node); + vlist_zero_node = build_int_2 (0, 0); + TREE_TYPE (vlist_zero_node) = vlist_type_node; + } + /* Simplify life by making a "sigtable_entry_type". Give its fields names so that the debugger can use them. */ @@ -11386,6 +11409,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (decl))) arg_types = TREE_CHAIN (arg_types); + /* And the `vlist' argument. */ + if (TYPE_USES_PVBASES (DECL_CONTEXT (decl))) + arg_types = TREE_CHAIN (arg_types); + if (arg_types == void_list_node || (arg_types && TREE_CHAIN (arg_types) @@ -12080,6 +12107,9 @@ replace_defarg (arg, init) TREE_PURPOSE (arg) = init; } +/* Return 1 if D copies its arguments. This is used to test for copy + constructors and copy assignment operators. */ + int copy_args_p (d) tree d; @@ -12087,7 +12117,12 @@ copy_args_p (d) tree t = FUNCTION_ARG_CHAIN (d); if (DECL_CONSTRUCTOR_P (d) && TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (d))) - t = TREE_CHAIN (t); + { + t = TREE_CHAIN (t); + if (TYPE_USES_PVBASES (DECL_CONTEXT (d))) + t = TREE_CHAIN (t); + } + if (t && TREE_CODE (TREE_VALUE (t)) == REFERENCE_TYPE && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (t))) == DECL_CLASS_CONTEXT (d)) @@ -12117,7 +12152,8 @@ grok_ctor_properties (ctype, decl) added to any ctor so we can tell if the class has been initialized yet. This could screw things up in this function, so we deliberately ignore the leading int if we're in that situation. */ - if (TYPE_USES_VIRTUAL_BASECLASSES (ctype)) + if (TYPE_USES_VIRTUAL_BASECLASSES (ctype) + && !CLASSTYPE_IS_TEMPLATE (ctype)) { my_friendly_assert (parmtypes && TREE_VALUE (parmtypes) == integer_type_node, @@ -12126,6 +12162,15 @@ grok_ctor_properties (ctype, decl) parmtype = TREE_VALUE (parmtypes); } + if (TYPE_USES_PVBASES (ctype)) + { + my_friendly_assert (parmtypes + && TREE_VALUE (parmtypes) == vlist_type_node, + 980529); + parmtypes = TREE_CHAIN (parmtypes); + parmtype = TREE_VALUE (parmtypes); + } + /* [class.copy] A non-template constructor for class X is a copy constructor if @@ -12923,6 +12968,16 @@ xref_basetypes (code_type_node, name, ref, binfo) { TYPE_USES_VIRTUAL_BASECLASSES (ref) = 1; TYPE_USES_COMPLEX_INHERITANCE (ref) = 1; + /* The PVBASES flag is never set for templates; we know + only for instantiations whether the virtual bases are + polymorphic. */ + if (flag_vtable_thunks >= 2 && !CLASSTYPE_IS_TEMPLATE (ref)) + { + if (via_virtual && TYPE_VIRTUAL_P (basetype)) + TYPE_USES_PVBASES (ref) = 1; + else if (TYPE_USES_PVBASES (basetype)) + TYPE_USES_PVBASES (ref) = 1; + } } if (CLASS_TYPE_P (basetype)) @@ -13928,6 +13983,313 @@ store_return_init (return_id, init) } +/* Emit implicit code for a destructor. This is a subroutine of + finish_function. */ + +static void +finish_dtor () +{ + tree binfo = TYPE_BINFO (current_class_type); + tree cond = integer_one_node; + tree exprstmt; + tree in_charge_node = lookup_name (in_charge_identifier, 0); + tree virtual_size; + int ok_to_optimize_dtor = 0; + int empty_dtor = get_last_insn () == last_dtor_insn; + rtx insns, last_parm_insn; + + if (current_function_assigns_this) + cond = build (NE_EXPR, boolean_type_node, + current_class_ptr, integer_zero_node); + else + { + int n_baseclasses = CLASSTYPE_N_BASECLASSES (current_class_type); + + /* If this destructor is empty, then we don't need to check + whether `this' is NULL in some cases. */ + if ((flag_this_is_variable & 1) == 0) + ok_to_optimize_dtor = 1; + else if (empty_dtor) + ok_to_optimize_dtor + = (n_baseclasses == 0 + || (n_baseclasses == 1 + && TYPE_HAS_DESTRUCTOR (TYPE_BINFO_BASETYPE (current_class_type, 0)))); + } + + /* If this has a vlist1 parameter, allocate the corresponding vlist + parameter. */ + if (DECL_DESTRUCTOR_FOR_PVBASE_P (current_function_decl)) + { + /* _Vlist __vlist; */ + tree vlist; + + mark_all_temps_used(); + vlist = pushdecl (build_decl (VAR_DECL, vlist_identifier, + vlist_type_node)); + TREE_USED (vlist) = 1; + DECL_ARTIFICIAL (vlist) = 1; + expand_decl (vlist); + expand_decl_init (vlist); + } + + /* These initializations might go inline. Protect + the binding level of the parms. */ + pushlevel (0); + expand_start_bindings (0); + + if (current_function_assigns_this) + { + current_function_assigns_this = 0; + current_function_just_assigned_this = 0; + } + + /* Generate the code to call destructor on base class. + If this destructor belongs to a class with virtual + functions, then set the virtual function table + pointer to represent the type of our base class. */ + + /* This side-effect makes call to `build_delete' generate the + code we have to have at the end of this destructor. + `build_delete' will set the flag again. */ + TYPE_HAS_DESTRUCTOR (current_class_type) = 0; + + /* These are two cases where we cannot delegate deletion. */ + if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type) + || TYPE_GETS_REG_DELETE (current_class_type)) + exprstmt = build_delete + (current_class_type, current_class_ref, integer_zero_node, + LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL, 0); + else + exprstmt = build_delete + (current_class_type, current_class_ref, in_charge_node, + LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL, 0); + + /* If we did not assign to this, then `this' is non-zero at + the end of a destructor. As a special optimization, don't + emit test if this is an empty destructor. If it does nothing, + it does nothing. If it calls a base destructor, the base + destructor will perform the test. */ + + if (exprstmt != error_mark_node + && (TREE_CODE (exprstmt) != NOP_EXPR + || TREE_OPERAND (exprstmt, 0) != integer_zero_node + || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))) + { + expand_label (dtor_label); + if (cond != integer_one_node) + expand_start_cond (cond, 0); + if (exprstmt != void_zero_node) + /* Don't call `expand_expr_stmt' if we're not going to do + anything, since -Wall will give a diagnostic. */ + expand_expr_stmt (exprstmt); + + /* Run destructor on all virtual baseclasses. */ + if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)) + { + tree vbases = nreverse + (copy_list (CLASSTYPE_VBASECLASSES (current_class_type))); + expand_start_cond (build (BIT_AND_EXPR, integer_type_node, + in_charge_node, integer_two_node), 0); + while (vbases) + { + if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (vbases))) + { + tree vb = get_vbase + (BINFO_TYPE (vbases), + TYPE_BINFO (current_class_type)); + + expand_expr_stmt + (build_base_dtor_call (current_class_ref, + vb, integer_zero_node)); + } + vbases = TREE_CHAIN (vbases); + } + expand_end_cond (); + } + + do_pending_stack_adjust (); + if (cond != integer_one_node) + expand_end_cond (); + } + + virtual_size = c_sizeof (current_class_type); + + /* At the end, call delete if that's what's requested. */ + + /* FDIS sez: At the point of definition of a virtual destructor + (including an implicit definition), non-placement operator + delete shall be looked up in the scope of the destructor's + class and if found shall be accessible and unambiguous. + + This is somewhat unclear, but I take it to mean that if the + class only defines placement deletes we don't do anything here. + So we pass LOOKUP_SPECULATIVELY; delete_sanity will complain + for us if they ever try to delete one of these. */ + + if (TYPE_GETS_REG_DELETE (current_class_type) + || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)) + exprstmt = build_op_delete_call + (DELETE_EXPR, current_class_ptr, virtual_size, + LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE); + else + exprstmt = NULL_TREE; + + if (exprstmt) + { + cond = build (BIT_AND_EXPR, integer_type_node, + in_charge_node, integer_one_node); + expand_start_cond (cond, 0); + expand_expr_stmt (exprstmt); + expand_end_cond (); + } + + /* End of destructor. */ + expand_end_bindings (NULL_TREE, getdecls () != NULL_TREE, 0); + poplevel (getdecls () != NULL_TREE, 0, 0); + + /* Back to the top of destructor. */ + /* Don't execute destructor code if `this' is NULL. */ + + start_sequence (); + + /* If we need thunk-style vlists, initialize them if the caller did + not pass them. This requires a new temporary. The generated code + looks like + if (!(__in_charge & 4)) + __vlist = __vl.<type> + sizeof(__vl.<type>); + else + __vlist = __vlist1; + */ + if (TYPE_USES_PVBASES (current_class_type)) + { + tree vlist = lookup_name (vlist_identifier, 0); + tree vlist1 = lookup_name (get_identifier (VLIST1_NAME), 0); + cond = build (BIT_AND_EXPR, integer_type_node, + in_charge_node, build_int_2 (4, 0)); + cond = build1 (TRUTH_NOT_EXPR, boolean_type_node, cond); + expand_start_cond (cond, 0); + init_vlist (current_class_type); + expand_start_else (); + expand_expr_stmt (build_modify_expr (vlist, NOP_EXPR, vlist1)); + expand_end_cond (); + } + + /* If the dtor is empty, and we know there is not possible way we + could use any vtable entries, before they are possibly set by + a base class dtor, we don't have to setup the vtables, as we + know that any base class dtoring will set up any vtables it + needs. We avoid MI, because one base class dtor can do a + virtual dispatch to an overridden function that would need to + have a non-related vtable set up, we cannot avoid setting up + vtables in that case. We could change this to see if there is + just one vtable. */ + if (! empty_dtor || TYPE_USES_COMPLEX_INHERITANCE (current_class_type)) + { + /* Make all virtual function table pointers in non-virtual base + classes point to CURRENT_CLASS_TYPE's virtual function + tables. */ + expand_direct_vtbls_init (binfo, binfo, 1, 0, current_class_ptr); + + if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)) + expand_indirect_vtbls_init (binfo, current_class_ref, current_class_ptr); + } + + if (! ok_to_optimize_dtor) + { + cond = build_binary_op (NE_EXPR, + current_class_ptr, integer_zero_node); + expand_start_cond (cond, 0); + } + + insns = get_insns (); + end_sequence (); + + last_parm_insn = get_first_nonparm_insn (); + if (last_parm_insn == NULL_RTX) + last_parm_insn = get_last_insn (); + else + last_parm_insn = previous_insn (last_parm_insn); + + emit_insns_after (insns, last_parm_insn); + + if (! ok_to_optimize_dtor) + expand_end_cond (); +} + +/* Emit implicit code for a constructor. This is a subroutine of + finish_function. CALL_POPLEVEL is the same variable in + finish_function. */ + +static void +finish_ctor (call_poplevel) + int call_poplevel; +{ + register tree fndecl = current_function_decl; + tree cond = NULL_TREE, thenclause = NULL_TREE; + rtx insns; + tree decls; + + /* Allow constructor for a type to get a new instance of the object + using `build_new'. */ + tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type); + CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = NULL_TREE; + + if (flag_this_is_variable > 0) + { + cond = build_binary_op (EQ_EXPR, current_class_ptr, integer_zero_node); + thenclause = + build_modify_expr (current_class_ptr, NOP_EXPR, + build_new (NULL_TREE, current_class_type, + void_type_node, 0)); + } + + CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = abstract_virtuals; + + start_sequence (); + + if (flag_this_is_variable > 0) + { + expand_start_cond (cond, 0); + expand_expr_stmt (thenclause); + expand_end_cond (); + } + + /* Emit insns from `emit_base_init' which sets up virtual + function table pointer(s). */ + if (base_init_expr) + { + expand_expr_stmt (base_init_expr); + base_init_expr = NULL_TREE; + } + + insns = get_insns (); + end_sequence (); + + /* This is where the body of the constructor begins. */ + + emit_insns_after (insns, last_parm_cleanup_insn); + + end_protect_partials (); + + /* This is where the body of the constructor ends. */ + expand_label (ctor_label); + ctor_label = NULL_TREE; + + if (call_poplevel) + { + decls = getdecls (); + expand_end_bindings (decls, decls != NULL_TREE, 0); + poplevel (decls != NULL_TREE, 1, 0); + } + + /* c_expand_return knows to return 'this' from a constructor. */ + c_expand_return (NULL_TREE); + + current_function_assigns_this = 0; + current_function_just_assigned_this = 0; +} + + /* Finish up a function declaration and compile that function all the way to assembler language output. The free the storage for the function definition. @@ -13956,7 +14318,6 @@ finish_function (lineno, flags, nested) { register tree fndecl = current_function_decl; tree fntype, ctype = NULL_TREE; - rtx last_parm_insn, insns; /* Label to use if this function is supposed to return a value. */ tree no_return_label = NULL_TREE; tree decls = NULL_TREE; @@ -14018,191 +14379,7 @@ finish_function (lineno, flags, nested) do_pending_stack_adjust (); if (dtor_label) - { - tree binfo = TYPE_BINFO (current_class_type); - tree cond = integer_one_node; - tree exprstmt; - tree in_charge_node = lookup_name (in_charge_identifier, 0); - tree virtual_size; - int ok_to_optimize_dtor = 0; - int empty_dtor = get_last_insn () == last_dtor_insn; - - if (current_function_assigns_this) - cond = build (NE_EXPR, boolean_type_node, - current_class_ptr, integer_zero_node); - else - { - int n_baseclasses = CLASSTYPE_N_BASECLASSES (current_class_type); - - /* If this destructor is empty, then we don't need to check - whether `this' is NULL in some cases. */ - if ((flag_this_is_variable & 1) == 0) - ok_to_optimize_dtor = 1; - else if (empty_dtor) - ok_to_optimize_dtor - = (n_baseclasses == 0 - || (n_baseclasses == 1 - && TYPE_HAS_DESTRUCTOR (TYPE_BINFO_BASETYPE (current_class_type, 0)))); - } - - /* These initializations might go inline. Protect - the binding level of the parms. */ - pushlevel (0); - expand_start_bindings (0); - - if (current_function_assigns_this) - { - current_function_assigns_this = 0; - current_function_just_assigned_this = 0; - } - - /* Generate the code to call destructor on base class. - If this destructor belongs to a class with virtual - functions, then set the virtual function table - pointer to represent the type of our base class. */ - - /* This side-effect makes call to `build_delete' generate the - code we have to have at the end of this destructor. - `build_delete' will set the flag again. */ - TYPE_HAS_DESTRUCTOR (current_class_type) = 0; - - /* These are two cases where we cannot delegate deletion. */ - if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type) - || TYPE_GETS_REG_DELETE (current_class_type)) - exprstmt = build_delete (current_class_type, current_class_ref, integer_zero_node, - LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL, 0); - else - exprstmt = build_delete (current_class_type, current_class_ref, in_charge_node, - LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL, 0); - - /* If we did not assign to this, then `this' is non-zero at - the end of a destructor. As a special optimization, don't - emit test if this is an empty destructor. If it does nothing, - it does nothing. If it calls a base destructor, the base - destructor will perform the test. */ - - if (exprstmt != error_mark_node - && (TREE_CODE (exprstmt) != NOP_EXPR - || TREE_OPERAND (exprstmt, 0) != integer_zero_node - || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))) - { - expand_label (dtor_label); - if (cond != integer_one_node) - expand_start_cond (cond, 0); - if (exprstmt != void_zero_node) - /* Don't call `expand_expr_stmt' if we're not going to do - anything, since -Wall will give a diagnostic. */ - expand_expr_stmt (exprstmt); - - /* Run destructor on all virtual baseclasses. */ - if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)) - { - tree vbases = nreverse (copy_list (CLASSTYPE_VBASECLASSES (current_class_type))); - expand_start_cond (build (BIT_AND_EXPR, integer_type_node, - in_charge_node, integer_two_node), 0); - while (vbases) - { - if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (vbases))) - { - tree vb = get_vbase - (BINFO_TYPE (vbases), - TYPE_BINFO (current_class_type)); - expand_expr_stmt - (build_scoped_method_call - (current_class_ref, vb, dtor_identifier, - build_expr_list (NULL_TREE, integer_zero_node))); - } - vbases = TREE_CHAIN (vbases); - } - expand_end_cond (); - } - - do_pending_stack_adjust (); - if (cond != integer_one_node) - expand_end_cond (); - } - - virtual_size = c_sizeof (current_class_type); - - /* At the end, call delete if that's what's requested. */ - - /* FDIS sez: At the point of definition of a virtual destructor - (including an implicit definition), non-placement operator - delete shall be looked up in the scope of the destructor's - class and if found shall be accessible and unambiguous. - - This is somewhat unclear, but I take it to mean that if the - class only defines placement deletes we don't do anything here. - So we pass LOOKUP_SPECULATIVELY; delete_sanity will complain - for us if they ever try to delete one of these. */ - - if (TYPE_GETS_REG_DELETE (current_class_type) - || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)) - exprstmt = build_op_delete_call - (DELETE_EXPR, current_class_ptr, virtual_size, - LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE); - else - exprstmt = NULL_TREE; - - if (exprstmt) - { - cond = build (BIT_AND_EXPR, integer_type_node, - in_charge_node, integer_one_node); - expand_start_cond (cond, 0); - expand_expr_stmt (exprstmt); - expand_end_cond (); - } - - /* End of destructor. */ - expand_end_bindings (NULL_TREE, getdecls () != NULL_TREE, 0); - poplevel (getdecls () != NULL_TREE, 0, 0); - - /* Back to the top of destructor. */ - /* Don't execute destructor code if `this' is NULL. */ - - start_sequence (); - - /* If the dtor is empty, and we know there is not possible way we - could use any vtable entries, before they are possibly set by - a base class dtor, we don't have to setup the vtables, as we - know that any base class dtoring will set up any vtables it - needs. We avoid MI, because one base class dtor can do a - virtual dispatch to an overridden function that would need to - have a non-related vtable set up, we cannot avoid setting up - vtables in that case. We could change this to see if there is - just one vtable. */ - if (! empty_dtor || TYPE_USES_COMPLEX_INHERITANCE (current_class_type)) - { - /* Make all virtual function table pointers in non-virtual base - classes point to CURRENT_CLASS_TYPE's virtual function - tables. */ - expand_direct_vtbls_init (binfo, binfo, 1, 0, current_class_ptr); - - if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)) - expand_indirect_vtbls_init (binfo, current_class_ref, current_class_ptr); - } - - if (! ok_to_optimize_dtor) - { - cond = build_binary_op (NE_EXPR, - current_class_ptr, integer_zero_node); - expand_start_cond (cond, 0); - } - - insns = get_insns (); - end_sequence (); - - last_parm_insn = get_first_nonparm_insn (); - if (last_parm_insn == NULL_RTX) - last_parm_insn = get_last_insn (); - else - last_parm_insn = previous_insn (last_parm_insn); - - emit_insns_after (insns, last_parm_insn); - - if (! ok_to_optimize_dtor) - expand_end_cond (); - } + finish_dtor (); else if (current_function_assigns_this) { /* Does not need to call emit_base_init, because @@ -14232,67 +14409,9 @@ finish_function (lineno, flags, nested) current_function_just_assigned_this = 0; base_init_expr = NULL_TREE; } - else if (DECL_CONSTRUCTOR_P (fndecl)) - { - tree cond = NULL_TREE, thenclause = NULL_TREE; - /* Allow constructor for a type to get a new instance of the object - using `build_new'. */ - tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type); - CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = NULL_TREE; - - if (flag_this_is_variable > 0) - { - cond = build_binary_op (EQ_EXPR, - current_class_ptr, integer_zero_node); - thenclause = build_modify_expr (current_class_ptr, NOP_EXPR, - build_new (NULL_TREE, current_class_type, void_type_node, 0)); - } - - CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = abstract_virtuals; - - start_sequence (); - - if (flag_this_is_variable > 0) - { - expand_start_cond (cond, 0); - expand_expr_stmt (thenclause); - expand_end_cond (); - } - - /* Emit insns from `emit_base_init' which sets up virtual - function table pointer(s). */ - if (base_init_expr) - { - expand_expr_stmt (base_init_expr); - base_init_expr = NULL_TREE; - } - - insns = get_insns (); - end_sequence (); - - /* This is where the body of the constructor begins. */ - - emit_insns_after (insns, last_parm_cleanup_insn); - - end_protect_partials (); - - /* This is where the body of the constructor ends. */ - expand_label (ctor_label); - ctor_label = NULL_TREE; - - if (call_poplevel) - { - decls = getdecls (); - expand_end_bindings (decls, decls != NULL_TREE, 0); - poplevel (decls != NULL_TREE, 1, 0); - } - - /* c_expand_return knows to return 'this' from a constructor. */ - c_expand_return (NULL_TREE); - - current_function_assigns_this = 0; - current_function_just_assigned_this = 0; - } + else if (DECL_CONSTRUCTOR_P (fndecl) + && !DECL_VLIST_CTOR_WRAPPER_P (fndecl)) + finish_ctor (call_poplevel); else if (DECL_MAIN_P (fndecl)) { /* Make it so that `main' always returns 0 by default. */ |