[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