diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1776,8 +1776,11 @@ ExprResult ParseCaseExpression(SourceLocation CaseLoc); ExprResult ParseConstraintExpression(); ExprResult - ParseConstraintLogicalAndExpression(bool IsTrailingRequiresClause); - ExprResult ParseConstraintLogicalOrExpression(bool IsTrailingRequiresClause); + ParseConstraintLogicalAndExpression(bool IsTrailingRequiresClause, + bool IsLambdaRequiresClause = false); + ExprResult + ParseConstraintLogicalOrExpression(bool IsTrailingRequiresClause, + bool IsLambdaRequiresClause = false); // Expr that doesn't include commas. ExprResult ParseAssignmentExpression(TypeCastState isTypeCast = NotTypeCast); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7253,7 +7253,8 @@ /// non-primary expression being used as an atomic constraint. bool CheckConstraintExpression(const Expr *CE, Token NextToken = Token(), bool *PossibleNonPrimary = nullptr, - bool IsTrailingRequiresClause = false); + bool IsTrailingRequiresClause = false, + bool IsLambdaRequiresClause = false); private: /// Caches pairs of template-like decls whose associated constraints were diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -255,7 +255,8 @@ /// /// \endverbatim ExprResult -Parser::ParseConstraintLogicalAndExpression(bool IsTrailingRequiresClause) { +Parser::ParseConstraintLogicalAndExpression(bool IsTrailingRequiresClause, + bool IsLambdaRequiresClause) { EnterExpressionEvaluationContext ConstantEvaluated( Actions, Sema::ExpressionEvaluationContext::Unevaluated); bool NotPrimaryExpression = false; @@ -299,9 +300,9 @@ NotPrimaryExpression = false; } bool PossibleNonPrimary; - bool IsConstraintExpr = - Actions.CheckConstraintExpression(E.get(), Tok, &PossibleNonPrimary, - IsTrailingRequiresClause); + bool IsConstraintExpr = Actions.CheckConstraintExpression( + E.get(), Tok, &PossibleNonPrimary, IsTrailingRequiresClause, + IsLambdaRequiresClause); if (!IsConstraintExpr || PossibleNonPrimary) { // Atomic constraint might be an unparenthesized non-primary expression // (such as a binary operator), in which case we might get here (e.g. in @@ -347,14 +348,16 @@ /// /// \endverbatim ExprResult -Parser::ParseConstraintLogicalOrExpression(bool IsTrailingRequiresClause) { - ExprResult LHS(ParseConstraintLogicalAndExpression(IsTrailingRequiresClause)); +Parser::ParseConstraintLogicalOrExpression(bool IsTrailingRequiresClause, + bool IsLambdaRequiresClause) { + ExprResult LHS(ParseConstraintLogicalAndExpression(IsTrailingRequiresClause, + IsLambdaRequiresClause)); if (!LHS.isUsable()) return ExprError(); while (Tok.is(tok::pipepipe)) { SourceLocation LogicalOrLoc = ConsumeToken(); - ExprResult RHS = - ParseConstraintLogicalAndExpression(IsTrailingRequiresClause); + ExprResult RHS = ParseConstraintLogicalAndExpression( + IsTrailingRequiresClause, IsLambdaRequiresClause); if (!RHS.isUsable()) { Actions.CorrectDelayedTyposInExpr(LHS); return ExprError(); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1345,7 +1345,8 @@ if (TryConsumeToken(tok::kw_requires)) { RequiresClause = Actions.ActOnRequiresClause(ParseConstraintLogicalOrExpression( - /*IsTrailingRequiresClause=*/false)); + /*IsTrailingRequiresClause=*/false, + /*IsLambdaRequiresClause=*/true)); if (RequiresClause.isInvalid()) SkipUntil({tok::l_brace, tok::l_paren}, StopAtSemi | StopBeforeMatch); } diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -87,7 +87,8 @@ bool Sema::CheckConstraintExpression(const Expr *ConstraintExpression, Token NextToken, bool *PossibleNonPrimary, - bool IsTrailingRequiresClause) { + bool IsTrailingRequiresClause, + bool IsLambdaRequiresClause) { // C++2a [temp.constr.atomic]p1 // ..E shall be a constant expression of type bool. @@ -112,7 +113,7 @@ // The user probably isn't aware of the parentheses required around // the function call, and we're only going to parse 'func' as the // primary-expression, and complain that it is of non-bool type. - (NextToken.is(tok::l_paren) && + (NextToken.is(tok::l_paren) && !IsLambdaRequiresClause && (IsTrailingRequiresClause || (Type->isDependentType() && isa(ConstraintExpression)) || diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -55,10 +55,15 @@ } namespace P0857R0 { + template static constexpr bool V = true; + void f() { auto x = [] requires B {}; // expected-note {{constraints not satisfied}} expected-note {{false}} x.operator()(); x.operator()(); // expected-error {{no matching member function}} + + auto y = [] requires V () {}; + y.operator()(); // OK } template concept C = true;