On Mon, Jun 22, 2026 at 11:18:45AM -0400, Jason Merrill wrote: > On 6/21/26 7:21 PM, Stefan Strogin wrote: > > While investigating an ICE in VCMI with Qt 6 headers and > > -Wmismatched-tags, I found that tsubst can read past the end of a > > template argument `level` during partial specialization matching. > > > > The failing path is: > > > > class_decl_loc_t::diag_mismatched_tags > > most_specialized_partial_spec > > get_partial_spec_bindings > > tsubst > > > > In tsubst, template_parm_level_and_index determines both `level` and > > `idx` from the template parameter. The current code checks that the > > argument `level` is non-empty before using TMPL_ARG, but that does not > > mean that `idx` is a valid element of the `level`. > > > > In my case GCC tries to read element 3 from a TREE_VEC with 2 elements. > > The code below already handles the case where no argument was found by > > returning `t` unchanged for `level == 1`. So check that the requested > > index exists, not only that the level is non-empty. > > This sort of ICE means that the args are wrong for this substitution, > and we need to correct that at a higher level, not paper over it like this.
Thanks, that makes sense. I'll send the v2 patch shortly. > > > gcc/cp/ChangeLog: > > > > * pt.cc (tsubst): Check the template argument index before > > reading from a template argument level. > > > > gcc/testsuite/ChangeLog: > > > > * g++.dg/warn/Wmismatched-tags-ice1.C: New test. > > > > Testing: > > > > * Built all-gcc on x86_64-pc-linux-gnu. > > * make -k check-g++ RUNTESTFLAGS="dg.exp=Wmismatched-tags-ice1.C" > > * Verified that the original preprocessed VCMI/Qt reproducer no > > longer ICEs with -Wmismatched-tags. > > > > Signed-off-by: Stefan Strogin <[email protected]> > > > > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc > > index b7f9ce4cb0a..c65db71fee0 100644 > > --- a/gcc/cp/pt.cc > > +++ b/gcc/cp/pt.cc > > @@ -17389,7 +17389,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, > > tree in_decl) > > > > levels = TMPL_ARGS_DEPTH (args); > > if (level <= levels > > - && TREE_VEC_LENGTH (TMPL_ARGS_LEVEL (args, level)) > 0) > > + && idx < TREE_VEC_LENGTH (TMPL_ARGS_LEVEL (args, level))) > > { > > arg = TMPL_ARG (args, level, idx); > > > > diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-tags-ice1.C > > b/gcc/testsuite/g++.dg/warn/Wmismatched-tags-ice1.C > > new file mode 100644 > > index 00000000000..debde11130c > > --- /dev/null > > +++ b/gcc/testsuite/g++.dg/warn/Wmismatched-tags-ice1.C > > @@ -0,0 +1,8 @@ > > +// { dg-do compile } > > +// { dg-options "-Wmismatched-tags" } > > + > > +template <class, class> struct A { > > + template <class, class = void> struct B; > > + template <class T> struct B<T>; > > + struct B<int>; > > +}; > > >
