Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -6487,6 +6487,8 @@ "lambda expression in an unevaluated operand">; def err_lambda_in_constant_expression : Error< "a lambda expression may not appear inside of a constant expression">; + def err_lambda_in_invalid_context : Error< + "a lambda expression cannot appear in this context">; def err_lambda_return_init_list : Error< "cannot deduce lambda return type from initializer list">; def err_lambda_capture_default_arg : Error< Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -979,15 +979,21 @@ /// expressions for which we have deferred checking the destructor. SmallVector DelayedDecltypeBinds; + /// \brief Describes whether we are in an expression constext which we have + /// to handle differently. + enum ExpressionKind { + EK_Decltype, EK_TemplateArgument, EK_Other + } ExprContext; + ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, unsigned NumCleanupObjects, CleanupInfo ParentCleanup, Decl *ManglingContextDecl, - bool IsDecltype) - : Context(Context), ParentCleanup(ParentCleanup), - IsDecltype(IsDecltype), NumCleanupObjects(NumCleanupObjects), - NumTypos(0), - ManglingContextDecl(ManglingContextDecl), MangleNumbering() { } + ExpressionKind ExprContext) + : Context(Context), ParentCleanup(ParentCleanup), + NumCleanupObjects(NumCleanupObjects), NumTypos(0), + ManglingContextDecl(ManglingContextDecl), MangleNumbering(), + ExprContext(ExprContext) {} /// Retrieve the mangling numbering context, used to consistently /// number constructs like lambdas for mangling. @@ -3989,13 +3995,13 @@ void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, ArrayRef Args); - void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, - Decl *LambdaContextDecl = nullptr, - bool IsDecltype = false); + void PushExpressionEvaluationContext( + ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl = nullptr, + ExpressionEvaluationContextRecord::ExpressionKind Type = ExpressionEvaluationContextRecord::EK_Other); enum ReuseLambdaContextDecl_t { ReuseLambdaContextDecl }; - void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, - ReuseLambdaContextDecl_t, - bool IsDecltype = false); + void PushExpressionEvaluationContext( + ExpressionEvaluationContext NewContext, ReuseLambdaContextDecl_t, + ExpressionEvaluationContextRecord::ExpressionKind Type = ExpressionEvaluationContextRecord::EK_Other); void PopExpressionEvaluationContext(); void DiscardCleanupsInEvaluationContext(); @@ -10748,25 +10754,25 @@ bool Entered = true; public: - - EnterExpressionEvaluationContext(Sema &Actions, - Sema::ExpressionEvaluationContext NewContext, - Decl *LambdaContextDecl = nullptr, - bool IsDecltype = false, - bool ShouldEnter = true) + EnterExpressionEvaluationContext( + Sema &Actions, Sema::ExpressionEvaluationContext NewContext, + Decl *LambdaContextDecl = nullptr, + Sema::ExpressionEvaluationContextRecord::ExpressionKind ExprContext = + Sema::ExpressionEvaluationContextRecord::EK_Other, + bool ShouldEnter = true) : Actions(Actions), Entered(ShouldEnter) { if (Entered) Actions.PushExpressionEvaluationContext(NewContext, LambdaContextDecl, - IsDecltype); + ExprContext); } - EnterExpressionEvaluationContext(Sema &Actions, - Sema::ExpressionEvaluationContext NewContext, - Sema::ReuseLambdaContextDecl_t, - bool IsDecltype = false) - : Actions(Actions) { - Actions.PushExpressionEvaluationContext(NewContext, - Sema::ReuseLambdaContextDecl, - IsDecltype); + EnterExpressionEvaluationContext( + Sema &Actions, Sema::ExpressionEvaluationContext NewContext, + Sema::ReuseLambdaContextDecl_t, + Sema::ExpressionEvaluationContextRecord::ExpressionKind ExprContext = + Sema::ExpressionEvaluationContextRecord::EK_Other) + : Actions(Actions) { + Actions.PushExpressionEvaluationContext( + NewContext, Sema::ReuseLambdaContextDecl, ExprContext); } enum InitListTag { InitList }; @@ -10780,7 +10786,7 @@ if (ShouldEnter && Actions.isUnevaluatedContext() && Actions.getLangOpts().CPlusPlus11) { Actions.PushExpressionEvaluationContext( - Sema::ExpressionEvaluationContext::UnevaluatedList, nullptr, false); + Sema::ExpressionEvaluationContext::UnevaluatedList); Entered = true; } } Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -309,9 +309,7 @@ EnterExpressionEvaluationContext Unevaluated( Actions, Uneval ? Sema::ExpressionEvaluationContext::Unevaluated - : Sema::ExpressionEvaluationContext::ConstantEvaluated, - /*LambdaContextDecl=*/nullptr, - /*IsDecltype=*/false); + : Sema::ExpressionEvaluationContext::ConstantEvaluated); ExprResult ArgExpr( Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression())); Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -942,7 +942,7 @@ // The operand of the decltype specifier is an unevaluated operand. EnterExpressionEvaluationContext Unevaluated( Actions, Sema::ExpressionEvaluationContext::Unevaluated, nullptr, - /*IsDecltype=*/true); + Sema::ExpressionEvaluationContextRecord::EK_Decltype); Result = Actions.CorrectDelayedTyposInExpr(ParseExpression(), [](Expr *E) { return E->hasPlaceholderType() ? ExprError() : E; Index: lib/Parse/ParseStmt.cpp =================================================================== --- lib/Parse/ParseStmt.cpp +++ lib/Parse/ParseStmt.cpp @@ -1196,7 +1196,7 @@ { EnterExpressionEvaluationContext PotentiallyDiscarded( Actions, Sema::ExpressionEvaluationContext::DiscardedStatement, nullptr, - false, + Sema::ExpressionEvaluationContextRecord::EK_Other, /*ShouldEnter=*/ConstexprCondition && !*ConstexprCondition); ThenStmt = ParseStatement(&InnerStatementTrailingElseLoc); } @@ -1230,7 +1230,7 @@ EnterExpressionEvaluationContext PotentiallyDiscarded( Actions, Sema::ExpressionEvaluationContext::DiscardedStatement, nullptr, - false, + Sema::ExpressionEvaluationContextRecord::EK_Other, /*ShouldEnter=*/ConstexprCondition && *ConstexprCondition); ElseStmt = ParseStatement(); Index: lib/Parse/ParseTemplate.cpp =================================================================== --- lib/Parse/ParseTemplate.cpp +++ lib/Parse/ParseTemplate.cpp @@ -1235,7 +1235,9 @@ // argument before trying to disambiguate. EnterExpressionEvaluationContext EnterConstantEvaluated( - Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); + Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated, + /*LambdaContextDecl=*/nullptr, + /*ExprContext=*/Sema::ExpressionEvaluationContextRecord::EK_TemplateArgument); if (isCXXTypeId(TypeIdAsTemplateArgument)) { TypeResult TypeArg = ParseTypeName( /*Range=*/nullptr, DeclaratorContext::TemplateArgContext); Index: lib/Sema/Sema.cpp =================================================================== --- lib/Sema/Sema.cpp +++ 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)); Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ 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; } Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ 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. Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -3859,6 +3859,10 @@ bool TreeTransform::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()) Index: test/CXX/expr/expr.prim/expr.prim.lambda/p2-template-parameter.cpp =================================================================== --- test/CXX/expr/expr.prim/expr.prim.lambda/p2-template-parameter.cpp +++ test/CXX/expr/expr.prim/expr.prim.lambda/p2-template-parameter.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -std=c++17 %s -verify + +template struct Nothing {}; + +void pr33696() { + Nothing<[]() { return 0; }()> nothing; // expected-error{{a lambda expression cannot appear in this context}} +}