From 76f09260b7eccd6c3cfa3dcf3c22897fe12a8065 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 31 Mar 2020 17:34:47 -0400 Subject: [PATCH] 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 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. --- gcc/cp/ChangeLog | 8 ++++++++ gcc/cp/constexpr.c | 6 ++++++ gcc/cp/tree.c | 2 +- gcc/cp/typeck2.c | 2 +- gcc/testsuite/g++.dg/cpp1y/constexpr-nsdmi2.C | 20 +++++++++++++++++++ gcc/testsuite/g++.dg/cpp1z/lambda-this4.C | 13 ++++++++++++ 6 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-nsdmi2.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/lambda-this4.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 2814a866f5d..3b522e8278c 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2020-03-31 Jason Merrill + + 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 * constexpr.c (cxx_eval_constant_expression) [TARGET_EXPR]: Use diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index e85b3c113f0..91f0c3ba269 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -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. */ diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index a2172dea0d8..5eb0dcd717a 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -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) diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index bff4ddbcf81..cf1cb5ace66 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -871,7 +871,7 @@ store_init_value (tree decl, tree init, vec** 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))) diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-nsdmi2.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-nsdmi2.C new file mode 100644 index 00000000000..c51f734a134 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-nsdmi2.C @@ -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); diff --git a/gcc/testsuite/g++.dg/cpp1z/lambda-this4.C b/gcc/testsuite/g++.dg/cpp1z/lambda-this4.C new file mode 100644 index 00000000000..5d968791491 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/lambda-this4.C @@ -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); -- 2.30.2