C++ PATCH: new abi vector new support

Mark Mitchell mark@codesourcery.com
Thu Mar 2 18:34:00 GMT 2000


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>
  


More information about the Gcc-patches mailing list