Hi,
On 19/05/2018 01:40, Jason Merrill wrote:
On Fri, May 18, 2018 at 1:40 PM, Paolo Carlini <paolo.carl...@oracle.com> wrote:
Hi again,
I'm playing with a wild, wild idea: would it make sense to try *first* an
expression? Because, a quickly hacked draft appears to handle very elegantly
all the possible cases of "junk" after the declarator, eg:
void foo()
{
if (void bar()JUNK);
}
and the parenthesized case, etc, etc. Before trying to seriously work on
that I wanted to ask...
We'd need to try parsing as a declaration whether or not parsing as an
expression works, since any ambiguous cases are treated as
declarations [stmt.ambig].
Yeah, that complicates the implementation of my idea. However, I'm
thinking that at least *in the specific case of cp_parse_condition* from
the computational complexity point of view probably we wouldn't regress
much, because declarations are rare anyway, thus in most of the cases we
end up doing both anyway. If we do expressions first and we save the
result, then I believe when we can handle the declarator as something
which cannot be a function or an array even if we don't see the
initializer much more easily, we easily have a better diagnostic for
things like
if (int x);
(another case we currently handle pretty badly, we don't talk about the
missing initializer at all!), we cope elegantly with any junk following
the wrong function/array declaration, etc. See that attached, if you are
curious, which essentially passes the testsuite modulo a nit (*) which
doesn't have anything to do with [stmt.ambig] per se (which of course is
*not* correctly implemented in the wip).
Can you give me your opinion about the more detailed idea, in particular
whether we already have good infrastructure to implement [stmt.ambig] in
this context, thus to keep the first parsing as an expression around,
possibly returning to it if the parsing as a declaration fails??
I hope I'm making sense, it's again late here... in any case the wip
patch I did much earlier today ;)
Paolo.
(*) Has to do with David's access failure hint not handling deferred
access checks (accessor-fixits-6.C).
Index: parser.c
===================================================================
--- parser.c (revision 260347)
+++ parser.c (working copy)
@@ -11527,6 +11527,33 @@ cp_parser_selection_statement (cp_parser* parser,
}
}
+/* Helper function for cp_parser_condition. Enforces [stmt.stmt]/2:
+ The declarator shall not specify a function or an array. Returns
+ TRUE if the declarator is valid, FALSE otherwise. */
+
+static bool
+cp_parser_check_condition_declarator (cp_parser* parser,
+ cp_declarator *declarator,
+ location_t loc)
+{
+ if (function_declarator_p (declarator)
+ || declarator->kind == cdk_array)
+ {
+ if (declarator->kind == cdk_array)
+ error_at (loc, "condition declares an array");
+ else
+ error_at (loc, "condition declares a function");
+ if (parser->fully_implicit_function_template_p)
+ abort_fully_implicit_template (parser);
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/false);
+ return false;
+ }
+ else
+ return true;
+}
+
/* Parse a condition.
condition:
@@ -11545,12 +11572,20 @@ cp_parser_selection_statement (cp_parser* parser,
static tree
cp_parser_condition (cp_parser* parser)
{
+ cp_parser_parse_tentatively (parser);
+
+ /* Try the expression first. */
+ tree expr = cp_parser_expression (parser);
+
+ if (cp_parser_parse_definitely (parser))
+ return expr;
+
+ cp_parser_parse_tentatively (parser);
+
cp_decl_specifier_seq type_specifiers;
const char *saved_message;
int declares_class_or_enum;
- /* Try the declaration first. */
- cp_parser_parse_tentatively (parser);
/* New types are not allowed in the type-specifier-seq for a
condition. */
saved_message = parser->type_definition_forbidden_message;
@@ -11563,6 +11598,7 @@ cp_parser_condition (cp_parser* parser)
&declares_class_or_enum);
/* Restore the saved message. */
parser->type_definition_forbidden_message = saved_message;
+
/* If all is well, we might be looking at a declaration. */
if (!cp_parser_error_occurred (parser))
{
@@ -11570,7 +11606,8 @@ cp_parser_condition (cp_parser* parser)
tree asm_specification;
tree attributes;
cp_declarator *declarator;
- tree initializer = NULL_TREE;
+ tree initializer;
+ location_t loc = cp_lexer_peek_token (parser->lexer)->location;
/* Parse the declarator. */
declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
@@ -11582,19 +11619,7 @@ cp_parser_condition (cp_parser* parser)
attributes = cp_parser_attributes_opt (parser);
/* Parse the asm-specification. */
asm_specification = cp_parser_asm_specification_opt (parser);
- /* If the next token is not an `=' or '{', then we might still be
- looking at an expression. For example:
- if (A(a).x)
-
- looks like a decl-specifier-seq and a declarator -- but then
- there is no `=', so this is an expression. */
- if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ)
- && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
- cp_parser_simulate_error (parser);
-
- /* If we did see an `=' or '{', then we are looking at a declaration
- for sure. */
if (cp_parser_parse_definitely (parser))
{
tree pushed_scope;
@@ -11601,6 +11626,9 @@ cp_parser_condition (cp_parser* parser)
bool non_constant_p;
int flags = LOOKUP_ONLYCONVERTING;
+ if (!cp_parser_check_condition_declarator (parser, declarator, loc))
+ return error_mark_node;
+
/* Create the declaration. */
decl = start_decl (declarator, &type_specifiers,
/*initialized_p=*/true,
@@ -11614,12 +11642,18 @@ cp_parser_condition (cp_parser* parser)
CONSTRUCTOR_IS_DIRECT_INIT (initializer) = 1;
flags = 0;
}
- else
+ else if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
{
/* Consume the `='. */
cp_parser_require (parser, CPP_EQ, RT_EQ);
- initializer = cp_parser_initializer_clause (parser,
&non_constant_p);
+ initializer = cp_parser_initializer_clause (parser,
+ &non_constant_p);
}
+ else
+ {
+ cp_parser_error (parser, "expected initializer");
+ initializer = error_mark_node;
+ }
if (BRACE_ENCLOSED_INITIALIZER_P (initializer))
maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
@@ -11640,8 +11674,8 @@ cp_parser_condition (cp_parser* parser)
else
cp_parser_abort_tentative_parse (parser);
- /* Otherwise, we are looking at an expression. */
- return cp_parser_expression (parser);
+ cp_parser_error (parser, "expected condition");
+ return error_mark_node;
}
/* Parses a for-statement or range-for-statement until the closing ')',