rymiel created this revision. rymiel added a project: clang. rymiel added reviewers: aaron.ballman, erichkeane. Herald added a project: All. rymiel requested review of this revision. Herald added a subscriber: cfe-commits.
Since P0857, part of C++20, a *lambda-expression* can contain a *requires-clause* after its *template-parameter-list*. While support for this was added as part of eccc734a69c0c012ae3160887b65a535b35ead3e <https://reviews.llvm.org/rGeccc734a69c0c012ae3160887b65a535b35ead3e>, one specific case isn't handled properly, where the *requires-clause* consists of an instantiation of a boolean variable template. This is due to a diagnostic check which was written with the assumption that a *requires-clause* can never be followed by a left parenthesis. This assumption no longer holds for lambdas. This diagnostic check would then attempt to perform a "recovery", but it does so in a valid parse state, resulting in an invalid parse state instead! This patch adds a special case when parsing requires clauses of lambda templates, to skip this diagnostic check. Fixes https://github.com/llvm/llvm-project/issues/61278 Fixes https://github.com/llvm/llvm-project/issues/61387 Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D146140 Files: clang/include/clang/Parse/Parser.h clang/include/clang/Sema/Sema.h clang/lib/Parse/ParseExpr.cpp clang/lib/Parse/ParseExprCXX.cpp clang/lib/Sema/SemaConcept.cpp clang/test/SemaTemplate/concepts.cpp
Index: clang/test/SemaTemplate/concepts.cpp =================================================================== --- clang/test/SemaTemplate/concepts.cpp +++ clang/test/SemaTemplate/concepts.cpp @@ -55,10 +55,15 @@ } namespace P0857R0 { + template <typename T> static constexpr bool V = true; + void f() { auto x = []<bool B> requires B {}; // expected-note {{constraints not satisfied}} expected-note {{false}} x.operator()<true>(); x.operator()<false>(); // expected-error {{no matching member function}} + + auto y = []<typename T> requires V<T> () {}; + y.operator()<int>(); // OK } template<typename T> concept C = true; Index: clang/lib/Sema/SemaConcept.cpp =================================================================== --- clang/lib/Sema/SemaConcept.cpp +++ 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<UnresolvedLookupExpr>(ConstraintExpression)) || Index: clang/lib/Parse/ParseExprCXX.cpp =================================================================== --- clang/lib/Parse/ParseExprCXX.cpp +++ 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); } Index: clang/lib/Parse/ParseExpr.cpp =================================================================== --- clang/lib/Parse/ParseExpr.cpp +++ 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(); Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ 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 Index: clang/include/clang/Parse/Parser.h =================================================================== --- clang/include/clang/Parse/Parser.h +++ 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);
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits