[cfe-dev] More Vexing Than the Most Vexing Parse; Clang Parser Bug?

John McCall rjmccall at apple.com
Tue Jul 10 20:14:43 PDT 2012


On Jul 10, 2012, at 7:07 PM, Seth Cantrell wrote:
> I'm trying to figure out against whom to file a bug.
> 
> This code is parsed differently between Clang, VC++, Comeau, and GCC.
> 
> struct A {
>    A() {}
>    A(int) {}
> };
> 
> struct B : A {
>    void init(int i);
> };
> 
> void B::init(int i) {
>  {
>    A::A(i); // what is this supposed to parse as?
>  }
> }
> 
> int main() {
>    B b;
>    b.init(2);
> }
> 
> Clang and an earlier version of GCC parse it a variable declaration, Comeau and current gcc parse it as an illegal constructor call (but since it's illegal is that constructor really "an acceptable lookup result" according to ยง3.4.3.1/2?), and VC++ seems to parse it as constructing a temporary (which it seems hard to fathom how because if A::A is a constructor name then it's not legal to call and does not 'return' a temporary object, but if A::A is a type name then this is a variable declaration).  

The standard doesn't precisely define "acceptable lookup result", but I think (given the example in the immediate context of an elaborated-type-specifier) that an acceptable lookup result is one which is not ignored by the kind of lookup being performed.  That means that A::A would also be legal as a base class specifier.  I believe it would not be legal as a base-or-member-initializer.

So the answer is that it's definitely ill-formed, because [class.qual]p2 says that A::A must name a constructor, but that doing so is only legal in a constructor declaration or a using declaration.  It's not really an ill-formed function-style cast *or* an ill-formed variable declaration, because both must start with a type name, and a constructor reference is not a type name.  So it's not anything at all;  it's just ill-formed.

clang is just failing to apply the rule that this is really a reference to the constructor.  In fact, I'm not sure we implement that rule at all.  Therefore, we're interpreting this as a type name and accepting it as a variable declaration, which is then invalid because you can't redeclare a parameter name in the outermost scope of a function.

VC++ is failing to apply the rule *and* failing to disambiguate correctly.  IIRC, VC++ has a lot of problems with injected class names.

GCC and Comeau seem to be correct.

John.



More information about the cfe-dev mailing list