Test code: // https://godbolt.org/z/7f8PE88xs struct A { int B; struct B {}; }; struct S1 : A::B {}; // OK // - EDG/MSVC: OK // - GCC (<= 12.5): OK // - GCC (>= 13.1): error: 'typename A::B' names 'int A::B', which is // not a type // - Clang: error: typename specifier refers to non-type member 'B' in // 'A' template <class T> struct S2 : T::B {}; template class S2<A>;
Reading the commit message for r13-6098-g46711ff8e60d64b7e5550f (the change most likely which introduced the difference), makes me think GCC 13+ is correct here.
In fact g++.dg/template/typename24.C that was added is very similar to this testcase. So yes GCC 13+ is correct. So a dup of bug 107773 . *** This bug has been marked as a duplicate of bug 107773 ***
On the other hand [class.derived.general]/2 says "The lookup for the component name of the type-name or simple-template-id (within a base-specifier) is type-only ([basic.lookup])". So perhaps we should accept the template case after all, matching the non-template case. Jason what do you think?
base-specifiers (and the corresponding mem-initializer-ids) have two properties: 1. Name lookup within them is type-only, as stated by Patrick above. Whether the name is dependent or not should not change this. 2. The `typename` disambiguator is disallowed within them by their syntax, since it is redundant semantically (we already ignore non-type names as per Property 1). The observation from the above code is that, seemingly, GCC 13+ and Clang haven't implemented Property 1 for dependent names.
reopening
A typename-specifier is a type-only context under https://eel.is/c++draft/temp.res.general#4.1 and so we should only find type names under https://eel.is/c++draft/basic.lookup.general#4 , so the patch for PR107773 seems wrong. The original testcase for 107773 is about a declaration in a derived class hiding a declaration in a base class, not type-only lookup.
.
(In reply to Jason Merrill from comment #6) > A typename-specifier is a type-only context under > https://eel.is/c++draft/temp.res.general#4.1 and so we should only find type > names under https://eel.is/c++draft/basic.lookup.general#4 , so the patch > for PR107773 seems wrong. I believe *type-only context* and *type-only* lookup serve different purposes. A dependent name inside a type-only context is assumed to be a type. However, if its lookup finds a non-type name, we would get an error. OTOH, type-only lookup (as in, e.g., base specifiers) gives us the privilege of ignoring non-type names. In the end, we either find a type name or get a name-not-found error.
Ah so a type-only context does not imply type-only lookup. Specifically a typename-specifier does not do type-only lookup. I think both elaborated-type-specifier and base-specifier are type-only contexts in which lookup is type-only though (are there others?). So it seems GCC gets things largely right, except for base-specifiers.
The master branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>: https://gcc.gnu.org/g:49ddf362f0a7c1fdeb62f13a852a2fdec9d6fe6d commit r16-4368-g49ddf362f0a7c1fdeb62f13a852a2fdec9d6fe6d Author: Patrick Palka <ppalka@redhat.com> Date: Fri Oct 10 10:25:25 2025 -0400 c++: base-specifier name lookup is type-only [PR122192] The r13-6098 change to make TYPENAME_TYPE no longer always ignore non-type bindings needs another exception: base-specifiers that are represented as TYPENAME_TYPE, for which lookup must be type-only (by [class.derived.general]/2). This patch fixes this by giving such TYPENAME_TYPEs a tag type of class_type rather than typename_type so that we treat them like elaborated-type-specifiers (another type-only lookup situation). PR c++/122192 gcc/cp/ChangeLog: * decl.cc (make_typename_type): Document base-specifier as another type-only lookup case. * parser.cc (cp_parser_class_name): Propagate tag_type to make_typename_type instead of hardcoding typename_type. (cp_parser_base_specifier): Pass class_type instead of typename_type as tag_type to cp_parser_class_name. gcc/testsuite/ChangeLog: * g++.dg/template/dependent-base6.C: New test. Reviewed-by: Jason Merrill <jason@redhat.com>
Fixed on trunk so far
(In reply to Patrick Palka from comment #11) > Fixed on trunk so far Testing on GCC trunk, it seems that name lookup in a mem-initializer-id faces the same issue: // https://godbolt.org/z/Mh3hYzd15 struct A { int B; struct B {}; }; struct S1 : A::B { // OK S1() : A::B{} {} // OK }; template <class T> struct S2 : T::B { // OK // error: 'typename A::B' names 'int A::B', which is not a type S2() : T::B{} {} }; template class S2<A>; Perhaps this could be fixed as well, so we don't need a separate issue.
Good catch, will fix
The master branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>: https://gcc.gnu.org/g:97da8fece19caf0277c2be523520d09252821973 commit r16-4433-g97da8fece19caf0277c2be523520d09252821973 Author: Patrick Palka <ppalka@redhat.com> Date: Tue Oct 14 12:56:23 2025 -0400 c++: mem-initializer-id qualified name lookup is type-only [PR122192] Since a mem-initializer needs to be able to initialize any base class, lookup for which is type-only, we in turn need to make mem-initializer-id qualified name lookup type-only too. PR c++/122192 gcc/cp/ChangeLog: * parser.cc (cp_parser_mem_initializer_id): Pass class_type instead of typename_type to cp_parser_class_name in the nested-name-specifier case. gcc/testsuite/ChangeLog: * g++.dg/template/dependent-base6.C: Verify mem-initializer-id qualified name lookup is type-only too. Reported-by: Vincent X Reviewed-by: Jason Merrill <jason@redhat.com>
The releases/gcc-15 branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>: https://gcc.gnu.org/g:df569c064eac2f30c6f19fe5db931cdad0b2abcb commit r15-10461-gdf569c064eac2f30c6f19fe5db931cdad0b2abcb Author: Patrick Palka <ppalka@redhat.com> Date: Fri Oct 10 10:25:25 2025 -0400 c++: base-specifier name lookup is type-only [PR122192] The r13-6098 change to make TYPENAME_TYPE no longer always ignore non-type bindings needs another exception: base-specifiers that are represented as TYPENAME_TYPE, for which lookup must be type-only (by [class.derived.general]/2). This patch fixes this by giving such TYPENAME_TYPEs a tag type of class_type rather than typename_type so that we treat them like elaborated-type-specifiers (another type-only lookup situation). PR c++/122192 gcc/cp/ChangeLog: * decl.cc (make_typename_type): Document base-specifier as another type-only lookup case. * parser.cc (cp_parser_class_name): Propagate tag_type to make_typename_type instead of hardcoding typename_type. (cp_parser_base_specifier): Pass class_type instead of typename_type as tag_type to cp_parser_class_name. gcc/testsuite/ChangeLog: * g++.dg/template/dependent-base6.C: New test. Reviewed-by: Jason Merrill <jason@redhat.com> (cherry picked from commit 49ddf362f0a7c1fdeb62f13a852a2fdec9d6fe6d)
The releases/gcc-15 branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>: https://gcc.gnu.org/g:402d57846c9acca15ff80e192e3ede1f179eb8f2 commit r15-10462-g402d57846c9acca15ff80e192e3ede1f179eb8f2 Author: Patrick Palka <ppalka@redhat.com> Date: Tue Oct 14 12:56:23 2025 -0400 c++: mem-initializer-id qualified name lookup is type-only [PR122192] Since a mem-initializer needs to be able to initialize any base class, lookup for which is type-only, we in turn need to make mem-initializer-id qualified name lookup type-only too. PR c++/122192 gcc/cp/ChangeLog: * parser.cc (cp_parser_mem_initializer_id): Pass class_type instead of typename_type to cp_parser_class_name in the nested-name-specifier case. gcc/testsuite/ChangeLog: * g++.dg/template/dependent-base6.C: Verify mem-initializer-id qualified name lookup is type-only too. Reported-by: Vincent X Reviewed-by: Jason Merrill <jason@redhat.com> (cherry picked from commit 97da8fece19caf0277c2be523520d09252821973)
(In reply to Patrick Palka from comment #11) > Fixed on trunk so far Now fixed for 15.3 too
If we decide to backport r16-4368 further we need to do so along with the PR122752 fix r16-6141.