X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=443946edbddb1c6b4879b162e2f38d5af5c4d352;hb=c0e7bebc766fcdd5ed3e42ca34ef9bdb3c573f7a;hp=749a1ee8400f6610d5bde978d88e14fd0a71ceb5;hpb=cd24f33c24e552774d431fedc17ecc00d02b2cb9;p=cparser diff --git a/parser.c b/parser.c index 749a1ee..443946e 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 */ @@ -165,7 +179,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 +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; } @@ -540,10 +556,6 @@ static bool at_anchor(void) */ static void eat_until_matching_token(int type) { - unsigned parenthesis_count = 0; - unsigned brace_count = 0; - unsigned bracket_count = 0; - int end_token; switch (type) { case '(': end_token = ')'; break; @@ -552,26 +564,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; } @@ -821,6 +847,10 @@ static void label_pop_to(size_t new_top) stack_pop_to(&label_stack, new_top); } +static int get_akind_rank(atomic_type_kind_t akind) +{ + return (int) akind; +} static int get_rank(const type_t *type) { @@ -831,10 +861,10 @@ static int get_rank(const type_t *type) * (unsigned int would be preferable when possible... for stuff like * struct { enum { ... } bla : 4; } ) */ if (type->kind == TYPE_ENUM) - return ATOMIC_TYPE_INT; + return get_akind_rank(ATOMIC_TYPE_INT); assert(type->kind == TYPE_ATOMIC); - return type->atomic.akind; + return get_akind_rank(type->atomic.akind); } static type_t *promote_integer(type_t *type) @@ -842,7 +872,7 @@ static type_t *promote_integer(type_t *type) if (type->kind == TYPE_BITFIELD) type = type->bitfield.base_type; - if (get_rank(type) < ATOMIC_TYPE_INT) + if (get_rank(type) < get_akind_rank(ATOMIC_TYPE_INT)) type = type_int; return type; @@ -941,9 +971,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 pointer target type", + orig_type_left, context, orig_type_right, missing_qualifiers); return; } @@ -986,12 +1016,13 @@ static assign_error_t semantic_assign(type_t *orig_type_left, = skip_typeref(type_left->pointer.points_to); type_t *points_to_right = skip_typeref(type_right->pointer.points_to); + assign_error_t res = ASSIGN_SUCCESS; /* the left type has all qualifiers from the right type */ unsigned missing_qualifiers = points_to_right->base.qualifiers & ~points_to_left->base.qualifiers; if (missing_qualifiers != 0) { - return ASSIGN_ERROR_POINTER_QUALIFIER_MISSING; + res = ASSIGN_ERROR_POINTER_QUALIFIER_MISSING; } points_to_left = get_unqualified_type(points_to_left); @@ -999,14 +1030,14 @@ static assign_error_t semantic_assign(type_t *orig_type_left, if (is_type_atomic(points_to_left, ATOMIC_TYPE_VOID) || is_type_atomic(points_to_right, ATOMIC_TYPE_VOID)) { - return ASSIGN_SUCCESS; + return res; } if (!types_compatible(points_to_left, points_to_right)) { return ASSIGN_WARNING_POINTER_INCOMPATIBLE; } - return ASSIGN_SUCCESS; + return res; } else if (is_type_integer(type_right)) { return ASSIGN_WARNING_POINTER_FROM_INT; } @@ -1061,6 +1092,7 @@ static type_t *make_global_typedef(const char *name, type_t *type) declaration->type = type; declaration->symbol = symbol; declaration->source_position = builtin_source_position; + declaration->implicit = true; record_declaration(declaration); @@ -1590,7 +1622,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: @@ -1639,6 +1670,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 */ @@ -2328,7 +2360,16 @@ static initializer_t *parse_sub_initializer(type_path_t *path, 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)) { @@ -3020,13 +3061,28 @@ end_error: return; } +static declaration_t *create_error_declaration(symbol_t *symbol, storage_class_tag_t storage_class) +{ + declaration_t *const decl = allocate_declaration_zero(); + decl->source_position = *HERE; + decl->storage_class = + storage_class != STORAGE_CLASS_NONE || scope == global_scope ? + storage_class : STORAGE_CLASS_AUTO; + decl->declared_storage_class = decl->storage_class; + decl->symbol = symbol; + decl->implicit = true; + record_declaration(decl); + return decl; +} + static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) { type_t *type = NULL; 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; @@ -3136,6 +3192,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) case T__forceinline: /* only in microsoft mode */ specifiers->modifiers |= DM_FORCEINLINE; + /* FALLTHROUGH */ case T_inline: next_token(); @@ -3179,13 +3236,58 @@ 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 specifier", &token); + next_token(); + continue; + + default: + 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); + + declaration_t *const decl = + create_error_declaration(token.v.symbol, STORAGE_CLASS_TYPEDEF); - type_t *typedef_type = get_typedef_type(token.v.symbol); + type = allocate_type_zero(TYPE_TYPEDEF, HERE); + type->typedeft.declaration = decl; - if (typedef_type == NULL) - goto finish_specifiers; + next_token(); + saw_error = true; + if (la1_type == '*') + goto finish_specifiers; + continue; + } + + default: + goto finish_specifiers; + } + } next_token(); type = typedef_type; @@ -3199,8 +3301,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) } finish_specifiers: - - if (type == NULL) { + if (type == NULL || (saw_error && type_specifiers != 0)) { atomic_type_kind_t atomic_type; /* match valid basic types */ @@ -3246,17 +3347,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: @@ -3331,7 +3439,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'"); } @@ -3342,7 +3455,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 { @@ -3363,11 +3476,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 */ @@ -3440,12 +3551,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; - 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"); + switch (declaration->declared_storage_class) { + case STORAGE_CLASS_TYPEDEF: + errorf(pos, "typedef not allowed in parameter list"); + break; + + /* 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; @@ -3458,7 +3578,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); } } @@ -3483,9 +3603,10 @@ static declaration_t *parse_parameters(function_type_t *type) add_anchor_token(')'); int saved_comma_state = save_and_reset_anchor_state(','); - if (token.type == T_IDENTIFIER) { - symbol_t *symbol = token.v.symbol; - if (!is_typedef_symbol(symbol)) { + if (token.type == T_IDENTIFIER && + !is_typedef_symbol(token.v.symbol)) { + token_type_t la1_type = look_ahead(1)->type; + if (la1_type == ',' || la1_type == ')') { type->kr_style_parameters = true; declarations = parse_identifier_list(); goto parameters_finished; @@ -3671,7 +3792,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) { @@ -3756,6 +3877,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) { @@ -3772,6 +3896,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; @@ -3961,9 +4087,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; @@ -4087,7 +4213,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; @@ -4105,6 +4231,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) { @@ -4211,8 +4344,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 && @@ -4609,6 +4742,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) { @@ -4622,6 +4759,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_DO_WHILE && + stmt->kind != STATEMENT_FOR && + (stmt->kind != STATEMENT_COMPOUND || stmt->compound.statements == NULL)) { + 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 @@ -4684,6 +5247,12 @@ static void parse_external_declaration(void) return; } + if (warning.aggregate_return && + is_type_compound(skip_typeref(type->function.return_type))) { + warningf(HERE, "function '%Y' returns an aggregate", + ndeclaration->symbol); + } + /* § 6.7.5.3 (14) a function definition with () means no * parameters (and not unspecified parameters) */ if (type->function.unspecified_parameters @@ -4719,7 +5288,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); @@ -4733,12 +5302,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); @@ -4971,7 +5558,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; } @@ -4994,7 +5581,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; } @@ -5098,6 +5685,7 @@ static declaration_t *create_implicit_function(symbol_t *symbol, declaration->type = type; declaration->symbol = symbol; declaration->source_position = *source_position; + declaration->implicit = true; bool strict_prototypes_old = warning.strict_prototypes; warning.strict_prototypes = false; @@ -5288,9 +5876,11 @@ static expression_t *parse_reference(void) next_token(); if (declaration == NULL) { - if (! strict_mode && token.type == '(') { - /* an implicitly defined function */ - if (warning.implicit_function_declaration) { + if (token.type == '(') { + /* an implicitly declared function */ + if (strict_mode) { + errorf(HERE, "unknown symbol '%Y' found.", symbol); + } else if (warning.implicit_function_declaration) { warningf(HERE, "implicit declaration of function '%Y'", symbol); } @@ -5299,11 +5889,11 @@ static expression_t *parse_reference(void) &source_position); } else { errorf(HERE, "unknown symbol '%Y' found.", symbol); - return create_invalid_expression(); + declaration = create_error_declaration(symbol, STORAGE_CLASS_NONE); } } - type_t *type = declaration->type; + type_t *type = declaration->type; /* we always do the auto-type conversions; the & and sizeof parser contains * code to revert this! */ @@ -5316,29 +5906,72 @@ 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); } } return expression; } -static void check_cast_allowed(expression_t *expression, type_t *dest_type) +static bool semantic_cast(expression_t *cast) { - (void) expression; - (void) dest_type; - /* TODO check if explicit cast is allowed and issue warnings/errors */ + expression_t *expression = cast->unary.value; + type_t *orig_dest_type = cast->base.type; + type_t *orig_type_right = expression->base.type; + type_t const *dst_type = skip_typeref(orig_dest_type); + type_t const *src_type = skip_typeref(orig_type_right); + source_position_t const *pos = &cast->base.source_position; + + /* §6.5.4 A (void) cast is explicitly permitted, more for documentation than for utility. */ + if (dst_type == type_void) + return true; + + /* only integer and pointer can be casted to pointer */ + if (is_type_pointer(dst_type) && + !is_type_pointer(src_type) && + !is_type_integer(src_type) && + is_type_valid(src_type)) { + errorf(pos, "cannot convert type '%T' to a pointer type", orig_type_right); + return false; + } + + if (!is_type_scalar(dst_type) && is_type_valid(dst_type)) { + errorf(pos, "conversion to non-scalar type '%T' requested", orig_dest_type); + return false; + } + + if (!is_type_scalar(src_type) && is_type_valid(src_type)) { + errorf(pos, "conversion from non-scalar type '%T' requested", orig_type_right); + return false; + } + + if (warning.cast_qual && + is_type_pointer(src_type) && + is_type_pointer(dst_type)) { + type_t *src = skip_typeref(src_type->pointer.points_to); + type_t *dst = skip_typeref(dst_type->pointer.points_to); + unsigned missing_qualifiers = + src->base.qualifiers & ~dst->base.qualifiers; + if (missing_qualifiers != 0) { + warningf(pos, + "cast discards qualifiers '%Q' in pointer target type of '%T'", + missing_qualifiers, orig_type_right); + } + } + return true; } static expression_t *parse_compound_literal(type_t *type) @@ -5380,12 +6013,13 @@ static expression_t *parse_cast(void) cast->base.source_position = source_position; expression_t *value = parse_sub_expression(20); - - check_cast_allowed(value, type); - cast->base.type = type; cast->unary.value = value; + if (! semantic_cast(cast)) { + /* TODO: record the error in the AST. else it is impossible to detect it */ + } + return cast; end_error: return create_invalid_expression(); @@ -5425,9 +6059,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(')'); @@ -5913,7 +6547,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(); } @@ -6266,6 +6900,12 @@ static expression_t *parse_call_expression(unsigned precedence, check_format(&result->call); + if (warning.aggregate_return && + is_type_compound(skip_typeref(function_type->return_type))) { + warningf(&result->base.source_position, + "function call has aggregate value"); + } + return result; end_error: return create_invalid_expression(); @@ -6289,13 +6929,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; @@ -6305,7 +6946,12 @@ static expression_t *parse_conditional_expression(unsigned precedence, &expression->base.source_position, condition_type_orig); } - expression_t *true_expression = parse_expression(); + expression_t *true_expression = expression; + bool gnu_cond = false; + if ((c_mode & _GNUC) && token.type == ':') { + gnu_cond = true; + } else + true_expression = parse_expression(); rem_anchor_token(':'); expect(':'); expression_t *false_expression = parse_sub_expression(precedence); @@ -6321,7 +6967,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; @@ -6367,7 +7013,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; @@ -6382,7 +7028,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 { @@ -6395,14 +7041,14 @@ 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; } conditional->true_expression - = create_implicit_cast(true_expression, result_type); + = gnu_cond ? NULL : create_implicit_cast(true_expression, result_type); conditional->false_expression = create_implicit_cast(false_expression, result_type); conditional->base.type = result_type; @@ -6446,24 +7092,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) @@ -6471,11 +7130,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; } @@ -6487,7 +7150,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; } @@ -6495,18 +7159,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) @@ -6515,7 +7177,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; } @@ -6529,7 +7192,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; } @@ -6578,11 +7242,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); \ @@ -6595,7 +7258,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, @@ -6613,11 +7276,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); \ \ @@ -6652,8 +7316,8 @@ 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); + int const rank_left = get_rank(type_left); + int const rank_right = get_rank(type_right); if (signed_left == signed_right) return rank_left >= rank_right ? type_left : type_right; @@ -6677,24 +7341,19 @@ static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right) if (u_rank >= s_rank) return u_type; - if (get_atomic_type_size(s_rank) > get_atomic_type_size(u_rank)) + /* casting rank to atomic_type_kind is a bit hacky, but makes things + * easier here... */ + if (get_atomic_type_size((atomic_type_kind_t) s_rank) + > get_atomic_type_size((atomic_type_kind_t) 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_unsigned_int; + case ATOMIC_TYPE_LONG: return type_unsigned_long; + case ATOMIC_TYPE_LONGLONG: return type_unsigned_long_long; default: panic("invalid atomic type"); } - - type_t* const result = typehash_insert(type); - if (result != type) - free_type(type); - - return result; } /** @@ -6712,7 +7371,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; } @@ -6723,6 +7383,24 @@ static void semantic_binexpr_arithmetic(binary_expression_t *expression) expression->base.type = arithmetic_type; } +static void warn_div_by_zero(binary_expression_t const *const expression) +{ + if (warning.div_by_zero && + is_type_integer(expression->base.type) && + is_constant_expression(expression->right) && + fold_constant(expression->right) == 0) { + warningf(&expression->base.source_position, "division by zero"); + } +} + +/** + * Check the semantic restrictions for a div/mod expression. + */ +static void semantic_divmod_arithmetic(binary_expression_t *expression) { + semantic_binexpr_arithmetic(expression); + warn_div_by_zero(expression); +} + static void semantic_shift_op(binary_expression_t *expression) { expression_t *const left = expression->left; @@ -6735,7 +7413,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; } @@ -6781,12 +7460,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)) { @@ -6803,22 +7483,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); } } @@ -6979,7 +7657,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; } @@ -6993,6 +7672,12 @@ static void semantic_arithmetic_assign(binary_expression_t *expression) expression->base.type = type_left; } +static void semantic_divmod_assign(binary_expression_t *expression) +{ + semantic_arithmetic_assign(expression); + warn_div_by_zero(expression); +} + static void semantic_arithmetic_addsubb_assign(binary_expression_t *expression) { expression_t *const left = expression->left; @@ -7018,7 +7703,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); } } @@ -7037,7 +7724,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; } @@ -7214,14 +7902,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); \ \ @@ -7230,8 +7917,8 @@ static expression_t *parse_##binexpression_type(unsigned precedence, \ CREATE_BINEXPR_PARSER(',', EXPR_BINARY_COMMA, semantic_comma, 1) CREATE_BINEXPR_PARSER('*', EXPR_BINARY_MUL, semantic_binexpr_arithmetic, 1) -CREATE_BINEXPR_PARSER('/', EXPR_BINARY_DIV, semantic_binexpr_arithmetic, 1) -CREATE_BINEXPR_PARSER('%', EXPR_BINARY_MOD, semantic_binexpr_arithmetic, 1) +CREATE_BINEXPR_PARSER('/', EXPR_BINARY_DIV, semantic_divmod_arithmetic, 1) +CREATE_BINEXPR_PARSER('%', EXPR_BINARY_MOD, semantic_divmod_arithmetic, 1) CREATE_BINEXPR_PARSER('+', EXPR_BINARY_ADD, semantic_add, 1) CREATE_BINEXPR_PARSER('-', EXPR_BINARY_SUB, semantic_sub, 1) CREATE_BINEXPR_PARSER('<', EXPR_BINARY_LESS, semantic_comparison, 1) @@ -7268,9 +7955,9 @@ CREATE_BINEXPR_PARSER(T_MINUSEQUAL, EXPR_BINARY_SUB_ASSIGN, CREATE_BINEXPR_PARSER(T_ASTERISKEQUAL, EXPR_BINARY_MUL_ASSIGN, semantic_arithmetic_assign, 0) CREATE_BINEXPR_PARSER(T_SLASHEQUAL, EXPR_BINARY_DIV_ASSIGN, - semantic_arithmetic_assign, 0) + semantic_divmod_assign, 0) CREATE_BINEXPR_PARSER(T_PERCENTEQUAL, EXPR_BINARY_MOD_ASSIGN, - semantic_arithmetic_assign, 0) + semantic_divmod_assign, 0) CREATE_BINEXPR_PARSER(T_LESSLESSEQUAL, EXPR_BINARY_SHIFTLEFT_ASSIGN, semantic_arithmetic_assign, 0) CREATE_BINEXPR_PARSER(T_GREATERGREATEREQUAL, EXPR_BINARY_SHIFTRIGHT_ASSIGN, @@ -7639,59 +8326,83 @@ 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 || l->expression == NULL) + 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(); + 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(); } -/** - * 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. */ @@ -7700,32 +8411,42 @@ 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, "'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(); } @@ -7766,6 +8487,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) { @@ -7773,13 +8500,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 == '}') { @@ -7798,7 +8521,11 @@ static statement_t *parse_label_statement(void) 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"); + } } /* remember the labels in a list for later checking */ @@ -7809,6 +8536,7 @@ static statement_t *parse_label_statement(void) } label_last = &statement->label; + POP_PARENT; return statement; } @@ -7822,6 +8550,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(); @@ -7837,11 +8567,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. */ @@ -7852,7 +8624,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)) { @@ -7864,6 +8639,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; @@ -7871,12 +8647,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(); } @@ -7901,6 +8681,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(); @@ -7909,8 +8691,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(); } @@ -7922,9 +8706,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); @@ -7937,8 +8722,10 @@ static statement_t *parse_do(void) expect(')'); expect(';'); + POP_PARENT; return statement; end_error: + POP_PARENT; return create_invalid_statement(); } @@ -7952,6 +8739,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); @@ -7999,9 +8788,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); @@ -8321,8 +9112,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; } /** @@ -8337,15 +9129,25 @@ static statement_t *intern_parse_statement(void) /* declaration or statement */ add_anchor_token(';'); switch (token.type) { - case T_IDENTIFIER: - if (look_ahead(1)->type == ':') { + case T_IDENTIFIER: { + token_type_t la1_type = (token_type_t)look_ahead(1)->type; + if (la1_type == ':') { statement = parse_label_statement(); } else if (is_typedef_symbol(token.v.symbol)) { statement = parse_declaration_statement(); - } else { - statement = parse_expression_statement(); + } else switch (la1_type) { + DECLARATION_START + case T_IDENTIFIER: + case '*': + statement = parse_declaration_statement(); + break; + + default: + statement = parse_expression_statement(); + break; } break; + } case T___extension__: /* This can be a prefix to a declaration or an expression statement. @@ -8413,9 +9215,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('}'); @@ -8423,8 +9226,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)) { @@ -8434,16 +9237,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 == '}') { @@ -8478,6 +9286,7 @@ end_error: set_scope(last_scope); environment_pop_to(top); + POP_PARENT; return statement; } @@ -8492,13 +9301,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); } /** @@ -8557,22 +9373,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; } }