https://github.com/philnik777 created https://github.com/llvm/llvm-project/pull/73376
This is a fairly simple extension, but makes the life for people who have to support C++03 a lot easier. As a nice bonus, this also improves diagnostics, since lambdas are now properly recognized when parsing C++03 code. >From b08f0a6621fe50f5da564c4b4cbf8fae12778c12 Mon Sep 17 00:00:00 2001 From: Nikolas Klauser <nikolasklau...@berlin.de> Date: Sat, 25 Nov 2023 04:00:57 +0100 Subject: [PATCH] [clang] Accept lambdas in C++03 as an extensions This is a fairly simple extension, but makes the life for people who have to support C++03 a lot easier. As a nice bonus, this also improves diagnostics, since lambdas are now properly recognized when parsing C++03 code. --- .../clang/Basic/DiagnosticParseKinds.td | 1 + clang/lib/Parse/ParseExpr.cpp | 2 +- clang/lib/Parse/ParseExprCXX.cpp | 4 +- clang/lib/Parse/ParseInit.cpp | 2 +- .../test/Parser/cxx0x-lambda-expressions.cpp | 116 +++++++----------- 5 files changed, 53 insertions(+), 72 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index b66ecf0724b1c77..c8616cacda62280 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1030,6 +1030,7 @@ def err_capture_default_first : Error< def ext_decl_attrs_on_lambda : ExtWarn< "%select{an attribute specifier sequence|%0}1 in this position " "is a C++23 extension">, InGroup<CXX23>; +def ext_lambda : ExtWarn<"lambdas are a C++11 extension">, InGroup<CXX11>; def ext_lambda_missing_parens : ExtWarn< "lambda without a parameter clause is a C++23 extension">, InGroup<CXX23>; diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 897810557976151..c453d77329111f6 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1799,7 +1799,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 79db094e098f8e6..9b459e8a4d3f4b2 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1271,7 +1271,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 637f21176792b6b..423497bfcb6621a 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/test/Parser/cxx0x-lambda-expressions.cpp b/clang/test/Parser/cxx0x-lambda-expressions.cpp index 72b315a497c0679..a786a964163e4c4 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 {{<initializer_list>}} -#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 {{<initializer_list>}} + // 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 - []<typename>[[]](){}; -#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}} + + []<typename>[[]](){}; // 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}} }; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits