[AST] Don't track lambda captures when checking a potential constant expression.

Fixes PR36054.

Differential revision: https://reviews.llvm.org/D45194

llvm-svn: 329244
This commit is contained in:
Erik Pilkington 2018-04-05 00:12:05 +00:00
parent 26c504fe1e
commit 11232912b1
2 changed files with 52 additions and 6 deletions

View File

@ -4309,9 +4309,15 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
This->moveInto(Result);
return true;
} else if (MD && isLambdaCallOperator(MD)) {
// We're in a lambda; determine the lambda capture field maps.
MD->getParent()->getCaptureFields(Frame.LambdaCaptureFields,
Frame.LambdaThisCaptureField);
// We're in a lambda; determine the lambda capture field maps unless we're
// just constexpr checking a lambda's call operator. constexpr checking is
// done before the captures have been added to the closure object (unless
// we're inferring constexpr-ness), so we don't have access to them in this
// case. But since we don't need the captures to constexpr check, we can
// just ignore them.
if (!Info.checkingPotentialConstantExpression())
MD->getParent()->getCaptureFields(Frame.LambdaCaptureFields,
Frame.LambdaThisCaptureField);
}
StmtResult Ret = {Result, ResultSlot};
@ -5201,10 +5207,17 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
// to within 'E' actually represents a lambda-capture that maps to a
// data-member/field within the closure object, and if so, evaluate to the
// field or what the field refers to.
if (Info.CurrentCall && isLambdaCallOperator(Info.CurrentCall->Callee)) {
if (Info.CurrentCall && isLambdaCallOperator(Info.CurrentCall->Callee) &&
isa<DeclRefExpr>(E) &&
cast<DeclRefExpr>(E)->refersToEnclosingVariableOrCapture()) {
// We don't always have a complete capture-map when checking or inferring if
// the function call operator meets the requirements of a constexpr function
// - but we don't need to evaluate the captures to determine constexprness
// (dcl.constexpr C++17).
if (Info.checkingPotentialConstantExpression())
return false;
if (auto *FD = Info.CurrentCall->LambdaCaptureFields.lookup(VD)) {
if (Info.checkingPotentialConstantExpression())
return false;
// Start with 'Result' referring to the complete closure object...
Result = *Info.CurrentCall->This;
// ... then update it to refer to the field of the closure object

View File

@ -270,4 +270,37 @@ namespace ns1_test_lvalue_type {
} // end ns test_lambda_is_cce
namespace PR36054 {
constexpr int fn() {
int Capture = 42;
return [=]() constexpr { return Capture; }();
}
static_assert(fn() == 42, "");
template <class T>
constexpr int tfn() {
int Capture = 42;
return [=]() constexpr { return Capture; }();
}
static_assert(tfn<int>() == 42, "");
constexpr int gfn() {
int Capture = 42;
return [=](auto P) constexpr { return Capture + P; }(58);
}
static_assert(gfn() == 100, "");
constexpr bool OtherCaptures() {
int Capture = 42;
constexpr auto Outer = [](auto P) constexpr { return 42 + P; };
auto Inner = [&](auto O) constexpr { return O(58) + Capture; };
return Inner(Outer) == 142;
}
static_assert(OtherCaptures(), "");
} // namespace PR36054
#endif // ndef CPP14_AND_EARLIER