I noticed that -Wc++14-compat was warning about headers that had been updated to include a declaration of a global sized operator delete. This was intended to catch problematic placement deletes, but now I think that C++14 headers that just don't bother to guard the declaration with a C++14 #if are going to be much more common than placement deletes. So this patch changes the warning to only trigger if we actually use the operator delete as a placement delete.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 9b7c323b8806bb8d9c21a72ab074f7bc961840c9
Author: Jason Merrill <ja...@redhat.com>
Date:   Wed May 20 14:23:50 2015 -0400

    	* decl.c (grok_op_properties): Don't complain about size_t
    	placement delete here.
    	* call.c (second_parm_is_size_t): Split out from...
    	(non_placement_deallocation_fn_p): ...here.
    	(build_op_delete_call): Warn about size_t placement delete with
    	-Wc++14-compat.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 07ccea9..bad49f1 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5748,6 +5748,18 @@ build_new_op (location_t loc, enum tree_code code, int flags,
   return ret;
 }
 
+/* Returns true if FN has two parameters, of which the second has type
+   size_t.  */
+
+static bool
+second_parm_is_size_t (tree fn)
+{
+  tree t = FUNCTION_ARG_CHAIN (fn);
+  return (t
+	  && same_type_p (TREE_VALUE (t), size_type_node)
+	  && TREE_CHAIN (t) == void_list_node);
+}
+
 /* Returns true iff T, an element of an OVERLOAD chain, is a usual
    deallocation function (3.7.4.2 [basic.stc.dynamic.deallocation]).  */
 
@@ -5768,11 +5780,9 @@ non_placement_deallocation_fn_p (tree t)
      of which has type std::size_t (18.2), then this function is a usual
      deallocation function.  */
   bool global = DECL_NAMESPACE_SCOPE_P (t);
-  t = FUNCTION_ARG_CHAIN (t);
-  if (t == void_list_node
-      || (t && same_type_p (TREE_VALUE (t), size_type_node)
-	  && (!global || flag_sized_deallocation)
-	  && TREE_CHAIN (t) == void_list_node))
+  if (FUNCTION_ARG_CHAIN (t) == void_list_node
+      || ((!global || flag_sized_deallocation)
+	  && second_parm_is_size_t (t)))
     return true;
   return false;
 }
@@ -5859,23 +5869,49 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
 	 function (3.7.4.2) and that function, considered as a placement
 	 deallocation function, would have been selected as a match for the
 	 allocation function, the program is ill-formed."  */
-      if (non_placement_deallocation_fn_p (fn))
+      if (second_parm_is_size_t (fn))
 	{
+	  const char *msg1
+	    = G_("exception cleanup for this placement new selects "
+		 "non-placement operator delete");
+	  const char *msg2
+	    = G_("%q+D is a usual (non-placement) deallocation "
+		 "function in C++14 (or with -fsized-deallocation)");
+
 	  /* But if the class has an operator delete (void *), then that is
 	     the usual deallocation function, so we shouldn't complain
 	     about using the operator delete (void *, size_t).  */
-	  for (t = BASELINK_P (fns) ? BASELINK_FUNCTIONS (fns) : fns;
-	       t; t = OVL_NEXT (t))
+	  if (DECL_CLASS_SCOPE_P (fn))
+	    for (t = BASELINK_P (fns) ? BASELINK_FUNCTIONS (fns) : fns;
+		 t; t = OVL_NEXT (t))
+	      {
+		tree elt = OVL_CURRENT (t);
+		if (non_placement_deallocation_fn_p (elt)
+		    && FUNCTION_ARG_CHAIN (elt) == void_list_node)
+		  goto ok;
+	      }
+	  /* Before C++14 a two-parameter global deallocation function is
+	     always a placement deallocation function, but warn if
+	     -Wc++14-compat.  */
+	  else if (!flag_sized_deallocation)
 	    {
-	      tree elt = OVL_CURRENT (t);
-	      if (non_placement_deallocation_fn_p (elt)
-		  && FUNCTION_ARG_CHAIN (elt) == void_list_node)
-		goto ok;
+	      if ((complain & tf_warning)
+		  && warning (OPT_Wc__14_compat, msg1))
+		inform (0, msg2, fn);
+	      goto ok;
 	    }
-	  if (complain & tf_error)
+
+	  if (complain & tf_warning_or_error)
 	    {
-	      permerror (0, "non-placement deallocation function %q+D", fn);
-	      permerror (input_location, "selected for placement delete");
+	      if (permerror (input_location, msg1))
+		{
+		  /* Only mention C++14 for namespace-scope delete.  */
+		  if (DECL_NAMESPACE_SCOPE_P (fn))
+		    inform (0, msg2, fn);
+		  else
+		    inform (0, "%q+D is a usual (non-placement) deallocation "
+			    "function", fn);
+		}
 	    }
 	  else
 	    return error_mark_node;
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 261a12d..e4d3c1d 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -11767,16 +11767,6 @@ grok_op_properties (tree decl, bool complain)
 	      error ("%qD may not be declared as static", decl);
 	      return false;
 	    }
