gcc 3.0 PATCH for PR 2688 and PR 2689

Philip Martin pm@ntlworld.com
Wed May 2 12:04:00 GMT 2001


This patch is against 3.0. It fixes PR 2688 and PR2689 which are both
regressions from 2.95. It also reduces by one the number of unexpected
failures in the g++ testsuite: g++.olivia/new1.C now passes.

There were two problems: first, build_op_delete_call() was not
allowing exception specifications on operator delete, and second
build_new_1() looked for a placement operator delete when
non-placement new throws.

Finally, there is a testcase I used to check some of the common
operator delete uses.

Philip

--


2001-05-02  Philip Martin  <philip_martin@ntlworld.com>

	* init.c: (build_new_1) Discriminate when (non-)placement operator
	delete is required.
	* call.c (build_op_delete_call) Don't require exact exception
	specification match for operator delete.
	* class.c (instantiate_type) ditto
	* typeck.c (comptypes) ditto
	* cp-tree.h ditto



Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/call.c,v
retrieving revision 1.255.2.10
diff -u -r1.255.2.10 call.c
--- call.c	2001/05/01 11:46:06	1.255.2.10
+++ call.c	2001/05/02 18:30:49
@@ -3613,7 +3613,8 @@
 					 void_list_node));
 
       fntype = build_function_type (void_type_node, argtypes);
-      fn = instantiate_type (fntype, fns, itf_no_attributes);
+      fn = instantiate_type (fntype, fns,
+			     itf_no_attributes|itf_no_exact_exceptions);
 
       if (fn != error_mark_node)
 	{
Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/class.c,v
retrieving revision 1.358.2.16
diff -u -r1.358.2.16 class.c
--- class.c	2001/04/27 10:46:44	1.358.2.16
+++ class.c	2001/05/02 18:30:54
@@ -6292,6 +6292,8 @@
   int strict = (flags & itf_no_attributes)
                ? COMPARE_NO_ATTRIBUTES : COMPARE_STRICT;
   int allow_ptrmem = flags & itf_ptrmem_ok;
+  if (flags & itf_no_exact_exceptions)
+    strict |= COMPARE_NO_EXACT_EXCEPTIONS;
   
   flags &= ~itf_ptrmem_ok;
   
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.572.2.23
diff -u -r1.572.2.23 cp-tree.h
--- cp-tree.h	2001/05/01 12:54:43	1.572.2.23
+++ cp-tree.h	2001/05/02 18:30:57
@@ -3199,6 +3199,7 @@
   itf_complain = 1 << 0,      /* complain about errors */
   itf_no_attributes = 1 << 1, /* ignore attributes on comparisons */
   itf_ptrmem_ok = 1 << 2,     /* pointers to member ok (internal use) */
+  itf_no_exact_exceptions = 1 << 3, /* second can be subset of first */
 } instantiate_type_flags;
 
 /* Nonzero means allow Microsoft extensions without a pedwarn.  */
@@ -3599,6 +3600,9 @@
 				   entity is seen.  */
 #define COMPARE_NO_ATTRIBUTES 8 /* The comparison should ignore
 				   extra-linguistic type attributes.  */
+#define COMPARE_NO_EXACT_EXCEPTIONS 16 /* The comparison should allow the
+					  second exception specification to
+					  be a subset of the first. */
 
 /* Used with push_overloaded_decl.  */
 #define PUSH_GLOBAL          0  /* Push the DECL into namespace scope,
Index: cp/init.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/init.c,v
retrieving revision 1.232.2.8
diff -u -r1.232.2.8 init.c
--- init.c	2001/04/16 02:48:33	1.232.2.8
+++ init.c	2001/05/02 18:30:59
@@ -2526,6 +2526,7 @@
       if (flag_exceptions && ! use_java_new)
 	{
 	  enum tree_code dcode = has_array ? VEC_DELETE_EXPR : DELETE_EXPR;
+	  tree fn = placement ? alloc_call : NULL_TREE;
 	  tree cleanup;
 	  int flags = (LOOKUP_NORMAL 
 		       | (globally_qualified_p * LOOKUP_GLOBAL));
@@ -2535,8 +2536,7 @@
              functions that we use for finding allocation functions.  */
 	  flags |= LOOKUP_SPECULATIVELY;
 
-	  cleanup = build_op_delete_call (dcode, alloc_node, size, flags,
-					  alloc_call);
+	  cleanup = build_op_delete_call (dcode, alloc_node, size, flags, fn);
 
 	  /* Ack!  First we allocate the memory.  Then we set our sentry
 	     variable to true, and expand a cleanup that deletes the memory
Index: cp/typeck.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/typeck.c,v
retrieving revision 1.337.2.4
diff -u -r1.337.2.4 typeck.c
--- typeck.c	2001/04/13 21:06:42	1.337.2.4
+++ typeck.c	2001/05/02 18:31:03
@@ -1048,7 +1048,8 @@
 
     case METHOD_TYPE:
       if (! comp_except_specs (TYPE_RAISES_EXCEPTIONS (t1),
-			       TYPE_RAISES_EXCEPTIONS (t2), 1))
+			       TYPE_RAISES_EXCEPTIONS (t2),
+			       !(strict & COMPARE_NO_EXACT_EXCEPTIONS)))
 	return 0;
 
       /* This case is anti-symmetrical!
@@ -1076,7 +1077,8 @@
 
     case FUNCTION_TYPE:
       if (! comp_except_specs (TYPE_RAISES_EXCEPTIONS (t1),
-			       TYPE_RAISES_EXCEPTIONS (t2), 1))
+			       TYPE_RAISES_EXCEPTIONS (t2),
+			       !(strict & COMPARE_NO_EXACT_EXCEPTIONS)))
 	return 0;
 
       val = ((TREE_TYPE (t1) == TREE_TYPE (t2)





// Copyright (C) 2001 Free Software Foundation

// by Philip Martin <philip_martin@ntlworld.com>

// Check that the calls to operator new/delete are to those functions with
// the appropriate signature.  See bugs 2688 and 2689 for background.

#include <new>
extern "C" void abort();

bool new_flag = false;
bool delete_flag = false;
bool delete_place_flag = false;

struct OneNoSpec {
   OneNoSpec( bool raise = false )
   {
      if ( raise )
         throw 1;
   }
   void* operator new( std::size_t n )
   {
      new_flag = true;
      return ::operator new( n );
   }
   // usual deallocation function [3.7.3.2]
   void operator delete( void* p )
   {
      delete_flag = true;
      ::operator delete( p );
   }
};

struct OneWithSpec {
   OneWithSpec( bool raise = false )
   {
      if ( raise )
         throw 1;
   }
   void* operator new( std::size_t n ) throw ( std::bad_alloc )
   {
      new_flag = true;
      return ::operator new( n );
   }
   // usual deallocation function [3.7.3.2]
   void operator delete( void* p ) throw ()
   {
      delete_flag = true;
      ::operator delete( p );
   }
};

struct TwoNoSpec {
   TwoNoSpec( bool raise = false )
   {
      if ( raise )
         throw 1;
   }
   void* operator new( std::size_t n )
   {
      new_flag = true;
      return ::operator new( n );
   }
   // usual deallocation function [3.7.3.2]
   void operator delete( void* p, std::size_t n )
   {
      delete_flag = true;
      ::operator delete( p );
   }
};

struct TwoWithSpec {
   TwoWithSpec( bool raise = false )
   {
      if ( raise )
         throw 1;
   }
   void* operator new( std::size_t n ) throw ( std::bad_alloc )
   {
      new_flag = true;
      return ::operator new( n );
   }
   // usual deallocation function [3.7.3.2]
   void operator delete( void* p, std::size_t n ) throw ()
   {
      delete_flag = true;
      ::operator delete( p );
   }
};

struct BothNoSpec {
   BothNoSpec( bool raise = false )
   {
      if ( raise )
         throw 1;
   }
   void* operator new( std::size_t n )
   {
      new_flag = true;
      return ::operator new( n );
   }
   // usual deallocation function [3.7.3.2]
   void operator delete( void* p )
   {
      delete_flag = true;
      ::operator delete( p );
   }
   // not the usual deallocation function, and never in fact called
   void operator delete( void* p, std::size_t n )
   {
      abort();
   }
};

struct BothWithSpec {
   BothWithSpec( bool raise = false )
   {
      if ( raise )
         throw 1;
   }
   void* operator new( std::size_t n ) throw ( std::bad_alloc )
   {
      new_flag = true;
      return ::operator new( n );
   }
   // usual deallocation function [3.7.3.2]
   void operator delete( void* p ) throw ()
   {
      delete_flag = true;
      ::operator delete( p );
   }
   // not the usual deallocation function, and never in fact called
   void operator delete( void* p, std::size_t n ) throw ()
   {
      abort();
   }
};

struct ArgType { };

struct PlaceNoSpec {
   PlaceNoSpec( bool raise = false )
   {
      if ( raise )
         throw 1;
   }
   void* operator new( std::size_t n, ArgType* a )
   {
      new_flag = true;
      return ::operator new( n );
   }
   // usual deallocation function [3.7.3.2]
   void operator delete( void* p )
   {
      delete_flag = true;
      ::operator delete( p );
   }
   // not the usual deallocation function, never in fact called
   void operator delete( void* p, std::size_t n )
   {
      abort();
   }
   // placement deallocation function
   void operator delete( void* p, ArgType* a )
   {
      delete_place_flag = true;
      ::operator delete( p );
   }
};

struct PlaceWithSpec {
   PlaceWithSpec( bool raise = false )
   {
      if ( raise )
         throw 1;
   }
   void* operator new( std::size_t n, ArgType* a ) throw ( std::bad_alloc )
   {
      new_flag = true;
      return ::operator new( n );
   }
   // usual deallocation function [3.7.3.2]
   void operator delete( void* p ) throw ()
   {
      delete_flag = true;
      ::operator delete( p );
   }
   // not the usual deallocation function, never in fact called
   void operator delete( void* p, std::size_t n ) throw ()
   {
      abort();
   }
   // placement deallocation function
   void operator delete( void* p, ArgType* a ) throw ()
   {
      delete_place_flag = true;
      ::operator delete( p );
   }
};

int
main()
{
   // non-placement new and explicit delete
   delete new OneNoSpec;
   if ( ! ( new_flag && delete_flag ) ) abort();
   new_flag = delete_flag = false;

   delete new OneWithSpec;
   if ( ! ( new_flag && delete_flag ) ) abort();
   new_flag = delete_flag = false;

   delete new TwoNoSpec;
   if ( ! ( new_flag && delete_flag ) ) abort();
   new_flag = delete_flag = false;

   delete new TwoWithSpec;
   if ( ! ( new_flag && delete_flag ) ) abort();
   new_flag = delete_flag = false;

   delete new BothNoSpec;
   if ( ! ( new_flag && delete_flag ) ) abort();
   new_flag = delete_flag = false;

   delete new BothWithSpec;
   if ( ! ( new_flag && delete_flag ) ) abort();
   new_flag = delete_flag = false;

   // non-placement new throwing
   try { new OneNoSpec( true ); } catch ( ... ) { }
   if ( ! ( new_flag && delete_flag ) ) abort();
   new_flag = delete_flag = false;

   try { new OneWithSpec( true ); } catch ( ... ) { }
   if ( ! ( new_flag && delete_flag ) ) abort();
   new_flag = delete_flag = false;

   try { new TwoNoSpec( true ); } catch ( ... ) { }
   if ( ! ( new_flag && delete_flag ) ) abort();
   new_flag = delete_flag = false;

   try { new TwoWithSpec( true ); } catch ( ... ) { }
   if ( ! ( new_flag && delete_flag ) ) abort();
   new_flag = delete_flag = false;

   try { new BothNoSpec( true ); } catch ( ... ) { }
   if ( ! ( new_flag && delete_flag ) ) abort();
   new_flag = delete_flag = false;

   try { new BothWithSpec( true ); } catch ( ... ) { }
   if ( ! ( new_flag && delete_flag ) ) abort();
   new_flag = delete_flag = false;

   ArgType a;
   // placement new and explicit delete
   delete new( &a ) PlaceNoSpec;
   if ( ! ( new_flag && delete_flag && !delete_place_flag ) ) abort();
   new_flag = delete_flag = delete_place_flag = false;

   delete new( &a ) PlaceWithSpec;
   if ( ! ( new_flag && delete_flag && !delete_place_flag ) ) abort();
   new_flag = delete_flag = delete_place_flag = false;

   // placement new throwing
   try { new( &a ) PlaceNoSpec( true ); } catch ( ... ) { }
   if ( ! ( new_flag && delete_place_flag && !delete_flag ) ) abort();
   new_flag = delete_flag = delete_place_flag = false;

   try { new( &a ) PlaceWithSpec( true ); } catch ( ... ) { }
   if ( ! ( new_flag && delete_place_flag && !delete_flag ) ) abort();
   new_flag = delete_flag = delete_place_flag = false;
}



More information about the Gcc-patches mailing list