[PATCH] D45194: [Sema] Defer checking constexpr lambda until after we've finished the lambda class.
Erik Pilkington via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 2 18:28:39 PDT 2018
erik.pilkington created this revision.
erik.pilkington added reviewers: rsmith, faisalv.
Previously, this caused ExprConstant to assert while verifying the lambda is constexpr:
void f() {
int x = 0;
[=]() constexpr {
return x;
};
}
The problem is that ActOnFinishFunctionBody evaluated the lambda's body before BuildLambdaExpr finished the lambda class. This patch fixes the problem by moving that check to BuildLambdaExpr.
PR36054
Thanks for taking a look!
Erik
Repository:
rC Clang
https://reviews.llvm.org/D45194
Files:
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaLambda.cpp
clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp
Index: clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp
===================================================================
--- clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp
+++ clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp
@@ -270,4 +270,37 @@
} // 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
Index: clang/lib/Sema/SemaLambda.cpp
===================================================================
--- clang/lib/Sema/SemaLambda.cpp
+++ clang/lib/Sema/SemaLambda.cpp
@@ -1604,17 +1604,27 @@
ExplicitParams, ExplicitResultType,
CaptureInits, EndLoc,
ContainsUnexpandedParameterPack);
- // If the lambda expression's call operator is not explicitly marked constexpr
- // and we are not in a dependent context, analyze the call operator to infer
- // its constexpr-ness, suppressing diagnostics while doing so.
- if (getLangOpts().CPlusPlus17 && !CallOperator->isInvalidDecl() &&
- !CallOperator->isConstexpr() &&
- !isa<CoroutineBodyStmt>(CallOperator->getBody()) &&
- !Class->getDeclContext()->isDependentContext()) {
- TentativeAnalysisScope DiagnosticScopeGuard(*this);
- CallOperator->setConstexpr(
- CheckConstexprFunctionDecl(CallOperator) &&
- CheckConstexprFunctionBody(CallOperator, CallOperator->getBody()));
+
+ if (!CallOperator->isInvalidDecl()) {
+ // If the call operator is explicitly marked constexpr, verify that that is
+ // actually the case. This is done here instead of in
+ // ActOnFinishFunctionBody because the constexpr evaluator needs access to
+ // the completed lambda class to check this.
+ if (CallOperator->isConstexpr()) {
+ if (!CheckConstexprFunctionDecl(CallOperator) ||
+ !CheckConstexprFunctionBody(CallOperator, CallOperator->getBody()))
+ CallOperator->setInvalidDecl();
+ }
+ // Otherwise, if we're not in a dependent context, analyze the call operator
+ // to infer its constexpr-ness, suppressing diagnostics while doing so.
+ else if (getLangOpts().CPlusPlus17 &&
+ !isa<CoroutineBodyStmt>(CallOperator->getBody()) &&
+ !Class->getDeclContext()->isDependentContext()) {
+ TentativeAnalysisScope DiagnosticScopeGuard(*this);
+ CallOperator->setConstexpr(
+ CheckConstexprFunctionDecl(CallOperator) &&
+ CheckConstexprFunctionBody(CallOperator, CallOperator->getBody()));
+ }
}
// Emit delayed shadowing warnings now that the full capture list is known.
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -12883,6 +12883,7 @@
}
if (!IsInstantiation && FD && FD->isConstexpr() && !FD->isInvalidDecl() &&
+ !isLambdaCallOperator(FD) &&
(!CheckConstexprFunctionDecl(FD) ||
!CheckConstexprFunctionBody(FD, Body)))
FD->setInvalidDecl();
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D45194.140722.patch
Type: text/x-patch
Size: 3781 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180403/042a562d/attachment.bin>
More information about the cfe-commits
mailing list