-	  if (!flag_sized_deallocation && warn_cxx14_compat)
-	    {
-	      tree parm = FUNCTION_ARG_CHAIN (decl);
-	      if (parm && same_type_p (TREE_VALUE (parm), size_type_node)
-		  && TREE_CHAIN (parm) == void_list_node)
-		warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc__14_compat,
-			    "%qD is a usual (non-placement) deallocation "
-			    "function in C++14 (or with -fsized-deallocation)",
-			    decl);
-	    }
 	}
     }
 
diff --git a/gcc/testsuite/g++.dg/cpp1y/sized-dealloc2.C b/gcc/testsuite/g++.dg/cpp1y/sized-dealloc2.C
index a3ab64c..0a76cdc 100644
--- a/gcc/testsuite/g++.dg/cpp1y/sized-dealloc2.C
+++ b/gcc/testsuite/g++.dg/cpp1y/sized-dealloc2.C
@@ -1,5 +1,26 @@
-// Test that -Wc++14-compat warns about the change in meaning.
-// { dg-options "-Wall" }
+// Test for a diagnostic about a usual deallocation function used as a
+// placement deallocation function.  This will be a warning in C++98/11
+// modes and an error in C++14 mode.
 
-typedef __SIZE_TYPE__ size_t;
-void operator delete[] (void *p, size_t s) throw(); // { dg-warning "usual" "" { target { ! c++14 } } }
+// { dg-options "-Wc++14-compat" }
+
+#include <new>
+void *operator new (std::size_t s, std::size_t)
+{
+  return operator new (s);
+}
+
+void operator delete (void *p, std::size_t) throw()
+{
+  return ::operator delete (p);
+}
+
+struct A
+{
+  A();
+};
+
+void f()
+{
+  new (42) A;		// { dg-message "" }
+}
diff --git a/gcc/testsuite/g++.dg/init/placement5.C b/gcc/testsuite/g++.dg/init/placement5.C
index 1d540da..c9f2ea5 100644
--- a/gcc/testsuite/g++.dg/init/placement5.C
+++ b/gcc/testsuite/g++.dg/init/placement5.C
@@ -13,7 +13,7 @@ struct A
 {
   A();
   void* operator new (size_t, size_t);
-  void operator delete (void *, size_t); // { dg-error "non-placement" }
+  void operator delete (void *, size_t); // { dg-message "non-placement" }
 };
 
 struct B
@@ -27,6 +27,6 @@ struct B
 
 int main()
 {
-  A* ap = new (24) A;		// { dg-error "placement delete" }
+  A* ap = new (24) A;		// { dg-error "placement" }
   B* bp = new (24) B;
 }

Reply via email to