From 7981c06ae92548bd66f07121db1802eb6aec73ed Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Sat, 28 Mar 2020 08:57:11 -0400 Subject: [PATCH] c++: Diagnose when "requires" is used instead of "requires requires" [PR94306] 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. 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/ChangeLog | 4 ++++ gcc/cp/parser.c | 17 ++++++++++++++++- gcc/testsuite/ChangeLog | 3 +++ gcc/testsuite/g++.dg/concepts/diagnostic8.C | 6 ++++++ 4 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic8.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a197c7d..e7c248a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,9 @@ 2020-03-28 Patrick Palka + PR c++/94306 + * parser.c (cp_parser_requires_clause_opt): Diagnose and recover from + "requires {" when "requires requires {" was probably intended. + PR c++/94252 * constraint.cc (tsubst_compound_requirement): Always suppress errors from type_deducible_p and expression_convertible_p, as they're not diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index bf7387d..fc3c297 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -27704,7 +27704,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) + { + /* 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_after (tok->location, " requires"); + error_at (&richloc, "missing additional % 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/ChangeLog b/gcc/testsuite/ChangeLog index 8c8eee0..3422550 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,8 @@ 2020-03-28 Patrick Palka + PR c++/94306 + * g++.dg/concepts/diagnostic8.C: New test. + PR c++/94252 * g++.dg/concepts/diagnostic7.C: New test. * g++.dg/concepts/pr94252.C: New test. diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic8.C b/gcc/testsuite/g++.dg/concepts/diagnostic8.C new file mode 100644 index 0000000..70d7e4a --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/diagnostic8.C @@ -0,0 +1,6 @@ +// PR c++/94306 +// { dg-do compile { target c++2a } } + +template struct S { }; +template requires { typename T::type; } struct S { }; +// { dg-error "missing additional .requires." "" { target *-*-* } .-1 } -- 2.7.4