PR c++/92105 - decltype(decltype) error cascade.
authorJason Merrill <jason@redhat.com>
Wed, 11 Dec 2019 16:51:14 +0000 (11:51 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 11 Dec 2019 16:51:14 +0000 (11:51 -0500)
The primary change here is to do the CPP_DECLTYPE replacement even when we
get an error, so we don't keep trying and giving the same parse error each
time.  We also commit to the tentative firewall parse more often, leading to
better diagnostics.

* parser.c (cp_parser_decltype_expr): Don't tentative_firewall here.
(cp_parser_decltype): Do it here.  Remember a non-tentative error.

From-SVN: r279237

gcc/cp/ChangeLog
gcc/cp/parser.c
gcc/testsuite/g++.dg/cpp0x/decltype-err1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/decltype10.C

index e371a408c488d1d2bfc7efd09bbe974bf4e63ef6..7051a42831f537636b5dfd37fd49a1ba817cded2 100644 (file)
@@ -1,5 +1,9 @@
 2019-12-11  Jason Merrill  <jason@redhat.com>
 
+       PR c++/92105 - decltype(decltype) error cascade.
+       * parser.c (cp_parser_decltype_expr): Don't tentative_firewall here.
+       (cp_parser_decltype): Do it here.  Remember a non-tentative error.
+
        PR c++/57082 - new X{} and private destructor.
        * init.c (build_new_1): Also pass tf_no_cleanup to
        build_special_member_call.
index bf6d291ba9d9354134df8d84cb89c433413d705d..16d1359c47df92c409c1f7077e30b1f1e024506b 100644 (file)
@@ -14637,11 +14637,6 @@ cp_parser_decltype_expr (cp_parser *parser,
   cp_token *id_expr_start_token;
   tree expr;
 
-  /* Since we're going to preserve any side-effects from this parse, set up a
-     firewall to protect our callers from cp_parser_commit_to_tentative_parse
-     in the expression.  */
-  tentative_firewall firewall (parser);
-
   /* First, try parsing an id-expression.  */
   id_expr_start_token = cp_lexer_peek_token (parser->lexer);
   cp_parser_parse_tentatively (parser);
@@ -14733,9 +14728,6 @@ cp_parser_decltype_expr (cp_parser *parser,
          expression.  */
       cp_parser_abort_tentative_parse (parser);
 
-      /* Commit to the tentative_firewall so we get syntax errors.  */
-      cp_parser_commit_to_tentative_parse (parser);
-
       /* Parse a full expression.  */
       expr = cp_parser_expression (parser, /*pidk=*/NULL, /*cast_p=*/false,
                                   /*decltype_p=*/true);
@@ -14773,6 +14765,17 @@ cp_parser_decltype (cp_parser *parser)
   if (!parens.require_open (parser))
     return error_mark_node;
 
+  /* Since we're going to preserve any side-effects from this parse, set up a
+     firewall to protect our callers from cp_parser_commit_to_tentative_parse
+     in the expression.  */
+  tentative_firewall firewall (parser);
+
+  /* If in_declarator_p, a reparse as an expression might succeed (60361).
+     Otherwise, commit now for better diagnostics.  */
+  if (cp_parser_uncommitted_to_tentative_parse_p (parser)
+      && !parser->in_declarator_p)
+    cp_parser_commit_to_topmost_tentative_parse (parser);
+
   push_deferring_access_checks (dk_deferred);
 
   tree expr = NULL_TREE;
@@ -14833,10 +14836,16 @@ cp_parser_decltype (cp_parser *parser)
     }
 
   /* Parse to the closing `)'.  */
-  if (!parens.require_close (parser))
+  if (expr == error_mark_node || !parens.require_close (parser))
     {
       cp_parser_skip_to_closing_parenthesis (parser, true, false,
                                             /*consume_paren=*/true);
+      expr = error_mark_node;
+    }
+
+  /* If we got a parse error while tentative, bail out now.  */
+  if (cp_parser_error_occurred (parser))
+    {
       pop_deferring_access_checks ();
       return error_mark_node;
     }
@@ -14859,6 +14868,11 @@ cp_parser_decltype (cp_parser *parser)
   start_token->u.tree_check_value->value = expr;
   start_token->u.tree_check_value->checks = get_deferred_access_checks ();
   start_token->keyword = RID_MAX;
+
+  location_t loc = start_token->location;
+  loc = make_location (loc, loc, parser->lexer);
+  start_token->location = loc;
+
   cp_lexer_purge_tokens_after (parser->lexer, start_token);
 
   pop_to_parent_deferring_access_checks ();
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype-err1.C b/gcc/testsuite/g++.dg/cpp0x/decltype-err1.C
new file mode 100644 (file)
index 0000000..302cb64
--- /dev/null
@@ -0,0 +1,7 @@
+// PR c++/92105
+// { dg-do compile { target c++11 } }
+
+// Test that we get exactly one "expected" error.
+
+decltype(decltype) x = 42;     // { dg-bogus "expected.*expected" }
+// { dg-error "expected" "" { target *-*-* } .-1 }
index 846d0bf57cf2aac18f4d3145e6d4121a38d731ee..fe7247269f5d9aac1ae7a2e2a0083c60c224701b 100644 (file)
@@ -6,4 +6,4 @@ template<int> struct A
   static int i;
 };
 
-template<int N> int A<N>::i(decltype (A::i;    // { dg-error "expected primary-expression before" }
+template<int N> int A<N>::i(decltype (A::i;    // { dg-error "expected" }