This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH: new abi vector new support
- To: gcc-patches at gcc dot gnu dot org
- Subject: C++ PATCH: new abi vector new support
- From: Mark Mitchell <mark at codesourcery dot com>
- Date: Thu, 02 Mar 2000 18:41:33 -0800
- Organization: CodeSourcery, LLC
The new ABI specifies slightly different rules about how "cookies" are
allocated when the user writes something like `new T[7]'. This patch
implements those rules, and adds a test case to see that they have
been implemented correctly.
In addition, I cleaned up some code in the C++ front-end, including
changing the TYPE_NEEDS_DESTRUCTOR macro to use the standard
terminology TYPE_HAS_NONTRIVIAL_DESTRUCTOR. It's a lot easier to see
that the code is correct when the concepts in the code line up with
the concepts in the standard.
I also fixed a buglet with --enable-new-gxx-abi. The -fnew-abi flag
was being added to the end of the command-line, which meant that it
could not be easily overridden. That caused g++.other/mangle1.C to
break using the new ABI; it's now fixed.
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
2000-03-02 Mark Mitchell <mark@codesourcery.com>
* tree.h (TYPE_ALIGN_UNIT): New macro.
Index: tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/tree.h,v
retrieving revision 1.129
diff -c -p -r1.129 tree.h
*** tree.h 2000/02/29 23:33:48 1.129
--- tree.h 2000/03/03 01:12:36
*************** struct tree_block
*** 880,885 ****
--- 880,889 ----
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
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.
Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/call.c,v
retrieving revision 1.198
diff -c -p -r1.198 call.c
*** call.c 2000/02/27 06:54:03 1.198
--- call.c 2000/03/03 01:12:40
*************** builtin:
*** 3452,3482 ****
}
}
- /* 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 *)
--- 3452,3457 ----
Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/class.c,v
retrieving revision 1.266
diff -c -p -r1.266 class.c
*** class.c 2000/02/29 10:29:52 1.266
--- class.c 2000/03/03 01:12:44
*************** check_bases (t, cant_have_default_ctor_p
*** 1934,1940 ****
/* 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_COMPLEX_ASSIGN_REF (t)
|= TYPE_HAS_COMPLEX_ASSIGN_REF (basetype);
TYPE_HAS_COMPLEX_INIT_REF (t) |= TYPE_HAS_COMPLEX_INIT_REF (basetype);
--- 1934,1941 ----
/* A lot of properties from the bases also apply to the derived
class. */
TYPE_NEEDS_CONSTRUCTING (t) |= TYPE_NEEDS_CONSTRUCTING (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);
*************** finish_struct_bits (t)
*** 2079,2085 ****
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_BASE_CONVS_MAY_REQUIRE_CODE_P (variants)
= TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (t);
--- 2080,2087 ----
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_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);
*************** add_implicitly_declared_members (t, cant
*** 3503,3516 ****
tree *f;
/* Destructor. */
! if (TYPE_NEEDS_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;
else
{
TREE_CHAIN (default_fn) = implicit_fns;
--- 3505,3518 ----
tree *f;
/* Destructor. */
! 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_HAS_NONTRIVIAL_DESTRUCTOR (t) = 0;
else
{
TREE_CHAIN (default_fn) = implicit_fns;
*************** add_implicitly_declared_members (t, cant
*** 3520,3526 ****
virtual_dtor = default_fn;
}
}
! TYPE_NEEDS_DESTRUCTOR (t) |= TYPE_HAS_DESTRUCTOR (t);
/* Default constructor. */
if (! TYPE_HAS_CONSTRUCTOR (t) && ! cant_have_default_ctor)
--- 3522,3530 ----
virtual_dtor = default_fn;
}
}
! 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)
*************** check_field_decl (field, t, cant_have_co
*** 3744,3750 ****
if (TYPE_NEEDS_CONSTRUCTING (type))
cp_error_at ("member `%#D' with constructor not allowed in union",
field);
! if (TYPE_NEEDS_DESTRUCTOR (type))
cp_error_at ("member `%#D' with destructor not allowed in union",
field);
if (TYPE_HAS_COMPLEX_ASSIGN_REF (type))
--- 3748,3754 ----
if (TYPE_NEEDS_CONSTRUCTING (type))
cp_error_at ("member `%#D' with constructor not allowed in union",
field);
! 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))
*************** check_field_decl (field, t, cant_have_co
*** 3754,3760 ****
else
{
TYPE_NEEDS_CONSTRUCTING (t) |= TYPE_NEEDS_CONSTRUCTING (type);
! TYPE_NEEDS_DESTRUCTOR (t) |= TYPE_NEEDS_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);
}
--- 3758,3765 ----
else
{
TYPE_NEEDS_CONSTRUCTING (t) |= TYPE_NEEDS_CONSTRUCTING (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);
}
*************** check_methods (t)
*** 4268,4273 ****
--- 4273,4279 ----
tree t;
{
tree x;
+ int seen_one_arg_array_delete_p = 0;
for (x = TYPE_METHODS (t); x; x = TREE_CHAIN (x))
{
*************** check_methods (t)
*** 4290,4295 ****
--- 4296,4332 ----
if (DECL_PURE_VIRTUAL_P (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;
}
}
}
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.410
diff -c -p -r1.410 cp-tree.h
*** cp-tree.h 2000/02/29 02:34:48 1.410
--- cp-tree.h 2000/03/03 01:12:47
*************** Boston, MA 02111-1307, USA. */
*** 81,87 ****
1: TYPE_HAS_CONSTRUCTOR.
2: TYPE_HAS_DESTRUCTOR.
3: TYPE_FOR_JAVA.
! 4: TYPE_NEEDS_DESTRUCTOR.
5: IS_AGGR_TYPE.
6: TYPE_BUILT_IN.
--- 81,87 ----
1: TYPE_HAS_CONSTRUCTOR.
2: TYPE_HAS_DESTRUCTOR.
3: TYPE_FOR_JAVA.
! 4: TYPE_HAS_NONTRIVIAL_DESTRUCTOR
5: IS_AGGR_TYPE.
6: TYPE_BUILT_IN.
*************** struct lang_type
*** 1310,1316 ****
unsigned has_nonpublic_assign_ref : 2;
unsigned vtable_needs_writing : 1;
unsigned has_assign_ref : 1;
! unsigned gets_new : 2;
unsigned gets_delete : 2;
unsigned has_call_overloaded : 1;
--- 1310,1317 ----
unsigned has_nonpublic_assign_ref : 2;
unsigned vtable_needs_writing : 1;
unsigned has_assign_ref : 1;
! unsigned has_new : 1;
! unsigned has_array_new : 1;
unsigned gets_delete : 2;
unsigned has_call_overloaded : 1;
*************** struct lang_type
*** 1391,1399 ****
/* 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)
#define TYPE_GETS_DELETE(NODE) (TYPE_LANG_SPECIFIC(NODE)->gets_delete)
#define TYPE_GETS_REG_DELETE(NODE) (TYPE_GETS_DELETE (NODE) & 1)
--- 1392,1398 ----
/* 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 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)
*************** struct lang_type
*** 1401,1410 ****
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 means that this _CLASSTYPE node defines ways of converting
itself to other types. */
#define TYPE_HAS_CONVERSION(NODE) (TYPE_LANG_SPECIFIC(NODE)->has_type_conversion)
--- 1400,1415 ----
takes the optional size_t argument. */
#define TYPE_VEC_DELETE_TAKES_SIZE(NODE) \
(TYPE_LANG_SPECIFIC(NODE)->vec_delete_takes_size)
+ /* 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. */
#define TYPE_HAS_CONVERSION(NODE) (TYPE_LANG_SPECIFIC(NODE)->has_type_conversion)
*************** struct lang_type
*** 1417,1422 ****
--- 1422,1436 ----
#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)
*************** struct lang_decl
*** 1916,1921 ****
--- 1930,1939 ----
#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
*************** extern int flag_new_for_scope;
*** 2409,2419 ****
#define TYPE_HAS_COMPLEX_ASSIGN_REF(NODE) (TYPE_LANG_SPECIFIC(NODE)->has_complex_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)
! /* 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 for class type means that initialization of this type can use
a bitwise copy. */
--- 2427,2453 ----
#define TYPE_HAS_COMPLEX_ASSIGN_REF(NODE) (TYPE_LANG_SPECIFIC(NODE)->has_complex_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)
+
+ /* 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. */
*************** extern tree type_decays_to PARAMS ((tr
*** 3578,3584 ****
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));
--- 3612,3617 ----
*************** extern tree build_offset_ref PARAMS ((
*** 3922,3928 ****
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));
--- 3955,3960 ----
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.555
diff -c -p -r1.555 decl.c
*** decl.c 2000/02/29 23:33:49 1.555
--- decl.c 2000/03/03 01:12:56
*************** start_decl_1 (decl)
*** 6844,6850 ****
/* 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)
&& current_binding_level->more_cleanups_ok == 0)
{
keep_next_level (2);
--- 6844,6850 ----
/* 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_HAS_NONTRIVIAL_DESTRUCTOR (type)
&& current_binding_level->more_cleanups_ok == 0)
{
keep_next_level (2);
*************** initialize_local_var (decl, init, flags)
*** 7490,7496 ****
if (TREE_STATIC (decl))
{
if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE
! || TYPE_NEEDS_DESTRUCTOR (type))
expand_static_init (decl, init);
return;
}
--- 7490,7496 ----
if (TREE_STATIC (decl))
{
if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE
! || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
expand_static_init (decl, init);
return;
}
*************** initialize_local_var (decl, init, flags)
*** 7522,7528 ****
marked used. (see TREE_USED, above.) */
if (TYPE_NEEDS_CONSTRUCTING (type)
&& ! already_used
! && !TYPE_NEEDS_DESTRUCTOR (type)
&& DECL_NAME (decl))
TREE_USED (decl) = 0;
else if (already_used)
--- 7522,7528 ----
marked used. (see TREE_USED, above.) */
if (TYPE_NEEDS_CONSTRUCTING (type)
&& ! already_used
! && TYPE_HAS_TRIVIAL_DESTRUCTOR (type)
&& DECL_NAME (decl))
TREE_USED (decl) = 0;
else if (already_used)
*************** destroy_local_var (decl)
*** 7544,7550 ****
return;
/* And only things with destructors need cleaning up. */
! if (!TYPE_NEEDS_DESTRUCTOR (type))
return;
if (TREE_CODE (decl) == VAR_DECL &&
--- 7544,7550 ----
return;
/* And only things with destructors need cleaning up. */
! if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
return;
if (TREE_CODE (decl) == VAR_DECL &&
*************** cp_finish_decl (decl, init, asmspec_tree
*** 7820,7826 ****
{
/* Cleanups for static variables are handled by `finish_file'. */
if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE
! || TYPE_NEEDS_DESTRUCTOR (type))
expand_static_init (decl, init);
}
finish_end0:
--- 7820,7826 ----
{
/* Cleanups for static variables are handled by `finish_file'. */
if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE
! || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
expand_static_init (decl, init);
}
finish_end0:
*************** register_dtor_fn (decl)
*** 8054,8060 ****
int saved_flag_access_control;
! if (!TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl)))
return;
/* Call build_cleanup before we enter the anonymous function so that
--- 8054,8060 ----
int saved_flag_access_control;
! if (TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
return;
/* Call build_cleanup before we enter the anonymous function so that
*************** grok_op_properties (decl, virtualp, frie
*** 11856,11866 ****
|| 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;
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;
else if (name == ansi_opname[(int) VEC_DELETE_EXPR])
TYPE_GETS_DELETE (current_class_type) |= 2;
}
--- 11856,11866 ----
|| name == ansi_opname[(int) MEMBER_REF])
TYPE_OVERLOADS_ARROW (current_class_type) = 1;
else if (name == ansi_opname[(int) NEW_EXPR])
! 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_HAS_ARRAY_NEW_OPERATOR (current_class_type) = 1;
else if (name == ansi_opname[(int) VEC_DELETE_EXPR])
TYPE_GETS_DELETE (current_class_type) |= 2;
}
*************** grok_op_properties (decl, virtualp, frie
*** 11894,11907 ****
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;
! }
}
else
{
--- 11894,11900 ----
hash_tree_chain (ptr_type_node,
void_list_node));
else
! TREE_TYPE (decl) = coerce_delete_type (TREE_TYPE (decl));
}
else
{
*************** xref_basetypes (code_type_node, name, re
*** 12508,12514 ****
if (CLASS_TYPE_P (basetype))
{
! TYPE_GETS_NEW (ref) |= TYPE_GETS_NEW (basetype);
TYPE_GETS_DELETE (ref) |= TYPE_GETS_DELETE (basetype);
/* If the base-class uses multiple inheritance, so do we. */
TYPE_USES_MULTIPLE_INHERITANCE (ref)
--- 12501,12510 ----
if (CLASS_TYPE_P (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)
*************** store_parm_decls ()
*** 13387,13393 ****
cleanups = tree_cons (parm, cleanup, cleanups);
}
else if (type != error_mark_node
! && TYPE_NEEDS_DESTRUCTOR (type))
parms_have_cleanups = 1;
}
else
--- 13383,13389 ----
cleanups = tree_cons (parm, cleanup, cleanups);
}
else if (type != error_mark_node
! && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
parms_have_cleanups = 1;
}
else
*************** finish_destructor_body ()
*** 13603,13609 ****
while (vbases)
{
! if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (vbases)))
{
tree vb = get_vbase
(BINFO_TYPE (vbases),
--- 13599,13605 ----
while (vbases)
{
! if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (BINFO_TYPE (vbases)))
{
tree vb = get_vbase
(BINFO_TYPE (vbases),
*************** maybe_build_cleanup_1 (decl, auto_delete
*** 14286,14292 ****
tree decl, auto_delete;
{
tree type = TREE_TYPE (decl);
! if (type != error_mark_node && TYPE_NEEDS_DESTRUCTOR (type))
{
int flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR;
tree rval;
--- 14282,14288 ----
tree decl, auto_delete;
{
tree type = TREE_TYPE (decl);
! if (type != error_mark_node && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
{
int flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR;
tree rval;
Index: cp/decl2.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl2.c,v
retrieving revision 1.313
diff -c -p -r1.313 decl2.c
*** decl2.c 2000/02/27 02:46:57 1.313
--- decl2.c 2000/03/03 01:12:59
*************** do_static_destruction (decl)
*** 3238,3244 ****
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)))
return;
/* Actually do the destruction. */
--- 3238,3244 ----
my_friendly_assert (!flag_use_cxa_atexit, 20000121);
/* If we don't need a destructor, there's nothing to do. */
! if (TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
return;
/* Actually do the destruction. */
Index: cp/g++spec.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/g++spec.c,v
retrieving revision 1.19
diff -c -p -r1.19 g++spec.c
*** g++spec.c 2000/01/13 15:37:03 1.19
--- g++spec.c 2000/03/03 01:13:00
*************** lang_specific_driver (in_argc, in_argv,
*** 206,213 ****
real_arglist = (char **) xmalloc (num_args * sizeof (char *));
arglist = (const char **) real_arglist;
/* NOTE: We start at 1 now, not 0. */
! for (i = 0, j = 0; i < argc; i++, j++)
{
arglist[j] = argv[i];
--- 206,226 ----
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. */
! while (i < argc)
{
arglist[j] = argv[i];
*************** lang_specific_driver (in_argc, in_argv,
*** 237,247 ****
arglist[j++] = argv[i];
arglist[j] = "-xnone";
}
- }
! #if ENABLE_NEW_GXX_ABI
! arglist[j++] = "-fnew-abi";
! #endif
/* Add `-lstdc++' if we haven't already done so. */
if (library)
--- 250,259 ----
arglist[j++] = argv[i];
arglist[j] = "-xnone";
}
! i++;
! j++;
! }
/* Add `-lstdc++' if we haven't already done so. */
if (library)
Index: cp/init.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/init.c,v
retrieving revision 1.170
diff -c -p -r1.170 init.c
*** init.c 2000/03/01 00:40:13 1.170
--- init.c 2000/03/03 01:13:01
*************** static tree build_java_class_ref PARAMS
*** 50,55 ****
--- 50,56 ----
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));
/* Set up local variable for this file. MUST BE CALLED AFTER
INIT_DECL_PROCESSING. */
*************** perform_member_init (member, name, init,
*** 226,232 ****
finish_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
}
! if (TYPE_NEEDS_DESTRUCTOR (type))
{
tree expr;
--- 227,233 ----
finish_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
}
! if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
{
tree expr;
*************** expand_cleanup_for_base (binfo, flag)
*** 702,708 ****
{
tree expr;
! if (!TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (binfo)))
return;
/* Call the destructor. */
--- 703,709 ----
{
tree expr;
! if (TYPE_HAS_TRIVIAL_DESTRUCTOR (BINFO_TYPE (binfo)))
return;
/* Call the destructor. */
*************** build_java_class_ref (type)
*** 2102,2111 ****
return class_decl;
}
/* Called from cplus_expand_expr when expanding a NEW_EXPR. The return
value is immediately handed to expand_expr. */
! tree
build_new_1 (exp)
tree exp;
{
--- 2103,2142 ----
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. */
! static tree
build_new_1 (exp)
tree exp;
{
*************** build_new_1 (exp)
*** 2114,2128 ****
tree nelts = NULL_TREE;
tree alloc_expr, alloc_node = NULL_TREE;
int has_array = 0;
! enum tree_code code = NEW_EXPR;
int use_cookie, nothrow, check_new;
int use_global_new;
int use_java_new = 0;
placement = TREE_OPERAND (exp, 0);
type = TREE_OPERAND (exp, 1);
init = TREE_OPERAND (exp, 2);
! use_global_new = NEW_EXPR_USE_GLOBAL (exp);
if (TREE_CODE (type) == ARRAY_REF)
{
--- 2145,2167 ----
tree nelts = NULL_TREE;
tree alloc_expr, alloc_node = NULL_TREE;
int has_array = 0;
! 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);
! globally_qualified_p = NEW_EXPR_USE_GLOBAL (exp);
if (TREE_CODE (type) == ARRAY_REF)
{
*************** build_new_1 (exp)
*** 2132,2137 ****
--- 2171,2178 ----
}
true_type = type;
+ code = has_array ? VEC_NEW_EXPR : NEW_EXPR;
+
if (CP_TYPE_QUALS (type))
type = TYPE_MAIN_VARIANT (type);
*************** build_new_1 (exp)
*** 2162,2193 ****
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.
!
! 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));
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");
}
/* Allocate the object. */
if (! placement && TYPE_FOR_JAVA (true_type))
--- 2203,2246 ----
if (abstract_virtuals_error (NULL_TREE, true_type))
return error_mark_node;
! /* 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;
!
! /* 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)
{
! 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))
*************** build_new_1 (exp)
*** 2209,2217 ****
}
else
{
! rval = build_op_new_call
! (code, true_type, tree_cons (NULL_TREE, size, placement),
! LOOKUP_NORMAL | (use_global_new * LOOKUP_GLOBAL));
rval = cp_convert (build_pointer_type (true_type), rval);
}
--- 2262,2281 ----
}
else
{
! 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);
}
*************** build_new_1 (exp)
*** 2250,2267 ****
/* 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 = cp_convert (build_pointer_type (true_type), rval);
rval = build_compound_expr
(tree_cons (NULL_TREE, exp1,
--- 2314,2349 ----
/* Finish up some magic for new'ed arrays */
if (use_cookie && rval != NULL_TREE)
{
tree cookie, exp1;
rval = convert (string_type_node, rval); /* for ptr arithmetic */
! 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,
*************** build_new_1 (exp)
*** 2373,2379 ****
{
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);
/* The Standard is unclear here, but the right thing to do
is to use the same method for finding deallocation
--- 2455,2462 ----
{
enum tree_code dcode = has_array ? VEC_DELETE_EXPR : DELETE_EXPR;
tree cleanup, fn = NULL_TREE;
! 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
*************** build_vec_delete_1 (base, maxindex, type
*** 2476,2482 ****
This is also the containing expression returned by this function. */
tree controller = NULL_TREE;
! if (! IS_AGGR_TYPE (type) || ! TYPE_NEEDS_DESTRUCTOR (type))
{
loop = integer_zero_node;
goto no_destructor;
--- 2559,2565 ----
This is also the containing expression returned by this function. */
tree controller = NULL_TREE;
! if (! IS_AGGR_TYPE (type) || TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
{
loop = integer_zero_node;
goto no_destructor;
*************** build_vec_delete_1 (base, maxindex, type
*** 2535,2546 ****
base_tbd = base;
else
{
! base_tbd = cp_convert (ptype,
! build_binary_op (MINUS_EXPR,
! cp_convert (string_type_node, base),
! BI_header_size));
/* True size with header. */
! virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size);
}
deallocate_expr = build_x_delete (base_tbd,
2 | use_global_delete,
--- 2618,2633 ----
base_tbd = base;
else
{
! 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, cookie_size);
}
deallocate_expr = build_x_delete (base_tbd,
2 | use_global_delete,
*************** build_vec_init (decl, base, maxindex, in
*** 2709,2715 ****
/* 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))
{
try_block = begin_try_block ();
try_body = begin_compound_stmt (/*has_no_scope=*/1);
--- 2796,2802 ----
/* Protect the entire array initialization so that we can destroy
the partially constructed array if an exception is thrown. */
! if (flag_exceptions && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
{
try_block = begin_try_block ();
try_body = begin_compound_stmt (/*has_no_scope=*/1);
*************** build_vec_init (decl, base, maxindex, in
*** 2894,2900 ****
}
/* Make sure to cleanup any partially constructed elements. */
! if (flag_exceptions && TYPE_NEEDS_DESTRUCTOR (type))
{
tree e;
--- 2981,2987 ----
}
/* Make sure to cleanup any partially constructed elements. */
! if (flag_exceptions && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
{
tree e;
*************** build_delete (type, addr, auto_delete, f
*** 3030,3036 ****
my_friendly_assert (IS_AGGR_TYPE (type), 220);
! if (! TYPE_NEEDS_DESTRUCTOR (type))
{
if (auto_delete == integer_zero_node)
return void_zero_node;
--- 3117,3123 ----
my_friendly_assert (IS_AGGR_TYPE (type), 220);
! if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
{
if (auto_delete == integer_zero_node)
return void_zero_node;
*************** build_delete (type, addr, auto_delete, f
*** 3106,3112 ****
if (auto_delete == integer_zero_node)
cond = NULL_TREE;
else if (base_binfo == NULL_TREE
! || ! TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo)))
{
cond = build (COND_EXPR, void_type_node,
build (BIT_AND_EXPR, integer_type_node, auto_delete, integer_one_node),
--- 3193,3199 ----
if (auto_delete == integer_zero_node)
cond = NULL_TREE;
else if (base_binfo == NULL_TREE
! || 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),
*************** build_delete (type, addr, auto_delete, f
*** 3121,3127 ****
if (base_binfo
&& ! TREE_VIA_VIRTUAL (base_binfo)
! && TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo)))
{
tree this_auto_delete;
--- 3208,3214 ----
if (base_binfo
&& ! TREE_VIA_VIRTUAL (base_binfo)
! && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo)))
{
tree this_auto_delete;
*************** build_delete (type, addr, auto_delete, f
*** 3140,3146 ****
for (i = 1; i < n_baseclasses; i++)
{
base_binfo = TREE_VEC_ELT (binfos, i);
! if (! TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo))
|| TREE_VIA_VIRTUAL (base_binfo))
continue;
--- 3227,3233 ----
for (i = 1; i < n_baseclasses; i++)
{
base_binfo = TREE_VEC_ELT (binfos, i);
! if (TYPE_HAS_TRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo))
|| TREE_VIA_VIRTUAL (base_binfo))
continue;
*************** build_delete (type, addr, auto_delete, f
*** 3155,3161 ****
{
if (TREE_CODE (member) != FIELD_DECL)
continue;
! if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (member)))
{
tree this_member = build_component_ref (ref, DECL_NAME (member), NULL_TREE, 0);
tree this_type = TREE_TYPE (member);
--- 3242,3248 ----
{
if (TREE_CODE (member) != FIELD_DECL)
continue;
! 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);
*************** build_vec_delete (base, maxindex, auto_d
*** 3235,3254 ****
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);
}
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);
base = build_unary_op (ADDR_EXPR, base, 1);
}
else
--- 3322,3355 ----
if (TREE_CODE (type) == POINTER_TYPE)
{
/* Step back one from start of vector, and read dimension. */
! 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);
! type = strip_array_types (type);
base = build_unary_op (ADDR_EXPR, base, 1);
}
else
Index: cp/lex.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/lex.c,v
retrieving revision 1.182
diff -c -p -r1.182 lex.c
*** lex.c 2000/02/27 21:39:38 1.182
--- lex.c 2000/03/03 01:13:04
*************** do_identifier (token, parsing, args)
*** 3147,3153 ****
else if (!DECL_ERROR_REPORTED (id))
{
DECL_ERROR_REPORTED (id) = 1;
! if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (id)))
{
error ("name lookup of `%s' changed for new ISO `for' scoping",
IDENTIFIER_POINTER (token));
--- 3147,3153 ----
else if (!DECL_ERROR_REPORTED (id))
{
DECL_ERROR_REPORTED (id) = 1;
! if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (id)))
{
error ("name lookup of `%s' changed for new ISO `for' scoping",
IDENTIFIER_POINTER (token));
Index: cp/pt.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/pt.c,v
retrieving revision 1.400
diff -c -p -r1.400 pt.c
*** pt.c 2000/02/29 10:29:51 1.400
--- pt.c 2000/03/03 01:13:10
*************** instantiate_class_template (type)
*** 4830,4836 ****
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_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);
--- 4830,4837 ----
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_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);
Index: cp/ptree.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/ptree.c,v
retrieving revision 1.22
diff -c -p -r1.22 ptree.c
*** ptree.c 2000/02/26 20:15:46 1.22
--- ptree.c 2000/03/03 01:13:10
*************** print_lang_type (file, node, indent)
*** 113,119 ****
if (TYPE_NEEDS_CONSTRUCTING (node))
fputs ( "needs-constructor", file);
! if (TYPE_NEEDS_DESTRUCTOR (node))
fputs (" needs-destructor", file);
if (TYPE_HAS_DESTRUCTOR (node))
fputs (" ~X()", file);
--- 113,119 ----
if (TYPE_NEEDS_CONSTRUCTING (node))
fputs ( "needs-constructor", file);
! if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (node))
fputs (" needs-destructor", file);
if (TYPE_HAS_DESTRUCTOR (node))
fputs (" ~X()", file);
*************** print_lang_type (file, node, indent)
*** 128,136 ****
else
fputs (" X(X&)", file);
}
! if (TYPE_GETS_NEW (node) & 1)
fputs (" new", file);
! if (TYPE_GETS_NEW (node) & 2)
fputs (" new[]", file);
if (TYPE_GETS_DELETE (node) & 1)
fputs (" delete", file);
--- 128,136 ----
else
fputs (" X(X&)", file);
}
! if (TYPE_HAS_NEW_OPERATOR (node))
fputs (" new", file);
! if (TYPE_HAS_ARRAY_NEW_OPERATOR (node))
fputs (" new[]", file);
if (TYPE_GETS_DELETE (node) & 1)
fputs (" delete", file);
Index: cp/search.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/search.c,v
retrieving revision 1.160
diff -c -p -r1.160 search.c
*** search.c 2000/03/01 05:45:44 1.160
--- search.c 2000/03/03 01:13:12
*************** context_for_name_lookup (decl)
*** 725,731 ****
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
declared. */
tree context = CP_DECL_CONTEXT (decl);
--- 725,731 ----
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 the anonymous union is
declared. */
tree context = CP_DECL_CONTEXT (decl);
*************** tree_has_any_destructor_p (binfo, data)
*** 1955,1961 ****
void *data ATTRIBUTE_UNUSED;
{
tree type = BINFO_TYPE (binfo);
! return TYPE_NEEDS_DESTRUCTOR (type) ? binfo : NULL_TREE;
}
/* Returns > 0 if a function with type DRETTYPE overriding a function
--- 1955,1961 ----
void *data ATTRIBUTE_UNUSED;
{
tree type = BINFO_TYPE (binfo);
! return TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type) ? binfo : NULL_TREE;
}
/* Returns > 0 if a function with type DRETTYPE overriding a function
Index: cp/tree.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/tree.c,v
retrieving revision 1.184
diff -c -p -r1.184 tree.c
*** tree.c 2000/02/27 21:39:38 1.184
--- tree.c 2000/03/03 01:13:13
*************** break_out_cleanups (exp)
*** 322,328 ****
tree tmp = exp;
if (TREE_CODE (tmp) == CALL_EXPR
! && TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (tmp)))
return build_cplus_new (TREE_TYPE (tmp), tmp);
while (TREE_CODE (tmp) == NOP_EXPR
--- 322,328 ----
tree tmp = exp;
if (TREE_CODE (tmp) == CALL_EXPR
! && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (tmp)))
return build_cplus_new (TREE_TYPE (tmp), tmp);
while (TREE_CODE (tmp) == NOP_EXPR
*************** break_out_cleanups (exp)
*** 330,336 ****
|| TREE_CODE (tmp) == NON_LVALUE_EXPR)
{
if (TREE_CODE (TREE_OPERAND (tmp, 0)) == CALL_EXPR
! && TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (TREE_OPERAND (tmp, 0))))
{
TREE_OPERAND (tmp, 0)
= build_cplus_new (TREE_TYPE (TREE_OPERAND (tmp, 0)),
--- 330,336 ----
|| TREE_CODE (tmp) == NON_LVALUE_EXPR)
{
if (TREE_CODE (TREE_OPERAND (tmp, 0)) == CALL_EXPR
! && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (TREE_OPERAND (tmp, 0))))
{
TREE_OPERAND (tmp, 0)
= build_cplus_new (TREE_TYPE (TREE_OPERAND (tmp, 0)),
*************** build_cplus_array_type_1 (elt_type, inde
*** 505,512 ****
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));
return t;
}
--- 505,512 ----
more easily. */
TYPE_NEEDS_CONSTRUCTING (t)
= TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (elt_type));
! TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
! = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TYPE_MAIN_VARIANT (elt_type));
return t;
}
*************** cp_build_qualified_type_real (type, type
*** 602,608 ****
}
/* Even if we already had this variant, we update
! TYPE_NEEDS_CONSTRUCTING and TYPE_NEEDS_DESTRUCTOR in case
they changed since the variant was originally created.
This seems hokey; if there is some way to use a previous
--- 602,608 ----
}
/* Even if we already had this variant, we update
! 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
*************** cp_build_qualified_type_real (type, type
*** 610,617 ****
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));
return t;
}
else if (TYPE_PTRMEMFUNC_P (type))
--- 610,617 ----
TYPE_NEEDS_CONSTRUCTING will never be updated. */
TYPE_NEEDS_CONSTRUCTING (t)
= TYPE_NEEDS_CONSTRUCTING (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))
Index: cp/typeck.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/typeck.c,v
retrieving revision 1.251
diff -c -p -r1.251 typeck.c
*** typeck.c 2000/03/01 05:45:44 1.251
--- typeck.c 2000/03/03 01:13:17
*************** complete_type (type)
*** 155,162 ****
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));
}
else if (CLASS_TYPE_P (type) && CLASSTYPE_TEMPLATE_INSTANTIATION (type))
instantiate_class_template (TYPE_MAIN_VARIANT (type));
--- 155,162 ----
layout_type (type);
TYPE_NEEDS_CONSTRUCTING (type)
= TYPE_NEEDS_CONSTRUCTING (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));
Index: testsuite/g++.old-deja/g++.abi/arraynew.C
===================================================================
RCS file: arraynew.C
diff -N arraynew.C
*** /dev/null Tue May 5 13:32:27 1998
--- arraynew.C Thu Mar 2 17:13:17 2000
***************
*** 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) */
Index: testsuite/g++.old-deja/g++.other/inline7.C
===================================================================
RCS file: /cvs/gcc/egcs/gcc/testsuite/g++.old-deja/g++.other/inline7.C,v
retrieving revision 1.1
diff -c -p -r1.1 inline7.C
*** inline7.C 2000/02/27 02:46:56 1.1
--- inline7.C 2000/03/03 01:13:19
***************
*** 1,4 ****
--- 1,5 ----
// Origin: Mark Mitchell <mark@codesourcery.com>
+ // Special g++ Options: -O2
#include <list>