constexpr.c (cxx_eval_store_expression): Ignore clobbers.
authorJason Merrill <jason@redhat.com>
Wed, 15 Apr 2015 21:17:29 +0000 (17:17 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 15 Apr 2015 21:17:29 +0000 (17:17 -0400)
* constexpr.c (cxx_eval_store_expression): Ignore clobbers.
(build_constexpr_constructor_member_initializers): Loop to find
the BIND_EXPR.
* decl.c (start_preparsed_function): Clobber the object at the
beginning of a constructor.

From-SVN: r222135

gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/cp/decl.c
gcc/testsuite/g++.dg/opt/flifetime-dse2.C [new file with mode: 0644]

index b18c2fb311ef6432711796becff6d4ceabf78031..bbfba2b1dfe22314c7f4c5a793afc7c9ef5864fd 100644 (file)
@@ -1,5 +1,11 @@
 2015-04-15  Jason Merrill  <jason@redhat.com>
 
+       * constexpr.c (cxx_eval_store_expression): Ignore clobbers.
+       (build_constexpr_constructor_member_initializers): Loop to find
+       the BIND_EXPR.
+       * decl.c (start_preparsed_function): Clobber the object at the
+       beginning of a constructor.
+
        * decl.c (grokmethod): Only set DECL_COMDAT if TREE_PUBLIC is set.
        * method.c (implicitly_declare_fn): Likewise.
        * decl2.c (vague_linkage_p): Check TREE_PUBLIC first.
index 60f0a790f858fe6d45db3f5d25b447da7dedb3b8..2990519b4bc0626266bc4c13cf1d3f9d40dc403f 100644 (file)
@@ -543,7 +543,16 @@ build_constexpr_constructor_member_initializers (tree type, tree body)
       || TREE_CODE (body) == EH_SPEC_BLOCK)
     body = TREE_OPERAND (body, 0);
   if (TREE_CODE (body) == STATEMENT_LIST)
-    body = STATEMENT_LIST_HEAD (body)->stmt;
+    {
+      tree_stmt_iterator i = tsi_start (body);
+      while (true)
+       {
+         body = tsi_stmt (i);
+         if (TREE_CODE (body) == BIND_EXPR)
+           break;
+         tsi_next (&i);
+       }
+    }
   body = BIND_EXPR_BODY (body);
   if (TREE_CODE (body) == CLEANUP_POINT_EXPR)
     {
@@ -2552,6 +2561,11 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
 {
   constexpr_ctx new_ctx = *ctx;
 
+  tree init = TREE_OPERAND (t, 1);
+  if (TREE_CLOBBER_P (init))
+    /* Just ignore clobbers.  */
+    return void_node;
+
   /* First we figure out where we're storing to.  */
   tree target = TREE_OPERAND (t, 0);
   target = cxx_eval_constant_expression (ctx, target,
@@ -2633,9 +2647,8 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
       new_ctx.object = target;
     }
 
-  tree init = cxx_eval_constant_expression (&new_ctx, TREE_OPERAND (t, 1),
-                                           false,
-                                           non_constant_p, overflow_p);
+  init = cxx_eval_constant_expression (&new_ctx, init, false,
+                                      non_constant_p, overflow_p);
   if (target == object)
     /* The hash table might have moved since the get earlier.  */
     ctx->values->put (object, init);
index 05385702978857c9f5e54b6409a0314912b8fc94..965f07cfbd79437a3315ebd468b86c69fab01d89 100644 (file)
@@ -13708,6 +13708,20 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
 
   store_parm_decls (current_function_parms);
 
+  if (!processing_template_decl
+      && flag_lifetime_dse && DECL_CONSTRUCTOR_P (decl1))
+    {
+      /* Insert a clobber to let the back end know that the object storage
+        is dead when we enter the constructor.  */
+      tree btype = CLASSTYPE_AS_BASE (current_class_type);
+      tree clobber = build_constructor (btype, NULL);
+      TREE_THIS_VOLATILE (clobber) = true;
+      tree bref = build_nop (build_reference_type (btype), current_class_ptr);
+      bref = convert_from_reference (bref);
+      tree exprstmt = build2 (MODIFY_EXPR, btype, bref, clobber);
+      finish_expr_stmt (exprstmt);
+    }
+
   return true;
 }
 
diff --git a/gcc/testsuite/g++.dg/opt/flifetime-dse2.C b/gcc/testsuite/g++.dg/opt/flifetime-dse2.C
new file mode 100644 (file)
index 0000000..16d9a74
--- /dev/null
@@ -0,0 +1,27 @@
+// { dg-options "-O3 -flifetime-dse" }
+// { dg-do run }
+
+typedef __SIZE_TYPE__ size_t;
+inline void * operator new (size_t, void *p) { return p; }
+
+struct A
+{
+  int i;
+  A() {}
+  ~A() {}
+};
+
+int main()
+{
+  int ar[1] = { 42 };
+  A* ap = new(ar) A;
+
+  // When the constructor starts the object has indeterminate value.
+  if (ap->i == 42) __builtin_abort();
+
+  ap->i = 42;
+  ap->~A();
+
+  // When the destructor ends the object no longer exists.
+  if (ar[0] == 42) __builtin_abort();
+}