diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 31c517338c21f..a7c8b2514b226 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -710,6 +710,7 @@ Bug Fixes to C++ Support - Clang now correctly parses arbitrary order of ``[[]]``, ``__attribute__`` and ``alignas`` attributes for declarations (#GH133107) - Fixed a crash when forming an invalid function type in a dependent context. (#GH138657) (#GH115725) (#GH68852) - Clang no longer segfaults when there is a configuration mismatch between modules and their users (http://crbug.com/400353616). +- Fix parsing of expressions of the form ``((T))[expr]``. (#GH20723) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index e6492b81dfff8..016708de2bf4c 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -4639,6 +4639,10 @@ class Parser : public CodeCompletionHandler { ParseLambdaIntroducer(LambdaIntroducer &Intro, LambdaIntroducerTentativeParse *Tentative = nullptr); + /// Tries to determine if an expression of the form (S())[...]... + /// is a type-cast followed by a lambda, or a subscript expression + bool IsLambdaAfterTypeCast(); + /// ParseLambdaExpressionAfterIntroducer - Parse the rest of a lambda /// expression. ExprResult ParseLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro); diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 11cfbbe790418..09dabaad4e231 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1585,8 +1585,10 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, } break; } - Res = ParseLambdaExpression(); - break; + if (isTypeCast != TypeCastState::IsTypeCast || IsLambdaAfterTypeCast()) { + Res = ParseLambdaExpression(); + break; + } } if (getLangOpts().ObjC) { Res = ParseObjCMessageExpression(); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index d95260829e4a0..e60cae9510979 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -692,6 +692,86 @@ ExprResult Parser::ParseLambdaExpression() { return ParseLambdaExpressionAfterIntroducer(Intro); } +bool Parser::IsLambdaAfterTypeCast() { + assert(getLangOpts().CPlusPlus && Tok.is(tok::l_square) && + "Not at the start of a possible lambda expression."); + RevertingTentativeParsingAction TPA(*this); + ConsumeBracket(); + // skip the introducer + if (Tok.is(tok::equal) || + (Tok.is(tok::amp) && NextToken().isOneOf(tok::comma, tok::r_square))) + return true; + + SkipUntil(tok::r_square); + + auto IsLambdaKWOrAttribute = [&]() { + // These are keyworks that can appear somewhere in a lambda declarator, + // or cannot appear in a cast-expression and we recover in favor of lambdas + if (Tok.isOneOf(tok::kw___declspec, tok::kw___noinline__, tok::kw_noexcept, + tok::kw_throw, tok::kw_mutable, tok::kw___attribute, + tok::kw_constexpr, tok::kw_consteval, tok::kw_static, + tok::kw_inline, tok::kw_extern, tok::kw___private, + tok::kw___global, tok::kw___local, tok::kw___constant, + tok::kw___generic, tok::kw_groupshared, tok::kw_requires, + tok::kw_noexcept)) + return true; + return Tok.isRegularKeywordAttribute() || + isCXX11AttributeSpecifier() != + CXX11AttributeKind::NotAttributeSpecifier; + }; + + if (Tok.is(tok::l_brace) || IsLambdaKWOrAttribute()) + return true; + + // This is a generic lambda, + if (Tok.is(tok::less)) { + ConsumeToken(); + // Common cases. We consider <> as an invalid lambda. + if (Tok.isOneOf(tok::greater, tok::kw_typename, tok::kw_auto, + tok::kw_template)) + return true; + if (isStartOfTemplateTypeParameter() != TPResult::False) + return true; + return isCXXDeclarationSpecifier(ImplicitTypenameContext::Yes) != + TPResult::False; + } + // skip the parameter list + if (Tok.is(tok::l_paren)) { + ConsumeParen(); + SkipUntil(tok::r_paren); + } + + if (IsLambdaKWOrAttribute()) + return true; + + if (Tok.is(tok::arrow)) { + ConsumeToken(); + // These cases are always id-expressions + if (Tok.isOneOf(tok::kw_template, tok::kw_operator, tok::tilde)) + return false; + if (!Tok.is(tok::identifier)) + return true; + if(NextToken().is(tok::l_brace)) + return true; + + // Use a nested unannotated so that we can revert + // annotations when we fail to find a brace. + TentativeParsingAction TPA(*this, /*Unannotated=*/true); + if(TryAnnotateTypeOrScopeToken() + || !Tok.isSimpleTypeSpecifier(getLangOpts())) { + TPA.Revert(); + return false; + } + ConsumeAnyToken(); + if(Tok.is(tok::l_brace)) { + TPA.Commit(); + return true; + } + TPA.Revert(); + } + return Tok.is(tok::l_brace); +} + ExprResult Parser::TryParseLambdaExpression() { assert(getLangOpts().CPlusPlus && Tok.is(tok::l_square) && "Not at the start of a possible lambda expression."); diff --git a/clang/test/Parser/cxx0x-lambda-expressions.cpp b/clang/test/Parser/cxx0x-lambda-expressions.cpp index a786a964163e4..f6d9f7effbfe8 100644 --- a/clang/test/Parser/cxx0x-lambda-expressions.cpp +++ b/clang/test/Parser/cxx0x-lambda-expressions.cpp @@ -40,6 +40,33 @@ class C { return 1; } + int type_cast() { + int foo, bar; + + (void)[]; // expected-error {{expected expression}} + (void)[+] {}; // expected-error {{expected variable name or 'this' in lambda capture list}} + (void)[foo+] {}; // expected-error {{expected ',' or ']' in lambda capture list}} + (void)[foo,&this] {}; // expected-error {{'this' cannot be captured by reference}} + (void)[&this] {}; // expected-error {{'this' cannot be captured by reference}} + (void)[&,] {}; // expected-error {{expected variable name or 'this' in lambda capture list}} + (void)[=,] {}; // expected-error {{expected variable name or 'this' in lambda capture list}} + (void)[] {}; + (void)[=] (int i) {}; + (void)[&] (int) mutable -> void {}; + (void)[foo,bar] () { return 3; }; + (void)[=,&foo] () {}; + (void)[&,foo] () {}; + (void)[this] () {}; + (void)[] () -> class C { return C(); }; + (void)[] () -> enum E { return e; }; + + (void)[] -> int { return 0; }; // cxx23ext-warning {{lambda without a parameter clause is a C++23 extension}} + (void)[] mutable -> int { return 0; }; // cxx23ext-warning {{is a C++23 extension}} + + (void)[](int) -> {}; // PR13652 expected-error {{expected a type}} + return 1; + } + void designator_or_lambda() { typedef int T; const int b = 0; @@ -125,10 +152,46 @@ class C { [][[]]{}; // cxx23ext-warning {{an attribute specifier sequence in this position is a C++23 extension}} } + void attributes_type_cast() { + (void)[] __attribute__((noreturn)){}; // cxx23ext-warning {{lambda without a parameter clause is a C++23 extension}} + + (void)[]() [[]] + mutable {}; // expected-error {{expected body of lambda expression}} + + (void)[]() [[]] {}; + (void)[]() [[]] -> void {}; + (void)[]() mutable [[]] -> void {}; +#if __cplusplus >= 201103L + (void)[]() mutable noexcept [[]] -> void {}; +#endif + + // Testing GNU-style attributes on lambdas -- the attribute is specified + // before the mutable specifier instead of after (unlike C++11). + (void)[]() __attribute__((noreturn)) mutable { while(1); }; + (void)[]() mutable + __attribute__((noreturn)) { while(1); }; // expected-error {{expected body of lambda expression}} + + // Testing support for P2173 on adding attributes to the declaration + // rather than the type. + (void)[][[]](){}; // cxx23ext-warning {{an attribute specifier sequence in this position is a C++23 extension}} + + (void)[][[]](){}; // cxx20ext-warning {{explicit template parameter list for lambdas is a C++20 extension}} + // cxx23ext-warning@-1 {{an attribute specifier sequence in this position is a C++23 extension}} + + (void)[][[]]{}; // cxx23ext-warning {{an attribute specifier sequence in this position is a C++23 extension}} + } + void missing_parens() { [] mutable {}; // cxx23ext-warning {{is a C++23 extension}} #if __cplusplus >= 201103L [] noexcept {}; // cxx23ext-warning {{is a C++23 extension}} +#endif + } + + void missing_parens_type_cast() { + (void)[] mutable {}; // cxx23ext-warning {{is a C++23 extension}} +#if __cplusplus >= 201103L + (void)[] noexcept {}; // cxx23ext-warning {{is a C++23 extension}} #endif } }; @@ -150,6 +213,41 @@ struct S { }; } +namespace GH20723 { +#if __cplusplus >= 201103L +struct S { + S operator[](int); + S operator()(); + S operator<(int); + S* operator->(); + long a; +}; +int n; +void f() { + static_assert(__is_same_as(decltype((S())[n]()), S), ""); + static_assert(__is_same_as(decltype((S())[n] < 0), S), ""); + static_assert(__is_same_as(decltype((S())[n]->a), long), ""); +} +#endif +#if __cplusplus >= 202302 +struct S2 { + S2 operator[](); + S2* operator->(); + template + constexpr static int trailing = 0; +}; + +template +struct trailing{}; + +void f2() { + static_assert(__is_same_as(decltype((S2())[]->trailing), const int)); + (void)[]->trailing{return {};}(); +} +#endif + +} + struct S { template void m (T x =[0); // expected-error{{expected variable name or 'this' in lambda capture list}} diff --git a/clang/test/Parser/cxx1z-constexpr-lambdas.cpp b/clang/test/Parser/cxx1z-constexpr-lambdas.cpp index 87584ee5ca91b..bba63b4925298 100644 --- a/clang/test/Parser/cxx1z-constexpr-lambdas.cpp +++ b/clang/test/Parser/cxx1z-constexpr-lambdas.cpp @@ -1,26 +1,34 @@ -// RUN: %clang_cc1 -std=c++23 %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 +// RUN: %clang_cc1 -std=c++23 %s -verify -Wno-unused "-DTYPE_CAST=" +// RUN: %clang_cc1 -std=c++20 %s -verify -Wno-unused "-DTYPE_CAST=" +// RUN: %clang_cc1 -std=c++17 %s -verify -Wno-unused "-DTYPE_CAST=" +// RUN: %clang_cc1 -std=c++14 %s -verify -Wno-unused "-DTYPE_CAST=" +// RUN: %clang_cc1 -std=c++11 %s -verify -Wno-unused "-DTYPE_CAST=" -auto XL0 = [] constexpr { return true; }; +// RUN: %clang_cc1 -std=c++23 %s -verify "-DTYPE_CAST=(void)" +// RUN: %clang_cc1 -std=c++20 %s -verify "-DTYPE_CAST=(void)" +// RUN: %clang_cc1 -std=c++17 %s -verify "-DTYPE_CAST=(void)" +// RUN: %clang_cc1 -std=c++14 %s -verify "-DTYPE_CAST=(void)" +// RUN: %clang_cc1 -std=c++11 %s -verify "-DTYPE_CAST=(void)" + +void test() { + +TYPE_CAST [] 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++23 extension}} #endif -auto XL1 = []() mutable // +TYPE_CAST []() 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}} -auto L = []() mutable constexpr { }; -auto L2 = []() constexpr { }; -auto L4 = []() constexpr mutable { }; -auto XL16 = [] () constexpr +TYPE_CAST [] () constexpr mutable constexpr { }; //expected-error{{cannot appear multiple times}} +TYPE_CAST []() mutable constexpr { }; +TYPE_CAST []() constexpr { }; +TYPE_CAST []() constexpr mutable { }; +TYPE_CAST [] () constexpr mutable constexpr //expected-error{{cannot appear multiple times}} mutable //expected-error{{cannot appear multiple times}} @@ -31,8 +39,10 @@ auto XL16 = [] () constexpr #else auto L = []() mutable constexpr {return 0; }; //expected-warning{{is a C++17 extension}} -auto L2 = []() constexpr { return 0;};//expected-warning{{is a C++17 extension}} -auto L4 = []() constexpr mutable { return 0; }; //expected-warning{{is a C++17 extension}} +TYPE_CAST []() constexpr { return 0;};//expected-warning{{is a C++17 extension}} +TYPE_CAST []() constexpr mutable { return 0; }; //expected-warning{{is a C++17 extension}} #endif +} + diff --git a/clang/test/Parser/cxx2a-template-lambdas.cpp b/clang/test/Parser/cxx2a-template-lambdas.cpp index 98c74a247b535..bb43101045e9e 100644 --- a/clang/test/Parser/cxx2a-template-lambdas.cpp +++ b/clang/test/Parser/cxx2a-template-lambdas.cpp @@ -1,38 +1,44 @@ -// RUN: %clang_cc1 -std=c++23 %s -verify -// RUN: %clang_cc1 -std=c++20 %s -verify +// RUN: %clang_cc1 -std=c++23 %s -verify -Wno-unused "-DTYPE_CAST=" +// RUN: %clang_cc1 -std=c++20 %s -verify -Wno-unused "-DTYPE_CAST=" +// RUN: %clang_cc1 -std=c++23 %s -verify "-DTYPE_CAST=(void)" +// RUN: %clang_cc1 -std=c++20 %s -verify "-DTYPE_CAST=(void)" -auto L0 = []<> { }; //expected-error {{cannot be empty}} +void test() { -auto L1 = [] { }; -auto L2 = [](T1 arg1, T2 arg2) -> T1 { }; -auto L3 = [](auto arg) { T t; }; -auto L4 = []() { }; +TYPE_CAST []<> { }; //expected-error {{cannot be empty}} + +TYPE_CAST [] { }; +TYPE_CAST [](T1 arg1, T2 arg2) -> T1 { }; +TYPE_CAST [](auto arg) { T t; }; +TYPE_CAST []() { }; // http://llvm.org/PR49736 -auto L5 = [](){}; -auto L6 = []{}; -auto L7 = []() noexcept {}; -auto L8 = [] noexcept {}; +TYPE_CAST [](){}; +TYPE_CAST []{}; +TYPE_CAST []() noexcept {}; +TYPE_CAST [] noexcept {}; #if __cplusplus <= 202002L // expected-warning@-2 {{lambda without a parameter clause is a C++23 extension}} #endif -auto L9 = [] requires true {}; -auto L10 = [] requires true(){}; -auto L11 = [] requires true() noexcept {}; -auto L12 = [] requires true noexcept {}; +TYPE_CAST [] requires true {}; +TYPE_CAST [] requires true(){}; +TYPE_CAST [] requires true() noexcept {}; +TYPE_CAST [] requires true noexcept {}; #if __cplusplus <= 202002L // expected-warning@-2 {{is a C++23 extension}} #endif -auto L13 = []() noexcept requires true {}; -auto L14 = [] requires true() noexcept requires true {}; +TYPE_CAST []() noexcept requires true {}; +TYPE_CAST [] requires true() noexcept requires true {}; -auto XL0 = [] noexcept requires true {}; // expected-error {{expected body of lambda expression}} -auto XL1 = [] requires true noexcept requires true {}; // expected-error {{expected body}} +TYPE_CAST [] noexcept requires true {}; // expected-error {{expected body of lambda expression}} +TYPE_CAST [] requires true noexcept requires true {}; // expected-error {{expected body}} #if __cplusplus <= 202002L // expected-warning@-3 {{is a C++23 extension}} // expected-warning@-3 {{is a C++23 extension}} #endif +} + namespace GH64962 { void f() { [] (T i) -> int[] // expected-error {{function cannot return array type 'int[]'}} diff --git a/clang/test/Parser/cxx2b-lambdas.cpp b/clang/test/Parser/cxx2b-lambdas.cpp index 758ec9a42f56d..a769fbda36276 100644 --- a/clang/test/Parser/cxx2b-lambdas.cpp +++ b/clang/test/Parser/cxx2b-lambdas.cpp @@ -1,88 +1,109 @@ -// RUN: %clang_cc1 -std=c++03 %s -verify -Wno-c++23-extensions -Wno-c++20-extensions -Wno-c++17-extensions -Wno-c++14-extensions -Wno-c++11-extensions -// RUN: %clang_cc1 -std=c++11 %s -verify=expected,cxx11 -Wno-c++23-extensions -Wno-c++20-extensions -Wno-c++17-extensions -Wno-c++14-extensions -// RUN: %clang_cc1 -std=c++14 %s -verify -Wno-c++23-extensions -Wno-c++20-extensions -Wno-c++17-extensions -// RUN: %clang_cc1 -std=c++17 %s -verify -Wno-c++23-extensions -Wno-c++20-extensions -// RUN: %clang_cc1 -std=c++20 %s -verify -Wno-c++23-extensions -// RUN: %clang_cc1 -std=c++23 %s -verify - -auto LL0 = [] {}; -auto LL1 = []() {}; -auto LL2 = []() mutable {}; +// RUN: %clang_cc1 -std=c++03 %s "-DTYPE_CAST=" -verify -Wno-unused -Wno-c++23-extensions -Wno-c++20-extensions -Wno-c++17-extensions -Wno-c++14-extensions -Wno-c++11-extensions +// RUN: %clang_cc1 -std=c++11 %s "-DTYPE_CAST=" -verify=expected,cxx11 -Wno-unused -Wno-c++23-extensions -Wno-c++20-extensions -Wno-c++17-extensions -Wno-c++14-extensions +// RUN: %clang_cc1 -std=c++14 %s "-DTYPE_CAST=" -verify -Wno-unused -Wno-c++23-extensions -Wno-c++20-extensions -Wno-c++17-extensions +// RUN: %clang_cc1 -std=c++17 %s "-DTYPE_CAST=" -verify -Wno-unused -Wno-c++23-extensions -Wno-c++20-extensions +// RUN: %clang_cc1 -std=c++20 %s "-DTYPE_CAST=" -verify -Wno-unused -Wno-c++23-extensions +// RUN: %clang_cc1 -std=c++23 %s "-DTYPE_CAST=" -verify -Wno-unused + +// RUN: %clang_cc1 -std=c++03 %s "-DTYPE_CAST=(void)" -verify -Wno-unused -Wno-c++23-extensions -Wno-c++20-extensions -Wno-c++17-extensions -Wno-c++14-extensions -Wno-c++11-extensions +// RUN: %clang_cc1 -std=c++11 %s "-DTYPE_CAST=(void)" -verify=expected,cxx11 -Wno-unused -Wno-c++23-extensions -Wno-c++20-extensions -Wno-c++17-extensions -Wno-c++14-extensions +// RUN: %clang_cc1 -std=c++14 %s "-DTYPE_CAST=(void)" -verify -Wno-unused -Wno-c++23-extensions -Wno-c++20-extensions -Wno-c++17-extensions +// RUN: %clang_cc1 -std=c++17 %s "-DTYPE_CAST=(void)" -verify -Wno-unused -Wno-c++23-extensions -Wno-c++20-extensions +// RUN: %clang_cc1 -std=c++20 %s "-DTYPE_CAST=(void)" -verify -Wno-unused -Wno-c++23-extensions +// RUN: %clang_cc1 -std=c++23 %s "-DTYPE_CAST=(void)" -verify -Wno-unused + +void test() { + +TYPE_CAST [] {}; +TYPE_CAST []() {}; +TYPE_CAST []() mutable {}; #if __cplusplus >= 201103L -auto LL3 = []() constexpr {}; // cxx11-error {{return type 'void' is not a literal type}} +TYPE_CAST []() constexpr {}; // cxx11-error {{return type 'void' is not a literal type}} #endif #if __cplusplus >= 201103L -auto L0 = [] constexpr {}; // cxx11-error {{return type 'void' is not a literal type}} +TYPE_CAST [] constexpr {}; // cxx11-error {{return type 'void' is not a literal type}} #endif -auto L1 = [] mutable {}; +TYPE_CAST [] mutable {}; #if __cplusplus >= 201103L -auto L2 = [] noexcept {}; -auto L3 = [] constexpr mutable {}; // cxx11-error {{return type 'void' is not a literal type}} -auto L4 = [] mutable constexpr {}; // cxx11-error {{return type 'void' is not a literal type}} -auto L5 = [] constexpr mutable noexcept {}; // cxx11-error {{return type 'void' is not a literal type}} +TYPE_CAST [] noexcept {}; +TYPE_CAST [] constexpr mutable {}; // cxx11-error {{return type 'void' is not a literal type}} +TYPE_CAST [] mutable constexpr {}; // cxx11-error {{return type 'void' is not a literal type}} +TYPE_CAST [] constexpr mutable noexcept {}; // cxx11-error {{return type 'void' is not a literal type}} #endif -auto L6 = [s = 1] mutable {}; +TYPE_CAST [s = 1] mutable {}; #if __cplusplus >= 201103L -auto L7 = [s = 1] constexpr mutable noexcept {}; // cxx11-error {{return type 'void' is not a literal type}} +TYPE_CAST [s = 1] constexpr mutable noexcept {}; // cxx11-error {{return type 'void' is not a literal type}} #endif -auto L8 = [] -> bool { return true; }; -auto L9 = [] { return true; }; +TYPE_CAST [] -> bool { return true; }; +TYPE_CAST [] { return true; }; #if __cplusplus >= 201103L -auto L10 = [] noexcept { return true; }; +TYPE_CAST [] noexcept { return true; }; #endif -auto L11 = [] -> bool { return true; }; +TYPE_CAST [] -> bool { return true; }; #if __cplusplus >= 202002L -auto L12 = [] consteval {}; -auto L13 = []() requires true {}; // expected-error{{non-templated function cannot have a requires clause}} -auto L14 = [] requires true() requires true {}; -auto L15 = [] requires true noexcept {}; +TYPE_CAST [] consteval {}; +TYPE_CAST []() requires true {}; // expected-error{{non-templated function cannot have a requires clause}} +TYPE_CAST [] requires true() requires true {}; +TYPE_CAST [] requires true noexcept {}; #endif -auto L16 = [] [[maybe_unused]]{}; +TYPE_CAST [] [[maybe_unused]]{}; #if __cplusplus >= 201103L -auto XL0 = [] mutable constexpr mutable {}; // expected-error{{cannot appear multiple times}} cxx11-error {{return type 'void' is not a literal type}} -auto XL1 = [] constexpr mutable constexpr {}; // expected-error{{cannot appear multiple times}} cxx11-error {{return type 'void' is not a literal type}} -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{{a type specifier is required}} \ - // expected-error{{expected ')'}} \ - // expected-note{{to match this '('}} \ - // expected-error{{expected body}} \ - // expected-warning{{duplicate 'constexpr'}} +TYPE_CAST [] mutable constexpr mutable {}; // expected-error{{cannot appear multiple times}} cxx11-error {{return type 'void' is not a literal type}} +TYPE_CAST [] constexpr mutable constexpr {}; // expected-error{{cannot appear multiple times}} cxx11-error {{return type 'void' is not a literal type}} + +[]) constexpr mutable constexpr {}; // expected-error{{expected body of lambda expression}} +[]( constexpr mutable constexpr {}; // expected-error{{invalid storage class specifier}} \ + // expected-error{{function parameter cannot be constexpr}} \ + // expected-error{{a type specifier is required}} \ + // expected-error{{expected ')'}} \ + // expected-note{{to match this '('}} \ + // expected-error{{expected body}} \ + // expected-warning{{duplicate 'constexpr'}} + #endif // http://llvm.org/PR49736 -auto XL4 = [] requires true {}; // expected-error{{expected body}} + +#if __cplusplus >= 202002L +[] requires true {}; // expected-error{{expected body}} +(void)[] requires true {}; // expected-error{{expected body}} +#else +[] requires true {}; // expected-error{{expected body}} +(void)[] requires true {}; // expected-error{{expected expression}} +#endif + #if __cplusplus >= 201703L -auto XL5 = [] requires true requires true {}; // expected-error{{expected body}} -auto XL6 = [] requires true noexcept requires true {}; // expected-error{{expected body}} +TYPE_CAST [] requires true requires true {}; // expected-error{{expected body}} +TYPE_CAST [] requires true noexcept requires true {}; // expected-error{{expected body}} #endif -auto XL7 = []() static static {}; // expected-error {{cannot appear multiple times}} -auto XL8 = []() static mutable {}; // expected-error {{cannot be both mutable and static}} +TYPE_CAST []() static static {}; // expected-error {{cannot appear multiple times}} +TYPE_CAST []() static mutable {}; // expected-error {{cannot be both mutable and static}} #if __cplusplus >= 202002L -auto XL9 = []() static consteval {}; +TYPE_CAST []() static consteval {}; #endif #if __cplusplus >= 201103L -auto XL10 = []() static constexpr {}; // cxx11-error {{return type 'void' is not a literal type}} +TYPE_CAST []() static constexpr {}; // cxx11-error {{return type 'void' is not a literal type}} #endif -auto XL11 = [] static {}; -auto XL12 = []() static {}; -auto XL13 = []() static extern {}; // expected-error {{expected body of lambda expression}} -auto XL14 = []() extern {}; // expected-error {{expected body of lambda expression}} +TYPE_CAST [] static {}; +TYPE_CAST []() static {}; +TYPE_CAST []() static extern {}; // expected-error {{expected body of lambda expression}} +TYPE_CAST []() extern {}; // expected-error {{expected body of lambda expression}} + +} void static_captures() { int x; - auto SC1 = [&]() static {}; // expected-error {{a static lambda cannot have any captures}} - auto SC4 = [x]() static {}; // expected-error {{a static lambda cannot have any captures}} - auto SC2 = [&x]() static {}; // expected-error {{a static lambda cannot have any captures}} - auto SC3 = [y=x]() static {}; // expected-error {{a static lambda cannot have any captures}} - auto SC5 = [&y = x]() static {}; // expected-error {{a static lambda cannot have any captures}} - auto SC6 = [=]() static {}; // expected-error {{a static lambda cannot have any captures}} + TYPE_CAST [&]() static {}; // expected-error {{a static lambda cannot have any captures}} + TYPE_CAST [x]() static {}; // expected-error {{a static lambda cannot have any captures}} + TYPE_CAST [&x]() static {}; // expected-error {{a static lambda cannot have any captures}} + TYPE_CAST [y=x]() static {}; // expected-error {{a static lambda cannot have any captures}} + TYPE_CAST [&y = x]() static {}; // expected-error {{a static lambda cannot have any captures}} + TYPE_CAST [=]() static {}; // expected-error {{a static lambda cannot have any captures}} struct X { int z; void f() {