[clang] a99b8ae - [clang] [PR49736] [C++2b] Correctly reject lambdas with requires clause and no parameter list

Marek Kurdej via cfe-commits cfe-commits at lists.llvm.org
Tue Mar 30 04:54:02 PDT 2021


Author: Marek Kurdej
Date: 2021-03-30T13:53:55+02:00
New Revision: a99b8ae3909106d831d880c1647dabe92f470290

URL: https://github.com/llvm/llvm-project/commit/a99b8ae3909106d831d880c1647dabe92f470290
DIFF: https://github.com/llvm/llvm-project/commit/a99b8ae3909106d831d880c1647dabe92f470290.diff

LOG: [clang] [PR49736] [C++2b] Correctly reject lambdas with requires clause and no parameter list

This fixes http://llvm.org/PR49736 caused by implementing http://wg21.link/P1102 (https://reviews.llvm.org/rG0620e6f4b76a9725dbd82454d58c5a68a7e47074), by correctly allowing requires-clause only:
1) directly after template-parameter-list
2) after lambda-specifiers iff parameter-declaration-clause is present (2nd kind of lambda-declarator)

Reviewed By: aaron.ballman

Differential Revision: https://reviews.llvm.org/D99489

Added: 
    

Modified: 
    clang/lib/Parse/ParseExprCXX.cpp
    clang/test/Parser/cxx-concepts-requires-clause.cpp
    clang/test/Parser/cxx2a-template-lambdas.cpp
    clang/test/Parser/cxx2b-lambdas.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index c2e74b5a7bbd..644df55bf46e 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -690,7 +690,7 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
 ///       lambda-expression:
 ///         lambda-introducer lambda-declarator compound-statement
 ///         lambda-introducer '<' template-parameter-list '>'
-///             lambda-declarator compound-statement
+///             requires-clause[opt] lambda-declarator compound-statement
 ///
 ///       lambda-introducer:
 ///         '[' lambda-capture[opt] ']'
@@ -1392,12 +1392,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
                 /*DeclsInPrototype=*/None, LParenLoc, FunLocalRangeEnd, D,
                 TrailingReturnType, TrailingReturnTypeLoc, &DS),
             std::move(Attr), DeclEndLoc);
-
-        // Parse requires-clause[opt].
-        if (Tok.is(tok::kw_requires))
-          ParseTrailingRequiresClause(D);
-
-        WarnIfHasCUDATargetAttr();
       };
 
   if (Tok.is(tok::l_paren)) {
@@ -1433,6 +1427,10 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
     // Parse lambda-specifiers.
     ParseLambdaSpecifiers(LParenLoc, /*DeclEndLoc=*/T.getCloseLocation(),
                           ParamInfo, EllipsisLoc);
+
+    // Parse requires-clause[opt].
+    if (Tok.is(tok::kw_requires))
+      ParseTrailingRequiresClause(D);
   } else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute,
                          tok::kw_constexpr, tok::kw_consteval,
                          tok::kw___private, tok::kw___global, tok::kw___local,
@@ -1453,6 +1451,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
                           EmptyParamInfo, /*EllipsisLoc=*/NoLoc);
   }
 
+  WarnIfHasCUDATargetAttr();
+
   // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using
   // it.
   unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope |

diff  --git a/clang/test/Parser/cxx-concepts-requires-clause.cpp b/clang/test/Parser/cxx-concepts-requires-clause.cpp
index 4d6d166d6fef..68f1af8b12cc 100644
--- a/clang/test/Parser/cxx-concepts-requires-clause.cpp
+++ b/clang/test/Parser/cxx-concepts-requires-clause.cpp
@@ -154,7 +154,9 @@ auto lambda1 = [] (auto x) requires (sizeof(decltype(x)) == 1) { };
 
 auto lambda2 = [] (auto x) constexpr -> int requires (sizeof(decltype(x)) == 1) { return 0; };
 
-auto lambda3 = [] requires (sizeof(char) == 1) { };
+auto lambda3 = []<auto> requires(sizeof(char) == 1){};
+
+auto lambda4 = [] requires(sizeof(char) == 1){}; // expected-error {{expected body of lambda expression}}
 #if __cplusplus <= 202002L
