5

Is the following program well-formed according to the c++ standard?

namespace X { class A; }

namespace Y { using X::A; class A {}; }

int main() {}

I'm getting different results with different compilers:

  • gcc compiles it without errors.
  • visual c++ gives error C2888: 'X::A': symbol cannot be defined within namespace 'Y'

I don't find any rule in the c++ standard that my program violates.

If the program is well-formed, why does visual studio give an error?

If the program is not well-formed, what rule in the c++ standard did it violate and why doesn't gcc give an error?

I'm not trying to make my program compile. I'm just trying to find out if it is well-formed according to the c++ standard and why the two compilers I tested behave differently.

Supremum
  • 542
  • 7
  • 23
  • The question title is confusing. `X::A` and `Y::A` are two different types; there is no "forward declaration and later definition" happening. – Kerrek SB Jul 04 '15 at 11:43
  • Thanks for the suggestion. I have changed the title now. – Supremum Jul 04 '15 at 12:02
  • Did you try `using ::X::A`? – bweber Jul 04 '15 at 12:09
  • The interesting question is whether you can define `X::A a;`. This should be ill-formed since `X::A` is incomplete. It is possible that GCC is in error here by identifying the definition of `Y::A` with that of `X::A`. Clang rejects that code. – Kerrek SB Jul 04 '15 at 12:17
  • 1
    It gets even more interesting if you also add `enum A { FOO };` into namespace `Y`. Now Clang compiles it, and GCC complains that `A` was previously declared. – Kerrek SB Jul 04 '15 at 12:23
  • Karrek SB: Interesting. This seem to suggest that what the compiler disagree about in this case is if class A; and class A {}; declares two independent entities or if the former is just a forward declaration of the latter. Is this an ambiguity in the standard or a compiler bug? – Supremum Jul 04 '15 at 12:41
  • @Supremum: I'm not sure. I think the standard is clear about this, but it's surprising that two large compilers would get it wrong in two different ways, so maybe I don't read the standard properly. I'm waiting for someone to offer a dissenting answer. – Kerrek SB Jul 04 '15 at 17:24
  • @Karrek SB: Yes I think you are right about that. I don't see anything in the standard allowing redeclaration via a using-declaration. They seem to be opaque in that respect. But it would be good if someone could confirm that. – Supremum Jul 04 '15 at 18:16
  • @Karrek SB: By using the global namespace instead of the namespace X, we get a program that, if you are correct, is i'll formed but compiles on at least three large compilers: gcc, clang ( http://melpon.org/wandbox/permlink/VFwckBYpyhILFaJQ ) and visual c++ ( http://webcompiler.cloudapp.net ). – Supremum Jul 04 '15 at 18:44
  • 1
    Report it to GCC, too :-) – Kerrek SB Jul 06 '15 at 10:48
  • Yes, I will, I just wanted it to be confirmed for clang first. – Supremum Jul 06 '15 at 10:54
  • @Supremum: GCC maintainer says "someone needs to report it". Please report it :-) – Kerrek SB Jul 06 '15 at 14:51
  • Kerrek SB: I have reported a similar bug to gcc now: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66879 – Supremum Jul 15 '15 at 16:33
  • good job finding this. it is amazing how after 25 years of history, compilers can still get unclear results on such small programs. – v.oddou Jul 16 '15 at 02:09

2 Answers2

4

I believe the program is ill formed. [basic.scope.declarative]/4 says:

Given a set of declarations in a single declarative region, each of which specifies the same unqualified name,

— they shall all refer to the same entity, or all refer to functions and function templates; or

— exactly one declaration shall declare a class name or enumeration name that is not a typedef name and the other declarations shall all refer to the same variable or enumerator, or all refer to functions and function templates; in this case the class name or enumeration name is hidden

The two declarations of unqualified name A refer to different entities, both of which are classes.

(Interestingly, neither GCC 6.0 nor Clang 3.7 seem to diagnose it that way. Both accept the code as written (not diagnosing the declaration of two distinct classes with the same name). If you add X::A a; to the body of main, then Clang complains about the incomplete type of X::A.)

Community
  • 1
  • 1
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Aren't the declarations class A; and class A {} are in two different declarative regions? – Supremum Jul 04 '15 at 12:59
  • `using` is not a declaration – StenSoft Jul 04 '15 at 13:01
  • The declaration class A; is made in the declarative region { class A; } and the declaration class A {}; is made in the declarative region { using X::A; class A {}; }. – Supremum Jul 04 '15 at 13:07
  • using X::A; is also a declaration. Maybe you where referring to the two declarations using X::A; and class A {}; They are in the same declarative region, but are they really referring to different entities? Is the standard clear about weather or not class A {}; is a redeclaration of class A; ? – Supremum Jul 04 '15 at 13:19
  • Lets say this is a violation [basic.scope.declarative]/4. Isn't diagnostics required then? In that case this is a bug in GCC and Clang. – Supremum Jul 04 '15 at 14:02
  • @StenSoft: Indeed, `using` is not a declaration but a keyword. However, it can be part of a *using-declaration*, which is indeed a declaration. – Kerrek SB Jul 04 '15 at 17:27
  • I have reported this as a bug to clang: https://llvm.org/bugs/show_bug.cgi?id=24030 – Supremum Jul 05 '15 at 11:58
  • Your quoted text is the ODR ? – v.oddou Jul 16 '15 at 02:10
-2

Not too sure but you can try something like this :

namespace X { class A; }

namespace Y 
{
  class X::A {}; 
}

int main() 
{
  return 0;
}
Mohit Jain
  • 30,259
  • 8
  • 73
  • 100
SBNamikaze
  • 25
  • 5
  • The suggested program isn't well-formed according to the c++ standard (it's violating 7.3.1.2 p 2). See http://eel.is/c++draft/namespace.memdef#2 It doesn't compile on gcc and it doesn't compile on visual c++. Also i'm not trying to make my program compile. I'm just trying to find out if it is well-formed according to the c++ standard and why the two compilers i tested behave differently. – Supremum Jul 04 '15 at 12:22