diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -949,9 +949,6 @@ def warn_cxx98_compat_lambda : Warning< "lambda expressions are incompatible with C++98">, InGroup, 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 ext_decl_attrs_on_lambda : ExtWarn< "an attribute specifier sequence in this position is a C++2b extension">, InGroup; +def ext_lambda_missing_parens : ExtWarn< + "lambda without a parameter clause is a C++2b extension">, + InGroup; 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, DefaultIgnore; diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -688,9 +688,9 @@ /// 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 @@ /// '&' 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 @@ 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 @@ TypeResult TrailingReturnType; SourceLocation TrailingReturnTypeLoc; + + auto ParseLambdaSpecifiers = + [&](SourceLocation LParenLoc, SourceLocation RParenLoc, + MutableArrayRef 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 DynamicExceptions; + SmallVector 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 @@ } 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 DynamicExceptions; - SmallVector 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 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 --- 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 @@ { 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@-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 --- a/clang/test/FixIt/fixit-c++11.cpp +++ b/clang/test/FixIt/fixit-c++11.cpp @@ -56,8 +56,12 @@ (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@-3{{is a C++2b extension}} + // expected-warning@-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 --- 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 lambda2 = [] (auto x) constexpr -> int requires (sizeof(decltype(x)) == 1) { return 0; }; auto lambda3 = [] requires (sizeof(char) == 1) { }; -// expected-error@-1{{lambda requires '()' before 'requires' clause}} \ No newline at end of file +#if __cplusplus <= 202002L +// expected-warning@-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 --- 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 @@ [&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 { 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@-3 {{lambda without a parameter clause is a C++2b extension}} + // expected-warning@-3 {{is a C++2b extension}} +#endif [](int) -> {}; // PR13652 expected-error {{expected a type}} return 1; } @@ -101,7 +106,10 @@ } void attributes() { - [] __attribute__((noreturn)) {}; // expected-error {{lambda requires '()' before attribute specifier}} + [] __attribute__((noreturn)){}; +#if __cplusplus <= 202002L + // expected-warning@-2 {{is a C++2b extension}} +#endif []() [[]] mutable {}; // expected-error {{expected body of lambda expression}} @@ -118,11 +126,29 @@ // 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@-2 {{an attribute specifier sequence in this position is a C++2b extension}} +#endif #if __cplusplus > 201703L - [] [[]] () {}; // expected-warning {{an attribute specifier sequence in this position is a C++2b extension}} + [][[]](){}; +#if __cplusplus <= 202002L + // expected-warning@-2 {{an attribute specifier sequence in this position is a C++2b extension}} +#endif +#endif + [][[]]{}; +#if __cplusplus <= 202002L + // expected-warning@-2 {{an attribute specifier sequence in this position is a C++2b extension}} +#endif + } + + void missing_parens() { + [] mutable {}; + [] noexcept {}; +#if __cplusplus <= 202002L + // expected-warning@-3 {{is a C++2b extension}} + // expected-warning@-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 --- 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@-2 {{is a C++17 extension}} +#endif +#if __cplusplus <= 202002L +// expected-warning@-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 --- 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 --- /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 = [] { return true; }; +auto L10 = [] noexcept { return true; }; +auto L11 = [] -> 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 --- a/clang/test/SemaOpenCLCXX/address-space-lambda.clcpp +++ b/clang/test/SemaOpenCLCXX/address-space-lambda.clcpp @@ -61,7 +61,10 @@ [&] () __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@-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 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -63,7 +63,7 @@ C++2b (tentatively C++23) -std=c++2b - No + Partial @@ -1276,7 +1276,7 @@ Make () in lambdas optional in all cases P1102R2 - No + Clang 13