c++: Diagnose when "requires" is used instead of "requires requires" [PR94306]
authorPatrick Palka <ppalka@redhat.com>
Sat, 28 Mar 2020 12:57:11 +0000 (08:57 -0400)
committerPatrick Palka <ppalka@redhat.com>
Sat, 28 Mar 2020 12:57:11 +0000 (08:57 -0400)
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
gcc/cp/parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/concepts/diagnostic8.C [new file with mode: 0644]

index a197c7d14e230966858012deb82681c8bf1bac43..e7c248a3c2fccff8d8595fe042b4b0276b573e71 100644 (file)
@@ -1,5 +1,9 @@
 2020-03-28  Patrick Palka  <ppalka@redhat.com>
 
+       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
index bf7387dd1495003e6e8e3e2e9f45a1df6c61411c..fc3c2976e3d96c054b19632191977bf67636a4e4 100644 (file)
@@ -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 %<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);
index 8c8eee014fd7f8b6315c17bf79dbeab651872481..3422550ae023ce99340e4bef53896a76b2bcc7eb 100644 (file)
@@ -1,5 +1,8 @@
 2020-03-28  Patrick Palka  <ppalka@redhat.com>
 
+       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 (file)
index 0000000..70d7e4a
--- /dev/null
@@ -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 }