From: Jason Merrill Date: Tue, 26 Mar 2019 16:02:19 +0000 (-0400) Subject: PR c++/86429 - constexpr variable in lambda. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=c59fa7eac4a82af74a5cdfe620dca27a45d16843;p=gcc.git 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 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 80d4ae3f1b9..550b7541d9f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2019-03-26 Jason Merrill + + 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 PR c++/89796 diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index e92ec55317b..c00d642fcfe 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 00000000000..e0080b3d4f6 --- /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 00000000000..491c7c322c3 --- /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 00000000000..2edb24e41ac --- /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 +struct Foo { + constexpr auto size() const { + return N; + } +}; + +constexpr int foo() { + constexpr auto a = Foo<5>{}; + + [&] { + Foo it = {}; + + return it; + }(); + + return 42; +} + +constexpr int i = foo();