From: Mark Mitchell <mark@codesourcery.com>
Date: Wed, 14 Feb 2001 06:32:15 +0000 (+0000)
Subject: cp-tree.h (CLASSTYPE_DESTRUCTORS): Fix typo in comment.
X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=52682a1b7720c9f2d8528c3498631636f09ebd90;p=gcc.git

cp-tree.h (CLASSTYPE_DESTRUCTORS): Fix typo in comment.

	* cp-tree.h (CLASSTYPE_DESTRUCTORS): Fix typo in comment.
	* call.c (build_op_delete_call): Simplify to remove duplicate
	code.
	* class.c (clone_function_decl): Don't build the deleting variant
	of a non-virtual destructor.
	* decl.c (finish_destructor_body): Don't call delete if this is a
	non-virtual destructor.
	* init.c (build_delete): Explicitly call `operator delete' when
	deleting an object with a non-virtual destructor.

From-SVN: r39659
---

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 64deaaf338a..4dad89821ba 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,15 @@
+2001-02-13  Mark Mitchell  <mark@codesourcery.com>
+
+	* cp-tree.h (CLASSTYPE_DESTRUCTORS): Fix typo in comment.
+	* call.c (build_op_delete_call): Simplify to remove duplicate
+	code.
+	* class.c (clone_function_decl): Don't build the deleting variant
+	of a non-virtual destructor.
+	* decl.c (finish_destructor_body): Don't call delete if this is a
+	non-virtual destructor.
+	* init.c (build_delete): Explicitly call `operator delete' when
+	deleting an object with a non-virtual destructor.
+	
 2001-02-13  Jason Merrill  <jason@redhat.com>
 
 	* lang-specs.h: Add more __EXCEPTIONS.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 7cb34bd1724..11cb6404054 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -3547,6 +3547,7 @@ build_op_delete_call (code, addr, size, flags, placement)
      int flags;
 {
   tree fn, fns, fnname, fntype, argtypes, args, type;
+  int pass;
 
   if (addr == error_mark_node)
     return error_mark_node;
@@ -3595,48 +3596,45 @@ build_op_delete_call (code, addr, size, flags, placement)
       args = NULL_TREE;
     }
 
-  argtypes = tree_cons (NULL_TREE, ptr_type_node, argtypes);
-  fntype = build_function_type (void_type_node, argtypes);
-
   /* Strip const and volatile from addr.  */
   addr = cp_convert (ptr_type_node, addr);
 
-  fn = instantiate_type (fntype, fns, itf_no_attributes);
-
-  if (fn != error_mark_node)
+  /* We make two tries at finding a matching `operator delete'.  On
+     the first pass, we look for an one-operator (or placement)
+     operator delete.  If we're not doing placement delete, then on
+     the second pass we look for a two-argument delete.  */
+  for (pass = 0; pass < (placement ? 1 : 2); ++pass) 
     {
-      if (TREE_CODE (fns) == TREE_LIST)
-	/* Member functions.  */
-	enforce_access (type, fn);
-      return build_function_call (fn, tree_cons (NULL_TREE, addr, args));
-    }
-
-  /* If we are doing placement delete we do nothing if we don't find a
-     matching op delete.  */
-  if (placement)
-    return NULL_TREE;
+      if (pass == 0)
+	argtypes = tree_cons (NULL_TREE, ptr_type_node, argtypes);
+      else 
+	/* Normal delete; now try to find a match including the size
+	   argument.  */
+	argtypes = tree_cons (NULL_TREE, ptr_type_node,
+			      tree_cons (NULL_TREE, sizetype, 
+					 void_list_node));
 
-  /* Normal delete; now try to find a match including the size argument.  */
-  argtypes = tree_cons (NULL_TREE, ptr_type_node,
-			tree_cons (NULL_TREE, sizetype, void_list_node));
-  fntype = build_function_type (void_type_node, argtypes);
+      fntype = build_function_type (void_type_node, argtypes);
+      fn = instantiate_type (fntype, fns, itf_no_attributes);
 
-  fn = instantiate_type (fntype, fns, itf_no_attributes);
+      if (fn != error_mark_node)
+	{
+	  /* Member functions.  */
+	  if (BASELINK_P (fns))
+	    enforce_access (type, fn);
 
-  if (fn != error_mark_node)
-    {
-      if (BASELINK_P (fns))
-	/* Member functions.  */
-	enforce_access (type, fn);
-      return build_function_call
-	(fn, tree_cons (NULL_TREE, addr,
-			build_tree_list (NULL_TREE, size)));
+	  if (pass == 0)
+	    args = tree_cons (NULL_TREE, addr, args);
+	  else
+	    args = tree_cons (NULL_TREE, addr, 
+			      build_tree_list (NULL_TREE, size));
+	  return build_function_call (fn, args);
+	}
     }
 
-  /* finish_function passes LOOKUP_SPECULATIVELY if we're in a
-     destructor, in which case the error should be deferred
-     until someone actually tries to delete one of these.  */
-  if (flags & LOOKUP_SPECULATIVELY)
+  /* If we are doing placement delete we do nothing if we don't find a
+     matching op delete.  */
+  if (placement)
     return NULL_TREE;
 
   cp_error ("no suitable `operator delete' for `%T'", type);
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 3f50da33108..2d8ab83dee2 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -4319,10 +4319,16 @@ clone_function_decl (fn, update_method_vec_p)
 	 version.  We clone the deleting version first because that
 	 means it will go second on the TYPE_METHODS list -- and that
 	 corresponds to the correct layout order in the virtual
