* tree.h (TYPE_ALIGN_UNIT): New macro.

From-SVN: r32302
This commit is contained in:
Mark Mitchell 2000-03-03 02:27:15 +00:00 committed by Mark Mitchell
parent a2b10a92a3
commit 834c6dff7b
18 changed files with 501 additions and 149 deletions

View File

@ -1,3 +1,7 @@
2000-03-02 Mark Mitchell <mark@codesourcery.com>
* tree.h (TYPE_ALIGN_UNIT): New macro.
2000-03-02 Clinton Popetz <cpopetz@cygnus.com> 2000-03-02 Clinton Popetz <cpopetz@cygnus.com>
* config/i386/i386.c: (constant_call_address_operand): Reject * config/i386/i386.c: (constant_call_address_operand): Reject

View File

@ -1,3 +1,64 @@
2000-03-02 Mark Mitchell <mark@codesourcery.com>
* 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 <jason@casey.cygnus.com> 2000-03-01 Jason Merrill <jason@casey.cygnus.com>
* pt.c (instantiate_decl): Clear TI_PENDING_TEMPLATE_FLAG. * pt.c (instantiate_decl): Clear TI_PENDING_TEMPLATE_FLAG.

View File

@ -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, /* Build a call to operator delete. This has to be handled very specially,
because the restrictions on what signatures match are different from all because the restrictions on what signatures match are different from all
other call instances. For a normal delete, only a delete taking (void *) other call instances. For a normal delete, only a delete taking (void *)

View File

@ -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 /* A lot of properties from the bases also apply to the derived
class. */ class. */
TYPE_NEEDS_CONSTRUCTING (t) |= TYPE_NEEDS_CONSTRUCTING (basetype); 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 (t)
|= TYPE_HAS_COMPLEX_ASSIGN_REF (basetype); |= TYPE_HAS_COMPLEX_ASSIGN_REF (basetype);
TYPE_HAS_COMPLEX_INIT_REF (t) |= TYPE_HAS_COMPLEX_INIT_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_CONSTRUCTOR (variants) = TYPE_HAS_CONSTRUCTOR (t);
TYPE_HAS_DESTRUCTOR (variants) = TYPE_HAS_DESTRUCTOR (t); TYPE_HAS_DESTRUCTOR (variants) = TYPE_HAS_DESTRUCTOR (t);
TYPE_NEEDS_CONSTRUCTING (variants) = TYPE_NEEDS_CONSTRUCTING (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 (variants)
= TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (t); = TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (t);
@ -3503,14 +3505,14 @@ add_implicitly_declared_members (t, cant_have_default_ctor,
tree *f; tree *f;
/* Destructor. */ /* 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); default_fn = cons_up_default_function (t, name, 0);
check_for_override (default_fn, t); check_for_override (default_fn, t);
/* If we couldn't make it work, then pretend we didn't need it. */ /* If we couldn't make it work, then pretend we didn't need it. */
if (default_fn == void_type_node) if (default_fn == void_type_node)
TYPE_NEEDS_DESTRUCTOR (t) = 0; TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = 0;
else else
{ {
TREE_CHAIN (default_fn) = implicit_fns; TREE_CHAIN (default_fn) = implicit_fns;
@ -3520,7 +3522,9 @@ add_implicitly_declared_members (t, cant_have_default_ctor,
virtual_dtor = default_fn; 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. */ /* Default constructor. */
if (! TYPE_HAS_CONSTRUCTOR (t) && ! cant_have_default_ctor) 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)) if (TYPE_NEEDS_CONSTRUCTING (type))
cp_error_at ("member `%#D' with constructor not allowed in union", cp_error_at ("member `%#D' with constructor not allowed in union",
field); field);
if (TYPE_NEEDS_DESTRUCTOR (type)) if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
cp_error_at ("member `%#D' with destructor not allowed in union", cp_error_at ("member `%#D' with destructor not allowed in union",
field); field);
if (TYPE_HAS_COMPLEX_ASSIGN_REF (type)) if (TYPE_HAS_COMPLEX_ASSIGN_REF (type))
@ -3754,7 +3758,8 @@ check_field_decl (field, t, cant_have_const_ctor,
else else
{ {
TYPE_NEEDS_CONSTRUCTING (t) |= TYPE_NEEDS_CONSTRUCTING (type); 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_ASSIGN_REF (t) |= TYPE_HAS_COMPLEX_ASSIGN_REF (type);
TYPE_HAS_COMPLEX_INIT_REF (t) |= TYPE_HAS_COMPLEX_INIT_REF (type); TYPE_HAS_COMPLEX_INIT_REF (t) |= TYPE_HAS_COMPLEX_INIT_REF (type);
} }
@ -4268,6 +4273,7 @@ check_methods (t)
tree t; tree t;
{ {
tree x; tree x;
int seen_one_arg_array_delete_p = 0;
for (x = TYPE_METHODS (t); x; x = TREE_CHAIN (x)) for (x = TYPE_METHODS (t); x; x = TREE_CHAIN (x))
{ {
@ -4291,6 +4297,37 @@ check_methods (t)
CLASSTYPE_PURE_VIRTUALS (t) CLASSTYPE_PURE_VIRTUALS (t)
= tree_cons (NULL_TREE, x, 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;
}
} }
} }

View File

@ -81,7 +81,7 @@ Boston, MA 02111-1307, USA. */
1: TYPE_HAS_CONSTRUCTOR. 1: TYPE_HAS_CONSTRUCTOR.
2: TYPE_HAS_DESTRUCTOR. 2: TYPE_HAS_DESTRUCTOR.
3: TYPE_FOR_JAVA. 3: TYPE_FOR_JAVA.
4: TYPE_NEEDS_DESTRUCTOR. 4: TYPE_HAS_NONTRIVIAL_DESTRUCTOR
5: IS_AGGR_TYPE. 5: IS_AGGR_TYPE.
6: TYPE_BUILT_IN. 6: TYPE_BUILT_IN.
@ -1310,7 +1310,8 @@ struct lang_type
unsigned has_nonpublic_assign_ref : 2; unsigned has_nonpublic_assign_ref : 2;
unsigned vtable_needs_writing : 1; unsigned vtable_needs_writing : 1;
unsigned has_assign_ref : 1; unsigned has_assign_ref : 1;
unsigned gets_new : 2; unsigned has_new : 1;
unsigned has_array_new : 1;
unsigned gets_delete : 2; unsigned gets_delete : 2;
unsigned has_call_overloaded : 1; unsigned has_call_overloaded : 1;
@ -1391,9 +1392,7 @@ struct lang_type
/* List of friends which were defined inline in this class definition. */ /* List of friends which were defined inline in this class definition. */
#define CLASSTYPE_INLINE_FRIENDS(NODE) (TYPE_NONCOPIED_PARTS (NODE)) #define CLASSTYPE_INLINE_FRIENDS(NODE) (TYPE_NONCOPIED_PARTS (NODE))
/* Nonzero for _CLASSTYPE means that operator new and delete are defined, /* Nonzero for _CLASSTYPE means that operator delete is defined. */
respectively. */
#define TYPE_GETS_NEW(NODE) (TYPE_LANG_SPECIFIC(NODE)->gets_new)
#define TYPE_GETS_DELETE(NODE) (TYPE_LANG_SPECIFIC(NODE)->gets_delete) #define TYPE_GETS_DELETE(NODE) (TYPE_LANG_SPECIFIC(NODE)->gets_delete)
#define TYPE_GETS_REG_DELETE(NODE) (TYPE_GETS_DELETE (NODE) & 1) #define TYPE_GETS_REG_DELETE(NODE) (TYPE_GETS_DELETE (NODE) & 1)
@ -1401,9 +1400,15 @@ struct lang_type
takes the optional size_t argument. */ takes the optional size_t argument. */
#define TYPE_VEC_DELETE_TAKES_SIZE(NODE) \ #define TYPE_VEC_DELETE_TAKES_SIZE(NODE) \
(TYPE_LANG_SPECIFIC(NODE)->vec_delete_takes_size) (TYPE_LANG_SPECIFIC(NODE)->vec_delete_takes_size)
#define TYPE_VEC_NEW_USES_COOKIE(NODE) \
(TYPE_NEEDS_DESTRUCTOR (NODE) \ /* Nonzero if `new NODE[x]' should cause the allocation of extra
|| (TYPE_LANG_SPECIFIC (NODE) && TYPE_VEC_DELETE_TAKES_SIZE (NODE))) 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 /* Nonzero means that this _CLASSTYPE node defines ways of converting
itself to other types. */ 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_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) #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 /* Nonzero means that this type is being defined. I.e., the left brace
starting the definition of this type has been seen. */ starting the definition of this type has been seen. */
#define TYPE_BEING_DEFINED(NODE) (TYPE_LANG_SPECIFIC(NODE)->being_defined) #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) \ #define SET_DECL_TINFO_FN_P(NODE) \
(DECL_LANG_SPECIFIC((NODE))->decl_flags.mutable_flag = 1) (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 /* 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 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 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_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) #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 /* Nonzero if TYPE has a trivial destructor. From [class.dtor]:
will involve a call to a destructor. This can apply to objects
of ARRAY_TYPE is the type of the elements needs a destructor. */ A destructor is trivial if it is an implicitly declared
#define TYPE_NEEDS_DESTRUCTOR(NODE) (TYPE_LANG_FLAG_4(NODE)) 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 /* Nonzero for class type means that initialization of this type can use
a bitwise copy. */ 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_user_type_conversion PARAMS ((tree, tree, int));
extern tree build_new_function_call PARAMS ((tree, tree)); 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_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 tree build_op_delete_call PARAMS ((enum tree_code, tree, tree, int, tree));
extern int can_convert PARAMS ((tree, tree)); extern int can_convert PARAMS ((tree, tree));
extern int can_convert_arg PARAMS ((tree, 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 resolve_offset_ref PARAMS ((tree));
extern tree decl_constant_value PARAMS ((tree)); extern tree decl_constant_value PARAMS ((tree));
extern tree build_new PARAMS ((tree, tree, tree, int)); 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_vec_init PARAMS ((tree, tree, tree, tree, int));
extern tree build_x_delete PARAMS ((tree, int, tree)); extern tree build_x_delete PARAMS ((tree, int, tree));
extern tree build_delete PARAMS ((tree, tree, tree, int, int)); extern tree build_delete PARAMS ((tree, tree, tree, int, int));

View File

@ -6844,7 +6844,7 @@ start_decl_1 (decl)
/* If this type of object needs a cleanup, but we're not allowed to /* 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 add any more objects with cleanups to the current scope, create a
new binding level. */ new binding level. */
if (TYPE_NEEDS_DESTRUCTOR (type) if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
&& current_binding_level->more_cleanups_ok == 0) && current_binding_level->more_cleanups_ok == 0)
{ {
keep_next_level (2); keep_next_level (2);
@ -7490,7 +7490,7 @@ initialize_local_var (decl, init, flags)
if (TREE_STATIC (decl)) if (TREE_STATIC (decl))
{ {
if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE
|| TYPE_NEEDS_DESTRUCTOR (type)) || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
expand_static_init (decl, init); expand_static_init (decl, init);
return; return;
} }
@ -7522,7 +7522,7 @@ initialize_local_var (decl, init, flags)
marked used. (see TREE_USED, above.) */ marked used. (see TREE_USED, above.) */
if (TYPE_NEEDS_CONSTRUCTING (type) if (TYPE_NEEDS_CONSTRUCTING (type)
&& ! already_used && ! already_used
&& !TYPE_NEEDS_DESTRUCTOR (type) && TYPE_HAS_TRIVIAL_DESTRUCTOR (type)
&& DECL_NAME (decl)) && DECL_NAME (decl))
TREE_USED (decl) = 0; TREE_USED (decl) = 0;
else if (already_used) else if (already_used)
@ -7544,7 +7544,7 @@ destroy_local_var (decl)
return; return;
/* And only things with destructors need cleaning up. */ /* And only things with destructors need cleaning up. */
if (!TYPE_NEEDS_DESTRUCTOR (type)) if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
return; return;
if (TREE_CODE (decl) == VAR_DECL && 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'. */ /* Cleanups for static variables are handled by `finish_file'. */
if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE
|| TYPE_NEEDS_DESTRUCTOR (type)) || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
expand_static_init (decl, init); expand_static_init (decl, init);
} }
finish_end0: finish_end0:
@ -8054,7 +8054,7 @@ register_dtor_fn (decl)
int saved_flag_access_control; int saved_flag_access_control;
if (!TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl))) if (TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
return; return;
/* Call build_cleanup before we enter the anonymous function so that /* 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]) || name == ansi_opname[(int) MEMBER_REF])
TYPE_OVERLOADS_ARROW (current_class_type) = 1; TYPE_OVERLOADS_ARROW (current_class_type) = 1;
else if (name == ansi_opname[(int) NEW_EXPR]) 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]) else if (name == ansi_opname[(int) DELETE_EXPR])
TYPE_GETS_DELETE (current_class_type) |= 1; TYPE_GETS_DELETE (current_class_type) |= 1;
else if (name == ansi_opname[(int) VEC_NEW_EXPR]) 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]) else if (name == ansi_opname[(int) VEC_DELETE_EXPR])
TYPE_GETS_DELETE (current_class_type) |= 2; TYPE_GETS_DELETE (current_class_type) |= 2;
} }
@ -11894,14 +11894,7 @@ grok_op_properties (decl, virtualp, friendp)
hash_tree_chain (ptr_type_node, hash_tree_chain (ptr_type_node,
void_list_node)); void_list_node));
else else
{ TREE_TYPE (decl) = coerce_delete_type (TREE_TYPE (decl));
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;
}
} }
else else
{ {
@ -12508,7 +12501,10 @@ xref_basetypes (code_type_node, name, ref, binfo)
if (CLASS_TYPE_P (basetype)) 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); TYPE_GETS_DELETE (ref) |= TYPE_GETS_DELETE (basetype);
/* If the base-class uses multiple inheritance, so do we. */ /* If the base-class uses multiple inheritance, so do we. */
TYPE_USES_MULTIPLE_INHERITANCE (ref) TYPE_USES_MULTIPLE_INHERITANCE (ref)
@ -13387,7 +13383,7 @@ store_parm_decls ()
cleanups = tree_cons (parm, cleanup, cleanups); cleanups = tree_cons (parm, cleanup, cleanups);
} }
else if (type != error_mark_node else if (type != error_mark_node
&& TYPE_NEEDS_DESTRUCTOR (type)) && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
parms_have_cleanups = 1; parms_have_cleanups = 1;
} }
else else
@ -13603,7 +13599,7 @@ finish_destructor_body ()
while (vbases) while (vbases)
{ {
if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (vbases))) if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (BINFO_TYPE (vbases)))
{ {
tree vb = get_vbase tree vb = get_vbase
(BINFO_TYPE (vbases), (BINFO_TYPE (vbases),
@ -14286,7 +14282,7 @@ maybe_build_cleanup_1 (decl, auto_delete)
tree decl, auto_delete; tree decl, auto_delete;
{ {
tree type = TREE_TYPE (decl); 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; int flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR;
tree rval; tree rval;

View File

@ -3238,7 +3238,7 @@ do_static_destruction (decl)
my_friendly_assert (!flag_use_cxa_atexit, 20000121); my_friendly_assert (!flag_use_cxa_atexit, 20000121);
/* If we don't need a destructor, there's nothing to do. */ /* 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; return;
/* Actually do the destruction. */ /* Actually do the destruction. */

View File

@ -206,8 +206,21 @@ lang_specific_driver (in_argc, in_argv, in_added_libraries)
real_arglist = (char **) xmalloc (num_args * sizeof (char *)); real_arglist = (char **) xmalloc (num_args * sizeof (char *));
arglist = (const char **) real_arglist; 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. */ /* NOTE: We start at 1 now, not 0. */
for (i = 0, j = 0; i < argc; i++, j++) while (i < argc)
{ {
arglist[j] = argv[i]; arglist[j] = argv[i];
@ -237,11 +250,10 @@ lang_specific_driver (in_argc, in_argv, in_added_libraries)
arglist[j++] = argv[i]; arglist[j++] = argv[i];
arglist[j] = "-xnone"; arglist[j] = "-xnone";
} }
}
#if ENABLE_NEW_GXX_ABI i++;
arglist[j++] = "-fnew-abi"; j++;
#endif }
/* Add `-lstdc++' if we haven't already done so. */ /* Add `-lstdc++' if we haven't already done so. */
if (library) if (library)

View File

@ -49,6 +49,8 @@ static tree initializing_context PARAMS ((tree));
static void expand_cleanup_for_base PARAMS ((tree, tree)); static void expand_cleanup_for_base PARAMS ((tree, tree));
static tree get_temp_regvar PARAMS ((tree, tree)); static tree get_temp_regvar PARAMS ((tree, tree));
static tree dfs_initialize_vtbl_ptrs PARAMS ((tree, void *)); 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 /* Set up local variable for this file. MUST BE CALLED AFTER
INIT_DECL_PROCESSING. */ INIT_DECL_PROCESSING. */
@ -225,7 +227,7 @@ perform_member_init (member, name, init, explicit)
finish_expr_stmt (build_modify_expr (decl, INIT_EXPR, init)); finish_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
} }
if (TYPE_NEEDS_DESTRUCTOR (type)) if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
{ {
tree expr; tree expr;
@ -701,7 +703,7 @@ expand_cleanup_for_base (binfo, flag)
{ {
tree expr; tree expr;
if (!TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (binfo))) if (TYPE_HAS_TRIVIAL_DESTRUCTOR (BINFO_TYPE (binfo)))
return; return;
/* Call the destructor. */ /* Call the destructor. */
@ -2101,10 +2103,40 @@ build_java_class_ref (type)
return class_decl; 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 /* Called from cplus_expand_expr when expanding a NEW_EXPR. The return
value is immediately handed to expand_expr. */ value is immediately handed to expand_expr. */
tree static tree
build_new_1 (exp) build_new_1 (exp)
tree exp; tree exp;
{ {
@ -2113,15 +2145,23 @@ build_new_1 (exp)
tree nelts = NULL_TREE; tree nelts = NULL_TREE;
tree alloc_expr, alloc_node = NULL_TREE; tree alloc_expr, alloc_node = NULL_TREE;
int has_array = 0; int has_array = 0;
enum tree_code code = NEW_EXPR; enum tree_code code;
int use_cookie, nothrow, check_new; 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_global_new;
int use_java_new = 0; 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); placement = TREE_OPERAND (exp, 0);
type = TREE_OPERAND (exp, 1); type = TREE_OPERAND (exp, 1);
init = TREE_OPERAND (exp, 2); 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) if (TREE_CODE (type) == ARRAY_REF)
{ {
@ -2131,6 +2171,8 @@ build_new_1 (exp)
} }
true_type = type; true_type = type;
code = has_array ? VEC_NEW_EXPR : NEW_EXPR;
if (CP_TYPE_QUALS (type)) if (CP_TYPE_QUALS (type))
type = TYPE_MAIN_VARIANT (type); type = TYPE_MAIN_VARIANT (type);
@ -2161,32 +2203,44 @@ build_new_1 (exp)
if (abstract_virtuals_error (NULL_TREE, true_type)) if (abstract_virtuals_error (NULL_TREE, true_type))
return error_mark_node; return error_mark_node;
/* When we allocate an array, and the corresponding deallocation /* Figure out whether or not we're going to use the global operator
function takes a second argument of type size_t, and that's the new. */
"usual deallocation function", we allocate some extra space at if (!globally_qualified_p
the beginning of the array to store the size of the array. && 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 /* We only need cookies for arrays containing types for which we
have to do this whenever there's a two-argument array-delete need cookies. */
operator. if (!has_array || !TYPE_VEC_NEW_USES_COOKIE (true_type))
use_cookie = 0;
FIXME: For -fnew-abi, we don't have to maintain backwards /* When using placement new, users may not realize that they need
compatibility and we should fix this. */ the extra storage. Under the old ABI, we don't allocate the
use_cookie = (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type) cookie whenever they use one placement argument of type `void
&& ! (placement && ! TREE_CHAIN (placement) *'. Under the new ABI, we require that the operator called be
&& TREE_TYPE (TREE_VALUE (placement)) == ptr_type_node)); 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) if (use_cookie)
size = size_binop (PLUS_EXPR, size, BI_header_size);
if (has_array)
{ {
code = VEC_NEW_EXPR; cookie_size = get_cookie_size (true_type);
size = size_binop (PLUS_EXPR, size, cookie_size);
if (init && pedantic)
cp_pedwarn ("initialization in array new");
} }
if (has_array && init && pedantic)
cp_pedwarn ("initialization in array new");
/* Allocate the object. */ /* Allocate the object. */
if (! placement && TYPE_FOR_JAVA (true_type)) if (! placement && TYPE_FOR_JAVA (true_type))
@ -2208,9 +2262,20 @@ build_new_1 (exp)
} }
else else
{ {
rval = build_op_new_call tree fnname;
(code, true_type, tree_cons (NULL_TREE, size, placement), tree args;
LOOKUP_NORMAL | (use_global_new * LOOKUP_GLOBAL));
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); 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 */ /* Finish up some magic for new'ed arrays */
if (use_cookie && rval != NULL_TREE) if (use_cookie && rval != NULL_TREE)
{ {
tree extra = BI_header_size;
tree cookie, exp1; tree cookie, exp1;
rval = convert (string_type_node, rval); /* for ptr arithmetic */ rval = convert (string_type_node, rval); /* for ptr arithmetic */
rval = save_expr (build_binary_op (PLUS_EXPR, rval, extra)); rval = save_expr (build_binary_op (PLUS_EXPR, rval, cookie_size));
/* Store header info. */ /* Store the number of bytes allocated so that we can know how
cookie = build_indirect_ref (build (MINUS_EXPR, many elements to destroy later. */
build_pointer_type (BI_header_type), if (flag_new_abi)
rval, extra), NULL_PTR); {
exp1 = build (MODIFY_EXPR, void_type_node, /* Under the new ABI, we use the last sizeof (size_t) bytes
build_component_ref (cookie, nelts_identifier, to store the number of elements. */
NULL_TREE, 0), cookie = build_indirect_ref (build (MINUS_EXPR,
nelts); 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 = cp_convert (build_pointer_type (true_type), rval);
rval = build_compound_expr rval = build_compound_expr
(tree_cons (NULL_TREE, exp1, (tree_cons (NULL_TREE, exp1,
@ -2372,7 +2455,8 @@ build_new_1 (exp)
{ {
enum tree_code dcode = has_array ? VEC_DELETE_EXPR : DELETE_EXPR; enum tree_code dcode = has_array ? VEC_DELETE_EXPR : DELETE_EXPR;
tree cleanup, fn = NULL_TREE; 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 /* The Standard is unclear here, but the right thing to do
is to use the same method for finding deallocation 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. */ This is also the containing expression returned by this function. */
tree controller = NULL_TREE; 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; loop = integer_zero_node;
goto no_destructor; goto no_destructor;
@ -2534,12 +2618,16 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, use_global_delete)
base_tbd = base; base_tbd = base;
else else
{ {
base_tbd = cp_convert (ptype, tree cookie_size;
build_binary_op (MINUS_EXPR,
cp_convert (string_type_node, base), cookie_size = get_cookie_size (type);
BI_header_size)); base_tbd
= cp_convert (ptype,
build_binary_op (MINUS_EXPR,
cp_convert (string_type_node, base),
cookie_size));
/* True size with header. */ /* 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, deallocate_expr = build_x_delete (base_tbd,
2 | use_global_delete, 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 /* Protect the entire array initialization so that we can destroy
the partially constructed array if an exception is thrown. */ 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_block = begin_try_block ();
try_body = begin_compound_stmt (/*has_no_scope=*/1); 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. */ /* 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; tree e;
@ -3029,7 +3117,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
my_friendly_assert (IS_AGGR_TYPE (type), 220); 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) if (auto_delete == integer_zero_node)
return void_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) if (auto_delete == integer_zero_node)
cond = NULL_TREE; cond = NULL_TREE;
else if (base_binfo == 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, cond = build (COND_EXPR, void_type_node,
build (BIT_AND_EXPR, integer_type_node, auto_delete, integer_one_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 if (base_binfo
&& ! TREE_VIA_VIRTUAL (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; 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++) for (i = 1; i < n_baseclasses; i++)
{ {
base_binfo = TREE_VEC_ELT (binfos, 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)) || TREE_VIA_VIRTUAL (base_binfo))
continue; continue;
@ -3154,7 +3242,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
{ {
if (TREE_CODE (member) != FIELD_DECL) if (TREE_CODE (member) != FIELD_DECL)
continue; 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_member = build_component_ref (ref, DECL_NAME (member), NULL_TREE, 0);
tree this_type = TREE_TYPE (member); 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) if (TREE_CODE (type) == POINTER_TYPE)
{ {
/* Step back one from start of vector, and read dimension. */ /* Step back one from start of vector, and read dimension. */
tree cookie_addr = build (MINUS_EXPR, build_pointer_type (BI_header_type), tree cookie_addr;
base, BI_header_size);
tree cookie = build_indirect_ref (cookie_addr, NULL_PTR); if (flag_new_abi)
maxindex = build_component_ref (cookie, nelts_identifier, NULL_TREE, 0); {
do cookie_addr = build (MINUS_EXPR,
type = TREE_TYPE (type); build_pointer_type (sizetype),
while (TREE_CODE (type) == ARRAY_TYPE); 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) else if (TREE_CODE (type) == ARRAY_TYPE)
{ {
/* get the total number of things in the array, maxindex is a bad name */ /* get the total number of things in the array, maxindex is a bad name */
maxindex = array_type_nelts_total (type); maxindex = array_type_nelts_total (type);
while (TREE_CODE (type) == ARRAY_TYPE) type = strip_array_types (type);
type = TREE_TYPE (type);
base = build_unary_op (ADDR_EXPR, base, 1); base = build_unary_op (ADDR_EXPR, base, 1);
} }
else else

View File

@ -3147,7 +3147,7 @@ do_identifier (token, parsing, args)
else if (!DECL_ERROR_REPORTED (id)) else if (!DECL_ERROR_REPORTED (id))
{ {
DECL_ERROR_REPORTED (id) = 1; 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", error ("name lookup of `%s' changed for new ISO `for' scoping",
IDENTIFIER_POINTER (token)); IDENTIFIER_POINTER (token));

View File

@ -4830,7 +4830,8 @@ instantiate_class_template (type)
TYPE_OVERLOADS_CALL_EXPR (type) = TYPE_OVERLOADS_CALL_EXPR (pattern); TYPE_OVERLOADS_CALL_EXPR (type) = TYPE_OVERLOADS_CALL_EXPR (pattern);
TYPE_OVERLOADS_ARRAY_REF (type) = TYPE_OVERLOADS_ARRAY_REF (pattern); TYPE_OVERLOADS_ARRAY_REF (type) = TYPE_OVERLOADS_ARRAY_REF (pattern);
TYPE_OVERLOADS_ARROW (type) = TYPE_OVERLOADS_ARROW (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_GETS_DELETE (type) = TYPE_GETS_DELETE (pattern);
TYPE_VEC_DELETE_TAKES_SIZE (type) = TYPE_VEC_DELETE_TAKES_SIZE (pattern); TYPE_VEC_DELETE_TAKES_SIZE (type) = TYPE_VEC_DELETE_TAKES_SIZE (pattern);
TYPE_HAS_ASSIGN_REF (type) = TYPE_HAS_ASSIGN_REF (pattern); TYPE_HAS_ASSIGN_REF (type) = TYPE_HAS_ASSIGN_REF (pattern);

View File

@ -113,7 +113,7 @@ print_lang_type (file, node, indent)
if (TYPE_NEEDS_CONSTRUCTING (node)) if (TYPE_NEEDS_CONSTRUCTING (node))
fputs ( "needs-constructor", file); fputs ( "needs-constructor", file);
if (TYPE_NEEDS_DESTRUCTOR (node)) if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (node))
fputs (" needs-destructor", file); fputs (" needs-destructor", file);
if (TYPE_HAS_DESTRUCTOR (node)) if (TYPE_HAS_DESTRUCTOR (node))
fputs (" ~X()", file); fputs (" ~X()", file);
@ -128,9 +128,9 @@ print_lang_type (file, node, indent)
else else
fputs (" X(X&)", file); fputs (" X(X&)", file);
} }
if (TYPE_GETS_NEW (node) & 1) if (TYPE_HAS_NEW_OPERATOR (node))
fputs (" new", file); fputs (" new", file);
if (TYPE_GETS_NEW (node) & 2) if (TYPE_HAS_ARRAY_NEW_OPERATOR (node))
fputs (" new[]", file); fputs (" new[]", file);
if (TYPE_GETS_DELETE (node) & 1) if (TYPE_GETS_DELETE (node) & 1)
fputs (" delete", file); fputs (" delete", file);

View File

@ -725,7 +725,7 @@ context_for_name_lookup (decl)
For the purposes of name lookup, after the anonymous union For the purposes of name lookup, after the anonymous union
definition, the members of the anonymous union are considered to 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. */ declared. */
tree context = CP_DECL_CONTEXT (decl); tree context = CP_DECL_CONTEXT (decl);
@ -1955,7 +1955,7 @@ tree_has_any_destructor_p (binfo, data)
void *data ATTRIBUTE_UNUSED; void *data ATTRIBUTE_UNUSED;
{ {
tree type = BINFO_TYPE (binfo); 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 /* Returns > 0 if a function with type DRETTYPE overriding a function

View File

@ -322,7 +322,7 @@ break_out_cleanups (exp)
tree tmp = exp; tree tmp = exp;
if (TREE_CODE (tmp) == CALL_EXPR 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); return build_cplus_new (TREE_TYPE (tmp), tmp);
while (TREE_CODE (tmp) == NOP_EXPR while (TREE_CODE (tmp) == NOP_EXPR
@ -330,7 +330,7 @@ break_out_cleanups (exp)
|| TREE_CODE (tmp) == NON_LVALUE_EXPR) || TREE_CODE (tmp) == NON_LVALUE_EXPR)
{ {
if (TREE_CODE (TREE_OPERAND (tmp, 0)) == CALL_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) TREE_OPERAND (tmp, 0)
= build_cplus_new (TREE_TYPE (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. */ more easily. */
TYPE_NEEDS_CONSTRUCTING (t) TYPE_NEEDS_CONSTRUCTING (t)
= TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (elt_type)); = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (elt_type));
TYPE_NEEDS_DESTRUCTOR (t) TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
= TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (elt_type)); = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TYPE_MAIN_VARIANT (elt_type));
return t; return t;
} }
@ -602,7 +602,7 @@ cp_build_qualified_type_real (type, type_quals, complain)
} }
/* Even if we already had this variant, we update /* 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. they changed since the variant was originally created.
This seems hokey; if there is some way to use a previous 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 will never be updated. */
TYPE_NEEDS_CONSTRUCTING (t) TYPE_NEEDS_CONSTRUCTING (t)
= TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (element_type)); = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (element_type));
TYPE_NEEDS_DESTRUCTOR (t) TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
= TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (element_type)); = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TYPE_MAIN_VARIANT (element_type));
return t; return t;
} }
else if (TYPE_PTRMEMFUNC_P (type)) else if (TYPE_PTRMEMFUNC_P (type))

