[clang] [Clang][Parser] Make 'T...[N]' within a function parameter a valid pack expansion prior to C++2c (PR #116332)
Younan Zhang via cfe-commits
cfe-commits at lists.llvm.org
Thu Nov 14 23:32:43 PST 2024
https://github.com/zyn0217 created https://github.com/llvm/llvm-project/pull/116332
This patch makes cases `void f(T... [N])` valid and adds a warning where the parameter is not of a pack indexing but of a pack expansion type, as per https://eel.is/c++draft/diff#cpp23.dcl.dcl-2.
Fixes https://github.com/llvm/llvm-project/issues/115222
>From 5973de1d4c368a26fd179954a13de94595f35575 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Fri, 15 Nov 2024 14:09:14 +0800
Subject: [PATCH] [Clang][Parser] Make 'T...[N]' within a function parameter a
valid pack expansion prior to C++2c
---
.../clang/Basic/DiagnosticParseKinds.td | 5 ++++
clang/lib/Parse/ParseExprCXX.cpp | 18 ++++++++++++++
.../CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp | 5 ++--
clang/test/Parser/cxx0x-decl.cpp | 8 ++-----
.../SemaCXX/cxx2c-pack-indexing-ext-diags.cpp | 24 +++++++++++++++++++
5 files changed, 52 insertions(+), 8 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 0da509280068ad..7b408f3eed5ba5 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -718,6 +718,11 @@ 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<
+ "parameter packs without specifying a name would become a pack indexing "
+ "declaration in C++2c onwards">, InGroup<CXXPre26Compat>;
+def note_add_a_name_to_pre_cxx26_parameter_packs : Note<
+ "add a name to disambiguate">;
// 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 ce3624f366a2a1..c596785b267b5b 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -242,7 +242,25 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
SourceLocation Start = Tok.getLocation();
DeclSpec DS(AttrFactory);
SourceLocation CCLoc;
+ TentativeParsingAction MaybePackIndexing(*this, /*Unannotated=*/true);
SourceLocation EndLoc = ParsePackIndexingType(DS);
+ // 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.
+ if (!Tok.is(tok::coloncolon) && !getLangOpts().CPlusPlus26 &&
+ getCurScope()->isFunctionDeclarationScope()) {
+ Diag(DS.getEllipsisLoc(),
+ diag::warn_pre_cxx26_ambiguous_pack_indexing_type);
+ Diag(DS.getEllipsisLoc(),
+ diag::note_add_a_name_to_pre_cxx26_parameter_packs);
+ MaybePackIndexing.Revert();
+ return false;
+ }
+
+ MaybePackIndexing.Commit();
+
if (DS.getTypeSpecType() == DeclSpec::TST_error)
return false;
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..0ae08da280b152 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
@@ -58,8 +58,9 @@ 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}}
+ // expected-error {{type 'T[]' of function parameter pack does not contain any unexpanded parameter packs}} \
+ // expected-warning {{would become a pack indexing declaration in C++2c onwards}} \
+ // expected-note {{add a name to disambiguate}}
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..91b97df459df92 100644
--- a/clang/test/Parser/cxx0x-decl.cpp
+++ b/clang/test/Parser/cxx0x-decl.cpp
@@ -214,12 +214,8 @@ struct MemberComponentOrder : Base {
void NoMissingSemicolonHere(struct S
[3]);
template<int ...N> void NoMissingSemicolonHereEither(struct S... [N]);
-// 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}} \
-// expected-error at -1 {{pack indexing is a C++2c extension}} \
-
-
+// expected-warning at -1 {{parameter packs without specifying a name would become a pack indexing declaration in C++2c onwards}} \
+// expected-note at -1 {{add a name to disambiguate}}
// This must be at the end of the file; we used to look ahead past the EOF token here.
// expected-error at +1 {{expected unqualified-id}} expected-error at +1{{expected ';'}}
diff --git a/clang/test/SemaCXX/cxx2c-pack-indexing-ext-diags.cpp b/clang/test/SemaCXX/cxx2c-pack-indexing-ext-diags.cpp
index 80dfeb9b6a8bf5..f4dbd5ca539635 100644
--- a/clang/test/SemaCXX/cxx2c-pack-indexing-ext-diags.cpp
+++ b/clang/test/SemaCXX/cxx2c-pack-indexing-ext-diags.cpp
@@ -19,3 +19,27 @@ 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 {{parameter packs without specifying a name would become a pack indexing declaration in C++2c onwards}} \
+ // cxx11-note {{add a name to disambiguate}} \
+ // 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}}
+
+void call() {
+ g<int, double>(nullptr, nullptr); // cxx26-error {{no matching function for call to 'g'}}
+ h<int, double>(nullptr, nullptr);
+ h<S<int>, S<const char *>>("hello");
+}
More information about the cfe-commits
mailing list