-	 function table.  */
-      clone = build_clone (fn, deleting_dtor_identifier);
-      if (update_method_vec_p)
-	add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
+	 function table.  
+
+         For a non-virtual destructor, we do not build a deleting
+	 destructor.  */
+      if (DECL_VIRTUAL_P (fn))
+	{
+	  clone = build_clone (fn, deleting_dtor_identifier);
+	  if (update_method_vec_p)
+	    add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
+	}
       clone = build_clone (fn, complete_dtor_identifier);
       if (update_method_vec_p)
 	add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index eb7afc04ff5..7881429dadf 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1456,7 +1456,7 @@ struct lang_type
 #define CLASSTYPE_CONSTRUCTORS(NODE) \
   (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (NODE), CLASSTYPE_CONSTRUCTOR_SLOT))
 
-/* A FUNCTION_DECL for the destructor for NODE.  These are te
+/* A FUNCTION_DECL for the destructor for NODE.  These are the
    destructors that take an in-charge parameter.  */
 #define CLASSTYPE_DESTRUCTORS(NODE) \
   (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (NODE), CLASSTYPE_DESTRUCTOR_SLOT))
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index ead15dbdd76..3e3f37be89d 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -13730,9 +13730,7 @@ static void
 finish_destructor_body ()
 {
   tree compound_stmt;
-  tree virtual_size;
   tree exprstmt;
-  tree if_stmt;
 
   /* Create a block to contain all the extra code.  */
   compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
@@ -13814,31 +13812,31 @@ finish_destructor_body ()
 	}
     }
 
-  virtual_size = c_sizeof (current_class_type);
-
-  /* At the end, call delete if that's what's requested.  */
+  /* In a virtual destructor, we must call delete.  */
+  if (DECL_VIRTUAL_P (current_function_decl))
+    {
+      tree if_stmt;
+      tree virtual_size = c_sizeof (current_class_type);
 
-  /* FDIS sez: At the point of definition of a virtual destructor
-     (including an implicit definition), non-placement operator delete
-     shall be looked up in the scope of the destructor's class and if
-     found shall be accessible and unambiguous.
+      /* [class.dtor]
 
-     This is somewhat unclear, but I take it to mean that if the class
-     only defines placement deletes we don't do anything here.  So we
-     pass LOOKUP_SPECULATIVELY; delete_sanity will complain for us if
-     they ever try to delete one of these.  */
-  exprstmt = build_op_delete_call
-    (DELETE_EXPR, current_class_ptr, virtual_size,
-     LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE);
+	 At the point of definition of a virtual destructor (including
+	 an implicit definition), non-placement operator delete shall
+	 be looked up in the scope of the destructor's class and if
+	 found shall be accessible and unambiguous.  */
+      exprstmt = build_op_delete_call
+	(DELETE_EXPR, current_class_ptr, virtual_size,
+	 LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE);
 
-  if_stmt = begin_if_stmt ();
-  finish_if_stmt_cond (build (BIT_AND_EXPR, integer_type_node,
-			      current_in_charge_parm,
-			      integer_one_node),
-		       if_stmt);
-  finish_expr_stmt (exprstmt);
-  finish_then_clause (if_stmt);
-  finish_if_stmt ();
+      if_stmt = begin_if_stmt ();
+      finish_if_stmt_cond (build (BIT_AND_EXPR, integer_type_node,
+				  current_in_charge_parm,
+				  integer_one_node),
+			   if_stmt);
+      finish_expr_stmt (exprstmt);
+      finish_then_clause (if_stmt);
+      finish_if_stmt ();
+    }
 
   /* Close the block we started above.  */
   finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 4e68b645b73..becb347bc96 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -3235,6 +3235,9 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
       tree do_delete = NULL_TREE;
       tree ifexp;
 
+      /* For `::delete x', we must not use the deleting destructor
+	 since then we would not be sure to get the global `operator
+	 delete'.  */
       if (use_global_delete && auto_delete == sfk_deleting_destructor)
 	{
 	  /* Delete the object. */
@@ -3243,6 +3246,21 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
 	     call.  */
 	  auto_delete = sfk_complete_destructor;
 	}
+      /* If the destructor is non-virtual, there is no deleting
+	 variant.  Instead, we must explicitly call the appropriate
+	 `operator delete' here.  */
+      else if (!DECL_VIRTUAL_P (CLASSTYPE_DESTRUCTORS (type))
+	       && auto_delete == sfk_deleting_destructor)
+	{
+	  /* Buidl the call.  */
+	  do_delete = build_op_delete_call (DELETE_EXPR,
+					    addr,
+					    c_sizeof_nowarn (type),
+					    LOOKUP_NORMAL,
+					    NULL_TREE);
+	  /* Call the complete object destructor.  */
+	  auto_delete = sfk_complete_destructor;
+	}
 
       expr = build_dtor_call (ref, auto_delete, flags);
       if (do_delete)
diff --git a/gcc/testsuite/g++.old-deja/g++.oliva/delete1.C b/gcc/testsuite/g++.old-deja/g++.oliva/delete1.C
index dee7f219f2e..d8ddefec32e 100644
--- a/gcc/testsuite/g++.old-deja/g++.oliva/delete1.C
+++ b/gcc/testsuite/g++.old-deja/g++.oliva/delete1.C
@@ -1,6 +1,6 @@
 // Build don't link:
 
-// Copyright (C) 1999 Free Software Foundation
+// Copyright (C) 1999, 2001 Free Software Foundation
 
 // by Alexandre Oliva <oliva@dcc.unicamp.br>
 // simplified from bug report by K. Haley <khaley@bigfoot.com>
@@ -21,7 +21,7 @@ struct bar : foo {
     delete this; // ERROR - delete is private
     // An implicit invocation of delete is emitted in destructors, but
     // it should only be checked in virtual destructors
-  } // gets bogus error - not virtual - XFAIL *-*-*
+  } // gets bogus error - not virtual
 } bar_;
 
 struct baz : foo {