Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -6268,6 +6268,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_potentially_mangled_constant_expression : Error< + "a lambda expression may not appear inside of a template argument or in a function signature">; 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/Parse/Parser.h =================================================================== --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -1428,7 +1428,8 @@ }; ExprResult ParseExpression(TypeCastState isTypeCast = NotTypeCast); - ExprResult ParseConstantExpression(TypeCastState isTypeCast = NotTypeCast); + ExprResult ParseConstantExpression(TypeCastState isTypeCast = NotTypeCast, + bool IsLambdaExprForbidden = false); ExprResult ParseConstraintExpression(); // Expr that doesn't include commas. ExprResult ParseAssignmentExpression(TypeCastState isTypeCast = NotTypeCast); Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -891,15 +891,20 @@ /// expressions for which we have deferred checking the destructor. SmallVector DelayedDecltypeBinds; + /// \brief Whether lambda expressions are forbidden here. + bool IsLambdaExprForbidden; + ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, unsigned NumCleanupObjects, CleanupInfo ParentCleanup, Decl *ManglingContextDecl, - bool IsDecltype) + bool IsDecltype, + bool IsLambdaExprForbidden) : Context(Context), ParentCleanup(ParentCleanup), IsDecltype(IsDecltype), NumCleanupObjects(NumCleanupObjects), NumTypos(0), - ManglingContextDecl(ManglingContextDecl), MangleNumbering() { } + ManglingContextDecl(ManglingContextDecl), MangleNumbering(), + IsLambdaExprForbidden(IsLambdaExprForbidden) { } /// \brief Retrieve the mangling numbering context, used to consistently /// number constructs like lambdas for mangling. @@ -3764,11 +3769,13 @@ void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl = nullptr, - bool IsDecltype = false); + bool IsDecltype = false, + bool IsLambdaExprForbidden = false); enum ReuseLambdaContextDecl_t { ReuseLambdaContextDecl }; void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, ReuseLambdaContextDecl_t, - bool IsDecltype = false); + bool IsDecltype = false, + bool IsLambdaExprForbidden = false); void PopExpressionEvaluationContext(); void DiscardCleanupsInEvaluationContext(); @@ -10232,11 +10239,13 @@ Sema::ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl = nullptr, bool IsDecltype = false, - bool ShouldEnter = true) + bool ShouldEnter = true, + bool IsLambdaExprForbidden = false) : Actions(Actions), Entered(ShouldEnter) { if (Entered) Actions.PushExpressionEvaluationContext(NewContext, LambdaContextDecl, - IsDecltype); + IsDecltype, + IsLambdaExprForbidden); } EnterExpressionEvaluationContext(Sema &Actions, Sema::ExpressionEvaluationContext NewContext, Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -6250,7 +6250,8 @@ // Parse the constant-expression or assignment-expression now (depending // on dialect). if (getLangOpts().CPlusPlus) { - NumElements = ParseConstantExpression(); + NumElements = ParseConstantExpression(NotTypeCast, + /*IsLambdaExprForbidden=*/D.getContext() == D.PrototypeContext); } else { EnterExpressionEvaluationContext Unevaluated(Actions, Sema::ConstantEvaluated); Index: lib/Parse/ParseExpr.cpp =================================================================== --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -193,13 +193,18 @@ } -ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) { +ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast, + bool IsLambdaExprForbidden) { // C++03 [basic.def.odr]p2: // An expression is potentially evaluated unless it appears where an // integral constant expression is required (see 5.19) [...]. // C++98 and C++11 have no such rule, but this is only a defect in C++98. - EnterExpressionEvaluationContext ConstantEvaluated(Actions, - Sema::ConstantEvaluated); + EnterExpressionEvaluationContext ConstantEvaluated( + Actions, Sema::ConstantEvaluated, + /*LambdaContextDecl=*/nullptr, + /*IsDecltype=*/false, + /*ShouldEnter=*/true, + /*IsLambdaExprForbidden=*/IsLambdaExprForbidden); ExprResult LHS(ParseCastExpression(false, false, isTypeCast)); ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); Index: lib/Parse/ParseTemplate.cpp =================================================================== --- lib/Parse/ParseTemplate.cpp +++ lib/Parse/ParseTemplate.cpp @@ -701,8 +701,12 @@ // end of the template-parameter-list rather than a greater-than // operator. GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); - EnterExpressionEvaluationContext ConstantEvaluated(Actions, - Sema::ConstantEvaluated); + EnterExpressionEvaluationContext ConstantEvaluated( + Actions, Sema::ConstantEvaluated, + /*LambdaContextDecl=*/nullptr, + /*IsDecltype=*/false, + /*ShouldEnter=*/true, + /*IsLambdaExprForbidden*/true); DefaultArg = Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); if (DefaultArg.isInvalid()) @@ -1220,7 +1224,8 @@ // Parse a non-type template argument. SourceLocation Loc = Tok.getLocation(); - ExprResult ExprArg = ParseConstantExpression(MaybeTypeCast); + ExprResult ExprArg = ParseConstantExpression(MaybeTypeCast, + /*IsLambdaExprForbidden*/true); if (ExprArg.isInvalid() || !ExprArg.get()) return ParsedTemplateArgument(); Index: lib/Sema/Sema.cpp =================================================================== --- lib/Sema/Sema.cpp +++ lib/Sema/Sema.cpp @@ -123,7 +123,7 @@ Diags.SetArgToStringFn(&FormatASTNodeDiagnosticArgument, &Context); ExprEvalContexts.emplace_back(PotentiallyEvaluated, 0, CleanupInfo{}, nullptr, - false); + false, /*IsLambdaExprForbidden*/false); FunctionScopes.push_back(new FunctionScopeInfo(Diags)); Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -13083,9 +13083,11 @@ void Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl, - bool IsDecltype) { + bool IsDecltype, + bool IsLambdaExprForbidden) { ExprEvalContexts.emplace_back(NewContext, ExprCleanupObjects.size(), Cleanup, - LambdaContextDecl, IsDecltype); + LambdaContextDecl, IsDecltype, + IsLambdaExprForbidden); Cleanup.reset(); if (!MaybeODRUseExprs.empty()) std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs); @@ -13094,9 +13096,11 @@ void Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, ReuseLambdaContextDecl_t, - bool IsDecltype) { + bool IsDecltype, + bool IsLambdaExprForbidden) { Decl *ClosureContextDecl = ExprEvalContexts.back().ManglingContextDecl; - PushExpressionEvaluationContext(NewContext, ClosureContextDecl, IsDecltype); + PushExpressionEvaluationContext(NewContext, ClosureContextDecl, IsDecltype, + IsLambdaExprForbidden); } void Sema::PopExpressionEvaluationContext() { @@ -13117,6 +13121,8 @@ // evaluation of e, following the rules of the abstract machine, would // evaluate [...] a lambda-expression. D = diag::err_lambda_in_constant_expression; + if (getLangOpts().CPlusPlus1z && Rec.IsLambdaExprForbidden) + D = diag::err_lambda_in_potentially_mangled_constant_expression; } // C++1z allows lambda expressions as core constant expressions. @@ -13125,9 +13131,11 @@ // 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.Context != ConstantEvaluated || !getLangOpts().CPlusPlus1z) + if (Rec.Context != ConstantEvaluated || Rec.IsLambdaExprForbidden || + !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. Index: test/SemaCXX/cxx1z-constexpr-lambdas.cpp =================================================================== --- test/SemaCXX/cxx1z-constexpr-lambdas.cpp +++ test/SemaCXX/cxx1z-constexpr-lambdas.cpp @@ -157,6 +157,38 @@ } // end ns1_simple_lambda +namespace test_forbidden_lambda_expressions { + +template struct X { }; //expected-error{{lambda expression may not appear}} +X<[]{return 10; }()> x; //expected-error{{lambda expression may not appear}} +void f(int arr[([] { return 5; }())]); //expected-error{{lambda expression may not appear}} +// FIXME: Should this be ok? +auto L = [](int arr[([] { return 5; }())]) { }; // OK???? + +// These should be allowed: +struct A { + int : ([] { return 5; }()); +}; + +int arr[([] { return 5; }())]; +enum { E = [] { return 5; }() }; +static_assert([]{return 5; }() == 5); +int *ip = new int[([] { return 5; })()]; + +int test_case(int x) { + switch(x) { + case [] { return 5; }(): //OK + break; + case [] (auto a) { return a; }(6): //expected-note{{previous}} + break; + case 6: //expected-error{{duplicate}} + break; + } + return x; +} + +} // end ns forbidden_lambda_expressions + namespace ns1_unimplemented { namespace ns1_captures { constexpr auto f(int i) {