On Wed, Mar 01, 2023 at 04:44:12PM -0500, Jason Merrill wrote: > On 3/1/23 16:40, Marek Polacek wrote: > > On Wed, Mar 01, 2023 at 04:30:16PM -0500, Jason Merrill wrote: > > > On 3/1/23 15:33, Marek Polacek wrote: > > > > -Wmismatched-tags warns about the (harmless) struct/class mismatch. > > > > For, e.g., > > > > > > > > template<typename T> struct A { }; > > > > class A<int> a; > > > > > > > > it works by adding A<T> to the class2loc hash table while parsing the > > > > class-head and then, while parsing the elaborate type-specifier, we > > > > add A<int>. At the end of c_parse_file we go through the table and > > > > warn about the class-key mismatches. In this PR we crash though; we > > > > have > > > > > > > > template<typename T> struct A { > > > > template<typename U> struct W { }; > > > > }; > > > > struct A<int>::W<int> w; // #1 > > > > > > > > where while parsing A and #1 we've stashed > > > > A<T> > > > > A<T>::W<U> > > > > A<int>::W<int> > > > > into class2loc. Then in class_decl_loc_t::diag_mismatched_tags TYPE > > > > is A<int>::W<int>, and specialization_of gets us A<int>::W<U>, which > > > > is not in class2loc, so we crash on gcc_assert (cdlguide). But it's > > > > OK not to have found A<int>::W<U>, we should just look one "level" up, > > > > that is, A<T>::W<U>. > > > > > > > > It's important to handle class specializations, so e.g. > > > > > > > > template<> > > > > struct A<char> { > > > > template<typename U> > > > > class W { }; > > > > }; > > > > > > > > where W's class-key is different than in the primary template above, > > > > so we should warn depending on whether we're looking into A<char> > > > > or into a different instantiation. > > > > > > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? > > > > > > > > PR c++/106259 > > > > > > > > gcc/cp/ChangeLog: > > > > > > > > * parser.cc (class_decl_loc_t::diag_mismatched_tags): If the > > > > first > > > > lookup of SPEC didn't find anything, try to look for > > > > most_general_template. > > > > > > > > gcc/testsuite/ChangeLog: > > > > > > > > * g++.dg/warn/Wmismatched-tags-11.C: New test. > > > > --- > > > > gcc/cp/parser.cc | 30 > > > > +++++++++++++++---- > > > > .../g++.dg/warn/Wmismatched-tags-11.C | 23 ++++++++++++++ > > > > 2 files changed, 47 insertions(+), 6 deletions(-) > > > > create mode 100644 gcc/testsuite/g++.dg/warn/Wmismatched-tags-11.C > > > > > > > > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc > > > > index 1a124f5395e..b528ee7b1d9 100644 > > > > --- a/gcc/cp/parser.cc > > > > +++ b/gcc/cp/parser.cc > > > > @@ -34473,14 +34473,32 @@ class_decl_loc_t::diag_mismatched_tags (tree > > > > type_decl) > > > > be (and inevitably is) at index zero. */ > > > > tree spec = specialization_of (type); > > > > cdlguide = class2loc.get (spec); > > > > + /* It's possible that we didn't find SPEC. Consider: > > > > + > > > > + template<typename T> struct A { > > > > + template<typename U> struct W { }; > > > > + }; > > > > + struct A<int>::W<int> w; // #1 > > > > + > > > > + where while parsing A and #1 we've stashed > > > > + A<T> > > > > + A<T>::W<U> > > > > + A<int>::W<int> > > > > + into CLASS2LOC. If TYPE is A<int>::W<int>, specialization_of > > > > + will yield A<int>::W<U> which may be in CLASS2LOC if we had > > > > + an A<int> class specialization, but otherwise won't be in it. > > > > + So try to look up A<T>::W<U>. */ > > > > + if (!cdlguide) > > > > + { > > > > + spec = DECL_TEMPLATE_RESULT (most_general_template (spec)); > > > > > > Would it make sense to only look at most_general_template, not > > > A<int>::W<U> > > > at all? > > > > I think that would break with class specialization, as in... > > > > > > +template<typename T> struct A { > > > > + template<typename U> > > > > + struct W { }; > > > > +}; > > > > + > > > > +template<> > > > > +struct A<char> { > > > > + template<typename U> > > > > + class W { }; > > > > +}; > > > > + > > > > +void > > > > +g () > > > > +{ > > > > + struct A<char>::W<int> w1; // { dg-warning "mismatched" } > > > > ...this, where we should first look into A<char>, and only if not > > found, go to A<T>. > > I'd expect the > > > /* Stop if we run into an explicitly specialized class template. */ > > code in most_general_template to avoid that problem.
Ah, I had no idea it does that. The unconditional most_general_template works fine for the new test, but some of the existing tests then fail. Reduced: template <class Z> struct S2; // #1 template <class T> class S2<const T>; // #2 extern class S2<const int> s2ci; // #3 extern struct S2<const int> s2ci; // { dg-warning "\\\[-Wmismatched-tags" } where the unconditional most_general_template changes spec from "class S2<const T>" to "struct S2<Z>" (both of which are in class2loc). So it regresses the diagnostic, complaining that #3 should have "struct" since #1 has "struct". I think we want to keep the current diagnostic, saying that the last line should have "class" since the specialization in line #2 has "class".