diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index c25d360eaf0c0b3b887fb39be719b8836a0c4f43..042e637f8eac952fb13028dc6bb879ee864f6d19 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,10 @@
 2009-11-19  Jason Merrill  <jason@redhat.com>
 
+	PR c++/42115
+	* call.c (build_op_delete_call): Don't complain about using
+	op delete (void *, size_t) for placement delete if there's an
+	op delete (void *).
+
 	DR 176 permissiveness
 	* class.c (build_self_reference): Call set_underlying_type.
 	* decl.c (check_elaborated_type_specifier): Don't complain about
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index ca6bd0b74621e8e866d16fb63d68ea9d2389dbdc..3b3ccb66bad2c1d878132fd6ce1641b9cf969ee7 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -4622,8 +4622,20 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
 	 allocation function, the program is ill-formed."  */
       if (non_placement_deallocation_fn_p (fn))
 	{
+	  /* 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))
+	    {
+	      tree elt = OVL_CURRENT (t);
+	      if (non_placement_deallocation_fn_p (elt)
+		  && FUNCTION_ARG_CHAIN (elt) == void_list_node)
+		goto ok;
+	    }
 	  permerror (0, "non-placement deallocation function %q+D", fn);
 	  permerror (input_location, "selected for placement delete");
+	ok:;
 	}
     }
   else
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 5a56a9c5fbb34991faa0f0ed4e0a9da765ad3b57..ecebcb136a36eb6eb97c6259238971bd71d80435 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,8 @@
 2009-11-19  Jason Merrill  <jason@redhat.com>
 
+	PR c++/42115
+	* g++.dg/init/placement5.C: Add positive test.
+
 	DR 176 permissiveness
 	* g++.dg/ext/injected-ttp.C: New.
 	* g++.old-deja/g++.pt/niklas01a.C: Adjust.
diff --git a/gcc/testsuite/g++.dg/init/placement5.C b/gcc/testsuite/g++.dg/init/placement5.C
index bb882396cf889fc09e7f116b440ab7cd1c289142..1d540daca4329b34e0b36bf607ce819e81657443 100644
--- a/gcc/testsuite/g++.dg/init/placement5.C
+++ b/gcc/testsuite/g++.dg/init/placement5.C
@@ -3,16 +3,30 @@
 // placement deallocation function, would have been selected as a match for
 // the allocation function, the program is ill-formed.
 
+// But we should only complain about using op delete (void *, size_t) for
+// placement delete if it would also be selected for normal delete, not if
+// there's also an op delete (void *).
+
 typedef __SIZE_TYPE__ size_t;
 
 struct A
 {
   A();
-  static void* operator new (size_t, size_t);
-  static void operator delete (void *, size_t); // { dg-error "non-placement" }
+  void* operator new (size_t, size_t);
+  void operator delete (void *, size_t); // { dg-error "non-placement" }
+};
+
+struct B
+{
+  B();
+  void * operator new (size_t);
+  void * operator new (size_t, size_t);
+  void operator delete (void *);
+  void operator delete (void *, size_t);
 };
 
 int main()
 {
   A* ap = new (24) A;		// { dg-error "placement delete" }
+  B* bp = new (24) B;
 }