C/C++: add fix-it hints for various missing symbols
authorDavid Malcolm <dmalcolm@redhat.com>
Thu, 12 Oct 2017 17:49:35 +0000 (17:49 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Thu, 12 Oct 2017 17:49:35 +0000 (17:49 +0000)
The patch improves our C/C++ frontends' handling of missing
symbols, by making c_parser_require and cp_parser_require use
"better" locations for the diagnostic, and insert fix-it hints,
under certain circumstances (see the comments in the patch for
full details).

For example, for this code with a missing semicolon:

  $ cat test.c
  int missing_semicolon (void)
  {
    return 42
  }

  trunk currently emits:

  test.c:4:1: error: expected ';' before '}' token
   }
   ^

This patch adds a fix-it hint for the missing semicolon, and puts
the error at the location of the missing semicolon, printing the
followup token as a secondary location:

  test.c:3:12: error: expected ';' before '}' token
     return 42
              ^
              ;
   }
   ~

More examples can be seen in the test cases.

gcc/c-family/ChangeLog:
* c-common.c (enum missing_token_insertion_kind): New enum.
(get_missing_token_insertion_kind): New function.
(maybe_suggest_missing_token_insertion): New function.
* c-common.h (maybe_suggest_missing_token_insertion): New decl.

gcc/c/ChangeLog:
* c-parser.c (c_parser_require): Add "type_is_unique" param and
use it to guard calls to maybe_suggest_missing_token_insertion.
(c_parser_parms_list_declarator): Override default value of new
"type_is_unique" param to c_parser_require.
(c_parser_asm_statement): Likewise.
* c-parser.h (c_parser_require): Add "type_is_unique" param,
defaulting to true.

gcc/cp/ChangeLog:
* parser.c (get_required_cpp_ttype): New function.
(cp_parser_error_1): Call it, using the result to call
maybe_suggest_missing_token_insertion.

gcc/testsuite/ChangeLog:
* c-c++-common/cilk-plus/AN/parser_errors.c: Update expected
output to reflect changes to reported locations of missing
symbols.
* c-c++-common/cilk-plus/AN/parser_errors2.c: Likewise.
* c-c++-common/cilk-plus/AN/parser_errors3.c: Likewise.
* c-c++-common/cilk-plus/AN/pr61191.c: Likewise.
* c-c++-common/gomp/pr63326.c: Likewise.
* c-c++-common/missing-close-symbol.c: Likewise, also update for
new fix-it hints.
* c-c++-common/missing-symbol.c: Likewise, also add test coverage
for missing colon in ternary operator.
* g++.dg/cpp1y/digit-sep-neg.C: Likewise.
* g++.dg/cpp1y/pr65202.C: Likewise.
* g++.dg/missing-symbol-2.C: New test case.
* g++.dg/other/do1.C: Update expected output to reflect
changes to reported locations of missing symbols.
* g++.dg/parse/error11.C: Likewise.
* g++.dg/template/error11.C: Likewise.
* gcc.dg/missing-symbol-2.c: New test case.
* gcc.dg/missing-symbol-3.c: New test case.
* gcc.dg/noncompile/940112-1.c: Update expected output to reflect
changes to reported locations of missing symbols.
* gcc.dg/noncompile/971104-1.c: Likewise.
* obj-c++.dg/exceptions-6.mm: Likewise.
* obj-c++.dg/pr48187.mm: Likewise.
* objc.dg/exceptions-6.m: Likewise.

From-SVN: r253690

29 files changed:
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c/ChangeLog
gcc/c/c-parser.c
gcc/c/c-parser.h
gcc/cp/ChangeLog
gcc/cp/parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors.c
gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors2.c
gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors3.c
gcc/testsuite/c-c++-common/cilk-plus/AN/pr61191.c
gcc/testsuite/c-c++-common/gomp/pr63326.c
gcc/testsuite/c-c++-common/missing-close-symbol.c
gcc/testsuite/c-c++-common/missing-symbol.c
gcc/testsuite/g++.dg/cpp1y/digit-sep-neg.C
gcc/testsuite/g++.dg/cpp1y/pr65202.C
gcc/testsuite/g++.dg/missing-symbol-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/other/do1.C
gcc/testsuite/g++.dg/parse/error11.C
gcc/testsuite/g++.dg/template/error11.C
gcc/testsuite/gcc.dg/missing-symbol-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/missing-symbol-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/noncompile/940112-1.c
gcc/testsuite/gcc.dg/noncompile/971104-1.c
gcc/testsuite/obj-c++.dg/exceptions-6.mm
gcc/testsuite/obj-c++.dg/pr48187.mm
gcc/testsuite/objc.dg/exceptions-6.m

index da40ab310026be10a706c033cfd1b7057a85ea15..ee6fc87dd6f3ae5f4751a67c99ac208756ebb7c3 100644 (file)
@@ -1,3 +1,10 @@
+2017-10-12  David Malcolm  <dmalcolm@redhat.com>
+
+       * c-common.c (enum missing_token_insertion_kind): New enum.
+       (get_missing_token_insertion_kind): New function.
+       (maybe_suggest_missing_token_insertion): New function.
+       * c-common.h (maybe_suggest_missing_token_insertion): New decl.
+
 2017-10-11  Nathan Sidwell  <nathan@acm.org>
 
        * c-opts.c (add_prefixed_path): Change chain to incpath_kind.
