mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-14 05:30:25 +08:00
c++: Refrain from using replace_placeholders in constexpr evaluation [PR94205]
This removes the use of replace_placeholders in cxx_eval_constant_expression (which is causing the new test lambda-this6.C to ICE due to replace_placeholders mutating the shared TARGET_EXPR_INITIAL tree which then trips up the gimplifier). In its place, this patch adds a 'parent' field to constexpr_ctx which is used to store a pointer to an outer constexpr_ctx that refers to another object under construction. With this new field, we can beef up lookup_placeholder to resolve PLACEHOLDER_EXPRs which refer to former objects under construction, which fixes PR94205 without needing to do replace_placeholders. Also we can now respect the CONSTRUCTOR_PLACEHOLDER_BOUNDARY flag when resolving PLACEHOLDER_EXPRs, and doing so fixes the constexpr analogue of PR79937. gcc/cp/ChangeLog: PR c++/94205 PR c++/79937 * constexpr.c (struct constexpr_ctx): New field 'parent'. (cxx_eval_bare_aggregate): Propagate CONSTRUCTOR_PLACEHOLDER_BOUNDARY flag from the original constructor to the reduced constructor. (lookup_placeholder): Prefer to return the outermost matching object by recursively calling lookup_placeholder on the 'parent' context, but don't cross CONSTRUCTOR_PLACEHOLDER_BOUNDARY constructors. (cxx_eval_constant_expression): Link the 'ctx' context to the 'new_ctx' context via 'new_ctx.parent' when being expanded without an explicit target. Don't call replace_placeholders. (cxx_eval_outermost_constant_expr): Initialize 'ctx.parent' to NULL. gcc/testsuite/ChangeLog: PR c++/94205 PR c++/79937 * g++.dg/cpp1y/pr79937-5.C: New test. * g++.dg/cpp1z/lambda-this6.C: New test.
This commit is contained in:
parent
37244b217a
commit
49a86fce1a
@ -1,5 +1,18 @@
|
||||
2020-04-04 Patrick Palka <ppalka@redhat.com>
|
||||
|
||||
PR c++/94205
|
||||
PR c++/79937
|
||||
* constexpr.c (struct constexpr_ctx): New field 'parent'.
|
||||
(cxx_eval_bare_aggregate): Propagate CONSTRUCTOR_PLACEHOLDER_BOUNDARY
|
||||
flag from the original constructor to the reduced constructor.
|
||||
(lookup_placeholder): Prefer to return the outermost matching object
|
||||
by recursively calling lookup_placeholder on the 'parent' context,
|
||||
but don't cross CONSTRUCTOR_PLACEHOLDER_BOUNDARY constructors.
|
||||
(cxx_eval_constant_expression): Link the 'ctx' context to the 'new_ctx'
|
||||
context via 'new_ctx.parent' when being expanded without an explicit
|
||||
target. Don't call replace_placeholders.
|
||||
(cxx_eval_outermost_constant_expr): Initialize 'ctx.parent' to NULL.
|
||||
|
||||
PR c++/94219
|
||||
PR c++/94205
|
||||
* constexpr.c (get_or_insert_ctor_field): Split out (while adding
|
||||
|
@ -1076,6 +1076,9 @@ struct constexpr_ctx {
|
||||
tree object;
|
||||
/* If inside SWITCH_EXPR. */
|
||||
constexpr_switch_state *css_state;
|
||||
/* The aggregate initialization context inside which this one is nested. This
|
||||
is used by lookup_placeholder to resolve PLACEHOLDER_EXPRs. */
|
||||
const constexpr_ctx *parent;
|
||||
|
||||
/* Whether we should error on a non-constant expression or fail quietly.
|
||||
This flag needs to be here, but some of the others could move to global
|
||||
@ -3841,6 +3844,9 @@ 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));
|
||||
|
||||
if (CONSTRUCTOR_PLACEHOLDER_BOUNDARY (t))
|
||||
CONSTRUCTOR_PLACEHOLDER_BOUNDARY (ctx->ctor) = 1;
|
||||
|
||||
unsigned i;
|
||||
tree index, value;
|
||||
bool constant_p = true;
|
||||
@ -5303,6 +5309,12 @@ lookup_placeholder (const constexpr_ctx *ctx, bool lval, tree type)
|
||||
if (!ctx)
|
||||
return NULL_TREE;
|
||||
|
||||
/* Prefer the outermost matching object, but don't cross
|
||||
CONSTRUCTOR_PLACEHOLDER_BOUNDARY constructors. */
|
||||
if (ctx->ctor && !CONSTRUCTOR_PLACEHOLDER_BOUNDARY (ctx->ctor))
|
||||
if (tree outer_ob = lookup_placeholder (ctx->parent, lval, type))
|
||||
return outer_ob;
|
||||
|
||||
/* We could use ctx->object unconditionally, but using ctx->ctor when we
|
||||
can is a minor optimization. */
|
||||
if (!lval && ctx->ctor && same_type_p (TREE_TYPE (ctx->ctor), type))
|
||||
@ -5606,19 +5618,16 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
|
||||
r = *p;
|
||||
break;
|
||||
}
|
||||
tree init = TARGET_EXPR_INITIAL (t);
|
||||
if ((AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type)))
|
||||
{
|
||||
if (ctx->object)
|
||||
/* If the initializer contains any PLACEHOLDER_EXPR, we need to
|
||||
resolve them before we create a new CONSTRUCTOR for the
|
||||
temporary. */
|
||||
init = replace_placeholders (init, ctx->object);
|
||||
|
||||
/* We're being expanded without an explicit target, so start
|
||||
initializing a new object; expansion with an explicit target
|
||||
strips the TARGET_EXPR before we get here. */
|
||||
new_ctx = *ctx;
|
||||
/* Link CTX to NEW_CTX so that lookup_placeholder can resolve
|
||||
any PLACEHOLDER_EXPR within the initializer that refers to the
|
||||
former object under construction. */
|
||||
new_ctx.parent = ctx;
|
||||
new_ctx.ctor = build_constructor (type, NULL);
|
||||
CONSTRUCTOR_NO_CLEARING (new_ctx.ctor) = true;
|
||||
new_ctx.object = slot;
|
||||
@ -6472,7 +6481,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
|
||||
bool overflow_p = false;
|
||||
|
||||
constexpr_global_ctx global_ctx;
|
||||
constexpr_ctx ctx = { &global_ctx, NULL, NULL, NULL, NULL, NULL,
|
||||
constexpr_ctx ctx = { &global_ctx, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
allow_non_constant, strict,
|
||||
manifestly_const_eval || !allow_non_constant,
|
||||
uid_sensitive };
|
||||
|
@ -1,5 +1,10 @@
|
||||
2020-04-04 Patrick Palka <ppalka@redhat.com>
|
||||
|
||||
PR c++/94205
|
||||
PR c++/79937
|
||||
* g++.dg/cpp1y/pr79937-5.C: New test.
|
||||
* g++.dg/cpp1z/lambda-this6.C: New test.
|
||||
|
||||
PR c++/94219
|
||||
PR c++/94205
|
||||
* g++.dg/cpp1y/constexpr-nsdmi3.C: New test.
|
||||
|
42
gcc/testsuite/g++.dg/cpp1y/pr79937-5.C
Normal file
42
gcc/testsuite/g++.dg/cpp1y/pr79937-5.C
Normal file
@ -0,0 +1,42 @@
|
||||
// PR c++/79937
|
||||
// This is a constexpr adaptation of pr79937-3.C and pr79937-4.C.
|
||||
// { dg-do compile { target c++14 } }
|
||||
|
||||
struct X {
|
||||
unsigned i;
|
||||
unsigned n = i;
|
||||
};
|
||||
|
||||
constexpr X bar(X x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
struct Y
|
||||
{
|
||||
static constexpr Y bar(Y y) { return y; }
|
||||
unsigned i;
|
||||
unsigned n = bar(Y{2,i}).n;
|
||||
};
|
||||
|
||||
constexpr X x { 1, bar(X{2}).n };
|
||||
static_assert(x.n == 2, "");
|
||||
|
||||
constexpr Y y { 1 };
|
||||
static_assert(y.n == 1, "");
|
||||
|
||||
struct Z {
|
||||
unsigned i;
|
||||
unsigned n = i;
|
||||
unsigned m = i;
|
||||
};
|
||||
|
||||
constexpr Z
|
||||
baz (Z z)
|
||||
{
|
||||
if (z.i != 1 || z.n != 2 || z.m != 1)
|
||||
__builtin_abort ();
|
||||
return z;
|
||||
}
|
||||
|
||||
constexpr Z z = baz (Z {1, Z {2}.n});
|
||||
static_assert(z.i == 1 && z.n == 2 && z.m == 1, "");
|
12
gcc/testsuite/g++.dg/cpp1z/lambda-this6.C
Normal file
12
gcc/testsuite/g++.dg/cpp1z/lambda-this6.C
Normal file
@ -0,0 +1,12 @@
|
||||
// { dg-do compile { target c++17 } }
|
||||
|
||||
struct S
|
||||
{
|
||||
int a = [this] { return 6; } ();
|
||||
};
|
||||
|
||||
S
|
||||
foo()
|
||||
{
|
||||
return {};
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user