[clang] 28c3bf5 - [Clang][Parser] Add a warning to ambiguous uses of T...[N] types (#116332)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Dec 12 23:50:46 PST 2024
Author: Younan Zhang
Date: 2024-12-13T15:50:41+08:00
New Revision: 28c3bf5c6dad0974f9f15b58afd0935c0c6cb3e4
URL: https://github.com/llvm/llvm-project/commit/28c3bf5c6dad0974f9f15b58afd0935c0c6cb3e4
DIFF: https://github.com/llvm/llvm-project/commit/28c3bf5c6dad0974f9f15b58afd0935c0c6cb3e4.diff
LOG: [Clang][Parser] Add a warning to ambiguous uses of T...[N] types (#116332)
`void f(T... [N])` is no longer treated as a function with a parameter
of pack expansion type after the implementation of the pack indexing
feature. This patch introduces a warning to clarify such cases while
maintaining it as a pack indexing type in all language modes.
Closes https://github.com/llvm/llvm-project/issues/115222
Added:
Modified:
clang/include/clang/Basic/DiagnosticParseKinds.td
clang/lib/Parse/ParseExprCXX.cpp
clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
clang/test/Parser/cxx0x-decl.cpp
clang/test/Parser/cxx2c-pack-indexing.cpp
clang/test/SemaCXX/cxx2c-pack-indexing-ext-diags.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 9fa8d5901bd0a5..86fcae209c40db 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -721,6 +721,9 @@ def warn_empty_init_statement : Warning<
"has no effect">, InGroup<EmptyInitStatement>, DefaultIgnore;
def err_keyword_as_parameter : Error <
"invalid parameter name: '%0' is a keyword">;
+def warn_pre_cxx26_ambiguous_pack_indexing_type : Warning<
+ "%0 is no longer a pack expansion but a pack "
+ "indexing type; add a name to specify a pack expansion">, InGroup<CXXPre26Compat>;
// C++ derived classes
def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">;
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 03a58048e53a94..33a90e0cb8a42a 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -238,7 +238,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
else if (!HasScopeSpecifier && Tok.is(tok::identifier) &&
GetLookAheadToken(1).is(tok::ellipsis) &&
- GetLookAheadToken(2).is(tok::l_square)) {
+ GetLookAheadToken(2).is(tok::l_square) &&
+ !GetLookAheadToken(3).is(tok::r_square)) {
SourceLocation Start = Tok.getLocation();
DeclSpec DS(AttrFactory);
SourceLocation CCLoc;
@@ -253,6 +254,19 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
if (Type.isNull())
return false;
+ // C++ [cpp23.dcl.dcl-2]:
+ // Previously, T...[n] would declare a pack of function parameters.
+ // T...[n] is now a pack-index-specifier. [...] Valid C++ 2023 code that
+ // declares a pack of parameters without specifying a declarator-id
+ // becomes ill-formed.
+ //
+ // However, we still treat it as a pack indexing type because the use case
+ // is fairly rare, to ensure semantic consistency given that we have
+ // backported this feature to pre-C++26 modes.
+ if (!Tok.is(tok::coloncolon) && !getLangOpts().CPlusPlus26 &&
+ getCurScope()->isFunctionDeclarationScope())
+ Diag(Start, diag::warn_pre_cxx26_ambiguous_pack_indexing_type) << Type;
+
if (!TryConsumeToken(tok::coloncolon, CCLoc)) {
AnnotateExistingIndexedTypeNamePack(ParsedType::make(Type), Start,
EndLoc);
diff --git a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
index dbb6e60d9b93d7..a633c108bc22cd 100644
--- a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
+++ b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
@@ -57,9 +57,11 @@ template<typename T>
void b(T[] ...);
template<typename T>
-void c(T ... []); // expected-error {{expected expression}} \
- // expected-error {{'T' does not refer to the name of a parameter pack}} \
- // expected-warning {{pack indexing is a C++2c extension}}
+void c(T ... []); // expected-error {{type 'T[]' of function parameter pack does not contain any unexpanded parameter packs}}
+
+// A function that takes pointers to each type T as arguments, after any decay.
+template <typename ...T>
+void g(T...[]);
template<typename T>
void d(T ... x[]); // expected-error{{type 'T[]' of function parameter pack does not contain any unexpanded parameter packs}}
diff --git a/clang/test/Parser/cxx0x-decl.cpp b/clang/test/Parser/cxx0x-decl.cpp
index a0b3266c738ff5..6d4f16c6f533e8 100644
--- a/clang/test/Parser/cxx0x-decl.cpp
+++ b/clang/test/Parser/cxx0x-decl.cpp
@@ -214,6 +214,7 @@ struct MemberComponentOrder : Base {
void NoMissingSemicolonHere(struct S
[3]);
template<int ...N> void NoMissingSemicolonHereEither(struct S... [N]);
+// expected-warning at -1 {{'S...[N]' is no longer a pack expansion but a pack indexing type; add a name to specify a pack expansion}} \
// expected-error at -1 {{'S' does not refer to the name of a parameter pack}} \
// expected-error at -1 {{declaration of anonymous struct must be a definition}} \
// expected-error at -1 {{expected parameter declarator}} \
diff --git a/clang/test/Parser/cxx2c-pack-indexing.cpp b/clang/test/Parser/cxx2c-pack-indexing.cpp
index 99347a2f8f1571..72e286322fa976 100644
--- a/clang/test/Parser/cxx2c-pack-indexing.cpp
+++ b/clang/test/Parser/cxx2c-pack-indexing.cpp
@@ -12,8 +12,7 @@ struct S {
// expected-note {{to match this '['}} \
// expected-warning{{declaration does not declare anything}}
- T...[]; // expected-error{{expected expression}} \
- // expected-warning{{declaration does not declare anything}}
+ T...[]; // expected-error{{expected member name or ';' after declaration specifiers}}
void f(auto... v) {
decltype(v...[1]) a = v...[1];
@@ -65,7 +64,7 @@ int main() {
}
-namespace GH11460 {
+namespace GH111460 {
template <typename... T>
requires( ); // expected-error {{expected expression}}
struct SS {
diff --git a/clang/test/SemaCXX/cxx2c-pack-indexing-ext-diags.cpp b/clang/test/SemaCXX/cxx2c-pack-indexing-ext-diags.cpp
index 80dfeb9b6a8bf5..118af8e867f5f6 100644
--- a/clang/test/SemaCXX/cxx2c-pack-indexing-ext-diags.cpp
+++ b/clang/test/SemaCXX/cxx2c-pack-indexing-ext-diags.cpp
@@ -19,3 +19,35 @@ void f(T... t) {
// cxx11-warning at +1 {{pack indexing is a C++2c extension}}
T...[0] c;
}
+
+template <typename... T>
+void g(T... [1]); // cxx11-warning {{'T...[1]' is no longer a pack expansion but a pack indexing type; add a name to specify a pack expansion}} \
+ // cxx11-warning {{pack indexing is a C++2c extension}} \
+ // cxx11-note {{candidate function template not viable}} \
+ // cxx26-warning {{pack indexing is incompatible with C++ standards before C++2c}} \
+ // cxx26-note {{candidate function template not viable}}
+
+template <typename... T>
+void h(T... param[1]);
+
+template <class T>
+struct S {
+ using type = T;
+};
+
+template <typename... T>
+void h(typename T... [1]::type); // cxx11-warning {{pack indexing is a C++2c extension}} \
+ // cxx26-warning {{pack indexing is incompatible with C++ standards before C++2c}}
+
+template <typename... T>
+void x(T... [0]); // cxx11-warning {{'T...[0]' is no longer a pack expansion but a pack indexing type; add a name to specify a pack expansion}} \
+ // cxx11-warning {{pack indexing is a C++2c extension}} \
+ // cxx26-warning {{pack indexing is incompatible with C++ standards before C++2c}}
+
+void call() {
+ g<int, double>(nullptr, nullptr); // cxx26-error {{no matching function for call to 'g'}} \
+ // cxx11-error {{no matching function for call to 'g'}}
+ h<int, double>(nullptr, nullptr);
+ h<S<int>, S<const char *>>("hello");
+ x<int*>(nullptr);
+}
More information about the cfe-commits
mailing list