Rakete1111 created this revision. This revision disallows lambdas in template parameters, as reported in PR33696.
https://reviews.llvm.org/D37442 Files: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/Parse/ParseTemplate.cpp lib/Sema/Sema.cpp lib/Sema/SemaExpr.cpp test/CXX/expr/expr.prim/expr.prim.lambda/p2-template-parameter.cpp
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,8 @@ +// RUN: %clang_cc1 -std=c++17 %s -verify + +template<auto> struct Nothing {}; + +void pr33696() { + Nothing<[]() { return 0; }()> nothing; // expected-error{{a lambda expression cannot appear in this context}} +} + Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -13355,9 +13355,10 @@ void Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl, - bool IsDecltype) { + bool IsDecltype, + bool IsLambdaValid) { ExprEvalContexts.emplace_back(NewContext, ExprCleanupObjects.size(), Cleanup, - LambdaContextDecl, IsDecltype); + LambdaContextDecl, IsDecltype, IsLambdaValid); Cleanup.reset(); if (!MaybeODRUseExprs.empty()) std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs); @@ -13366,9 +13367,11 @@ void Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, ReuseLambdaContextDecl_t, - bool IsDecltype) { + bool IsDecltype, + bool IsLambdaValid) { Decl *ClosureContextDecl = ExprEvalContexts.back().ManglingContextDecl; - PushExpressionEvaluationContext(NewContext, ClosureContextDecl, IsDecltype); + PushExpressionEvaluationContext(NewContext, ClosureContextDecl, IsDecltype, + IsLambdaValid); } void Sema::PopExpressionEvaluationContext() { @@ -13376,7 +13379,8 @@ unsigned NumTypos = Rec.NumTypos; if (!Rec.Lambdas.empty()) { - if (Rec.isUnevaluated() || Rec.isConstantEvaluated()) { + if (!Rec.IsLambdaValid || Rec.isUnevaluated() || + (Rec.isConstantEvaluated() && !getLangOpts().CPlusPlus1z)) { unsigned D; if (Rec.isUnevaluated()) { // C++11 [expr.prim.lambda]p2: @@ -13383,23 +13387,21 @@ // A lambda-expression shall not appear in an unevaluated operand // (Clause 5). D = diag::err_lambda_unevaluated_operand; - } else { + } else if (Rec.isConstantEvaluated() && !getLangOpts().CPlusPlus1z) { // 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.IsLambdaValid) { + // C++17 [expr.prim.lambda]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().CPlusPlus1z) - 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. Index: lib/Sema/Sema.cpp =================================================================== --- lib/Sema/Sema.cpp +++ lib/Sema/Sema.cpp @@ -159,7 +159,7 @@ ExprEvalContexts.emplace_back( ExpressionEvaluationContext::PotentiallyEvaluated, 0, CleanupInfo{}, - nullptr, false); + nullptr, false, true); FunctionScopes.push_back(new FunctionScopeInfo(Diags)); Index: lib/Parse/ParseTemplate.cpp =================================================================== --- lib/Parse/ParseTemplate.cpp +++ lib/Parse/ParseTemplate.cpp @@ -1189,7 +1189,9 @@ // argument before trying to disambiguate. EnterExpressionEvaluationContext EnterConstantEvaluated( - Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); + Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated, + /*LambdaContextDecl=*/nullptr, /*IsDecltype=*/false, + /*ShouldEnter=*/true, /*IsLambdaValid=*/false); if (isCXXTypeId(TypeIdAsTemplateArgument)) { SourceLocation Loc = Tok.getLocation(); TypeResult TypeArg = ParseTypeName(/*Range=*/nullptr, Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -934,6 +934,10 @@ /// \brief Whether we are in a decltype expression. bool IsDecltype; + /// \brief Whether we are in an expression where lambdas + /// are disallowed (such as template parameters). + bool IsLambdaValid; + /// \brief The number of active cleanup objects when we entered /// this expression evaluation context. unsigned NumCleanupObjects; @@ -972,10 +976,11 @@ unsigned NumCleanupObjects, CleanupInfo ParentCleanup, Decl *ManglingContextDecl, - bool IsDecltype) + bool IsDecltype, + bool IsLambdaValid) : Context(Context), ParentCleanup(ParentCleanup), - IsDecltype(IsDecltype), NumCleanupObjects(NumCleanupObjects), - NumTypos(0), + IsDecltype(IsDecltype), IsLambdaValid(IsLambdaValid), + NumCleanupObjects(NumCleanupObjects), NumTypos(0), ManglingContextDecl(ManglingContextDecl), MangleNumbering() { } /// \brief Retrieve the mangling numbering context, used to consistently @@ -3926,11 +3931,13 @@ void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl = nullptr, - bool IsDecltype = false); + bool IsDecltype = false, + bool IsLambdaValid = true); enum ReuseLambdaContextDecl_t { ReuseLambdaContextDecl }; void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, ReuseLambdaContextDecl_t, - bool IsDecltype = false); + bool IsDecltype = false, + bool IsLambdaValid = true); void PopExpressionEvaluationContext(); void DiscardCleanupsInEvaluationContext(); @@ -10546,20 +10553,22 @@ Sema::ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl = nullptr, bool IsDecltype = false, - bool ShouldEnter = true) + bool ShouldEnter = true, + bool IsLambdaValid = true) : Actions(Actions), Entered(ShouldEnter) { if (Entered) Actions.PushExpressionEvaluationContext(NewContext, LambdaContextDecl, - IsDecltype); + IsDecltype, IsLambdaValid); } EnterExpressionEvaluationContext(Sema &Actions, Sema::ExpressionEvaluationContext NewContext, Sema::ReuseLambdaContextDecl_t, - bool IsDecltype = false) + bool IsDecltype = false, + bool IsLambdaValid = true) : Actions(Actions) { Actions.PushExpressionEvaluationContext(NewContext, Sema::ReuseLambdaContextDecl, - IsDecltype); + IsDecltype, IsLambdaValid); } enum InitListTag { InitList }; Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -6506,6 +6506,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<
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits