diff options
author | Jason Merrill <jason@redhat.com> | 2019-03-26 12:02:19 -0400 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2019-03-26 12:02:19 -0400 |
commit | c59fa7eac4a82af74a5cdfe620dca27a45d16843 (patch) | |
tree | 45250c1852f1bfe23db6d53a66beb6a39faac3e9 /gcc | |
parent | 7ac205673caade367552a567a98e27940f17cf35 (diff) | |
download | gcc-c59fa7eac4a82af74a5cdfe620dca27a45d16843.zip gcc-c59fa7eac4a82af74a5cdfe620dca27a45d16843.tar.gz gcc-c59fa7eac4a82af74a5cdfe620dca27a45d16843.tar.bz2 |
PR c++/86429 - constexpr variable in lambda.
When we refer to a captured variable from a constant-expression context
inside a lambda, the closure (like any function parameter) is not constant
because we aren't in a call, so we don't have an argument. So the capture
is non-constant. But if the captured variable is constant, we might be able
to use it directly in constexpr evaluation.
PR c++/82643
PR c++/87327
* constexpr.c (cxx_eval_constant_expression): In a lambda function,
try evaluating the captured variable directly.
From-SVN: r269951
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/cp/constexpr.c | 25 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1y/lambda-generic-const10.C | 24 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1y/lambda-generic-const9.C | 16 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1z/constexpr-lambda24.C | 23 |
5 files changed, 94 insertions, 2 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 80d4ae3..550b754 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2019-03-26 Jason Merrill <jason@redhat.com> + + PR c++/86429 - constexpr variable in lambda. + PR c++/82643 + PR c++/87327 + * constexpr.c (cxx_eval_constant_expression): In a lambda function, + try evaluating the captured variable directly. + 2019-03-26 Jakub Jelinek <jakub@redhat.com> PR c++/89796 diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index e92ec55..c00d642 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -4442,8 +4442,29 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case VAR_DECL: if (DECL_HAS_VALUE_EXPR_P (t)) - return cxx_eval_constant_expression (ctx, DECL_VALUE_EXPR (t), - lval, non_constant_p, overflow_p); + { + if (is_normal_capture_proxy (t) + && current_function_decl == DECL_CONTEXT (t)) + { + /* Function parms aren't constexpr within the function + definition, so don't try to look at the closure. But if the + captured variable is constant, try to evaluate it directly. */ + r = DECL_CAPTURED_VARIABLE (t); + tree type = TREE_TYPE (t); + if (TYPE_REF_P (type) != TYPE_REF_P (TREE_TYPE (r))) + { + /* Adjust r to match the reference-ness of t. */ + if (TYPE_REF_P (type)) + r = build_address (r); + else + r = convert_from_reference (r); + } + } + else + r = DECL_VALUE_EXPR (t); + return cxx_eval_constant_expression (ctx, r, lval, non_constant_p, + overflow_p); + } /* fall through */ case CONST_DECL: /* We used to not check lval for CONST_DECL, but darwin.c uses diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const10.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const10.C new file mode 100644 index 0000000..e0080b3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const10.C @@ -0,0 +1,24 @@ +// PR c++/82643 +// { dg-do compile { target c++14 } } + +int main() +{ + struct A { + constexpr int operator()() const { return 42; } + }; + + auto f = A(); + constexpr auto x = f(); //ok, call constexpr const non-static method + + [](auto const &f) { + constexpr auto x = f(); /*ok*/ + }(f); + + [&]() { + constexpr auto x = f(); //ko, __closure is not a constant expression + }; + + [=]() { + constexpr auto x = f(); //same ko, __closure is not a constant expression + }; +} diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const9.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const9.C new file mode 100644 index 0000000..491c7c3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const9.C @@ -0,0 +1,16 @@ +// PR c++/86429 +// { dg-do compile { target c++14 } } + +struct A +{ + int i; + constexpr int f(const int&) const { return i; } +}; + +void g() +{ + constexpr A a = { 42 }; + [&](auto x) { + constexpr auto y = a.f(x); + }(24); +} diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda24.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda24.C new file mode 100644 index 0000000..2edb24e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda24.C @@ -0,0 +1,23 @@ +// PR c++/87327 +// { dg-do compile { target c++17 } } + +template <int N> +struct Foo { + constexpr auto size() const { + return N; + } +}; + +constexpr int foo() { + constexpr auto a = Foo<5>{}; + + [&] { + Foo<a.size()> it = {}; + + return it; + }(); + + return 42; +} + +constexpr int i = foo(); |