[clang] [clang] Accept lambdas in C++03 as an extensions (PR #73376)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 24 19:06:38 PST 2023
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 <nikolasklauser at 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 at -3 {{lambda without a parameter clause is a C++23 extension}}
- // expected-warning at -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 at -4{{extension}}
- // expected-warning at -4{{extension}}
- // expected-warning at -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 at -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 at -6{{extension}}
- // expected-warning at -6{{extension}}
- // expected-warning at -6{{extension}}
- // expected-warning at -7{{extension}}
- // expected-warning at -7{{extension}}
- // expected-warning at -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 at -1 {{initialized lambda captures are a C++14 extension}}
+ [n = {0}] { return; }; // expected-error {{<initializer_list>}}
+ // cxx14ext-warning at -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 at -2{{extension}}
- // expected-warning at -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 at -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 at -2 {{an attribute specifier sequence in this position is a C++23 extension}}
-#endif
-#if __cplusplus > 201703L
- []<typename>[[]](){};
-#if __cplusplus <= 202002L
- // expected-warning at -2 {{an attribute specifier sequence in this position is a C++23 extension}}
-#endif
-#endif
- [][[]]{};
-#if __cplusplus <= 202002L
- // expected-warning at -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 at -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 at -3 {{is a C++23 extension}}
- // expected-warning at -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 at -2 {{C++17 extension}}
-#endif
+ void mf() { A(([*this]{})); } // cxx17ext-warning {{'*this' by copy is a C++17 extension}}
};
}
More information about the cfe-commits
mailing list