[C++17] Disallow lambdas in template parameters (PR33696).
Summary: This revision disallows lambdas in template parameters, as reported in PR33696.
Reviewers: rsmith
Reviewed By: rsmith
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D37442
llvm-svn: 336930
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index d6d105c..b26cf3c 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -163,7 +163,7 @@
ExprEvalContexts.emplace_back(
ExpressionEvaluationContext::PotentiallyEvaluated, 0, CleanupInfo{},
- nullptr, false);
+ nullptr, ExpressionEvaluationContextRecord::EK_Other);
PreallocatedFunctionScope.reset(new FunctionScopeInfo(Diags));
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 820e5a9..51c1c84 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -14132,22 +14132,22 @@
}
void
-Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext,
- Decl *LambdaContextDecl,
- bool IsDecltype) {
+Sema::PushExpressionEvaluationContext(
+ ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl,
+ ExpressionEvaluationContextRecord::ExpressionKind ExprContext) {
ExprEvalContexts.emplace_back(NewContext, ExprCleanupObjects.size(), Cleanup,
- LambdaContextDecl, IsDecltype);
+ LambdaContextDecl, ExprContext);
Cleanup.reset();
if (!MaybeODRUseExprs.empty())
std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs);
}
void
-Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext,
- ReuseLambdaContextDecl_t,
- bool IsDecltype) {
+Sema::PushExpressionEvaluationContext(
+ ExpressionEvaluationContext NewContext, ReuseLambdaContextDecl_t,
+ ExpressionEvaluationContextRecord::ExpressionKind ExprContext) {
Decl *ClosureContextDecl = ExprEvalContexts.back().ManglingContextDecl;
- PushExpressionEvaluationContext(NewContext, ClosureContextDecl, IsDecltype);
+ PushExpressionEvaluationContext(NewContext, ClosureContextDecl, ExprContext);
}
void Sema::PopExpressionEvaluationContext() {
@@ -14155,30 +14155,30 @@
unsigned NumTypos = Rec.NumTypos;
if (!Rec.Lambdas.empty()) {
- if (Rec.isUnevaluated() || Rec.isConstantEvaluated()) {
+ using ExpressionKind = ExpressionEvaluationContextRecord::ExpressionKind;
+ if (Rec.ExprContext == ExpressionKind::EK_TemplateArgument || Rec.isUnevaluated() ||
+ (Rec.isConstantEvaluated() && !getLangOpts().CPlusPlus17)) {
unsigned D;
if (Rec.isUnevaluated()) {
// C++11 [expr.prim.lambda]p2:
// A lambda-expression shall not appear in an unevaluated operand
// (Clause 5).
D = diag::err_lambda_unevaluated_operand;
- } else {
+ } else if (Rec.isConstantEvaluated() && !getLangOpts().CPlusPlus17) {
// C++1y [expr.const]p2:
// A conditional-expression e is a core constant expression unless the
// evaluation of e, following the rules of the abstract machine, would
// evaluate [...] a lambda-expression.
D = diag::err_lambda_in_constant_expression;
- }
+ } else if (Rec.ExprContext == ExpressionKind::EK_TemplateArgument) {
+ // C++17 [expr.prim.lamda]p2:
+ // A lambda-expression shall not appear [...] in a template-argument.
+ D = diag::err_lambda_in_invalid_context;
+ } else
+ llvm_unreachable("Couldn't infer lambda error message.");
- // C++1z allows lambda expressions as core constant expressions.
- // FIXME: In C++1z, reinstate the restrictions on lambda expressions (CWG
- // 1607) from appearing within template-arguments and array-bounds that
- // are part of function-signatures. Be mindful that P0315 (Lambdas in
- // unevaluated contexts) might lift some of these restrictions in a
- // future version.
- if (!Rec.isConstantEvaluated() || !getLangOpts().CPlusPlus17)
- for (const auto *L : Rec.Lambdas)
- Diag(L->getLocStart(), D);
+ for (const auto *L : Rec.Lambdas)
+ Diag(L->getLocStart(), D);
} else {
// Mark the capture expressions odr-used. This was deferred
// during lambda expression creation.
@@ -15637,7 +15637,8 @@
// If we're inside a decltype's expression, don't check for a valid return
// type or construct temporaries until we know whether this is the last call.
- if (ExprEvalContexts.back().IsDecltype) {
+ if (ExprEvalContexts.back().ExprContext ==
+ ExpressionEvaluationContextRecord::EK_Decltype) {
ExprEvalContexts.back().DelayedDecltypeCalls.push_back(CE);
return false;
}
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 8dd9c19..8ed795a 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -6434,7 +6434,8 @@
if (RD->isInvalidDecl() || RD->isDependentContext())
return E;
- bool IsDecltype = ExprEvalContexts.back().IsDecltype;
+ bool IsDecltype = ExprEvalContexts.back().ExprContext ==
+ ExpressionEvaluationContextRecord::EK_Decltype;
CXXDestructorDecl *Destructor = IsDecltype ? nullptr : LookupDestructor(RD);
if (Destructor) {
@@ -6516,7 +6517,9 @@
/// are omitted for the 'topmost' call in the decltype expression. If the
/// topmost call bound a temporary, strip that temporary off the expression.
ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
- assert(ExprEvalContexts.back().IsDecltype && "not in a decltype expression");
+ assert(ExprEvalContexts.back().ExprContext ==
+ ExpressionEvaluationContextRecord::EK_Decltype &&
+ "not in a decltype expression");
// C++11 [expr.call]p11:
// If a function call is a prvalue of object type,
@@ -6558,7 +6561,8 @@
TopBind = nullptr;
// Disable the special decltype handling now.
- ExprEvalContexts.back().IsDecltype = false;
+ ExprEvalContexts.back().ExprContext =
+ ExpressionEvaluationContextRecord::EK_Other;
// In MS mode, don't perform any extra checking of call return types within a
// decltype expression.
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 66c947a..6ee5eca 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -3859,6 +3859,10 @@
bool TreeTransform<Derived>::TransformTemplateArgument(
const TemplateArgumentLoc &Input,
TemplateArgumentLoc &Output, bool Uneval) {
+ EnterExpressionEvaluationContext EEEC(
+ SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated,
+ /*LambdaContextDecl=*/nullptr, /*ExprContext=*/
+ Sema::ExpressionEvaluationContextRecord::EK_TemplateArgument);
const TemplateArgument &Arg = Input.getArgument();
switch (Arg.getKind()) {
case TemplateArgument::Null:
@@ -5494,7 +5498,7 @@
// decltype expressions are not potentially evaluated contexts
EnterExpressionEvaluationContext Unevaluated(
SemaRef, Sema::ExpressionEvaluationContext::Unevaluated, nullptr,
- /*IsDecltype=*/true);
+ Sema::ExpressionEvaluationContextRecord::EK_Decltype);
ExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr());
if (E.isInvalid())