3

Code example:

struct A {};
struct B { using A = A; };

int main()
{
    B b;
}

Clang compiles it. But GCC gives the following error (demo):

declaration of 'using A = struct A' changes meaning of 'A'

The C++ standard says:

If a class name ([class.name]) or enumeration name ([dcl.enum]) and a variable, data member, function, or enumerator are declared in the same declarative region (in any order) with the same name (excluding declarations made visible via using-directives ([basic.lookup.unqual])), the class or enumeration name is hidden wherever the variable, data member, function, or enumerator name is visible.

UPD.0: thanks to Vlad from Moscow

A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in the completed scope of S. No diagnostic is required for a violation of this rule

Does that mean that GCC behavior is incorrect? Thanks!

isnullxbh
  • 807
  • 13
  • 20
  • Your quote is about a *"variable, data member, function, or enumerator"* hiding a class name, which is not the case here, so you probably need to look elsewhere in the standard. And the *"using-directives"* here seems to refer to `using namespace`: http://eel.is/c++draft/namespace.udir#nt:using-directive – Holt Apr 27 '20 at 09:22
  • @Holt, thanks for the answer, but the link you provided relates only to namespaces. – isnullxbh Apr 27 '20 at 09:32
  • Read my comment entirely, not just the link... My point was that your quote of the standard is irrelevant here for the two reasons: 1) it does not contain anything about class names hiding other class names, 2) the *using-directives* refers to namespaces, and not `using =` which are named differently by the standard: http://eel.is/c++draft/dcl.typedef The keyword `using` is used in 3 different situations in C++, so you have to be careful when looking up the standard for stuff related to `using`. – Holt Apr 27 '20 at 09:35
  • @Holt, ok, I got it. Thanks for the explanation! I will edit the question of how I will find the necessary paras in the C ++ standard. – isnullxbh Apr 27 '20 at 09:41
  • @LanguageLawyer, yes, thanks, it seems that is the same question. – isnullxbh Apr 27 '20 at 10:48
  • If you need a workaround, `struct B { using A = ::A; };` – Eljay Apr 27 '20 at 13:03

1 Answers1

3

It seems that it is a bug of gcc. According to the C++ 20 Standard (6.3.7 Class scope)

2 A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in the completed scope of S. No diagnostic is required for a violation of this rule.

In this case

struct A {};
struct B { using A = A; };

the name B::A refers to the same declaration of struct A.

Here is an example from the C++ Standard that shows the meaning of the quote.

typedef char* T;
struct Y {
   T a; // error: T refers to ::T but when reevaluated is Y::T
   typedef long T;
   T b;
};
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • That's also my conclusion. Some more evidences: 1) `using A = A;` works perfectly fine outside of `struct B`, 2) `using A2 = A;` before `struct B` and then `using A = A2;` in `struct B` also works (so it's not a problem of hiding the name `A`), 3) `std::is_same_v` is true in `struct B` (so it's not a problem of `A` not being what it looks like). – Holt Apr 27 '20 at 09:52
  • is reevaluating `using A = A;` correct? and not evaluating to `using A = B::A;`? – Jarod42 Apr 27 '20 at 09:57
  • 2
    Note that the error comment in the example doesn't say that `T` refers to different type when reevaluated, but means different **declaration** – Language Lawyer Apr 27 '20 at 10:58