Skip to content

Commit b566ad7

Browse files
committed
[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.
1 parent 563f86b commit b566ad7

21 files changed

+209
-181
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,39 +1455,44 @@ More information could be found `here <https://clang.llvm.org/docs/Modules.html>
14551455
Language Extensions Back-ported to Previous Standards
14561456
=====================================================
14571457

1458-
====================================== ================================ ============= =============
1459-
Feature Feature Test Macro Introduced In Backported To
1460-
====================================== ================================ ============= =============
1461-
variadic templates __cpp_variadic_templates C++11 C++03
1462-
Alias templates __cpp_alias_templates C++11 C++03
1463-
Non-static data member initializers __cpp_nsdmi C++11 C++03
1464-
Range-based ``for`` loop __cpp_range_based_for C++11 C++03
1465-
RValue references __cpp_rvalue_references C++11 C++03
1466-
Attributes __cpp_attributes C++11 C++03
1467-
variable templates __cpp_variable_templates C++14 C++03
1468-
Binary literals __cpp_binary_literals C++14 C++03
1469-
Relaxed constexpr __cpp_constexpr C++14 C++11
1470-
``if constexpr`` __cpp_if_constexpr C++17 C++11
1471-
fold expressions __cpp_fold_expressions C++17 C++03
1472-
Lambda capture of \*this by value __cpp_capture_star_this C++17 C++11
1473-
Attributes on enums __cpp_enumerator_attributes C++17 C++11
1474-
Guaranteed copy elision __cpp_guaranteed_copy_elision C++17 C++03
1475-
Hexadecimal floating literals __cpp_hex_float C++17 C++03
1476-
``inline`` variables __cpp_inline_variables C++17 C++03
1477-
Attributes on namespaces __cpp_namespace_attributes C++17 C++11
1478-
Structured bindings __cpp_structured_bindings C++17 C++03
1479-
template template arguments __cpp_template_template_args C++17 C++03
1480-
``static operator[]`` __cpp_multidimensional_subscript C++20 C++03
1481-
Designated initializers __cpp_designated_initializers C++20 C++03
1482-
Conditional ``explicit`` __cpp_conditional_explicit C++20 C++03
1483-
``using enum`` __cpp_using_enum C++20 C++03
1484-
``if consteval`` __cpp_if_consteval C++23 C++20
1485-
``static operator()`` __cpp_static_call_operator C++23 C++03
1486-
-------------------------------------- -------------------------------- ------------- -------------
1487-
Designated initializers (N494) C99 C89
1488-
Array & element qualification (N2607) C23 C89
1489-
Attributes (N2335) C23 C89
1490-
====================================== ================================ ============= =============
1458+
============================================ ================================ ============= =============
1459+
Feature Feature Test Macro Introduced In Backported To
1460+
============================================ ================================ ============= =============
1461+
variadic templates __cpp_variadic_templates C++11 C++03
1462+
Alias templates __cpp_alias_templates C++11 C++03
1463+
Non-static data member initializers __cpp_nsdmi C++11 C++03
1464+
Range-based ``for`` loop __cpp_range_based_for C++11 C++03
1465+
RValue references __cpp_rvalue_references C++11 C++03
1466+
Attributes __cpp_attributes C++11 C++03
1467+
Lambdas __cpp_lambdas C++11 C++03
1468+
Generalized lambda captures __cpp_init_captures C++14 C++03
1469+
Generic lambda expressions __cpp_generic_lambdas C++14 C++03
1470+
variable templates __cpp_variable_templates C++14 C++03
1471+
Binary literals __cpp_binary_literals C++14 C++03
1472+
Relaxed constexpr __cpp_constexpr C++14 C++11
1473+
Pack expansion in generalized lambda-capture __cpp_init_captures C++17 C++03
1474+
``if constexpr`` __cpp_if_constexpr C++17 C++11
1475+
fold expressions __cpp_fold_expressions C++17 C++03
1476+
Lambda capture of \*this by value __cpp_capture_star_this C++17 C++03
1477+
Attributes on enums __cpp_enumerator_attributes C++17 C++11
1478+
Guaranteed copy elision __cpp_guaranteed_copy_elision C++17 C++03
1479+
Hexadecimal floating literals __cpp_hex_float C++17 C++03
1480+
``inline`` variables __cpp_inline_variables C++17 C++03
1481+
Attributes on namespaces __cpp_namespace_attributes C++17 C++11
1482+
Structured bindings __cpp_structured_bindings C++17 C++03
1483+
template template arguments __cpp_template_template_args C++17 C++03
1484+
Familiar template syntax for generic lambdas __cpp_generic_lambdas C++20 C++03
1485+
``static operator[]`` __cpp_multidimensional_subscript C++20 C++03
1486+
Designated initializers __cpp_designated_initializers C++20 C++03
1487+
Conditional ``explicit`` __cpp_conditional_explicit C++20 C++03
1488+
``using enum`` __cpp_using_enum C++20 C++03
1489+
``if consteval`` __cpp_if_consteval C++23 C++20
1490+
``static operator()`` __cpp_static_call_operator C++23 C++03
1491+
-------------------------------------------- -------------------------------- ------------- -------------
1492+
Designated initializers (N494) C99 C89
1493+
Array & element qualification (N2607) C23 C89
1494+
Attributes (N2335) C23 C89
1495+
============================================ ================================ ============= =============
14911496

14921497
Type Trait Primitives
14931498
=====================

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,7 @@ def err_expected_lambda_body : Error<"expected body of lambda expression">;
10231023
def warn_cxx98_compat_lambda : Warning<
10241024
"lambda expressions are incompatible with C++98">,
10251025
InGroup<CXX98Compat>, DefaultIgnore;
1026+
def ext_lambda : ExtWarn<"lambdas are a C++11 extension">, InGroup<CXX11>;
10261027
def err_lambda_decl_specifier_repeated : Error<
10271028
"%select{'mutable'|'static'|'constexpr'|'consteval'}0 cannot "
10281029
"appear multiple times in a lambda declarator">;

clang/include/clang/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ EXTENSION(cxx_defaulted_functions, LangOpts.CPlusPlus)
254254
EXTENSION(cxx_deleted_functions, LangOpts.CPlusPlus)
255255
EXTENSION(cxx_explicit_conversions, LangOpts.CPlusPlus)
256256
EXTENSION(cxx_inline_namespaces, LangOpts.CPlusPlus)
257+
EXTENSION(cxx_lambdas, LangOpts.CPlusPlus)
257258
EXTENSION(cxx_local_type_template_args, LangOpts.CPlusPlus)
258259
EXTENSION(cxx_nonstatic_member_init, LangOpts.CPlusPlus)
259260
EXTENSION(cxx_override_control, LangOpts.CPlusPlus)

clang/lib/Parse/ParseExpr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1799,7 +1799,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
17991799
}
18001800
goto ExpectedExpression;
18011801
case tok::l_square:
1802-
if (getLangOpts().CPlusPlus11) {
1802+
if (getLangOpts().CPlusPlus) {
18031803
if (getLangOpts().ObjC) {
18041804
// C++11 lambda expressions and Objective-C message sends both start with a
18051805
// square bracket. There are three possibilities here:

clang/lib/Parse/ParseExprCXX.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -751,9 +751,8 @@ ExprResult Parser::ParseLambdaExpression() {
751751
///
752752
/// If we are not looking at a lambda expression, returns ExprError().
753753
ExprResult Parser::TryParseLambdaExpression() {
754-
assert(getLangOpts().CPlusPlus11
755-
&& Tok.is(tok::l_square)
756-
&& "Not at the start of a possible lambda expression.");
754+
assert(getLangOpts().CPlusPlus && Tok.is(tok::l_square) &&
755+
"Not at the start of a possible lambda expression.");
757756

758757
const Token Next = NextToken();
759758
if (Next.is(tok::eof)) // Nothing else to lookup here...
@@ -1271,7 +1270,9 @@ static void DiagnoseStaticSpecifierRestrictions(Parser &P,
12711270
ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
12721271
LambdaIntroducer &Intro) {
12731272
SourceLocation LambdaBeginLoc = Intro.Range.getBegin();
1274-
Diag(LambdaBeginLoc, diag::warn_cxx98_compat_lambda);
1273+
Diag(LambdaBeginLoc, getLangOpts().CPlusPlus11
1274+
? diag::warn_cxx98_compat_lambda
1275+
: diag::ext_lambda);
12751276

12761277
PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), LambdaBeginLoc,
12771278
"lambda expression parsing");

clang/lib/Parse/ParseInit.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ bool Parser::MayBeDesignationStart() {
3535
return true;
3636

3737
case tok::l_square: { // designator: array-designator
38-
if (!PP.getLangOpts().CPlusPlus11)
38+
if (!PP.getLangOpts().CPlusPlus)
3939
return true;
4040

4141
// C++11 lambda expressions and C99 designators can be ambiguous all the

clang/lib/Sema/SemaDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15877,7 +15877,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
1587715877
FD->setInvalidDecl();
1587815878
}
1587915879
}
15880-
} else if (getLangOpts().CPlusPlus11 && isLambdaCallOperator(FD)) {
15880+
} else if (getLangOpts().CPlusPlus && isLambdaCallOperator(FD)) {
1588115881
// In C++11, we don't use 'auto' deduction rules for lambda call
1588215882
// operators because we don't support return type deduction.
1588315883
auto *LSI = getCurLambda();

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9716,7 +9716,8 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
97169716
return false;
97179717
CXXRecordDecl *RD = MD->getParent();
97189718
assert(!RD->isDependentType() && "do deletion after instantiation");
9719-
if (!LangOpts.CPlusPlus11 || RD->isInvalidDecl())
9719+
if (!LangOpts.CPlusPlus || (!LangOpts.CPlusPlus11 && !RD->isLambda()) ||
9720+
RD->isInvalidDecl())
97209721
return false;
97219722

97229723
// C++11 [expr.lambda.prim]p19:

clang/test/Lexer/has_extension_cxx.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ int has_deleted_functions();
3131
int has_inline_namespaces();
3232
#endif
3333

34+
// CHECK: has_lambdas
35+
#if __has_extension(cxx_lambdas)
36+
int has_lambdas();
37+
#endif
38+
3439
// CHECK: has_override_control
3540
#if __has_extension(cxx_override_control)
3641
int has_override_control();

clang/test/OpenMP/declare_reduction_messages.cpp

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,10 @@ class Class2 : public Class1<T> {
5858
#pragma omp declare reduction(fun1 : long : omp_out += omp_in) initializer // expected-error {{expected '(' after 'initializer'}}
5959
#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}}
6060
#pragma omp declare reduction(fun3 : long : omp_out += omp_in) initializer[
61-
#if __cplusplus <= 199711L
62-
// expected-error@-2 {{expected '(' after 'initializer'}}
63-
// expected-error@-3 {{expected expression}}
64-
// expected-warning@-4 {{extra tokens at the end of '#pragma omp declare reduction' are ignored}}
65-
#else
66-
// expected-error@-6 {{expected '(' after 'initializer'}}
67-
// expected-error@-7 {{expected variable name or 'this' in lambda capture list}}
68-
// expected-error@-8 {{expected ')'}}
69-
// expected-note@-9 {{to match this '('}}
70-
#endif
61+
// expected-error@-1 {{expected '(' after 'initializer'}}
62+
// expected-error@-2 {{expected variable name or 'this' in lambda capture list}}
63+
// expected-error@-3 {{expected ')'}}
64+
// expected-note@-4 {{to match this '('}}
7165
#pragma omp declare reduction(fun4 : long : omp_out += omp_in) initializer() // expected-error {{expected expression}}
7266
#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}}
7367
#pragma omp declare reduction(fun6 : long : omp_out += omp_in) initializer(omp_orig // expected-error {{expected ')'}} expected-note {{to match this '('}}

clang/test/OpenMP/openmp_check.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ int nested(int a) {
1818
auto F = [&]() {
1919
#if __cplusplus <= 199711L
2020
// expected-warning@-2 {{'auto' type specifier is a C++11 extension}}
21-
// expected-error@-3 {{expected expression}}
21+
// expected-warning@-3 {{lambdas are a C++11 extension}}
2222
#endif
2323

2424
#pragma omp parallel
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++03 %s
2+
3+
void func() {
4+
[]() {}; // expected-warning {{lambdas are a C++11 extension}}
5+
}

0 commit comments

Comments
 (0)