From 834c6dff7ba7845c7fabeda67f711b5aa0f341d8 Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Fri, 3 Mar 2000 02:27:15 +0000 Subject: [PATCH] * tree.h (TYPE_ALIGN_UNIT): New macro. From-SVN: r32302 --- gcc/ChangeLog | 4 + gcc/cp/ChangeLog | 61 +++++ gcc/cp/call.c | 25 -- gcc/cp/class.c | 51 +++- gcc/cp/cp-tree.h | 60 +++-- gcc/cp/decl.c | 36 ++- gcc/cp/decl2.c | 2 +- gcc/cp/g++spec.c | 22 +- gcc/cp/init.c | 224 +++++++++++++----- gcc/cp/lex.c | 2 +- gcc/cp/pt.c | 3 +- gcc/cp/ptree.c | 6 +- gcc/cp/search.c | 4 +- gcc/cp/tree.c | 14 +- gcc/cp/typeck.c | 4 +- gcc/testsuite/g++.old-deja/g++.abi/arraynew.C | 127 ++++++++++ .../g++.old-deja/g++.other/inline7.C | 1 + gcc/tree.h | 4 + 18 files changed, 501 insertions(+), 149 deletions(-) create mode 100644 gcc/testsuite/g++.old-deja/g++.abi/arraynew.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 543b24e7796..d0eee382924 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,7 @@ +2000-03-02 Mark Mitchell + + * tree.h (TYPE_ALIGN_UNIT): New macro. + 2000-03-02 Clinton Popetz * config/i386/i386.c: (constant_call_address_operand): Reject diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b3c50929e53..d9bb284df1e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,64 @@ +2000-03-02 Mark Mitchell + + * cp-tree.h (TYPE_NEEDS_DESTRUCTOR): Rename to ... + (TYPE_HAS_NONTRIVIAL_DESTRUCTOR): ... this. + (TYPE_HAS_TRIVIAL_DESTRUCTOR): New macro. + (lang_type): Split gets_new into has_new and has_array_new. + (TYPE_VEC_NEW_USES_COOKIE): Use TYPE_HAS_NONTRIVIAL_DESTRUCTOR. + (TYPE_GETS_NEW): Split into ... + (TYPE_HAS_NEW_OPERATOR): ... this, and ... + (TYPE_HAS_ARRAY_NEW_OPERATOR): ... this. + (DECL_ARRAY_DELETE_OPERATOR_P): New macro + (build_op_new_call): Don't declare. + (build_new_1): Likewise. + * call.c (build_op_new_call): Remove. + * class.c (check_bases): Use TYPE_HAS_NONTRIVIAL_DESTRUCTOR + instead of TYPE_NEEDS_DESTRUCTOR. + (finish_struct_bits): Likewise. + (add_implicitly_declared_members): Likewise. + (check_field_decl): Likewise. + (check_methods): Set TYPE_VEC_DELETE_TAKES_SIZE here, and set it + correctly under the new ABI. + * decl.c (start_decl_1): Use TYPE_HAS_NONTRIVIAL_DESTRUCTOR + instead of TYPE_NEEDS_DESTRUCTOR. + (initialize_local_var): Likewise. + (destroy_local_var): Likewise. + (cp_finish_decl): Likewise. + (register_dtor_fn): Likewise. + (grok_op_properties): Set TYPE_HAS_NEW_OPERATOR and + TYPE_HAS_ARRAY_NEW_OPERATOR, not TYPE_HAS_NEW. Don't set + TYPE_VEC_DELETE_TAKES_SIZE here. + (xref_basetypes): Set TYPE_HAS_NEW_OPERATOR and + TYPE_HAS_ARRAY_NEW_OPERATOR, not TYPE_HAS_NEW. + (store_parm_decls): Use TYPE_HAS_NONTRIVIAL_DESTRUCTOR. + (finish_destructor_body): Likewise. + (maybe_build_cleanup_1): Likewise. + * decl2.c (do_static_destruction): Likewise. + * init.c (build_new_1): Make it static. + (perform_member_init): Use TYPE_HAS_NONTRIVIAL_DESTRUCTOR. + (expand_cleanup_for_base): Likewise. + (get_cookie_size): New function. + (build_new_1): Handle array-new cookies correctly under the new + ABI. + (build_vec_delete_1): Likewise. + (build_vec_init): Use TYPE_HAS_NONTRIVIAL_DESTRUCTOR. + (build_delete): Likewise. + (build_vec_delete): Handle array-new cookies correctly under the new + ABI. + * lex.c (do_identifier): Use TYPE_HAS_NONTRIVIAL_DESTRUCTOR. + * pt.c (instantiate_class_template): Set TYPE_HAS_NEW_OPERATOR and + TYPE_HAS_ARRAY_NEW_OPERATOR. + * ptree.c (print_lang_type): Check them. + * search.c (context_for_name_lookup): Fix typo in comment. + (tree_has_any_destructor_p): Use TYPE_HAS_NONTRIVIAL_DESTRUCTOR. + * tree.c (break_out_cleanups): Likewise. + (build_cplus_array_test_1): Likewise. + (cp_build_qualified_type_real): Likewise. + * typeck.c (complete_type): Likewise. + + * g++spec.c (lang_specific_driver): Add -fnew-abi at the start of + the command-line, not the end. + 2000-03-01 Jason Merrill * pt.c (instantiate_decl): Clear TI_PENDING_TEMPLATE_FLAG. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 8ced4781445..72c4ccbd187 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -3452,31 +3452,6 @@ builtin: } } -/* Build up a call to operator new. This has to be handled differently - from other operators in the way lookup is handled; first members are - considered, then globals. CODE is either NEW_EXPR or VEC_NEW_EXPR. - TYPE is the type to be created. ARGS are any new-placement args. - FLAGS are the usual overloading flags. */ - -tree -build_op_new_call (code, type, args, flags) - enum tree_code code; - tree type, args; - int flags; -{ - tree fnname = ansi_opname[code]; - - if (IS_AGGR_TYPE (type) && ! (flags & LOOKUP_GLOBAL) - && (TYPE_GETS_NEW (type) & (1 << (code == VEC_NEW_EXPR)))) - { - return build_method_call (build_dummy_object (type), - fnname, args, NULL_TREE, flags); - } - else - return build_new_function_call - (lookup_function_nonclass (fnname, args), args); -} - /* Build a call to operator delete. This has to be handled very specially, because the restrictions on what signatures match are different from all other call instances. For a normal delete, only a delete taking (void *) diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 3f922ef4210..c76146ab00a 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -1934,7 +1934,8 @@ check_bases (t, cant_have_default_ctor_p, cant_have_const_ctor_p, /* A lot of properties from the bases also apply to the derived class. */ TYPE_NEEDS_CONSTRUCTING (t) |= TYPE_NEEDS_CONSTRUCTING (basetype); - TYPE_NEEDS_DESTRUCTOR (t) |= TYPE_NEEDS_DESTRUCTOR (basetype); + TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) + |= TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype); TYPE_HAS_COMPLEX_ASSIGN_REF (t) |= TYPE_HAS_COMPLEX_ASSIGN_REF (basetype); TYPE_HAS_COMPLEX_INIT_REF (t) |= TYPE_HAS_COMPLEX_INIT_REF (basetype); @@ -2079,7 +2080,8 @@ finish_struct_bits (t) TYPE_HAS_CONSTRUCTOR (variants) = TYPE_HAS_CONSTRUCTOR (t); TYPE_HAS_DESTRUCTOR (variants) = TYPE_HAS_DESTRUCTOR (t); TYPE_NEEDS_CONSTRUCTING (variants) = TYPE_NEEDS_CONSTRUCTING (t); - TYPE_NEEDS_DESTRUCTOR (variants) = TYPE_NEEDS_DESTRUCTOR (t); + TYPE_HAS_NONTRIVIAL_DESTRUCTOR (variants) + = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t); TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (variants) = TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (t); @@ -3503,14 +3505,14 @@ add_implicitly_declared_members (t, cant_have_default_ctor, tree *f; /* Destructor. */ - if (TYPE_NEEDS_DESTRUCTOR (t) && !TYPE_HAS_DESTRUCTOR (t)) + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) && !TYPE_HAS_DESTRUCTOR (t)) { default_fn = cons_up_default_function (t, name, 0); check_for_override (default_fn, t); /* If we couldn't make it work, then pretend we didn't need it. */ if (default_fn == void_type_node) - TYPE_NEEDS_DESTRUCTOR (t) = 0; + TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = 0; else { TREE_CHAIN (default_fn) = implicit_fns; @@ -3520,7 +3522,9 @@ add_implicitly_declared_members (t, cant_have_default_ctor, virtual_dtor = default_fn; } } - TYPE_NEEDS_DESTRUCTOR (t) |= TYPE_HAS_DESTRUCTOR (t); + else + /* Any non-implicit destructor is non-trivial. */ + TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) |= TYPE_HAS_DESTRUCTOR (t); /* Default constructor. */ if (! TYPE_HAS_CONSTRUCTOR (t) && ! cant_have_default_ctor) @@ -3744,7 +3748,7 @@ check_field_decl (field, t, cant_have_const_ctor, if (TYPE_NEEDS_CONSTRUCTING (type)) cp_error_at ("member `%#D' with constructor not allowed in union", field); - if (TYPE_NEEDS_DESTRUCTOR (type)) + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) cp_error_at ("member `%#D' with destructor not allowed in union", field); if (TYPE_HAS_COMPLEX_ASSIGN_REF (type)) @@ -3754,7 +3758,8 @@ check_field_decl (field, t, cant_have_const_ctor, else { TYPE_NEEDS_CONSTRUCTING (t) |= TYPE_NEEDS_CONSTRUCTING (type); - TYPE_NEEDS_DESTRUCTOR (t) |= TYPE_NEEDS_DESTRUCTOR (type); + TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) + |= TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type); TYPE_HAS_COMPLEX_ASSIGN_REF (t) |= TYPE_HAS_COMPLEX_ASSIGN_REF (type); TYPE_HAS_COMPLEX_INIT_REF (t) |= TYPE_HAS_COMPLEX_INIT_REF (type); } @@ -4268,6 +4273,7 @@ check_methods (t) tree t; { tree x; + int seen_one_arg_array_delete_p = 0; for (x = TYPE_METHODS (t); x; x = TREE_CHAIN (x)) { @@ -4291,6 +4297,37 @@ check_methods (t) CLASSTYPE_PURE_VIRTUALS (t) = tree_cons (NULL_TREE, x, CLASSTYPE_PURE_VIRTUALS (t)); } + + if (DECL_ARRAY_DELETE_OPERATOR_P (x)) + { + tree second_parm; + + /* When dynamically allocating an array of this type, we + need a "cookie" to record how many elements we allocated, + even if the array elements have no non-trivial + destructor, if the usual array deallocation function + takes a second argument of type size_t. The standard (in + [class.free]) requires that the second argument be set + correctly. */ + second_parm = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (x))); + /* This is overly conservative, but we must maintain this + behavior for backwards compatibility. */ + if (!flag_new_abi && second_parm != void_list_node) + TYPE_VEC_DELETE_TAKES_SIZE (t) = 1; + /* Under the new ABI, we choose only those function that are + explicitly declared as `operator delete[] (void *, + size_t)'. */ + else if (flag_new_abi + && !seen_one_arg_array_delete_p + && second_parm + && TREE_CHAIN (second_parm) == void_list_node + && same_type_p (TREE_VALUE (second_parm), sizetype)) + TYPE_VEC_DELETE_TAKES_SIZE (t) = 1; + /* If there's no second parameter, then this is the usual + deallocation function. */ + else if (second_parm == void_list_node) + seen_one_arg_array_delete_p = 1; + } } } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 3c46940e068..ce2b94c639f 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -81,7 +81,7 @@ Boston, MA 02111-1307, USA. */ 1: TYPE_HAS_CONSTRUCTOR. 2: TYPE_HAS_DESTRUCTOR. 3: TYPE_FOR_JAVA. - 4: TYPE_NEEDS_DESTRUCTOR. + 4: TYPE_HAS_NONTRIVIAL_DESTRUCTOR 5: IS_AGGR_TYPE. 6: TYPE_BUILT_IN. @@ -1310,7 +1310,8 @@ struct lang_type unsigned has_nonpublic_assign_ref : 2; unsigned vtable_needs_writing : 1; unsigned has_assign_ref : 1; - unsigned gets_new : 2; + unsigned has_new : 1; + unsigned has_array_new : 1; unsigned gets_delete : 2; unsigned has_call_overloaded : 1; @@ -1391,9 +1392,7 @@ struct lang_type /* List of friends which were defined inline in this class definition. */ #define CLASSTYPE_INLINE_FRIENDS(NODE) (TYPE_NONCOPIED_PARTS (NODE)) -/* Nonzero for _CLASSTYPE means that operator new and delete are defined, - respectively. */ -#define TYPE_GETS_NEW(NODE) (TYPE_LANG_SPECIFIC(NODE)->gets_new) +/* Nonzero for _CLASSTYPE means that operator delete is defined. */ #define TYPE_GETS_DELETE(NODE) (TYPE_LANG_SPECIFIC(NODE)->gets_delete) #define TYPE_GETS_REG_DELETE(NODE) (TYPE_GETS_DELETE (NODE) & 1) @@ -1401,9 +1400,15 @@ struct lang_type takes the optional size_t argument. */ #define TYPE_VEC_DELETE_TAKES_SIZE(NODE) \ (TYPE_LANG_SPECIFIC(NODE)->vec_delete_takes_size) -#define TYPE_VEC_NEW_USES_COOKIE(NODE) \ - (TYPE_NEEDS_DESTRUCTOR (NODE) \ - || (TYPE_LANG_SPECIFIC (NODE) && TYPE_VEC_DELETE_TAKES_SIZE (NODE))) + +/* Nonzero if `new NODE[x]' should cause the allocation of extra + storage to indicate how many array elements are in use. The old + ABI had a bug in that we always allocate the extra storage if NODE + has a two-argument array operator delete. */ +#define TYPE_VEC_NEW_USES_COOKIE(NODE) \ + (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (NODE) \ + || (TYPE_LANG_SPECIFIC (NODE) \ + && TYPE_VEC_DELETE_TAKES_SIZE (NODE))) /* Nonzero means that this _CLASSTYPE node defines ways of converting itself to other types. */ @@ -1417,6 +1422,15 @@ struct lang_type #define TYPE_HAS_INIT_REF(NODE) (TYPE_LANG_SPECIFIC(NODE)->has_init_ref) #define TYPE_HAS_CONST_INIT_REF(NODE) (TYPE_LANG_SPECIFIC(NODE)->has_const_init_ref) +/* Nonzero if this class defines an overloaded operator new. (An + operator new [] doesn't count.) */ +#define TYPE_HAS_NEW_OPERATOR(NODE) \ + (TYPE_LANG_SPECIFIC (NODE)->has_new) + +/* Nonzero if this class defines an overloaded operator new[]. */ +#define TYPE_HAS_ARRAY_NEW_OPERATOR(NODE) \ + (TYPE_LANG_SPECIFIC (NODE)->has_array_new) + /* Nonzero means that this type is being defined. I.e., the left brace starting the definition of this type has been seen. */ #define TYPE_BEING_DEFINED(NODE) (TYPE_LANG_SPECIFIC(NODE)->being_defined) @@ -1916,6 +1930,10 @@ struct lang_decl #define SET_DECL_TINFO_FN_P(NODE) \ (DECL_LANG_SPECIFIC((NODE))->decl_flags.mutable_flag = 1) +/* Nonzero if NODE is an overloaded `operator delete[]' function. */ +#define DECL_ARRAY_DELETE_OPERATOR_P(NODE) \ + (DECL_NAME (NODE) == ansi_opname[(int) VEC_DELETE_EXPR]) + /* Nonzero for _DECL means that this decl appears in (or will appear in) as a member in a RECORD_TYPE or UNION_TYPE node. It is also for detecting circularity in case members are multiply defined. In the @@ -2410,10 +2428,26 @@ extern int flag_new_for_scope; #define TYPE_HAS_ABSTRACT_ASSIGN_REF(NODE) (TYPE_LANG_SPECIFIC(NODE)->has_abstract_assign_ref) #define TYPE_HAS_COMPLEX_INIT_REF(NODE) (TYPE_LANG_SPECIFIC(NODE)->has_complex_init_ref) -/* Nonzero for _TYPE node means that destroying an object of this type - will involve a call to a destructor. This can apply to objects - of ARRAY_TYPE is the type of the elements needs a destructor. */ -#define TYPE_NEEDS_DESTRUCTOR(NODE) (TYPE_LANG_FLAG_4(NODE)) +/* Nonzero if TYPE has a trivial destructor. From [class.dtor]: + + A destructor is trivial if it is an implicitly declared + destructor and if: + + - all of the direct base classes of its class have trivial + destructors, + + - for all of the non-static data members of its class that are + of class type (or array thereof), each such class has a + trivial destructor. */ +#define TYPE_HAS_TRIVIAL_DESTRUCTOR(NODE) \ + (!TYPE_HAS_NONTRIVIAL_DESTRUCTOR (NODE)) + +/* Nonzero for _TYPE node means that this type does not have a trivial + destructor. Therefore, destroying an object of this type will + involve a call to a destructor. This can apply to objects of + ARRAY_TYPE is the type of the elements needs a destructor. */ +#define TYPE_HAS_NONTRIVIAL_DESTRUCTOR(NODE) \ + (TYPE_LANG_FLAG_4(NODE)) /* Nonzero for class type means that initialization of this type can use a bitwise copy. */ @@ -3578,7 +3612,6 @@ extern tree type_decays_to PARAMS ((tree)); extern tree build_user_type_conversion PARAMS ((tree, tree, int)); extern tree build_new_function_call PARAMS ((tree, tree)); extern tree build_new_op PARAMS ((enum tree_code, int, tree, tree, tree)); -extern tree build_op_new_call PARAMS ((enum tree_code, tree, tree, int)); extern tree build_op_delete_call PARAMS ((enum tree_code, tree, tree, int, tree)); extern int can_convert PARAMS ((tree, tree)); extern int can_convert_arg PARAMS ((tree, tree, tree)); @@ -3922,7 +3955,6 @@ extern tree build_offset_ref PARAMS ((tree, tree)); extern tree resolve_offset_ref PARAMS ((tree)); extern tree decl_constant_value PARAMS ((tree)); extern tree build_new PARAMS ((tree, tree, tree, int)); -extern tree build_new_1 PARAMS ((tree)); extern tree build_vec_init PARAMS ((tree, tree, tree, tree, int)); extern tree build_x_delete PARAMS ((tree, int, tree)); extern tree build_delete PARAMS ((tree, tree, tree, int, int)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 9d4301bdd09..df8e008fcad 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -6844,7 +6844,7 @@ start_decl_1 (decl) /* If this type of object needs a cleanup, but we're not allowed to add any more objects with cleanups to the current scope, create a new binding level. */ - if (TYPE_NEEDS_DESTRUCTOR (type) + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type) && current_binding_level->more_cleanups_ok == 0) { keep_next_level (2); @@ -7490,7 +7490,7 @@ initialize_local_var (decl, init, flags) if (TREE_STATIC (decl)) { if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE - || TYPE_NEEDS_DESTRUCTOR (type)) + || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) expand_static_init (decl, init); return; } @@ -7522,7 +7522,7 @@ initialize_local_var (decl, init, flags) marked used. (see TREE_USED, above.) */ if (TYPE_NEEDS_CONSTRUCTING (type) && ! already_used - && !TYPE_NEEDS_DESTRUCTOR (type) + && TYPE_HAS_TRIVIAL_DESTRUCTOR (type) && DECL_NAME (decl)) TREE_USED (decl) = 0; else if (already_used) @@ -7544,7 +7544,7 @@ destroy_local_var (decl) return; /* And only things with destructors need cleaning up. */ - if (!TYPE_NEEDS_DESTRUCTOR (type)) + if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type)) return; if (TREE_CODE (decl) == VAR_DECL && @@ -7820,7 +7820,7 @@ cp_finish_decl (decl, init, asmspec_tree, flags) { /* Cleanups for static variables are handled by `finish_file'. */ if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE - || TYPE_NEEDS_DESTRUCTOR (type)) + || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) expand_static_init (decl, init); } finish_end0: @@ -8054,7 +8054,7 @@ register_dtor_fn (decl) int saved_flag_access_control; - if (!TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl))) + if (TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl))) return; /* Call build_cleanup before we enter the anonymous function so that @@ -11856,11 +11856,11 @@ grok_op_properties (decl, virtualp, friendp) || name == ansi_opname[(int) MEMBER_REF]) TYPE_OVERLOADS_ARROW (current_class_type) = 1; else if (name == ansi_opname[(int) NEW_EXPR]) - TYPE_GETS_NEW (current_class_type) |= 1; + TYPE_HAS_NEW_OPERATOR (current_class_type) = 1; else if (name == ansi_opname[(int) DELETE_EXPR]) TYPE_GETS_DELETE (current_class_type) |= 1; else if (name == ansi_opname[(int) VEC_NEW_EXPR]) - TYPE_GETS_NEW (current_class_type) |= 2; + TYPE_HAS_ARRAY_NEW_OPERATOR (current_class_type) = 1; else if (name == ansi_opname[(int) VEC_DELETE_EXPR]) TYPE_GETS_DELETE (current_class_type) |= 2; } @@ -11894,14 +11894,7 @@ grok_op_properties (decl, virtualp, friendp) hash_tree_chain (ptr_type_node, void_list_node)); else - { - TREE_TYPE (decl) = coerce_delete_type (TREE_TYPE (decl)); - - if (! friendp && name == ansi_opname[(int) VEC_DELETE_EXPR] - && (TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (decl))) - != void_list_node)) - TYPE_VEC_DELETE_TAKES_SIZE (current_class_type) = 1; - } + TREE_TYPE (decl) = coerce_delete_type (TREE_TYPE (decl)); } else { @@ -12508,7 +12501,10 @@ xref_basetypes (code_type_node, name, ref, binfo) if (CLASS_TYPE_P (basetype)) { - TYPE_GETS_NEW (ref) |= TYPE_GETS_NEW (basetype); + TYPE_HAS_NEW_OPERATOR (ref) + |= TYPE_HAS_NEW_OPERATOR (basetype); + TYPE_HAS_ARRAY_NEW_OPERATOR (ref) + |= TYPE_HAS_ARRAY_NEW_OPERATOR (basetype); TYPE_GETS_DELETE (ref) |= TYPE_GETS_DELETE (basetype); /* If the base-class uses multiple inheritance, so do we. */ TYPE_USES_MULTIPLE_INHERITANCE (ref) @@ -13387,7 +13383,7 @@ store_parm_decls () cleanups = tree_cons (parm, cleanup, cleanups); } else if (type != error_mark_node - && TYPE_NEEDS_DESTRUCTOR (type)) + && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) parms_have_cleanups = 1; } else @@ -13603,7 +13599,7 @@ finish_destructor_body () while (vbases) { - if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (vbases))) + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (BINFO_TYPE (vbases))) { tree vb = get_vbase (BINFO_TYPE (vbases), @@ -14286,7 +14282,7 @@ maybe_build_cleanup_1 (decl, auto_delete) tree decl, auto_delete; { tree type = TREE_TYPE (decl); - if (type != error_mark_node && TYPE_NEEDS_DESTRUCTOR (type)) + if (type != error_mark_node && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) { int flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR; tree rval; diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 2f9c574249e..b961f26dc13 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -3238,7 +3238,7 @@ do_static_destruction (decl) my_friendly_assert (!flag_use_cxa_atexit, 20000121); /* If we don't need a destructor, there's nothing to do. */ - if (!TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl))) + if (TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl))) return; /* Actually do the destruction. */ diff --git a/gcc/cp/g++spec.c b/gcc/cp/g++spec.c index ca1ab68c06f..b3bab5a3a0c 100644 --- a/gcc/cp/g++spec.c +++ b/gcc/cp/g++spec.c @@ -206,8 +206,21 @@ lang_specific_driver (in_argc, in_argv, in_added_libraries) real_arglist = (char **) xmalloc (num_args * sizeof (char *)); arglist = (const char **) real_arglist; + i = 0; + j = 0; + + /* Copy the 0th argument, i.e., the name of the program itself. */ + arglist[i++] = arglist[j++]; + +#if ENABLE_NEW_GXX_ABI + /* If we should use the new ABI by default, add the appropriate flag + to cc1plus here. We put this first so that it can be overridden + by other command-line options. */ + arglist[j++] = "-fnew-abi"; +#endif + /* NOTE: We start at 1 now, not 0. */ - for (i = 0, j = 0; i < argc; i++, j++) + while (i < argc) { arglist[j] = argv[i]; @@ -237,11 +250,10 @@ lang_specific_driver (in_argc, in_argv, in_added_libraries) arglist[j++] = argv[i]; arglist[j] = "-xnone"; } - } -#if ENABLE_NEW_GXX_ABI - arglist[j++] = "-fnew-abi"; -#endif + i++; + j++; + } /* Add `-lstdc++' if we haven't already done so. */ if (library) diff --git a/gcc/cp/init.c b/gcc/cp/init.c index e9f02d8162b..fb6c4e661da 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -49,6 +49,8 @@ static tree initializing_context PARAMS ((tree)); static void expand_cleanup_for_base PARAMS ((tree, tree)); static tree get_temp_regvar PARAMS ((tree, tree)); static tree dfs_initialize_vtbl_ptrs PARAMS ((tree, void *)); +static tree build_new_1 PARAMS ((tree)); +static tree get_cookie_size PARAMS ((tree)); /* Set up local variable for this file. MUST BE CALLED AFTER INIT_DECL_PROCESSING. */ @@ -225,7 +227,7 @@ perform_member_init (member, name, init, explicit) finish_expr_stmt (build_modify_expr (decl, INIT_EXPR, init)); } - if (TYPE_NEEDS_DESTRUCTOR (type)) + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) { tree expr; @@ -701,7 +703,7 @@ expand_cleanup_for_base (binfo, flag) { tree expr; - if (!TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (binfo))) + if (TYPE_HAS_TRIVIAL_DESTRUCTOR (BINFO_TYPE (binfo))) return; /* Call the destructor. */ @@ -2101,10 +2103,40 @@ build_java_class_ref (type) return class_decl; } +/* Returns teh size of the cookie to use when allocating an array + whose elements have the indicated TYPE. Assumes that it is already + known that a cookie is needed. */ + +static tree +get_cookie_size (type) + tree type; +{ + tree cookie_size; + + if (flag_new_abi) + { + /* Under the new ABI, we need to allocate an additional max + (sizeof (size_t), alignof (true_type)) bytes. */ + tree sizetype_size; + tree type_align; + + sizetype_size = size_in_bytes (sizetype); + type_align = size_int (TYPE_ALIGN_UNIT (type)); + if (INT_CST_LT_UNSIGNED (type_align, sizetype_size)) + cookie_size = sizetype_size; + else + cookie_size = type_align; + } + else + cookie_size = BI_header_size; + + return cookie_size; +} + /* Called from cplus_expand_expr when expanding a NEW_EXPR. The return value is immediately handed to expand_expr. */ -tree +static tree build_new_1 (exp) tree exp; { @@ -2113,15 +2145,23 @@ build_new_1 (exp) tree nelts = NULL_TREE; tree alloc_expr, alloc_node = NULL_TREE; int has_array = 0; - enum tree_code code = NEW_EXPR; + enum tree_code code; int use_cookie, nothrow, check_new; + /* Nonzero if the user wrote `::new' rather than just `new'. */ + int globally_qualified_p; + /* Nonzero if we're going to call a global operator new, rather than + a class-specific version. */ int use_global_new; int use_java_new = 0; + /* If non-NULL, the number of extra bytes to allocate at the + beginning of the storage allocated for an array-new expression in + order to store the number of elements. */ + tree cookie_size = NULL_TREE; placement = TREE_OPERAND (exp, 0); type = TREE_OPERAND (exp, 1); init = TREE_OPERAND (exp, 2); - use_global_new = NEW_EXPR_USE_GLOBAL (exp); + globally_qualified_p = NEW_EXPR_USE_GLOBAL (exp); if (TREE_CODE (type) == ARRAY_REF) { @@ -2131,6 +2171,8 @@ build_new_1 (exp) } true_type = type; + code = has_array ? VEC_NEW_EXPR : NEW_EXPR; + if (CP_TYPE_QUALS (type)) type = TYPE_MAIN_VARIANT (type); @@ -2161,32 +2203,44 @@ build_new_1 (exp) if (abstract_virtuals_error (NULL_TREE, true_type)) return error_mark_node; - /* When we allocate an array, and the corresponding deallocation - function takes a second argument of type size_t, and that's the - "usual deallocation function", we allocate some extra space at - the beginning of the array to store the size of the array. + /* Figure out whether or not we're going to use the global operator + new. */ + if (!globally_qualified_p + && IS_AGGR_TYPE (true_type) + && ((!has_array && TYPE_HAS_NEW_OPERATOR (true_type)) + || (has_array && TYPE_HAS_ARRAY_NEW_OPERATOR (true_type)))) + use_global_new = 0; + else + use_global_new = 1; - Well, that's what we should do. For backwards compatibility, we - have to do this whenever there's a two-argument array-delete - operator. - - FIXME: For -fnew-abi, we don't have to maintain backwards - compatibility and we should fix this. */ - use_cookie = (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type) - && ! (placement && ! TREE_CHAIN (placement) - && TREE_TYPE (TREE_VALUE (placement)) == ptr_type_node)); + /* We only need cookies for arrays containing types for which we + need cookies. */ + if (!has_array || !TYPE_VEC_NEW_USES_COOKIE (true_type)) + use_cookie = 0; + /* When using placement new, users may not realize that they need + the extra storage. Under the old ABI, we don't allocate the + cookie whenever they use one placement argument of type `void + *'. Under the new ABI, we require that the operator called be + the global placement operator delete[]. */ + else if (placement && !TREE_CHAIN (placement) + && same_type_p (TREE_TYPE (TREE_VALUE (placement)), + ptr_type_node)) + use_cookie = (!flag_new_abi || !use_global_new); + /* Otherwise, we need the cookie. */ + else + use_cookie = 1; + /* Compute the number of extra bytes to allocate, now that we know + whether or not we need the cookie. */ if (use_cookie) - size = size_binop (PLUS_EXPR, size, BI_header_size); - - if (has_array) { - code = VEC_NEW_EXPR; - - if (init && pedantic) - cp_pedwarn ("initialization in array new"); + cookie_size = get_cookie_size (true_type); + size = size_binop (PLUS_EXPR, size, cookie_size); } + if (has_array && init && pedantic) + cp_pedwarn ("initialization in array new"); + /* Allocate the object. */ if (! placement && TYPE_FOR_JAVA (true_type)) @@ -2208,9 +2262,20 @@ build_new_1 (exp) } else { - rval = build_op_new_call - (code, true_type, tree_cons (NULL_TREE, size, placement), - LOOKUP_NORMAL | (use_global_new * LOOKUP_GLOBAL)); + tree fnname; + tree args; + + args = tree_cons (NULL_TREE, size, placement); + fnname = ansi_opname[code]; + + if (use_global_new) + rval = (build_new_function_call + (lookup_function_nonclass (fnname, args), + args)); + else + rval = build_method_call (build_dummy_object (true_type), + fnname, args, NULL_TREE, + LOOKUP_NORMAL); rval = cp_convert (build_pointer_type (true_type), rval); } @@ -2249,18 +2314,36 @@ build_new_1 (exp) /* Finish up some magic for new'ed arrays */ if (use_cookie && rval != NULL_TREE) { - tree extra = BI_header_size; tree cookie, exp1; rval = convert (string_type_node, rval); /* for ptr arithmetic */ - rval = save_expr (build_binary_op (PLUS_EXPR, rval, extra)); - /* Store header info. */ - cookie = build_indirect_ref (build (MINUS_EXPR, - build_pointer_type (BI_header_type), - rval, extra), NULL_PTR); - exp1 = build (MODIFY_EXPR, void_type_node, - build_component_ref (cookie, nelts_identifier, - NULL_TREE, 0), - nelts); + rval = save_expr (build_binary_op (PLUS_EXPR, rval, cookie_size)); + /* Store the number of bytes allocated so that we can know how + many elements to destroy later. */ + if (flag_new_abi) + { + /* Under the new ABI, we use the last sizeof (size_t) bytes + to store the number of elements. */ + cookie = build_indirect_ref (build (MINUS_EXPR, + build_pointer_type (sizetype), + rval, + size_in_bytes (sizetype)), + NULL_PTR); + exp1 = build (MODIFY_EXPR, void_type_node, cookie, nelts); + } + else + { + cookie + = build_indirect_ref (build (MINUS_EXPR, + build_pointer_type (BI_header_type), + rval, cookie_size), NULL_PTR); + exp1 = build (MODIFY_EXPR, void_type_node, + build_component_ref (cookie, nelts_identifier, + NULL_TREE, 0), + nelts); + } + + /* Build `(cookie = nelts, rval)' and use that as the complete + expression. */ rval = cp_convert (build_pointer_type (true_type), rval); rval = build_compound_expr (tree_cons (NULL_TREE, exp1, @@ -2372,7 +2455,8 @@ build_new_1 (exp) { enum tree_code dcode = has_array ? VEC_DELETE_EXPR : DELETE_EXPR; tree cleanup, fn = NULL_TREE; - int flags = LOOKUP_NORMAL | (use_global_new * LOOKUP_GLOBAL); + int flags = (LOOKUP_NORMAL + | (globally_qualified_p * LOOKUP_GLOBAL)); /* The Standard is unclear here, but the right thing to do is to use the same method for finding deallocation @@ -2475,7 +2559,7 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, use_global_delete) This is also the containing expression returned by this function. */ tree controller = NULL_TREE; - if (! IS_AGGR_TYPE (type) || ! TYPE_NEEDS_DESTRUCTOR (type)) + if (! IS_AGGR_TYPE (type) || TYPE_HAS_TRIVIAL_DESTRUCTOR (type)) { loop = integer_zero_node; goto no_destructor; @@ -2534,12 +2618,16 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, use_global_delete) base_tbd = base; else { - base_tbd = cp_convert (ptype, - build_binary_op (MINUS_EXPR, - cp_convert (string_type_node, base), - BI_header_size)); + tree cookie_size; + + cookie_size = get_cookie_size (type); + base_tbd + = cp_convert (ptype, + build_binary_op (MINUS_EXPR, + cp_convert (string_type_node, base), + cookie_size)); /* True size with header. */ - virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size); + virtual_size = size_binop (PLUS_EXPR, virtual_size, cookie_size); } deallocate_expr = build_x_delete (base_tbd, 2 | use_global_delete, @@ -2708,7 +2796,7 @@ build_vec_init (decl, base, maxindex, init, from_array) /* Protect the entire array initialization so that we can destroy the partially constructed array if an exception is thrown. */ - if (flag_exceptions && TYPE_NEEDS_DESTRUCTOR (type)) + if (flag_exceptions && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) { try_block = begin_try_block (); try_body = begin_compound_stmt (/*has_no_scope=*/1); @@ -2893,7 +2981,7 @@ build_vec_init (decl, base, maxindex, init, from_array) } /* Make sure to cleanup any partially constructed elements. */ - if (flag_exceptions && TYPE_NEEDS_DESTRUCTOR (type)) + if (flag_exceptions && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) { tree e; @@ -3029,7 +3117,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete) my_friendly_assert (IS_AGGR_TYPE (type), 220); - if (! TYPE_NEEDS_DESTRUCTOR (type)) + if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type)) { if (auto_delete == integer_zero_node) return void_zero_node; @@ -3105,7 +3193,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete) if (auto_delete == integer_zero_node) cond = NULL_TREE; else if (base_binfo == NULL_TREE - || ! TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo))) + || TYPE_HAS_TRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo))) { cond = build (COND_EXPR, void_type_node, build (BIT_AND_EXPR, integer_type_node, auto_delete, integer_one_node), @@ -3120,7 +3208,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete) if (base_binfo && ! TREE_VIA_VIRTUAL (base_binfo) - && TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo))) + && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo))) { tree this_auto_delete; @@ -3139,7 +3227,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete) for (i = 1; i < n_baseclasses; i++) { base_binfo = TREE_VEC_ELT (binfos, i); - if (! TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo)) + if (TYPE_HAS_TRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo)) || TREE_VIA_VIRTUAL (base_binfo)) continue; @@ -3154,7 +3242,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete) { if (TREE_CODE (member) != FIELD_DECL) continue; - if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (member))) + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (member))) { tree this_member = build_component_ref (ref, DECL_NAME (member), NULL_TREE, 0); tree this_type = TREE_TYPE (member); @@ -3234,20 +3322,34 @@ build_vec_delete (base, maxindex, auto_delete_vec, use_global_delete) if (TREE_CODE (type) == POINTER_TYPE) { /* Step back one from start of vector, and read dimension. */ - tree cookie_addr = build (MINUS_EXPR, build_pointer_type (BI_header_type), - base, BI_header_size); - tree cookie = build_indirect_ref (cookie_addr, NULL_PTR); - maxindex = build_component_ref (cookie, nelts_identifier, NULL_TREE, 0); - do - type = TREE_TYPE (type); - while (TREE_CODE (type) == ARRAY_TYPE); + tree cookie_addr; + + if (flag_new_abi) + { + cookie_addr = build (MINUS_EXPR, + build_pointer_type (sizetype), + base, + TYPE_SIZE_UNIT (sizetype)); + maxindex = build_indirect_ref (cookie_addr, NULL_PTR); + } + else + { + tree cookie; + + cookie_addr = build (MINUS_EXPR, build_pointer_type (BI_header_type), + base, BI_header_size); + cookie = build_indirect_ref (cookie_addr, NULL_PTR); + maxindex = build_component_ref (cookie, nelts_identifier, + NULL_TREE, 0); + } + + type = strip_array_types (TREE_TYPE (type)); } else if (TREE_CODE (type) == ARRAY_TYPE) { /* get the total number of things in the array, maxindex is a bad name */ maxindex = array_type_nelts_total (type); - while (TREE_CODE (type) == ARRAY_TYPE) - type = TREE_TYPE (type); + type = strip_array_types (type); base = build_unary_op (ADDR_EXPR, base, 1); } else diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c index 2e5a2e6b466..5c42a414699 100644 --- a/gcc/cp/lex.c +++ b/gcc/cp/lex.c @@ -3147,7 +3147,7 @@ do_identifier (token, parsing, args) else if (!DECL_ERROR_REPORTED (id)) { DECL_ERROR_REPORTED (id) = 1; - if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (id))) + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (id))) { error ("name lookup of `%s' changed for new ISO `for' scoping", IDENTIFIER_POINTER (token)); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index d5e52e82f13..e6e079ce8a1 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -4830,7 +4830,8 @@ instantiate_class_template (type) TYPE_OVERLOADS_CALL_EXPR (type) = TYPE_OVERLOADS_CALL_EXPR (pattern); TYPE_OVERLOADS_ARRAY_REF (type) = TYPE_OVERLOADS_ARRAY_REF (pattern); TYPE_OVERLOADS_ARROW (type) = TYPE_OVERLOADS_ARROW (pattern); - TYPE_GETS_NEW (type) = TYPE_GETS_NEW (pattern); + TYPE_HAS_NEW_OPERATOR (type) = TYPE_HAS_NEW_OPERATOR (pattern); + TYPE_HAS_ARRAY_NEW_OPERATOR (type) = TYPE_HAS_ARRAY_NEW_OPERATOR (pattern); TYPE_GETS_DELETE (type) = TYPE_GETS_DELETE (pattern); TYPE_VEC_DELETE_TAKES_SIZE (type) = TYPE_VEC_DELETE_TAKES_SIZE (pattern); TYPE_HAS_ASSIGN_REF (type) = TYPE_HAS_ASSIGN_REF (pattern); diff --git a/gcc/cp/ptree.c b/gcc/cp/ptree.c index 91f4ec4efb1..aa723845616 100644 --- a/gcc/cp/ptree.c +++ b/gcc/cp/ptree.c @@ -113,7 +113,7 @@ print_lang_type (file, node, indent) if (TYPE_NEEDS_CONSTRUCTING (node)) fputs ( "needs-constructor", file); - if (TYPE_NEEDS_DESTRUCTOR (node)) + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (node)) fputs (" needs-destructor", file); if (TYPE_HAS_DESTRUCTOR (node)) fputs (" ~X()", file); @@ -128,9 +128,9 @@ print_lang_type (file, node, indent) else fputs (" X(X&)", file); } - if (TYPE_GETS_NEW (node) & 1) + if (TYPE_HAS_NEW_OPERATOR (node)) fputs (" new", file); - if (TYPE_GETS_NEW (node) & 2) + if (TYPE_HAS_ARRAY_NEW_OPERATOR (node)) fputs (" new[]", file); if (TYPE_GETS_DELETE (node) & 1) fputs (" delete", file); diff --git a/gcc/cp/search.c b/gcc/cp/search.c index 56917eb374f..bc0ab2609ed 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -725,7 +725,7 @@ context_for_name_lookup (decl) For the purposes of name lookup, after the anonymous union definition, the members of the anonymous union are considered to - have been defined in the scope in which teh anonymous union is + have been defined in the scope in which the anonymous union is declared. */ tree context = CP_DECL_CONTEXT (decl); @@ -1955,7 +1955,7 @@ tree_has_any_destructor_p (binfo, data) void *data ATTRIBUTE_UNUSED; { tree type = BINFO_TYPE (binfo); - return TYPE_NEEDS_DESTRUCTOR (type) ? binfo : NULL_TREE; + return TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type) ? binfo : NULL_TREE; } /* Returns > 0 if a function with type DRETTYPE overriding a function diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index c739db7e381..57adf99b4a0 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -322,7 +322,7 @@ break_out_cleanups (exp) tree tmp = exp; if (TREE_CODE (tmp) == CALL_EXPR - && TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (tmp))) + && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (tmp))) return build_cplus_new (TREE_TYPE (tmp), tmp); while (TREE_CODE (tmp) == NOP_EXPR @@ -330,7 +330,7 @@ break_out_cleanups (exp) || TREE_CODE (tmp) == NON_LVALUE_EXPR) { if (TREE_CODE (TREE_OPERAND (tmp, 0)) == CALL_EXPR - && TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (TREE_OPERAND (tmp, 0)))) + && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (TREE_OPERAND (tmp, 0)))) { TREE_OPERAND (tmp, 0) = build_cplus_new (TREE_TYPE (TREE_OPERAND (tmp, 0)), @@ -505,8 +505,8 @@ build_cplus_array_type_1 (elt_type, index_type) more easily. */ TYPE_NEEDS_CONSTRUCTING (t) = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (elt_type)); - TYPE_NEEDS_DESTRUCTOR (t) - = TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (elt_type)); + TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) + = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TYPE_MAIN_VARIANT (elt_type)); return t; } @@ -602,7 +602,7 @@ cp_build_qualified_type_real (type, type_quals, complain) } /* Even if we already had this variant, we update - TYPE_NEEDS_CONSTRUCTING and TYPE_NEEDS_DESTRUCTOR in case + TYPE_NEEDS_CONSTRUCTING and TYPE_HAS_NONTRIVIAL_DESTRUCTOR in case they changed since the variant was originally created. This seems hokey; if there is some way to use a previous @@ -610,8 +610,8 @@ cp_build_qualified_type_real (type, type_quals, complain) TYPE_NEEDS_CONSTRUCTING will never be updated. */ TYPE_NEEDS_CONSTRUCTING (t) = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (element_type)); - TYPE_NEEDS_DESTRUCTOR (t) - = TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (element_type)); + TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) + = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TYPE_MAIN_VARIANT (element_type)); return t; } else if (TYPE_PTRMEMFUNC_P (type)) diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 8fc3ab8a667..400d930b0d2 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -155,8 +155,8 @@ complete_type (type) layout_type (type); TYPE_NEEDS_CONSTRUCTING (type) = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (t)); - TYPE_NEEDS_DESTRUCTOR (type) - = TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (t)); + TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type) + = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TYPE_MAIN_VARIANT (t)); } else if (CLASS_TYPE_P (type) && CLASSTYPE_TEMPLATE_INSTANTIATION (type)) instantiate_class_template (TYPE_MAIN_VARIANT (type)); diff --git a/gcc/testsuite/g++.old-deja/g++.abi/arraynew.C b/gcc/testsuite/g++.old-deja/g++.abi/arraynew.C new file mode 100644 index 00000000000..3e39e372f8d --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.abi/arraynew.C @@ -0,0 +1,127 @@ +// Origin: Mark Mitchell + +#if defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 + +#include +#include + +extern "C" int printf (const char*, ...); + +void* p; + +void* operator new[](size_t s) throw (bad_alloc) +{ + // Record the base of the last array allocated. + p = malloc (s); + return p; +} + +template +void check_no_cookie (int i) +{ + void* a = new T[7]; + if (p != a) + exit (i); +} + +template +void check_no_placement_cookie (int i) +{ + p = malloc (13 * sizeof (T)); + void* a = new (p) T[13]; + if (p != a) + exit (i); +} + +template +void check_cookie (int i) +{ + void* a = new T[11]; + + // Compute the cookie location manually. + size_t x = __alignof__ (T); + if (x < sizeof (size_t)) + x = sizeof (size_t); + if ((char *) a - x != (char *) p) + exit (i); + + // Check the cookie value. + size_t *sp = ((size_t *) a) - 1; + if (*sp != 11) + exit (i); +} + +template +void check_placement_cookie (int i) +{ + p = malloc (sizeof (T) * 11 + 100); + void* a = new (p) T[11]; + + printf ("%x %x\n", a, p); + // Compute the cookie location manually. + size_t x = __alignof__ (T); + if (x < sizeof (size_t)) + x = sizeof (size_t); + if ((char *) a - x != (char *) p) + exit (i); + + // Check the cookie value. + size_t *sp = ((size_t *) a) - 1; + if (*sp != 11) + exit (i); +} + +struct X {}; + +template +struct Y { int i; virtual void f () {}; }; + +// A class with a non-trivial destructor -- it needs a cookie. +struct Z { ~Z () {}; }; +// Likewise, but this class needs a bigger cookie so that the array +// elements are correctly aligned. +struct Z2 { ~Z2 () {}; long double d; }; + +struct W1 { void operator delete[] (void *, size_t) {}; }; +struct W2 { void operator delete[] (void *) {}; + void operator delete[] (void *, size_t) {}; }; + +struct V { void *operator new[] (size_t s, void *p) + { return p; } + ~V () {} + }; + +int main () +{ + // There should be no cookies for types with trivial destructors. + check_no_cookie (1); + check_no_cookie (2); + check_no_cookie > (3); + + // There should be no cookies for allocations using global placement + // new. + check_no_placement_cookie (4); + check_no_placement_cookie (5); + check_no_placement_cookie (6); + + // There should be a cookie when using a non-trivial destructor. + check_cookie (7); + check_cookie (8); + + // There should be a cookie when using the two-argument array delete + // operator. + check_cookie (9); + // But not when the one-argument version is also available. + check_no_cookie (10); + + // There should be a cookie when using a non-global placement new. + check_placement_cookie (11); +} + +#else /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */ + +int main () +{ +} + +#endif /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */ diff --git a/gcc/testsuite/g++.old-deja/g++.other/inline7.C b/gcc/testsuite/g++.old-deja/g++.other/inline7.C index c3f54398f13..e6483ca6402 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/inline7.C +++ b/gcc/testsuite/g++.old-deja/g++.other/inline7.C @@ -1,4 +1,5 @@ // Origin: Mark Mitchell +// Special g++ Options: -O2 #include diff --git a/gcc/tree.h b/gcc/tree.h index 51157c6a2dc..a59b5d2b743 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -880,6 +880,10 @@ struct tree_block The value is an int, measured in bits. */ #define TYPE_ALIGN(NODE) (TYPE_CHECK (NODE)->type.align) +/* The alignment for NODE, in bytes. */ +#define TYPE_ALIGN_UNIT(NODE) \ + (TYPE_ALIGN (NODE) / BITS_PER_UNIT) + #define TYPE_STUB_DECL(NODE) (TREE_CHAIN (NODE)) /* In a RECORD_TYPE, UNION_TYPE or QUAL_UNION_TYPE, it means the type