https://gcc.gnu.org/g:647cbb7812ed77a1b39c41dcacc8f30626087a95
commit r16-8461-g647cbb7812ed77a1b39c41dcacc8f30626087a95 Author: Jakub Jelinek <[email protected]> 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 <[email protected]> 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> ();
