X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=501f575b62c9f10898c6bf2d20e8c9545eec8382;hb=1518ab3996492fbb86a084cca8ea8cb851cd3b80;hp=4925adf0259ff39d0f2fb74831165a9a11bd5d41;hpb=2788e437530378ada31a28484ec49a9eeb05faf2;p=cparser diff --git a/parser.c b/parser.c index 4925adf..501f575 100644 --- a/parser.c +++ b/parser.c @@ -840,7 +840,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 @@ -959,9 +959,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; } @@ -1608,7 +1608,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: @@ -1657,6 +1656,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 */ @@ -3053,7 +3053,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; @@ -3207,13 +3208,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; + + default: + goto finish_specifiers; + } + } - type_t *typedef_type = get_typedef_type(token.v.symbol); + 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; - if (typedef_type == NULL) - goto finish_specifiers; + default: + goto finish_specifiers; + } + } next_token(); type = typedef_type; @@ -3274,17 +3312,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: @@ -3359,7 +3404,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'"); } @@ -3370,7 +3420,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 { @@ -3391,11 +3441,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 */ @@ -3468,12 +3516,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; @@ -3486,7 +3543,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); } } @@ -3699,7 +3756,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) { @@ -3766,7 +3823,7 @@ static construct_type_t *parse_inner_declarator(declaration_t *declaration, construct_type_t *last = NULL; gnu_attribute_t *attributes = NULL; - declaration->modifiers |= parse_attributes(&attributes); + decl_modifiers_t modifiers = parse_attributes(&attributes); /* pointers */ while (token.type == '*') { @@ -3781,9 +3838,12 @@ static construct_type_t *parse_inner_declarator(declaration_t *declaration, } /* TODO: find out if this is correct */ - declaration->modifiers |= parse_attributes(&attributes); + modifiers |= parse_attributes(&attributes); } + if (declaration != NULL) + declaration->modifiers |= modifiers; + construct_type_t *inner_types = NULL; switch(token.type) { @@ -3800,6 +3860,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; @@ -3989,9 +4051,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; @@ -4115,7 +4177,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; @@ -4133,6 +4195,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) { @@ -4637,6 +4706,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) { @@ -4658,6 +4731,8 @@ static int determine_truth(expression_t const* const cond) -1; } +static bool noreturn_candidate; + static void check_reachable(statement_t *const stmt) { if (stmt->base.reachable) @@ -4680,6 +4755,7 @@ static void check_reachable(statement_t *const stmt) break; case STATEMENT_RETURN: + noreturn_candidate = false; return; case STATEMENT_IF: { @@ -4714,9 +4790,7 @@ static void check_reachable(statement_t *const stmt) continue; } - expression_t *const case_expr = i->expression; - if (is_constant_expression(case_expr) && - fold_constant(case_expr) == val) { + if (i->first_case <= val && val <= i->last_case) { check_reachable((statement_t*)i); return; } @@ -4790,6 +4864,7 @@ static void check_reachable(statement_t *const stmt) case STATEMENT_WHILE: case STATEMENT_DO_WHILE: case STATEMENT_FOR: + last = parent; next = parent->base.next; goto found_break_parent; @@ -4861,11 +4936,14 @@ found_break_parent: 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"); @@ -4982,8 +5060,7 @@ static void check_unreachable(statement_t const* const stmt) stmt->kind != STATEMENT_COMPOUND && stmt->kind != STATEMENT_DO_WHILE && stmt->kind != STATEMENT_FOR) { - warningf(&stmt->base.source_position, - "statement is unreachable"); + warningf(&stmt->base.source_position, "statement is unreachable"); } switch (stmt->kind) { @@ -5040,19 +5117,24 @@ static void check_unreachable(statement_t const* const stmt) case STATEMENT_FOR: { for_statement_t const* const fors = &stmt->fors; - if (!stmt->base.reachable && fors->initialisation != NULL) { - warningf(&fors->initialisation->base.source_position, - "initialisation of for-statement is unreachable"); - } + // if 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->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"); + if (!fors->step_reachable && fors->step != NULL) { + warningf(&fors->step->base.source_position, + "step of for-statement is unreachable"); + } } check_unreachable(stmt->fors.body); @@ -5164,7 +5246,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); @@ -5185,10 +5267,20 @@ static void parse_external_declaration(void) first_err = true; check_labels(); check_declarations(); - if (warning.return_type || warning.unreachable_code) { + 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); @@ -5424,7 +5516,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; } @@ -5447,7 +5539,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; } @@ -5769,18 +5861,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); } } @@ -6742,13 +6836,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; @@ -6774,7 +6869,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; @@ -6820,7 +6915,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; @@ -6835,7 +6930,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 { @@ -6848,7 +6943,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; @@ -6899,7 +6994,7 @@ 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) { @@ -6907,16 +7002,30 @@ static void check_pointer_arithmetic(const source_position_t *source_position, points_to = skip_typeref(points_to); if (is_type_incomplete(points_to) && - (! (c_mode & _GNUC) - || !is_type_atomic(points_to, ATOMIC_TYPE_VOID))) { + !((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); - } else if (is_type_function(points_to)) { + "arithmetic with pointer to incomplete type '%T' not allowed", + orig_pointer_type); + return false; + } else if (!(c_mode & _GNUC) && is_type_function(points_to)) { errorf(source_position, - "arithmetic with pointer to function type '%T' not allowed", - orig_pointer_type); + "arithmetic with pointer to function type '%T' not allowed", + orig_pointer_type); + return false; + } + if (warning.pointer_arith) { + if (is_type_atomic(points_to, ATOMIC_TYPE_VOID)) { + warningf(source_position, + "pointer of type '%T' used in arithmetic", + orig_pointer_type); + } else if (is_type_function(points_to)) { + warningf(source_position, + "pointer to a function '%T' used in arithmetic", + orig_pointer_type); + } } + return true; } static void semantic_incdec(unary_expression_t *expression) @@ -6924,11 +7033,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; } @@ -6940,7 +7053,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; } @@ -6948,18 +7062,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) @@ -6968,7 +7080,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; } @@ -6982,7 +7095,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; } @@ -7031,11 +7145,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); \ @@ -7048,7 +7161,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, @@ -7066,11 +7179,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); \ \ @@ -7105,16 +7219,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; @@ -7133,21 +7247,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; } /** @@ -7165,7 +7271,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; } @@ -7188,7 +7295,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; } @@ -7234,12 +7342,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)) { @@ -7256,22 +7365,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); } } @@ -7432,7 +7539,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; } @@ -7471,7 +7579,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); } } @@ -7490,7 +7600,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; } @@ -7667,14 +7778,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); \ \ @@ -8097,34 +8207,54 @@ static statement_t *parse_case_statement(void) *pos = token.source_position; statement->case_label.expression = parse_expression(); - - PUSH_PARENT(statement); + 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(pos, "case label does not reduce to an integer constant"); - } else if (current_switch != NULL) { - /* Check for duplicate case values */ - /* FIXME slow */ - long const val = fold_constant(statement->case_label.expression); - for (case_label_statement_t *l = current_switch->first_case; l != NULL; l = l->next) { - expression_t const* const e = l->expression; - if (e == NULL || !is_constant_expression(e) || fold_constant(e) != val) - continue; + 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; - errorf(pos, "duplicate case value"); - errorf(&l->base.source_position, "previously used here"); - break; - } + 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; @@ -8149,20 +8279,6 @@ end_error: 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. */ @@ -8177,11 +8293,13 @@ static statement_t *parse_default_statement(void) 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 = &statement->case_label; @@ -8332,6 +8450,46 @@ end_error: 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. */ @@ -8345,6 +8503,7 @@ static statement_t *parse_switch(void) 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)) { @@ -8356,6 +8515,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; @@ -8363,9 +8523,11 @@ 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; @@ -8931,6 +9093,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) statement_t *last_statement = NULL; + 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)) { @@ -8940,6 +9103,15 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) continue; } + 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"); + } + } + if (last_statement != NULL) { last_statement->base.next = sub_statement; } else { @@ -9006,6 +9178,13 @@ static void initialize_builtin_types(void) 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); } /**