-// expected-warning at -2{{is a C++2b extension}}
+// expected-warning at -2{{lambda without a parameter clause is a C++2b extension}}
 #endif

diff  --git a/clang/test/Parser/cxx2a-template-lambdas.cpp b/clang/test/Parser/cxx2a-template-lambdas.cpp
index 2a2305b5530c..f85280f7ece5 100644
--- a/clang/test/Parser/cxx2a-template-lambdas.cpp
+++ b/clang/test/Parser/cxx2a-template-lambdas.cpp
@@ -7,3 +7,28 @@ auto L1 = []<typename T1, typename T2> { };
 auto L2 = []<typename T1, typename T2>(T1 arg1, T2 arg2) -> T1 { };
 auto L3 = []<typename T>(auto arg) { T t; };
 auto L4 = []<int I>() { };
+
+// http://llvm.org/PR49736
+auto L5 = []<auto>(){};
+auto L6 = []<auto>{};
+auto L7 = []<auto>() noexcept {};
+auto L8 = []<auto> noexcept {};
+#if __cplusplus <= 202002L
+// expected-warning at -2 {{lambda without a parameter clause is a C++2b extension}}
+#endif
+auto L9 = []<auto> requires true {};
+auto L10 = []<auto> requires true(){};
+auto L11 = []<auto> requires true() noexcept {};
+auto L12 = []<auto> requires true noexcept {};
+#if __cplusplus <= 202002L
+// expected-warning at -2 {{is a C++2b extension}}
+#endif
+auto L13 = []<auto>() noexcept requires true {};
+auto L14 = []<auto> requires true() noexcept requires true {};
+
+auto XL0 = []<auto> noexcept requires true {};               // expected-error {{expected body of lambda expression}}
+auto XL1 = []<auto> requires true noexcept requires true {}; // expected-error {{expected body}}
+#if __cplusplus <= 202002L
+// expected-warning at -3 {{is a C++2b extension}}
+// expected-warning at -3 {{is a C++2b extension}}
+#endif

diff  --git a/clang/test/Parser/cxx2b-lambdas.cpp b/clang/test/Parser/cxx2b-lambdas.cpp
index e008dc8f2d36..57e81eed7b9e 100644
--- a/clang/test/Parser/cxx2b-lambdas.cpp
+++ b/clang/test/Parser/cxx2b-lambdas.cpp
@@ -18,13 +18,14 @@ auto L9 = []<typename T> { return true; };
 auto L10 = []<typename T> noexcept { return true; };
 auto L11 = []<typename T> -> bool { return true; };
 auto L12 = [] consteval {};
-auto L13 = [] requires requires() { true; }
-{};
-auto L15 = [] [[maybe_unused]]{};
+auto L13 = []() requires true {};
+auto L14 = []<auto> requires true() requires true {};
+auto L15 = []<auto> requires true noexcept {};
+auto L16 = [] [[maybe_unused]]{};
 
 auto XL0 = [] mutable constexpr mutable {};    // expected-error{{cannot appear multiple times}}
 auto XL1 = [] constexpr mutable constexpr {};  // expected-error{{cannot appear multiple times}}
-auto XL2 = []) constexpr mutable constexpr {}; // expected-error{{expected body}}
+auto XL2 = []) constexpr mutable constexpr {}; // expected-error{{expected body of lambda expression}}
 auto XL3 = []( constexpr mutable constexpr {}; // expected-error{{invalid storage class specifier}} \
                                                // expected-error{{function parameter cannot be constexpr}} \
                                                // expected-error{{C++ requires}} \
@@ -32,3 +33,8 @@ auto XL3 = []( constexpr mutable constexpr {}; // expected-error{{invalid storag
                                                // expected-note{{to match this '('}} \
                                                // expected-error{{expected body}} \
                                                // expected-warning{{duplicate 'constexpr'}}
+
+// http://llvm.org/PR49736
+auto XL4 = [] requires true {}; // expected-error{{expected body}}
+auto XL5 = []<auto> requires true requires true {}; // expected-error{{expected body}}
+auto XL6 = []<auto> requires true noexcept requires true {}; // expected-error{{expected body}}


        


More information about the cfe-commits mailing list