c++: Pseudo-destructor ends object lifetime.
authorJason Merrill <jason@redhat.com>
Sun, 12 Jul 2020 21:31:24 +0000 (17:31 -0400)
committerJason Merrill <jason@redhat.com>
Mon, 20 Jul 2020 22:18:12 +0000 (18:18 -0400)
P0593R6 is mostly about a new object model whereby malloc and the like are
treated as implicitly starting the lifetime of whatever trivial types are
necessary to give the program well-defined semantics; that seems only
relevant to TBAA, and is not implemented here.

The paper also specifies that a pseudo-destructor call (a destructor call
for a non-class type) ends the lifetime of the object like a destructor call
for an object of class type, even though it doesn't call a destructor; this
patch implements that change.

The paper was voted as a DR, so I'm applying this change to all standard
levels.  Like class end-of-life clobbers, it is controlled by
-flifetime-dse.

gcc/cp/ChangeLog:

* pt.c (type_dependent_expression_p): A pseudo-dtor can be
dependent.
* semantics.c (finish_call_expr): Use build_trivial_dtor_call for
pseudo-destructor.
(finish_pseudo_destructor_expr): Leave type NULL for dependent arg.

gcc/testsuite/ChangeLog:

* g++.dg/opt/flifetime-dse7.C: New test.

gcc/cp/pt.c
gcc/cp/semantics.c
gcc/testsuite/g++.dg/opt/flifetime-dse7.C [new file with mode: 0644]

index cfe5dcd59cf11f9aa1c8af7a4af79341f5ee84cc..f9e80e5a1c37966bcd6c4b9b40eea5cd82065bc6 100644 (file)
@@ -26729,8 +26729,7 @@ type_dependent_expression_p (tree expression)
     return true;
 
   /* Some expression forms are never type-dependent.  */
-  if (TREE_CODE (expression) == PSEUDO_DTOR_EXPR
-      || TREE_CODE (expression) == SIZEOF_EXPR
+  if (TREE_CODE (expression) == SIZEOF_EXPR
       || TREE_CODE (expression) == ALIGNOF_EXPR
       || TREE_CODE (expression) == AT_ENCODE_EXPR
       || TREE_CODE (expression) == NOEXCEPT_EXPR
index 4a3ef3d28393597934e4603ec82a5d0869e108b7..3096fe834336fc86acaece27328136d3f23ddf1e 100644 (file)
@@ -2707,12 +2707,16 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
     {
       if (!vec_safe_is_empty (*args))
        error ("arguments to destructor are not allowed");
-      /* Mark the pseudo-destructor call as having side-effects so
-        that we do not issue warnings about its use.  */
-      result = build1 (NOP_EXPR,
-                      void_type_node,
-                      TREE_OPERAND (fn, 0));
-      TREE_SIDE_EFFECTS (result) = 1;
+      /* C++20/DR: If the postfix-expression names a pseudo-destructor (in
+        which case the postfix-expression is a possibly-parenthesized class
+        member access), the function call destroys the object of scalar type
+        denoted by the object expression of the class member access.  */
+      tree ob = TREE_OPERAND (fn, 0);
+      if (obvalue_p (ob))
+       result = build_trivial_dtor_call (ob);
+      else
+       /* No location to clobber.  */
+       result = convert_to_void (ob, ICV_STATEMENT, complain);
     }
   else if (CLASS_TYPE_P (TREE_TYPE (fn)))
     /* If the "function" is really an object of class type, it might
@@ -2845,7 +2849,10 @@ finish_pseudo_destructor_expr (tree object, tree scope, tree destructor,
        }
     }
 
-  return build3_loc (loc, PSEUDO_DTOR_EXPR, void_type_node, object,
+  tree type = (type_dependent_expression_p (object)
+              ? NULL_TREE : void_type_node);
+
+  return build3_loc (loc, PSEUDO_DTOR_EXPR, type, object,
                     scope, destructor);
 }
 
diff --git a/gcc/testsuite/g++.dg/opt/flifetime-dse7.C b/gcc/testsuite/g++.dg/opt/flifetime-dse7.C
new file mode 100644 (file)
index 0000000..4fe1eb0
--- /dev/null
@@ -0,0 +1,16 @@
+// { dg-options "-O3 -flifetime-dse" }
+// { dg-do run }
+
+template <class T>
+void f()
+{
+  T t = 42;
+  t.~T();
+  if (t == 42) __builtin_abort();
+}
+
+int main()
+{
+  f<int>();
+}
+