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
This commit is contained in:
Jason Merrill 2019-03-26 12:02:19 -04:00 committed by Jason Merrill
parent 7ac205673c
commit c59fa7eac4
5 changed files with 94 additions and 2 deletions

View file

@ -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

View file

@ -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

View file

@ -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
};
}

View file

@ -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);
}

View file

@ -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();