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>;
> > +};
> > 
> 

Reply via email to