index 09594e44e6c5f1c10a539221a4cd4f6ca5ba1d02..dfcfb1960285d0f9afd2d5313bbbe804ce4286a2 100644 (file)
@@ -7946,6 +7946,164 @@ c_flt_eval_method (bool maybe_c11_only_p)
     return c_ts18661_flt_eval_method ();
 }
 
+/* An enum for get_missing_token_insertion_kind for describing the best
+   place to insert a missing token, if there is one.  */
+
+enum missing_token_insertion_kind
+{
+  MTIK_IMPOSSIBLE,
+  MTIK_INSERT_BEFORE_NEXT,
+  MTIK_INSERT_AFTER_PREV
+};
+
+/* Given a missing token of TYPE, determine if it is reasonable to
+   emit a fix-it hint suggesting the insertion of the token, and,
+   if so, where the token should be inserted relative to other tokens.
+
+   It only makes sense to do this for values of TYPE that are symbols.
+
+   Some symbols should go before the next token, e.g. in:
+     if flag)
+   we want to insert the missing '(' immediately before "flag",
+   giving:
+     if (flag)
+   rather than:
+     if( flag)
+   These use MTIK_INSERT_BEFORE_NEXT.
+
+   Other symbols should go after the previous token, e.g. in:
+     if (flag
+       do_something ();
+   we want to insert the missing ')' immediately after the "flag",
+   giving:
+     if (flag)
+       do_something ();
+   rather than:
+     if (flag
+       )do_something ();
+   These use MTIK_INSERT_AFTER_PREV.  */
+
+static enum missing_token_insertion_kind
+get_missing_token_insertion_kind (enum cpp_ttype type)
+{
+  switch (type)
+    {
+      /* Insert missing "opening" brackets immediately
+        before the next token.  */
+    case CPP_OPEN_SQUARE:
+    case CPP_OPEN_PAREN:
+      return MTIK_INSERT_BEFORE_NEXT;
+
+      /* Insert other missing symbols immediately after
+        the previous token.  */
+    case CPP_CLOSE_PAREN:
+    case CPP_CLOSE_SQUARE:
+    case CPP_SEMICOLON:
+    case CPP_COMMA:
+    case CPP_COLON:
+      return MTIK_INSERT_AFTER_PREV;
+
+      /* Other kinds of token don't get fix-it hints.  */
+    default:
+      return MTIK_IMPOSSIBLE;
+    }
+}
+
+/* Given RICHLOC, a location for a diagnostic describing a missing token
+   of kind TOKEN_TYPE, potentially add a fix-it hint suggesting the
+   insertion of the token.
+
+   The location of the attempted fix-it hint depends on TOKEN_TYPE:
+   it will either be:
+     (a) immediately after PREV_TOKEN_LOC, or
+
+     (b) immediately before the primary location within RICHLOC (taken to
+        be that of the token following where the token was expected).
+
+   If we manage to add a fix-it hint, then the location of the
+   fix-it hint is likely to be more useful as the primary location
+   of the diagnostic than that of the following token, so we swap
+   these locations.
+
+   For example, given this bogus code:
+       123456789012345678901234567890
+   1 | int missing_semicolon (void)
+   2 | {
+   3 |   return 42
+   4 | }
+
+   we will emit:
+
+     "expected ';' before '}'"
+
+   RICHLOC's primary location is at the closing brace, so before "swapping"
+   we would emit the error at line 4 column 1:
+
+       123456789012345678901234567890
+   3 |   return 42  |< fix-it hint emitted for this line
+     |            ; |
+   4 | }            |< "expected ';' before '}'" emitted at this line
+     | ^            |
+
+   It's more useful for the location of the diagnostic to be at the
+   fix-it hint, so we swap the locations, so the primary location
+   is at the fix-it hint, with the old primary location inserted
+   as a secondary location, giving this, with the error at line 3
+   column 12:
+
+       123456789012345678901234567890
+   3 |   return 42   |< "expected ';' before '}'" emitted at this line,
+     |            ^  |   with fix-it hint
+   4 |            ;  |
+     | }             |< secondary range emitted here
+     | ~             |.  */
+
+void
+maybe_suggest_missing_token_insertion (rich_location *richloc,
+                                      enum cpp_ttype token_type,
+                                      location_t prev_token_loc)
+{
+  gcc_assert (richloc);
+
+  enum missing_token_insertion_kind mtik
+    = get_missing_token_insertion_kind (token_type);
+
+  switch (mtik)
+    {
+    default:
+      gcc_unreachable ();
+      break;
+
+    case MTIK_IMPOSSIBLE:
+      return;
+
+    case MTIK_INSERT_BEFORE_NEXT:
+      /* Attempt to add the fix-it hint before the primary location
+        of RICHLOC.  */
+      richloc->add_fixit_insert_before (cpp_type2name (token_type, 0));
+      break;
+
+    case MTIK_INSERT_AFTER_PREV:
+      /* Attempt to add the fix-it hint after PREV_TOKEN_LOC.  */
+      richloc->add_fixit_insert_after (prev_token_loc,
+                                      cpp_type2name (token_type, 0));
+      break;
+    }
+
+  /* If we were successful, use the fix-it hint's location as the
+     primary location within RICHLOC, adding the old primary location
+     back as a secondary location.  */
+  if (!richloc->seen_impossible_fixit_p ())
+    {
+      fixit_hint *hint = richloc->get_last_fixit_hint ();
+      location_t hint_loc = hint->get_start_loc ();
+      location_t old_loc = richloc->get_loc ();
+
+      richloc->set_range (line_table, 0, hint_loc, true);
+      richloc->add_range (old_loc, false);
+    }
+}
+
 #if CHECKING_P
 
 namespace selftest {
index da6a0be92000dd1605c61d700327d3165b231b21..7e1877e8d164adfef446be519f3ec6d983a235c4 100644 (file)
@@ -1550,6 +1550,9 @@ extern int c_flt_eval_method (bool ts18661_p);
 extern void add_no_sanitize_value (tree node, unsigned int flags);
 
 extern void maybe_add_include_fixit (rich_location *, const char *);
+extern void maybe_suggest_missing_token_insertion (rich_location *richloc,
+                                                  enum cpp_ttype token_type,
+                                                  location_t prev_token_loc);
 
 #if CHECKING_P
 namespace selftest {
index baf57c1f95add0028dd816f7f1a7c5a14a6ca298..1f697f17f9924982ccad43f23e78ad48fd656a16 100644 (file)
@@ -1,3 +1,13 @@
+2017-10-12  David Malcolm  <dmalcolm@redhat.com>
+
+       * c-parser.c (c_parser_require): Add "type_is_unique" param and
+       use it to guard calls to maybe_suggest_missing_token_insertion.
+       (c_parser_parms_list_declarator): Override default value of new
+       "type_is_unique" param to c_parser_require.
+       (c_parser_asm_statement): Likewise.
+       * c-parser.h (c_parser_require): Add "type_is_unique" param,
+       defaulting to true.
+
 2017-10-11  Nathan Sidwell  <nathan@acm.org>
 
        * c-decl.c (grokdeclarator): Check HAS_DECL_ASSEMBLER_NAME_P too.
index a622e2a89c9fb6645e2a12e34db52b27ae806a9e..6b843247911e84f94c1c775a00d616379c600241 100644 (file)
@@ -1041,13 +1041,21 @@ get_matching_symbol (enum cpp_ttype type)
    If MATCHING_LOCATION is not UNKNOWN_LOCATION, then highlight it
    within any error as the location of an "opening" token matching
    the close token TYPE (e.g. the location of the '(' when TYPE is
-   CPP_CLOSE_PAREN).  */
+   CPP_CLOSE_PAREN).
+
+   If TYPE_IS_UNIQUE is true (the default) then msgid describes exactly
+   one type (e.g. "expected %<)%>") and thus it may be reasonable to
+   attempt to generate a fix-it hint for the problem.
+   Otherwise msgid describes multiple token types (e.g.
+   "expected %<;%>, %<,%> or %<)%>"), and thus we shouldn't attempt to
+   generate a fix-it hint.  */
 
 bool
 c_parser_require (c_parser *parser,
                  enum cpp_ttype type,
                  const char *msgid,
-                 location_t matching_location)
+                 location_t matching_location,
+                 bool type_is_unique)
 {
   if (c_parser_next_token_is (parser, type))
     {
@@ -1059,6 +1067,13 @@ c_parser_require (c_parser *parser,
       location_t next_token_loc = c_parser_peek_token (parser)->location;
       gcc_rich_location richloc (next_token_loc);
 
+      /* Potentially supply a fix-it hint, suggesting to add the
+        missing token immediately after the *previous* token.
+        This may move the primary location within richloc.  */
+      if (!parser->error && type_is_unique)
+       maybe_suggest_missing_token_insertion (&richloc, type,
+                                              parser->last_token_location);
+
       /* If matching_location != UNKNOWN_LOCATION, highlight it.
         Attempt to consolidate diagnostics by printing it as a
         secondary range within the main diagnostic.  */
@@ -3975,7 +3990,8 @@ c_parser_parms_list_declarator (c_parser *parser, tree attrs, tree expr)
            return get_parm_info (false, expr);
        }
       if (!c_parser_require (parser, CPP_COMMA,
-                            "expected %<;%>, %<,%> or %<)%>"))
+                            "expected %<;%>, %<,%> or %<)%>",
+                            UNKNOWN_LOCATION, false))
        {
          c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
          return NULL;
@@ -6429,7 +6445,8 @@ c_parser_asm_statement (c_parser *parser)
       if (!c_parser_require (parser, CPP_COLON,
                             is_goto
                             ? G_("expected %<:%>")
-                            : G_("expected %<:%> or %<)%>")))
+                            : G_("expected %<:%> or %<)%>"),
+                            UNKNOWN_LOCATION, is_goto))
        goto error_close_paren;
 
       /* Once past any colon, we're no longer a simple asm.  */
