C: detect more missing semicolons (PR c/7356)
authorDavid Malcolm <dmalcolm@redhat.com>
Wed, 25 Oct 2017 23:53:41 +0000 (23:53 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Wed, 25 Oct 2017 23:53:41 +0000 (23:53 +0000)
c_parser_declaration_or_fndef has logic for parsing what might be
either a declaration or a function definition.

This patch adds a test to detect cases where a semicolon would have
terminated the decls as a declaration, where the token that follows
would start a new declaration specifier, and updates the error message
accordingly, with a fix-it hint.

This addresses PR c/7356, fixing the case of a stray token before a
#include that previously gave inscrutable output, and improving e.g.:

  int i
  int j;

from:

  t.c:2:1: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'int'
   int j;
   ^~~

to:

  t.c:1:6: error: expected ';' before 'int'
   int i
        ^
        ;
   int j;
   ~~~

gcc.dg/noncompile/920923-1.c needs a slight update, as the output for
the first line changes from:

  920923-1.c:2:14: error: expected '=', ',', ';', 'asm' or
  '__attribute__' before 'unsigned'
   typedef BYTE unsigned char; /* { dg-error "expected" } */
                ^~~~~~~~

to:
  920923-1.c:2:13: error: expected ';' before 'unsigned'
   typedef BYTE unsigned char; /* { dg-error "expected" } */
               ^~~~~~~~~
               ;
  920923-1.c:2:1: warning: useless type name in empty declaration
   typedef BYTE unsigned char; /* { dg-error "expected" } */
   ^~~~~~~

The patch also adds a test for PR c/44515 as a baseline.

gcc/c/ChangeLog:
PR c/7356
* c-parser.c (c_parser_declaration_or_fndef): Detect missing
semicolons.

gcc/testsuite/ChangeLog:
PR c/7356
PR c/44515
* c-c++-common/pr44515.c: New test case.
* gcc.dg/pr7356-2.c: New test case.
* gcc.dg/pr7356.c: New test case.
* gcc.dg/spellcheck-typenames.c: Update the "singed" char "TODO"
case to reflect changes to output.
* gcc.dg/noncompile/920923-1.c: Add dg-warning to reflect changes
to output.

From-SVN: r254093

gcc/c/ChangeLog
gcc/c/c-parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/pr44515.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/noncompile/920923-1.c
gcc/testsuite/gcc.dg/pr7356-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr7356.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/spellcheck-typenames.c

index b4fde0d..5d028b4 100644 (file)
@@ -1,3 +1,9 @@
+2017-10-25  David Malcolm  <dmalcolm@redhat.com>
+
+       PR c/7356
+       * c-parser.c (c_parser_declaration_or_fndef): Detect missing
+       semicolons.
+
 2017-10-25  Jakub Jelinek  <jakub@redhat.com>
 
        PR libstdc++/81706
index 6b84324..68c45fd 100644 (file)
@@ -2241,11 +2241,37 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
        }
       if (!start_function (specs, declarator, all_prefix_attrs))
        {
-         /* This can appear in many cases looking nothing like a
-            function definition, so we don't give a more specific
-            error suggesting there was one.  */
-         c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, %<asm%> "
-                         "or %<__attribute__%>");
+         /* At this point we've consumed:
+              declaration-specifiers declarator
+            and the next token isn't CPP_EQ, CPP_COMMA, CPP_SEMICOLON,
+            RID_ASM, RID_ATTRIBUTE, or RID_IN,
+            but the
+              declaration-specifiers declarator
+            aren't grokkable as a function definition, so we have
+            an error.  */
+         gcc_assert (!c_parser_next_token_is (parser, CPP_SEMICOLON));
+         if (c_parser_next_token_starts_declspecs (parser))
+           {
+             /* If we have
+                  declaration-specifiers declarator decl-specs
+                then assume we have a missing semicolon, which would
+                give us:
+                  declaration-specifiers declarator  decl-specs
+                                                   ^
+                                                   ;
+                  <~~~~~~~~~ declaration ~~~~~~~~~~>
+                Use c_parser_require to get an error with a fix-it hint.  */
+             c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>");
+             parser->error = false;
+           }
+         else
+           {
+             /* This can appear in many cases looking nothing like a
+                function definition, so we don't give a more specific
+                error suggesting there was one.  */
+             c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, %<asm%> "
+                             "or %<__attribute__%>");
+           }
          if (nested)
            c_pop_function_context ();
          break;
