Hi again,
On 19/05/2018 15:30, Jason Merrill wrote:
How about doing cp_parser_commit_to_tentative_parse if we see
something that must be a declaration? cp_parser_simple_declaration
has
/* If we have seen at least one decl-specifier, and the next token
is not a parenthesis, then we must be looking at a declaration.
(After "int (" we might be looking at a functional cast.) */
if (decl_specifiers.any_specifiers_p
&& cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN)
&& cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)
&& !cp_parser_error_occurred (parser))
cp_parser_commit_to_tentative_parse (parser);
That seems useful here, as well. Maybe factored into a separate function.
The below implements this new idea, which indeed appears to work well: I
tested it and testsuite-wise seems essentially equivalent to what I
posted yesterday, besides a slightly worse error-recovery for the first
issue in cpp1z/decomp16.C: an additional 'no match for ‘operator=’' error.
Thanks!
Paolo.
//////////////////
Index: cp/parser.c
===================================================================
--- cp/parser.c (revision 260402)
+++ cp/parser.c (working copy)
@@ -11527,6 +11527,53 @@ cp_parser_selection_statement (cp_parser* parser,
}
}
+/* Helper function for cp_parser_condition and cp_parser_simple_declaration.
+ If we have seen at least one decl-specifier, and the next token
+ is not a parenthesis, then we must be looking at a declaration.
+ (After "int (" we might be looking at a functional cast.) */
+
+static bool
+cp_parser_maybe_commit_to_declaration (cp_parser* parser,
+ bool any_specifiers_p)
+{
+ if (any_specifiers_p
+ && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN)
+ && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)
+ && !cp_parser_error_occurred (parser))
+ {
+ cp_parser_commit_to_tentative_parse (parser);
+ return true;
+ }
+ return false;
+}
+
+/* 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:
@@ -11563,6 +11610,10 @@ cp_parser_condition (cp_parser* parser)
&declares_class_or_enum);
/* Restore the saved message. */
parser->type_definition_forbidden_message = saved_message;
+
+ cp_parser_maybe_commit_to_declaration (parser,
+ type_specifiers.any_specifiers_p);
+
/* If all is well, we might be looking at a declaration. */
if (!cp_parser_error_occurred (parser))
{
@@ -11571,6 +11622,7 @@ cp_parser_condition (cp_parser* parser)
tree attributes;
cp_declarator *declarator;
tree initializer = NULL_TREE;
+ location_t loc = cp_lexer_peek_token (parser->lexer)->location;
/* Parse the declarator. */
declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
@@ -11601,6 +11653,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 +11669,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);
+ cp_lexer_consume_token (parser->lexer);
+ 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);
@@ -12936,14 +12997,8 @@ cp_parser_simple_declaration (cp_parser* parser,
goto done;
}
- /* If we have seen at least one decl-specifier, and the next token
- is not a parenthesis, then we must be looking at a declaration.
- (After "int (" we might be looking at a functional cast.) */
- if (decl_specifiers.any_specifiers_p
- && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN)
- && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)
- && !cp_parser_error_occurred (parser))
- cp_parser_commit_to_tentative_parse (parser);
+ cp_parser_maybe_commit_to_declaration (parser,
+ decl_specifiers.any_specifiers_p);
/* Look for C++17 decomposition declaration. */
for (size_t n = 1; ; n++)
Index: testsuite/g++.dg/cpp0x/cond1.C
===================================================================
--- testsuite/g++.dg/cpp0x/cond1.C (nonexistent)
+++ testsuite/g++.dg/cpp0x/cond1.C (working copy)
@@ -0,0 +1,17 @@
+// PR c++/84588
+// { dg-do compile { target c++11 } }
+
+void foo()
+{
+ if (int bar() {}); // { dg-error "condition declares a function" }
+
+ for (;int bar() {};); // { dg-error "condition declares a function" }
+
+ while (int bar() {}); // { dg-error "condition declares a function" }
+
+ if (int a[] {}); // { dg-error "condition declares an array" }
+
+ for (;int a[] {};); // { dg-error "condition declares an array" }
+
+ while (int a[] {}); // { dg-error "condition declares an array" }
+}
Index: testsuite/g++.dg/cpp1y/pr84588-1.C
===================================================================
--- testsuite/g++.dg/cpp1y/pr84588-1.C (nonexistent)
+++ testsuite/g++.dg/cpp1y/pr84588-1.C (working copy)
@@ -0,0 +1,25 @@
+// { dg-do compile { target c++14 } }
+
+struct a {
+ void b() {}
+ void c(void (*) () = [] {
+ if (a a(int auto) {}) // { dg-error "two or more data types|condition
declares a function" }
+ ;
+ }) {}
+};
+
+struct d {
+ void e() {}
+ void f(void (*) () = [] {
+ for (;d d(int auto) {};) // { dg-error "two or more data
types|condition declares a function" }
+ ;
+ }) {}
+};
+
+struct g {
+ void h() {}
+ void i(void (*) () = [] {
+ while (g g(int auto) {}) // { dg-error "two or more data
types|condition declares a function" }
+ ;
+ }) {}
+};
Index: testsuite/g++.dg/cpp1y/pr84588-2.C
===================================================================
--- testsuite/g++.dg/cpp1y/pr84588-2.C (nonexistent)
+++ testsuite/g++.dg/cpp1y/pr84588-2.C (working copy)
@@ -0,0 +1,25 @@
+// { dg-do compile { target c++14 } }
+
+struct a {
+ void b() {}
+ void c(void (*) () = [] {
+ if (a a(int auto)) // { dg-error "two or more data types|condition
declares a function" }
+ ;
+ }) {}
+};
+
+struct d {
+ void e() {}
+ void f(void (*) () = [] {
+ for (;d d(int auto);) // { dg-error "two or more data types|condition
declares a function" }
+ ;
+ }) {}
+};
+
+struct g {
+ void h() {}
+ void i(void (*) () = [] {
+ while (g g(int auto)) // { dg-error "two or more data types|condition
declares a function" }
+ ;
+ }) {}
+};
Index: testsuite/g++.dg/cpp1y/pr84588-3.C
===================================================================
--- testsuite/g++.dg/cpp1y/pr84588-3.C (nonexistent)
+++ testsuite/g++.dg/cpp1y/pr84588-3.C (working copy)
@@ -0,0 +1,25 @@
+// { dg-do compile { target c++14 } }
+
+struct a {
+ void b() {}
+ void c(void (*) () = [] {
+ if (a a(int auto)JUNK) // { dg-error "two or more data types|condition
declares a function" }
+ ;
+ }) {}
+};
+
+struct d {
+ void e() {}
+ void f(void (*) () = [] {
+ for (;d d(int auto)JUNK;) // { dg-error "two or more data
types|condition declares a function" }
+ ;
+ }) {}
+};
+
+struct g {
+ void h() {}
+ void i(void (*) () = [] {
+ while (g g(int auto)JUNK) // { dg-error "two or more data
types|condition declares a function" }
+ ;
+ }) {}
+};
Index: testsuite/g++.dg/cpp1z/decomp16.C
===================================================================
--- testsuite/g++.dg/cpp1z/decomp16.C (revision 260402)
+++ testsuite/g++.dg/cpp1z/decomp16.C (working copy)
@@ -8,7 +8,7 @@ void
foo ()
{
auto [ a, b ] = A ();
- for (; auto [ a, b ] = A (); ) // { dg-error
"expected" }
+ for (; auto [ a, b ] = A (); ) // { dg-error
"expected|no match" }
;
for (; false; auto [ a, b ] = A ()) // { dg-error
"expected" }
;
Index: testsuite/g++.dg/parse/cond6.C
===================================================================
--- testsuite/g++.dg/parse/cond6.C (nonexistent)
+++ testsuite/g++.dg/parse/cond6.C (working copy)
@@ -0,0 +1,16 @@
+// PR c++/84588
+
+void foo()
+{
+ if (int bar()); // { dg-error "condition declares a function" }
+
+ for (;int bar();); // { dg-error "condition declares a function" }
+
+ while (int bar()); // { dg-error "condition declares a function" }
+
+ if (int a[]); // { dg-error "condition declares an array" }
+
+ for (;int a[];); // { dg-error "condition declares an array" }
+
+ while (int a[]); // { dg-error "condition declares an array" }
+}
Index: testsuite/g++.dg/parse/cond7.C
===================================================================
--- testsuite/g++.dg/parse/cond7.C (nonexistent)
+++ testsuite/g++.dg/parse/cond7.C (working copy)
@@ -0,0 +1,18 @@
+// PR c++/84588
+
+bool (bar()) { return 0; } // declaration
+
+void foo1()
+{
+ if (bool (bar())); // expression
+}
+
+void foo2()
+{
+ for (;bool (bar());); // expression
+}
+
+void foo3()
+{
+ while (bool (bar())); // expression
+}
Index: testsuite/g++.dg/parse/cond8.C
===================================================================
--- testsuite/g++.dg/parse/cond8.C (nonexistent)
+++ testsuite/g++.dg/parse/cond8.C (working copy)
@@ -0,0 +1,10 @@
+// PR c++/84588
+
+void foo()
+{
+ if (int x); // { dg-error "expected initializer" }
+
+ for (;int x;); // { dg-error "expected initializer" }
+
+ while (int x); // { dg-error "expected initializer" }
+}
Index: testsuite/g++.old-deja/g++.jason/cond.C
===================================================================
--- testsuite/g++.old-deja/g++.jason/cond.C (revision 260402)
+++ testsuite/g++.old-deja/g++.jason/cond.C (working copy)
@@ -47,11 +47,10 @@ int main()
if (struct B * foo = new B)
;
- if (int f () = 1) // { dg-warning "extern" "extern" }
- // { dg-error "is initialized like a variable" "var" { target *-*-* } .-1 }
+ if (int f () = 1) // { dg-error "declares a function" }
;
- if (int a[2] = {1, 2}) // { dg-error "extended init" "" { target { !
c++11 } } }
+ if (int a[2] = {1, 2}) // { dg-error "declares an array" }
;
}