public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* C++ PATCH to clobber objects on constructor entry
@ 2015-04-15 21:15 Jason Merrill
  0 siblings, 0 replies; only message in thread
From: Jason Merrill @ 2015-04-15 21:15 UTC (permalink / raw)
  To: gcc-patches List

[-- Attachment #1: Type: text/plain, Size: 465 bytes --]

Currently we clobber objects at the end of the destructor to express 
that the language guarantees nothing about the state of storage after an 
object is destroyed.  The same is true at the other end: when a 
constructor begins the object has indeterminate value, so any stores to 
the underlying storage before that can be considered dead.  Like the 
destructor clobber, this can be disabled with -fno-lifetime-dse.

Tested x86_64-pc-linux-gnu, applying to trunk.

[-- Attachment #2: ctor-lifetime-dse.patch --]
[-- Type: text/x-patch, Size: 3554 bytes --]

commit b5ddc7d2b7bea43f0108e3eca1013ecec1ceda89
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Feb 10 23:49:14 2015 -0500

    	* 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.

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 2952cbe..1f9ba3e 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -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)
     {
@@ -2603,6 +2612,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,
@@ -2684,9 +2698,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);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 0538570..965f07c 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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
index 0000000..16d9a74
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/flifetime-dse2.C
@@ -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();
+}

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2015-04-15 21:15 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-04-15 21:15 C++ PATCH to clobber objects on constructor entry Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).