diff options
author | Paolo Bonzini <bonzini@gnu.org> | 2010-11-17 18:17:17 +0000 |
---|---|---|
committer | Paolo Bonzini <bonzini@gcc.gnu.org> | 2010-11-17 18:17:17 +0000 |
commit | f725e72170f4db044404007b3c33bebf3cc7600c (patch) | |
tree | 7f20a50b2e03297314d83ada80da9cddc61f1427 /gcc/c-parser.c | |
parent | 0197bf54a19f23c0bcb3fb2e38965db7f9434aaf (diff) | |
download | gcc-f725e72170f4db044404007b3c33bebf3cc7600c.zip gcc-f725e72170f4db044404007b3c33bebf3cc7600c.tar.gz gcc-f725e72170f4db044404007b3c33bebf3cc7600c.tar.bz2 |
c-parser.c (c_token_is_qualifier, [...]): New.
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.
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.
From-SVN: r166874
Diffstat (limited to 'gcc/c-parser.c')
-rw-r--r-- | gcc/c-parser.c | 101 |
1 files changed, 93 insertions, 8 deletions
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; |