diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 13d7261d83d7f..201a4c27f7dd8 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -1459,40 +1459,45 @@ More information could be found `here Language Extensions Back-ported to Previous Standards ===================================================== -====================================== ================================ ============= ============= -Feature Feature Test Macro Introduced In Backported To -====================================== ================================ ============= ============= -variadic templates __cpp_variadic_templates C++11 C++03 -Alias templates __cpp_alias_templates C++11 C++03 -Non-static data member initializers __cpp_nsdmi C++11 C++03 -Range-based ``for`` loop __cpp_range_based_for C++11 C++03 -RValue references __cpp_rvalue_references C++11 C++03 -Attributes __cpp_attributes C++11 C++03 -variable templates __cpp_variable_templates C++14 C++03 -Binary literals __cpp_binary_literals C++14 C++03 -Relaxed constexpr __cpp_constexpr C++14 C++11 -``if constexpr`` __cpp_if_constexpr C++17 C++11 -fold expressions __cpp_fold_expressions C++17 C++03 -Lambda capture of \*this by value __cpp_capture_star_this C++17 C++11 -Attributes on enums __cpp_enumerator_attributes C++17 C++03 -Guaranteed copy elision __cpp_guaranteed_copy_elision C++17 C++03 -Hexadecimal floating literals __cpp_hex_float C++17 C++03 -``inline`` variables __cpp_inline_variables C++17 C++03 -Attributes on namespaces __cpp_namespace_attributes C++17 C++11 -Structured bindings __cpp_structured_bindings C++17 C++03 -template template arguments __cpp_template_template_args C++17 C++03 -``static operator[]`` __cpp_multidimensional_subscript C++20 C++03 -Designated initializers __cpp_designated_initializers C++20 C++03 -Conditional ``explicit`` __cpp_conditional_explicit C++20 C++03 -``using enum`` __cpp_using_enum C++20 C++03 -``if consteval`` __cpp_if_consteval C++23 C++20 -``static operator()`` __cpp_static_call_operator C++23 C++03 -Attributes on Lambda-Expressions C++23 C++11 --------------------------------------- -------------------------------- ------------- ------------- -Designated initializers (N494) C99 C89 -Array & element qualification (N2607) C23 C89 -Attributes (N2335) C23 C89 -====================================== ================================ ============= ============= +============================================ ================================ ============= ============= +Feature Feature Test Macro Introduced In Backported To +============================================ ================================ ============= ============= +variadic templates __cpp_variadic_templates C++11 C++03 +Alias templates __cpp_alias_templates C++11 C++03 +Non-static data member initializers __cpp_nsdmi C++11 C++03 +Range-based ``for`` loop __cpp_range_based_for C++11 C++03 +RValue references __cpp_rvalue_references C++11 C++03 +Attributes __cpp_attributes C++11 C++03 +Lambdas __cpp_lambdas C++11 C++03 +Generalized lambda captures __cpp_init_captures C++14 C++03 +Generic lambda expressions __cpp_generic_lambdas C++14 C++03 +variable templates __cpp_variable_templates C++14 C++03 +Binary literals __cpp_binary_literals C++14 C++03 +Relaxed constexpr __cpp_constexpr C++14 C++11 +Pack expansion in generalized lambda-capture __cpp_init_captures C++17 C++03 +``if constexpr`` __cpp_if_constexpr C++17 C++11 +fold expressions __cpp_fold_expressions C++17 C++03 +Lambda capture of \*this by value __cpp_capture_star_this C++17 C++03 +Attributes on enums __cpp_enumerator_attributes C++17 C++03 +Guaranteed copy elision __cpp_guaranteed_copy_elision C++17 C++03 +Hexadecimal floating literals __cpp_hex_float C++17 C++03 +``inline`` variables __cpp_inline_variables C++17 C++03 +Attributes on namespaces __cpp_namespace_attributes C++17 C++11 +Structured bindings __cpp_structured_bindings C++17 C++03 +template template arguments __cpp_template_template_args C++17 C++03 +Familiar template syntax for generic lambdas __cpp_generic_lambdas C++20 C++03 +``static operator[]`` __cpp_multidimensional_subscript C++20 C++03 +Designated initializers __cpp_designated_initializers C++20 C++03 +Conditional ``explicit`` __cpp_conditional_explicit C++20 C++03 +``using enum`` __cpp_using_enum C++20 C++03 +``if consteval`` __cpp_if_consteval C++23 C++20 +``static operator()`` __cpp_static_call_operator C++23 C++03 +Attributes on Lambda-Expressions C++23 C++11 +-------------------------------------------- -------------------------------- ------------- ------------- +Designated initializers (N494) C99 C89 +Array & element qualification (N2607) C23 C89 +Attributes (N2335) C23 C89 +============================================ ================================ ============= ============= Type Trait Primitives ===================== diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 125d51c42d507..820bb03ac87e1 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -177,6 +177,8 @@ Non-comprehensive list of changes in this release the previous builtins, this new builtin is constexpr and may be used in constant expressions. +- Lambda expressions are now accepted in C++03 mode as an extension. + New Compiler Flags ------------------ diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 816c3ff5f8b2a..48de5e2ef5f4a 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1029,6 +1029,7 @@ 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, DefaultIgnore; +def ext_lambda : ExtWarn<"lambdas are a C++11 extension">, InGroup; def err_lambda_decl_specifier_repeated : Error< "%select{'mutable'|'static'|'constexpr'|'consteval'}0 cannot " "appear multiple times in a lambda declarator">; diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index eeed5f4751f2f..17fb4c9d20d8a 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -258,6 +258,7 @@ EXTENSION(cxx_defaulted_functions, LangOpts.CPlusPlus) EXTENSION(cxx_deleted_functions, LangOpts.CPlusPlus) EXTENSION(cxx_explicit_conversions, LangOpts.CPlusPlus) EXTENSION(cxx_inline_namespaces, LangOpts.CPlusPlus) +EXTENSION(cxx_lambdas, LangOpts.CPlusPlus) EXTENSION(cxx_local_type_template_args, LangOpts.CPlusPlus) EXTENSION(cxx_nonstatic_member_init, LangOpts.CPlusPlus) EXTENSION(cxx_override_control, LangOpts.CPlusPlus) diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 88c3a1469e8ed..ae23cb432c439 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1823,7 +1823,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, } goto ExpectedExpression; case tok::l_square: - if (getLangOpts().CPlusPlus11) { + if (getLangOpts().CPlusPlus) { if (getLangOpts().ObjC) { // C++11 lambda expressions and Objective-C message sends both start with a // square bracket. There are three possibilities here: diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 9471f6f725efb..73c85c585baae 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -806,9 +806,8 @@ ExprResult Parser::ParseLambdaExpression() { /// /// If we are not looking at a lambda expression, returns ExprError(). ExprResult Parser::TryParseLambdaExpression() { - assert(getLangOpts().CPlusPlus11 - && Tok.is(tok::l_square) - && "Not at the start of a possible lambda expression."); + assert(getLangOpts().CPlusPlus && Tok.is(tok::l_square) && + "Not at the start of a possible lambda expression."); const Token Next = NextToken(); if (Next.is(tok::eof)) // Nothing else to lookup here... @@ -1326,7 +1325,9 @@ static void DiagnoseStaticSpecifierRestrictions(Parser &P, ExprResult Parser::ParseLambdaExpressionAfterIntroducer( LambdaIntroducer &Intro) { SourceLocation LambdaBeginLoc = Intro.Range.getBegin(); - Diag(LambdaBeginLoc, diag::warn_cxx98_compat_lambda); + Diag(LambdaBeginLoc, getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_lambda + : diag::ext_lambda); PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), LambdaBeginLoc, "lambda expression parsing"); diff --git a/clang/lib/Parse/ParseInit.cpp b/clang/lib/Parse/ParseInit.cpp index 637f21176792b..423497bfcb662 100644 --- a/clang/lib/Parse/ParseInit.cpp +++ b/clang/lib/Parse/ParseInit.cpp @@ -35,7 +35,7 @@ bool Parser::MayBeDesignationStart() { return true; case tok::l_square: { // designator: array-designator - if (!PP.getLangOpts().CPlusPlus11) + if (!PP.getLangOpts().CPlusPlus) return true; // C++11 lambda expressions and C99 designators can be ambiguous all the diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 5850cd0ab6b9a..8ad4947bbe3c3 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -16115,7 +16115,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, FD->setInvalidDecl(); } } - } else if (getLangOpts().CPlusPlus11 && isLambdaCallOperator(FD)) { + } else if (getLangOpts().CPlusPlus && isLambdaCallOperator(FD)) { // In C++11, we don't use 'auto' deduction rules for lambda call // operators because we don't support return type deduction. auto *LSI = getCurLambda(); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index e258a4f7c8941..ee732679417e3 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -9738,7 +9738,8 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, return false; CXXRecordDecl *RD = MD->getParent(); assert(!RD->isDependentType() && "do deletion after instantiation"); - if (!LangOpts.CPlusPlus11 || RD->isInvalidDecl()) + if (!LangOpts.CPlusPlus || (!LangOpts.CPlusPlus11 && !RD->isLambda()) || + RD->isInvalidDecl()) return false; // C++11 [expr.lambda.prim]p19: diff --git a/clang/test/Lexer/has_extension_cxx.cpp b/clang/test/Lexer/has_extension_cxx.cpp index 7941997428aca..7366029d3727a 100644 --- a/clang/test/Lexer/has_extension_cxx.cpp +++ b/clang/test/Lexer/has_extension_cxx.cpp @@ -33,6 +33,11 @@ int has_deleted_functions(); int has_inline_namespaces(); #endif +// CHECK: has_lambdas +#if __has_extension(cxx_lambdas) +int has_lambdas(); +#endif + // CHECK: has_override_control #if __has_extension(cxx_override_control) int has_override_control(); diff --git a/clang/test/OpenMP/declare_reduction_messages.cpp b/clang/test/OpenMP/declare_reduction_messages.cpp index 38a5d766eeadf..752cc4fb05a12 100644 --- a/clang/test/OpenMP/declare_reduction_messages.cpp +++ b/clang/test/OpenMP/declare_reduction_messages.cpp @@ -58,16 +58,10 @@ class Class2 : public Class1 { #pragma omp declare reduction(fun1 : long : omp_out += omp_in) initializer // expected-error {{expected '(' after 'initializer'}} #pragma omp declare reduction(fun2 : long : omp_out += omp_in) initializer { // expected-error {{expected '(' after 'initializer'}} expected-error {{expected expression}} expected-warning {{extra tokens at the end of '#pragma omp declare reduction' are ignored}} #pragma omp declare reduction(fun3 : long : omp_out += omp_in) initializer[ -#if __cplusplus <= 199711L -// expected-error@-2 {{expected '(' after 'initializer'}} -// expected-error@-3 {{expected expression}} -// expected-warning@-4 {{extra tokens at the end of '#pragma omp declare reduction' are ignored}} -#else -// expected-error@-6 {{expected '(' after 'initializer'}} -// expected-error@-7 {{expected variable name or 'this' in lambda capture list}} -// expected-error@-8 {{expected ')'}} -// expected-note@-9 {{to match this '('}} -#endif +// expected-error@-1 {{expected '(' after 'initializer'}} +// expected-error@-2 {{expected variable name or 'this' in lambda capture list}} +// expected-error@-3 {{expected ')'}} +// expected-note@-4 {{to match this '('}} #pragma omp declare reduction(fun4 : long : omp_out += omp_in) initializer() // expected-error {{expected expression}} #pragma omp declare reduction(fun5 : long : omp_out += omp_in) initializer(temp) // expected-error {{only 'omp_priv' or 'omp_orig' variables are allowed in initializer expression}} #pragma omp declare reduction(fun6 : long : omp_out += omp_in) initializer(omp_orig // expected-error {{expected ')'}} expected-note {{to match this '('}} diff --git a/clang/test/OpenMP/openmp_check.cpp b/clang/test/OpenMP/openmp_check.cpp index 6a8dd17fc8367..b52ce0c066922 100644 --- a/clang/test/OpenMP/openmp_check.cpp +++ b/clang/test/OpenMP/openmp_check.cpp @@ -18,7 +18,7 @@ int nested(int a) { auto F = [&]() { #if __cplusplus <= 199711L // expected-warning@-2 {{'auto' type specifier is a C++11 extension}} - // expected-error@-3 {{expected expression}} + // expected-warning@-3 {{lambdas are a C++11 extension}} #endif #pragma omp parallel diff --git a/clang/test/Parser/cxx03-lambda-extension.cpp b/clang/test/Parser/cxx03-lambda-extension.cpp new file mode 100644 index 0000000000000..82ae7da305305 --- /dev/null +++ b/clang/test/Parser/cxx03-lambda-extension.cpp @@ -0,0 +1,5 @@ +// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++03 %s + +void func() { + []() {}; // expected-warning {{lambdas are a C++11 extension}} +} diff --git a/clang/test/Parser/cxx0x-lambda-expressions.cpp b/clang/test/Parser/cxx0x-lambda-expressions.cpp index 72b315a497c06..a786a964163e4 100644 --- a/clang/test/Parser/cxx0x-lambda-expressions.cpp +++ b/clang/test/Parser/cxx0x-lambda-expressions.cpp @@ -1,10 +1,15 @@ -// 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++20 -Wno-c99-designator %s -// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++23 -Wno-c99-designator %s +// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify=expected,cxx14ext,cxx17ext,cxx20ext,cxx23ext -std=c++03 -Wno-c99-designator %s -Wno-c++11-extensions +// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify=expected,cxx14ext,cxx17ext,cxx20ext,cxx23ext -std=c++11 -Wno-c99-designator %s +// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify=expected,cxx17ext,cxx20ext,cxx23ext -std=c++14 -Wno-c99-designator %s +// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify=expected,cxx20ext,cxx23ext -std=c++17 -Wno-c99-designator %s +// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify=expected,cxx23ext -std=c++20 -Wno-c99-designator %s +// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify=expected -std=c++23 -Wno-c99-designator %s enum E { e }; +#if __cplusplus >= 201103L constexpr int id(int n) { return n; } +#endif class C { @@ -19,28 +24,25 @@ class C { [&,] {}; // 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; }; - [=,&foo] () {}; - [&,foo] () {}; - [this] () {}; + [=] (int i) {}; + [&] (int) mutable -> void {}; + [foo,bar] () { return 3; }; + [=,&foo] () {}; + [&,foo] () {}; + [this] () {}; [] () -> class C { return C(); }; [] () -> enum E { return e; }; - [] -> int { return 0; }; - [] mutable -> int { return 0; }; -#if __cplusplus <= 202002L - // expected-warning@-3 {{lambda without a parameter clause is a C++23 extension}} - // expected-warning@-3 {{is a C++23 extension}} -#endif + [] -> int { return 0; }; // cxx23ext-warning {{lambda without a parameter clause is a C++23 extension}} + [] mutable -> int { return 0; }; // cxx23ext-warning {{is a C++23 extension}} + [](int) -> {}; // PR13652 expected-error {{expected a type}} return 1; } void designator_or_lambda() { - typedef int T; - const int b = 0; + typedef int T; + const int b = 0; const int c = 1; int d; int a1[1] = {[b] (T()) {}}; // expected-error{{no viable conversion from '(lambda}} @@ -49,19 +51,18 @@ class C { int a4[1] = {[&b] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'const int *'}} int a5[3] = { []{return 0;}() }; int a6[1] = {[this] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'C *'}} - int a7[1] = {[d(0)] { return d; } ()}; - int a8[1] = {[d = 0] { return d; } ()}; - int a10[1] = {[id(0)] { return id; } ()}; -#if __cplusplus <= 201103L - // expected-warning@-4{{extension}} - // expected-warning@-4{{extension}} - // expected-warning@-4{{extension}} + int a7[1] = {[d(0)] { return d; } ()}; // cxx14ext-warning {{initialized lambda captures are a C++14 extension}} + int a8[1] = {[d = 0] { return d; } ()}; // cxx14ext-warning {{initialized lambda captures are a C++14 extension}} +#if __cplusplus >= 201103L + int a10[1] = {[id(0)] { return id; } ()}; // cxx14ext-warning {{initialized lambda captures are a C++14 extension}} #endif int a9[1] = {[d = 0] = 1}; // expected-error{{is not an integral constant expression}} #if __cplusplus >= 201402L // expected-note@-2{{constant expression cannot modify an object that is visible outside that expression}} #endif +#if __cplusplus >= 201103L int a11[1] = {[id(0)] = 1}; +#endif } void delete_lambda(int *p) { @@ -80,43 +81,33 @@ class C { // We support init-captures in C++11 as an extension. int z; void init_capture() { - [n(0)] () mutable -> int { return ++n; }; - [n{0}] { return; }; - [a([&b = z]{})](){}; - [n = 0] { return ++n; }; // expected-error {{captured by copy in a non-mutable}} - [n = {0}] { return; }; // expected-error {{}} -#if __cplusplus <= 201103L - // expected-warning@-6{{extension}} - // expected-warning@-6{{extension}} - // expected-warning@-6{{extension}} - // expected-warning@-7{{extension}} - // expected-warning@-7{{extension}} - // expected-warning@-7{{extension}} -#endif + [n(0)] () mutable -> int { return ++n; }; // cxx14ext-warning {{initialized lambda captures are a C++14 extension}} + [n{0}] { return; }; // cxx14ext-warning {{initialized lambda captures are a C++14 extension}} + [a([&b = z]{})](){}; // cxx14ext-warning 2 {{initialized lambda captures are a C++14 extension}} + [n = 0] { return ++n; }; // expected-error {{captured by copy in a non-mutable}} + // cxx14ext-warning@-1 {{initialized lambda captures are a C++14 extension}} + [n = {0}] { return; }; // expected-error {{}} + // cxx14ext-warning@-1 {{initialized lambda captures are a C++14 extension}} int x = 4; - auto y = [&r = x, x = x + 1]() -> int { -#if __cplusplus <= 201103L - // expected-warning@-2{{extension}} - // expected-warning@-3{{extension}} -#endif + auto y = [&r = x, x = x + 1]() -> int { // cxx14ext-warning 2 {{initialized lambda captures are a C++14 extension}} r += 2; return x + 2; } (); } void attributes() { - [] __attribute__((noreturn)){}; -#if __cplusplus <= 202002L - // expected-warning@-2 {{is a C++23 extension}} -#endif + [] __attribute__((noreturn)){}; // cxx23ext-warning {{lambda without a parameter clause is a C++23 extension}} + []() [[]] mutable {}; // expected-error {{expected body of lambda expression}} []() [[]] {}; []() [[]] -> void {}; []() mutable [[]] -> void {}; +#if __cplusplus >= 201103L []() mutable noexcept [[]] -> void {}; +#endif // Testing GNU-style attributes on lambdas -- the attribute is specified // before the mutable specifier instead of after (unlike C++11). @@ -126,28 +117,18 @@ class C { // Testing support for P2173 on adding attributes to the declaration // rather than the type. - [][[]](){}; -#if __cplusplus <= 202002L - // expected-warning@-2 {{an attribute specifier sequence in this position is a C++23 extension}} -#endif -#if __cplusplus > 201703L - [][[]](){}; -#if __cplusplus <= 202002L - // expected-warning@-2 {{an attribute specifier sequence in this position is a C++23 extension}} -#endif -#endif - [][[]]{}; -#if __cplusplus <= 202002L - // expected-warning@-2 {{an attribute specifier sequence in this position is a C++23 extension}} -#endif + [][[]](){}; // cxx23ext-warning {{an attribute specifier sequence in this position is a C++23 extension}} + + [][[]](){}; // 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}} + + [][[]]{}; // cxx23ext-warning {{an attribute specifier sequence in this position is a C++23 extension}} } void missing_parens() { - [] mutable {}; - [] noexcept {}; -#if __cplusplus <= 202002L - // expected-warning@-3 {{is a C++23 extension}} - // expected-warning@-3 {{is a C++23 extension}} + [] mutable {}; // cxx23ext-warning {{is a C++23 extension}} +#if __cplusplus >= 201103L + [] noexcept {}; // cxx23ext-warning {{is a C++23 extension}} #endif } }; @@ -165,10 +146,7 @@ struct A { }; struct S { - void mf() { A{[*this]{}}; } -#if __cplusplus < 201703L - // expected-warning@-2 {{C++17 extension}} -#endif + void mf() { A(([*this]{})); } // cxx17ext-warning {{'*this' by copy is a C++17 extension}} }; } diff --git a/clang/test/Parser/cxx2b-lambdas.cpp b/clang/test/Parser/cxx2b-lambdas.cpp index ad975a17b6e47..758ec9a42f56d 100644 --- a/clang/test/Parser/cxx2b-lambdas.cpp +++ b/clang/test/Parser/cxx2b-lambdas.cpp @@ -1,30 +1,48 @@ +// 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 {}; -auto LL3 = []() constexpr {}; +#if __cplusplus >= 201103L +auto LL3 = []() constexpr {}; // cxx11-error {{return type 'void' is not a literal type}} +#endif -auto L0 = [] constexpr {}; +#if __cplusplus >= 201103L +auto L0 = [] constexpr {}; // cxx11-error {{return type 'void' is not a literal type}} +#endif auto L1 = [] mutable {}; +#if __cplusplus >= 201103L auto L2 = [] noexcept {}; -auto L3 = [] constexpr mutable {}; -auto L4 = [] mutable constexpr {}; -auto L5 = [] constexpr mutable 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}} +#endif auto L6 = [s = 1] mutable {}; -auto L7 = [s = 1] constexpr mutable noexcept {}; +#if __cplusplus >= 201103L +auto L7 = [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; }; +#if __cplusplus >= 201103L auto L10 = [] noexcept { return true; }; +#endif auto L11 = [] -> 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 {}; +#endif auto L16 = [] [[maybe_unused]]{}; -auto XL0 = [] mutable constexpr mutable {}; // expected-error{{cannot appear multiple times}} -auto XL1 = [] constexpr mutable constexpr {}; // expected-error{{cannot appear multiple times}} +#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}} \ @@ -33,16 +51,23 @@ auto XL3 = []( constexpr mutable constexpr {}; // expected-error{{invalid storag // 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 >= 201703L auto XL5 = [] requires true requires true {}; // expected-error{{expected body}} auto XL6 = [] 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}} +#if __cplusplus >= 202002L auto XL9 = []() static consteval {}; -auto XL10 = []() static constexpr {}; +#endif +#if __cplusplus >= 201103L +auto XL10 = []() static constexpr {}; // cxx11-error {{return type 'void' is not a literal type}} +#endif auto XL11 = [] static {}; auto XL12 = []() static {}; @@ -67,6 +92,7 @@ void static_captures() { }; } +#if __cplusplus >= 201703L constexpr auto static_capture_constexpr() { char n = 'n'; return [n] static { return n; }(); // expected-error {{a static lambda cannot have any captures}} @@ -78,3 +104,4 @@ constexpr auto capture_constexpr() { return [n] { return n; }(); } static_assert(capture_constexpr()); +#endif diff --git a/clang/test/Parser/objcxx-lambda-expressions-neg.mm b/clang/test/Parser/objcxx-lambda-expressions-neg.mm index b2fe39dfbf708..795157816dcfd 100644 --- a/clang/test/Parser/objcxx-lambda-expressions-neg.mm +++ b/clang/test/Parser/objcxx-lambda-expressions-neg.mm @@ -1,13 +1,8 @@ // RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify %s -// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++98 %s +// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify=cxx03 -std=c++98 %s // RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++11 %s int main() { - []{}; -#if __cplusplus <= 199711L - // expected-error@-2 {{expected expression}} -#else + []{}; // cxx03-warning {{lambdas are a C++11 extension}} // expected-no-diagnostics -#endif - } diff --git a/clang/test/ParserHLSL/group_shared.hlsl b/clang/test/ParserHLSL/group_shared.hlsl index 0b9f28395ee48..44f3a2e5b4505 100644 --- a/clang/test/ParserHLSL/group_shared.hlsl +++ b/clang/test/ParserHLSL/group_shared.hlsl @@ -3,8 +3,8 @@ extern groupshared float f; extern float groupshared f; // Ok, redeclaration? -// NOTE:lambda is not enabled except for hlsl202x. -// expected-error@+2 {{expected expression}} +// expected-warning@+3 {{lambdas are a C++11 extension}} +// expected-error@+2 {{expected body of lambda expression}} // expected-warning@+1 {{'auto' type specifier is a C++11 extension}} auto l = []() groupshared {}; diff --git a/clang/test/SemaCXX/cxx2a-template-lambdas.cpp b/clang/test/SemaCXX/cxx2a-template-lambdas.cpp index 7ac4813698914..fff524e77d3bf 100644 --- a/clang/test/SemaCXX/cxx2a-template-lambdas.cpp +++ b/clang/test/SemaCXX/cxx2a-template-lambdas.cpp @@ -1,10 +1,14 @@ -// RUN: %clang_cc1 -std=c++2a -verify %s +// RUN: %clang_cc1 -std=c++03 -verify -Dstatic_assert=_Static_assert -Wno-c++11-extensions -Wno-c++14-extensions -Wno-c++17-extensions -Wno-c++20-extensions %s +// RUN: %clang_cc1 -std=c++11 -verify=expected,cxx11,cxx11-cxx14 -Wno-c++20-extensions -Wno-c++17-extensions -Wno-c++14-extensions %s +// RUN: %clang_cc1 -std=c++14 -verify=expected,cxx11-cxx14,cxx14 -Wno-c++20-extensions -Wno-c++17-extensions %s +// RUN: %clang_cc1 -std=c++17 -verify -Wno-c++20-extensions %s +// RUN: %clang_cc1 -std=c++20 -verify %s template -constexpr bool is_same = false; +inline const bool is_same = false; template -constexpr bool is_same = true; +inline const bool is_same = true; template struct DummyTemplate { }; @@ -23,7 +27,7 @@ void func() { L1.operator()<6>(); // expected-note {{in instantiation}} auto L2 = [] class T, class U>(T &&arg) { - static_assert(is_same, DummyTemplate>); // // expected-error {{static assertion failed}} + static_assert(is_same, DummyTemplate >); // // expected-error {{static assertion failed}} }; L2(DummyTemplate()); L2(DummyTemplate()); // expected-note {{in instantiation}} @@ -36,15 +40,20 @@ struct ShadowMe { } }; +#if __cplusplus >= 201102L template constexpr T outer() { - return []() { return x; }.template operator()<123>(); // expected-error {{no matching member function}} \ - expected-note {{candidate template ignored}} + // FIXME: The C++11 error seems wrong + return []() { return x; }.template operator()<123>(); // expected-error {{no matching member function}} \ + expected-note {{candidate template ignored}} \ + cxx11-note {{non-literal type '' cannot be used in a constant expression}} \ + cxx14-note {{non-literal type}} } -static_assert(outer() == 123); +static_assert(outer() == 123); // cxx11-cxx14-error {{not an integral constant expression}} cxx11-cxx14-note {{in call}} template int *outer(); // expected-note {{in instantiation}} +#endif - +#if __cplusplus >= 202002L namespace GH62611 { template struct C { @@ -87,3 +96,4 @@ void foo() { } } +#endif diff --git a/clang/test/SemaCXX/lambda-expressions.cpp b/clang/test/SemaCXX/lambda-expressions.cpp index 389002ab0e349..151d74f21d64d 100644 --- a/clang/test/SemaCXX/lambda-expressions.cpp +++ b/clang/test/SemaCXX/lambda-expressions.cpp @@ -1,6 +1,7 @@ -// RUN: %clang_cc1 -std=c++11 -Wno-unused-value -fsyntax-only -verify=expected,expected-cxx14,cxx11 -fblocks %s -// RUN: %clang_cc1 -std=c++14 -Wno-unused-value -fsyntax-only -verify -verify=expected-cxx14 -fblocks %s -// RUN: %clang_cc1 -std=c++17 -Wno-unused-value -verify -ast-dump -fblocks %s | FileCheck %s +// RUN: %clang_cc1 -std=c++11 -Wno-unused-value -fsyntax-only -verify=expected,not-cxx03,cxx03-cxx11,cxx11,expected-cxx14 -fblocks %s +// RUN: %clang_cc1 -std=c++03 -Wno-unused-value -fsyntax-only -verify=expected,cxx03,cxx03-cxx11,expected-cxx14 -fblocks %s -Ddecltype=__decltype -Dstatic_assert=_Static_assert -Wno-c++11-extensions +// RUN: %clang_cc1 -std=c++14 -Wno-unused-value -fsyntax-only -verify=expected,not-cxx03,expected-cxx14 -fblocks %s +// RUN: %clang_cc1 -std=c++17 -Wno-unused-value -verify=expected,not-cxx03 -ast-dump -fblocks %s | FileCheck %s namespace std { class type_info; }; @@ -93,14 +94,14 @@ namespace ImplicitCapture { [] { return ref_i; }; // expected-error {{variable 'ref_i' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}} expected-note 2 {{capture 'ref_i' by}} expected-note 2 {{default capture by}} static int j; - int &ref_j = j; - [] { return ref_j; }; // ok + int &ref_j = j; // cxx03-note {{declared here}} + [] { return ref_j; }; // cxx03-error {{variable 'ref_j' cannot be implicitly captured in a lambda with no capture-default specified}} cxx03-note 4 {{capture}} cxx03-note {{lambda expression begins here}} } } namespace SpecialMembers { void f() { - auto a = []{}; // expected-note 2{{here}} expected-note 2{{candidate}} + auto a = []{}; // expected-note 2{{here}} expected-note {{candidate}} not-cxx03-note {{candidate}} decltype(a) b; // expected-error {{no matching constructor}} decltype(a) c = a; decltype(a) d = static_cast(a); @@ -213,7 +214,7 @@ namespace VariadicPackExpansion { }; template void local_class() { - sink { + sink s( [] (Ts t) { struct S : Ts { void f(Ts t) { @@ -226,7 +227,7 @@ namespace VariadicPackExpansion { s.f(t); return s; } (Ts()).g() ... - }; + ); }; struct X {}; struct Y {}; template void local_class(); @@ -296,7 +297,7 @@ namespace PR16708 { namespace TypeDeduction { struct S {}; void f() { - const S s {}; + const S s = S(); S &&t = [&] { return s; } (); #if __cplusplus > 201103L S &&u = [&] () -> auto { return s; } (); @@ -308,7 +309,7 @@ namespace TypeDeduction { namespace lambdas_in_NSDMIs { template struct L { - T t{}; + T t = T(); T t2 = ([](int a) { return [](int b) { return b; };})(t)(t); }; L l; @@ -345,6 +346,7 @@ namespace CaptureIncomplete { } } +#if __cplusplus >= 201103L namespace CaptureAbstract { struct S { virtual void f() = 0; // expected-note {{unimplemented}} @@ -362,6 +364,7 @@ namespace CaptureAbstract { [=] { return s.n; }; // expected-error {{abstract}} } } +#endif namespace PR18128 { auto l = [=]{}; // expected-error {{non-local lambda expression cannot have a capture-default}} @@ -372,6 +375,8 @@ namespace PR18128 { // expected-error@-1 {{non-local lambda expression cannot have a capture-default}} // expected-error@-2 {{invalid use of non-static data member 'n'}} // expected-cxx14-error@-3 {{a lambda expression may not appear inside of a constant expression}} + // cxx03-error@-4 {{function declaration cannot have variably modified type}} + // cxx03-warning@-5 {{variable length arrays in C++ are a Clang extension}} int g(int k = ([=]{ return n; }(), 0)); // expected-error@-1 {{non-local lambda expression cannot have a capture-default}} // expected-error@-2 {{invalid use of non-static data member 'n'}} @@ -434,13 +439,13 @@ struct A { template void g(F f) { - auto a = A{}; + auto a = A(); // expected-note@-1 {{in instantiation of template class 'PR20731::A' requested here}} auto xf = [a, f]() {}; int x = sizeof(xf); }; void f() { - g([] {}); + g([] {}); // cxx03-warning {{template argument uses local type}} // expected-note-re@-1 {{in instantiation of function template specialization 'PR20731::g<(lambda at {{.*}}>' requested here}} } @@ -491,8 +496,8 @@ namespace PR21857 { fun() = default; using Fn::operator(); }; - template fun wrap(Fn fn); - auto x = wrap([](){}); + template fun wrap(Fn fn); // cxx03-warning {{template argument uses unnamed type}} + auto x = wrap([](){}); // cxx03-warning {{template argument uses unnamed type}} cxx03-note 2 {{unnamed type used in template argument was declared here}} } namespace PR13987 { @@ -559,8 +564,8 @@ struct B { int x; A a = [&] { int y = x; }; A b = [&] { [&] { [&] { int y = x; }; }; }; - A d = [&](auto param) { int y = x; }; // cxx11-error {{'auto' not allowed in lambda parameter}} - A e = [&](auto param) { [&] { [&](auto param2) { int y = x; }; }; }; // cxx11-error 2 {{'auto' not allowed in lambda parameter}} + A d = [&](auto param) { int y = x; }; // cxx03-cxx11-error {{'auto' not allowed in lambda parameter}} + A e = [&](auto param) { [&] { [&](auto param2) { int y = x; }; }; }; // cxx03-cxx11-error 2 {{'auto' not allowed in lambda parameter}} }; B b; @@ -588,9 +593,9 @@ struct S1 { }; void foo1() { - auto s0 = S1{[name=]() {}}; // expected-error 2 {{expected expression}} - auto s1 = S1{[name=name]() {}}; // expected-error {{use of undeclared identifier 'name'; did you mean 'name1'?}} - // cxx11-warning@-1 {{initialized lambda captures are a C++14 extension}} + auto s0 = S1([name=]() {}); // expected-error {{expected expression}} + auto s1 = S1([name=name]() {}); // expected-error {{use of undeclared identifier 'name'; did you mean 'name1'?}} + // cxx03-cxx11-warning@-1 {{initialized lambda captures are a C++14 extension}} } } @@ -606,7 +611,7 @@ namespace PR25627_dont_odr_use_local_consts { namespace ConversionOperatorDoesNotHaveDeducedReturnType { auto x = [](int){}; - auto y = [](auto &v) -> void { v.n = 0; }; // cxx11-error {{'auto' not allowed in lambda parameter}} cxx11-note {{candidate function not viable}} cxx11-note {{conversion candidate}} + auto y = [](auto &v) -> void { v.n = 0; }; // cxx03-cxx11-error {{'auto' not allowed in lambda parameter}} cxx03-cxx11-note {{candidate function not viable}} cxx03-cxx11-note {{conversion candidate}} using T = decltype(x); using U = decltype(y); using ExpectedTypeT = void (*)(int); @@ -626,14 +631,15 @@ namespace ConversionOperatorDoesNotHaveDeducedReturnType { template friend constexpr U::operator ExpectedTypeU() const noexcept; #else - friend auto T::operator()(int) const; // cxx11-error {{'auto' return without trailing return type; deduced return types are a C++14 extension}} + friend auto T::operator()(int) const; // cxx11-error {{'auto' return without trailing return type; deduced return types are a C++14 extension}} \ + cxx03-error {{'auto' not allowed in function return type}} friend T::operator ExpectedTypeT() const; template - friend void U::operator()(T&) const; // cxx11-error {{friend declaration of 'operator()' does not match any declaration}} + friend void U::operator()(T&) const; // cxx03-cxx11-error {{friend declaration of 'operator()' does not match any declaration}} // FIXME: This should not match, as above. template - friend U::operator ExpectedTypeU() const; // cxx11-error {{friend declaration of 'operator void (*)(type-parameter-0-0 &)' does not match any declaration}} + friend U::operator ExpectedTypeU() const; // cxx03-cxx11-error {{friend declaration of 'operator void (*)(type-parameter-0-0 &)' does not match any declaration}} #endif private: @@ -641,7 +647,7 @@ namespace ConversionOperatorDoesNotHaveDeducedReturnType { }; // Should be OK in C++14 and later: lambda's call operator is a friend. - void use(X &x) { y(x); } // cxx11-error {{no matching function for call to object}} + void use(X &x) { y(x); } // cxx03-cxx11-error {{no matching function for call to object}} // This used to crash in return type deduction for the conversion opreator. struct A { int n; void f() { +[](decltype(n)) {}; } }; @@ -682,8 +688,8 @@ namespace GH60518 { // function parameters that are used in enable_if struct StringLiteral { template -StringLiteral(const char (&array)[N]) - __attribute__((enable_if(__builtin_strlen(array) == 2, +StringLiteral(const char (&array)[N]) // cxx03-note {{declared here}} + __attribute__((enable_if(__builtin_strlen(array) == 2, // cxx03-error {{'enable_if' attribute expression never produces a constant expression}} cxx03-note {{read of variable}} "invalid string literal"))); }; @@ -695,7 +701,7 @@ StringLiteral(const char (&array)[N]) [[clang::annotate_type("test", array)]]; } void Func1() { - [[maybe_unused]] auto y = [&](decltype(StringLiteral("xx"))) {}; + [[maybe_unused]] auto y = [&](decltype(StringLiteral("xx"))) {}; // cxx03-note {{in instantiation of function template specialization}} [[maybe_unused]] auto z = [&](decltype(cpp_attribute::StringLiteral("xx"))) {}; } @@ -718,6 +724,7 @@ static_assert([]() constexpr { // Call operator attributes refering to a variable should // be properly handled after D124351 +#if __cplusplus >= 201103L constexpr int i = 2; void foo() { (void)[=][[gnu::aligned(i)]] () {}; // expected-warning{{C++23 extension}} @@ -725,15 +732,18 @@ void foo() { // CHECK-NEXT: ConstantExpr // CHECK-NEXT: value: Int 2 } +#endif void GH48527() { auto a = []()__attribute__((b(({ return 0; })))){}; // expected-warning {{unknown attribute 'b' ignored}} } +#if __cplusplus >= 201103L void GH67492() { constexpr auto test = 42; auto lambda = (test, []() noexcept(true) {}); } +#endif // FIXME: This currently causes clang to crash in C++11 mode. #if __cplusplus >= 201402L diff --git a/clang/test/SemaCXX/lambda-implicit-this-capture.cpp b/clang/test/SemaCXX/lambda-implicit-this-capture.cpp index 7e0e347a8fee7..eb1f9e880aec0 100644 --- a/clang/test/SemaCXX/lambda-implicit-this-capture.cpp +++ b/clang/test/SemaCXX/lambda-implicit-this-capture.cpp @@ -1,3 +1,4 @@ +// RUN: %clang_cc1 -std=c++03 -verify=cxx11 %s -Wno-c++11-extensions // RUN: %clang_cc1 -std=c++11 -verify=cxx11 %s // RUN: %clang_cc1 -std=c++2a -verify=cxx2a %s // RUN: %clang_cc1 -std=c++2a -verify=cxx2a-no-deprecated %s -Wno-deprecated diff --git a/clang/test/SemaCXX/lambda-invalid-capture.cpp b/clang/test/SemaCXX/lambda-invalid-capture.cpp index 236753871d701..5be8c8c5078f2 100644 --- a/clang/test/SemaCXX/lambda-invalid-capture.cpp +++ b/clang/test/SemaCXX/lambda-invalid-capture.cpp @@ -1,3 +1,4 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++03 -Wno-c++11-extensions %s // RUN: %clang_cc1 -fsyntax-only -verify %s // Don't crash. diff --git a/clang/test/SemaCXX/new-delete.cpp b/clang/test/SemaCXX/new-delete.cpp index 4f78b7c71a91c..1a99c6aac604f 100644 --- a/clang/test/SemaCXX/new-delete.cpp +++ b/clang/test/SemaCXX/new-delete.cpp @@ -171,12 +171,7 @@ void good_deletes() void bad_deletes() { delete 0; // expected-error {{cannot delete expression of type 'int'}} - delete [0] (int*)0; -#if __cplusplus <= 199711L - // expected-error@-2 {{expected expression}} -#else - // expected-error@-4 {{expected variable name or 'this' in lambda capture list}} -#endif + delete [0] (int*)0; // expected-error {{expected variable name or 'this' in lambda capture list}} delete (void*)0; // expected-warning {{cannot delete expression with pointer-to-'void' type 'void *'}} delete (T*)0; // expected-warning {{deleting pointer to incomplete type}} ::S::delete (int*)0; // expected-error {{expected unqualified-id}}