X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=4925adf0259ff39d0f2fb74831165a9a11bd5d41;hb=2788e437530378ada31a28484ec49a9eeb05faf2;hp=ed42823aec77347713202ed9c85fe32becfd02b2;hpb=a71054fa6ac24d348860ceaaa3baec2eee6d801d;p=cparser diff --git a/parser.c b/parser.c index ed42823..4925adf 100644 --- a/parser.c +++ b/parser.c @@ -108,6 +108,7 @@ static declaration_t *last_declaration = NULL; static declaration_t *current_function = NULL; static switch_statement_t *current_switch = NULL; static statement_t *current_loop = NULL; +static statement_t *current_parent = NULL; static ms_try_statement_t *current_try = NULL; static goto_statement_t *goto_first = NULL; static goto_statement_t *goto_last = NULL; @@ -116,6 +117,11 @@ static label_statement_t *label_last = NULL; static translation_unit_t *unit = NULL; static struct obstack temp_obst; +#define PUSH_PARENT(stmt) \ + statement_t *const prev_parent = current_parent; \ + current_parent = (stmt); +#define POP_PARENT ((void)(current_parent = prev_parent)) + static source_position_t null_position = { NULL, 0 }; /* symbols for Microsoft extended-decl-modifier */ @@ -165,7 +171,8 @@ static void semantic_comparison(binary_expression_t *expression); case T_extern: \ case T_static: \ case T_auto: \ - case T_register: + case T_register: \ + case T___thread: #define TYPE_QUALIFIERS \ case T_const: \ @@ -320,7 +327,8 @@ static statement_t *allocate_statement_zero(statement_kind_t kind) size_t size = get_statement_struct_size(kind); statement_t *res = allocate_ast_zero(size); - res->base.kind = kind; + res->base.kind = kind; + res->base.parent = current_parent; return res; } @@ -499,19 +507,22 @@ static inline const token_t *look_ahead(int num) /** * Adds a token to the token anchor set (a multi-set). */ -static void add_anchor_token(int token_type) { +static void add_anchor_token(int token_type) +{ assert(0 <= token_type && token_type < T_LAST_TOKEN); ++token_anchor_set[token_type]; } -static int save_and_reset_anchor_state(int token_type) { +static int save_and_reset_anchor_state(int token_type) +{ assert(0 <= token_type && token_type < T_LAST_TOKEN); int count = token_anchor_set[token_type]; token_anchor_set[token_type] = 0; return count; } -static void restore_anchor_state(int token_type, int count) { +static void restore_anchor_state(int token_type, int count) +{ assert(0 <= token_type && token_type < T_LAST_TOKEN); token_anchor_set[token_type] = count; } @@ -519,12 +530,14 @@ static void restore_anchor_state(int token_type, int count) { /** * Remove a token from the token anchor set (a multi-set). */ -static void rem_anchor_token(int token_type) { +static void rem_anchor_token(int token_type) +{ assert(0 <= token_type && token_type < T_LAST_TOKEN); --token_anchor_set[token_type]; } -static bool at_anchor(void) { +static bool at_anchor(void) +{ if (token.type < 0) return false; return token_anchor_set[token.type]; @@ -533,11 +546,8 @@ static bool at_anchor(void) { /** * Eat tokens until a matching token is found. */ -static void eat_until_matching_token(int type) { - unsigned parenthesis_count = 0; - unsigned brace_count = 0; - unsigned bracket_count = 0; - +static void eat_until_matching_token(int type) +{ int end_token; switch (type) { case '(': end_token = ')'; break; @@ -546,26 +556,40 @@ static void eat_until_matching_token(int type) { default: end_token = type; break; } - while(token.type != end_token || - (parenthesis_count > 0 || brace_count > 0 || bracket_count > 0)) { - - switch(token.type) { + unsigned parenthesis_count = 0; + unsigned brace_count = 0; + unsigned bracket_count = 0; + while (token.type != end_token || + parenthesis_count != 0 || + brace_count != 0 || + bracket_count != 0) { + switch (token.type) { case T_EOF: return; case '(': ++parenthesis_count; break; case '{': ++brace_count; break; case '[': ++bracket_count; break; + case ')': if (parenthesis_count > 0) --parenthesis_count; - break; + goto check_stop; + case '}': if (brace_count > 0) --brace_count; - break; + goto check_stop; + case ']': if (bracket_count > 0) --bracket_count; +check_stop: + if (token.type == end_token && + parenthesis_count == 0 && + brace_count == 0 && + bracket_count == 0) + return; break; + default: break; } @@ -576,10 +600,11 @@ static void eat_until_matching_token(int type) { /** * Eat input tokens until an anchor is found. */ -static void eat_until_anchor(void) { +static void eat_until_anchor(void) +{ if (token.type == T_EOF) return; - while(token_anchor_set[token.type] == 0) { + while (token_anchor_set[token.type] == 0) { if (token.type == '(' || token.type == '{' || token.type == '[') eat_until_matching_token(token.type); if (token.type == T_EOF) @@ -588,7 +613,8 @@ static void eat_until_anchor(void) { } } -static void eat_block(void) { +static void eat_block(void) +{ eat_until_matching_token('{'); if (token.type == '}') next_token(); @@ -597,13 +623,14 @@ static void eat_block(void) { /** * eat all token until a ';' is reached or a stop token is found. */ -static void eat_statement(void) { +static void eat_statement(void) +{ eat_until_matching_token(';'); if (token.type == ';') next_token(); } -#define eat(token_type) do { assert(token.type == token_type); next_token(); } while(0) +#define eat(token_type) do { assert(token.type == token_type); next_token(); } while (0) /** * Report a parse error because an expected token was not found. @@ -659,7 +686,7 @@ static void type_error_incompatible(const char *msg, goto end_error; \ } \ next_token(); \ - } while(0) + } while (0) static void set_scope(scope_t *new_scope) { @@ -1076,7 +1103,7 @@ static string_t parse_string_literals(void) return result; } -static const char *gnu_attribute_names[GNU_AK_LAST] = { +static const char *const gnu_attribute_names[GNU_AK_LAST] = { [GNU_AK_CONST] = "const", [GNU_AK_VOLATILE] = "volatile", [GNU_AK_CDECL] = "cdecl", @@ -1090,7 +1117,7 @@ static const char *gnu_attribute_names[GNU_AK_LAST] = { [GNU_AK_ALWAYS_INLINE] = "always_inline", [GNU_AK_MALLOC] = "malloc", [GNU_AK_WEAK] = "weak", - [GNU_AK_CONSTRUCTOR] = "constructor", + [GNU_AK_CONSTRUCTOR] = "constructor", [GNU_AK_DESTRUCTOR] = "destructor", [GNU_AK_NOTHROW] = "nothrow", [GNU_AK_TRANSPARENT_UNION] = "transparent_union", @@ -1104,15 +1131,15 @@ static const char *gnu_attribute_names[GNU_AK_LAST] = { [GNU_AK_NO_INSTRUMENT_FUNCTION] = "no_instrument_function", [GNU_AK_WARN_UNUSED_RESULT] = "warn_unused_result", [GNU_AK_LONGCALL] = "longcall", - [GNU_AK_SHORTCALL] = "shortcall", + [GNU_AK_SHORTCALL] = "shortcall", [GNU_AK_LONG_CALL] = "long_call", - [GNU_AK_SHORT_CALL] = "short_call", + [GNU_AK_SHORT_CALL] = "short_call", [GNU_AK_FUNCTION_VECTOR] = "function_vector", - [GNU_AK_INTERRUPT] = "interrupt", - [GNU_AK_INTERRUPT_HANDLER] = "interrupt_handler", - [GNU_AK_NMI_HANDLER] = "nmi_handler", - [GNU_AK_NESTING] = "nesting", - [GNU_AK_NEAR] = "near", + [GNU_AK_INTERRUPT] = "interrupt", + [GNU_AK_INTERRUPT_HANDLER] = "interrupt_handler", + [GNU_AK_NMI_HANDLER] = "nmi_handler", + [GNU_AK_NESTING] = "nesting", + [GNU_AK_NEAR] = "near", [GNU_AK_FAR] = "far", [GNU_AK_SIGNAL] = "signal", [GNU_AK_EIGTHBIT_DATA] = "eightbit_data", @@ -1147,7 +1174,8 @@ static const char *gnu_attribute_names[GNU_AK_LAST] = { /** * compare two string, ignoring double underscores on the second. */ -static int strcmp_underscore(const char *s1, const char *s2) { +static int strcmp_underscore(const char *s1, const char *s2) +{ if (s2[0] == '_' && s2[1] == '_') { size_t len2 = strlen(s2); size_t len1 = strlen(s1); @@ -1162,7 +1190,8 @@ static int strcmp_underscore(const char *s1, const char *s2) { /** * Allocate a new gnu temporal attribute. */ -static gnu_attribute_t *allocate_gnu_attribute(gnu_attribute_kind_t kind) { +static gnu_attribute_t *allocate_gnu_attribute(gnu_attribute_kind_t kind) +{ gnu_attribute_t *attribute = obstack_alloc(&temp_obst, sizeof(*attribute)); attribute->kind = kind; attribute->next = NULL; @@ -1175,7 +1204,8 @@ static gnu_attribute_t *allocate_gnu_attribute(gnu_attribute_kind_t kind) { /** * parse one constant expression argument. */ -static void parse_gnu_attribute_const_arg(gnu_attribute_t *attribute) { +static void parse_gnu_attribute_const_arg(gnu_attribute_t *attribute) +{ expression_t *expression; add_anchor_token(')'); expression = parse_constant_expression(); @@ -1190,7 +1220,8 @@ end_error: /** * parse a list of constant expressions arguments. */ -static void parse_gnu_attribute_const_arg_list(gnu_attribute_t *attribute) { +static void parse_gnu_attribute_const_arg_list(gnu_attribute_t *attribute) +{ argument_list_t **list = &attribute->u.arguments; argument_list_t *entry; expression_t *expression; @@ -1238,8 +1269,9 @@ end_error: /** * parse one tls model. */ -static void parse_gnu_attribute_tls_model_arg(gnu_attribute_t *attribute) { - static const char *tls_models[] = { +static void parse_gnu_attribute_tls_model_arg(gnu_attribute_t *attribute) +{ + static const char *const tls_models[] = { "global-dynamic", "local-dynamic", "initial-exec", @@ -1262,8 +1294,9 @@ static void parse_gnu_attribute_tls_model_arg(gnu_attribute_t *attribute) { /** * parse one tls model. */ -static void parse_gnu_attribute_visibility_arg(gnu_attribute_t *attribute) { - static const char *visibilities[] = { +static void parse_gnu_attribute_visibility_arg(gnu_attribute_t *attribute) +{ + static const char *const visibilities[] = { "default", "protected", "hidden", @@ -1286,8 +1319,9 @@ static void parse_gnu_attribute_visibility_arg(gnu_attribute_t *attribute) { /** * parse one (code) model. */ -static void parse_gnu_attribute_model_arg(gnu_attribute_t *attribute) { - static const char *visibilities[] = { +static void parse_gnu_attribute_model_arg(gnu_attribute_t *attribute) +{ + static const char *const visibilities[] = { "small", "medium", "large" @@ -1348,8 +1382,9 @@ end_error: /** * parse one interrupt argument. */ -static void parse_gnu_attribute_interrupt_arg(gnu_attribute_t *attribute) { - static const char *interrupts[] = { +static void parse_gnu_attribute_interrupt_arg(gnu_attribute_t *attribute) +{ + static const char *const interrupts[] = { "IRQ", "FIQ", "SWI", @@ -1373,8 +1408,9 @@ static void parse_gnu_attribute_interrupt_arg(gnu_attribute_t *attribute) { /** * parse ( identifier, const expression, const expression ) */ -static void parse_gnu_attribute_format_args(gnu_attribute_t *attribute) { - static const char *format_names[] = { +static void parse_gnu_attribute_format_args(gnu_attribute_t *attribute) +{ + static const char *const format_names[] = { "printf", "scanf", "strftime", @@ -1517,12 +1553,12 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) if (token.type != ')') { /* find the end of the list */ if (last != NULL) { - while(last->next != NULL) + while (last->next != NULL) last = last->next; } /* non-empty attribute list */ - while(true) { + while (true) { const char *name; if (token.type == T_const) { name = "const"; @@ -1580,7 +1616,6 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) case GNU_AK_NOCOMMON: case GNU_AK_SHARED: case GNU_AK_NOTSHARED: - case GNU_AK_UNUSED: case GNU_AK_NO_INSTRUMENT_FUNCTION: case GNU_AK_WARN_UNUSED_RESULT: case GNU_AK_LONGCALL: @@ -1609,6 +1644,7 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) case GNU_AK_CDECL: modifiers |= DM_CDECL; goto no_arg; case GNU_AK_FASTCALL: modifiers |= DM_FASTCALL; goto no_arg; case GNU_AK_STDCALL: modifiers |= DM_STDCALL; goto no_arg; + case GNU_AK_UNUSED: modifiers |= DM_UNUSED; goto no_arg; case GNU_AK_USED: modifiers |= DM_USED; goto no_arg; case GNU_AK_PURE: modifiers |= DM_PURE; goto no_arg; case GNU_AK_ALWAYS_INLINE: modifiers |= DM_FORCEINLINE; goto no_arg; @@ -1743,7 +1779,7 @@ static decl_modifiers_t parse_attributes(gnu_attribute_t **attributes) { decl_modifiers_t modifiers = 0; - while(true) { + while (true) { switch(token.type) { case T___attribute__: modifiers |= parse_gnu_attribute(attributes); @@ -1785,7 +1821,7 @@ static designator_t *parse_designation(void) designator_t *result = NULL; designator_t *last = NULL; - while(true) { + while (true) { designator_t *designator; switch(token.type) { case '[': @@ -1949,7 +1985,7 @@ static initializer_t *parse_scalar_initializer(type_t *type, } bool additional_warning_displayed = false; - while(braces > 0) { + while (braces > 0) { if (token.type == ',') { next_token(); } @@ -2008,7 +2044,7 @@ static __attribute__((unused)) void debug_print_type_path( } fprintf(stderr, ".%s", entry->v.compound_entry->symbol->string); } else if (is_type_array(type)) { - fprintf(stderr, "[%zd]", entry->v.index); + fprintf(stderr, "[%zu]", entry->v.index); } else { fprintf(stderr, "-INVALID-"); } @@ -2098,7 +2134,7 @@ static void ascend_to(type_path_t *path, size_t top_path_level) { size_t len = ARR_LEN(path->path); - while(len > top_path_level) { + while (len > top_path_level) { ascend_from_subtype(path); len = ARR_LEN(path->path); } @@ -2241,8 +2277,9 @@ static void advance_current_object(type_path_t *path, size_t top_path_level) /** * skip until token is found. */ -static void skip_until(int type) { - while(token.type != type) { +static void skip_until(int type) +{ + while (token.type != type) { if (token.type == T_EOF) return; next_token(); @@ -2257,7 +2294,7 @@ static void skip_initializers(void) if (token.type == '{') next_token(); - while(token.type != '}') { + while (token.type != '}') { if (token.type == T_EOF) return; if (token.type == '{') { @@ -2305,11 +2342,20 @@ static initializer_t *parse_sub_initializer(type_path_t *path, initializer_t **initializers = NEW_ARR_F(initializer_t*, 0); - while(true) { + while (true) { designator_t *designator = NULL; if (token.type == '.' || token.type == '[') { designator = parse_designation(); + goto finish_designator; + } else if (token.type == T_IDENTIFIER && look_ahead(1)->type == ':') { + /* GNU-style designator ("identifier: value") */ + designator = allocate_ast_zero(sizeof(designator[0])); + designator->source_position = token.source_position; + designator->symbol = token.v.symbol; + eat(T_IDENTIFIER); + eat(':'); +finish_designator: /* reset path to toplevel, evaluate designator from there */ ascend_to(path, top_path_level); if (!walk_designator(path, designator, false)) { @@ -2390,7 +2436,7 @@ static initializer_t *parse_sub_initializer(type_path_t *path, } /* descend into subtypes until expression matches type */ - while(true) { + while (true) { orig_type = path->top_type; type = skip_typeref(orig_type); @@ -2671,7 +2717,7 @@ static void parse_enum_entries(type_t *const enum_type) if (token.type != ',') break; next_token(); - } while(token.type != '}'); + } while (token.type != '}'); rem_anchor_token('}'); expect('}'); @@ -2755,11 +2801,11 @@ static type_t *parse_typeof(void) restart: switch(token.type) { case T___extension__: - /* this can be a prefix to a typename or an expression */ - /* we simply eat it now. */ + /* This can be a prefix to a typename or an expression. We simply eat + * it now. */ do { next_token(); - } while(token.type == T___extension__); + } while (token.type == T___extension__); goto restart; case T_IDENTIFIER: @@ -2845,7 +2891,8 @@ static type_t *get_typedef_type(symbol_t *symbol) /** * check for the allowed MS alignment values. */ -static bool check_elignment_value(long long intvalue) { +static bool check_alignment_value(long long intvalue) +{ if (intvalue < 1 || intvalue > 8192) { errorf(HERE, "illegal alignment value"); return false; @@ -2862,13 +2909,13 @@ static bool check_elignment_value(long long intvalue) { #define DET_MOD(name, tag) do { \ if (*modifiers & tag) warningf(HERE, #name " used more than once"); \ *modifiers |= tag; \ -} while(0) +} while (0) static void parse_microsoft_extended_decl_modifier(declaration_specifiers_t *specifiers) { decl_modifiers_t *modifiers = &specifiers->modifiers; - while(true) { + while (true) { if (token.type == T_restrict) { next_token(); DET_MOD(restrict, DM_RESTRICT); @@ -2881,7 +2928,7 @@ static void parse_microsoft_extended_decl_modifier(declaration_specifiers_t *spe expect('('); if (token.type != T_INTEGER) goto end_error; - if (check_elignment_value(token.v.intvalue)) { + if (check_alignment_value(token.v.intvalue)) { if (specifiers->alignment != 0) warningf(HERE, "align used more than once"); specifiers->alignment = (unsigned char)token.v.intvalue; @@ -3010,7 +3057,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) specifiers->source_position = token.source_position; - while(true) { + while (true) { specifiers->modifiers |= parse_attributes(&specifiers->gnu_attributes); if (specifiers->modifiers & DM_TRANSPARENT_UNION) @@ -3069,7 +3116,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) case token: \ qualifiers |= qualifier; \ next_token(); \ - break; + break MATCH_TYPE_QUALIFIER(T_const, TYPE_QUALIFIER_CONST); MATCH_TYPE_QUALIFIER(T_restrict, TYPE_QUALIFIER_RESTRICT); @@ -3094,28 +3141,29 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) } else { \ type_specifiers |= specifier; \ } \ - break; - - MATCH_SPECIFIER(T_void, SPECIFIER_VOID, "void") - MATCH_SPECIFIER(T_char, SPECIFIER_CHAR, "char") - MATCH_SPECIFIER(T_short, SPECIFIER_SHORT, "short") - MATCH_SPECIFIER(T_int, SPECIFIER_INT, "int") - MATCH_SPECIFIER(T_float, SPECIFIER_FLOAT, "float") - MATCH_SPECIFIER(T_double, SPECIFIER_DOUBLE, "double") - MATCH_SPECIFIER(T_signed, SPECIFIER_SIGNED, "signed") - MATCH_SPECIFIER(T_unsigned, SPECIFIER_UNSIGNED, "unsigned") - MATCH_SPECIFIER(T__Bool, SPECIFIER_BOOL, "_Bool") - MATCH_SPECIFIER(T__int8, SPECIFIER_INT8, "_int8") - MATCH_SPECIFIER(T__int16, SPECIFIER_INT16, "_int16") - MATCH_SPECIFIER(T__int32, SPECIFIER_INT32, "_int32") - MATCH_SPECIFIER(T__int64, SPECIFIER_INT64, "_int64") - MATCH_SPECIFIER(T__int128, SPECIFIER_INT128, "_int128") - MATCH_SPECIFIER(T__Complex, SPECIFIER_COMPLEX, "_Complex") - MATCH_SPECIFIER(T__Imaginary, SPECIFIER_IMAGINARY, "_Imaginary") + break + + MATCH_SPECIFIER(T_void, SPECIFIER_VOID, "void"); + MATCH_SPECIFIER(T_char, SPECIFIER_CHAR, "char"); + MATCH_SPECIFIER(T_short, SPECIFIER_SHORT, "short"); + MATCH_SPECIFIER(T_int, SPECIFIER_INT, "int"); + MATCH_SPECIFIER(T_float, SPECIFIER_FLOAT, "float"); + MATCH_SPECIFIER(T_double, SPECIFIER_DOUBLE, "double"); + MATCH_SPECIFIER(T_signed, SPECIFIER_SIGNED, "signed"); + MATCH_SPECIFIER(T_unsigned, SPECIFIER_UNSIGNED, "unsigned"); + MATCH_SPECIFIER(T__Bool, SPECIFIER_BOOL, "_Bool"); + MATCH_SPECIFIER(T__int8, SPECIFIER_INT8, "_int8"); + MATCH_SPECIFIER(T__int16, SPECIFIER_INT16, "_int16"); + MATCH_SPECIFIER(T__int32, SPECIFIER_INT32, "_int32"); + MATCH_SPECIFIER(T__int64, SPECIFIER_INT64, "_int64"); + MATCH_SPECIFIER(T__int128, SPECIFIER_INT128, "_int128"); + MATCH_SPECIFIER(T__Complex, SPECIFIER_COMPLEX, "_Complex"); + MATCH_SPECIFIER(T__Imaginary, SPECIFIER_IMAGINARY, "_Imaginary"); case T__forceinline: /* only in microsoft mode */ specifiers->modifiers |= DM_FORCEINLINE; + /* FALLTHROUGH */ case T_inline: next_token(); @@ -3369,7 +3417,7 @@ static type_qualifiers_t parse_type_qualifiers(void) { type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE; - while(true) { + while (true) { switch(token.type) { /* type qualifiers */ MATCH_TYPE_QUALIFIER(T_const, TYPE_QUALIFIER_CONST); @@ -3410,7 +3458,7 @@ static declaration_t *parse_identifier_list(void) break; } next_token(); - } while(token.type == T_IDENTIFIER); + } while (token.type == T_IDENTIFIER); return declarations; } @@ -3482,7 +3530,7 @@ static declaration_t *parse_parameters(function_type_t *type) function_parameter_t *parameter; function_parameter_t *last_parameter = NULL; - while(true) { + while (true) { switch(token.type) { case T_DOTDOTDOT: next_token(); @@ -3718,10 +3766,10 @@ static construct_type_t *parse_inner_declarator(declaration_t *declaration, construct_type_t *last = NULL; gnu_attribute_t *attributes = NULL; - decl_modifiers_t modifiers = parse_attributes(&attributes); + declaration->modifiers |= parse_attributes(&attributes); /* pointers */ - while(token.type == '*') { + while (token.type == '*') { construct_type_t *type = parse_pointer_declarator(); if (last == NULL) { @@ -3733,7 +3781,7 @@ static construct_type_t *parse_inner_declarator(declaration_t *declaration, } /* TODO: find out if this is correct */ - modifiers |= parse_attributes(&attributes); + declaration->modifiers |= parse_attributes(&attributes); } construct_type_t *inner_types = NULL; @@ -4042,11 +4090,11 @@ static void check_type_of_main(const declaration_t *const decl, const function_t "third argument of 'main' should be 'char**', but is '%T'", third_type); } parm = parm->next; - if (parm != NULL) { - warningf(&decl->source_position, "'main' takes only zero, two or three arguments"); - } + if (parm != NULL) + goto warn_arg_count; } } else { +warn_arg_count: warningf(&decl->source_position, "'main' takes only zero, two or three arguments"); } } @@ -4108,6 +4156,16 @@ static declaration_t *internal_record_declaration( return previous_declaration; } + if (warning.redundant_decls && + is_definition && + previous_declaration->storage_class == STORAGE_CLASS_STATIC && + !(previous_declaration->modifiers & DM_USED) && + !previous_declaration->used) { + warningf(&previous_declaration->source_position, + "unnecessary static forward declaration for '%#T'", + previous_declaration->type, symbol); + } + unsigned new_storage_class = declaration->storage_class; if (is_type_incomplete(prev_type)) { @@ -4181,8 +4239,8 @@ warn_redundant_declaration: } } - if (declaration->is_inline) - previous_declaration->is_inline = true; + previous_declaration->modifiers |= declaration->modifiers; + previous_declaration->is_inline |= declaration->is_inline; return previous_declaration; } else if (is_type_function(type)) { if (is_definition && @@ -4525,7 +4583,8 @@ static bool first_err = true; * When called with first_err set, prints the name of the current function, * else does noting. */ -static void print_in_function(void) { +static void print_in_function(void) +{ if (first_err) { first_err = false; diagnosticf("%s: In function '%Y':\n", @@ -4591,6 +4650,423 @@ static void check_declarations(void) } } +static int determine_truth(expression_t const* const cond) +{ + return + !is_constant_expression(cond) ? 0 : + fold_constant(cond) != 0 ? 1 : + -1; +} + +static void check_reachable(statement_t *const stmt) +{ + if (stmt->base.reachable) + return; + if (stmt->kind != STATEMENT_DO_WHILE) + stmt->base.reachable = true; + + statement_t *last = stmt; + statement_t *next; + switch (stmt->kind) { + case STATEMENT_INVALID: + case STATEMENT_EMPTY: + case STATEMENT_DECLARATION: + case STATEMENT_ASM: + next = stmt->base.next; + break; + + case STATEMENT_COMPOUND: + next = stmt->compound.statements; + break; + + case STATEMENT_RETURN: + return; + + case STATEMENT_IF: { + if_statement_t const* const ifs = &stmt->ifs; + int const val = determine_truth(ifs->condition); + + if (val >= 0) + check_reachable(ifs->true_statement); + + if (val > 0) + return; + + if (ifs->false_statement != NULL) { + check_reachable(ifs->false_statement); + return; + } + + next = stmt->base.next; + break; + } + + case STATEMENT_SWITCH: { + switch_statement_t const *const switchs = &stmt->switchs; + expression_t const *const expr = switchs->expression; + + if (is_constant_expression(expr)) { + long const val = fold_constant(expr); + case_label_statement_t * defaults = NULL; + for (case_label_statement_t *i = switchs->first_case; i != NULL; i = i->next) { + if (i->expression == NULL) { + defaults = i; + continue; + } + + expression_t *const case_expr = i->expression; + if (is_constant_expression(case_expr) && + fold_constant(case_expr) == val) { + check_reachable((statement_t*)i); + return; + } + } + + if (defaults != NULL) { + check_reachable((statement_t*)defaults); + return; + } + } else { + bool has_default = false; + for (case_label_statement_t *i = switchs->first_case; i != NULL; i = i->next) { + if (i->expression == NULL) + has_default = true; + + check_reachable((statement_t*)i); + } + + if (has_default) + return; + } + + next = stmt->base.next; + break; + } + + case STATEMENT_EXPRESSION: { + /* Check for noreturn function call */ + expression_t const *const expr = stmt->expression.expression; + if (expr->kind == EXPR_CALL) { + expression_t const *const func = expr->call.function; + if (func->kind == EXPR_REFERENCE) { + declaration_t const *const decl = func->reference.declaration; + if (decl != NULL && decl->modifiers & DM_NORETURN) { + return; + } + } + } + + next = stmt->base.next; + break; + } + + case STATEMENT_CONTINUE: { + statement_t *parent = stmt; + for (;;) { + parent = parent->base.parent; + if (parent == NULL) /* continue not within loop */ + return; + + next = parent; + switch (parent->kind) { + case STATEMENT_WHILE: goto continue_while; + case STATEMENT_DO_WHILE: goto continue_do_while; + case STATEMENT_FOR: goto continue_for; + + default: break; + } + } + } + + case STATEMENT_BREAK: { + statement_t *parent = stmt; + for (;;) { + parent = parent->base.parent; + if (parent == NULL) /* break not within loop/switch */ + return; + + switch (parent->kind) { + case STATEMENT_SWITCH: + case STATEMENT_WHILE: + case STATEMENT_DO_WHILE: + case STATEMENT_FOR: + next = parent->base.next; + goto found_break_parent; + + default: break; + } + } +found_break_parent: + break; + } + + case STATEMENT_GOTO: + next = stmt->gotos.label->init.statement; + if (next == NULL) /* missing label */ + return; + break; + + case STATEMENT_LABEL: + next = stmt->label.statement; + break; + + case STATEMENT_CASE_LABEL: + next = stmt->case_label.statement; + break; + + case STATEMENT_WHILE: { + while_statement_t const *const whiles = &stmt->whiles; + int const val = determine_truth(whiles->condition); + + if (val >= 0) + check_reachable(whiles->body); + + if (val > 0) + return; + + next = stmt->base.next; + break; + } + + case STATEMENT_DO_WHILE: + next = stmt->do_while.body; + break; + + case STATEMENT_FOR: { + for_statement_t *const fors = &stmt->fors; + + if (fors->condition_reachable) + return; + fors->condition_reachable = true; + + expression_t const *const cond = fors->condition; + int const val = + cond == NULL ? 1 : determine_truth(cond); + + if (val >= 0) + check_reachable(fors->body); + + if (val > 0) + return; + + next = stmt->base.next; + break; + } + + case STATEMENT_MS_TRY: + case STATEMENT_LEAVE: + panic("unimplemented"); + } + + while (next == NULL) { + next = last->base.parent; + if (next == NULL) { + type_t *const type = current_function->type; + assert(is_type_function(type)); + type_t *const ret = skip_typeref(type->function.return_type); + if (warning.return_type && + !is_type_atomic(ret, ATOMIC_TYPE_VOID) && + !is_sym_main(current_function->symbol)) { + warningf(&stmt->base.source_position, + "control reaches end of non-void function"); + } + return; + } + + switch (next->kind) { + case STATEMENT_INVALID: + case STATEMENT_EMPTY: + case STATEMENT_DECLARATION: + case STATEMENT_EXPRESSION: + case STATEMENT_ASM: + case STATEMENT_RETURN: + case STATEMENT_CONTINUE: + case STATEMENT_BREAK: + case STATEMENT_GOTO: + case STATEMENT_LEAVE: + panic("invalid control flow in function"); + + case STATEMENT_COMPOUND: + case STATEMENT_IF: + case STATEMENT_SWITCH: + case STATEMENT_LABEL: + case STATEMENT_CASE_LABEL: + last = next; + next = next->base.next; + break; + + case STATEMENT_WHILE: { +continue_while: + if (next->base.reachable) + return; + next->base.reachable = true; + + while_statement_t const *const whiles = &next->whiles; + int const val = determine_truth(whiles->condition); + + if (val >= 0) + check_reachable(whiles->body); + + if (val > 0) + return; + + last = next; + next = next->base.next; + break; + } + + case STATEMENT_DO_WHILE: { +continue_do_while: + if (next->base.reachable) + return; + next->base.reachable = true; + + do_while_statement_t const *const dw = &next->do_while; + int const val = determine_truth(dw->condition); + + if (val >= 0) + check_reachable(dw->body); + + if (val > 0) + return; + + last = next; + next = next->base.next; + break; + } + + case STATEMENT_FOR: { +continue_for:; + for_statement_t *const fors = &next->fors; + + fors->step_reachable = true; + + if (fors->condition_reachable) + return; + fors->condition_reachable = true; + + expression_t const *const cond = fors->condition; + int const val = + cond == NULL ? 1 : determine_truth(cond); + + if (val >= 0) + check_reachable(fors->body); + + if (val > 0) + return; + + last = next; + next = next->base.next; + break; + } + + case STATEMENT_MS_TRY: + panic("unimplemented"); + } + } + + if (next == NULL) { + next = stmt->base.parent; + if (next == NULL) { + warningf(&stmt->base.source_position, + "control reaches end of non-void function"); + } + } + + check_reachable(next); +} + +static void check_unreachable(statement_t const* const stmt) +{ + if (!stmt->base.reachable && + stmt->kind != STATEMENT_COMPOUND && + stmt->kind != STATEMENT_DO_WHILE && + stmt->kind != STATEMENT_FOR) { + warningf(&stmt->base.source_position, + "statement is unreachable"); + } + + switch (stmt->kind) { + case STATEMENT_INVALID: + case STATEMENT_EMPTY: + case STATEMENT_RETURN: + case STATEMENT_DECLARATION: + case STATEMENT_EXPRESSION: + case STATEMENT_CONTINUE: + case STATEMENT_BREAK: + case STATEMENT_GOTO: + case STATEMENT_ASM: + case STATEMENT_LEAVE: + break; + + case STATEMENT_COMPOUND: + if (stmt->compound.statements) + check_unreachable(stmt->compound.statements); + break; + + case STATEMENT_IF: + check_unreachable(stmt->ifs.true_statement); + if (stmt->ifs.false_statement != NULL) + check_unreachable(stmt->ifs.false_statement); + break; + + case STATEMENT_SWITCH: + check_unreachable(stmt->switchs.body); + break; + + case STATEMENT_LABEL: + check_unreachable(stmt->label.statement); + break; + + case STATEMENT_CASE_LABEL: + check_unreachable(stmt->case_label.statement); + break; + + case STATEMENT_WHILE: + check_unreachable(stmt->whiles.body); + break; + + case STATEMENT_DO_WHILE: + check_unreachable(stmt->do_while.body); + if (!stmt->base.reachable) { + expression_t const *const cond = stmt->do_while.condition; + if (determine_truth(cond) >= 0) { + warningf(&cond->base.source_position, + "condition of do-while-loop is unreachable"); + } + } + break; + + case STATEMENT_FOR: { + for_statement_t const* const fors = &stmt->fors; + + if (!stmt->base.reachable && fors->initialisation != NULL) { + warningf(&fors->initialisation->base.source_position, + "initialisation of for-statement is unreachable"); + } + + if (!fors->condition_reachable && fors->condition != NULL) { + warningf(&fors->condition->base.source_position, + "condition of for-statement is unreachable"); + } + + if (!fors->step_reachable && fors->step != NULL) { + warningf(&fors->step->base.source_position, + "step of for-statement is unreachable"); + } + + check_unreachable(stmt->fors.body); + break; + } + + case STATEMENT_MS_TRY: + panic("unimplemented"); + } + + if (stmt->base.next) + check_unreachable(stmt->base.next); +} + static void parse_external_declaration(void) { /* function-definitions and declarations both start with declaration @@ -4702,12 +5178,20 @@ static void parse_external_declaration(void) int label_stack_top = label_top(); declaration_t *old_current_function = current_function; current_function = declaration; + current_parent = NULL; - declaration->init.statement = parse_compound_statement(false); + statement_t *const body = parse_compound_statement(false); + declaration->init.statement = body; first_err = true; check_labels(); check_declarations(); + if (warning.return_type || warning.unreachable_code) { + check_reachable(body); + if (warning.unreachable_code) + check_unreachable(body); + } + assert(current_parent == NULL); assert(current_function == declaration); current_function = old_current_function; label_pop_to(label_stack_top); @@ -5785,7 +6269,8 @@ end_error: /** * Parses a MS assume() expression. */ -static expression_t *parse_assume(void) { +static expression_t *parse_assume(void) +{ eat(T__assume); expression_t *expression @@ -5806,7 +6291,8 @@ end_error: /** * Parse a microsoft __noop expression. */ -static expression_t *parse_noop_expression(void) { +static expression_t *parse_noop_expression(void) +{ source_position_t source_position = *HERE; eat(T___noop); @@ -5891,7 +6377,8 @@ static expression_t *parse_primary_expression(void) /** * Check if the expression has the character type and issue a warning then. */ -static void check_for_char_index_type(const expression_t *expression) { +static void check_for_char_index_type(const expression_t *expression) +{ type_t *const type = expression->base.type; const type_t *const base_type = skip_typeref(type); @@ -7435,12 +7922,60 @@ static asm_argument_t *parse_asm_arguments(bool is_out) argument->constraints = parse_string_literals(); expect('('); + add_anchor_token(')'); expression_t *expression = parse_expression(); - argument->expression = expression; - if (is_out && !is_lvalue(expression)) { - errorf(&expression->base.source_position, - "asm output argument is not an lvalue"); + rem_anchor_token(')'); + if (is_out) { + /* Ugly GCC stuff: Allow lvalue casts. Skip casts, when they do not + * change size or type representation (e.g. int -> long is ok, but + * int -> float is not) */ + if (expression->kind == EXPR_UNARY_CAST) { + type_t *const type = expression->base.type; + type_kind_t const kind = type->kind; + if (kind == TYPE_ATOMIC || kind == TYPE_POINTER) { + unsigned flags; + unsigned size; + if (kind == TYPE_ATOMIC) { + atomic_type_kind_t const akind = type->atomic.akind; + flags = get_atomic_type_flags(akind) & ~ATOMIC_TYPE_FLAG_SIGNED; + size = get_atomic_type_size(akind); + } else { + flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC; + size = get_atomic_type_size(get_intptr_kind()); + } + + do { + expression_t *const value = expression->unary.value; + type_t *const value_type = value->base.type; + type_kind_t const value_kind = value_type->kind; + + unsigned value_flags; + unsigned value_size; + if (value_kind == TYPE_ATOMIC) { + atomic_type_kind_t const value_akind = value_type->atomic.akind; + value_flags = get_atomic_type_flags(value_akind) & ~ATOMIC_TYPE_FLAG_SIGNED; + value_size = get_atomic_type_size(value_akind); + } else if (value_kind == TYPE_POINTER) { + value_flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC; + value_size = get_atomic_type_size(get_intptr_kind()); + } else { + break; + } + + if (value_flags != flags || value_size != size) + break; + + expression = value; + } while (expression->kind == EXPR_UNARY_CAST); + } + } + + if (!is_lvalue(expression)) { + errorf(&expression->base.source_position, + "asm output argument is not an lvalue"); + } } + argument->expression = expression; expect(')'); set_address_taken(expression, true); @@ -7538,6 +8073,13 @@ end_of_asm: rem_anchor_token(')'); expect(')'); expect(';'); + + if (asm_statement->outputs == NULL) { + /* GCC: An 'asm' instruction without any output operands will be treated + * identically to a volatile 'asm' instruction. */ + asm_statement->is_volatile = true; + } + return statement; end_error: return create_invalid_statement(); @@ -7550,11 +8092,14 @@ static statement_t *parse_case_statement(void) { eat(T_case); - statement_t *statement = allocate_statement_zero(STATEMENT_CASE_LABEL); + statement_t *const statement = allocate_statement_zero(STATEMENT_CASE_LABEL); + source_position_t *const pos = &statement->base.source_position; - statement->base.source_position = token.source_position; + *pos = token.source_position; statement->case_label.expression = parse_expression(); + PUSH_PARENT(statement); + if (c_mode & _GNUC) { if (token.type == T_DOTDOTDOT) { next_token(); @@ -7565,27 +8110,42 @@ static statement_t *parse_case_statement(void) expect(':'); if (! is_constant_expression(statement->case_label.expression)) { - errorf(&statement->base.source_position, - "case label does not reduce to an integer constant"); - } else { - /* TODO: check if the case label is already known */ - if (current_switch != NULL) { - /* link all cases into the switch statement */ - if (current_switch->last_case == NULL) { - current_switch->first_case = - current_switch->last_case = &statement->case_label; - } else { - current_switch->last_case->next = &statement->case_label; - } + errorf(pos, "case label does not reduce to an integer constant"); + } else if (current_switch != NULL) { + /* Check for duplicate case values */ + /* FIXME slow */ + long const val = fold_constant(statement->case_label.expression); + for (case_label_statement_t *l = current_switch->first_case; l != NULL; l = l->next) { + expression_t const* const e = l->expression; + if (e == NULL || !is_constant_expression(e) || fold_constant(e) != val) + continue; + + errorf(pos, "duplicate case value"); + errorf(&l->base.source_position, "previously used here"); + break; + } + + /* link all cases into the switch statement */ + if (current_switch->last_case == NULL) { + current_switch->first_case = &statement->case_label; } else { - errorf(&statement->base.source_position, - "case label not within a switch statement"); + current_switch->last_case->next = &statement->case_label; } + current_switch->last_case = &statement->case_label; + } else { + errorf(pos, "case label not within a switch statement"); + } + + statement_t *const inner_stmt = parse_statement(); + statement->case_label.statement = inner_stmt; + if (inner_stmt->kind == STATEMENT_DECLARATION) { + errorf(&inner_stmt->base.source_position, "declaration after case label"); } - statement->case_label.statement = parse_statement(); + POP_PARENT; return statement; end_error: + POP_PARENT; return create_invalid_statement(); } @@ -7611,9 +8171,10 @@ static statement_t *parse_default_statement(void) eat(T_default); statement_t *statement = allocate_statement_zero(STATEMENT_CASE_LABEL); - statement->base.source_position = token.source_position; + PUSH_PARENT(statement); + expect(':'); if (current_switch != NULL) { const case_label_statement_t *def_label = find_default_label(current_switch); @@ -7623,20 +8184,27 @@ static statement_t *parse_default_statement(void) } else { /* link all cases into the switch statement */ if (current_switch->last_case == NULL) { - current_switch->first_case = - current_switch->last_case = &statement->case_label; + current_switch->first_case = &statement->case_label; } else { current_switch->last_case->next = &statement->case_label; } + current_switch->last_case = &statement->case_label; } } else { errorf(&statement->base.source_position, "'default' label not within a switch statement"); } - statement->case_label.statement = parse_statement(); + statement_t *const inner_stmt = parse_statement(); + statement->case_label.statement = inner_stmt; + if (inner_stmt->kind == STATEMENT_DECLARATION) { + errorf(&inner_stmt->base.source_position, "declaration after default label"); + } + + POP_PARENT; return statement; end_error: + POP_PARENT; return create_invalid_statement(); } @@ -7677,6 +8245,12 @@ static statement_t *parse_label_statement(void) declaration_t *label = get_label(symbol); + statement_t *const statement = allocate_statement_zero(STATEMENT_LABEL); + statement->base.source_position = token.source_position; + statement->label.label = label; + + PUSH_PARENT(statement); + /* if source position is already set then the label is defined twice, * otherwise it was just mentioned in a goto so far */ if (label->source_position.input_name != NULL) { @@ -7684,13 +8258,9 @@ static statement_t *parse_label_statement(void) symbol, &label->source_position); } else { label->source_position = token.source_position; + label->init.statement = statement; } - statement_t *statement = allocate_statement_zero(STATEMENT_LABEL); - - statement->base.source_position = token.source_position; - statement->label.label = label; - eat(':'); if (token.type == '}') { @@ -7702,16 +8272,17 @@ static statement_t *parse_label_statement(void) errorf(HERE, "label at end of compound statement"); statement->label.statement = create_invalid_statement(); } - return statement; + } else if (token.type == ';') { + /* Eat an empty statement here, to avoid the warning about an empty + * statement after a label. label:; is commonly used to have a label + * before a closing brace. */ + statement->label.statement = create_empty_statement(); + next_token(); } else { - if (token.type == ';') { - /* eat an empty statement here, to avoid the warning about an empty - * after a label. label:; is commonly used to have a label before - * a }. */ - statement->label.statement = create_empty_statement(); - next_token(); - } else { - statement->label.statement = parse_statement(); + statement_t *const inner_stmt = parse_statement(); + statement->label.statement = inner_stmt; + if (inner_stmt->kind == STATEMENT_DECLARATION) { + errorf(&inner_stmt->base.source_position, "declaration after label"); } } @@ -7723,6 +8294,7 @@ static statement_t *parse_label_statement(void) } label_last = &statement->label; + POP_PARENT; return statement; } @@ -7736,6 +8308,8 @@ static statement_t *parse_if(void) statement_t *statement = allocate_statement_zero(STATEMENT_IF); statement->base.source_position = token.source_position; + PUSH_PARENT(statement); + expect('('); add_anchor_token(')'); statement->ifs.condition = parse_expression(); @@ -7751,8 +8325,10 @@ static statement_t *parse_if(void) statement->ifs.false_statement = parse_statement(); } + POP_PARENT; return statement; end_error: + POP_PARENT; return create_invalid_statement(); } @@ -7766,6 +8342,8 @@ static statement_t *parse_switch(void) statement_t *statement = allocate_statement_zero(STATEMENT_SWITCH); statement->base.source_position = token.source_position; + PUSH_PARENT(statement); + expect('('); expression_t *const expr = parse_expression(); type_t * type = skip_typeref(expr->base.type); @@ -7789,8 +8367,10 @@ static statement_t *parse_switch(void) warningf(&statement->base.source_position, "switch has no default case"); } + POP_PARENT; return statement; end_error: + POP_PARENT; return create_invalid_statement(); } @@ -7815,6 +8395,8 @@ static statement_t *parse_while(void) statement_t *statement = allocate_statement_zero(STATEMENT_WHILE); statement->base.source_position = token.source_position; + PUSH_PARENT(statement); + expect('('); add_anchor_token(')'); statement->whiles.condition = parse_expression(); @@ -7823,8 +8405,10 @@ static statement_t *parse_while(void) statement->whiles.body = parse_loop_body(statement); + POP_PARENT; return statement; end_error: + POP_PARENT; return create_invalid_statement(); } @@ -7836,9 +8420,10 @@ static statement_t *parse_do(void) eat(T_do); statement_t *statement = allocate_statement_zero(STATEMENT_DO_WHILE); - statement->base.source_position = token.source_position; + PUSH_PARENT(statement) + add_anchor_token(T_while); statement->do_while.body = parse_loop_body(statement); rem_anchor_token(T_while); @@ -7851,8 +8436,10 @@ static statement_t *parse_do(void) expect(')'); expect(';'); + POP_PARENT; return statement; end_error: + POP_PARENT; return create_invalid_statement(); } @@ -7866,6 +8453,8 @@ static statement_t *parse_for(void) statement_t *statement = allocate_statement_zero(STATEMENT_FOR); statement->base.source_position = token.source_position; + PUSH_PARENT(statement); + int top = environment_top(); scope_t *last_scope = scope; set_scope(&statement->fors.scope); @@ -7913,9 +8502,11 @@ static statement_t *parse_for(void) set_scope(last_scope); environment_pop_to(top); + POP_PARENT; return statement; end_error: + POP_PARENT; rem_anchor_token(')'); assert(scope == &statement->fors.scope); set_scope(last_scope); @@ -8033,7 +8624,8 @@ end_error: /** * Check if a given declaration represents a local variable. */ -static bool is_local_var_declaration(const declaration_t *declaration) { +static bool is_local_var_declaration(const declaration_t *declaration) +{ switch ((storage_class_tag_t) declaration->storage_class) { case STORAGE_CLASS_AUTO: case STORAGE_CLASS_REGISTER: { @@ -8052,7 +8644,8 @@ static bool is_local_var_declaration(const declaration_t *declaration) { /** * Check if a given declaration represents a variable. */ -static bool is_var_declaration(const declaration_t *declaration) { +static bool is_var_declaration(const declaration_t *declaration) +{ if (declaration->storage_class == STORAGE_CLASS_TYPEDEF) return false; @@ -8187,7 +8780,8 @@ end_error: * Parse a microsoft __try { } __finally { } or * __try{ } __except() { } */ -static statement_t *parse_ms_try_statment(void) { +static statement_t *parse_ms_try_statment(void) +{ statement_t *statement = allocate_statement_zero(STATEMENT_MS_TRY); statement->base.source_position = token.source_position; @@ -8227,6 +8821,15 @@ end_error: return create_invalid_statement(); } +static statement_t *parse_empty_statement(void) +{ + if (warning.empty_statement) { + warningf(HERE, "statement is empty"); + } + eat(';'); + return create_empty_statement(); +} + /** * Parse a statement. * There's also parse_statement() which additionally checks for @@ -8238,91 +8841,23 @@ static statement_t *intern_parse_statement(void) /* declaration or statement */ add_anchor_token(';'); - switch(token.type) { - case T_asm: - statement = parse_asm_statement(); - break; - - case T_case: - statement = parse_case_statement(); - break; - - case T_default: - statement = parse_default_statement(); - break; - - case '{': - statement = parse_compound_statement(false); - break; - - case T_if: - statement = parse_if (); - break; - - case T_switch: - statement = parse_switch(); - break; - - case T_while: - statement = parse_while(); - break; - - case T_do: - statement = parse_do(); - break; - - case T_for: - statement = parse_for(); - break; - - case T_goto: - statement = parse_goto(); - break; - - case T_continue: - statement = parse_continue(); - break; - - case T_break: - statement = parse_break(); - break; - - case T___leave: - statement = parse_leave(); - break; - - case T_return: - statement = parse_return(); - break; - - case ';': - if (warning.empty_statement) { - warningf(HERE, "statement is empty"); - } - statement = create_empty_statement(); - next_token(); - break; - + switch (token.type) { case T_IDENTIFIER: if (look_ahead(1)->type == ':') { statement = parse_label_statement(); - break; - } - - if (is_typedef_symbol(token.v.symbol)) { + } else if (is_typedef_symbol(token.v.symbol)) { statement = parse_declaration_statement(); - break; + } else { + statement = parse_expression_statement(); } - - statement = parse_expression_statement(); break; case T___extension__: - /* this can be a prefix to a declaration or an expression statement */ - /* we simply eat it now and parse the rest with tail recursion */ + /* This can be a prefix to a declaration or an expression statement. + * We simply eat it now and parse the rest with tail recursion. */ do { next_token(); - } while(token.type == T___extension__); + } while (token.type == T___extension__); statement = parse_statement(); break; @@ -8330,13 +8865,23 @@ static statement_t *intern_parse_statement(void) statement = parse_declaration_statement(); break; - case T___try: - statement = parse_ms_try_statment(); - break; - - default: - statement = parse_expression_statement(); - break; + case ';': statement = parse_empty_statement(); break; + case '{': statement = parse_compound_statement(false); break; + case T___leave: statement = parse_leave(); break; + case T___try: statement = parse_ms_try_statment(); break; + case T_asm: statement = parse_asm_statement(); break; + case T_break: statement = parse_break(); break; + case T_case: statement = parse_case_statement(); break; + case T_continue: statement = parse_continue(); break; + case T_default: statement = parse_default_statement(); break; + case T_do: statement = parse_do(); break; + case T_for: statement = parse_for(); break; + case T_goto: statement = parse_goto(); break; + case T_if: statement = parse_if (); break; + case T_return: statement = parse_return(); break; + case T_switch: statement = parse_switch(); break; + case T_while: statement = parse_while(); break; + default: statement = parse_expression_statement(); break; } rem_anchor_token(';'); @@ -8373,9 +8918,10 @@ static statement_t *parse_statement(void) static statement_t *parse_compound_statement(bool inside_expression_statement) { statement_t *statement = allocate_statement_zero(STATEMENT_COMPOUND); - statement->base.source_position = token.source_position; + PUSH_PARENT(statement); + eat('{'); add_anchor_token('}'); @@ -8385,7 +8931,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) statement_t *last_statement = NULL; - while(token.type != '}' && token.type != T_EOF) { + while (token.type != '}' && token.type != T_EOF) { statement_t *sub_statement = intern_parse_statement(); if (is_invalid_statement(sub_statement)) { /* an error occurred. if we are at an anchor, return */ @@ -8400,7 +8946,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) statement->compound.statements = sub_statement; } - while(sub_statement->base.next != NULL) + while (sub_statement->base.next != NULL) sub_statement = sub_statement->base.next; last_statement = sub_statement; @@ -8438,6 +8984,7 @@ end_error: set_scope(last_scope); environment_pop_to(top); + POP_PARENT; return statement; } @@ -8470,8 +9017,9 @@ static void check_unused_globals(void) return; for (const declaration_t *decl = global_scope->declarations; decl != NULL; decl = decl->next) { - if (decl->used || - decl->modifiers & DM_USED || + if (decl->used || + decl->modifiers & DM_UNUSED || + decl->modifiers & DM_USED || decl->storage_class != STORAGE_CLASS_STATIC) continue; @@ -8516,22 +9064,32 @@ end_error:; */ static void parse_translation_unit(void) { - while(token.type != T_EOF) { - switch (token.type) { - case ';': - /* TODO error in strict mode */ - warningf(HERE, "stray ';' outside of function"); - next_token(); - break; + for (;;) switch (token.type) { + DECLARATION_START + case T_IDENTIFIER: + case T___extension__: + parse_external_declaration(); + break; - case T_asm: - parse_global_asm(); - break; + case T_asm: + parse_global_asm(); + break; - default: - parse_external_declaration(); - break; - } + case T_EOF: + return; + + case ';': + /* TODO error in strict mode */ + warningf(HERE, "stray ';' outside of function"); + next_token(); + break; + + default: + errorf(HERE, "stray %K outside of function", &token); + if (token.type == '(' || token.type == '{' || token.type == '[') + eat_until_matching_token(token.type); + next_token(); + break; } }