Hi,

On 24/01/19 23:21, Jason Merrill wrote:
On 1/24/19 2:53 PM, Paolo Carlini wrote:
Hi,

as far as I can see this ICE on invalid points to a substantive, if minor, weakness of our implementation of the destroying operator delete facility: we aren't implementing the bits, per 7.6.2.5/(10.1), about destroying operator delete having precedence over any other operator delete. Thus the below, which is the most straightforward implementation I have been able to figure out given the current infrastructure. Tested x86_64-linux.

OK, thanks.

Thanks you.

Yesterday I didn't notice that the bug report includes another testcase, for an unrelated buglet: if the destroying operator delete is wrongly specified as not-taking a pointer to the class type as first argument, TYPE_POINTER_TO may not be set yet in coerce_delete_type and we crash later on. Thus the below, which changes it to build_pointer_type.

Thanks, Paolo.

//////////////////////////

/cp
2019-01-25  Paolo Carlini  <paolo.carl...@oracle.com>

        PR c++/88969
        * call.c (build_op_delete_call): Implement 7.6.2.5/(10.1).
        * decl2.c (coerce_delete_type): Use build_pointer_type instead
        of TYPE_POINTER_TO.

/testsuite
2019-01-25  Paolo Carlini  <paolo.carl...@oracle.com>

        PR c++/88969
        * g++.dg/cpp2a/destroying-delete2.C: New.
        * g++.dg/cpp2a/destroying-delete3.C: Likewise.
Index: cp/call.c
===================================================================
--- cp/call.c   (revision 268257)
+++ cp/call.c   (working copy)
@@ -6461,6 +6461,19 @@ build_op_delete_call (enum tree_code code, tree ad
                continue;
              }
 
+           /* -- If any of the deallocation functions is a destroying
+              operator delete, all deallocation functions that are not
+              destroying operator deletes are eliminated from further
+              consideration.  */
+           bool fn_destroying = destroying_delete_p (fn);
+           bool elt_destroying = destroying_delete_p (elt);
+           if (elt_destroying != fn_destroying)
+             {
+               if (elt_destroying)
+                 fn = elt;
+               continue;
+             }
+
            /* -- If the type has new-extended alignment, a function with a
               parameter of type std::align_val_t is preferred; otherwise a
               function without such a parameter is preferred. If exactly one
Index: cp/decl2.c
===================================================================
--- cp/decl2.c  (revision 268257)
+++ cp/decl2.c  (working copy)
@@ -1757,9 +1757,9 @@ coerce_delete_type (tree decl, location_t loc)
   if (destroying_delete_p (decl))
     {
       if (DECL_CLASS_SCOPE_P (decl))
-       /* If the function is a destroying operator delete declared in class 
type
-          C, the type of its first parameter shall be C*.  */
-       ptrtype = TYPE_POINTER_TO (DECL_CONTEXT (decl));
+       /* If the function is a destroying operator delete declared in class
+          type C, the type of its first parameter shall be C*.  */
+       ptrtype = build_pointer_type (DECL_CONTEXT (decl));
       else
        /* A destroying operator delete shall be a class member function named
           operator delete.  */
Index: testsuite/g++.dg/cpp2a/destroying-delete2.C
===================================================================
--- testsuite/g++.dg/cpp2a/destroying-delete2.C (nonexistent)
+++ testsuite/g++.dg/cpp2a/destroying-delete2.C (working copy)
@@ -0,0 +1,20 @@
+// PR c++/88969
+// { dg-do compile { target c++2a } }
+
+#include <new>
+
+namespace delete_selection_d {
+  struct B {
+    void operator delete(void*) = delete;
+    void operator delete(B *, std::destroying_delete_t) = delete;  // { 
dg-message "declared here" }
+  };
+  void delete_B(B *b) { delete b; }  // { dg-error "use of deleted function" }
+}
+
+namespace delete_selection_r {
+  struct B {
+    void operator delete(B *, std::destroying_delete_t) = delete;  // { 
dg-message "declared here" }
+    void operator delete(void*) = delete;
+  };
+  void delete_B(B *b) { delete b; }  // { dg-error "use of deleted function" }
+}
Index: testsuite/g++.dg/cpp2a/destroying-delete3.C
===================================================================
--- testsuite/g++.dg/cpp2a/destroying-delete3.C (nonexistent)
+++ testsuite/g++.dg/cpp2a/destroying-delete3.C (working copy)
@@ -0,0 +1,8 @@
+// PR c++/88969
+// { dg-do compile { target c++2a } }
+
+#include <new>
+
+struct B {
+  void operator delete(void*, std::destroying_delete_t);  // { dg-error 
".operator delete. takes type .B*." }
+};

Reply via email to