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.
Tested x86_64-pc-linux-gnu, applying to trunk.
PR c++/82643
PR c++/87327
* constexpr.c (cxx_eval_constant_expression): In a lambda function,
try evaluating the captured variable directly.
---
gcc/cp/constexpr.c | 25 +++++++++++++++++--
.../g++.dg/cpp1y/lambda-generic-const10.C | 24 ++++++++++++++++++
.../g++.dg/cpp1y/lambda-generic-const9.C | 16 ++++++++++++
.../g++.dg/cpp1z/constexpr-lambda24.C | 23 +++++++++++++++++
gcc/cp/ChangeLog | 8 ++++++
5 files changed, 94 insertions(+), 2 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-const10.C
create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-const9.C
create mode 100644 gcc/testsuite/g++.dg/cpp1z/constexpr-lambda24.C
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 <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();
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 <[email protected]>
+
+ 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 <[email protected]>
PR c++/89796
base-commit: 7237dce709ba3deef79bd146a009cf0e727476d8
--
2.20.1