Is "int (x), 1;" an ambiguous statement?
Asked Answered
N

1

15
void f(int x) {
    int (x), 1;
}

Clang compiles it, GCC doesn't. Which compiler is correct?

Nonbelligerent answered 8/11, 2017 at 22:10 Comment(13)
Well, I guess it shouldn't.Lani
You always have interesting questions.Passover
Looks correct. But what is the point?Brandybrandyn
Wouldn't this error because it has no entry point defined?Quean
I see no reason why this shouldn't compile. What error does gcc produce? Edit : It appears to complain that local x shadows the argument x. As far as I know, while this is a bad idea, it's allowed.Washko
@FrançoisAndrieux This looks a lot like a declaration of int x, <other declarations>. And you are allowed extraneous parentheses in declarationsNigelniger
@Quean Having a void f() { ... } has no problem compiling. If there's no main function anywhere, that will be a linker error. But compiling code that doesn't contain a main function is actually the common caseNigelniger
Similar to g++ rejects, clang++ accepts: foo(x)(“bar”)(“baz”); ... this looks like it should be addressed by Ambiguity resolution sectionGinelle
@FrançoisAndrieux: that's the point. Is that line a declaration, or an expression? Because I think clang compiles this, because it handles it as an expression.Nonbelligerent
Yeah it can also be seen as an expression: int(x), 1 which is effectively ((int) x), 1Nigelniger
@FrançoisAndrieux: You cannot redeclare a name within the same scope, only a nested scope.Passover
@RegisPortalez: this is a stripped down example, so it may seem pointless, but it is not.Nonbelligerent
@ShafikYaghmour: thanks, now I know where to look for answers: stmt.ambig. I've read this section three times, but still undecided. Maybe I need to re-read several timesNonbelligerent
U
18

IMO, the wording in [stmt.ambig] is clear enough on this:

An expression-statement with a function-style explicit type conversion as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a (. In those cases the statement is a declaration.

[Note: If the statement cannot syntactically be a declaration, there is no ambiguity, so this rule does not apply. The whole statement might need to be examined to determine whether this is the case.

The wording speaks of an entire (expression-)statement. Your statement cannot be parsed as a declaration, because the lexeme 1 is grammatically not a declarator. There is no ambiguity: it might look ambiguous if we looked solely at int(x), but the standard quite explicitly denies that if some prefix of the statement parses as a declaration, the entire statement is considered a potential declaration.

In fact, core experts had a highly similar discussion back in 2002 over core issue 340---I highlighted the important bits. Here, again, we have a supposed declaration that contains an incompatible sub-construct.

Consider the following program:

struct Point   {
  Point(int){}   
};
struct Lattice    {
  Lattice(Point, Point, int){}   
};
int main(void)   {
  int a, b;
  Lattice latt(Point(a), Point(b), 3);   /* Line X */   
} 

The problem concerns the line marked /* Line X */, which is an ambiguous declarations for either an object or a function. The clause that governs this ambiguity is 8.2 [dcl.ambig.res] paragraph 1, and reads:

The ambiguity arising from the similarity between a function-style cast and a declaration mentioned in 6.8 [stmt.ambig] [..]

Based on this clause there are two possible interpretations of the declaration in line X:

  • The declaration of latt declares a function with a return value of the type Lattice and taking three arguments. The type of the first two arguments is Point and each of these arguments is followed by a parameter name in redundant parentheses. The type of the third argument can not be determined, because it is a literal. This will result in a syntax error.
  • The declaration of latt declares an object, because the other option (a function declaration) would result in a syntax error. Note that the last sentence before the "[Note:" is not much help, because both options are declarations.

Steve Adamczyk: a number of people replied to this posting on comp.std.c++ saying that they did not see a problem.

The original poster replied:

I can't do anything but agree with your argumentation. So there is only one correct interpretation of clause 8.2 [dcl.ambig.res] paragraph 1, but I have to say that with some rewording, the clause can be made a lot clearer, like stating explicitly that the entire declaration must be taken into account and that function declarations are preferred over object declarations.

I would like to suggest the following as replacement for the current clause 8.2 [dcl.ambig.res] paragraph 1:

The ambiguity arising from the similarity between a functionstyle cast and a declaration mentioned in 6.8 [stmt.ambig] […]

The working group felt that the current wording is clear enough.

Unspotted answered 8/11, 2017 at 23:57 Comment(1)
Thanks for the answer! Now it's clear that clang is right. But, in my opinion, current wording should be improved. Because, it states at the end of 1: "In those cases the statement is a declaration." Then, the note tells, that this statement is not really always true, but only in the case when the statement can be syntactically a declaration. This can be a little bit confusing. End of 1 should read something like "In those cases, when the whole statement can be a syntactically correct declaration, then it is a declaration"Nonbelligerent

© 2022 - 2024 — McMap. All rights reserved.