index 01a7b724081ab7d3f815eb543fe76f078efc51db..21e40541ce60ecfa9061dd508624a808bde6b738 100644 (file)
@@ -137,7 +137,8 @@ extern c_token * c_parser_peek_2nd_token (c_parser *parser);
 extern c_token * c_parser_peek_nth_token (c_parser *parser, unsigned int n);
 extern bool c_parser_require (c_parser *parser, enum cpp_ttype type,
                              const char *msgid,
-                             location_t matching_location = UNKNOWN_LOCATION);
+                             location_t matching_location = UNKNOWN_LOCATION,
+                             bool type_is_unique=true);
 extern bool c_parser_error (c_parser *parser, const char *gmsgid);
 extern void c_parser_consume_token (c_parser *parser);
 extern void c_parser_skip_until_found (c_parser *parser, enum cpp_ttype type,
index 4c78cc0a01b0a981fbc92111ffda454f7a9458f9..717411582b33a4a1037e32e0b13e25c6b2712e61 100644 (file)
@@ -1,3 +1,9 @@
+2017-10-12  David Malcolm  <dmalcolm@redhat.com>
+
+       * parser.c (get_required_cpp_ttype): New function.
+       (cp_parser_error_1): Call it, using the result to call
+       maybe_suggest_missing_token_insertion.
+
 2017-10-12  David Malcolm  <dmalcolm@redhat.com>
 
        * parser.c (get_matching_symbol): Move to before...
index b668b59d9ae1aba3b5cf7b2500432e770faff761..810e2b7f72e124941c5534e840d71281ad5164b8 100644 (file)
@@ -2788,6 +2788,40 @@ get_matching_symbol (required_token token_desc)
     }
 }
 
+/* Attempt to convert TOKEN_DESC from a required_token to an
+   enum cpp_ttype, returning CPP_EOF if there is no good conversion.  */
+
+static enum cpp_ttype
+get_required_cpp_ttype (required_token token_desc)
+{
+  switch (token_desc)
+    {
+    case RT_SEMICOLON:
+      return CPP_SEMICOLON;
+    case RT_OPEN_PAREN:
+      return CPP_OPEN_PAREN;
+    case RT_CLOSE_BRACE:
+      return CPP_CLOSE_BRACE;
+    case RT_OPEN_BRACE:
+      return CPP_OPEN_BRACE;
+    case RT_CLOSE_SQUARE:
+      return CPP_CLOSE_SQUARE;
+    case RT_OPEN_SQUARE:
+      return CPP_OPEN_SQUARE;
+    case RT_COMMA:
+      return CPP_COMMA;
+    case RT_COLON:
+      return CPP_COLON;
+    case RT_CLOSE_PAREN:
+      return CPP_CLOSE_PAREN;
+
+    default:
+      /* Use CPP_EOF as a "no completions possible" code.  */
+      return CPP_EOF;
+    }
+}
+
+
 /* Subroutine of cp_parser_error and cp_parser_required_error.
 
    Issue a diagnostic of the form
@@ -2799,9 +2833,12 @@ get_matching_symbol (required_token token_desc)
    This bypasses the check for tentative passing, and potentially
    adds material needed by cp_parser_required_error.
 
-   If MISSING_TOKEN_DESC is not RT_NONE, and MATCHING_LOCATION is not
-   UNKNOWN_LOCATION, then we have an unmatched symbol at
-   MATCHING_LOCATION; highlight this secondary location.  */
+   If MISSING_TOKEN_DESC is not RT_NONE, then potentially add fix-it hints
+   suggesting insertion of the missing token.
+
+   Additionally, if MATCHING_LOCATION is not UNKNOWN_LOCATION, then we
+   have an unmatched symbol at MATCHING_LOCATION; highlight this secondary
+   location.  */
 
 static void
 cp_parser_error_1 (cp_parser* parser, const char* gmsgid,
@@ -2840,6 +2877,14 @@ cp_parser_error_1 (cp_parser* parser, const char* gmsgid,
 
   if (missing_token_desc != RT_NONE)
     {
+      /* Potentially supply a fix-it hint, suggesting to add the
+        missing token immediately after the *previous* token.
+        This may move the primary location within richloc.  */
+      enum cpp_ttype ttype = get_required_cpp_ttype (missing_token_desc);
+      location_t prev_token_loc
+       = cp_lexer_previous_token (parser->lexer)->location;
+      maybe_suggest_missing_token_insertion (&richloc, ttype, prev_token_loc);
+
       /* If matching_location != UNKNOWN_LOCATION, highlight it.
         Attempt to consolidate diagnostics by printing it as a
        secondary range within the main diagnostic.  */
index a910f8aeac166e3bb0459cde32ba7938b06f0d2d..79642b88d8236c33be49865c6dff11ff9c67ed76 100644 (file)
@@ -1,3 +1,32 @@
+2017-10-12  David Malcolm  <dmalcolm@redhat.com>
+
+       * c-c++-common/cilk-plus/AN/parser_errors.c: Update expected
+       output to reflect changes to reported locations of missing
+       symbols.
+       * c-c++-common/cilk-plus/AN/parser_errors2.c: Likewise.
+       * c-c++-common/cilk-plus/AN/parser_errors3.c: Likewise.
+       * c-c++-common/cilk-plus/AN/pr61191.c: Likewise.
+       * c-c++-common/gomp/pr63326.c: Likewise.
+       * c-c++-common/missing-close-symbol.c: Likewise, also update for
+       new fix-it hints.
+       * c-c++-common/missing-symbol.c: Likewise, also add test coverage
+       for missing colon in ternary operator.
+       * g++.dg/cpp1y/digit-sep-neg.C: Likewise.
+       * g++.dg/cpp1y/pr65202.C: Likewise.
+       * g++.dg/missing-symbol-2.C: New test case.
+       * g++.dg/other/do1.C: Update expected output to reflect
+       changes to reported locations of missing symbols.
+       * g++.dg/parse/error11.C: Likewise.
+       * g++.dg/template/error11.C: Likewise.
+       * gcc.dg/missing-symbol-2.c: New test case.
+       * gcc.dg/missing-symbol-3.c: New test case.
+       * gcc.dg/noncompile/940112-1.c: Update expected output to reflect
+       changes to reported locations of missing symbols.
+       * gcc.dg/noncompile/971104-1.c: Likewise.
+       * obj-c++.dg/exceptions-6.mm: Likewise.
+       * obj-c++.dg/pr48187.mm: Likewise.
+       * objc.dg/exceptions-6.m: Likewise.
+
 2017-10-12  Martin Sebor  <msebor@redhat.com>
 
        PR other/82301
index 18816e0ec6f814fbf7fc4b574a3d28d0eb6a3cc8..fd4fe5419b641b49ac6ab46a19643bd930f4fcc8 100644 (file)
@@ -7,5 +7,5 @@ int main (void)
   
   array2[:] = array2[: ;  /* { dg-error "expected ']'" } */
 
-  return 0;
-} /* { dg-error "expected ';' before" "" { target c } } */
+  return 0; /* { dg-error "expected ';' before" "" { target c } } */
+}
index 2bb91343a79fd79c244c4fcaca2a16fb454d33e8..d003d7cc2bb3e5d7dc09ae2b8275d0c9843b114d 100644 (file)
@@ -7,6 +7,7 @@ int main (void)
   
   array2[:] = array2[1:2:] ;  /* { dg-error "expected expression before" "" { target c } } */ 
   /* { dg-error  "expected primary-expression before" "" { target c++ } .-1 } */
+  /* { dg-error "expected ';' before" "" { target c } .-2 } */
 
-  return 0; /* { dg-error "expected ';' before" "" { target c }  } */
+  return 0;
 }
index 9270007050e6a5600f8fa4c91d2470312b20a7f5..14256e9579ee7f4108779f4a85745dd976f15fda 100644 (file)
@@ -7,6 +7,7 @@ int main (void)
   
   array2[:] = array2[1: :] ;  /* { dg-error "expected expression before" "" { target c }  } */ 
   /* { dg-error "expected primary-expression before" "" { target c++ }  .-1 } */
+  /* { dg-error "expected ';' before" "" { target c } .-2 } */
 
-  return 0; /* { dg-error "expected ';' before" "" { target c } } */
+  return 0;
 }
index a9a9d6601bcf4a6c326235da7fa46d9fd9be2d3b..8c32ad9a267af3b05b7d8ef5618f5885fea9873d 100644 (file)
@@ -7,4 +7,5 @@ double f(double * A, double * B)
   return __sec_reduce_add((B[0:500])(; /* { dg-error "called object" "" { target c } } */
 /* { dg-error "expected expression before ';' token" "" { target c } .-1 } */
 /* { dg-error "expected primary-expression before ';' token" "" { target c++ } .-2 } */
-} /* { dg-error "expected" "" { target c } } */
+/* { dg-error "expected" "" { target c } .-3 } */
+}
index e319f49701117c1b4387de496b6de61b7d5ef88f..3e627237c4317ec2cfc017279520db34b720a26f 100644 (file)
@@ -156,34 +156,34 @@ f4 (int x)
   {
     do
       #pragma omp barrier                      /* { dg-error "may only be used in compound statements" } */
-    while (0);
+    while (0); /* { dg-error "before" "" { target c++ } } */
   } /* { dg-error "before" "" { target c++ } } */
   {
     do
       #pragma omp flush                                /* { dg-error "may only be used in compound statements" } */
-    while (0);
+    while (0); /* { dg-error "before" "" { target c++ } } */
   } /* { dg-error "before" "" { target c++ } } */
   {
     do
       #pragma omp taskwait                     /* { dg-error "may only be used in compound statements" } */
-    while (0);
+    while (0); /* { dg-error "before" "" { target c++ } } */
   } /* { dg-error "before" "" { target c++ } } */
   {
     do
       #pragma omp taskyield                    /* { dg-error "may only be used in compound statements" } */
-    while (0);
+    while (0); /* { dg-error "before" "" { target c++ } } */
   } /* { dg-error "before" "" { target c++ } } */
   #pragma omp parallel
   {
     do
       #pragma omp cancel parallel              /* { dg-error "may only be used in compound statements" } */
-    while (0);
+    while (0); /* { dg-error "before" "" { target c++ } } */
   } /* { dg-error "before" "" { target c++ } } */
   #pragma omp parallel
   {
     do
       #pragma omp cancellation point parallel  /* { dg-error "may only be used in compound statements" } */
-    while (0);
+    while (0); /* { dg-error "before" "" { target c++ } } */
   } /* { dg-error "before" "" { target c++ } } */
   #pragma omp for ordered(1)
   for (i = 0; i < 16; i++)
