rymiel updated this revision to Diff 505499.
rymiel added a comment.

Slightly rewrite CheckForNonPrimary for slightly better clarity


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D146140/new/

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.
 
@@ -105,27 +106,35 @@
   QualType Type = ConstraintExpression->getType();
 
   auto CheckForNonPrimary = [&] {
-    if (PossibleNonPrimary)
-      *PossibleNonPrimary =
-          // We have the following case:
-          // template<typename> requires func(0) struct S { };
-          // 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) &&
-           (IsTrailingRequiresClause ||
-            (Type->isDependentType() &&
-             isa<UnresolvedLookupExpr>(ConstraintExpression)) ||
-            Type->isFunctionType() ||
-            Type->isSpecificBuiltinType(BuiltinType::Overload))) ||
-          // We have the following case:
-          // template<typename T> requires size_<T> == 0 struct S { };
-          // The user probably isn't aware of the parentheses required around
-          // the binary operator, and we're only going to parse 'func' as the
-          // first operand, and complain that it is of non-bool type.
-          getBinOpPrecedence(NextToken.getKind(),
-                             /*GreaterThanIsOperator=*/true,
-                             getLangOpts().CPlusPlus11) > prec::LogicalAnd;
+    if (!PossibleNonPrimary)
+      return;
+
+    *PossibleNonPrimary =
+        // We have the following case:
+        // template<typename> requires func(0) struct S { };
+        // 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.
+        //
+        // However, if we're in a lambda, this might also be:
+        // []<typename> requires var () {};
+        // Which also looks like a function call due to the lambda parentheses,
+        // but unlike the first case, isn't an error, so this check is skipped.
+        (NextToken.is(tok::l_paren) &&
+         (IsTrailingRequiresClause ||
+          (Type->isDependentType() &&
+           isa<UnresolvedLookupExpr>(ConstraintExpression) &&
+           !IsLambdaRequiresClause) ||
+          Type->isFunctionType() ||
+          Type->isSpecificBuiltinType(BuiltinType::Overload))) ||
+        // We have the following case:
+        // template<typename T> requires size_<T> == 0 struct S { };
+        // The user probably isn't aware of the parentheses required around
+        // the binary operator, and we're only going to parse 'func' as the
+        // first operand, and complain that it is of non-bool type.
+        getBinOpPrecedence(NextToken.getKind(),
+                           /*GreaterThanIsOperator=*/true,
+                           getLangOpts().CPlusPlus11) > prec::LogicalAnd;
   };
 
   // An atomic constraint!
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

Reply via email to