void f(int x) {
int (x), 1;
}
Clang compiles it, GCC doesn't. Which compiler is correct?
void f(int x) {
int (x), 1;
}
Clang compiles it, GCC doesn't. Which compiler is correct?
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 typeLattice
and taking three arguments. The type of the first two arguments isPoint
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.
© 2022 - 2024 — McMap. All rights reserved.
x
shadows the argumentx
. As far as I know, while this is a bad idea, it's allowed. – Washkoint x, <other declarations>
. And you are allowed extraneous parentheses in declarations – Nigelnigervoid 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 case – NigelnigerAmbiguity resolution
section – Ginelleint(x), 1
which is effectively((int) x), 1
– Nigelnigerstmt.ambig
. I've read this section three times, but still undecided. Maybe I need to re-read several times – Nonbelligerent