22

Consider this code:

struct foo{};

int main() {
    foo::foo a;
}

I would expect this to be well-formed, declaring a variable of type foo by the rule in [class]/2 (N4140, emphasis mine):

A class-name is inserted into the scope in which it is declared immediately after the class-name is seen. The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name. For purposes of access checking, the injected-class-name is treated as if it were a public member name.

clang 3.6.0 agrees with me, compiling the above code with no applicable warnings with -Wall -pedantic.

gcc 5.2.0 disagrees, providing the following error message:

main.cpp: In function 'int main()':
main.cpp:5:5: error: 'foo::foo' names the constructor, not the type
   foo::foo a;

The above holds no matter how deep the nesting of injected class names, e.g. foo::foo::foo::foo.

Is there a rule which forces that construct to be interpreted as a constructor in that context, or is this agcc bug? Or am I interpreting the standards quote incorrectly?

TartanLlama
  • 63,752
  • 13
  • 157
  • 193
  • 3
    Clang has a number of bugs with its handling of injected-class-names. This is one of them. – T.C. Aug 14 '15 at 09:37
  • 1
    Very closely related: http://stackoverflow.com/questions/29681449/program-being-compiled-differently-in-3-major-c-compilers-which-one-is-right – T.C. Aug 14 '15 at 09:48

3 Answers3

13

It appears that clang is wrong in this case. The relevant exception I was looking for is in [class.qual]/2:

2 In a lookup in which function names are not ignored and the nested-name-specifier nominates a class C:

  • (2.1) if the name specified after the nested-name-specifier, when looked up in C, is the injected-class-name of C, or

  • [...]

the name is instead considered to name the constructor of class C.

The standard has a near-equivalent (non-normative, obviously) example:

struct A { A(); };
struct B: public A { B(); };

A::A() { }
B::B() { }

B::A ba;// object of type A
A::A a;// error, A::A is not a type name
struct A::A a2;// object of type A

However, clang actually issues a correct diagnostic in this case:

error: qualified reference to 'A' is a constructor name rather than a type wherever a constructor can be declared

Perhaps clang interprets the line In a lookup in which function names are not ignored as In a lookup in which a constructor declaration is valid, but that doesn't seem to be a correct interpretation.

There is an existing bug for this in the clang bugzilla.

TartanLlama
  • 63,752
  • 13
  • 157
  • 193
7

Relevant, but not an answer: The GCC people discussed exactly this for years and figured that it should not be accepted. They explicitly made this an error in GCC 4.5 and newer - in 4.4.7 it was accepted.

BTW: You probably want to use Clang's -Weverything instead of -Wall -pedantic when investigating such stuff.

rettichschnidi
  • 904
  • 7
  • 23
0

I think this is the subject of language defect #147 which contains this example

class B { };
class A: public B {
    A::B ab;       // B is the inherited injected B
    A::A aa;       // Error: A::A is the constructor
};

At least gcc seems to believe that. :-)

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
  • Ah, so the relevant exception is [class.qual]/2.2 and this is actually a bug in `clang`? – TartanLlama Aug 14 '15 at 09:23
  • I'm not sure. This example is using `A::A` inside a class, while your use is inside `main`. Could be different rules there. (I just had a weak memory about the rules having been changed, and looked up the defect report). – Bo Persson Aug 14 '15 at 09:26