[cxx1z-constexpr-lambda] Implement constant evaluation of non-capturing lambda expressions.
Add a visitor for lambda expressions to RecordExprEvaluator in ExprConstant.cpp that creates an empty APValue of Struct type to represent the closure object. Additionally, add a LambdaExpr visitor to the TemporaryExprEvaluator that forwards constant evaluation of immediately-called-lambda-expressions to the one in RecordExprEvaluator through VisitConstructExpr. This patch supports: constexpr auto ID = [] (auto a) { return a; }; static_assert(ID(3.14) == 3.14); static_assert([](auto a) { return a + 1; }(10) == 11); Lambda captures are still not supported for constexpr lambdas. llvm-svn: 291416
This commit is contained in:
parent
6393afce97
commit
c72a08c1f6
|
@ -5868,6 +5868,7 @@ namespace {
|
|||
bool VisitCXXConstructExpr(const CXXConstructExpr *E) {
|
||||
return VisitCXXConstructExpr(E, E->getType());
|
||||
}
|
||||
bool VisitLambdaExpr(const LambdaExpr *E);
|
||||
bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
|
||||
bool VisitCXXConstructExpr(const CXXConstructExpr *E, QualType T);
|
||||
bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
|
||||
|
@ -6202,6 +6203,21 @@ bool RecordExprEvaluator::VisitCXXStdInitializerListExpr(
|
|||
return true;
|
||||
}
|
||||
|
||||
bool RecordExprEvaluator::VisitLambdaExpr(const LambdaExpr *E) {
|
||||
const CXXRecordDecl *ClosureClass = E->getLambdaClass();
|
||||
if (ClosureClass->isInvalidDecl()) return false;
|
||||
|
||||
if (Info.checkingPotentialConstantExpression()) return true;
|
||||
if (E->capture_size()) {
|
||||
Info.FFDiag(E, diag::note_unimplemented_constexpr_lambda_feature_ast)
|
||||
<< "can not evaluate lambda expressions with captures";
|
||||
return false;
|
||||
}
|
||||
// FIXME: Implement captures.
|
||||
Result = APValue(APValue::UninitStruct(), /*NumBases*/0, /*NumFields*/0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool EvaluateRecord(const Expr *E, const LValue &This,
|
||||
APValue &Result, EvalInfo &Info) {
|
||||
assert(E->isRValue() && E->getType()->isRecordType() &&
|
||||
|
@ -6251,6 +6267,9 @@ public:
|
|||
bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E) {
|
||||
return VisitConstructExpr(E);
|
||||
}
|
||||
bool VisitLambdaExpr(const LambdaExpr *E) {
|
||||
return VisitConstructExpr(E);
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
|
|
|
@ -13097,8 +13097,10 @@ void Sema::PopExpressionEvaluationContext() {
|
|||
// evaluate [...] a lambda-expression.
|
||||
D = diag::err_lambda_in_constant_expression;
|
||||
}
|
||||
for (const auto *L : Rec.Lambdas)
|
||||
Diag(L->getLocStart(), D);
|
||||
// C++1z allows lambda expressions as core constant expressions.
|
||||
if (Rec.Context != ConstantEvaluated || !getLangOpts().CPlusPlus1z)
|
||||
for (const auto *L : Rec.Lambdas)
|
||||
Diag(L->getLocStart(), D);
|
||||
} else {
|
||||
// Mark the capture expressions odr-used. This was deferred
|
||||
// during lambda expression creation.
|
||||
|
|
|
@ -96,4 +96,81 @@ decltype(deduced_return_type(0)) d; //expected-note{{requested here}}
|
|||
|
||||
} // end ns test_conversion_function_for_non_capturing_lambdas
|
||||
|
||||
namespace test_lambda_is_cce {
|
||||
namespace ns1_simple_lambda {
|
||||
|
||||
namespace ns0 {
|
||||
constexpr int I = [](auto a) { return a; }(10);
|
||||
|
||||
static_assert(I == 10);
|
||||
static_assert(10 == [](auto a) { return a; }(10));
|
||||
static_assert(3.14 == [](auto a) { return a; }(3.14));
|
||||
|
||||
} //end ns0
|
||||
|
||||
namespace ns1 {
|
||||
constexpr auto f(int i) {
|
||||
double d = 3.14;
|
||||
auto L = [=](auto a) {
|
||||
int Isz = sizeof(i);
|
||||
return sizeof(i) + sizeof(a) + sizeof(d);
|
||||
};
|
||||
int I = L("abc") + L(nullptr);
|
||||
return L;
|
||||
}
|
||||
constexpr auto L = f(3);
|
||||
constexpr auto M = L("abc") + L(nullptr);
|
||||
|
||||
static_assert(M == sizeof(int) * 2 + sizeof(double) * 2 + sizeof(nullptr) + sizeof(const char*));
|
||||
|
||||
} // end ns1
|
||||
|
||||
namespace ns2 {
|
||||
constexpr auto f(int i) {
|
||||
auto L = [](auto a) { return a + a; };
|
||||
return L;
|
||||
}
|
||||
constexpr auto L = f(3);
|
||||
constexpr int I = L(6);
|
||||
static_assert(I == 12);
|
||||
} // end ns2
|
||||
|
||||
namespace contained_lambdas_call_operator_is_not_constexpr {
|
||||
constexpr auto f(int i) {
|
||||
double d = 3.14;
|
||||
auto L = [=](auto a) { //expected-note{{declared here}}
|
||||
int Isz = sizeof(i);
|
||||
asm("hello");
|
||||
return sizeof(i) + sizeof(a) + sizeof(d);
|
||||
};
|
||||
return L;
|
||||
}
|
||||
|
||||
constexpr auto L = f(3);
|
||||
|
||||
constexpr auto M = // expected-error{{must be initialized by}}
|
||||
L("abc"); //expected-note{{non-constexpr function}}
|
||||
|
||||
} // end ns contained_lambdas_call_operator_is_not_constexpr
|
||||
|
||||
|
||||
|
||||
} // end ns1_simple_lambda
|
||||
|
||||
namespace ns1_unimplemented {
|
||||
namespace ns1_captures {
|
||||
constexpr auto f(int i) {
|
||||
double d = 3.14;
|
||||
auto L = [=](auto a) { //expected-note{{coming soon}}
|
||||
int Isz = i + d;
|
||||
return sizeof(i) + sizeof(a) + sizeof(d);
|
||||
};
|
||||
return L;
|
||||
}
|
||||
constexpr auto M = f(3); //expected-error{{constant expression}} expected-note{{in call to}}
|
||||
} // end ns1_captures
|
||||
} // end ns1_unimplemented
|
||||
|
||||
} // end ns test_lambda_is_cce
|
||||
|
||||
#endif // ndef CPP14_AND_EARLIER
|
||||
|
|
Loading…
Reference in New Issue