mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-05 08:00:26 +08:00
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
This commit is contained in:
parent
3671c99673
commit
2d63bc398f
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
27
gcc/testsuite/g++.dg/cpp0x/constexpr-aggr2.C
Normal file
27
gcc/testsuite/g++.dg/cpp0x/constexpr-aggr2.C
Normal file
@ -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 );
|
||||
}
|
68
gcc/tree.c
68
gcc/tree.c
@ -1790,34 +1790,66 @@ build_vector_from_val (tree vectype, tree sc)
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
unsigned int i;
|
||||
tree val;
|
||||
bool constant_p = true;
|
||||
bool side_effects_p = false;
|
||||
vec<constructor_elt, va_gc> *vals = CONSTRUCTOR_ELTS (c);
|
||||
|
||||
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 (val))
|
||||
constant_p = false;
|
||||
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);
|
||||
unsigned int i;
|
||||
constructor_elt *elt;
|
||||
bool constant_p = true;
|
||||
bool side_effects_p = false;
|
||||
|
||||
TREE_TYPE (c) = type;
|
||||
CONSTRUCTOR_ELTS (c) = vals;
|
||||
|
||||
FOR_EACH_VEC_SAFE_ELT (vals, i, elt)
|
||||
{
|
||||
/* 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))
|
||||
constant_p = false;
|
||||
if (TREE_SIDE_EFFECTS (elt->value))
|
||||
side_effects_p = true;
|
||||
}
|
||||
|
||||
TREE_SIDE_EFFECTS (c) = side_effects_p;
|
||||
TREE_CONSTANT (c) = constant_p;
|
||||
recompute_constructor_flags (c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user