Bug 122192 - [13/14 Regression] Lookup for a dependent nested type as a base-specifier should be type-only
Summary: [13/14 Regression] Lookup for a dependent nested type as a base-specifier sho...
Status: ASSIGNED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 15.2.0
: P3 normal
Target Milestone: 13.5
Assignee: Patrick Palka
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2025-10-07 15:57 UTC by Vincent X
Modified: 2025-12-16 15:41 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work: 12.5.0
Known to fail: 13.1.0
Last reconfirmed: 2025-10-08 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Vincent X 2025-10-07 15:57:08 UTC
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>;
Comment 1 Andrew Pinski 2025-10-07 17:15:36 UTC
Reading the commit message for r13-6098-g46711ff8e60d64b7e5550f (the change most likely which introduced the difference), makes me think GCC 13+ is correct here.
Comment 2 Andrew Pinski 2025-10-07 17:19:00 UTC
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 ***
Comment 3 Patrick Palka 2025-10-07 19:20:04 UTC
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?
Comment 4 Vincent X 2025-10-08 02:57:44 UTC
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.
Comment 5 Patrick Palka 2025-10-08 13:25:58 UTC
reopening
Comment 6 Jason Merrill 2025-10-08 15:22:23 UTC
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.
Comment 7 Andrew Pinski 2025-10-08 15:48:44 UTC
.
Comment 8 Vincent X 2025-10-09 03:23:37 UTC
(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.
Comment 9 Patrick Palka 2025-10-09 12:57:51 UTC
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.
Comment 10 GCC Commits 2025-10-10 14:26:08 UTC
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>
Comment 11 Patrick Palka 2025-10-10 14:26:28 UTC
Fixed on trunk so far
Comment 12 Vincent X 2025-10-11 07:33:18 UTC
(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.
Comment 13 Patrick Palka 2025-10-11 14:22:40 UTC
Good catch, will fix
Comment 14 GCC Commits 2025-10-14 16:57:49 UTC
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>
Comment 15 GCC Commits 2025-10-28 14:35:51 UTC
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)
Comment 16 GCC Commits 2025-10-28 14:35:57 UTC
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)
Comment 17 Patrick Palka 2025-10-28 14:37:20 UTC
(In reply to Patrick Palka from comment #11)
> Fixed on trunk so far
Now fixed for 15.3 too
Comment 18 Patrick Palka 2025-12-16 15:41:12 UTC
If we decide to backport r16-4368 further we need to do so along with the PR122752 fix r16-6141.