@@ -191,28 +191,28 @@ f4 (int x)
       {
        do
          #pragma omp ordered depend(source)    /* { dg-error "may only be used in compound statements" } */
-       while (0);
+       while (0); /* { dg-error "before" "" { target c++ } } */
       } /* { dg-error "before" "" { target c++ } } */
       {
        do
          #pragma omp ordered depend(sink: i-1) /* { dg-error "may only be used in compound statements" } */
-       while (0);
+       while (0); /* { dg-error "before" "" { target c++ } } */
       } /* { dg-error "before" "" { target c++ } } */
     }
   {
     do
       #pragma omp target enter data map(to:i)  /* { dg-error "may only be used in compound statements" } */
-    while (0);
+    while (0); /* { dg-error "before" "" { target c++ } } */
   } /* { dg-error "before" "" { target c++ } } */
   {
     do
       #pragma omp target update to(i)          /* { dg-error "may only be used in compound statements" } */
-    while (0);
+    while (0); /* { dg-error "before" "" { target c++ } } */
   } /* { dg-error "before" "" { target c++ } } */
   {
     do
       #pragma omp target exit data map(from:i) /* { dg-error "may only be used in compound statements" } */
-    while (0);
+    while (0); /* { dg-error "before" "" { target c++ } } */
   } /* { dg-error "before" "" { target c++ } } */
 }
 
index 85b96f28ef83365845b4face59e5813fbf3cb63b..abeb83748c163161d15f8584d174b3dc250a042f 100644 (file)
@@ -12,6 +12,7 @@ void test_static_assert_same_line (void)
   /* { dg-begin-multiline-output "" }
    _Static_assert(sizeof(int) >= sizeof(char), "msg";
                  ~                                  ^
+                                                    )
      { dg-end-multiline-output "" } */
 }
 
