From 2d63bc398f7221edbec3e3f1d4ecbacac87cb3a5 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 26 Jan 2016 16:34:10 -0500 Subject: [PATCH] re PR c++/68782 (bad reference member formed with constexpr) PR c++/68782 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. From-SVN: r232847 --- gcc/ChangeLog | 8 +++ gcc/cp/ChangeLog | 8 +++ gcc/cp/constexpr.c | 60 +++++++++++++++++--- gcc/testsuite/g++.dg/cpp0x/constexpr-aggr2.C | 27 +++++++++ gcc/tree.c | 56 ++++++++++++++---- gcc/tree.h | 2 + 6 files changed, 141 insertions(+), 20 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-aggr2.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e94010a9cc5..043dd88bf61 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2016-01-26 Jason Merrill + + 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 PR rtl-optimization/69217 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3d7824c4b8e..dee9e4d3a93 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2016-01-26 Jason Merrill + + 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 PR c++/68357 diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 6b0e5a8717f..eed7308fb1a 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -2214,7 +2214,10 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t, vec **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 *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 index 00000000000..805d026269d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-aggr2.C @@ -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 ); +} diff --git a/gcc/tree.c b/gcc/tree.c index 9c67beaf976..fa7646b14e1 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -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 *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 *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 *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 *vals) +{ + tree c = make_node (CONSTRUCTOR); + + TREE_TYPE (c) = type; + CONSTRUCTOR_ELTS (c) = vals; + + recompute_constructor_flags (c); return c; } diff --git a/gcc/tree.h b/gcc/tree.h index 9b987bbbbc6..f789785ed25 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -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 *); 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 *); extern tree build_constructor_single (tree, tree, tree); extern tree build_constructor_from_list (tree, tree); -- 2.30.2