On Thu, 26 Mar 2020, Jason Merrill wrote: > On 3/26/20 6:36 PM, Patrick Palka wrote: > > On Thu, 26 Mar 2020, Jason Merrill wrote: > > > > > On 3/26/20 5:28 PM, Patrick Palka wrote: > > > > This adds support to detect and recover from the case where an opening > > > > brace > > > > immediately follows the start of a requires-clause. So rather than > > > > emitting > > > > the > > > > error > > > > > > > > error: expected primary-expression before '{' token > > > > > > > > followed by a slew of irrevelant errors, we now assume the user had > > > > intended > > > > to > > > > write "requires requires {" and diagnose and recover accordingly. > > > > > > > > Tested on x86_64-pc-linux-gnu, does this look OK? > > > > > > > > gcc/cp/ChangeLog: > > > > > > > > PR c++/94306 > > > > * parser.c (cp_parser_requires_clause_opt): Diagnose and > > > > recover from > > > > "requires {" when "requires requires {" was probably intended. > > > > > > > > gcc/testsuite/ChangeLog: > > > > > > > > PR c++/94306 > > > > * g++.dg/concepts/diagnostic8.C: New test. > > > > --- > > > > gcc/cp/parser.c | 17 ++++++++++++++++- > > > > gcc/testsuite/g++.dg/concepts/diagnostic8.C | 6 ++++++ > > > > 2 files changed, 22 insertions(+), 1 deletion(-) > > > > create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic8.C > > > > > > > > diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c > > > > index 05363653691..73c2c2cb010 100644 > > > > --- a/gcc/cp/parser.c > > > > +++ b/gcc/cp/parser.c > > > > @@ -27639,7 +27639,22 @@ cp_parser_requires_clause_opt (cp_parser > > > > *parser, > > > > bool lambda_p) > > > > } > > > > return NULL_TREE; > > > > } > > > > - cp_lexer_consume_token (parser->lexer); > > > > + > > > > + cp_token *tok2 = cp_lexer_peek_nth_token (parser->lexer, 2); > > > > + if (tok2->type == CPP_OPEN_BRACE) > > > > > > Do we want to handle an open paren the same way? > > > > Hmm, wouldn't the error recovery be significantly different for an open > > paren here? Just pretending that there's another "requires" token would > > mean we proceed as if we got "requires requires (" but that is still > > ill-formed I think. > > Not ill-formed; a requires-expression can have a parameter-list.
Ah, of course.. But then again, wouldn't "requires (" be not necessarily ill-formed, since the open paren could possibly be a part of the constraint-expression e.g. "requires (a || b)"? We could perhaps look ahead of the open paren and check if we match the ill-formed pattern "requires (...) {...}" and if so, handle the open paren the same way. Oh, but even that pattern is not necessarily ill-formed, at least when parsing a lambda: the following "[] <typename T> () -> void requires (true) { }" is apparently a well-formed lambda-expression whose tokens starting from its requires-clause would match that pattern. So we would probably have to condition this open-paren handling on !lambda_p. > > > > > > > > + { > > > > + /* An opening brace following the start of a requires-clause is > > > > + ill-formed; the user likely forgot the second `requires' that > > > > + would start a requires-expression. */ > > > > + gcc_rich_location richloc (tok2->location); > > > > + richloc.add_fixit_insert_before (" requires"); > > > > + error_at (&richloc, "missing additional %<requires%> to start " > > > > + "a requires-expression"); > > > > + /* Don't consume the `requires', so that it's reused as the start > > > > of > > > > a > > > > + requires-expression. */ > > > > + } > > > > + else > > > > + cp_lexer_consume_token (parser->lexer); > > > > if (!flag_concepts_ts) > > > > return cp_parser_requires_clause_expression (parser, lambda_p); > > > > diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic8.C > > > > b/gcc/testsuite/g++.dg/concepts/diagnostic8.C > > > > new file mode 100644 > > > > index 00000000000..70d7e4a9cc1 > > > > --- /dev/null > > > > +++ b/gcc/testsuite/g++.dg/concepts/diagnostic8.C > > > > @@ -0,0 +1,6 @@ > > > > +// PR c++/94306 > > > > +// { dg-do compile { target c++2a } } > > > > + > > > > +template<typename T> struct S { }; > > > > +template<typename T> requires { typename T::type; } struct S<T> { }; > > > > +// { dg-error "missing additional .requires." "" { target *-*-* } .-1 } > > > > > > > > > > > > > >