+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
+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
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;
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
/* 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;
}
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)
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();
/* 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;
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;
--- /dev/null
+// 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 );
+}
}
}
-/* 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;
}
#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);