Skip to content

Commit db504f5

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 dc567a2 commit db504f5

21 files changed

+208
-181
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1458,40 +1458,45 @@ More information could be found `here <https://clang.llvm.org/docs/Modules.html>
14581458
Language Extensions Back-ported to Previous Standards
14591459
=====================================================
14601460

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

14961501
Type Trait Primitives
14971502
=====================

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,7 @@ def err_expected_lambda_body : Error<"expected body of lambda expression">;
10261026
def warn_cxx98_compat_lambda : Warning<
10271027
"lambda expressions are incompatible with C++98">,
10281028
InGroup<CXX98Compat>, DefaultIgnore;
1029+
def ext_lambda : ExtWarn<"lambdas are a C++11 extension">, InGroup<CXX11>;
10291030
def err_lambda_decl_specifier_repeated : Error<
10301031
"%select{'mutable'|'static'|'constexpr'|'consteval'}0 cannot "
10311032
"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
@@ -257,6 +257,7 @@ EXTENSION(cxx_defaulted_functions, LangOpts.CPlusPlus)
257257
EXTENSION(cxx_deleted_functions, LangOpts.CPlusPlus)
258258
EXTENSION(cxx_explicit_conversions, LangOpts.CPlusPlus)
259259
EXTENSION(cxx_inline_namespaces, LangOpts.CPlusPlus)
260+
EXTENSION(cxx_lambdas, LangOpts.CPlusPlus)
260261
EXTENSION(cxx_local_type_template_args, LangOpts.CPlusPlus)
261262
EXTENSION(cxx_nonstatic_member_init, LangOpts.CPlusPlus)
262263
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
@@ -1810,7 +1810,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
18101810
}
18111811
goto ExpectedExpression;
18121812
case tok::l_square:
1813-
if (getLangOpts().CPlusPlus11) {
1813+
if (getLangOpts().CPlusPlus) {
18141814
if (getLangOpts().ObjC) {
18151815
// C++11 lambda expressions and Objective-C message sends both start with a
18161816
// 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
@@ -806,9 +806,8 @@ ExprResult Parser::ParseLambdaExpression() {
806806
///
807807
/// If we are not looking at a lambda expression, returns ExprError().
808808
ExprResult Parser::TryParseLambdaExpression() {
809-
assert(getLangOpts().CPlusPlus11
810-
&& Tok.is(tok::l_square)
811-
&& "Not at the start of a possible lambda expression.");
809+
assert(getLangOpts().CPlusPlus && Tok.is(tok::l_square) &&
810+
"Not at the start of a possible lambda expression.");
812811

813812
const Token Next = NextToken();
814813
if (Next.is(tok::eof)) // Nothing else to lookup here...
@@ -1326,7 +1325,9 @@ static void DiagnoseStaticSpecifierRestrictions(Parser &P,
13261325
ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
13271326
LambdaIntroducer &Intro) {
13281327
SourceLocation LambdaBeginLoc = Intro.Range.getBegin();
1329-
Diag(LambdaBeginLoc, diag::warn_cxx98_compat_lambda);
1328+
Diag(LambdaBeginLoc, getLangOpts().CPlusPlus11
1329+
? diag::warn_cxx98_compat_lambda
1330+
: diag::ext_lambda);
13301331

13311332
PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), LambdaBeginLoc,
13321333
"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
@@ -16111,7 +16111,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
1611116111
FD->setInvalidDecl();
1611216112
}
1611316113
}
16114-
} else if (getLangOpts().CPlusPlus11 && isLambdaCallOperator(FD)) {
16114+
} else if (getLangOpts().CPlusPlus && isLambdaCallOperator(FD)) {
1611516115
// In C++11, we don't use 'auto' deduction rules for lambda call
1611616116
// operators because we don't support return type deduction.
1611716117
auto *LSI = getCurLambda();

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9738,7 +9738,8 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
97389738
return false;
97399739
CXXRecordDecl *RD = MD->getParent();
97409740
assert(!RD->isDependentType() && "do deletion after instantiation");
9741-
if (!LangOpts.CPlusPlus11 || RD->isInvalidDecl())
9741+
if (!LangOpts.CPlusPlus || (!LangOpts.CPlusPlus11 && !RD->isLambda()) ||
9742+
RD->isInvalidDecl())
97429743
return false;
97439744

97449745
// 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
@@ -33,6 +33,11 @@ int has_deleted_functions();
3333
int has_inline_namespaces();
3434
#endif
3535

36+
// CHECK: has_lambdas
37+
#if __has_extension(cxx_lambdas)
38+
int has_lambdas();
39+
#endif
40+
3641
// CHECK: has_override_control
3742
#if __has_extension(cxx_override_control)
3843
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)