[clang] 0620e6f - [clang] [C++2b] [P1102] Accept lambdas without parameter list ().

Marek Kurdej via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 24 06:42:34 PDT 2021


Author: Marek Kurdej
Date: 2021-03-24T14:42:27+01:00
New Revision: 0620e6f4b76a9725dbd82454d58c5a68a7e47074

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

LOG: [clang] [C++2b] [P1102] Accept lambdas without parameter list ().

As an extension, accept such lambdas in previous standards with a warning.

* http://eel.is/c++draft/expr.prim.lambda
* http://wg21.link/P1102

Reviewed By: aaron.ballman

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

Added: 
    clang/test/Parser/cxx2b-lambdas.cpp

Modified: 
    clang/include/clang/Basic/DiagnosticParseKinds.td
    clang/lib/Parse/ParseExprCXX.cpp
    clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp
    clang/test/FixIt/fixit-c++11.cpp
    clang/test/Parser/cxx-concepts-requires-clause.cpp
    clang/test/Parser/cxx0x-lambda-expressions.cpp
    clang/test/Parser/cxx1z-constexpr-lambdas.cpp
    clang/test/Parser/cxx2a-template-lambdas.cpp
    clang/test/SemaOpenCLCXX/address-space-lambda.clcpp
    clang/www/cxx_status.html

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 7957fb8b75a4..b0f9b317a020 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -949,9 +949,6 @@ def err_expected_lambda_body : Error<"expected body of lambda expression">;
 def warn_cxx98_compat_lambda : Warning<
   "lambda expressions are incompatible with C++98">,
   InGroup<CXX98Compat>, DefaultIgnore;
-def err_lambda_missing_parens : Error<
-  "lambda requires '()' before %select{'mutable'|return type|"
-  "attribute specifier|'constexpr'|'consteval'|'requires' clause}0">;
 def err_lambda_decl_specifier_repeated : Error<
   "%select{'mutable'|'constexpr'|'consteval'}0 cannot appear multiple times in a lambda declarator">;
 def err_lambda_capture_misplaced_ellipsis : Error<
@@ -964,6 +961,9 @@ def err_capture_default_first : Error<
 def ext_decl_attrs_on_lambda : ExtWarn<
   "an attribute specifier sequence in this position is a C++2b extension">,
   InGroup<CXX2b>;
+def ext_lambda_missing_parens : ExtWarn<
+  "lambda without a parameter clause is a C++2b extension">,
+  InGroup<CXX2b>;
 def warn_cxx20_compat_decl_attrs_on_lambda : Warning<
   "an attribute specifier sequence in this position is incompatible with C++ "
   "standards before C++2b">, InGroup<CXXPre2bCompat>, DefaultIgnore;

diff  --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index befa7709f2d9..c2e74b5a7bbd 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -688,9 +688,9 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
 /// ParseLambdaExpression - Parse a C++11 lambda expression.
 ///
 ///       lambda-expression:
-///         lambda-introducer lambda-declarator[opt] compound-statement
+///         lambda-introducer lambda-declarator compound-statement
 ///         lambda-introducer '<' template-parameter-list '>'
-///             lambda-declarator[opt] compound-statement
+///             lambda-declarator compound-statement
 ///
 ///       lambda-introducer:
 ///         '[' lambda-capture[opt] ']'
@@ -722,9 +722,13 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
 ///         '&' identifier initializer
 ///
 ///       lambda-declarator:
-///         '(' parameter-declaration-clause ')' attribute-specifier[opt]
-///           'mutable'[opt] exception-specification[opt]
-///           trailing-return-type[opt]
+///         lambda-specifiers     [C++2b]
+///         '(' parameter-declaration-clause ')' lambda-specifiers
+///             requires-clause[opt]
+///
+///       lambda-specifiers:
+///         decl-specifier-seq[opt] noexcept-specifier[opt]
+///             attribute-specifier-seq[opt] trailing-return-type[opt]
 ///
 ExprResult Parser::ParseLambdaExpression() {
   // Parse lambda-introducer.
@@ -1249,7 +1253,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
   Actions.PushLambdaScope();
 
   ParsedAttributes Attr(AttrFactory);
-  SourceLocation DeclLoc = Tok.getLocation();
   if (getLangOpts().CUDA) {
     // In CUDA code, GNU attributes are allowed to appear immediately after the
     // "[...]", even if there is no "(...)" before the lambda body.
@@ -1315,11 +1318,92 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
 
   TypeResult TrailingReturnType;
   SourceLocation TrailingReturnTypeLoc;
+
+  auto ParseLambdaSpecifiers =
+      [&](SourceLocation LParenLoc, SourceLocation RParenLoc,
+          MutableArrayRef<DeclaratorChunk::ParamInfo> ParamInfo,
+          SourceLocation EllipsisLoc) {
+        SourceLocation DeclEndLoc = RParenLoc;
+
+        // GNU-style attributes must be parsed before the mutable specifier to
+        // be compatible with GCC. MSVC-style attributes must be parsed before
+        // the mutable specifier to be compatible with MSVC.
+        MaybeParseAttributes(PAKM_GNU | PAKM_Declspec, Attr);
+
+        // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update
+        // the DeclEndLoc.
+        SourceLocation MutableLoc;
+        SourceLocation ConstexprLoc;
+        SourceLocation ConstevalLoc;
+        tryConsumeLambdaSpecifierToken(*this, MutableLoc, ConstexprLoc,
+                                       ConstevalLoc, DeclEndLoc);
+
+        addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS);
+        addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS);
+        // Parse exception-specification[opt].
+        ExceptionSpecificationType ESpecType = EST_None;
+        SourceRange ESpecRange;
+        SmallVector<ParsedType, 2> DynamicExceptions;
+        SmallVector<SourceRange, 2> DynamicExceptionRanges;
+        ExprResult NoexceptExpr;
+        CachedTokens *ExceptionSpecTokens;
+        ESpecType = tryParseExceptionSpecification(
+            /*Delayed=*/false, ESpecRange, DynamicExceptions,
+            DynamicExceptionRanges, NoexceptExpr, ExceptionSpecTokens);
+
+        if (ESpecType != EST_None)
+          DeclEndLoc = ESpecRange.getEnd();
+
+        // Parse attribute-specifier[opt].
+        MaybeParseCXX11Attributes(Attr, &DeclEndLoc);
+
+        // Parse OpenCL addr space attribute.
+        if (Tok.isOneOf(tok::kw___private, tok::kw___global, tok::kw___local,
+                        tok::kw___constant, tok::kw___generic)) {
+          ParseOpenCLQualifiers(DS.getAttributes());
+          ConsumeToken();
+        }
+
+        SourceLocation FunLocalRangeEnd = DeclEndLoc;
+
+        // Parse trailing-return-type[opt].
+        if (Tok.is(tok::arrow)) {
+          FunLocalRangeEnd = Tok.getLocation();
+          SourceRange Range;
+          TrailingReturnType = ParseTrailingReturnType(
+              Range, /*MayBeFollowedByDirectInit*/ false);
+          TrailingReturnTypeLoc = Range.getBegin();
+          if (Range.getEnd().isValid())
+            DeclEndLoc = Range.getEnd();
+        }
+
+        SourceLocation NoLoc;
+        D.AddTypeInfo(
+            DeclaratorChunk::getFunction(
+                /*HasProto=*/true,
+                /*IsAmbiguous=*/false, LParenLoc, ParamInfo.data(),
+                ParamInfo.size(), EllipsisLoc, RParenLoc,
+                /*RefQualifierIsLvalueRef=*/true,
+                /*RefQualifierLoc=*/NoLoc, MutableLoc, ESpecType, ESpecRange,
+                DynamicExceptions.data(), DynamicExceptionRanges.data(),
+                DynamicExceptions.size(),
+                NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr,
+                /*ExceptionSpecTokens*/ nullptr,
+                /*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)) {
-    ParseScope PrototypeScope(this,
-                              Scope::FunctionPrototypeScope |
-                              Scope::FunctionDeclarationScope |
-                              Scope::DeclScope);
+    ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
+                                        Scope::FunctionDeclarationScope |
+                                        Scope::DeclScope);
 
     BalancedDelimiterTracker T(*this, tok::l_paren);
     T.consumeOpen();
@@ -1345,165 +1429,28 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
     }
 
     T.consumeClose();
-    SourceLocation RParenLoc = T.getCloseLocation();
-    SourceLocation DeclEndLoc = RParenLoc;
-
-    // GNU-style attributes must be parsed before the mutable specifier to be
-    // compatible with GCC. MSVC-style attributes must be parsed before the
-    // mutable specifier to be compatible with MSVC.
-    MaybeParseAttributes(PAKM_GNU | PAKM_Declspec, Attr);
-
-    // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update the
-    // DeclEndLoc.
-    SourceLocation MutableLoc;
-    SourceLocation ConstexprLoc;
-    SourceLocation ConstevalLoc;
-    tryConsumeLambdaSpecifierToken(*this, MutableLoc, ConstexprLoc,
-                                   ConstevalLoc, DeclEndLoc);
-
-    addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS);
-    addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS);
-    // Parse exception-specification[opt].
-    ExceptionSpecificationType ESpecType = EST_None;
-    SourceRange ESpecRange;
-    SmallVector<ParsedType, 2> DynamicExceptions;
-    SmallVector<SourceRange, 2> DynamicExceptionRanges;
-    ExprResult NoexceptExpr;
-    CachedTokens *ExceptionSpecTokens;
-    ESpecType = tryParseExceptionSpecification(/*Delayed=*/false,
-                                               ESpecRange,
-                                               DynamicExceptions,
-                                               DynamicExceptionRanges,
-                                               NoexceptExpr,
-                                               ExceptionSpecTokens);
-
-    if (ESpecType != EST_None)
-      DeclEndLoc = ESpecRange.getEnd();
-
-    // Parse attribute-specifier[opt].
-    MaybeParseCXX11Attributes(Attr, &DeclEndLoc);
-
-    // Parse OpenCL addr space attribute.
-    if (Tok.isOneOf(tok::kw___private, tok::kw___global, tok::kw___local,
-                    tok::kw___constant, tok::kw___generic)) {
-      ParseOpenCLQualifiers(DS.getAttributes());
-      ConsumeToken();
-    }
 
-    SourceLocation FunLocalRangeEnd = DeclEndLoc;
-
-    // Parse trailing-return-type[opt].
-    if (Tok.is(tok::arrow)) {
-      FunLocalRangeEnd = Tok.getLocation();
-      SourceRange Range;
-      TrailingReturnType =
-          ParseTrailingReturnType(Range, /*MayBeFollowedByDirectInit*/ false);
-      TrailingReturnTypeLoc = Range.getBegin();
-      if (Range.getEnd().isValid())
-        DeclEndLoc = Range.getEnd();
-    }
-
-    SourceLocation NoLoc;
-    D.AddTypeInfo(DeclaratorChunk::getFunction(
-                      /*HasProto=*/true,
-                      /*IsAmbiguous=*/false, LParenLoc, ParamInfo.data(),
-                      ParamInfo.size(), EllipsisLoc, RParenLoc,
-                      /*RefQualifierIsLvalueRef=*/true,
-                      /*RefQualifierLoc=*/NoLoc, MutableLoc, ESpecType,
-                      ESpecRange, DynamicExceptions.data(),
-                      DynamicExceptionRanges.data(), DynamicExceptions.size(),
-                      NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr,
-                      /*ExceptionSpecTokens*/ nullptr,
-                      /*DeclsInPrototype=*/None, LParenLoc, FunLocalRangeEnd, D,
-                      TrailingReturnType, TrailingReturnTypeLoc, &DS),
-                  std::move(Attr), DeclEndLoc);
-
-    // Parse requires-clause[opt].
-    if (Tok.is(tok::kw_requires))
-      ParseTrailingRequiresClause(D);
-
-    PrototypeScope.Exit();
-
-    WarnIfHasCUDATargetAttr();
+    // Parse lambda-specifiers.
+    ParseLambdaSpecifiers(LParenLoc, /*DeclEndLoc=*/T.getCloseLocation(),
+                          ParamInfo, EllipsisLoc);
   } 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,
                          tok::kw___constant, tok::kw___generic,
-                         tok::kw_requires) ||
+                         tok::kw_requires, tok::kw_noexcept) ||
              (Tok.is(tok::l_square) && NextToken().is(tok::l_square))) {
-    // It's common to forget that one needs '()' before 'mutable', an attribute
-    // specifier, the result type, or the requires clause. Deal with this.
-    unsigned TokKind = 0;
-    switch (Tok.getKind()) {
-    case tok::kw_mutable: TokKind = 0; break;
-    case tok::arrow: TokKind = 1; break;
-    case tok::kw___attribute:
-    case tok::kw___private:
-    case tok::kw___global:
-    case tok::kw___local:
-    case tok::kw___constant:
-    case tok::kw___generic:
-    case tok::l_square: TokKind = 2; break;
-    case tok::kw_constexpr: TokKind = 3; break;
-    case tok::kw_consteval: TokKind = 4; break;
-    case tok::kw_requires: TokKind = 5; break;
-    default: llvm_unreachable("Unknown token kind");
-    }
-
-    Diag(Tok, diag::err_lambda_missing_parens)
-      << TokKind
-      << FixItHint::CreateInsertion(Tok.getLocation(), "() ");
-    SourceLocation DeclEndLoc = DeclLoc;
-
-    // GNU-style attributes must be parsed before the mutable specifier to be
-    // compatible with GCC.
-    MaybeParseGNUAttributes(Attr, &DeclEndLoc);
-
-    // Parse 'mutable', if it's there.
-    SourceLocation MutableLoc;
-    if (Tok.is(tok::kw_mutable)) {
-      MutableLoc = ConsumeToken();
-      DeclEndLoc = MutableLoc;
-    }
-
-    // Parse attribute-specifier[opt].
-    MaybeParseCXX11Attributes(Attr, &DeclEndLoc);
-
-    // Parse the return type, if there is one.
-    if (Tok.is(tok::arrow)) {
-      SourceRange Range;
-      TrailingReturnType =
-          ParseTrailingReturnType(Range, /*MayBeFollowedByDirectInit*/ false);
-      if (Range.getEnd().isValid())
-        DeclEndLoc = Range.getEnd();
-    }
+    if (!getLangOpts().CPlusPlus2b)
+      // It's common to forget that one needs '()' before 'mutable', an
+      // attribute specifier, the result type, or the requires clause. Deal with
+      // this.
+      Diag(Tok, diag::ext_lambda_missing_parens)
+          << FixItHint::CreateInsertion(Tok.getLocation(), "() ");
 
     SourceLocation NoLoc;
-    D.AddTypeInfo(DeclaratorChunk::getFunction(
-                      /*HasProto=*/true,
-                      /*IsAmbiguous=*/false,
-                      /*LParenLoc=*/NoLoc,
-                      /*Params=*/nullptr,
-                      /*NumParams=*/0,
-                      /*EllipsisLoc=*/NoLoc,
-                      /*RParenLoc=*/NoLoc,
-                      /*RefQualifierIsLvalueRef=*/true,
-                      /*RefQualifierLoc=*/NoLoc, MutableLoc, EST_None,
-                      /*ESpecRange=*/SourceRange(),
-                      /*Exceptions=*/nullptr,
-                      /*ExceptionRanges=*/nullptr,
-                      /*NumExceptions=*/0,
-                      /*NoexceptExpr=*/nullptr,
-                      /*ExceptionSpecTokens=*/nullptr,
-                      /*DeclsInPrototype=*/None, DeclLoc, DeclEndLoc, D,
-                      TrailingReturnType),
-                  std::move(Attr), DeclEndLoc);
-
-    // Parse the requires-clause, if present.
-    if (Tok.is(tok::kw_requires))
-      ParseTrailingRequiresClause(D);
-
-    WarnIfHasCUDATargetAttr();
+    // Parse lambda-specifiers.
+    std::vector<DeclaratorChunk::ParamInfo> EmptyParamInfo;
+    ParseLambdaSpecifiers(/*LParenLoc=*/NoLoc, /*RParenLoc=*/NoLoc,
+                          EmptyParamInfo, /*EllipsisLoc=*/NoLoc);
   }
 
   // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using

