Hi!
The following testcase ICEs in tsubst_pack_expansion, we trigger the
gcc_assert (DECL_DECOMPOSITION_P (orig_arg));
assertion. But in this case, retrieve_local_specialization doesn't
return the expected DECL_DECOMPOSITION_P, but ARGUMENT_PACK_SELECT instead.
That is because it has been registered earlier in
gen_elem_of_pack_expansion_instantiation
in
aps = make_argument_pack_select (arg_pack, index);
if (!mark_used (parm, complain) && !(complain & tf_error))
return error_mark_node;
register_local_specialization (aps, parm);
The following patch just stops assuming retrieve_local_specialization
has to return DECL_DECOMPOSITION_P, but allows also ARGUMENT_PACK_SELECT.
The patch is large due to reindentation, with diff -upb it is just
@@ -14309,8 +14309,9 @@ tsubst_pack_expansion (tree t, tree args
else if (DECL_DECOMPOSITION_P (parm_pack))
{
orig_arg = retrieve_local_specialization (parm_pack);
+ if (DECL_DECOMPOSITION_P (orig_arg))
+ {
expand_sb_pack:
- gcc_assert (DECL_DECOMPOSITION_P (orig_arg));
if (TREE_TYPE (orig_arg) == error_mark_node)
return error_mark_node;
gcc_assert (DECL_HAS_VALUE_EXPR_P (orig_arg));
@@ -14339,6 +14340,12 @@ tsubst_pack_expansion (tree t, tree args
}
}
else
+ {
+ gcc_assert (TREE_CODE (orig_arg) == ARGUMENT_PACK_SELECT);
+ arg_pack = orig_arg;
+ }
+ }
+ else
{
int idx;
template_parm_level_and_index (parm_pack, &level, &idx);
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
2026-06-05 Jakub Jelinek <[email protected]>
PR c++/125591
* pt.cc (tsubst_pack_expansion): Don't require
retrieve_local_specialization on structured binding to
always return structured binding, instead handle if it returns
ARGUMENT_PACK_SELECT.
* g++.dg/cpp26/decomp31.C: New test.
--- gcc/cp/pt.cc.jj 2026-06-04 10:14:24.000000000 +0200
+++ gcc/cp/pt.cc 2026-06-04 11:56:57.660514412 +0200
@@ -14265,33 +14265,40 @@ tsubst_pack_expansion (tree t, tree args
else if (DECL_DECOMPOSITION_P (parm_pack))
{
orig_arg = retrieve_local_specialization (parm_pack);
- expand_sb_pack:
- gcc_assert (DECL_DECOMPOSITION_P (orig_arg));
- if (TREE_TYPE (orig_arg) == error_mark_node)
- return error_mark_node;
- gcc_assert (DECL_HAS_VALUE_EXPR_P (orig_arg));
- arg_pack = DECL_VALUE_EXPR (orig_arg);
- if (TREE_CODE (arg_pack) != ARRAY_REF)
+ if (DECL_DECOMPOSITION_P (orig_arg))
{
- /* Structured binding packs when initializer is non-dependent
- should have their DECL_VALUE_EXPR set to a TREE_VEC. See
- cp_finish_decomp comment above the packv variable for
- details. */
- tree vec = make_tree_vec (TREE_VEC_LENGTH (arg_pack) - 2);
- if (TREE_VEC_LENGTH (vec))
- memcpy (TREE_VEC_BEGIN (vec), &TREE_VEC_ELT (arg_pack, 2),
- TREE_VEC_LENGTH (vec) * sizeof (tree));
- arg_pack = make_node (NONTYPE_ARGUMENT_PACK);
- ARGUMENT_PACK_ARGS (arg_pack) = vec;
+ expand_sb_pack:
+ if (TREE_TYPE (orig_arg) == error_mark_node)
+ return error_mark_node;
+ gcc_assert (DECL_HAS_VALUE_EXPR_P (orig_arg));
+ arg_pack = DECL_VALUE_EXPR (orig_arg);
+ if (TREE_CODE (arg_pack) != ARRAY_REF)
+ {
+ /* Structured binding packs when initializer is non-dependent
+ should have their DECL_VALUE_EXPR set to a TREE_VEC. See
+ cp_finish_decomp comment above the packv variable for
+ details. */
+ tree vec = make_tree_vec (TREE_VEC_LENGTH (arg_pack) - 2);
+ if (TREE_VEC_LENGTH (vec))
+ memcpy (TREE_VEC_BEGIN (vec), &TREE_VEC_ELT (arg_pack, 2),
+ TREE_VEC_LENGTH (vec) * sizeof (tree));
+ arg_pack = make_node (NONTYPE_ARGUMENT_PACK);
+ ARGUMENT_PACK_ARGS (arg_pack) = vec;
+ }
+ else
+ {
+ /* If the structured binding pack has type dependent
+ base, we can't expand it yet. */
+ tree base = TREE_OPERAND (arg_pack, 0);
+ gcc_assert (VAR_P (base)
+ && type_dependent_expression_p (base));
+ arg_pack = NULL_TREE;
+ }
}
else
{
- /* If the structured binding pack has type dependent
- base, we can't expand it yet. */
- tree base = TREE_OPERAND (arg_pack, 0);
- gcc_assert (VAR_P (base)
- && type_dependent_expression_p (base));
- arg_pack = NULL_TREE;
+ gcc_assert (TREE_CODE (orig_arg) == ARGUMENT_PACK_SELECT);
+ arg_pack = orig_arg;
}
}
else
--- gcc/testsuite/g++.dg/cpp26/decomp31.C.jj 2026-06-04 12:05:14.975054168
+0200
+++ gcc/testsuite/g++.dg/cpp26/decomp31.C 2026-06-04 12:11:57.886790758
+0200
@@ -0,0 +1,19 @@
+// PR c++/125591
+// { dg-do compile { target c++20 } }
+// { dg-options "" }
+
+template <typename T, typename U>
+concept is_same_v = __is_same (T, U);
+
+struct A { int x, y, z; };
+struct B { int x; long y; };
+
+template <class V>
+consteval bool
+foo ()
+{
+ constexpr auto [...Ms] = V {}; // { dg-warning "structured
binding packs only available with" "" { target c++23_down } }
+ // { dg-warning "structured
binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+ using T = decltype (Ms...[0]); // { dg-warning "pack indexing
only available with" "" { target c++23_down } }
+ return (is_same_v<decltype(Ms), T> && ...);
+}
Jakub