diff options
-rw-r--r-- | gcc/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/c-parser.c | 101 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 14 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/two-types-1.c | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/two-types-10.c | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/two-types-2.c | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/two-types-3.c | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/two-types-4.c | 9 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/two-types-5.c | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/two-types-6.c | 7 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/two-types-7.c | 8 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/two-types-8.c | 10 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/two-types-9.c | 10 | ||||
-rw-r--r-- | gcc/testsuite/objc.dg/two-types-1.m | 15 |
14 files changed, 206 insertions, 8 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6018090..bd1e98d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/c-parser.c b/gcc/c-parser.c index 577528d..0c4662a 100644 --- a/gcc/c-parser.c +++ b/gcc/c-parser.c @@ -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; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4c94254..571dbc4 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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 index 0000000..f6160aa --- /dev/null +++ b/gcc/testsuite/gcc.dg/two-types-1.c @@ -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 index 0000000..6c2b79b --- /dev/null +++ b/gcc/testsuite/gcc.dg/two-types-10.c @@ -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 index 0000000..30fcabc --- /dev/null +++ b/gcc/testsuite/gcc.dg/two-types-2.c @@ -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 index 0000000..233f9da --- /dev/null +++ b/gcc/testsuite/gcc.dg/two-types-3.c @@ -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 index 0000000..1ec734f --- /dev/null +++ b/gcc/testsuite/gcc.dg/two-types-4.c @@ -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 index 0000000..a127388 --- /dev/null +++ b/gcc/testsuite/gcc.dg/two-types-5.c @@ -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 index 0000000..1c55549 --- /dev/null +++ b/gcc/testsuite/gcc.dg/two-types-6.c @@ -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 index 0000000..981c69b --- /dev/null +++ b/gcc/testsuite/gcc.dg/two-types-7.c @@ -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 index 0000000..0103b22 --- /dev/null +++ b/gcc/testsuite/gcc.dg/two-types-8.c @@ -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 index 0000000..c6da949 --- /dev/null +++ b/gcc/testsuite/gcc.dg/two-types-9.c @@ -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 index 0000000..da902a3 --- /dev/null +++ b/gcc/testsuite/objc.dg/two-types-1.m @@ -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 " "" } */ +} |