c++: Fix DMI with lambda 'this' capture [PR94205]
We represent 'this' in a default member initializer with a PLACEHOLDER_EXPR. Normally in constexpr evaluation when we encounter one it refers to ctx->ctor, but when we're creating a temporary of class type, that replaces ctx->ctor, so a PLACEHOLDER_EXPR that refers to the type of the member being initialized needs to be replaced before that happens. gcc/cp/ChangeLog 2020-03-31 Jason Merrill <jason@redhat.com> PR c++/94205 * constexpr.c (cxx_eval_constant_expression) [TARGET_EXPR]: Call replace_placeholders. * typeck2.c (store_init_value): Fix arguments to fold_non_dependent_expr.
This commit is contained in:
parent
595f1b1274
commit
76f09260b7
6 changed files with 49 additions and 2 deletions
|
@ -1,3 +1,11 @@
|
|||
2020-03-31 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR c++/94205
|
||||
* constexpr.c (cxx_eval_constant_expression) [TARGET_EXPR]: Call
|
||||
replace_placeholders.
|
||||
* typeck2.c (store_init_value): Fix arguments to
|
||||
fold_non_dependent_expr.
|
||||
|
||||
2020-03-31 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* constexpr.c (cxx_eval_constant_expression) [TARGET_EXPR]: Use
|
||||
|
|
|
@ -5553,6 +5553,12 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
|
|||
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. */
|
||||
|
|
|
@ -3239,7 +3239,7 @@ replace_placeholders_r (tree* t, int* walk_subtrees, void* data_)
|
|||
a PLACEHOLDER_EXPR has been encountered. */
|
||||
|
||||
tree
|
||||
replace_placeholders (tree exp, tree obj, bool *seen_p)
|
||||
replace_placeholders (tree exp, tree obj, bool *seen_p /*= NULL*/)
|
||||
{
|
||||
/* This is only relevant for C++14. */
|
||||
if (cxx_dialect < cxx14)
|
||||
|
|
|
@ -871,7 +871,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
|
|||
{
|
||||
bool const_init;
|
||||
tree oldval = value;
|
||||
value = fold_non_dependent_expr (value);
|
||||
value = fold_non_dependent_expr (value, tf_warning_or_error, true, decl);
|
||||
if (DECL_DECLARED_CONSTEXPR_P (decl)
|
||||
|| (DECL_IN_AGGR_P (decl)
|
||||
&& DECL_INITIALIZED_IN_CLASS_P (decl)))
|
||||
|
|
20
gcc/testsuite/g++.dg/cpp1y/constexpr-nsdmi2.C
Normal file
20
gcc/testsuite/g++.dg/cpp1y/constexpr-nsdmi2.C
Normal file
|
@ -0,0 +1,20 @@
|
|||
// PR c++/94205
|
||||
// { dg-do compile { target c++14 } }
|
||||
|
||||
struct S
|
||||
{
|
||||
struct A
|
||||
{
|
||||
S *p;
|
||||
constexpr A(S* p): p(p) {}
|
||||
constexpr operator int() { p->i = 5; return 6; }
|
||||
};
|
||||
int i;
|
||||
int a = A(this);
|
||||
};
|
||||
|
||||
|
||||
constexpr S s = {};
|
||||
|
||||
#define SA(X) static_assert((X),#X)
|
||||
SA(s.i == 5 && s.a == 6);
|
13
gcc/testsuite/g++.dg/cpp1z/lambda-this4.C
Normal file
13
gcc/testsuite/g++.dg/cpp1z/lambda-this4.C
Normal file
|
@ -0,0 +1,13 @@
|
|||
// PR c++/94205
|
||||
// { dg-do compile { target c++17 } }
|
||||
|
||||
struct S
|
||||
{
|
||||
int i;
|
||||
int a = [this] { this->i = 5; return 6; } ();
|
||||
};
|
||||
|
||||
|
||||
constexpr S s = {};
|
||||
|
||||
static_assert (s.i == 5 && s.a == 6);
|
Loading…
Add table
Reference in a new issue