This bug is an example of the (in)famous C++ grammar ambiguity
involving expression-statements and declarations. The ambiguity is
between function-style explicit type conversions (i.e., casts) and
declarations.
In general, backtracking (and infinite lookahead) are needed
to resolve those ambiguities (see section 6.8, pp. 93-94 of ARM for
more details).
Backtracking is not an easy thing to do with a yacc parser and the
yacc-based C++ parsers that I know and that can do it accomplish it
by doing a recursive-descent parse (with backtracking) right in the
lexer.
Needless to say, our current parser does not. An interesting bit of
trivia (that I was actually not aware of until now) is that our
parser picks one of the two possibilities in a quite "creative" way.
Here's what I mean:
int i = int(1.2); // can't do this because for built-in types
// the declaration is always picked,
//function-style casts are not allowed
foo(int(*fp)(int)); //fine
class A{
public:
A(double){}
};
A a = A(1.2); // fine, for user-defined types (that also
// includes typedefs) expression-statement is
// picked
//foo(A(*fp)(int)); // parse error
As for the reason for such non-uniform behavior, I suspect that it
has something to do with parsing pC++ (as opposed to plain C++), but
maybe Dennis (or Pete when he comes back from vacation) could confirm
that. Below is a relevant fragment of the y++.y file:
expr_no_commas:
/* basic_type_name '(' expr ')' /* my new rule. dbg */
/* { $$=installLowLevelNode(CAST_OP,$3,LLNULL,SMNULL);
NODE_TYPE($$) = map_rid_to_type($1);
}
REMOVED by PHB, was causing '(' parmlist ')' problems */
THROW
{ $$=installLowLevelNode(THROW_OP,LLNULL,LLNULL,SMNULL);
}
| THROW expr_no_commas %prec UNARY
{ $$=installLowLevelNode(THROW_OP,$2,LLNULL,SMNULL);
}
/* the following will cause the same conflict that pete found */
/* that is, int foo(A (*f)()) will not parse correctly */
| TYPENAME '(' exprlist ')'
{ PTR_SYMB symb2;
PTR_TYPE type2;
PTR_LLND ll2;
if($3) ll2 = $3;
else ll2 =
installLowLevelNode(EXPR_LIST,LLNULL,LLNULL,SMNULL);
$$=installLowLevelNode(CAST_OP,ll2,LLNULL,SMNULL);
symb2= find_type_symbol($1,TYPE_NAME,area());
type2= (PTR_TYPE) newNode(T_DERIVED_TYPE);
TYPE_SYMB_DERIVE(type2) = (PTR_SYMB) symb2;
NODE_TYPE($$) = type2;
}
| TYPENAME '(' exprlist ')' '.' identifier
{
...
--Beata