Skip to content

[clang] Accept lambdas in C++03 as an extensions #73376

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 39 additions & 34 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1459,40 +1459,45 @@ More information could be found `here <https://clang.llvm.org/docs/Modules.html>
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
=====================
Expand Down
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
------------------

Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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<CXX98Compat>, DefaultIgnore;
def ext_lambda : ExtWarn<"lambdas are a C++11 extension">, InGroup<CXX11>;
def err_lambda_decl_specifier_repeated : Error<
"%select{'mutable'|'static'|'constexpr'|'consteval'}0 cannot "
"appear multiple times in a lambda declarator">;
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
9 changes: 5 additions & 4 deletions clang/lib/Parse/ParseExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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...
Expand Down Expand Up @@ -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");
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Parse/ParseInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
5 changes: 5 additions & 0 deletions clang/test/Lexer/has_extension_cxx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
14 changes: 4 additions & 10 deletions clang/test/OpenMP/declare_reduction_messages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,10 @@ class Class2 : public Class1<T> {
#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 '('}}
Expand Down
2 changes: 1 addition & 1 deletion clang/test/OpenMP/openmp_check.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions clang/test/Parser/cxx03-lambda-extension.cpp
Original file line number Diff line number Diff line change
@@ -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}}
}
Loading