PR c++/68782
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 26 Jan 2016 21:34:10 +0000 (21:34 +0000)
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 26 Jan 2016 21:34:10 +0000 (21:34 +0000)
gcc/
* tree.c (recompute_constructor_flags): Split out from
build_constructor.
(verify_constructor_flags): New.
* tree.h: Declare them.
gcc/cp/
* constexpr.c (cxx_eval_bare_aggregate): Update TREE_CONSTANT
and TREE_SIDE_EFFECTS.
(cxx_eval_constant_expression) [CONSTRUCTOR]: Call
verify_constructor_flags.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@232847 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/testsuite/g++.dg/cpp0x/constexpr-aggr2.C [new file with mode: 0644]
gcc/tree.c
gcc/tree.h

index e94010a..043dd88 100644 (file)
@@ -1,3 +1,11 @@
+2016-01-26  Jason Merrill  <jason@redhat.com>
+
+       PR c++/68782
+       * tree.c (recompute_constructor_flags): Split out from
+       build_constructor.
+       (verify_constructor_flags): New.
+       * tree.h: Declare them.
+
 2016-01-26  Iain Buclaw  <ibuclaw@gdcproject.org>
 
        PR rtl-optimization/69217
index 3d7824c..dee9e4d 100644 (file)
@@ -1,3 +1,11 @@
+2016-01-26  Jason Merrill  <jason@redhat.com>
+
+       PR c++/68782
+       * constexpr.c (cxx_eval_bare_aggregate): Update TREE_CONSTANT
+       and TREE_SIDE_EFFECTS.
+       (cxx_eval_constant_expression) [CONSTRUCTOR]: Call
+       verify_constructor_flags.
+
 2016-01-26  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/68357
index 6b0e5a8..eed7308 100644 (file)
@@ -2214,7 +2214,10 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
   vec<constructor_elt, va_gc> **p = &CONSTRUCTOR_ELTS (ctx->ctor);
   vec_alloc (*p, vec_safe_length (v));
 
-  unsigned i; tree index, value;
+  unsigned i;
+  tree index, value;
+  bool constant_p = true;
+  bool side_effects_p = false;
   FOR_EACH_CONSTRUCTOR_ELT (v, i, index, value)
     {
       constexpr_ctx new_ctx;
@@ -2231,6 +2234,11 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
        break;
       if (elt != value)
        changed = true;
+
+      if (!TREE_CONSTANT (elt))
+       constant_p = false;
+      if (TREE_SIDE_EFFECTS (elt))
+       side_effects_p = true;
       if (index && TREE_CODE (index) == COMPONENT_REF)
        {
          /* This is an initialization of a vfield inside a base
@@ -2264,6 +2272,8 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
   /* We're done building this CONSTRUCTOR, so now we can interpret an
      element without an explicit initializer as value-initialized.  */
   CONSTRUCTOR_NO_IMPLICIT_ZERO (t) = false;
+  TREE_CONSTANT (t) = constant_p;
+  TREE_SIDE_EFFECTS (t) = side_effects_p;
   if (VECTOR_TYPE_P (TREE_TYPE (t)))
     t = fold (t);
   return t;
@@ -2826,6 +2836,8 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
     }
   type = TREE_TYPE (object);
   bool no_zero_init = true;
+
+  vec<tree,va_gc> *ctors = make_tree_vector ();
   while (!refs->is_empty())
     {
       if (*valp == NULL_TREE)
@@ -2837,6 +2849,8 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
         subobjects will also be zero-initialized.  */
       no_zero_init = CONSTRUCTOR_NO_IMPLICIT_ZERO (*valp);
 
+      vec_safe_push (ctors, *valp);
+
       enum tree_code code = TREE_CODE (type);
       type = refs->pop();
       tree index = refs->pop();
@@ -2889,14 +2903,36 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
       /* The hash table might have moved since the get earlier.  */
       valp = ctx->values->get (object);
       if (TREE_CODE (init) == CONSTRUCTOR)
-       /* An outer ctx->ctor might be pointing to *valp, so just replace
-          its contents.  */
-       CONSTRUCTOR_ELTS (*valp) = CONSTRUCTOR_ELTS (init);
+       {
+         /* An outer ctx->ctor might be pointing to *valp, so replace
+            its contents.  */
+         CONSTRUCTOR_ELTS (*valp) = CONSTRUCTOR_ELTS (init);
+         TREE_CONSTANT (*valp) = TREE_CONSTANT (init);
+         TREE_SIDE_EFFECTS (*valp) = TREE_SIDE_EFFECTS (init);
+       }
       else
        *valp = init;
     }
   else
-    *valp = init;
+    {
+      *valp = init;
+
+      /* Update TREE_CONSTANT and TREE_SIDE_EFFECTS on enclosing
+        CONSTRUCTORs.  */
+      tree elt;
+      unsigned i;
+      bool c = TREE_CONSTANT (init);
+      bool s = TREE_SIDE_EFFECTS (init);
+      if (!c || s)
+       FOR_EACH_VEC_SAFE_ELT (ctors, i, elt)
+         {
+           if (!c)
+             TREE_CONSTANT (elt) = false;
+           if (s)
+             TREE_SIDE_EFFECTS (elt) = true;
+         }
+    }
+  release_tree_vector (ctors);
 
   if (*non_constant_p)
     return t;
@@ -3579,9 +3615,17 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 
     case CONSTRUCTOR:
       if (TREE_CONSTANT (t))
-       /* Don't re-process a constant CONSTRUCTOR, but do fold it to
-          VECTOR_CST if applicable.  */
-       return fold (t);
+       {
+         /* Don't re-process a constant CONSTRUCTOR, but do fold it to
+            VECTOR_CST if applicable.  */
+         /* FIXME after GCC 6 branches, make the verify unconditional.  */
+         if (CHECKING_P)
+           verify_constructor_flags (t);
+         else
+           recompute_constructor_flags (t);
+         if (TREE_CONSTANT (t))
+           return fold (t);
+       }
       r = cxx_eval_bare_aggregate (ctx, t, lval,
                                   non_constant_p, overflow_p);
       break;
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-aggr2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-aggr2.C
new file mode 100644 (file)
index 0000000..805d026
--- /dev/null
@@ -0,0 +1,27 @@
+// PR c++/68782
+// { dg-do compile { target c++11 } }
+
+#define assert(X) do { if (!(X)) __builtin_abort(); } while (0)
+
+struct holder { int& value; };
+
+constexpr holder from_value(int& value)
+{ return { value }; }
+
+struct aggr { int i; };
+
+constexpr holder from_aggr(aggr& a)
+{ return from_value(a.i); }
+
+int main()
+{
+    aggr a { 42 };
+
+    // these don't fire
+    assert( &from_value(a.i).value != nullptr );
+    assert( &a.i == &from_value(a.i).value );
+
+    // those do
+    assert( &from_aggr(a).value != nullptr );
+    assert( &a.i == &from_aggr(a).value );
+}
index 9c67bea..fa7646b 100644 (file)
@@ -1790,34 +1790,66 @@ build_vector_from_val (tree vectype, tree sc)
     }
 }
 
-/* Return a new CONSTRUCTOR node whose type is TYPE and whose values
-   are in the vec pointed to by VALS.  */
-tree
-build_constructor (tree type, vec<constructor_elt, va_gc> *vals)
+/* Something has messed with the elements of CONSTRUCTOR C after it was built;
+   calculate TREE_CONSTANT and TREE_SIDE_EFFECTS.  */
+
+void
+recompute_constructor_flags (tree c)
 {
-  tree c = make_node (CONSTRUCTOR);
   unsigned int i;
-  constructor_elt *elt;
+  tree val;
   bool constant_p = true;
   bool side_effects_p = false;
+  vec<constructor_elt, va_gc> *vals = CONSTRUCTOR_ELTS (c);
 
-  TREE_TYPE (c) = type;
-  CONSTRUCTOR_ELTS (c) = vals;
-
-  FOR_EACH_VEC_SAFE_ELT (vals, i, elt)
+  FOR_EACH_CONSTRUCTOR_VALUE (vals, i, val)
     {
       /* Mostly ctors will have elts that don't have side-effects, so
         the usual case is to scan all the elements.  Hence a single
         loop for both const and side effects, rather than one loop
         each (with early outs).  */
-      if (!TREE_CONSTANT (elt->value))
+      if (!TREE_CONSTANT (val))
        constant_p = false;
-      if (TREE_SIDE_EFFECTS (elt->value))
+      if (TREE_SIDE_EFFECTS (val))
        side_effects_p = true;
     }
 
   TREE_SIDE_EFFECTS (c) = side_effects_p;
   TREE_CONSTANT (c) = constant_p;
+}
+
+/* Make sure that TREE_CONSTANT and TREE_SIDE_EFFECTS are correct for
+   CONSTRUCTOR C.  */
+
+void
+verify_constructor_flags (tree c)
+{
+  unsigned int i;
+  tree val;
+  bool constant_p = TREE_CONSTANT (c);
+  bool side_effects_p = TREE_SIDE_EFFECTS (c);
+  vec<constructor_elt, va_gc> *vals = CONSTRUCTOR_ELTS (c);
+
+  FOR_EACH_CONSTRUCTOR_VALUE (vals, i, val)
+    {
+      if (constant_p && !TREE_CONSTANT (val))
+       internal_error ("non-constant element in constant CONSTRUCTOR");
+      if (!side_effects_p && TREE_SIDE_EFFECTS (val))
+       internal_error ("side-effects element in no-side-effects CONSTRUCTOR");
+    }
+}
+
+/* Return a new CONSTRUCTOR node whose type is TYPE and whose values
+   are in the vec pointed to by VALS.  */
+tree
+build_constructor (tree type, vec<constructor_elt, va_gc> *vals)
+{
+  tree c = make_node (CONSTRUCTOR);
+
+  TREE_TYPE (c) = type;
+  CONSTRUCTOR_ELTS (c) = vals;
+
+  recompute_constructor_flags (c);
 
   return c;
 }
index 9b987bb..f789785 100644 (file)
@@ -3918,6 +3918,8 @@ extern tree build_vector_stat (tree, tree * MEM_STAT_DECL);
 #define build_vector(t,v) build_vector_stat (t, v MEM_STAT_INFO)
 extern tree build_vector_from_ctor (tree, vec<constructor_elt, va_gc> *);
 extern tree build_vector_from_val (tree, tree);
+extern void recompute_constructor_flags (tree);
+extern void verify_constructor_flags (tree);
 extern tree build_constructor (tree, vec<constructor_elt, va_gc> *);
 extern tree build_constructor_single (tree, tree, tree);
 extern tree build_constructor_from_list (tree, tree);