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:
parent
7ac205673c
commit
c59fa7eac4
5 changed files with 94 additions and 2 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
24
gcc/testsuite/g++.dg/cpp1y/lambda-generic-const10.C
Normal file
24
gcc/testsuite/g++.dg/cpp1y/lambda-generic-const10.C
Normal 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
|
||||
};
|
||||
}
|
16
gcc/testsuite/g++.dg/cpp1y/lambda-generic-const9.C
Normal file
16
gcc/testsuite/g++.dg/cpp1y/lambda-generic-const9.C
Normal 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);
|
||||
}
|
23
gcc/testsuite/g++.dg/cpp1z/constexpr-lambda24.C
Normal file
23
gcc/testsuite/g++.dg/cpp1z/constexpr-lambda24.C
Normal 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();
|
Loading…
Add table
Reference in a new issue