index 443e7c7..e2f7e4d 100644 (file)
@@ -1,3 +1,15 @@
+2017-10-25  David Malcolm  <dmalcolm@redhat.com>
+
+       PR c/7356
+       PR c/44515
+       * c-c++-common/pr44515.c: New test case.
+       * gcc.dg/pr7356-2.c: New test case.
+       * gcc.dg/pr7356.c: New test case.
+       * gcc.dg/spellcheck-typenames.c: Update the "singed" char "TODO"
+       case to reflect changes to output.
+       * gcc.dg/noncompile/920923-1.c: Add dg-warning to reflect changes
+       to output.
+
 2017-10-25  Eric Botcazou  <ebotcazou@adacore.com>
 
        * gcc.dg/fold-cond_expr-1.c: Rename to...
diff --git a/gcc/testsuite/c-c++-common/pr44515.c b/gcc/testsuite/c-c++-common/pr44515.c
new file mode 100644 (file)
index 0000000..dbb7750
--- /dev/null
@@ -0,0 +1,14 @@
+/* { dg-options "-fdiagnostics-show-caret" } */
+
+void bar(void);
+void foo(void)
+{
+  bar() /* { dg-error "expected ';' before '.' token" } */
+}
+/* { dg-begin-multiline-output "" }
+   bar()
+        ^
+        ;
+ }
+ ~       
+   { dg-end-multiline-output "" } */
index 1cb140e..006a071 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-message "undeclared identifier is reported only once" "reminder for mmu_base" { target *-*-* } 0 } */
 typedef BYTE unsigned char;    /* { dg-error "expected" } */
+/* { dg-warning "useless type name in empty declaration" ""  { target *-*-* } .-1 } */
 typedef int item_n;
 typedef int perm_set;
 struct PENT { caddr_t v_addr; };/* { dg-error "unknown type name" } */
diff --git a/gcc/testsuite/gcc.dg/pr7356-2.c b/gcc/testsuite/gcc.dg/pr7356-2.c
new file mode 100644 (file)
index 0000000..ad67975
--- /dev/null
@@ -0,0 +1,33 @@
+/* { dg-options "-fdiagnostics-show-caret" } */
+
+int i /* { dg-error "6: expected ';' before 'int'" } */
+int j;
+/* { dg-begin-multiline-output "" }
+ int i 
+      ^
+      ;
+ int j;
+ ~~~   
+   { dg-end-multiline-output "" } */
+
+
+void test (void)
+{
+  int i /* { dg-error "8: expected ';' before 'int'" } */
+  int j;
+
+  /* { dg-begin-multiline-output "" }
+   int i 
+        ^
+        ;
+   int j;
+   ~~~   
+     { dg-end-multiline-output "" } */
+}
+
+int old_style_params (first, second)
+     int first;
+     int second;
+{
+  return first + second;
+}
diff --git a/gcc/testsuite/gcc.dg/pr7356.c b/gcc/testsuite/gcc.dg/pr7356.c
new file mode 100644 (file)
index 0000000..84baf07
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-options "-fdiagnostics-show-caret" } */
+
+a /* { dg-line stray_token } */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+int main(int argc, char** argv)
+{
+  return 0;
+}
+
+/* { dg-error "expected ';' before '.*'" "" { target *-*-* } stray_token } */
+/* { dg-begin-multiline-output "" }
+ a
+  ^
+  ;
+   { dg-end-multiline-output "" } */
index f3b8102..3717ad8 100644 (file)
@@ -100,8 +100,9 @@ baz value; /* { dg-error "1: unknown type name .baz.; use .enum. keyword to refe
    { dg-end-multiline-output "" } */
 
 /* TODO: it would be better to detect the "singed" vs "signed" typo here.  */
-singed char ch; /* { dg-error "8: before .char." } */
+singed char ch; /* { dg-error "7: before .char." } */
 /* { dg-begin-multiline-output "" }
  singed char ch;
-        ^~~~
+       ^~~~~
+       ;
    { dg-end-multiline-output "" } */