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 }
> > > > 
> > > 
> > > 
> > 
> 
> 

Reply via email to