@@ -25,6 +26,7 @@ void test_static_assert_different_line (void)
   /* { dg-begin-multiline-output "" }
     "msg";
          ^
+         )
      { dg-end-multiline-output "" } */
   /* { dg-begin-multiline-output "" }
    _Static_assert(sizeof(int) >= sizeof(char),
index 33a501b998864d9e78954e77da4600fb2ec266eb..326b9faad7a90714e42802ff689f65b8fa9dfe01 100644 (file)
@@ -5,15 +5,14 @@ extern int bar (void);
 
 int missing_close_paren_in_switch (int i)
 {
-  switch (i /* { dg-message "10: to match this '\\('" } */
-    { /* { dg-error "5: expected '\\)' before '.' token" } */
-  /* { dg-begin-multiline-output "" }
-     {
-     ^
-     { dg-end-multiline-output "" } */
+  switch (i /* { dg-error "12: expected '\\)' before '.' token" } */
+    {
   /* { dg-begin-multiline-output "" }
    switch (i
-          ^
+          ~ ^
+            )
+     {
+     ~       
      { dg-end-multiline-output "" } */
 
     case 0:
@@ -30,21 +29,33 @@ int missing_close_paren_in_switch (int i)
 void missing_close_paren_in_if (void)
 {
   if (foo () /* { dg-line start_of_if } */
-      && bar () 
-    { /* { dg-error "5: expected '\\)' before '.' token" } */
+      && bar () /* { dg-error "16: expected '\\)' before '.' token" } */
+    {
       /* { dg-begin-multiline-output "" }
+       && bar ()
+                ^
+                )
      {
-     ^
+     ~           
          { dg-end-multiline-output "" } */
       /* { dg-message "6: to match this '\\('" "" { target *-*-* } start_of_if } */
       /* { dg-begin-multiline-output "" }
    if (foo ()
       ^
-      { dg-end-multiline-output "" } */
+         { dg-end-multiline-output "" } */
     }
-
 } /* { dg-error "1: expected" } */
   /* { dg-begin-multiline-output "" }
  }
  ^
      { dg-end-multiline-output "" } */
+
+int missing_colon_in_ternary (int flag)
+{
+  return flag ? 42 0; /* { dg-error "expected ':' before numeric constant" } */
+  /* { dg-begin-multiline-output "" }
+   return flag ? 42 0;
+                   ^~
+                   :
+     { dg-end-multiline-output "" } */
+}
index 833fab7c50b9c7576070b2c8639170d50b2e10b2..727e74e2e108c8c78c4ae4a2b86b795e82d24237 100644 (file)
@@ -26,5 +26,5 @@ main()
 }
 
 // { dg-error "exponent has no digits" "exponent has no digits" { target *-*-* } 21 }
-// { dg-error "expected ';' before" "expected ';' before" { target *-*-* } 14 }
-// { dg-error "expected ';' before" "expected ';' before" { target *-*-* } 25 }
+// { dg-error "expected ';' before" "expected ';' before" { target *-*-* } 13 }
+// { dg-error "expected ';' before" "expected ';' before" { target *-*-* } 24 }
index 602b264b302821d17a64c8ed4dbda04da609d0a1..7ce4895a13449792c6abf7de27106a384847c00e 100644 (file)
@@ -22,5 +22,5 @@ struct bar;
 int main()
 {
     foo<ns::bar> f;
-    adl::swap(f, f)
-} // { dg-error "" }
+    adl::swap(f, f) // { dg-error "expected ';'" }
+} // { dg-error "expected '.'" "expected end of namespace" }
diff --git a/gcc/testsuite/g++.dg/missing-symbol-2.C b/gcc/testsuite/g++.dg/missing-symbol-2.C
new file mode 100644 (file)
index 0000000..4a119f8
--- /dev/null
@@ -0,0 +1,58 @@
+/* { dg-options "-fdiagnostics-show-caret" } */
+
+extern int foo (void);
+
+void missing_open_paren (void)
+{
+  if foo ()) /* { dg-error "expected '\\(' before 'foo'" } */
+    {
+    }
+  /* { dg-begin-multiline-output "" }
+   if foo ())
+      ^~~
+      (
+     { dg-end-multiline-output "" } */
+}
+
+
+void missing_close_square (void)
+{
+  const char test [42;  /* { dg-error "22: expected ']' before ';' token" } */
+  /* { dg-begin-multiline-output "" }
+   const char test [42;
+                      ^
+                      ]
+     { dg-end-multiline-output "" } */
+}
+
+int missing_semicolon (void)
+{
+  return 42 /* { dg-error "expected ';'" } */
+}
+/* { dg-begin-multiline-output "" }
+   return 42
+            ^
+            ;
+ }
+ ~           
+   { dg-end-multiline-output "" } */
+
+
+int missing_colon_in_switch (int val)
+{
+  switch (val)
+    {
+    case 42 /* { dg-error "expected ':' before 'return'" } */
+      return 42;
+    /* { dg-begin-multiline-output "" }
+     case 42
+            ^
+            :
+       return 42;
+       ~~~~~~
+       { dg-end-multiline-output "" } */
+
+    default:
+      return val;
+    }
+}
index b3a9daf90560638a0e6f12f4766e3cf6f91d6c16..db65e7de301cb089d64f27a7cbcfde408feaf98c 100644 (file)
@@ -7,7 +7,7 @@
 
 void init ()
 {
-  do {  } while (0)
-           obj = 0; // { dg-error "expected|not declared" }
+  do {  } while (0) // { dg-error "expected ';'" }
+           obj = 0; // { dg-error "not declared" }
      
 }
index d118c19deb8985fd2167dd080e1aeefd2f4a0c48..1a49d6edb12f0a156c985e0b9ce7082ed60d8ecc 100644 (file)
@@ -52,7 +52,7 @@ void func(void)
   Foo[:B> k1;       // { dg-bogus "cannot begin|alternate spelling" "smart error should not be triggered here" } 
 // { dg-error "6:missing template arguments before" "template" { target *-*-* } 51 }
 // { dg-error "9:expected primary-expression before ':' token" "primary" { target *-*-* } 51 }
-// { dg-error "9:expected '\]' before ':' token" "backslash" { target *-*-* } 51 }
+// { dg-error "8:expected '\]' before ':' token" "backslash" { target *-*-* } 51 }
 // { dg-error "6:missing template arguments before" "template" { target *-*-* } 52 }
 // { dg-error "7:expected primary-expression before ':' token" "primary" { target *-*-* } 52 }
 // { dg-error "7:expected '\]' before ':' token" "backslash" { target *-*-* } 52 }
index 3a469fd1a8ca68f065f66dc81b7ef892dbdf981d..16402988a8704209405c0bb60cea49e6fec83e3d 100644 (file)
@@ -1,4 +1,4 @@
 // PR c++/12132
 
 inline template <int> void foo () {} // { dg-error "<" }
-void abort (); // { dg-error ";" }
+void abort (); // { dg-error ";" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/gcc.dg/missing-symbol-2.c b/gcc/testsuite/gcc.dg/missing-symbol-2.c
new file mode 100644 (file)
index 0000000..7ee795d
--- /dev/null
@@ -0,0 +1,71 @@
+/* { dg-options "-fdiagnostics-show-caret -Wno-switch-unreachable" } */
+
+extern int foo (void);
+
+void missing_open_paren (void)
+{
+  if foo ()) /* { dg-line missing_open_paren } */
+    {
+    }
+  /* { dg-error "expected '\\(' before 'foo'" "" { target c } missing_open_paren } */
+  /* { dg-begin-multiline-output "" }
+   if foo ())
+      ^~~
+      (
+     { dg-end-multiline-output "" } */
+  /* { dg-error "expected statement before '\\)' token"  "" { target c } missing_open_paren } */
+  /* { dg-begin-multiline-output "" }
+   if foo ())
+            ^
+     { dg-end-multiline-output "" } */
+}
+
+void missing_close_square (void)
+{
+  const char test [42;  /* { dg-error "22: expected ']' before ';' token" } */
+  /* { dg-begin-multiline-output "" }
+   const char test [42;
+                      ^
+                      ]
+     { dg-end-multiline-output "" } */
+}
+
+int missing_semicolon (void)
+{
+  return 42 /* { dg-error "expected ';'" } */
+}
+/* { dg-begin-multiline-output "" }
+   return 42
+            ^
+            ;
+ }
+ ~           
+   { dg-end-multiline-output "" } */
+
+
+/* We don't offer a fix-it hint for this case in C, as it could be
+   colon or ellipsis.
+   TODO: we could be smarter about error-recovery here; given the
+   return perhaps we could assume a missing colon.  */
+
+int missing_colon_in_switch (int val)
+{
+  switch (val)
+    {
+    case 42
+      return 42; /* { dg-error "expected ':' or '...' before 'return'" } */
+    /* { dg-begin-multiline-output "" }
+       return 42;
+       ^~~~~~
+       { dg-end-multiline-output "" } */
+
+    default:
+      return val;
+    }
+}
+
+/* { dg-begin-multiline-output "" }
+ int dummy;
+ ^~~
+   { dg-end-multiline-output "" } */
+int dummy;/* { dg-error "expected declaration or statement at end of input" "" { target c } } */
diff --git a/gcc/testsuite/gcc.dg/missing-symbol-3.c b/gcc/testsuite/gcc.dg/missing-symbol-3.c
new file mode 100644 (file)
index 0000000..e2d00df
--- /dev/null
@@ -0,0 +1,50 @@
+/* { dg-options "-fdiagnostics-show-caret" } */
+
+/* A sequence of bogus _Static_assert.
+   We can offer fix-it hints for some of these, but not all.  */
+
+void test_static_assert_1 (void)
+{
+  _Static_assert sizeof(int) >= sizeof(char); /* { dg-error "expected '\\(' before 'sizeof'" } */
+  /* { dg-begin-multiline-output "" }
+   _Static_assert sizeof(int) >= sizeof(char);
+                  ^~~~~~
+                  (
+     { dg-end-multiline-output "" } */
+}
+
+void test_static_assert_2 (void)
+{
+  _Static_assert(sizeof(int) >= sizeof(char); /* { dg-error "expected ',' before ';' token" } */
+  /* { dg-begin-multiline-output "" }
+   _Static_assert(sizeof(int) >= sizeof(char);
+                                             ^
+                                             ,
+     { dg-end-multiline-output "" } */
+}
+
+void test_static_assert_3 (void)
+{
+  _Static_assert(sizeof(int) >= sizeof(char),; /* { dg-error "expected string literal before ';' token" } */
+  /* { dg-begin-multiline-output "" }
+   _Static_assert(sizeof(int) >= sizeof(char),;
+                                              ^
+     { dg-end-multiline-output "" } */
+}
+
+void test_static_assert_4 (void)
+{
+  _Static_assert(sizeof(int) >= sizeof(char), "msg"; /* { dg-error "expected '\\)' before ';' token" } */
+  /* { dg-begin-multiline-output "" }
+   _Static_assert(sizeof(int) >= sizeof(char), "msg";
+                 ~                                  ^
+                                                    )
+     { dg-end-multiline-output "" } */
+}
+
+/* The final one is correct.  */
+
+void test_static_assert_5 (void)
+{
+  _Static_assert(sizeof(int) >= sizeof(char), "msg");
+}
index bb5e0f66c85c571e135d99a799eb5c3c49eaeddc..0a9e07dcaf9cb88911ab1588039fe95d09321943 100644 (file)
@@ -3,5 +3,5 @@ f (int x)
 {
   double e = 1;
   e = 1;
-  return (e)
-}      /* { dg-error "parse error|syntax error|expected" } */
+  return (e) /* { dg-error "parse error|syntax error|expected" } */
+}      
index 39e00c60fc2efbc64d92f696145fcbfc0280123e..4a04dad7747b02cb91931e8cd3db29925869c10e 100644 (file)
@@ -27,6 +27,6 @@ static void up(int sem){
     printf("%s had processes sleeping on it!\n",
     ({ "MUTEX     ", "BARB_SEM 1", "BARB_SEM 2", "CUST_SEM 1",
        "CUST_SEM 2", "WAIT_SEM 1", "WAIT_SEM 2", "WAIT_SEM 3",
-       "WAIT_SEM 4"}    /* { dg-error "parse error|syntax error|expected" } */
-       [( sb.sem_num )]) ); /* { dg-error "expected" } */
+       "WAIT_SEM 4"}    /* { dg-error "expected" } */
+       [( sb.sem_num )]) );
 }
index 58882fed8b71acf4000ff4137112d82547ea5074..6f6ba783ea75b02203a233ae878b03e1e3f61b39 100644 (file)
@@ -11,15 +11,15 @@ void test (id object)
   @throw object;   /* Ok */
   @throw;          /* { dg-error ".@throw. .rethrow. used outside of a @catch block" } */
   @throw (object); /* Ok.  */
-  @throw (id)0
-}                  /* { dg-error "expected" } */
+  @throw (id)0     /* { dg-error "expected" } */
+}
 
 void test2 (id object)
 {
   @throw object);  /* { dg-error "expected" } */
   @throw (...);    /* { dg-error "expected" } */
   @throw ();       /* { dg-error "expected" } */
-  @throw           
+  @throw           /* { dg-error "expected" } */
 }                  /* { dg-error "expected" } */
 
 void test3 (id object1, id object2)
