2010-11-17 Paolo Bonzini <bonzini@gnu.org>
authorbonzini <bonzini@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 17 Nov 2010 18:17:17 +0000 (18:17 +0000)
committerbonzini <bonzini@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 17 Nov 2010 18:17:17 +0000 (18:17 +0000)
        * c-parser.c (c_token_is_qualifier,
        c_parser_next_token_is_qualifier): New.
        (c_parser_declaration_or_fndef, c_parser_struct_declaration):
        Improve error message on specs->tagdef_seen_p.
        (c_parser_struct_or_union_specifier): Improve error recovery.
        (c_parser_declspecs): Move exit condition on C_ID_ID early.
        Reorganize exit condition for C_ID_TYPENAME/C_ID_CLASSNAME
        using c_parser_next_token_is_qualifier; extend it to cover
        a ctsk_tagdef typespec and !typespec_ok in general.

testsuite:
2010-11-17  Paolo Bonzini  <bonzini@gnu.org>

        * gcc.dg/two-types-1.c: New test.
        * gcc.dg/two-types-2.c: New test.
        * gcc.dg/two-types-3.c: New test.
        * gcc.dg/two-types-4.c: New test.
        * gcc.dg/two-types-5.c: New test.
        * gcc.dg/two-types-6.c: New test.
        * gcc.dg/two-types-7.c: New test.
        * gcc.dg/two-types-8.c: New test.
        * gcc.dg/two-types-9.c: New test.
        * gcc.dg/two-types-10.c: New test.
        * objc.dg/two-types-1.m: New test.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@166874 138bc75d-0d04-0410-961f-82ee72b054a4

14 files changed:
gcc/ChangeLog
gcc/c-parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/two-types-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/two-types-10.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/two-types-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/two-types-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/two-types-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/two-types-5.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/two-types-6.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/two-types-7.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/two-types-8.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/two-types-9.c [new file with mode: 0644]
gcc/testsuite/objc.dg/two-types-1.m [new file with mode: 0644]

index 6018090..bd1e98d 100644 (file)
@@ -1,3 +1,15 @@
+2010-11-17  Paolo Bonzini  <bonzini@gnu.org>
+
+       * c-parser.c (c_token_is_qualifier,
+       c_parser_next_token_is_qualifier): New.
+       (c_parser_declaration_or_fndef, c_parser_struct_declaration):
+       Improve error message on specs->tagdef_seen_p.
+       (c_parser_struct_or_union_specifier): Improve error recovery.
+       (c_parser_declspecs): Move exit condition on C_ID_ID early.
+       Reorganize exit condition for C_ID_TYPENAME/C_ID_CLASSNAME
+       using c_parser_next_token_is_qualifier; extend it to cover
+       a ctsk_tagdef typespec and !typespec_ok in general.
+
 2010-11-17  Richard Guenther  <rguenther@suse.de>
 
        * value-prof.c (gimple_divmod_fixed_value_transform): Update
index 577528d..0c4662a 100644 (file)
@@ -506,6 +506,47 @@ c_parser_next_token_starts_typename (c_parser *parser)
   return c_token_starts_typename (token);
 }
 