View File

@ -155,8 +155,8 @@ complete_type (type)
layout_type (type); layout_type (type);
TYPE_NEEDS_CONSTRUCTING (type) TYPE_NEEDS_CONSTRUCTING (type)
= TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (t)); = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (t));
TYPE_NEEDS_DESTRUCTOR (type) TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
= TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (t)); = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TYPE_MAIN_VARIANT (t));
} }
else if (CLASS_TYPE_P (type) && CLASSTYPE_TEMPLATE_INSTANTIATION (type)) else if (CLASS_TYPE_P (type) && CLASSTYPE_TEMPLATE_INSTANTIATION (type))
instantiate_class_template (TYPE_MAIN_VARIANT (type)); instantiate_class_template (TYPE_MAIN_VARIANT (type));

View File

@ -0,0 +1,127 @@
// Origin: Mark Mitchell <mark@codesourcery.com>
#if defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100
#include <cstdlib>
#include <new>
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 <typename T>
void check_no_cookie (int i)
{
void* a = new T[7];
if (p != a)
exit (i);
}
template <typename T>
void check_no_placement_cookie (int i)
{
p = malloc (13 * sizeof (T));
void* a = new (p) T[13];
if (p != a)
exit (i);
}
template <typename T>
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 <typename T>
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 <typename T>
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<int> (1);
check_no_cookie<X> (2);
check_no_cookie<Y<double> > (3);
// There should be no cookies for allocations using global placement
// new.
check_no_placement_cookie<int> (4);
check_no_placement_cookie<X> (5);
check_no_placement_cookie<Z> (6);
// There should be a cookie when using a non-trivial destructor.
check_cookie<Z> (7);
check_cookie<Z2> (8);
// There should be a cookie when using the two-argument array delete
// operator.
check_cookie<W1> (9);
// But not when the one-argument version is also available.
check_no_cookie<W2> (10);
// There should be a cookie when using a non-global placement new.
check_placement_cookie<V> (11);
}
#else /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */
int main ()
{
}
#endif /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */

View File

@ -1,4 +1,5 @@
// Origin: Mark Mitchell <mark@codesourcery.com> // Origin: Mark Mitchell <mark@codesourcery.com>
// Special g++ Options: -O2
#include <list> #include <list>

View File

@ -880,6 +880,10 @@ struct tree_block
The value is an int, measured in bits. */ The value is an int, measured in bits. */
#define TYPE_ALIGN(NODE) (TYPE_CHECK (NODE)->type.align) #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)) #define TYPE_STUB_DECL(NODE) (TREE_CHAIN (NODE))
/* In a RECORD_TYPE, UNION_TYPE or QUAL_UNION_TYPE, it means the type /* In a RECORD_TYPE, UNION_TYPE or QUAL_UNION_TYPE, it means the type