index 750710b1f240351bcb44f7f7486461603d5f136f..99677a562443181dd1159ed0d9a4f2fa7d2a8054 100644 (file)
@@ -1,19 +1,19 @@
 /* { dg-do compile } */
 
 @interface A
-{
+{    /* { dg-error "xpected" } */
   ]  /* { dg-error "xpected" } */
 }
 @end
 
 @interface B
-{
+{     /* { dg-error "xpected" } */
   ];  /* { dg-error "xpected" } */
 }
 @end
 
 @interface C
-{
+{     /* { dg-error "xpected" } */
   ];  /* { dg-error "xpected" } */
   int x;
 }
@@ -21,7 +21,7 @@
 
 @interface D
 {
-  (
+  (  /* { dg-error "xpected" } */
 }  /* { dg-error "xpected" } */
 @end
 
index 58882fed8b71acf4000ff4137112d82547ea5074..74be98d39fa0ec6954ad0d5c7180cf2fdfa310c4 100644 (file)
@@ -11,8 +11,8 @@ void test (id object)
   @throw object;   /* Ok */
   @throw;          /* { dg-error ".@throw. .rethrow. used outside of a @catch block" } */
   @throw (object); /* Ok.  */
-  @throw (id)0
-}                  /* { dg-error "expected" } */
+  @throw (id)0     /* { dg-error "expected" } */
+}
 
 void test2 (id object)
 {