+/* Return true if TOKEN is a type qualifier, false otherwise.  */
+static bool
+c_token_is_qualifier (c_token *token)
+{
+  switch (token->type)
+    {
+    case CPP_NAME:
+      switch (token->id_kind)
+       {
+       case C_ID_ADDRSPACE:
+         return true;
+       default:
+         return false;
+       }
+    case CPP_KEYWORD:
+      switch (token->keyword)
+       {
+       case RID_CONST:
+       case RID_VOLATILE:
+       case RID_RESTRICT:
+       case RID_ATTRIBUTE:
+         return true;
+       default:
+         return false;
+       }
+    case CPP_LESS:
+      return false;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Return true if the next token from PARSER is a type qualifier,
+   false otherwise.  */
+static inline bool
+c_parser_next_token_is_qualifier (c_parser *parser)
+{
+  c_token *token = c_parser_peek_token (parser);
+  return c_token_is_qualifier (token);
+}
+
 /* Return true if TOKEN can start declaration specifiers, false
    otherwise.  */
 static bool
@@ -1409,6 +1450,19 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
       c_parser_consume_token (parser);
       return;
     }
+
+  /* Provide better error recovery.  Note that a type name here is usually
+     better diagnosed as a redeclaration.  */
+  if (empty_ok
+      && specs->typespec_kind == ctsk_tagdef
+      && c_parser_next_token_starts_declspecs (parser)
+      && !c_parser_next_token_is (parser, CPP_NAME))
+    {
+      c_parser_error (parser, "expected %<;%>, identifier or %<(%>");
+      parser->error = false;
+      shadow_tag_warned (specs, 1);
+      return;
+    }
   else if (c_dialect_objc ())
     {
       /* Prefix attributes are an error on method decls.  */
@@ -1872,13 +1926,31 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
 {
   bool attrs_ok = start_attr_ok;
   bool seen_type = specs->typespec_kind != ctsk_none;
-  while (c_parser_next_token_is (parser, CPP_NAME)
+  while ((c_parser_next_token_is (parser, CPP_NAME)
+         && c_parser_peek_token (parser)->id_kind != C_ID_ID)
         || c_parser_next_token_is (parser, CPP_KEYWORD)
         || (c_dialect_objc () && c_parser_next_token_is (parser, CPP_LESS)))
     {
       struct c_typespec t;
       tree attrs;
       location_t loc = c_parser_peek_token (parser)->location;
+
+      if (!c_parser_next_token_is_qualifier (parser))
+        {
+         /* Exit for TYPENAMEs after any type because they can appear as a
+            field name.  */
+          if (seen_type && c_parser_next_token_is (parser, CPP_NAME))
+            break;
+
+          /* If we cannot accept a type, and the next token must start one,
+            exit.  Do the same if we already have seen a tagged definition,
+            since it would be an error anyway and likely the user has simply
+            forgotten a semicolon.  */
+          if ((!typespec_ok || specs->typespec_kind == ctsk_tagdef)
+             && c_parser_next_token_starts_typename (parser))
+            break;
+        }
+
       if (c_parser_next_token_is (parser, CPP_NAME))
        {
          tree value = c_parser_peek_token (parser)->value;
@@ -1894,12 +1966,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
              continue;
            }
 
-         /* This finishes the specifiers unless a type name is OK, it
-            is declared as a type name and a type name hasn't yet
-            been seen.  */
-         if (!typespec_ok || seen_type
-             || (kind != C_ID_TYPENAME && kind != C_ID_CLASSNAME))
-           break;
+         /* Now at a C_ID_TYPENAME or C_ID_CLASSNAME.  */
          c_parser_consume_token (parser);
          seen_type = true;
          attrs_ok = true;
@@ -2340,12 +2407,17 @@ c_parser_struct_or_union_specifier (c_parser *parser)
              if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
                pedwarn (c_parser_peek_token (parser)->location, 0,
                         "no semicolon at end of struct or union");
-             else
+             else if (parser->error
+                      || !c_parser_next_token_starts_declspecs (parser))
                {
                  c_parser_error (parser, "expected %<;%>");
                  c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
                  break;
                }
+
+             /* If we come here, we have already emitted an error
+                for an expected `;', identifier or `(', and we also
+                recovered already.  Go on with the next field. */
            }
        }
       postfix_attrs = c_parser_attributes (parser);
@@ -2461,6 +2533,19 @@ c_parser_struct_declaration (c_parser *parser)
        }
       return ret;
     }
+
+  /* Provide better error recovery.  Note that a type name here is valid,
+     and will be treated as a field name.  */
+  if (specs->typespec_kind == ctsk_tagdef
+      && TREE_CODE (specs->type) != ENUMERAL_TYPE
+      && c_parser_next_token_starts_declspecs (parser)
+      && !c_parser_next_token_is (parser, CPP_NAME))
+    {
+      c_parser_error (parser, "expected %<;%>, identifier or %<(%>");
+      parser->error = false;
+      return NULL_TREE;
+    }
+
   pending_xref_error ();
   prefix_attrs = specs->attrs;
   all_prefix_attrs = prefix_attrs;
index 4c94254..571dbc4 100644 (file)
@@ -1,3 +1,17 @@
+2010-11-17  Paolo Bonzini  <bonzini@gnu.org>
+
+       * gcc.dg/two-types-1.c: New test.
+       * gcc.dg/two-types-2.c: New test.
+       * gcc.dg/two-types-3.c: New test.
+       * gcc.dg/two-types-4.c: New test.
+       * gcc.dg/two-types-5.c: New test.
+       * gcc.dg/two-types-6.c: New test.
+       * gcc.dg/two-types-7.c: New test.
+       * gcc.dg/two-types-8.c: New test.
+       * gcc.dg/two-types-9.c: New test.
+       * gcc.dg/two-types-10.c: New test.
+       * objc.dg/two-types-1.m: New test.
+
 2010-11-17  Jakub Jelinek  <jakub@redhat.com>
 
        PR rtl-optimization/46440
diff --git a/gcc/testsuite/gcc.dg/two-types-1.c b/gcc/testsuite/gcc.dg/two-types-1.c
new file mode 100644 (file)
index 0000000..f6160aa
--- /dev/null
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89" } // suppress default -pedantic-errors */
+
+typedef int x, y;
+x y z;                 /* { dg-error "" "" } */
diff --git a/gcc/testsuite/gcc.dg/two-types-10.c b/gcc/testsuite/gcc.dg/two-types-10.c
new file mode 100644 (file)
index 0000000..6c2b79b
--- /dev/null
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89" } // suppress default -pedantic-errors */
+
+typedef enum a { XYZ } a; /* { dg-message "previous declaration" } */
+enum a a;      /* { dg-error "redeclared" } */
+struct b { enum a a : 8; };
diff --git a/gcc/testsuite/gcc.dg/two-types-2.c b/gcc/testsuite/gcc.dg/two-types-2.c
new file mode 100644 (file)
index 0000000..30fcabc
--- /dev/null
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89" } // suppress default -pedantic-errors */
+
+typedef int x, y;
+x struct f z; /* { dg-error "two or more " "" } */
diff --git a/gcc/testsuite/gcc.dg/two-types-3.c b/gcc/testsuite/gcc.dg/two-types-3.c
new file mode 100644 (file)
index 0000000..233f9da
--- /dev/null
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89" } // suppress default -pedantic-errors */
+
+struct f {
+}
+int z(); /* { dg-error "expected ';', identifier or " ""  { target *-*-* }  } */
diff --git a/gcc/testsuite/gcc.dg/two-types-4.c b/gcc/testsuite/gcc.dg/two-types-4.c
new file mode 100644 (file)
index 0000000..1ec734f
--- /dev/null
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89" } // suppress default -pedantic-errors */
+
+int f()
+{
+  struct f {
+  }
+  int z; /* { dg-error "expected ';', identifier or " "" } */
+}
diff --git a/gcc/testsuite/gcc.dg/two-types-5.c b/gcc/testsuite/gcc.dg/two-types-5.c
new file mode 100644 (file)
index 0000000..a127388
--- /dev/null
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89" } // suppress default -pedantic-errors */
+
+struct f {}
+struct g {} /* { dg-error "expected ';', identifier or " "" } */
+int f(); /* { dg-error "expected ';', identifier or " "" } */
diff --git a/gcc/testsuite/gcc.dg/two-types-6.c b/gcc/testsuite/gcc.dg/two-types-6.c
new file mode 100644 (file)
index 0000000..1c55549
--- /dev/null
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89" } // suppress default -pedantic-errors */
+
+struct s {
+  struct f {} /* dg-warning "does not declare anything" "" } */
+  struct g {} x; /* { dg-error "expected ';', identifier or " "" } */
+};
diff --git a/gcc/testsuite/gcc.dg/two-types-7.c b/gcc/testsuite/gcc.dg/two-types-7.c
new file mode 100644 (file)
index 0000000..981c69b
--- /dev/null
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89" } // suppress default -pedantic-errors */
+
+struct s {
+  struct f {}
+  enum a { X } /* { dg-error "expected ';', identifier or " "" } */
+  struct g {} /* { dg-error "expected identifier " "" } */
+}; /* { dg-warning "no semicolon" "" } */
diff --git a/gcc/testsuite/gcc.dg/two-types-8.c b/gcc/testsuite/gcc.dg/two-types-8.c
new file mode 100644 (file)
index 0000000..0103b22
--- /dev/null
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89" } // suppress default -pedantic-errors */
+
+enum x { XYZ }
+struct g { enum x a; }; /* { dg-error "expected ';', identifier or " "" } */
+
+int f(struct g *x)
+{
+  return x->a == XYZ; /* { dg-bogus " has no member " "" } */
+}
diff --git a/gcc/testsuite/gcc.dg/two-types-9.c b/gcc/testsuite/gcc.dg/two-types-9.c
new file mode 100644 (file)
index 0000000..c6da949
--- /dev/null
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89" } // suppress default -pedantic-errors */
+
+struct f {}
+static int a, b; /* { dg-error "expected ';', identifier or " "" } */
+
+int f()
+{
+       return a - b; /* { dg-bogus "invalid operands " "" } */
+}
diff --git a/gcc/testsuite/objc.dg/two-types-1.m b/gcc/testsuite/objc.dg/two-types-1.m
new file mode 100644 (file)
index 0000000..da902a3
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89" } // suppress default -pedantic-errors */
+
+@interface foo
+struct f {}
+struct g { int a; }; /* { dg-error "expected ';', identifier or " "" } */
+
+- (struct f *) a;
+- (struct g *) b;
+@end
+
+int f(struct g *x)
+{
+  return x->a; /* { dg-bogus " has no member " "" } */
+}