More Vexing Than the Most Vexing Parse; Clang Parser Bug?

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) {
  {
  }
}

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).

I'm asking as a result of the discussion at http://stackoverflow.com/questions/11423380/why-are-redundant-class-name-qualifiers-allowed

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.

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.

Core issue 1310 covers this unfortunately-unclear wording. One problem with the current statement of the rule is that we must perform two different kinds of lookup: we must look A::A up as a simple-type-specifier in case it’s a decl-specifier, and we must look it up as a qualified-id in case there is no decl-specifier-seq. For the former lookup, a constructor is (presumably) not an acceptable lookup result, but core issue 147 strongly suggests that the intention was that the lookup should find the constructor anyway for that case.

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.

We do: look for err_out_of_line_type_names_constructor. It seems that whoever implemented that interpreted “constructor is an acceptable lookup result” as meaning “appears somewhere a constructor could be declared”. We reject this, for instance:

struct S {}; S::S(i);

     > 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?
    <http://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.

One problem

with the current statement of the rule is that we must perform two
different kinds of lookup: we must look A::A up as a
simple-type-specifier in case it's a decl-specifier, and we must look it
up as a qualified-id in case there is no decl-specifier-seq.

Why do we must perform two different kinds of lookup? As far as I can see, "A::A" can never be a decl-specifier.

Only for the current approach of clang, I can imagine such a complication.

For the

former lookup, a constructor is (presumably) not an acceptable lookup
result, but core issue 147 strongly suggests that the intention was that
the lookup should find the constructor anyway for that case.

Not only core issue 147, but the direct in-committee response does so :slight_smile:

    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.

We do: look for err_out_of_line_type_names_constructor. It seems that
whoever implemented that interpreted "constructor is an acceptable
lookup result" as meaning "appears somewhere a constructor could be
declared". We reject this, for instance:

struct S {}; S::S(i);

There has been a PR open for this. See http://llvm.org/bugs/show_bug.cgi?id=8263