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> ();

Reply via email to