https://gcc.gnu.org/g:e28d144e3492b93b5b09e365439758e7403a16d2
commit r17-651-ge28d144e3492b93b5b09e365439758e7403a16d2 Author: Marek Polacek <[email protected]> Date: Wed May 20 16:52:12 2026 -0400 c++: ICE with variadic using-decl with conv fn [PR125284] When we have using foo<T>::operator T...; tsubst_decl/USING_DECL calls tsubst_pack_expansion twice and then builds up a USING_DECL via do_class_using_decl. But we crash here with using foo<T>::operator T...; using foo<T>::operator T*...; because tsubst/TEMPLATE_TYPE_PARM gets an identifier node for __conv_op which is not TYPE_P. When we are substituting the first using, args is <tree_vec 0x7fffe99c6e20 length:1 elt:0 <type_argument_pack 0x7fffe99e6690 type <tree_vec 0x7fffe99c6e40 length:1 elt:0 <integer_type 0x7fffe98235e8 int>> VOID align:8 warn_if_not_align:0 symtab:0 alias-set -1 canonical-type 0x7fffe99e6690>> and tsubst_pack_expansion gives us <tree_vec 0x7fffe99c6e40 length:1 elt:0 <integer_type 0x7fffe98235e8 int public type_6 SI size <integer_cst 0x7fffe981b528 constant 32> unit-size <integer_cst 0x7fffe981b540 constant 4> align:32 warn_if_not_align:0 symtab:0 alias-set -1 canonical-type 0x7fffe98235e8 precision:32 min <integer_cst 0x7fffe981b4e0 -2147483648> max <integer_cst 0x7fffe981b4f8 2147483647> pointer_to_this <pointer_type 0x7fffe982ab28>>> Note that the tree_vecs are the same one. So when we rewrite the arguments from tsubst_pack_expansion using make_conv_op_name, we also rewrite args. PR c++/125284 PR c++/125333 gcc/cp/ChangeLog: * pt.cc (tsubst_decl) <case USING_DECL>: Copy targs before modifying them. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/using-variadic4.C: New test. * g++.dg/cpp1z/using-variadic5.C: New test. Reviewed-by: Jason Merrill <[email protected]> Diff: --- gcc/cp/pt.cc | 1 + gcc/testsuite/g++.dg/cpp1z/using-variadic4.C | 16 ++++++++++++++++ gcc/testsuite/g++.dg/cpp1z/using-variadic5.C | 19 +++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index d19864774a3c..91aa9f556022 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -16086,6 +16086,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain, r = error_mark_node; break; } + name = copy_node (name); for (tree& elt : tree_vec_range (name)) elt = make_conv_op_name (elt); variadic_p = true; diff --git a/gcc/testsuite/g++.dg/cpp1z/using-variadic4.C b/gcc/testsuite/g++.dg/cpp1z/using-variadic4.C new file mode 100644 index 000000000000..1c0728e20817 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/using-variadic4.C @@ -0,0 +1,16 @@ +// PR c++/125284 +// { dg-do compile { target c++17 } } + +template<typename T> +struct foo { + operator T(); + operator T*(); +}; + +template<typename... T> +struct bar : foo<T>... { + using foo<T>::operator T...; + using foo<T>::operator T*...; +}; + +bar<int> z; diff --git a/gcc/testsuite/g++.dg/cpp1z/using-variadic5.C b/gcc/testsuite/g++.dg/cpp1z/using-variadic5.C new file mode 100644 index 000000000000..88b03373bae6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/using-variadic5.C @@ -0,0 +1,19 @@ +// PR c++/125333 +// { dg-do compile { target c++17 } } + +template<typename... T> +struct X {}; + +template <typename U> +struct Y { + operator U(); +}; + +template <typename... V> +struct Z : Y<V>... { + using Y<V>::operator V...; + + X<V...> x; +}; + +Z<int, double> z;