diff  --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp
index f8461335b768..f2b0e26e29f9 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp
@@ -52,7 +52,10 @@ int test_no_parameter_list()
 {
   static int si = 0;
     auto M = [] { return 5; }; // OK
-    auto M2 = [] -> auto&& { return si; }; // expected-error{{lambda requires '()'}}
+    auto M2 = [] -> auto && { return si; };
+#if __cplusplus <= 202002L
+      // expected-warning at -2{{is a C++2b extension}}
+#endif
     M();
 }
 

diff  --git a/clang/test/FixIt/fixit-c++11.cpp b/clang/test/FixIt/fixit-c++11.cpp
index 70342075a15e..9a2020c41870 100644
--- a/clang/test/FixIt/fixit-c++11.cpp
+++ b/clang/test/FixIt/fixit-c++11.cpp
@@ -56,8 +56,12 @@ void S2::f(int i) {
   (void)[&, &i, &i]{}; // expected-error 2{{'&' cannot precede a capture when the capture default is '&'}}
   (void)[i, i]{ }; // expected-error{{'i' can appear only once in a capture list}}
   (void)[&, i, i]{ }; // expected-error{{'i' can appear only once in a capture list}}
-  (void)[] mutable { }; // expected-error{{lambda requires '()' before 'mutable'}}
-  (void)[] -> int { }; // expected-error{{lambda requires '()' before return type}}
+  (void)[] mutable {};
+  (void)[]->int{};
+#if __cplusplus <= 202002L
+  // expected-warning at -3{{is a C++2b extension}}
+  // expected-warning at -3{{is a C++2b extension}}
+#endif
 
   delete []() { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
   delete [] { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}

diff  --git a/clang/test/Parser/cxx-concepts-requires-clause.cpp b/clang/test/Parser/cxx-concepts-requires-clause.cpp
index 9cef4c64ee96..4d6d166d6fef 100644
--- a/clang/test/Parser/cxx-concepts-requires-clause.cpp
+++ b/clang/test/Parser/cxx-concepts-requires-clause.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -std=c++2a -x c++ %s -verify
+// RUN: %clang_cc1 -std=c++2b -x c++ %s -verify
 
 // Test parsing of the optional requires-clause in a template-declaration.
 
@@ -154,4 +155,6 @@ 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) { };
-// expected-error at -1{{lambda requires '()' before 'requires' clause}}
\ No newline at end of file
+#if __cplusplus <= 202002L
+// expected-warning at -2{{is a C++2b extension}}
+#endif

diff  --git a/clang/test/Parser/cxx0x-lambda-expressions.cpp b/clang/test/Parser/cxx0x-lambda-expressions.cpp
index 3148c73a4069..00a9b70ccd01 100644
--- a/clang/test/Parser/cxx0x-lambda-expressions.cpp
+++ b/clang/test/Parser/cxx0x-lambda-expressions.cpp
@@ -1,5 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++11 -Wno-c99-designator %s
 // RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++2a -Wno-c99-designator %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++2b -Wno-c99-designator %s
 
 enum E { e };
 
@@ -17,7 +18,7 @@ class C {
     [&this] {}; // expected-error {{'this' cannot be captured by reference}}
     [&,] {}; // expected-error {{expected variable name or 'this' in lambda capture list}}
     [=,] {}; // expected-error {{expected variable name or 'this' in lambda capture list}}
-    [] {}; 
+    [] {};
     [=] (int i) {}; 
     [&] (int) mutable -> void {}; 
     [foo,bar] () { return 3; }; 
@@ -27,8 +28,12 @@ class C {
     [] () -> class C { return C(); };
     [] () -> enum E { return e; };
 
-    [] -> int { return 0; }; // expected-error{{lambda requires '()' before return type}}
-    [] mutable -> int { return 0; }; // expected-error{{lambda requires '()' before 'mutable'}}
+    [] -> int { return 0; };
+    [] mutable -> int { return 0; };
+#if __cplusplus <= 202002L
+    // expected-warning at -3 {{lambda without a parameter clause is a C++2b extension}}
+    // expected-warning at -3 {{is a C++2b extension}}
+#endif
     [](int) -> {}; // PR13652 expected-error {{expected a type}}
     return 1;
   }
@@ -101,7 +106,10 @@ class C {
   }
 
   void attributes() {
-    [] __attribute__((noreturn)) {}; // expected-error {{lambda requires '()' before attribute specifier}}
+    [] __attribute__((noreturn)){};
+#if __cplusplus <= 202002L
+    // expected-warning at -2 {{is a C++2b extension}}
+#endif
     []() [[]]
       mutable {}; // expected-error {{expected body of lambda expression}}
 
@@ -118,11 +126,29 @@ class C {
 
     // Testing support for P2173 on adding attributes to the declaration
     // rather than the type.
-    [] [[]] () {}; // expected-warning {{an attribute specifier sequence in this position is a C++2b extension}}
+    [][[]](){};
+#if __cplusplus <= 202002L
+    // expected-warning at -2 {{an attribute specifier sequence in this position is a C++2b extension}}
+#endif
 #if __cplusplus > 201703L
-    [] <typename> [[]] () {};  // expected-warning {{an attribute specifier sequence in this position is a C++2b extension}}
+    []<typename>[[]](){};
+#if __cplusplus <= 202002L
+    // expected-warning at -2 {{an attribute specifier sequence in this position is a C++2b extension}}
+#endif
+#endif
+    [][[]]{};
+#if __cplusplus <= 202002L
+    // expected-warning at -2 {{an attribute specifier sequence in this position is a C++2b extension}}
+#endif
+  }
+
+  void missing_parens() {
+    [] mutable {};
+    [] noexcept {};
+#if __cplusplus <= 202002L
+    // expected-warning at -3 {{is a C++2b extension}}
+    // expected-warning at -3 {{is a C++2b extension}}
 #endif
-    [] [[]] {}; // expected-warning {{an attribute specifier sequence in this position is a C++2b extension}}
   }
 };
 

diff  --git a/clang/test/Parser/cxx1z-constexpr-lambdas.cpp b/clang/test/Parser/cxx1z-constexpr-lambdas.cpp
index 4cf3d1221167..0c2f81d318a1 100644
--- a/clang/test/Parser/cxx1z-constexpr-lambdas.cpp
+++ b/clang/test/Parser/cxx1z-constexpr-lambdas.cpp
@@ -1,12 +1,19 @@
-// RUN: %clang_cc1 -std=c++17 %s -verify 
-// RUN: %clang_cc1 -std=c++14 %s -verify 
-// RUN: %clang_cc1 -std=c++11 %s -verify 
+// RUN: %clang_cc1 -std=c++2b %s -verify
+// RUN: %clang_cc1 -std=c++20 %s -verify
+// RUN: %clang_cc1 -std=c++17 %s -verify
+// RUN: %clang_cc1 -std=c++14 %s -verify
+// RUN: %clang_cc1 -std=c++11 %s -verify
 
-
-auto XL0 = [] constexpr { }; //expected-error{{requires '()'}} expected-error{{expected body}}
-auto XL1 = [] () mutable 
-                 mutable     //expected-error{{cannot appear multiple times}}
-                 mutable { }; //expected-error{{cannot appear multiple times}}
+auto XL0 = [] constexpr { return true; };
+#if __cplusplus <= 201402L
+// expected-warning at -2 {{is a C++17 extension}}
+#endif
+#if __cplusplus <= 202002L
+// expected-warning at -5 {{lambda without a parameter clause is a C++2b extension}}
+#endif
+auto XL1 = []() mutable //
+    mutable             // expected-error{{cannot appear multiple times}}
+    mutable {};         // expected-error{{cannot appear multiple times}}
 
 #if __cplusplus > 201402L
 auto XL2 = [] () constexpr mutable constexpr { }; //expected-error{{cannot appear multiple times}}

diff  --git a/clang/test/Parser/cxx2a-template-lambdas.cpp b/clang/test/Parser/cxx2a-template-lambdas.cpp
index 034a3b157d80..2a2305b5530c 100644
--- a/clang/test/Parser/cxx2a-template-lambdas.cpp
+++ b/clang/test/Parser/cxx2a-template-lambdas.cpp
@@ -1,3 +1,4 @@
+// RUN: %clang_cc1 -std=c++2b %s -verify
 // RUN: %clang_cc1 -std=c++2a %s -verify
 
 auto L0 = []<> { }; //expected-error {{cannot be empty}}

diff  --git a/clang/test/Parser/cxx2b-lambdas.cpp b/clang/test/Parser/cxx2b-lambdas.cpp
new file mode 100644
index 000000000000..e008dc8f2d36
--- /dev/null
+++ b/clang/test/Parser/cxx2b-lambdas.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -std=c++2b %s -verify
+
+auto LL0 = [] {};
+auto LL1 = []() {};
+auto LL2 = []() mutable {};
+auto LL3 = []() constexpr {};
+
+auto L0 = [] constexpr {};
+auto L1 = [] mutable {};
+auto L2 = [] noexcept {};
+auto L3 = [] constexpr mutable {};
+auto L4 = [] mutable constexpr {};
+auto L5 = [] constexpr mutable noexcept {};
+auto L6 = [s = 1] mutable {};
+auto L7 = [s = 1] constexpr mutable noexcept {};
+auto L8 = [] -> bool { return true; };
+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 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 XL3 = []( constexpr mutable constexpr {}; // expected-error{{invalid storage class specifier}} \
+                                               // expected-error{{function parameter cannot be constexpr}} \
+                                               // expected-error{{C++ requires}} \
+                                               // expected-error{{expected ')'}} \
+                                               // expected-note{{to match this '('}} \
+                                               // expected-error{{expected body}} \
+                                               // expected-warning{{duplicate 'constexpr'}}

diff  --git a/clang/test/SemaOpenCLCXX/address-space-lambda.clcpp b/clang/test/SemaOpenCLCXX/address-space-lambda.clcpp
index 180624094ee8..66dc4da13d2c 100644
--- a/clang/test/SemaOpenCLCXX/address-space-lambda.clcpp
+++ b/clang/test/SemaOpenCLCXX/address-space-lambda.clcpp
@@ -61,7 +61,10 @@ __kernel void test_qual() {
   [&] () __global {} (); //expected-error{{no matching function for call to object of type '(lambda at}} expected-note{{candidate function not viable: 'this' object is in default address space, but method expects object in address space '__global'}}
   [&] () __private {} (); //expected-error{{no matching function for call to object of type '(lambda at}} expected-note{{candidate function not viable: 'this' object is in default address space, but method expects object in address space '__private'}}
 
-  [&] __private {} (); //expected-error{{lambda requires '()' before attribute specifier}} expected-error{{expected body of lambda expression}}
+  [&] __private {} (); // expected-error{{no matching function for call to object of type '(lambda at}} expected-note{{candidate function not viable: 'this' object is in default address space, but method expects object in address space '__private'}}
+#if __cplusplus <= 202002L
+// expected-warning at -2{{lambda without a parameter clause is a C++2b extension}}
+#endif
 
   [&] () mutable __private {} ();
   [&] () __private mutable {} (); //expected-error{{expected body of lambda expression}}

diff  --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index d7baa595d6ee..473316005d37 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -63,7 +63,7 @@ <h1>C++ Support in Clang</h1>
 <tr>
  <td><a href="#cxx23">C++2b (tentatively C++23)</a></td>
  <td><tt>-std=c++2b</tt></td>
- <td class="none" align="center">No</td>
+ <td class="partial" align="center">Partial</td>
 </tr>
 </table>
 
@@ -1276,7 +1276,7 @@ <h2 id="cxx23">C++2b implementation status</h2>
     <tr>
       <td>Make <tt>()</tt> in lambdas optional in all cases</td>
       <td><a href="https://wg21.link/p1102r2">P1102R2</a></td>
-      <td class="none" align="center">No</td>
+      <td class="full" align="center">Clang 13</td>
     </tr>
 </table>
 </details>


        


More information about the cfe-commits mailing list