Ambiguous name lookup with C++20 using-enum-declaration
Asked Answered
S

2

5

Consider following code snippet with C++20 using-enum-declaration:

namespace A { enum A {}; };

using namespace A;
using enum A;

gcc-trunk rejects it with:

<source>:4:12: error: reference to 'A' is ambiguous
    4 | using enum A;
      |            ^
<source>:1:20: note: candidates are: 'enum A::A'
    1 | namespace A { enum A {}; };
      |                    ^
<source>:1:11: note:                 'namespace A { }'
    1 | namespace A { enum A {}; };
      |           ^
<source>:4:12: error: 'A' has not been declared
    4 | using enum A;
      |            ^

However, msvc accepts it. Interestingly, if I add a namespace qualifier for enum A:

namespace A { enum A {}; };

using namespace A;
using enum A::A;

gcc accepts it this time, but msvc rejects it with:

<source>(4): error C2872: 'A': ambiguous symbol
<source>(1): note: could be 'A'
<source>(1): note: or       'A::A'

Which compiler is right?

Siriasis answered 14/4, 2021 at 17:38 Comment(0)
P
5

gcc is wrong here (submitted 100'084).

The grammar for using enum A; is from [enum.udecl]:

using-enum-declaration:

    using elaborated-enum-specifier ;

Lookup for such a thing is defined in [basic.lookup.elab]:

If the class-key or enum keyword in an elaborated-type-specifier is followed by an identifier that is not followed by ​::​, lookup for the identifier is type-only ([basic.lookup.general]).

An elaborated-enum-specifier is one kind of elaborated-type-specifier, so we do type-only lookup. Which is defined as, in [basic.lookup.general]/4:

However, if a lookup is type-only, only declarations of types and templates whose specializations are types are considered; furthermore, if declarations of a typedef-name and of the type to which it refers are found, the declaration of the typedef-name is discarded instead of the type declaration.

This means that when we look up A, while we find both the enum A and the namespace A, because our lookup is type-only we only consider the former and not the latter. As a result, we only have a single candidate and that's the one our lookup finds. There is no ambiguity.

Plexiglas answered 14/4, 2021 at 18:2 Comment(0)
C
5

MSVC is correct here. The first case is a type-only lookup (as it’s considered an elaborated type specifier), so it ignores the namespace and finds the enumeration via the using-directive. In the second case, the following :: allows namespaces to be found, so it’s ambiguous.

Clanton answered 14/4, 2021 at 18:5 Comment(3)
Wait the second case is supposed to be ambiguous? I love this language. I thought it was so "obvious" that MSVC was wrong for the second one that I didn't even write that...Plexiglas
@Plexiglas gcc seems to have this issue a long time ago.Huonghupeh
@Barry: You can do qualified lookup into any enumeration. The fact that you can’t possibly find there an entity that would be a valid subject for an elaborated-type-specifier isn’t considered, as per usual.Clanton

© 2022 - 2024 — McMap. All rights reserved.