X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=baa943af371f7d56b6deb85153433683575ebc11;hb=d4a27091c638acf4f67f8a4f1faf3aac911c7fce;hp=44ec3f323a1a52442649a43febe7f1853c3502fb;hpb=2c1b184ca0496cfbdf2c64c07b885fa0c2c65b42;p=cparser diff --git a/parser.c b/parser.c index 44ec3f3..baa943a 100644 --- a/parser.c +++ b/parser.c @@ -39,6 +39,14 @@ #include "adt/error.h" #include "adt/array.h" +/** if wchar_t is equal to unsigned short. */ +bool opt_short_wchar_t = +#ifdef _WIN32 + true; +#else + false; +#endif + //#define PRINT_TOKENS #define MAX_LOOKAHEAD 2 @@ -108,6 +116,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 +125,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 */ @@ -321,7 +335,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; } @@ -833,7 +848,7 @@ static void label_pop_to(size_t new_top) } -static int get_rank(const type_t *type) +static atomic_type_kind_t get_rank(const type_t *type) { assert(!is_typeref(type)); /* The C-standard allows promoting enums to int or unsigned int (see § 7.2.2 @@ -952,9 +967,9 @@ static void report_assign_error(assign_error_t error, type_t *orig_type_left, /* the left type has all qualifiers from the right type */ unsigned missing_qualifiers = points_to_right->base.qualifiers & ~points_to_left->base.qualifiers; - errorf(source_position, - "destination type '%T' in %s from type '%T' lacks qualifiers '%Q' in pointed-to type", - orig_type_left, context, orig_type_right, missing_qualifiers); + warningf(source_position, + "destination type '%T' in %s from type '%T' lacks qualifiers '%Q' in pointed-to type", + orig_type_left, context, orig_type_right, missing_qualifiers); return; } @@ -1601,7 +1616,6 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) switch(kind) { case GNU_AK_CONST: case GNU_AK_VOLATILE: - case GNU_AK_DEPRECATED: case GNU_AK_NAKED: case GNU_AK_MALLOC: case GNU_AK_WEAK: @@ -1650,6 +1664,7 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) case GNU_AK_TRANSPARENT_UNION: modifiers |= DM_TRANSPARENT_UNION; goto no_arg; case GNU_AK_CONSTRUCTOR: modifiers |= DM_CONSTRUCTOR; goto no_arg; case GNU_AK_DESTRUCTOR: modifiers |= DM_DESTRUCTOR; goto no_arg; + case GNU_AK_DEPRECATED: modifiers |= DM_DEPRECATED; goto no_arg; case GNU_AK_ALIGNED: /* __align__ may be used without an argument */ @@ -3046,7 +3061,8 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE; type_modifiers_t modifiers = TYPE_MODIFIER_NONE; unsigned type_specifiers = 0; - int newtype = 0; + bool newtype = false; + bool saw_error = false; specifiers->source_position = token.source_position; @@ -3200,13 +3216,50 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) case T_IDENTIFIER: { /* only parse identifier if we haven't found a type yet */ - if (type != NULL || type_specifiers != 0) - goto finish_specifiers; + if (type != NULL || type_specifiers != 0) { + /* Be somewhat resilient to typos like 'unsigned lng* f()' in a + * declaration, so it doesn't generate errors about expecting '(' or + * '{' later on. */ + switch (look_ahead(1)->type) { + STORAGE_CLASSES + TYPE_SPECIFIERS + case T_const: + case T_restrict: + case T_volatile: + case T_inline: + case T__forceinline: /* ^ DECLARATION_START except for __attribute__ */ + case T_IDENTIFIER: + case '*': + errorf(HERE, "discarding stray %K in declaration specifer", &token); + next_token(); + continue; - type_t *typedef_type = get_typedef_type(token.v.symbol); + default: + goto finish_specifiers; + } + } - if (typedef_type == NULL) - goto finish_specifiers; + type_t *const typedef_type = get_typedef_type(token.v.symbol); + if (typedef_type == NULL) { + /* Be somewhat resilient to typos like 'vodi f()' at the beginning of a + * declaration, so it doesn't generate 'implicit int' followed by more + * errors later on. */ + token_type_t const la1_type = (token_type_t)look_ahead(1)->type; + switch (la1_type) { + DECLARATION_START + case T_IDENTIFIER: + case '*': + errorf(HERE, "%K does not name a type", &token); + next_token(); + saw_error = true; + if (la1_type == '*') + goto finish_specifiers; + continue; + + default: + goto finish_specifiers; + } + } next_token(); type = typedef_type; @@ -3267,17 +3320,24 @@ finish_specifiers: case SPECIFIER_UNSIGNED | SPECIFIER_LONG | SPECIFIER_INT: atomic_type = ATOMIC_TYPE_ULONG; break; + case SPECIFIER_LONG | SPECIFIER_LONG_LONG: case SPECIFIER_SIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG: case SPECIFIER_LONG | SPECIFIER_LONG_LONG | SPECIFIER_INT: case SPECIFIER_SIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG | SPECIFIER_INT: atomic_type = ATOMIC_TYPE_LONGLONG; - break; + goto warn_about_long_long; + case SPECIFIER_UNSIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG: case SPECIFIER_UNSIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG | SPECIFIER_INT: atomic_type = ATOMIC_TYPE_ULONGLONG; +warn_about_long_long: + if (warning.long_long) { + warningf(&specifiers->source_position, + "ISO C90 does not support 'long long'"); + } break; case SPECIFIER_UNSIGNED | SPECIFIER_INT8: @@ -3352,7 +3412,12 @@ finish_specifiers: default: /* invalid specifier combination, give an error message */ if (type_specifiers == 0) { - if (! strict_mode) { + if (saw_error) { + specifiers->type = type_error_type; + return; + } + + if (!strict_mode) { if (warning.implicit_int) { warningf(HERE, "no type specifiers in declaration, using 'int'"); } @@ -3363,7 +3428,7 @@ finish_specifiers: } } else if ((type_specifiers & SPECIFIER_SIGNED) && (type_specifiers & SPECIFIER_UNSIGNED)) { - errorf(HERE, "signed and unsigned specifiers gives"); + errorf(HERE, "signed and unsigned specifiers given"); } else if (type_specifiers & (SPECIFIER_SIGNED | SPECIFIER_UNSIGNED)) { errorf(HERE, "only integer types can be signed or unsigned"); } else { @@ -3384,11 +3449,9 @@ finish_specifiers: type = allocate_type_zero(TYPE_ATOMIC, &builtin_source_position); type->atomic.akind = atomic_type; } - newtype = 1; - } else { - if (type_specifiers != 0) { - errorf(HERE, "multiple datatypes in declaration"); - } + newtype = true; + } else if (type_specifiers != 0) { + errorf(HERE, "multiple datatypes in declaration"); } /* FIXME: check type qualifiers here */ @@ -3461,12 +3524,21 @@ static type_t *automatic_type_conversion(type_t *orig_type); static void semantic_parameter(declaration_t *declaration) { /* TODO: improve error messages */ + source_position_t const* const pos = &declaration->source_position; + + switch (declaration->declared_storage_class) { + case STORAGE_CLASS_TYPEDEF: + errorf(pos, "typedef not allowed in parameter list"); + break; - if (declaration->declared_storage_class == STORAGE_CLASS_TYPEDEF) { - errorf(HERE, "typedef not allowed in parameter list"); - } else if (declaration->declared_storage_class != STORAGE_CLASS_NONE - && declaration->declared_storage_class != STORAGE_CLASS_REGISTER) { - errorf(HERE, "parameter may only have none or register storage class"); + /* Allowed storage classes */ + case STORAGE_CLASS_NONE: + case STORAGE_CLASS_REGISTER: + break; + + default: + errorf(pos, "parameter may only have none or register storage class"); + break; } type_t *const orig_type = declaration->type; @@ -3479,7 +3551,7 @@ static void semantic_parameter(declaration_t *declaration) declaration->type = type; if (is_type_incomplete(skip_typeref(type))) { - errorf(HERE, "incomplete type '%T' not allowed for parameter '%Y'", + errorf(pos, "incomplete type '%T' not allowed for parameter '%Y'", orig_type, declaration->symbol); } } @@ -3692,7 +3764,7 @@ static construct_type_t *parse_function_declarator(declaration_t *declaration) else if (second == NULL) second = "stdcall"; } if (declaration->modifiers & DM_FASTCALL) { - if (first == NULL) first = "faslcall"; + if (first == NULL) first = "fastcall"; else if (second == NULL) second = "fastcall"; } if (declaration->modifiers & DM_THISCALL) { @@ -3777,6 +3849,9 @@ static construct_type_t *parse_inner_declarator(declaration_t *declaration, modifiers |= parse_attributes(&attributes); } + if (declaration != NULL) + declaration->modifiers |= modifiers; + construct_type_t *inner_types = NULL; switch(token.type) { @@ -3793,6 +3868,8 @@ static construct_type_t *parse_inner_declarator(declaration_t *declaration, next_token(); add_anchor_token(')'); inner_types = parse_inner_declarator(declaration, may_be_abstract); + /* All later declarators only modify the return type, not declaration */ + declaration = NULL; rem_anchor_token(')'); expect(')'); break; @@ -3982,9 +4059,9 @@ static declaration_t *parse_declarator( const declaration_specifiers_t *specifiers, bool may_be_abstract) { declaration_t *const declaration = allocate_declaration_zero(); + declaration->source_position = specifiers->source_position; declaration->declared_storage_class = specifiers->declared_storage_class; declaration->modifiers = specifiers->modifiers; - declaration->deprecated = specifiers->deprecated; declaration->deprecated_string = specifiers->deprecated_string; declaration->get_property_sym = specifiers->get_property_sym; declaration->put_property_sym = specifiers->put_property_sym; @@ -4108,7 +4185,7 @@ static declaration_t *internal_record_declaration( const symbol_t *const symbol = declaration->symbol; const namespace_t namespc = (namespace_t)declaration->namespc; - assert(declaration->symbol != NULL); + assert(symbol != NULL); declaration_t *previous_declaration = get_declaration(symbol, namespc); type_t *const orig_type = declaration->type; @@ -4126,6 +4203,13 @@ static declaration_t *internal_record_declaration( check_type_of_main(declaration, &type->function); } + if (warning.nested_externs && + declaration->storage_class == STORAGE_CLASS_EXTERN && + scope != global_scope) { + warningf(&declaration->source_position, + "nested extern declaration of '%#T'", declaration->type, symbol); + } + assert(declaration != previous_declaration); if (previous_declaration != NULL && previous_declaration->parent_scope == scope) { @@ -4232,8 +4316,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 && @@ -4630,6 +4714,10 @@ static void check_declarations(void) if (warning.unused_parameter) { const scope_t *scope = ¤t_function->scope; + if (is_sym_main(current_function->symbol)) { + /* do not issue unused warnings for main */ + return; + } const declaration_t *parameter = scope->declarations; for (; parameter != NULL; parameter = parameter->next) { if (! parameter->used) { @@ -4643,6 +4731,432 @@ 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 bool noreturn_candidate; + +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: + noreturn_candidate = false; + 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; + } + + if (i->first_case <= val && val <= i->last_case) { + 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: + last = parent; + 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) { + noreturn_candidate = false; + + 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_type_valid(ret) && + !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 init and step are unreachable, cond is unreachable, too + if (!stmt->base.reachable && !fors->step_reachable) { + warningf(&stmt->base.source_position, "statement is unreachable"); + } else { + 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 @@ -4740,7 +5254,7 @@ static void parse_external_declaration(void) || parameter->parent_scope == scope); parameter->parent_scope = scope; if (parameter->symbol == NULL) { - errorf(&ndeclaration->source_position, "parameter name omitted"); + errorf(¶meter->source_position, "parameter name omitted"); continue; } environment_push(parameter); @@ -4754,12 +5268,30 @@ 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 || + (warning.missing_noreturn && !(declaration->modifiers & DM_NORETURN))) { + noreturn_candidate = true; + check_reachable(body); + if (warning.unreachable_code) + check_unreachable(body); + if (warning.missing_noreturn && + noreturn_candidate && + !(declaration->modifiers & DM_NORETURN)) { + warningf(&body->base.source_position, + "function '%#T' is candidate for attribute 'noreturn'", + type, declaration->symbol); + } + } + assert(current_parent == NULL); assert(current_function == declaration); current_function = old_current_function; label_pop_to(label_stack_top); @@ -4992,7 +5524,7 @@ static expression_t *parse_string_const(void) /* note: that we use type_char_ptr here, which is already the * automatic converted type. revert_automatic_type_conversion * will construct the array type */ - cnst->base.type = type_char_ptr; + cnst->base.type = warning.write_strings ? type_const_char_ptr : type_char_ptr; cnst->string.value = res; return cnst; } @@ -5015,7 +5547,7 @@ static expression_t *parse_string_const(void) default: { expression_t *const cnst = allocate_expression_zero(EXPR_WIDE_STRING_LITERAL); - cnst->base.type = type_wchar_t_ptr; + cnst->base.type = warning.write_strings ? type_const_wchar_t_ptr : type_wchar_t_ptr; cnst->wide_string.value = wres; return cnst; } @@ -5337,18 +5869,20 @@ static expression_t *parse_reference(void) declaration->used = true; /* check for deprecated functions */ - if (declaration->deprecated != 0) { - const char *prefix = ""; - if (is_type_function(declaration->type)) - prefix = "function "; + if (warning.deprecated_declarations && + declaration->modifiers & DM_DEPRECATED) { + char const *const prefix = is_type_function(declaration->type) ? + "function" : "variable"; if (declaration->deprecated_string != NULL) { warningf(&source_position, - "%s'%Y' was declared 'deprecated(\"%s\")'", prefix, declaration->symbol, + "%s '%Y' is deprecated (declared %P): \"%s\"", prefix, + declaration->symbol, &declaration->source_position, declaration->deprecated_string); } else { warningf(&source_position, - "%s'%Y' was declared 'deprecated'", prefix, declaration->symbol); + "%s '%Y' is deprecated (declared %P)", prefix, + declaration->symbol, &declaration->source_position); } } @@ -5446,9 +5980,9 @@ end_error: } /** - * Parse a braced expression. + * Parse a parenthesized expression. */ -static expression_t *parse_brace_expression(void) +static expression_t *parse_parenthesized_expression(void) { eat('('); add_anchor_token(')'); @@ -5934,7 +6468,7 @@ static expression_t *parse_primary_expression(void) case T___builtin_prefetch: return parse_builtin_prefetch(); case T__assume: return parse_assume(); - case '(': return parse_brace_expression(); + case '(': return parse_parenthesized_expression(); case T___noop: return parse_noop_expression(); } @@ -6310,13 +6844,14 @@ static bool same_compound_type(const type_t *type1, const type_t *type2) static expression_t *parse_conditional_expression(unsigned precedence, expression_t *expression) { - eat('?'); - add_anchor_token(':'); - expression_t *result = allocate_expression_zero(EXPR_CONDITIONAL); conditional_expression_t *conditional = &result->conditional; - conditional->condition = expression; + conditional->base.source_position = *HERE; + conditional->condition = expression; + + eat('?'); + add_anchor_token(':'); /* 6.5.15.2 */ type_t *const condition_type_orig = expression->base.type; @@ -6342,7 +6877,7 @@ static expression_t *parse_conditional_expression(unsigned precedence, is_type_atomic(false_type, ATOMIC_TYPE_VOID)) { if (!is_type_atomic(true_type, ATOMIC_TYPE_VOID) || !is_type_atomic(false_type, ATOMIC_TYPE_VOID)) { - warningf(&expression->base.source_position, + warningf(&conditional->base.source_position, "ISO C forbids conditional expression with only one void side"); } result_type = type_void; @@ -6388,7 +6923,7 @@ static expression_t *parse_conditional_expression(unsigned precedence, get_unqualified_type(to2))) { to = to1; } else { - warningf(&expression->base.source_position, + warningf(&conditional->base.source_position, "pointer types '%T' and '%T' in conditional expression are incompatible", true_type, false_type); to = type_void; @@ -6403,7 +6938,7 @@ static expression_t *parse_conditional_expression(unsigned precedence, result_type = make_pointer_type(type, TYPE_QUALIFIER_NONE); } else if (is_type_integer(other_type)) { - warningf(&expression->base.source_position, + warningf(&conditional->base.source_position, "pointer/integer type mismatch in conditional expression ('%T' and '%T')", true_type, false_type); result_type = pointer_type; } else { @@ -6416,7 +6951,7 @@ static expression_t *parse_conditional_expression(unsigned precedence, if (is_type_valid(true_type) && is_type_valid(false_type)) { type_error_incompatible("while parsing conditional", - &expression->base.source_position, true_type, + &conditional->base.source_position, true_type, false_type); } result_type = type_error_type; @@ -6467,24 +7002,37 @@ end_error: return create_invalid_expression(); } -static void check_pointer_arithmetic(const source_position_t *source_position, +static bool check_pointer_arithmetic(const source_position_t *source_position, type_t *pointer_type, type_t *orig_pointer_type) { type_t *points_to = pointer_type->pointer.points_to; points_to = skip_typeref(points_to); - if (is_type_incomplete(points_to) && - (! (c_mode & _GNUC) - || !is_type_atomic(points_to, ATOMIC_TYPE_VOID))) { - errorf(source_position, - "arithmetic with pointer to incomplete type '%T' not allowed", - orig_pointer_type); + if (is_type_incomplete(points_to)) { + if (!(c_mode & _GNUC) || !is_type_atomic(points_to, ATOMIC_TYPE_VOID)) { + errorf(source_position, + "arithmetic with pointer to incomplete type '%T' not allowed", + orig_pointer_type); + return false; + } else if (warning.pointer_arith) { + warningf(source_position, + "pointer of type '%T' used in arithmetic", + orig_pointer_type); + } } else if (is_type_function(points_to)) { - errorf(source_position, - "arithmetic with pointer to function type '%T' not allowed", - orig_pointer_type); + if (!(c_mode && _GNUC)) { + errorf(source_position, + "arithmetic with pointer to function type '%T' not allowed", + orig_pointer_type); + return false; + } else if (warning.pointer_arith) { + warningf(source_position, + "pointer to a function '%T' used in arithmetic", + orig_pointer_type); + } } + return true; } static void semantic_incdec(unary_expression_t *expression) @@ -6492,11 +7040,15 @@ static void semantic_incdec(unary_expression_t *expression) type_t *const orig_type = expression->value->base.type; type_t *const type = skip_typeref(orig_type); if (is_type_pointer(type)) { - check_pointer_arithmetic(&expression->base.source_position, - type, orig_type); + if (!check_pointer_arithmetic(&expression->base.source_position, + type, orig_type)) { + return; + } } else if (!is_type_real(type) && is_type_valid(type)) { /* TODO: improve error message */ - errorf(HERE, "operation needs an arithmetic or pointer type"); + errorf(&expression->base.source_position, + "operation needs an arithmetic or pointer type"); + return; } expression->base.type = orig_type; } @@ -6508,7 +7060,8 @@ static void semantic_unexpr_arithmetic(unary_expression_t *expression) if (!is_type_arithmetic(type)) { if (is_type_valid(type)) { /* TODO: improve error message */ - errorf(HERE, "operation needs an arithmetic type"); + errorf(&expression->base.source_position, + "operation needs an arithmetic type"); } return; } @@ -6516,18 +7069,16 @@ static void semantic_unexpr_arithmetic(unary_expression_t *expression) expression->base.type = orig_type; } -static void semantic_unexpr_scalar(unary_expression_t *expression) +static void semantic_not(unary_expression_t *expression) { type_t *const orig_type = expression->value->base.type; type_t *const type = skip_typeref(orig_type); - if (!is_type_scalar(type)) { - if (is_type_valid(type)) { - errorf(HERE, "operand of ! must be of scalar type"); - } - return; + if (!is_type_scalar(type) && is_type_valid(type)) { + errorf(&expression->base.source_position, + "operand of ! must be of scalar type"); } - expression->base.type = orig_type; + expression->base.type = type_int; } static void semantic_unexpr_integer(unary_expression_t *expression) @@ -6536,7 +7087,8 @@ static void semantic_unexpr_integer(unary_expression_t *expression) type_t *const type = skip_typeref(orig_type); if (!is_type_integer(type)) { if (is_type_valid(type)) { - errorf(HERE, "operand of ~ must be of integer type"); + errorf(&expression->base.source_position, + "operand of ~ must be of integer type"); } return; } @@ -6550,7 +7102,8 @@ static void semantic_dereference(unary_expression_t *expression) type_t *const type = skip_typeref(orig_type); if (!is_type_pointer(type)) { if (is_type_valid(type)) { - errorf(HERE, "Unary '*' needs pointer or arrray type, but type '%T' given", orig_type); + errorf(&expression->base.source_position, + "Unary '*' needs pointer or arrray type, but type '%T' given", orig_type); } return; } @@ -6599,11 +7152,10 @@ static void semantic_take_addr(unary_expression_t *expression) #define CREATE_UNARY_EXPRESSION_PARSER(token_type, unexpression_type, sfunc) \ static expression_t *parse_##unexpression_type(unsigned precedence) \ { \ - eat(token_type); \ - \ expression_t *unary_expression \ = allocate_expression_zero(unexpression_type); \ unary_expression->base.source_position = *HERE; \ + eat(token_type); \ unary_expression->unary.value = parse_sub_expression(precedence); \ \ sfunc(&unary_expression->unary); \ @@ -6616,7 +7168,7 @@ CREATE_UNARY_EXPRESSION_PARSER('-', EXPR_UNARY_NEGATE, CREATE_UNARY_EXPRESSION_PARSER('+', EXPR_UNARY_PLUS, semantic_unexpr_arithmetic) CREATE_UNARY_EXPRESSION_PARSER('!', EXPR_UNARY_NOT, - semantic_unexpr_scalar) + semantic_not) CREATE_UNARY_EXPRESSION_PARSER('*', EXPR_UNARY_DEREFERENCE, semantic_dereference) CREATE_UNARY_EXPRESSION_PARSER('&', EXPR_UNARY_TAKE_ADDRESS, @@ -6634,11 +7186,12 @@ static expression_t *parse_##unexpression_type(unsigned precedence, \ expression_t *left) \ { \ (void) precedence; \ - eat(token_type); \ \ expression_t *unary_expression \ = allocate_expression_zero(unexpression_type); \ - unary_expression->unary.value = left; \ + unary_expression->base.source_position = *HERE; \ + eat(token_type); \ + unary_expression->unary.value = left; \ \ sfunc(&unary_expression->unary); \ \ @@ -6673,16 +7226,16 @@ static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right) bool const signed_left = is_type_signed(type_left); bool const signed_right = is_type_signed(type_right); - int const rank_left = get_rank(type_left); - int const rank_right = get_rank(type_right); + atomic_type_kind_t const rank_left = get_rank(type_left); + atomic_type_kind_t const rank_right = get_rank(type_right); if (signed_left == signed_right) return rank_left >= rank_right ? type_left : type_right; - int s_rank; - int u_rank; - type_t *s_type; - type_t *u_type; + atomic_type_kind_t s_rank; + atomic_type_kind_t u_rank; + type_t *s_type; + type_t *u_type; if (signed_left) { s_rank = rank_left; s_type = type_left; @@ -6701,21 +7254,13 @@ static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right) if (get_atomic_type_size(s_rank) > get_atomic_type_size(u_rank)) return s_type; - /* FIXME ugly */ - type_t *const type = allocate_type_zero(TYPE_ATOMIC, &builtin_source_position); switch (s_rank) { - case ATOMIC_TYPE_INT: type->atomic.akind = ATOMIC_TYPE_UINT; break; - case ATOMIC_TYPE_LONG: type->atomic.akind = ATOMIC_TYPE_ULONG; break; - case ATOMIC_TYPE_LONGLONG: type->atomic.akind = ATOMIC_TYPE_ULONGLONG; break; + case ATOMIC_TYPE_INT: return type_int; + case ATOMIC_TYPE_LONG: return type_long; + case ATOMIC_TYPE_LONGLONG: return type_long_long; default: panic("invalid atomic type"); } - - type_t* const result = typehash_insert(type); - if (result != type) - free_type(type); - - return result; } /** @@ -6733,7 +7278,8 @@ static void semantic_binexpr_arithmetic(binary_expression_t *expression) if (!is_type_arithmetic(type_left) || !is_type_arithmetic(type_right)) { /* TODO: improve error message */ if (is_type_valid(type_left) && is_type_valid(type_right)) { - errorf(HERE, "operation needs arithmetic types"); + errorf(&expression->base.source_position, + "operation needs arithmetic types"); } return; } @@ -6756,7 +7302,8 @@ static void semantic_shift_op(binary_expression_t *expression) if (!is_type_integer(type_left) || !is_type_integer(type_right)) { /* TODO: improve error message */ if (is_type_valid(type_left) && is_type_valid(type_right)) { - errorf(HERE, "operation needs integer types"); + errorf(&expression->base.source_position, + "operands of shift operation must have integer types"); } return; } @@ -6802,12 +7349,13 @@ static void semantic_add(binary_expression_t *expression) static void semantic_sub(binary_expression_t *expression) { - expression_t *const left = expression->left; - expression_t *const right = expression->right; - type_t *const orig_type_left = left->base.type; - type_t *const orig_type_right = right->base.type; - type_t *const type_left = skip_typeref(orig_type_left); - type_t *const type_right = skip_typeref(orig_type_right); + expression_t *const left = expression->left; + expression_t *const right = expression->right; + type_t *const orig_type_left = left->base.type; + type_t *const orig_type_right = right->base.type; + type_t *const type_left = skip_typeref(orig_type_left); + type_t *const type_right = skip_typeref(orig_type_right); + source_position_t const *const pos = &expression->base.source_position; /* § 5.6.5 */ if (is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) { @@ -6824,22 +7372,20 @@ static void semantic_sub(binary_expression_t *expression) type_t *const unqual_left = get_unqualified_type(skip_typeref(type_left->pointer.points_to)); type_t *const unqual_right = get_unqualified_type(skip_typeref(type_right->pointer.points_to)); if (!types_compatible(unqual_left, unqual_right)) { - errorf(&expression->base.source_position, + errorf(pos, "subtracting pointers to incompatible types '%T' and '%T'", orig_type_left, orig_type_right); } else if (!is_type_object(unqual_left)) { if (is_type_atomic(unqual_left, ATOMIC_TYPE_VOID)) { - warningf(&expression->base.source_position, - "subtracting pointers to void"); + warningf(pos, "subtracting pointers to void"); } else { - errorf(&expression->base.source_position, - "subtracting pointers to non-object types '%T'", + errorf(pos, "subtracting pointers to non-object types '%T'", orig_type_left); } } expression->base.type = type_ptrdiff_t; } else if (is_type_valid(type_left) && is_type_valid(type_right)) { - errorf(HERE, "invalid operands of types '%T' and '%T' to binary '-'", + errorf(pos, "invalid operands of types '%T' and '%T' to binary '-'", orig_type_left, orig_type_right); } } @@ -7000,7 +7546,8 @@ static void semantic_arithmetic_assign(binary_expression_t *expression) if (!is_type_arithmetic(type_left) || !is_type_arithmetic(type_right)) { /* TODO: improve error message */ if (is_type_valid(type_left) && is_type_valid(type_right)) { - errorf(HERE, "operation needs arithmetic types"); + errorf(&expression->base.source_position, + "operation needs arithmetic types"); } return; } @@ -7039,7 +7586,9 @@ static void semantic_arithmetic_addsubb_assign(binary_expression_t *expression) type_left, orig_type_left); expression->base.type = type_left; } else if (is_type_valid(type_left) && is_type_valid(type_right)) { - errorf(HERE, "incompatible types '%T' and '%T' in assignment", orig_type_left, orig_type_right); + errorf(&expression->base.source_position, + "incompatible types '%T' and '%T' in assignment", + orig_type_left, orig_type_right); } } @@ -7058,7 +7607,8 @@ static void semantic_logical_op(binary_expression_t *expression) if (!is_type_scalar(type_left) || !is_type_scalar(type_right)) { /* TODO: improve error message */ if (is_type_valid(type_left) && is_type_valid(type_right)) { - errorf(HERE, "operation needs scalar types"); + errorf(&expression->base.source_position, + "operation needs scalar types"); } return; } @@ -7235,14 +7785,13 @@ static void semantic_comma(binary_expression_t *expression) static expression_t *parse_##binexpression_type(unsigned precedence, \ expression_t *left) \ { \ + expression_t *binexpr = allocate_expression_zero(binexpression_type); \ + binexpr->base.source_position = *HERE; \ + binexpr->binary.left = left; \ eat(token_type); \ - source_position_t pos = *HERE; \ \ expression_t *right = parse_sub_expression(precedence + lr); \ \ - expression_t *binexpr = allocate_expression_zero(binexpression_type); \ - binexpr->base.source_position = pos; \ - binexpr->binary.left = left; \ binexpr->binary.right = right; \ sfunc(&binexpr->binary); \ \ @@ -7660,37 +8209,68 @@ 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(); + if (! is_constant_expression(statement->case_label.expression)) { + errorf(pos, "case label does not reduce to an integer constant"); + statement->case_label.is_bad = true; + } else { + long const val = fold_constant(statement->case_label.expression); + statement->case_label.first_case = val; + statement->case_label.last_case = val; + } if (c_mode & _GNUC) { if (token.type == T_DOTDOTDOT) { next_token(); statement->case_label.end_range = parse_expression(); + if (! is_constant_expression(statement->case_label.end_range)) { + errorf(pos, "case range does not reduce to an integer constant"); + statement->case_label.is_bad = true; + } else { + long const val = fold_constant(statement->case_label.end_range); + statement->case_label.last_case = val; + + if (val < statement->case_label.first_case) { + statement->case_label.is_empty = true; + warningf(pos, "empty range specified"); + } + } } } + PUSH_PARENT(statement); + 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; + if (current_switch != NULL) { + if (! statement->case_label.is_bad) { + /* Check for duplicate case values */ + case_label_statement_t *c = &statement->case_label; + for (case_label_statement_t *l = current_switch->first_case; l != NULL; l = l->next) { + if (l->is_bad || l->is_empty) + continue; + + if (c->last_case < l->first_case || c->first_case > l->last_case) + continue; + + errorf(pos, "duplicate case value (previously used %P)", + &l->base.source_position); + 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(); @@ -7699,25 +8279,13 @@ static statement_t *parse_case_statement(void) errorf(&inner_stmt->base.source_position, "declaration after case label"); } + POP_PARENT; return statement; end_error: + POP_PARENT; return create_invalid_statement(); } -/** - * Finds an existing default label of a switch statement. - */ -static case_label_statement_t * -find_default_label(const switch_statement_t *statement) -{ - case_label_statement_t *label = statement->first_case; - for ( ; label != NULL; label = label->next) { - if (label->expression == NULL) - return label; - } - return NULL; -} - /** * Parse a default statement. */ @@ -7726,23 +8294,26 @@ 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); + const case_label_statement_t *def_label = current_switch->default_label; if (def_label != NULL) { errorf(HERE, "multiple default labels in one switch (previous declared %P)", &def_label->base.source_position); } else { + current_switch->default_label = &statement->case_label; + /* 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, @@ -7755,8 +8326,10 @@ static statement_t *parse_default_statement(void) errorf(&inner_stmt->base.source_position, "declaration after default label"); } + POP_PARENT; return statement; end_error: + POP_PARENT; return create_invalid_statement(); } @@ -7797,6 +8370,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) { @@ -7804,13 +8383,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 == '}') { @@ -7844,6 +8419,7 @@ static statement_t *parse_label_statement(void) } label_last = &statement->label; + POP_PARENT; return statement; } @@ -7857,6 +8433,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(); @@ -7872,11 +8450,53 @@ static statement_t *parse_if(void) statement->ifs.false_statement = parse_statement(); } + POP_PARENT; return statement; end_error: + POP_PARENT; return create_invalid_statement(); } +/** + * Check that all enums are handled in a switch. + * + * @param statement the switch statement to check + */ +static void check_enum_cases(const switch_statement_t *statement) { + const type_t *type = skip_typeref(statement->expression->base.type); + if (! is_type_enum(type)) + return; + const enum_type_t *enumt = &type->enumt; + + /* if we have a default, no warnings */ + if (statement->default_label != NULL) + return; + + /* FIXME: calculation of value should be done while parsing */ + const declaration_t *declaration; + long last_value = -1; + for (declaration = enumt->declaration->next; + declaration != NULL && declaration->storage_class == STORAGE_CLASS_ENUM_ENTRY; + declaration = declaration->next) { + const expression_t *expression = declaration->init.enum_value; + long value = expression != NULL ? fold_constant(expression) : last_value + 1; + bool found = false; + for (const case_label_statement_t *l = statement->first_case; l != NULL; l = l->next) { + if (l->expression == NULL) + continue; + if (l->first_case <= value && value <= l->last_case) { + found = true; + break; + } + } + if (! found) { + warningf(&statement->base.source_position, + "enumeration value '%Y' not handled in switch", declaration->symbol); + } + last_value = value; + } +} + /** * Parse a switch statement. */ @@ -7887,7 +8507,10 @@ 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('('); + add_anchor_token(')'); expression_t *const expr = parse_expression(); type_t * type = skip_typeref(expr->base.type); if (is_type_integer(type)) { @@ -7899,6 +8522,7 @@ static statement_t *parse_switch(void) } statement->switchs.expression = create_implicit_cast(expr, type); expect(')'); + rem_anchor_token(')'); switch_statement_t *rem = current_switch; current_switch = &statement->switchs; @@ -7906,12 +8530,16 @@ static statement_t *parse_switch(void) current_switch = rem; if (warning.switch_default && - find_default_label(&statement->switchs) == NULL) { + statement->switchs.default_label == NULL) { warningf(&statement->base.source_position, "switch has no default case"); } + if (warning.switch_enum) + check_enum_cases(&statement->switchs); + POP_PARENT; return statement; end_error: + POP_PARENT; return create_invalid_statement(); } @@ -7936,6 +8564,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(); @@ -7944,8 +8574,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(); } @@ -7957,9 +8589,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); @@ -7972,8 +8605,10 @@ static statement_t *parse_do(void) expect(')'); expect(';'); + POP_PARENT; return statement; end_error: + POP_PARENT; return create_invalid_statement(); } @@ -7987,6 +8622,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); @@ -8034,9 +8671,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); @@ -8356,8 +8995,9 @@ static statement_t *parse_empty_statement(void) if (warning.empty_statement) { warningf(HERE, "statement is empty"); } + statement_t *const statement = create_empty_statement(); eat(';'); - return create_empty_statement(); + return statement; } /** @@ -8448,9 +9088,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('}'); @@ -8458,8 +9099,8 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) scope_t *last_scope = scope; set_scope(&statement->compound.scope); - statement_t *last_statement = NULL; - + statement_t **anchor = &statement->compound.statements; + bool only_decls_so_far = true; while (token.type != '}' && token.type != T_EOF) { statement_t *sub_statement = intern_parse_statement(); if (is_invalid_statement(sub_statement)) { @@ -8469,16 +9110,21 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) continue; } - if (last_statement != NULL) { - last_statement->base.next = sub_statement; - } else { - statement->compound.statements = sub_statement; + if (warning.declaration_after_statement) { + if (sub_statement->kind != STATEMENT_DECLARATION) { + only_decls_so_far = false; + } else if (!only_decls_so_far) { + warningf(&sub_statement->base.source_position, + "ISO C90 forbids mixed declarations and code"); + } } + *anchor = sub_statement; + while (sub_statement->base.next != NULL) sub_statement = sub_statement->base.next; - last_statement = sub_statement; + anchor = &sub_statement->base.next; } if (token.type == '}') { @@ -8513,6 +9159,7 @@ end_error: set_scope(last_scope); environment_pop_to(top); + POP_PARENT; return statement; } @@ -8527,13 +9174,20 @@ static void initialize_builtin_types(void) type_ptrdiff_t = make_global_typedef("__PTRDIFF_TYPE__", type_long); type_uintmax_t = make_global_typedef("__uintmax_t__", type_unsigned_long_long); type_uptrdiff_t = make_global_typedef("__UPTRDIFF_TYPE__", type_unsigned_long); - type_wchar_t = make_global_typedef("__WCHAR_TYPE__", type_int); + type_wchar_t = make_global_typedef("__WCHAR_TYPE__", opt_short_wchar_t ? type_unsigned_short : type_int); type_wint_t = make_global_typedef("__WINT_TYPE__", type_int); type_intmax_t_ptr = make_pointer_type(type_intmax_t, TYPE_QUALIFIER_NONE); type_ptrdiff_t_ptr = make_pointer_type(type_ptrdiff_t, TYPE_QUALIFIER_NONE); type_ssize_t_ptr = make_pointer_type(type_ssize_t, TYPE_QUALIFIER_NONE); type_wchar_t_ptr = make_pointer_type(type_wchar_t, TYPE_QUALIFIER_NONE); + + /* const version of wchar_t */ + type_const_wchar_t = allocate_type_zero(TYPE_TYPEDEF, &builtin_source_position); + type_const_wchar_t->typedeft.declaration = type_wchar_t->typedeft.declaration; + type_const_wchar_t->base.qualifiers |= TYPE_QUALIFIER_CONST; + + type_const_wchar_t_ptr = make_pointer_type(type_const_wchar_t, TYPE_QUALIFIER_NONE); } /**