[gcc r16-8461] c++: Fix up pack indexing [PR124198]
Jakub Jelinek
jakub@gcc.gnu.org
Sat Apr 4 09:08:36 GMT 2026
https://gcc.gnu.org/g:647cbb7812ed77a1b39c41dcacc8f30626087a95
commit r16-8461-g647cbb7812ed77a1b39c41dcacc8f30626087a95
Author: Jakub Jelinek <jakub@redhat.com>
Date: Sat Apr 4 11:07:40 2026 +0200
c++: Fix up pack indexing [PR124198]
https://eel.is/c++draft/expr.prim.pack.index#2 says:
The constant-expression shall be a converted constant expression of type
std::size_t whose value V, termed the index, is such that 0<=V<sizeof...(P).
But we actually don't implement it like that, instead just error out if
the index doesn't have an integral type or is negative.
Because of this we don't call mark_rvalue_use on it, so on pack-indexing20.C
we report a bogus warning that the var used in the index is unused but set,
and more importantly we reject the IMHO valid testcase pack-indexing21.C.
The following patch calls build_converted_constant_expr to make sure it
is converted, marked as read, if not possible to be converted diagnostics
is emitted.
2026-04-04 Jakub Jelinek <jakub@redhat.com>
PR c++/124198
* parser.cc (cp_parser_pack_index): If index is not type dependent,
call build_converted_constant_expr on it. Return error_mark_node
if index is error_operand_p.
* pt.cc (tsubst_pack_index): Likewise.
* g++.dg/cpp26/pack-indexing2.C (getT2, badtype4): Expect different
diagnostics.
* g++.dg/cpp26/pack-indexing20.C: New test.
* g++.dg/cpp26/pack-indexing21.C: New test.
Diff:
---
gcc/cp/parser.cc | 5 +++++
gcc/cp/pt.cc | 4 ++++
gcc/testsuite/g++.dg/cpp26/pack-indexing2.C | 4 ++--
gcc/testsuite/g++.dg/cpp26/pack-indexing20.C | 13 +++++++++++++
gcc/testsuite/g++.dg/cpp26/pack-indexing21.C | 19 +++++++++++++++++++
5 files changed, 43 insertions(+), 2 deletions(-)
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 8d88dc9c312c..84eef39941c9 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -6091,6 +6091,11 @@ cp_parser_pack_index (cp_parser *parser, tree pack)
if (TREE_CODE (pack) == TYPE_DECL)
pack = TREE_TYPE (pack);
pack = make_pack_expansion (pack);
+ if (!type_dependent_expression_p (index))
+ index = build_converted_constant_expr (size_type_node, index,
+ tf_warning_or_error);
+ if (error_operand_p (index))
+ return error_mark_node;
return make_pack_index (pack, index);
}
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index ab88488be4b5..d83ff031d77b 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -14416,6 +14416,10 @@ tsubst_pack_index (tree t, tree args, tsubst_flags_t complain, tree in_decl)
const bool parenthesized_p = (TREE_CODE (t) == PACK_INDEX_EXPR
&& PACK_INDEX_PARENTHESIZED_P (t));
tree r;
+ if (!type_dependent_expression_p (index))
+ index = build_converted_constant_expr (size_type_node, index, complain);
+ if (error_operand_p (index))
+ return error_mark_node;
if (!value_dependent_expression_p (index) && TREE_CODE (pack) == TREE_VEC)
r = pack_index_element (index, pack, parenthesized_p, complain);
else
diff --git a/gcc/testsuite/g++.dg/cpp26/pack-indexing2.C b/gcc/testsuite/g++.dg/cpp26/pack-indexing2.C
index 4a7e494ab043..a1dea4f5bfcb 100644
--- a/gcc/testsuite/g++.dg/cpp26/pack-indexing2.C
+++ b/gcc/testsuite/g++.dg/cpp26/pack-indexing2.C
@@ -49,7 +49,7 @@ template<int N>
int
getT2 (auto... Ts)
{
- return Ts...[N]; // { dg-error "pack index '-1' is negative" }
+ return Ts...[N]; // { dg-error "pack index '\[0-9]*' is out of range for pack of length '1'" }
}
template<auto N, typename... Ts>
@@ -77,7 +77,7 @@ template<auto N, typename... Ts>
void
badtype4 ()
{
- Ts...[N] t; // { dg-error "pack index '-1' is negative" }
+ Ts...[N] t; // { dg-error "narrowing conversion of '-1' from 'int' to" }
}
int nonconst () { return 42; }
diff --git a/gcc/testsuite/g++.dg/cpp26/pack-indexing20.C b/gcc/testsuite/g++.dg/cpp26/pack-indexing20.C
new file mode 100644
index 000000000000..422d34445f2b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/pack-indexing20.C
@@ -0,0 +1,13 @@
+// PR c++/124198
+// { dg-do compile { target c++17 } }
+// { dg-options "-Wunused-but-set-variable" }
+
+template <int ...N>
+int
+foo ()
+{
+ constexpr int a = 1; // { dg-bogus "variable 'a' set but not used" }
+ return N...[a]; // { dg-warning "pack indexing only available with" "" { target c++23_down } }
+}
+
+int a = foo <1, 2, 3> ();
diff --git a/gcc/testsuite/g++.dg/cpp26/pack-indexing21.C b/gcc/testsuite/g++.dg/cpp26/pack-indexing21.C
new file mode 100644
index 000000000000..c824f79bcf2c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/pack-indexing21.C
@@ -0,0 +1,19 @@
+// PR c++/124198
+// { dg-do compile { target c++17 } }
+// { dg-options "" }
+
+struct A {
+ constexpr A () : a (1) {}
+ int a;
+ constexpr operator int () const { return a; }
+};
+
+template <int ...N>
+int
+foo ()
+{
+ constexpr A a;
+ return N...[a]; // { dg-warning "pack indexing only available with" "" { target c++23_down } }
+}
+
+int a = foo <1, 2, 3> ();
More information about the Gcc-cvs
mailing list