[clang] [Clang] Fix parsing of expressions of the form (T())[/*...*/] (PR #140053)
via cfe-commits
cfe-commits at lists.llvm.org
Thu May 15 08:54:55 PDT 2025
https://github.com/cor3ntin updated https://github.com/llvm/llvm-project/pull/140053
>From 7b4f82cef62e3b793673e4edfed55c7252be9bcf Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Thu, 15 May 2025 14:59:03 +0200
Subject: [PATCH 1/3] [Clang] Fix parsing of expressions of the form
(T())[/*...*/]
when checking cast expression, we were assuming `[` was the start
of a lambda expression.
However, the expression might instead by
a subscripted parenthesized postfix expression.
Therefore we need to check if the expression
is in fact a lambda.
We do that by looking an open brace, bailing early
when possible.
Fixes #20723
---
clang/docs/ReleaseNotes.rst | 1 +
clang/include/clang/Parse/Parser.h | 4 +
clang/lib/Parse/ParseExpr.cpp | 6 +-
clang/lib/Parse/ParseExprCXX.cpp | 64 +++++++++
.../test/Parser/cxx0x-lambda-expressions.cpp | 82 +++++++++++
clang/test/Parser/cxx1z-constexpr-lambdas.cpp | 38 +++--
clang/test/Parser/cxx2a-template-lambdas.cpp | 44 +++---
clang/test/Parser/cxx2b-lambdas.cpp | 131 ++++++++++--------
8 files changed, 280 insertions(+), 90 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 31c517338c21f..a7c8b2514b226 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -710,6 +710,7 @@ Bug Fixes to C++ Support
- Clang now correctly parses arbitrary order of ``[[]]``, ``__attribute__`` and ``alignas`` attributes for declarations (#GH133107)
- Fixed a crash when forming an invalid function type in a dependent context. (#GH138657) (#GH115725) (#GH68852)
- Clang no longer segfaults when there is a configuration mismatch between modules and their users (http://crbug.com/400353616).
+- Fix parsing of expressions of the form ``((T))[expr]``. (#GH20723)
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index e6492b81dfff8..016708de2bf4c 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -4639,6 +4639,10 @@ class Parser : public CodeCompletionHandler {
ParseLambdaIntroducer(LambdaIntroducer &Intro,
LambdaIntroducerTentativeParse *Tentative = nullptr);
+ /// Tries to determine if an expression of the form (S())[...]...
+ /// is a type-cast followed by a lambda, or a subscript expression
+ bool IsLambdaAfterTypeCast();
+
/// ParseLambdaExpressionAfterIntroducer - Parse the rest of a lambda
/// expression.
ExprResult ParseLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro);
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 11cfbbe790418..09dabaad4e231 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1585,8 +1585,10 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
}
break;
}
- Res = ParseLambdaExpression();
- break;
+ if (isTypeCast != TypeCastState::IsTypeCast || IsLambdaAfterTypeCast()) {
+ Res = ParseLambdaExpression();
+ break;
+ }
}
if (getLangOpts().ObjC) {
Res = ParseObjCMessageExpression();
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index d95260829e4a0..77544432bbee8 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -692,6 +692,70 @@ ExprResult Parser::ParseLambdaExpression() {
return ParseLambdaExpressionAfterIntroducer(Intro);
}
+bool Parser::IsLambdaAfterTypeCast() {
+ assert(getLangOpts().CPlusPlus && Tok.is(tok::l_square) &&
+ "Not at the start of a possible lambda expression.");
+ RevertingTentativeParsingAction TPA(*this);
+ ConsumeBracket();
+ // skip the introducer
+ if (Tok.is(tok::equal) ||
+ (Tok.is(tok::amp) && NextToken().isOneOf(tok::comma, tok::r_square)))
+ return true;
+
+ SkipUntil(tok::r_square);
+
+ auto IsLambdaKWOrAttribute = [&]() {
+ // These keyworks that either can appear somewhere in a lambda declarator,
+ // or cannot appear in a cast expression and we recover in favor of lambdas
+ if (Tok.isOneOf(tok::kw___declspec, tok::kw___noinline__, tok::kw_noexcept,
+ tok::kw_throw, tok::kw_mutable, tok::kw___attribute,
+ tok::kw_constexpr, tok::kw_consteval, tok::kw_static,
+ tok::kw_inline, tok::kw_extern, tok::kw___private,
+ tok::kw___global, tok::kw___local, tok::kw___constant,
+ tok::kw___generic, tok::kw_groupshared, tok::kw_requires,
+ tok::kw_noexcept))
+ return true;
+ return Tok.isRegularKeywordAttribute() ||
+ isCXX11AttributeSpecifier() !=
+ CXX11AttributeKind::NotAttributeSpecifier;
+ };
+
+ if (Tok.is(tok::l_brace) || IsLambdaKWOrAttribute())
+ return true;
+
+ // This is a generic lambda,
+ if (Tok.is(tok::less)) {
+ ConsumeToken();
+ // Common cases. We consider <> as an invalid lambda.
+ if (Tok.isOneOf(tok::greater, tok::kw_typename, tok::kw_auto,
+ tok::kw_template))
+ return true;
+ if (isStartOfTemplateTypeParameter() != TPResult::False)
+ return true;
+ return isCXXDeclarationSpecifier(ImplicitTypenameContext::Yes) !=
+ TPResult::False;
+ }
+ // skip the parameter list
+ if (Tok.is(tok::l_paren)) {
+ ConsumeParen();
+ SkipUntil(tok::r_paren);
+ }
+
+ if (IsLambdaKWOrAttribute())
+ return true;
+
+ if (Tok.is(tok::arrow)) {
+ ConsumeToken();
+ // These cases are always id-expressions
+ if (Tok.isOneOf(tok::kw_template, tok::kw_operator, tok::tilde))
+ return false;
+ if (!Tok.is(tok::identifier))
+ return true;
+ return isCXXTypeId(TentativeCXXTypeIdContext::InTrailingReturnType);
+ }
+ return Tok.is(tok::l_brace);
+}
+
ExprResult Parser::TryParseLambdaExpression() {
assert(getLangOpts().CPlusPlus && Tok.is(tok::l_square) &&
"Not at the start of a possible lambda expression.");
diff --git a/clang/test/Parser/cxx0x-lambda-expressions.cpp b/clang/test/Parser/cxx0x-lambda-expressions.cpp
index a786a964163e4..d5466d44d8fff 100644
--- a/clang/test/Parser/cxx0x-lambda-expressions.cpp
+++ b/clang/test/Parser/cxx0x-lambda-expressions.cpp
@@ -40,6 +40,33 @@ class C {
return 1;
}
+ int type_cast() {
+ int foo, bar;
+
+ (void)[]; // expected-error {{expected expression}}
+ (void)[+] {}; // expected-error {{expected variable name or 'this' in lambda capture list}}
+ (void)[foo+] {}; // expected-error {{expected ',' or ']' in lambda capture list}}
+ (void)[foo,&this] {}; // expected-error {{'this' cannot be captured by reference}}
+ (void)[&this] {}; // expected-error {{'this' cannot be captured by reference}}
+ (void)[&,] {}; // expected-error {{expected variable name or 'this' in lambda capture list}}
+ (void)[=,] {}; // expected-error {{expected variable name or 'this' in lambda capture list}}
+ (void)[] {};
+ (void)[=] (int i) {};
+ (void)[&] (int) mutable -> void {};
+ (void)[foo,bar] () { return 3; };
+ (void)[=,&foo] () {};
+ (void)[&,foo] () {};
+ (void)[this] () {};
+ (void)[] () -> class C { return C(); };
+ (void)[] () -> enum E { return e; };
+
+ (void)[] -> int { return 0; }; // cxx23ext-warning {{lambda without a parameter clause is a C++23 extension}}
+ (void)[] mutable -> int { return 0; }; // cxx23ext-warning {{is a C++23 extension}}
+
+ (void)[](int) -> {}; // PR13652 expected-error {{expected a type}}
+ return 1;
+ }
+
void designator_or_lambda() {
typedef int T;
const int b = 0;
@@ -125,10 +152,46 @@ class C {
[][[]]{}; // cxx23ext-warning {{an attribute specifier sequence in this position is a C++23 extension}}
}
+ void attributes_type_cast() {
+ (void)[] __attribute__((noreturn)){}; // cxx23ext-warning {{lambda without a parameter clause is a C++23 extension}}
+
+ (void)[]() [[]]
+ mutable {}; // expected-error {{expected body of lambda expression}}
+
+ (void)[]() [[]] {};
+ (void)[]() [[]] -> void {};
+ (void)[]() mutable [[]] -> void {};
+#if __cplusplus >= 201103L
+ (void)[]() mutable noexcept [[]] -> void {};
+#endif
+
+ // Testing GNU-style attributes on lambdas -- the attribute is specified
+ // before the mutable specifier instead of after (unlike C++11).
+ (void)[]() __attribute__((noreturn)) mutable { while(1); };
+ (void)[]() mutable
+ __attribute__((noreturn)) { while(1); }; // expected-error {{expected body of lambda expression}}
+
+ // Testing support for P2173 on adding attributes to the declaration
+ // rather than the type.
+ (void)[][[]](){}; // cxx23ext-warning {{an attribute specifier sequence in this position is a C++23 extension}}
+
+ (void)[]<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}}
+
+ (void)[][[]]{}; // cxx23ext-warning {{an attribute specifier sequence in this position is a C++23 extension}}
+ }
+
void missing_parens() {
[] mutable {}; // cxx23ext-warning {{is a C++23 extension}}
#if __cplusplus >= 201103L
[] noexcept {}; // cxx23ext-warning {{is a C++23 extension}}
+#endif
+ }
+
+ void missing_parens_type_cast() {
+ (void)[] mutable {}; // cxx23ext-warning {{is a C++23 extension}}
+#if __cplusplus >= 201103L
+ (void)[] noexcept {}; // cxx23ext-warning {{is a C++23 extension}}
#endif
}
};
@@ -150,6 +213,25 @@ struct S {
};
}
+#if __cplusplus >= 201103L
+namespace GH20723 {
+struct S {
+ S operator[](int);
+ S operator()();
+ S operator<(int);
+ S* operator->();
+ long a;
+};
+int n;
+void f() {
+ static_assert(__is_same_as(decltype((S())[n]()), S), "");
+ static_assert(__is_same_as(decltype((S())[n] < 0), S), "");
+ static_assert(__is_same_as(decltype((S())[n]->a), long), "");
+}
+}
+#endif
+
+
struct S {
template <typename T>
void m (T x =[0); // expected-error{{expected variable name or 'this' in lambda capture list}}
diff --git a/clang/test/Parser/cxx1z-constexpr-lambdas.cpp b/clang/test/Parser/cxx1z-constexpr-lambdas.cpp
index 87584ee5ca91b..bba63b4925298 100644
--- a/clang/test/Parser/cxx1z-constexpr-lambdas.cpp
+++ b/clang/test/Parser/cxx1z-constexpr-lambdas.cpp
@@ -1,26 +1,34 @@
-// RUN: %clang_cc1 -std=c++23 %s -verify
-// RUN: %clang_cc1 -std=c++20 %s -verify
-// RUN: %clang_cc1 -std=c++17 %s -verify
-// RUN: %clang_cc1 -std=c++14 %s -verify
-// RUN: %clang_cc1 -std=c++11 %s -verify
+// RUN: %clang_cc1 -std=c++23 %s -verify -Wno-unused "-DTYPE_CAST="
+// RUN: %clang_cc1 -std=c++20 %s -verify -Wno-unused "-DTYPE_CAST="
+// RUN: %clang_cc1 -std=c++17 %s -verify -Wno-unused "-DTYPE_CAST="
+// RUN: %clang_cc1 -std=c++14 %s -verify -Wno-unused "-DTYPE_CAST="
+// RUN: %clang_cc1 -std=c++11 %s -verify -Wno-unused "-DTYPE_CAST="
-auto XL0 = [] constexpr { return true; };
+// RUN: %clang_cc1 -std=c++23 %s -verify "-DTYPE_CAST=(void)"
+// RUN: %clang_cc1 -std=c++20 %s -verify "-DTYPE_CAST=(void)"
+// RUN: %clang_cc1 -std=c++17 %s -verify "-DTYPE_CAST=(void)"
+// RUN: %clang_cc1 -std=c++14 %s -verify "-DTYPE_CAST=(void)"
+// RUN: %clang_cc1 -std=c++11 %s -verify "-DTYPE_CAST=(void)"
+
+void test() {
+
+TYPE_CAST [] constexpr { return true; };
#if __cplusplus <= 201402L
// expected-warning at -2 {{is a C++17 extension}}
#endif
#if __cplusplus <= 202002L
// expected-warning at -5 {{lambda without a parameter clause is a C++23 extension}}
#endif
-auto XL1 = []() mutable //
+TYPE_CAST []() mutable //
mutable // expected-error{{cannot appear multiple times}}
mutable {}; // expected-error{{cannot appear multiple times}}
#if __cplusplus > 201402L
-auto XL2 = [] () constexpr mutable constexpr { }; //expected-error{{cannot appear multiple times}}
-auto L = []() mutable constexpr { };
-auto L2 = []() constexpr { };
-auto L4 = []() constexpr mutable { };
-auto XL16 = [] () constexpr
+TYPE_CAST [] () constexpr mutable constexpr { }; //expected-error{{cannot appear multiple times}}
+TYPE_CAST []() mutable constexpr { };
+TYPE_CAST []() constexpr { };
+TYPE_CAST []() constexpr mutable { };
+TYPE_CAST [] () constexpr
mutable
constexpr //expected-error{{cannot appear multiple times}}
mutable //expected-error{{cannot appear multiple times}}
@@ -31,8 +39,10 @@ auto XL16 = [] () constexpr
#else
auto L = []() mutable constexpr {return 0; }; //expected-warning{{is a C++17 extension}}
-auto L2 = []() constexpr { return 0;};//expected-warning{{is a C++17 extension}}
-auto L4 = []() constexpr mutable { return 0; }; //expected-warning{{is a C++17 extension}}
+TYPE_CAST []() constexpr { return 0;};//expected-warning{{is a C++17 extension}}
+TYPE_CAST []() constexpr mutable { return 0; }; //expected-warning{{is a C++17 extension}}
#endif
+}
+
diff --git a/clang/test/Parser/cxx2a-template-lambdas.cpp b/clang/test/Parser/cxx2a-template-lambdas.cpp
index 98c74a247b535..bb43101045e9e 100644
--- a/clang/test/Parser/cxx2a-template-lambdas.cpp
+++ b/clang/test/Parser/cxx2a-template-lambdas.cpp
@@ -1,38 +1,44 @@
-// RUN: %clang_cc1 -std=c++23 %s -verify
-// RUN: %clang_cc1 -std=c++20 %s -verify
+// RUN: %clang_cc1 -std=c++23 %s -verify -Wno-unused "-DTYPE_CAST="
+// RUN: %clang_cc1 -std=c++20 %s -verify -Wno-unused "-DTYPE_CAST="
+// RUN: %clang_cc1 -std=c++23 %s -verify "-DTYPE_CAST=(void)"
+// RUN: %clang_cc1 -std=c++20 %s -verify "-DTYPE_CAST=(void)"
-auto L0 = []<> { }; //expected-error {{cannot be empty}}
+void test() {
-auto L1 = []<typename T1, typename T2> { };
-auto L2 = []<typename T1, typename T2>(T1 arg1, T2 arg2) -> T1 { };
-auto L3 = []<typename T>(auto arg) { T t; };
-auto L4 = []<int I>() { };
+TYPE_CAST []<> { }; //expected-error {{cannot be empty}}
+
+TYPE_CAST []<typename T1, typename T2> { };
+TYPE_CAST []<typename T1, typename T2>(T1 arg1, T2 arg2) -> T1 { };
+TYPE_CAST []<typename T>(auto arg) { T t; };
+TYPE_CAST []<int I>() { };
// http://llvm.org/PR49736
-auto L5 = []<auto>(){};
-auto L6 = []<auto>{};
-auto L7 = []<auto>() noexcept {};
-auto L8 = []<auto> noexcept {};
+TYPE_CAST []<auto>(){};
+TYPE_CAST []<auto>{};
+TYPE_CAST []<auto>() noexcept {};
+TYPE_CAST []<auto> noexcept {};
#if __cplusplus <= 202002L
// expected-warning at -2 {{lambda without a parameter clause is a C++23 extension}}
#endif
-auto L9 = []<auto> requires true {};
-auto L10 = []<auto> requires true(){};
-auto L11 = []<auto> requires true() noexcept {};
-auto L12 = []<auto> requires true noexcept {};
+TYPE_CAST []<auto> requires true {};
+TYPE_CAST []<auto> requires true(){};
+TYPE_CAST []<auto> requires true() noexcept {};
+TYPE_CAST []<auto> requires true noexcept {};
#if __cplusplus <= 202002L
// expected-warning at -2 {{is a C++23 extension}}
#endif
-auto L13 = []<auto>() noexcept requires true {};
-auto L14 = []<auto> requires true() noexcept requires true {};
+TYPE_CAST []<auto>() noexcept requires true {};
+TYPE_CAST []<auto> requires true() noexcept requires true {};
-auto XL0 = []<auto> noexcept requires true {}; // expected-error {{expected body of lambda expression}}
-auto XL1 = []<auto> requires true noexcept requires true {}; // expected-error {{expected body}}
+TYPE_CAST []<auto> noexcept requires true {}; // expected-error {{expected body of lambda expression}}
+TYPE_CAST []<auto> requires true noexcept requires true {}; // expected-error {{expected body}}
#if __cplusplus <= 202002L
// expected-warning at -3 {{is a C++23 extension}}
// expected-warning at -3 {{is a C++23 extension}}
#endif
+}
+
namespace GH64962 {
void f() {
[] <typename T>(T i) -> int[] // expected-error {{function cannot return array type 'int[]'}}
diff --git a/clang/test/Parser/cxx2b-lambdas.cpp b/clang/test/Parser/cxx2b-lambdas.cpp
index 758ec9a42f56d..a769fbda36276 100644
--- a/clang/test/Parser/cxx2b-lambdas.cpp
+++ b/clang/test/Parser/cxx2b-lambdas.cpp
@@ -1,88 +1,109 @@
-// RUN: %clang_cc1 -std=c++03 %s -verify -Wno-c++23-extensions -Wno-c++20-extensions -Wno-c++17-extensions -Wno-c++14-extensions -Wno-c++11-extensions
-// RUN: %clang_cc1 -std=c++11 %s -verify=expected,cxx11 -Wno-c++23-extensions -Wno-c++20-extensions -Wno-c++17-extensions -Wno-c++14-extensions
-// RUN: %clang_cc1 -std=c++14 %s -verify -Wno-c++23-extensions -Wno-c++20-extensions -Wno-c++17-extensions
-// RUN: %clang_cc1 -std=c++17 %s -verify -Wno-c++23-extensions -Wno-c++20-extensions
-// RUN: %clang_cc1 -std=c++20 %s -verify -Wno-c++23-extensions
-// RUN: %clang_cc1 -std=c++23 %s -verify
-
-auto LL0 = [] {};
-auto LL1 = []() {};
-auto LL2 = []() mutable {};
+// RUN: %clang_cc1 -std=c++03 %s "-DTYPE_CAST=" -verify -Wno-unused -Wno-c++23-extensions -Wno-c++20-extensions -Wno-c++17-extensions -Wno-c++14-extensions -Wno-c++11-extensions
+// RUN: %clang_cc1 -std=c++11 %s "-DTYPE_CAST=" -verify=expected,cxx11 -Wno-unused -Wno-c++23-extensions -Wno-c++20-extensions -Wno-c++17-extensions -Wno-c++14-extensions
+// RUN: %clang_cc1 -std=c++14 %s "-DTYPE_CAST=" -verify -Wno-unused -Wno-c++23-extensions -Wno-c++20-extensions -Wno-c++17-extensions
+// RUN: %clang_cc1 -std=c++17 %s "-DTYPE_CAST=" -verify -Wno-unused -Wno-c++23-extensions -Wno-c++20-extensions
+// RUN: %clang_cc1 -std=c++20 %s "-DTYPE_CAST=" -verify -Wno-unused -Wno-c++23-extensions
+// RUN: %clang_cc1 -std=c++23 %s "-DTYPE_CAST=" -verify -Wno-unused
+
+// RUN: %clang_cc1 -std=c++03 %s "-DTYPE_CAST=(void)" -verify -Wno-unused -Wno-c++23-extensions -Wno-c++20-extensions -Wno-c++17-extensions -Wno-c++14-extensions -Wno-c++11-extensions
+// RUN: %clang_cc1 -std=c++11 %s "-DTYPE_CAST=(void)" -verify=expected,cxx11 -Wno-unused -Wno-c++23-extensions -Wno-c++20-extensions -Wno-c++17-extensions -Wno-c++14-extensions
+// RUN: %clang_cc1 -std=c++14 %s "-DTYPE_CAST=(void)" -verify -Wno-unused -Wno-c++23-extensions -Wno-c++20-extensions -Wno-c++17-extensions
+// RUN: %clang_cc1 -std=c++17 %s "-DTYPE_CAST=(void)" -verify -Wno-unused -Wno-c++23-extensions -Wno-c++20-extensions
+// RUN: %clang_cc1 -std=c++20 %s "-DTYPE_CAST=(void)" -verify -Wno-unused -Wno-c++23-extensions
+// RUN: %clang_cc1 -std=c++23 %s "-DTYPE_CAST=(void)" -verify -Wno-unused
+
+void test() {
+
+TYPE_CAST [] {};
+TYPE_CAST []() {};
+TYPE_CAST []() mutable {};
#if __cplusplus >= 201103L
-auto LL3 = []() constexpr {}; // cxx11-error {{return type 'void' is not a literal type}}
+TYPE_CAST []() constexpr {}; // cxx11-error {{return type 'void' is not a literal type}}
#endif
#if __cplusplus >= 201103L
-auto L0 = [] constexpr {}; // cxx11-error {{return type 'void' is not a literal type}}
+TYPE_CAST [] constexpr {}; // cxx11-error {{return type 'void' is not a literal type}}
#endif
-auto L1 = [] mutable {};
+TYPE_CAST [] mutable {};
#if __cplusplus >= 201103L
-auto L2 = [] noexcept {};
-auto L3 = [] constexpr mutable {}; // cxx11-error {{return type 'void' is not a literal type}}
-auto L4 = [] mutable constexpr {}; // cxx11-error {{return type 'void' is not a literal type}}
-auto L5 = [] constexpr mutable noexcept {}; // cxx11-error {{return type 'void' is not a literal type}}
+TYPE_CAST [] noexcept {};
+TYPE_CAST [] constexpr mutable {}; // cxx11-error {{return type 'void' is not a literal type}}
+TYPE_CAST [] mutable constexpr {}; // cxx11-error {{return type 'void' is not a literal type}}
+TYPE_CAST [] constexpr mutable noexcept {}; // cxx11-error {{return type 'void' is not a literal type}}
#endif
-auto L6 = [s = 1] mutable {};
+TYPE_CAST [s = 1] mutable {};
#if __cplusplus >= 201103L
-auto L7 = [s = 1] constexpr mutable noexcept {}; // cxx11-error {{return type 'void' is not a literal type}}
+TYPE_CAST [s = 1] constexpr mutable noexcept {}; // cxx11-error {{return type 'void' is not a literal type}}
#endif
-auto L8 = [] -> bool { return true; };
-auto L9 = []<typename T> { return true; };
+TYPE_CAST [] -> bool { return true; };
+TYPE_CAST []<typename T> { return true; };
#if __cplusplus >= 201103L
-auto L10 = []<typename T> noexcept { return true; };
+TYPE_CAST []<typename T> noexcept { return true; };
#endif
-auto L11 = []<typename T> -> bool { return true; };
+TYPE_CAST []<typename T> -> bool { return true; };
#if __cplusplus >= 202002L
-auto L12 = [] consteval {};
-auto L13 = []() requires true {}; // expected-error{{non-templated function cannot have a requires clause}}
-auto L14 = []<auto> requires true() requires true {};
-auto L15 = []<auto> requires true noexcept {};
+TYPE_CAST [] consteval {};
+TYPE_CAST []() requires true {}; // expected-error{{non-templated function cannot have a requires clause}}
+TYPE_CAST []<auto> requires true() requires true {};
+TYPE_CAST []<auto> requires true noexcept {};
#endif
-auto L16 = [] [[maybe_unused]]{};
+TYPE_CAST [] [[maybe_unused]]{};
#if __cplusplus >= 201103L
-auto XL0 = [] mutable constexpr mutable {}; // expected-error{{cannot appear multiple times}} cxx11-error {{return type 'void' is not a literal type}}
-auto XL1 = [] constexpr mutable constexpr {}; // expected-error{{cannot appear multiple times}} cxx11-error {{return type 'void' is not a literal type}}
-auto XL2 = []) constexpr mutable constexpr {}; // expected-error{{expected body of lambda expression}}
-auto XL3 = []( constexpr mutable constexpr {}; // expected-error{{invalid storage class specifier}} \
- // expected-error{{function parameter cannot be constexpr}} \
- // expected-error{{a type specifier is required}} \
- // expected-error{{expected ')'}} \
- // expected-note{{to match this '('}} \
- // expected-error{{expected body}} \
- // expected-warning{{duplicate 'constexpr'}}
+TYPE_CAST [] mutable constexpr mutable {}; // expected-error{{cannot appear multiple times}} cxx11-error {{return type 'void' is not a literal type}}
+TYPE_CAST [] constexpr mutable constexpr {}; // expected-error{{cannot appear multiple times}} cxx11-error {{return type 'void' is not a literal type}}
+
+[]) constexpr mutable constexpr {}; // expected-error{{expected body of lambda expression}}
+[]( constexpr mutable constexpr {}; // expected-error{{invalid storage class specifier}} \
+ // expected-error{{function parameter cannot be constexpr}} \
+ // expected-error{{a type specifier is required}} \
+ // expected-error{{expected ')'}} \
+ // expected-note{{to match this '('}} \
+ // expected-error{{expected body}} \
+ // expected-warning{{duplicate 'constexpr'}}
+
#endif
// http://llvm.org/PR49736
-auto XL4 = [] requires true {}; // expected-error{{expected body}}
+
+#if __cplusplus >= 202002L
+[] requires true {}; // expected-error{{expected body}}
+(void)[] requires true {}; // expected-error{{expected body}}
+#else
+[] requires true {}; // expected-error{{expected body}}
+(void)[] requires true {}; // expected-error{{expected expression}}
+#endif
+
#if __cplusplus >= 201703L
-auto XL5 = []<auto> requires true requires true {}; // expected-error{{expected body}}
-auto XL6 = []<auto> requires true noexcept requires true {}; // expected-error{{expected body}}
+TYPE_CAST []<auto> requires true requires true {}; // expected-error{{expected body}}
+TYPE_CAST []<auto> requires true noexcept requires true {}; // expected-error{{expected body}}
#endif
-auto XL7 = []() static static {}; // expected-error {{cannot appear multiple times}}
-auto XL8 = []() static mutable {}; // expected-error {{cannot be both mutable and static}}
+TYPE_CAST []() static static {}; // expected-error {{cannot appear multiple times}}
+TYPE_CAST []() static mutable {}; // expected-error {{cannot be both mutable and static}}
#if __cplusplus >= 202002L
-auto XL9 = []() static consteval {};
+TYPE_CAST []() static consteval {};
#endif
#if __cplusplus >= 201103L
-auto XL10 = []() static constexpr {}; // cxx11-error {{return type 'void' is not a literal type}}
+TYPE_CAST []() static constexpr {}; // cxx11-error {{return type 'void' is not a literal type}}
#endif
-auto XL11 = [] static {};
-auto XL12 = []() static {};
-auto XL13 = []() static extern {}; // expected-error {{expected body of lambda expression}}
-auto XL14 = []() extern {}; // expected-error {{expected body of lambda expression}}
+TYPE_CAST [] static {};
+TYPE_CAST []() static {};
+TYPE_CAST []() static extern {}; // expected-error {{expected body of lambda expression}}
+TYPE_CAST []() extern {}; // expected-error {{expected body of lambda expression}}
+
+}
void static_captures() {
int x;
- auto SC1 = [&]() static {}; // expected-error {{a static lambda cannot have any captures}}
- auto SC4 = [x]() static {}; // expected-error {{a static lambda cannot have any captures}}
- auto SC2 = [&x]() static {}; // expected-error {{a static lambda cannot have any captures}}
- auto SC3 = [y=x]() static {}; // expected-error {{a static lambda cannot have any captures}}
- auto SC5 = [&y = x]() static {}; // expected-error {{a static lambda cannot have any captures}}
- auto SC6 = [=]() static {}; // expected-error {{a static lambda cannot have any captures}}
+ TYPE_CAST [&]() static {}; // expected-error {{a static lambda cannot have any captures}}
+ TYPE_CAST [x]() static {}; // expected-error {{a static lambda cannot have any captures}}
+ TYPE_CAST [&x]() static {}; // expected-error {{a static lambda cannot have any captures}}
+ TYPE_CAST [y=x]() static {}; // expected-error {{a static lambda cannot have any captures}}
+ TYPE_CAST [&y = x]() static {}; // expected-error {{a static lambda cannot have any captures}}
+ TYPE_CAST [=]() static {}; // expected-error {{a static lambda cannot have any captures}}
struct X {
int z;
void f() {
>From d9c6d2180e220667ba1bb5ae942a3a04a0b86ed4 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Thu, 15 May 2025 15:27:31 +0200
Subject: [PATCH 2/3] fix typo
---
clang/lib/Parse/ParseExprCXX.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 77544432bbee8..a40e2ad0cadb5 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -705,8 +705,8 @@ bool Parser::IsLambdaAfterTypeCast() {
SkipUntil(tok::r_square);
auto IsLambdaKWOrAttribute = [&]() {
- // These keyworks that either can appear somewhere in a lambda declarator,
- // or cannot appear in a cast expression and we recover in favor of lambdas
+ // These are keyworks that can appear somewhere in a lambda declarator,
+ // or cannot appear in a cast-expression and we recover in favor of lambdas
if (Tok.isOneOf(tok::kw___declspec, tok::kw___noinline__, tok::kw_noexcept,
tok::kw_throw, tok::kw_mutable, tok::kw___attribute,
tok::kw_constexpr, tok::kw_consteval, tok::kw_static,
>From 2be96b5b81b0f9007cc3bb9db5da085e914c072a Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Thu, 15 May 2025 17:54:21 +0200
Subject: [PATCH 3/3] Improve trailing return tyoe handling
---
clang/lib/Parse/ParseExprCXX.cpp | 18 +++++++++++++++++-
clang/test/Parser/cxx0x-lambda-expressions.cpp | 18 +++++++++++++++++-
2 files changed, 34 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index a40e2ad0cadb5..e60cae9510979 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -751,7 +751,23 @@ bool Parser::IsLambdaAfterTypeCast() {
return false;
if (!Tok.is(tok::identifier))
return true;
- return isCXXTypeId(TentativeCXXTypeIdContext::InTrailingReturnType);
+ if(NextToken().is(tok::l_brace))
+ return true;
+
+ // Use a nested unannotated so that we can revert
+ // annotations when we fail to find a brace.
+ TentativeParsingAction TPA(*this, /*Unannotated=*/true);
+ if(TryAnnotateTypeOrScopeToken()
+ || !Tok.isSimpleTypeSpecifier(getLangOpts())) {
+ TPA.Revert();
+ return false;
+ }
+ ConsumeAnyToken();
+ if(Tok.is(tok::l_brace)) {
+ TPA.Commit();
+ return true;
+ }
+ TPA.Revert();
}
return Tok.is(tok::l_brace);
}
diff --git a/clang/test/Parser/cxx0x-lambda-expressions.cpp b/clang/test/Parser/cxx0x-lambda-expressions.cpp
index d5466d44d8fff..f6d9f7effbfe8 100644
--- a/clang/test/Parser/cxx0x-lambda-expressions.cpp
+++ b/clang/test/Parser/cxx0x-lambda-expressions.cpp
@@ -213,8 +213,8 @@ struct S {
};
}
-#if __cplusplus >= 201103L
namespace GH20723 {
+#if __cplusplus >= 201103L
struct S {
S operator[](int);
S operator()();
@@ -228,9 +228,25 @@ void f() {
static_assert(__is_same_as(decltype((S())[n] < 0), S), "");
static_assert(__is_same_as(decltype((S())[n]->a), long), "");
}
+#endif
+#if __cplusplus >= 202302
+struct S2 {
+ S2 operator[]();
+ S2* operator->();
+ template <typename U>
+ constexpr static int trailing = 0;
+};
+
+template <typename T>
+struct trailing{};
+
+void f2() {
+ static_assert(__is_same_as(decltype((S2())[]->trailing<int>), const int));
+ (void)[]->trailing<int>{return {};}();
}
#endif
+}
struct S {
template <typename T>
More information about the cfe-commits
mailing list