Re: [PATCH] c++: Fix structured binding pack instantiation ICE [PR125591]

Jason Merrill <[email protected]> Wed, 5 Aug 2026 16:08:13 -0400
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
On 6/5/26 2:18 AM, Jakub Jelinek wrote:
> 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?

OK.

> 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
>