X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=3c1001362c37fd0f8ca179a1da1763e1e73ee011;hb=1cd9fac9d1a48d012cf3084c8edc4130e75a1ea5;hp=b45e513a6b076dc3bd61528a140fcc1af6fc35a8;hpb=38bd1c517215f649be5bffabc713076bff6577af;p=cparser diff --git a/parser.c b/parser.c index b45e513..3c10013 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 @@ -95,19 +103,22 @@ typedef struct parse_initializer_env_t { bool must_be_constant; } parse_initializer_env_t; -typedef declaration_t* (*parsed_declaration_func) (declaration_t *declaration); +typedef declaration_t* (*parsed_declaration_func) (declaration_t *declaration, bool is_definition); static token_t token; static token_t lookahead_buffer[MAX_LOOKAHEAD]; static int lookahead_bufpos; static stack_entry_t *environment_stack = NULL; static stack_entry_t *label_stack = NULL; +static stack_entry_t *local_label_stack = NULL; static scope_t *global_scope = NULL; static scope_t *scope = NULL; static declaration_t *last_declaration = NULL; static declaration_t *current_function = NULL; +static declaration_t *current_init_decl = 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 +127,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 */ @@ -156,7 +172,7 @@ static type_t *parse_typename(void); static void parse_compound_type_entries(declaration_t *compound_declaration); static declaration_t *parse_declarator( const declaration_specifiers_t *specifiers, bool may_be_abstract); -static declaration_t *record_declaration(declaration_t *declaration); +static declaration_t *record_declaration(declaration_t *declaration, bool is_definition); static void semantic_comparison(binary_expression_t *expression); @@ -300,6 +316,7 @@ static size_t get_expression_struct_size(expression_kind_t kind) [EXPR_VA_START] = sizeof(va_start_expression_t), [EXPR_VA_ARG] = sizeof(va_arg_expression_t), [EXPR_STATEMENT] = sizeof(statement_expression_t), + [EXPR_LABEL_ADDRESS] = sizeof(label_address_expression_t), }; if (kind >= EXPR_UNARY_FIRST && kind <= EXPR_UNARY_LAST) { return sizes[EXPR_UNARY_FIRST]; @@ -321,7 +338,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; } @@ -463,13 +481,21 @@ static size_t environment_top(void) } /** - * Returns the index of the top element of the label stack. + * Returns the index of the top element of the global label stack. */ static size_t label_top(void) { return ARR_LEN(label_stack); } +/** + * Returns the index of the top element of the local label stack. + */ +static size_t local_label_top(void) +{ + return ARR_LEN(local_label_stack); +} + /** * Return the next token. */ @@ -748,6 +774,11 @@ static void stack_push(stack_entry_t **stack_ptr, declaration_t *declaration) ARR_APP1(stack_entry_t, *stack_ptr, entry); } +/** + * Push a declaration on the environment stack. + * + * @param declaration the declaration + */ static void environment_push(declaration_t *declaration) { assert(declaration->source_position.input_name != NULL); @@ -756,7 +787,7 @@ static void environment_push(declaration_t *declaration) } /** - * Push a declaration of the label stack. + * Push a declaration on the global label stack. * * @param declaration the declaration */ @@ -766,6 +797,17 @@ static void label_push(declaration_t *declaration) stack_push(&label_stack, declaration); } +/** + * Push a declaration of the local label stack. + * + * @param declaration the declaration + */ +static void local_label_push(declaration_t *declaration) +{ + assert(declaration->parent_scope != NULL); + stack_push(&local_label_stack, declaration); +} + /** * pops symbols from the environment stack until @p new_top is the top element */ @@ -816,13 +858,19 @@ static void stack_pop_to(stack_entry_t **stack_ptr, size_t new_top) ARR_SHRINKLEN(*stack_ptr, (int) new_top); } +/** + * Pop all entries from the environment stack until the new_top + * is reached. + * + * @param new_top the new stack top + */ static void environment_pop_to(size_t new_top) { stack_pop_to(&environment_stack, new_top); } /** - * Pop all entries on the label stack until the new_top + * Pop all entries from the global label stack until the new_top * is reached. * * @param new_top the new stack top @@ -832,6 +880,22 @@ static void label_pop_to(size_t new_top) stack_pop_to(&label_stack, new_top); } +/** + * Pop all entries from the local label stack until the new_top + * is reached. + * + * @param new_top the new stack top + */ +static void local_label_pop_to(size_t new_top) +{ + stack_pop_to(&local_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) { @@ -842,10 +906,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) @@ -853,7 +917,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; @@ -952,9 +1016,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; } @@ -997,12 +1061,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); @@ -1010,14 +1075,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; } @@ -1072,8 +1137,9 @@ 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); + record_declaration(declaration, false); type_t *typedef_type = allocate_type_zero(TYPE_TYPEDEF, &builtin_source_position); typedef_type->typedeft.declaration = declaration; @@ -1601,7 +1667,6 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) switch(kind) { case GNU_AK_CONST: case GNU_AK_VOLATILE: - case GNU_AK_DEPRECATED: case GNU_AK_NAKED: case GNU_AK_MALLOC: case GNU_AK_WEAK: @@ -1650,6 +1715,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 */ @@ -2705,7 +2771,7 @@ static void parse_enum_entries(type_t *const enum_type) /* TODO semantic */ } - record_declaration(entry); + record_declaration(entry, false); if (token.type != ',') break; @@ -3040,13 +3106,117 @@ 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->declared_storage_class = storage_class; + decl->storage_class = + storage_class != STORAGE_CLASS_NONE || scope == global_scope ? + storage_class : STORAGE_CLASS_AUTO; + decl->symbol = symbol; + decl->implicit = true; + record_declaration(decl, false); + return decl; +} + +/** + * Finish the construction of a struct type by calculating + * its size, offsets, alignment. + */ +static void finish_struct_type(compound_type_t *type) { + if (type->declaration == NULL) + return; + declaration_t *struct_decl = type->declaration; + if (! struct_decl->init.complete) + return; + + il_size_t size = 0; + il_size_t new_size; + il_alignment_t alignment = 1; + bool need_pad = false; + + declaration_t *entry = struct_decl->scope.declarations; + for (; entry != NULL; entry = entry->next) { + if (entry->namespc != NAMESPACE_NORMAL) + continue; + + type_t *m_type = skip_typeref(entry->type); + il_alignment_t m_alignment = m_type->base.alignment; + + new_size = (size + m_alignment - 1) & -m_alignment; + if (m_alignment > alignment) + alignment = m_alignment; + if (new_size > size) + need_pad = true; + entry->offset = new_size; + size = new_size + m_type->base.size; + } + if (type->base.alignment != 0) { + alignment = type->base.alignment; + } + + new_size = (size + alignment - 1) & -alignment; + if (new_size > size) + need_pad = true; + + if (warning.padded && need_pad) { + warningf(&struct_decl->source_position, + "'%#T' needs padding", type, struct_decl->symbol); + } + if (warning.packed && !need_pad) { + warningf(&struct_decl->source_position, + "superfluous packed attribute on '%#T'", + type, struct_decl->symbol); + } + + type->base.size = new_size; + type->base.alignment = alignment; +} + +/** + * Finish the construction of an union type by calculating + * its size and alignment. + */ +static void finish_union_type(compound_type_t *type) { + if (type->declaration == NULL) + return; + declaration_t *union_decl = type->declaration; + if (! union_decl->init.complete) + return; + + il_size_t size = 0; + il_alignment_t alignment = 1; + + declaration_t *entry = union_decl->scope.declarations; + for (; entry != NULL; entry = entry->next) { + if (entry->namespc != NAMESPACE_NORMAL) + continue; + + type_t *m_type = skip_typeref(entry->type); + + entry->offset = 0; + if (m_type->base.size > size) + size = m_type->base.size; + if (m_type->base.alignment > alignment) + alignment = m_type->base.alignment; + } + if (type->base.alignment != 0) { + alignment = type->base.alignment; + } + size = (size + alignment - 1) & -alignment; + type->base.size = size; + type->base.alignment = alignment; +} + 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; @@ -3178,6 +3348,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) type = allocate_type_zero(TYPE_COMPOUND_STRUCT, HERE); type->compound.declaration = parse_compound_type_specifier(true); + finish_struct_type(&type->compound); break; } case T_union: { @@ -3186,6 +3357,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) if (type->compound.declaration->modifiers & DM_TRANSPARENT_UNION) modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION; break; + finish_union_type(&type->compound); } case T_enum: type = parse_enum_specifier(); @@ -3200,13 +3372,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); - type_t *typedef_type = get_typedef_type(token.v.symbol); + declaration_t *const decl = + create_error_declaration(token.v.symbol, STORAGE_CLASS_TYPEDEF); - if (typedef_type == NULL) - goto finish_specifiers; + type = allocate_type_zero(TYPE_TYPEDEF, HERE); + type->typedeft.declaration = decl; + + next_token(); + saw_error = true; + if (la1_type == '*') + goto finish_specifiers; + continue; + } + + default: + goto finish_specifiers; + } + } next_token(); type = typedef_type; @@ -3220,8 +3437,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 */ @@ -3267,17 +3483,24 @@ finish_specifiers: case SPECIFIER_UNSIGNED | SPECIFIER_LONG | SPECIFIER_INT: atomic_type = ATOMIC_TYPE_ULONG; break; + case SPECIFIER_LONG | SPECIFIER_LONG_LONG: case SPECIFIER_SIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG: case SPECIFIER_LONG | SPECIFIER_LONG_LONG | SPECIFIER_INT: case SPECIFIER_SIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG | SPECIFIER_INT: atomic_type = ATOMIC_TYPE_LONGLONG; - break; + goto warn_about_long_long; + case SPECIFIER_UNSIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG: case SPECIFIER_UNSIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG | SPECIFIER_INT: atomic_type = ATOMIC_TYPE_ULONGLONG; +warn_about_long_long: + if (warning.long_long) { + warningf(&specifiers->source_position, + "ISO C90 does not support 'long long'"); + } break; case SPECIFIER_UNSIGNED | SPECIFIER_INT8: @@ -3352,7 +3575,12 @@ finish_specifiers: default: /* invalid specifier combination, give an error message */ if (type_specifiers == 0) { - if (! strict_mode) { + if (saw_error) { + specifiers->type = type_error_type; + return; + } + + if (!strict_mode) { if (warning.implicit_int) { warningf(HERE, "no type specifiers in declaration, using 'int'"); } @@ -3363,7 +3591,7 @@ finish_specifiers: } } else if ((type_specifiers & SPECIFIER_SIGNED) && (type_specifiers & SPECIFIER_UNSIGNED)) { - errorf(HERE, "signed and unsigned specifiers gives"); + errorf(HERE, "signed and unsigned specifiers given"); } else if (type_specifiers & (SPECIFIER_SIGNED | SPECIFIER_UNSIGNED)) { errorf(HERE, "only integer types can be signed or unsigned"); } else { @@ -3384,11 +3612,9 @@ finish_specifiers: type = allocate_type_zero(TYPE_ATOMIC, &builtin_source_position); type->atomic.akind = atomic_type; } - newtype = 1; - } else { - if (type_specifiers != 0) { - errorf(HERE, "multiple datatypes in declaration"); - } + newtype = true; + } else if (type_specifiers != 0) { + errorf(HERE, "multiple datatypes in declaration"); } /* FIXME: check type qualifiers here */ @@ -3461,12 +3687,21 @@ static type_t *automatic_type_conversion(type_t *orig_type); static void semantic_parameter(declaration_t *declaration) { /* TODO: improve error messages */ + source_position_t const* const pos = &declaration->source_position; + + switch (declaration->declared_storage_class) { + case STORAGE_CLASS_TYPEDEF: + errorf(pos, "typedef not allowed in parameter list"); + break; + + /* Allowed storage classes */ + case STORAGE_CLASS_NONE: + case STORAGE_CLASS_REGISTER: + break; - if (declaration->declared_storage_class == STORAGE_CLASS_TYPEDEF) { - errorf(HERE, "typedef not allowed in parameter list"); - } else if (declaration->declared_storage_class != STORAGE_CLASS_NONE - && declaration->declared_storage_class != STORAGE_CLASS_REGISTER) { - errorf(HERE, "parameter may only have none or register storage class"); + default: + errorf(pos, "parameter may only have none or register storage class"); + break; } type_t *const orig_type = declaration->type; @@ -3479,7 +3714,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, "parameter '%#T' is of incomplete type", orig_type, declaration->symbol); } } @@ -3504,9 +3739,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 = (token_type_t)look_ahead(1)->type; + if (la1_type == ',' || la1_type == ')') { type->kr_style_parameters = true; declarations = parse_identifier_list(); goto parameters_finished; @@ -3692,7 +3928,7 @@ static construct_type_t *parse_function_declarator(declaration_t *declaration) else if (second == NULL) second = "stdcall"; } if (declaration->modifiers & DM_FASTCALL) { - if (first == NULL) first = "faslcall"; + if (first == NULL) first = "fastcall"; else if (second == NULL) second = "fastcall"; } if (declaration->modifiers & DM_THISCALL) { @@ -3777,6 +4013,9 @@ static construct_type_t *parse_inner_declarator(declaration_t *declaration, modifiers |= parse_attributes(&attributes); } + if (declaration != NULL) + declaration->modifiers |= modifiers; + construct_type_t *inner_types = NULL; switch(token.type) { @@ -3793,6 +4032,10 @@ static construct_type_t *parse_inner_declarator(declaration_t *declaration, next_token(); add_anchor_token(')'); inner_types = parse_inner_declarator(declaration, may_be_abstract); + if (inner_types != NULL) { + /* All later declarators only modify the return type, not declaration */ + declaration = NULL; + } rem_anchor_token(')'); expect(')'); break; @@ -3982,9 +4225,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; @@ -4101,14 +4344,14 @@ static bool is_sym_main(const symbol_t *const sym) return strcmp(sym->string, "main") == 0; } -static declaration_t *internal_record_declaration( +static declaration_t *record_declaration( declaration_t *const declaration, const bool is_definition) { const symbol_t *const symbol = declaration->symbol; const namespace_t namespc = (namespace_t)declaration->namespc; - assert(declaration->symbol != NULL); + assert(symbol != NULL); declaration_t *previous_declaration = get_declaration(symbol, namespc); type_t *const orig_type = declaration->type; @@ -4126,6 +4369,13 @@ static declaration_t *internal_record_declaration( check_type_of_main(declaration, &type->function); } + if (warning.nested_externs && + declaration->storage_class == STORAGE_CLASS_EXTERN && + scope != global_scope) { + warningf(&declaration->source_position, + "nested extern declaration of '%#T'", declaration->type, symbol); + } + assert(declaration != previous_declaration); if (previous_declaration != NULL && previous_declaration->parent_scope == scope) { @@ -4232,8 +4482,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 && @@ -4267,16 +4517,6 @@ warn_redundant_declaration: return append_declaration(declaration); } -static declaration_t *record_declaration(declaration_t *declaration) -{ - return internal_record_declaration(declaration, false); -} - -static declaration_t *record_definition(declaration_t *declaration) -{ - return internal_record_declaration(declaration, true); -} - static void parser_error_multiple_definition(declaration_t *declaration, const source_position_t *source_position) { @@ -4321,32 +4561,32 @@ static void parse_init_declarator_rest(declaration_t *declaration) must_be_constant = true; } + if (is_type_function(type)) { + errorf(&declaration->source_position, + "function '%#T' is initialized like a variable", + orig_type, declaration->symbol); + orig_type = type_error_type; + } + parse_initializer_env_t env; env.type = orig_type; env.must_be_constant = must_be_constant; - env.declaration = declaration; + env.declaration = current_init_decl = declaration; initializer_t *initializer = parse_initializer(&env); + current_init_decl = NULL; - if (env.type != orig_type) { - orig_type = env.type; - type = skip_typeref(orig_type); - declaration->type = env.type; - } - - if (is_type_function(type)) { - errorf(&declaration->source_position, - "initializers not allowed for function types at declator '%Y' (type '%T')", - declaration->symbol, orig_type); - } else { + if (!is_type_function(type)) { + /* § 6.7.5 (22) array initializers for arrays with unknown size determine + * the array type size */ + declaration->type = env.type; declaration->init.initializer = initializer; } } /* parse rest of a declaration without any declarator */ static void parse_anonymous_declaration_rest( - const declaration_specifiers_t *specifiers, - parsed_declaration_func finished_declaration) + const declaration_specifiers_t *specifiers) { eat(';'); @@ -4381,7 +4621,7 @@ static void parse_anonymous_declaration_rest( break; } - finished_declaration(declaration); + append_declaration(declaration); } static void parse_declaration_rest(declaration_t *ndeclaration, @@ -4392,7 +4632,8 @@ static void parse_declaration_rest(declaration_t *ndeclaration, add_anchor_token('='); add_anchor_token(','); while(true) { - declaration_t *declaration = finished_declaration(ndeclaration); + declaration_t *declaration = + finished_declaration(ndeclaration, token.type == '='); type_t *orig_type = declaration->type; type_t *type = skip_typeref(orig_type); @@ -4422,7 +4663,7 @@ end_error: rem_anchor_token(','); } -static declaration_t *finished_kr_declaration(declaration_t *declaration) +static declaration_t *finished_kr_declaration(declaration_t *declaration, bool is_definition) { symbol_t *symbol = declaration->symbol; if (symbol == NULL) { @@ -4431,7 +4672,7 @@ static declaration_t *finished_kr_declaration(declaration_t *declaration) } namespace_t namespc = (namespace_t) declaration->namespc; if (namespc != NAMESPACE_NORMAL) { - return record_declaration(declaration); + return record_declaration(declaration, false); } declaration_t *previous_declaration = get_declaration(symbol, namespc); @@ -4442,6 +4683,10 @@ static declaration_t *finished_kr_declaration(declaration_t *declaration) return declaration; } + if (is_definition) { + errorf(HERE, "parameter %Y is initialised", declaration->symbol); + } + if (previous_declaration->type == NULL) { previous_declaration->type = declaration->type; previous_declaration->declared_storage_class = declaration->declared_storage_class; @@ -4449,7 +4694,7 @@ static declaration_t *finished_kr_declaration(declaration_t *declaration) previous_declaration->parent_scope = scope; return previous_declaration; } else { - return record_declaration(declaration); + return record_declaration(declaration, false); } } @@ -4460,7 +4705,7 @@ static void parse_declaration(parsed_declaration_func finished_declaration) parse_declaration_specifiers(&specifiers); if (token.type == ';') { - parse_anonymous_declaration_rest(&specifiers, append_declaration); + parse_anonymous_declaration_rest(&specifiers); } else { declaration_t *declaration = parse_declarator(&specifiers, /*may_be_abstract=*/false); parse_declaration_rest(declaration, &specifiers, finished_declaration); @@ -4595,6 +4840,10 @@ static void check_labels(void) for (const goto_statement_t *goto_statement = goto_first; goto_statement != NULL; goto_statement = goto_statement->next) { + /* skip computed gotos */ + if (goto_statement->expression != NULL) + continue; + declaration_t *label = goto_statement->label; label->used = true; @@ -4630,6 +4879,10 @@ static void check_declarations(void) if (warning.unused_parameter) { const scope_t *scope = ¤t_function->scope; + if (is_sym_main(current_function->symbol)) { + /* do not issue unused warnings for main */ + return; + } const declaration_t *parameter = scope->declarations; for (; parameter != NULL; parameter = parameter->next) { if (! parameter->used) { @@ -4643,132 +4896,618 @@ static void check_declarations(void) } } -static void parse_external_declaration(void) +static int determine_truth(expression_t const* const cond) { - /* function-definitions and declarations both start with declaration - * specifiers */ - declaration_specifiers_t specifiers; - memset(&specifiers, 0, sizeof(specifiers)); + return + !is_constant_expression(cond) ? 0 : + fold_constant(cond) != 0 ? 1 : + -1; +} - add_anchor_token(';'); - parse_declaration_specifiers(&specifiers); - rem_anchor_token(';'); +static bool noreturn_candidate; - /* must be a declaration */ - if (token.type == ';') { - parse_anonymous_declaration_rest(&specifiers, append_declaration); +static void check_reachable(statement_t *const stmt) +{ + if (stmt->base.reachable) return; - } - - add_anchor_token(','); - add_anchor_token('='); - rem_anchor_token(';'); - - /* declarator is common to both function-definitions and declarations */ - declaration_t *ndeclaration = parse_declarator(&specifiers, /*may_be_abstract=*/false); + 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; - rem_anchor_token(','); - rem_anchor_token('='); - rem_anchor_token(';'); + case STATEMENT_COMPOUND: + next = stmt->compound.statements; + break; - /* must be a declaration */ - switch (token.type) { - case ',': - case ';': - parse_declaration_rest(ndeclaration, &specifiers, record_declaration); + case STATEMENT_RETURN: + noreturn_candidate = false; return; - case '=': - parse_declaration_rest(ndeclaration, &specifiers, record_definition); - return; - } + case STATEMENT_IF: { + if_statement_t const* const ifs = &stmt->ifs; + int const val = determine_truth(ifs->condition); - /* must be a function definition */ - parse_kr_declaration_list(ndeclaration); + if (val >= 0) + check_reachable(ifs->true_statement); - if (token.type != '{') { - parse_error_expected("while parsing function definition", '{', NULL); - eat_until_matching_token(';'); - return; - } + if (val > 0) + return; - type_t *type = ndeclaration->type; + if (ifs->false_statement != NULL) { + check_reachable(ifs->false_statement); + return; + } - /* note that we don't skip typerefs: the standard doesn't allow them here - * (so we can't use is_type_function here) */ - if (type->kind != TYPE_FUNCTION) { - if (is_type_valid(type)) { - errorf(HERE, "declarator '%#T' has a body but is not a function type", - type, ndeclaration->symbol); + next = stmt->base.next; + break; } - eat_block(); - return; - } - /* § 6.7.5.3 (14) a function definition with () means no - * parameters (and not unspecified parameters) */ - if (type->function.unspecified_parameters - && type->function.parameters == NULL - && !type->function.kr_style_parameters) { - type_t *duplicate = duplicate_type(type); - duplicate->function.unspecified_parameters = false; + case STATEMENT_SWITCH: { + switch_statement_t const *const switchs = &stmt->switchs; + expression_t const *const expr = switchs->expression; - type = typehash_insert(duplicate); - if (type != duplicate) { - obstack_free(type_obst, duplicate); - } - ndeclaration->type = type; - } + 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; + } - declaration_t *const declaration = record_definition(ndeclaration); - if (ndeclaration != declaration) { - declaration->scope = ndeclaration->scope; - } - type = skip_typeref(declaration->type); + if (i->first_case <= val && val <= i->last_case) { + check_reachable((statement_t*)i); + return; + } + } - /* push function parameters and switch scope */ - int top = environment_top(); - scope_t *last_scope = scope; - set_scope(&declaration->scope); + 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; - declaration_t *parameter = declaration->scope.declarations; - for( ; parameter != NULL; parameter = parameter->next) { - if (parameter->parent_scope == &ndeclaration->scope) { - parameter->parent_scope = scope; - } - assert(parameter->parent_scope == NULL - || parameter->parent_scope == scope); - parameter->parent_scope = scope; - if (parameter->symbol == NULL) { - errorf(&ndeclaration->source_position, "parameter name omitted"); - continue; + check_reachable((statement_t*)i); + } + + if (has_default) + return; + } + + next = stmt->base.next; + break; } - environment_push(parameter); - } - if (declaration->init.statement != NULL) { - parser_error_multiple_definition(declaration, HERE); - eat_block(); - } else { - /* parse function body */ - int label_stack_top = label_top(); - declaration_t *old_current_function = current_function; - current_function = declaration; + 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; + } + } + } - declaration->init.statement = parse_compound_statement(false); - first_err = true; - check_labels(); - check_declarations(); + next = stmt->base.next; + break; + } - assert(current_function == declaration); - current_function = old_current_function; - label_pop_to(label_stack_top); - } + case STATEMENT_CONTINUE: { + statement_t *parent = stmt; + for (;;) { + parent = parent->base.parent; + if (parent == NULL) /* continue not within loop */ + return; - assert(scope == &declaration->scope); - set_scope(last_scope); - environment_pop_to(top); -} + 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: + if (stmt->gotos.expression) { + statement_t *parent = stmt->base.parent; + if (parent == NULL) /* top level goto */ + return; + next = parent; + } else { + 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: { + ms_try_statement_t const *const ms_try = &stmt->ms_try; + check_reachable(ms_try->try_statement); + next = ms_try->final_statement; + break; + } + + case STATEMENT_LEAVE: { + statement_t *parent = stmt; + for (;;) { + parent = parent->base.parent; + if (parent == NULL) /* __leave not within __try */ + return; + + if (parent->kind == STATEMENT_MS_TRY) { + last = parent; + next = parent->ms_try.final_statement; + break; + } + } + break; + } + } + + 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: + last = next; + next = next->ms_try.final_statement; + break; + } + } + + 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(fors->body); + break; + } + + case STATEMENT_MS_TRY: { + ms_try_statement_t const *const ms_try = &stmt->ms_try; + check_unreachable(ms_try->try_statement); + check_unreachable(ms_try->final_statement); + } + } + + if (stmt->base.next) + check_unreachable(stmt->base.next); +} + +static void parse_external_declaration(void) +{ + /* function-definitions and declarations both start with declaration + * specifiers */ + declaration_specifiers_t specifiers; + memset(&specifiers, 0, sizeof(specifiers)); + + add_anchor_token(';'); + parse_declaration_specifiers(&specifiers); + rem_anchor_token(';'); + + /* must be a declaration */ + if (token.type == ';') { + parse_anonymous_declaration_rest(&specifiers); + return; + } + + add_anchor_token(','); + add_anchor_token('='); + rem_anchor_token(';'); + + /* declarator is common to both function-definitions and declarations */ + declaration_t *ndeclaration = parse_declarator(&specifiers, /*may_be_abstract=*/false); + + rem_anchor_token(','); + rem_anchor_token('='); + rem_anchor_token(';'); + + /* must be a declaration */ + switch (token.type) { + case ',': + case ';': + case '=': + parse_declaration_rest(ndeclaration, &specifiers, record_declaration); + return; + } + + /* must be a function definition */ + parse_kr_declaration_list(ndeclaration); + + if (token.type != '{') { + parse_error_expected("while parsing function definition", '{', NULL); + eat_until_matching_token(';'); + return; + } + + type_t *type = ndeclaration->type; + + /* note that we don't skip typerefs: the standard doesn't allow them here + * (so we can't use is_type_function here) */ + if (type->kind != TYPE_FUNCTION) { + if (is_type_valid(type)) { + errorf(HERE, "declarator '%#T' has a body but is not a function type", + type, ndeclaration->symbol); + } + eat_block(); + return; + } + + if (warning.aggregate_return && + is_type_compound(skip_typeref(type->function.return_type))) { + warningf(HERE, "function '%Y' returns an aggregate", + ndeclaration->symbol); + } + if (warning.traditional && !type->function.unspecified_parameters) { + warningf(HERE, "traditional C rejects ISO C style function definition of function '%Y'", + ndeclaration->symbol); + } + if (warning.old_style_definition && type->function.unspecified_parameters) { + warningf(HERE, "old-style function definition '%Y'", + ndeclaration->symbol); + } + + /* § 6.7.5.3 (14) a function definition with () means no + * parameters (and not unspecified parameters) */ + if (type->function.unspecified_parameters + && type->function.parameters == NULL + && !type->function.kr_style_parameters) { + type_t *duplicate = duplicate_type(type); + duplicate->function.unspecified_parameters = false; + + type = typehash_insert(duplicate); + if (type != duplicate) { + obstack_free(type_obst, duplicate); + } + ndeclaration->type = type; + } + + declaration_t *const declaration = record_declaration(ndeclaration, true); + if (ndeclaration != declaration) { + declaration->scope = ndeclaration->scope; + } + type = skip_typeref(declaration->type); + + /* push function parameters and switch scope */ + int top = environment_top(); + scope_t *last_scope = scope; + set_scope(&declaration->scope); + + declaration_t *parameter = declaration->scope.declarations; + for( ; parameter != NULL; parameter = parameter->next) { + if (parameter->parent_scope == &ndeclaration->scope) { + parameter->parent_scope = scope; + } + assert(parameter->parent_scope == NULL + || parameter->parent_scope == scope); + parameter->parent_scope = scope; + if (parameter->symbol == NULL) { + errorf(¶meter->source_position, "parameter name omitted"); + continue; + } + environment_push(parameter); + } + + if (declaration->init.statement != NULL) { + parser_error_multiple_definition(declaration, HERE); + eat_block(); + } else { + /* parse function body */ + int label_stack_top = label_top(); + declaration_t *old_current_function = current_function; + current_function = declaration; + current_parent = NULL; + + 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); + } + + assert(scope == &declaration->scope); + set_scope(last_scope); + environment_pop_to(top); +} static type_t *make_bitfield_type(type_t *base_type, expression_t *size, source_position_t *source_position) @@ -4813,12 +5552,12 @@ static void parse_compound_declarators(declaration_t *struct_declaration, { declaration_t *last_declaration = struct_declaration->scope.declarations; if (last_declaration != NULL) { - while(last_declaration->next != NULL) { + while (last_declaration->next != NULL) { last_declaration = last_declaration->next; } } - while(1) { + while (true) { declaration_t *declaration; if (token.type == ':') { @@ -4854,8 +5593,8 @@ static void parse_compound_declarators(declaration_t *struct_declaration, expression_t *size = parse_constant_expression(); if (!is_type_integer(type)) { - errorf(HERE, "bitfield base type '%T' is not an " - "integer type", orig_type); + errorf(HERE, "bitfield base type '%T' is not an integer type", + orig_type); } type_t *bitfield_type = make_bitfield_type(orig_type, size, &source_position); @@ -4868,8 +5607,8 @@ static void parse_compound_declarators(declaration_t *struct_declaration, "compound member '%Y' has incomplete type '%T'", declaration->symbol, orig_type); } else if (is_type_function(type)) { - errorf(HERE, "compound member '%Y' must not have function " - "type '%T'", declaration->symbol, orig_type); + errorf(HERE, "compound member '%Y' must not have function type '%T'", + declaration->symbol, orig_type); } } } @@ -4911,7 +5650,7 @@ static void parse_compound_type_entries(declaration_t *compound_declaration) eat('{'); add_anchor_token('}'); - while(token.type != '}' && token.type != T_EOF) { + while (token.type != '}' && token.type != T_EOF) { declaration_specifiers_t specifiers; memset(&specifiers, 0, sizeof(specifiers)); parse_declaration_specifiers(&specifiers); @@ -4992,7 +5731,7 @@ static expression_t *parse_string_const(void) /* note: that we use type_char_ptr here, which is already the * automatic converted type. revert_automatic_type_conversion * will construct the array type */ - cnst->base.type = type_char_ptr; + cnst->base.type = warning.write_strings ? type_const_char_ptr : type_char_ptr; cnst->string.value = res; return cnst; } @@ -5015,7 +5754,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; } @@ -5119,10 +5858,11 @@ 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; - record_declaration(declaration); + record_declaration(declaration, false); warning.strict_prototypes = strict_prototypes_old; return declaration; @@ -5256,7 +5996,10 @@ type_t *revert_automatic_type_conversion(const expression_t *expression) { switch (expression->kind) { case EXPR_REFERENCE: return expression->reference.declaration->type; - case EXPR_SELECT: return expression->select.compound_entry->type; + + case EXPR_SELECT: + return get_qualified_type(expression->select.compound_entry->type, + expression->base.type->base.qualifiers); case EXPR_UNARY_DEREFERENCE: { const expression_t *const value = expression->unary.value; @@ -5309,9 +6052,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); } @@ -5320,11 +6065,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! */ @@ -5337,29 +6082,78 @@ 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); } } + if (warning.init_self && declaration == current_init_decl) { + current_init_decl = NULL; + warningf(&source_position, + "variable '%#T' is initialized by itself", + declaration->type, declaration->symbol); + } 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) @@ -5401,12 +6195,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(); @@ -5446,9 +6241,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(')'); @@ -5856,6 +6651,71 @@ end_error: return create_invalid_expression(); } +/** + * Return the declaration for a given label symbol or create a new one. + * + * @param symbol the symbol of the label + */ +static declaration_t *get_label(symbol_t *symbol) +{ + declaration_t *candidate; + assert(current_function != NULL); + + candidate = get_declaration(symbol, NAMESPACE_LOCAL_LABEL); + /* if we found a local label, we already created the declaration */ + if (candidate != NULL) { + assert(candidate->parent_scope == scope); + return candidate; + } + + candidate = get_declaration(symbol, NAMESPACE_LABEL); + /* if we found a label in the same function, then we already created the + * declaration */ + if (candidate != NULL + && candidate->parent_scope == ¤t_function->scope) { + return candidate; + } + + /* otherwise we need to create a new one */ + declaration_t *const declaration = allocate_declaration_zero(); + declaration->namespc = NAMESPACE_LABEL; + declaration->symbol = symbol; + + label_push(declaration); + + return declaration; +} + +/** + * Parses a GNU && label address expression. + */ +static expression_t *parse_label_address(void) +{ + source_position_t source_position = token.source_position; + eat(T_ANDAND); + if (token.type != T_IDENTIFIER) { + parse_error_expected("while parsing label address", T_IDENTIFIER, NULL); + goto end_error; + } + symbol_t *symbol = token.v.symbol; + next_token(); + + declaration_t *label = get_label(symbol); + + label->used = true; + label->address_taken = true; + + expression_t *expression = allocate_expression_zero(EXPR_LABEL_ADDRESS); + expression->base.source_position = source_position; + + /* label address is threaten as a void pointer */ + expression->base.type = type_void_ptr; + expression->label_address.declaration = label; + return expression; +end_error: + return create_invalid_expression(); +} + /** * Parse a microsoft __noop expression. */ @@ -5933,8 +6793,12 @@ static expression_t *parse_primary_expression(void) case T___builtin_constant_p: return parse_builtin_constant(); case T___builtin_prefetch: return parse_builtin_prefetch(); case T__assume: return parse_assume(); + case T_ANDAND: + if (c_mode & _GNUC) + return parse_label_address(); + break; - case '(': return parse_brace_expression(); + case '(': return parse_parenthesized_expression(); case T___noop: return parse_noop_expression(); } @@ -6096,56 +6960,67 @@ static expression_t *parse_select_expression(unsigned precedence, parse_error_expected("while parsing select", T_IDENTIFIER, NULL); return select; } - symbol_t *symbol = token.v.symbol; - select->select.symbol = symbol; + symbol_t *symbol = token.v.symbol; next_token(); type_t *const orig_type = compound->base.type; type_t *const type = skip_typeref(orig_type); - type_t *type_left = type; - if (is_pointer) { - if (!is_type_pointer(type)) { - if (is_type_valid(type)) { - errorf(HERE, "left hand side of '->' is not a pointer, but '%T'", orig_type); - } - return create_invalid_expression(); + type_t *type_left; + bool saw_error = false; + if (is_type_pointer(type)) { + if (!is_pointer) { + errorf(HERE, + "request for member '%Y' in something not a struct or union, but '%T'", + symbol, orig_type); + saw_error = true; } - type_left = type->pointer.points_to; - } - type_left = skip_typeref(type_left); - - if (type_left->kind != TYPE_COMPOUND_STRUCT && - type_left->kind != TYPE_COMPOUND_UNION) { - if (is_type_valid(type_left)) { - errorf(HERE, "request for member '%Y' in something not a struct or " - "union, but '%T'", symbol, type_left); + type_left = skip_typeref(type->pointer.points_to); + } else { + if (is_pointer && is_type_valid(type)) { + errorf(HERE, "left hand side of '->' is not a pointer, but '%T'", orig_type); + saw_error = true; } - return create_invalid_expression(); + type_left = type; } - declaration_t *const declaration = type_left->compound.declaration; + declaration_t *entry; + if (type_left->kind == TYPE_COMPOUND_STRUCT || + type_left->kind == TYPE_COMPOUND_UNION) { + declaration_t *const declaration = type_left->compound.declaration; - if (!declaration->init.complete) { - errorf(HERE, "request for member '%Y' of incomplete type '%T'", - symbol, type_left); - return create_invalid_expression(); - } + if (!declaration->init.complete) { + errorf(HERE, "request for member '%Y' of incomplete type '%T'", + symbol, type_left); + goto create_error_entry; + } - declaration_t *iter = find_compound_entry(declaration, symbol); - if (iter == NULL) { - errorf(HERE, "'%T' has no member named '%Y'", orig_type, symbol); - return create_invalid_expression(); + entry = find_compound_entry(declaration, symbol); + if (entry == NULL) { + errorf(HERE, "'%T' has no member named '%Y'", orig_type, symbol); + goto create_error_entry; + } + } else { + if (is_type_valid(type_left) && !saw_error) { + errorf(HERE, + "request for member '%Y' in something not a struct or union, but '%T'", + symbol, type_left); + } +create_error_entry: + entry = allocate_declaration_zero(); + entry->symbol = symbol; } + select->select.compound_entry = entry; + + type_t *const res_type = + get_qualified_type(entry->type, type_left->base.qualifiers); + /* we always do the auto-type conversions; the & and sizeof parser contains * code to revert this! */ - type_t *expression_type = automatic_type_conversion(iter->type); - - select->select.compound_entry = iter; - select->base.type = expression_type; + select->base.type = automatic_type_conversion(res_type); - type_t *skipped = skip_typeref(iter->type); + type_t *skipped = skip_typeref(res_type); if (skipped->kind == TYPE_BITFIELD) { select->base.type = skipped->bitfield.base_type; } @@ -6154,12 +7029,13 @@ static expression_t *parse_select_expression(unsigned precedence, } static void check_call_argument(const function_parameter_t *parameter, - call_argument_t *argument) + call_argument_t *argument, unsigned pos) { type_t *expected_type = parameter->type; type_t *expected_type_skip = skip_typeref(expected_type); assign_error_t error = ASSIGN_ERROR_INCOMPATIBLE; expression_t *arg_expr = argument->expression; + type_t *arg_type = skip_typeref(arg_expr->base.type); /* handle transparent union gnu extension */ if (is_type_union(expected_type_skip) @@ -6192,9 +7068,34 @@ static void check_call_argument(const function_parameter_t *parameter, argument->expression = create_implicit_cast(argument->expression, expected_type); - /* TODO report exact scope in error messages (like "in 3rd parameter") */ - report_assign_error(error, expected_type, arg_expr, "function call", - &arg_expr->base.source_position); + if (error != ASSIGN_SUCCESS) { + /* report exact scope in error messages (like "in argument 3") */ + char buf[64]; + snprintf(buf, sizeof(buf), "call argument %u", pos); + report_assign_error(error, expected_type, arg_expr, buf, + &arg_expr->base.source_position); + } else if (warning.traditional | warning.conversion) { + if ( + /* passing as integer instead of float or complex */ + (is_type_integer(expected_type) && + (is_type_float(arg_type) || is_type_complex(arg_type))) || + /* passing as complex instead of integer or float */ + (is_type_complex(expected_type) && + (is_type_integer(arg_type) || is_type_float(arg_type))) || + /* passing as float instead of integer or complex */ + (is_type_float(expected_type) && + (is_type_integer(arg_type) || is_type_complex(arg_type))) || + /* passing as float instead of double */ + (is_type_float(expected_type) && expected_type != type_double && + is_type_float(arg_type))) { + warningf(&arg_expr->base.source_position, + "passing call argument %u as '%T' rather than '%T' due to prototype", + pos, expected_type, arg_type); + } + if (is_type_integer(expected_type) && is_type_integer(arg_type)) { + /* TODO check for size HERE */ + } + } } /** @@ -6237,7 +7138,7 @@ static expression_t *parse_call_expression(unsigned precedence, if (token.type != ')') { call_argument_t *last_argument = NULL; - while(true) { + while (true) { call_argument_t *argument = allocate_ast_zero(sizeof(argument[0])); argument->expression = parse_assignment_expression(); @@ -6263,9 +7164,9 @@ static expression_t *parse_call_expression(unsigned precedence, function_parameter_t *parameter = function_type->parameters; call_argument_t *argument = call->arguments; if (!function_type->unspecified_parameters) { - for( ; parameter != NULL && argument != NULL; + for (unsigned pos = 0; parameter != NULL && argument != NULL; parameter = parameter->next, argument = argument->next) { - check_call_argument(parameter, argument); + check_call_argument(parameter, argument, ++pos); } if (parameter != NULL) { @@ -6287,6 +7188,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(); @@ -6310,13 +7217,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; @@ -6326,7 +7234,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); @@ -6342,7 +7255,7 @@ static expression_t *parse_conditional_expression(unsigned precedence, is_type_atomic(false_type, ATOMIC_TYPE_VOID)) { if (!is_type_atomic(true_type, ATOMIC_TYPE_VOID) || !is_type_atomic(false_type, ATOMIC_TYPE_VOID)) { - warningf(&expression->base.source_position, + warningf(&conditional->base.source_position, "ISO C forbids conditional expression with only one void side"); } result_type = type_void; @@ -6388,22 +7301,17 @@ 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; } - type_t *const copy = duplicate_type(to); - copy->base.qualifiers = to1->base.qualifiers | to2->base.qualifiers; - - type_t *const type = typehash_insert(copy); - if (type != copy) - free_type(copy); - + type_t *const type = + get_qualified_type(to, to1->base.qualifiers | to2->base.qualifiers); result_type = make_pointer_type(type, TYPE_QUALIFIER_NONE); } else if (is_type_integer(other_type)) { - warningf(&expression->base.source_position, + warningf(&conditional->base.source_position, "pointer/integer type mismatch in conditional expression ('%T' and '%T')", true_type, false_type); result_type = pointer_type; } else { @@ -6416,14 +7324,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; @@ -6467,23 +7375,50 @@ 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 bool is_lvalue(const expression_t *expression) +{ + switch (expression->kind) { + case EXPR_REFERENCE: + case EXPR_ARRAY_ACCESS: + case EXPR_SELECT: + case EXPR_UNARY_DEREFERENCE: + return true; + + default: + return false; } } @@ -6492,11 +7427,19 @@ 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; + } + if (!is_lvalue(expression->value)) { + /* TODO: improve error message */ + errorf(&expression->base.source_position, "lvalue required as operand"); } expression->base.type = orig_type; } @@ -6508,7 +7451,8 @@ static void semantic_unexpr_arithmetic(unary_expression_t *expression) if (!is_type_arithmetic(type)) { if (is_type_valid(type)) { /* TODO: improve error message */ - errorf(HERE, "operation needs an arithmetic type"); + errorf(&expression->base.source_position, + "operation needs an arithmetic type"); } return; } @@ -6516,18 +7460,24 @@ 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_unexpr_plus(unary_expression_t *expression) +{ + semantic_unexpr_arithmetic(expression); + if (warning.traditional) + warningf(&expression->base.source_position, + "traditional C rejects the unary plus operator"); +} + +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; + type_t *const type = skip_typeref(orig_type); + if (!is_type_scalar(type) && is_type_valid(type)) { + errorf(&expression->base.source_position, + "operand of ! must be of scalar type"); } - expression->base.type = orig_type; + expression->base.type = type_int; } static void semantic_unexpr_integer(unary_expression_t *expression) @@ -6536,7 +7486,8 @@ static void semantic_unexpr_integer(unary_expression_t *expression) type_t *const type = skip_typeref(orig_type); if (!is_type_integer(type)) { if (is_type_valid(type)) { - errorf(HERE, "operand of ~ must be of integer type"); + errorf(&expression->base.source_position, + "operand of ~ must be of integer type"); } return; } @@ -6550,7 +7501,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 array type, but type '%T' given", orig_type); } return; } @@ -6560,6 +7512,12 @@ static void semantic_dereference(unary_expression_t *expression) expression->base.type = result_type; } +/** + * Record that an address is taken (expression represents an lvalue). + * + * @param expression the expression + * @param may_be_register if true, the expression might be an register + */ static void set_address_taken(expression_t *expression, bool may_be_register) { if (expression->kind != EXPR_REFERENCE) @@ -6599,11 +7557,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); \ @@ -6614,9 +7571,9 @@ static expression_t *parse_##unexpression_type(unsigned precedence) \ CREATE_UNARY_EXPRESSION_PARSER('-', EXPR_UNARY_NEGATE, semantic_unexpr_arithmetic) CREATE_UNARY_EXPRESSION_PARSER('+', EXPR_UNARY_PLUS, - semantic_unexpr_arithmetic) + semantic_unexpr_plus) CREATE_UNARY_EXPRESSION_PARSER('!', EXPR_UNARY_NOT, - semantic_unexpr_scalar) + semantic_not) CREATE_UNARY_EXPRESSION_PARSER('*', EXPR_UNARY_DEREFERENCE, semantic_dereference) CREATE_UNARY_EXPRESSION_PARSER('&', EXPR_UNARY_TAKE_ADDRESS, @@ -6634,11 +7591,12 @@ static expression_t *parse_##unexpression_type(unsigned precedence, \ expression_t *left) \ { \ (void) precedence; \ - eat(token_type); \ \ expression_t *unary_expression \ = allocate_expression_zero(unexpression_type); \ - unary_expression->unary.value = left; \ + unary_expression->base.source_position = *HERE; \ + eat(token_type); \ + unary_expression->unary.value = left; \ \ sfunc(&unary_expression->unary); \ \ @@ -6673,8 +7631,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; @@ -6698,24 +7656,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; } /** @@ -6733,7 +7686,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; } @@ -6744,6 +7698,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; @@ -6756,7 +7728,8 @@ static void semantic_shift_op(binary_expression_t *expression) if (!is_type_integer(type_left) || !is_type_integer(type_right)) { /* TODO: improve error message */ if (is_type_valid(type_left) && is_type_valid(type_right)) { - errorf(HERE, "operation needs integer types"); + errorf(&expression->base.source_position, + "operands of shift operation must have integer types"); } return; } @@ -6802,12 +7775,13 @@ static void semantic_add(binary_expression_t *expression) static void semantic_sub(binary_expression_t *expression) { - expression_t *const left = expression->left; - expression_t *const right = expression->right; - type_t *const orig_type_left = left->base.type; - type_t *const orig_type_right = right->base.type; - type_t *const type_left = skip_typeref(orig_type_left); - type_t *const type_right = skip_typeref(orig_type_right); + expression_t *const left = expression->left; + expression_t *const right = expression->right; + type_t *const orig_type_left = left->base.type; + type_t *const orig_type_right = right->base.type; + type_t *const type_left = skip_typeref(orig_type_left); + type_t *const type_right = skip_typeref(orig_type_right); + source_position_t const *const pos = &expression->base.source_position; /* § 5.6.5 */ if (is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) { @@ -6824,22 +7798,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); } } @@ -6936,20 +7908,6 @@ static bool has_const_fields(const compound_type_t *type) return false; } -static bool is_lvalue(const expression_t *expression) -{ - switch (expression->kind) { - case EXPR_REFERENCE: - case EXPR_ARRAY_ACCESS: - case EXPR_SELECT: - case EXPR_UNARY_DEREFERENCE: - return true; - - default: - return false; - } -} - static bool is_valid_assignment_lhs(expression_t const* const left) { type_t *const orig_type_left = revert_automatic_type_conversion(left); @@ -7000,7 +7958,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; } @@ -7014,6 +7973,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; @@ -7039,7 +8004,9 @@ static void semantic_arithmetic_addsubb_assign(binary_expression_t *expression) type_left, orig_type_left); expression->base.type = type_left; } else if (is_type_valid(type_left) && is_type_valid(type_right)) { - errorf(HERE, "incompatible types '%T' and '%T' in assignment", orig_type_left, orig_type_right); + errorf(&expression->base.source_position, + "incompatible types '%T' and '%T' in assignment", + orig_type_left, orig_type_right); } } @@ -7058,7 +8025,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; } @@ -7074,9 +8042,6 @@ static void semantic_binexpr_assign(binary_expression_t *expression) expression_t *left = expression->left; type_t *orig_type_left = left->base.type; - type_t *type_left = revert_automatic_type_conversion(left); - type_left = skip_typeref(orig_type_left); - if (!is_valid_assignment_lhs(left)) return; @@ -7111,6 +8076,7 @@ static bool expression_has_effect(const expression_t *const expr) case EXPR_WIDE_CHARACTER_CONSTANT: return false; case EXPR_STRING_LITERAL: return false; case EXPR_WIDE_STRING_LITERAL: return false; + case EXPR_LABEL_ADDRESS: return false; case EXPR_CALL: { const call_expression_t *const call = &expr->call; @@ -7235,14 +8201,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); \ \ @@ -7251,8 +8216,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) @@ -7289,9 +8254,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, @@ -7665,32 +8630,54 @@ static statement_t *parse_case_statement(void) *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(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 (!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 || l->expression == NULL) + 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; @@ -7708,25 +8695,13 @@ static statement_t *parse_case_statement(void) errorf(&inner_stmt->base.source_position, "declaration after case label"); } + POP_PARENT; return statement; end_error: + POP_PARENT; return create_invalid_statement(); } -/** - * Finds an existing default label of a switch statement. - */ -static case_label_statement_t * -find_default_label(const switch_statement_t *statement) -{ - case_label_statement_t *label = statement->first_case; - for ( ; label != NULL; label = label->next) { - if (label->expression == NULL) - return label; - } - return NULL; -} - /** * Parse a default statement. */ @@ -7735,16 +8710,19 @@ 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 = &statement->case_label; @@ -7764,37 +8742,13 @@ static statement_t *parse_default_statement(void) errorf(&inner_stmt->base.source_position, "declaration after default label"); } + POP_PARENT; return statement; end_error: + POP_PARENT; return create_invalid_statement(); } -/** - * Return the declaration for a given label symbol or create a new one. - * - * @param symbol the symbol of the label - */ -static declaration_t *get_label(symbol_t *symbol) -{ - declaration_t *candidate = get_declaration(symbol, NAMESPACE_LABEL); - assert(current_function != NULL); - /* if we found a label in the same function, then we already created the - * declaration */ - if (candidate != NULL - && candidate->parent_scope == ¤t_function->scope) { - return candidate; - } - - /* otherwise we need to create a new one */ - declaration_t *const declaration = allocate_declaration_zero(); - declaration->namespc = NAMESPACE_LABEL; - declaration->symbol = symbol; - - label_push(declaration); - - return declaration; -} - /** * Parse a label statement. */ @@ -7806,20 +8760,22 @@ static statement_t *parse_label_statement(void) declaration_t *label = get_label(symbol); - /* 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) { + statement_t *const statement = allocate_statement_zero(STATEMENT_LABEL); + statement->base.source_position = token.source_position; + statement->label.label = label; + + PUSH_PARENT(statement); + + /* if statement is already set then the label is defined twice, + * otherwise it was just mentioned in a goto/local label declaration so far */ + if (label->init.statement != NULL) { errorf(HERE, "duplicate label '%Y' (declared %P)", 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 == '}') { @@ -7853,6 +8809,7 @@ static statement_t *parse_label_statement(void) } label_last = &statement->label; + POP_PARENT; return statement; } @@ -7866,6 +8823,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(); @@ -7881,11 +8840,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. */ @@ -7896,11 +8897,21 @@ 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)) { type = promote_integer(type); + if (warning.traditional) { + if (get_rank(type) >= get_akind_rank(ATOMIC_TYPE_LONG)) { + warningf(&expr->base.source_position, + "'%T' switch expression not converted to '%T' in ISO C", + type, type_int); + } + } } else if (is_type_valid(type)) { errorf(&expr->base.source_position, "switch quantity is not an integer, but '%T'", type); @@ -7908,6 +8919,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; @@ -7915,12 +8927,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(); } @@ -7945,6 +8961,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(); @@ -7953,8 +8971,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(); } @@ -7966,9 +8986,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); @@ -7981,8 +9002,10 @@ static statement_t *parse_do(void) expect(')'); expect(';'); + POP_PARENT; return statement; end_error: + POP_PARENT; return create_invalid_statement(); } @@ -7996,6 +9019,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); @@ -8043,9 +9068,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); @@ -8059,22 +9086,47 @@ end_error: */ static statement_t *parse_goto(void) { + source_position_t source_position = token.source_position; eat(T_goto); - if (token.type != T_IDENTIFIER) { - parse_error_expected("while parsing goto", T_IDENTIFIER, NULL); - eat_statement(); - goto end_error; - } - symbol_t *symbol = token.v.symbol; - next_token(); + statement_t *statement; + if (c_mode & _GNUC && token.type == '*') { + next_token(); + expression_t *expression = parse_expression(); - declaration_t *label = get_label(symbol); + /* Argh: although documentation say the expression must be of type void *, + * gcc excepts anything that can be casted into void * without error */ + type_t *type = expression->base.type; - statement_t *statement = allocate_statement_zero(STATEMENT_GOTO); - statement->base.source_position = token.source_position; + if (type != type_error_type) { + if (!is_type_pointer(type) && !is_type_integer(type)) { + errorf(&source_position, "cannot convert to a pointer type"); + } else if (type != type_void_ptr) { + warningf(&source_position, + "type of computed goto expression should be 'void*' not '%T'", type); + } + expression = create_implicit_cast(expression, type_void_ptr); + } + + statement = allocate_statement_zero(STATEMENT_GOTO); + statement->base.source_position = source_position; + statement->gotos.expression = expression; + } else { + if (token.type != T_IDENTIFIER) { + if (c_mode & _GNUC) + parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL); + else + parse_error_expected("while parsing goto", T_IDENTIFIER, NULL); + eat_statement(); + goto end_error; + } + symbol_t *symbol = token.v.symbol; + next_token(); - statement->gotos.label = label; + statement = allocate_statement_zero(STATEMENT_GOTO); + statement->base.source_position = source_position; + statement->gotos.label = get_label(symbol); + } /* remember the goto's in a list for later checking */ if (goto_last == NULL) { @@ -8096,22 +9148,18 @@ end_error: */ static statement_t *parse_continue(void) { - statement_t *statement; if (current_loop == NULL) { errorf(HERE, "continue statement not within loop"); - statement = create_invalid_statement(); - } else { - statement = allocate_statement_zero(STATEMENT_CONTINUE); - - statement->base.source_position = token.source_position; } + statement_t *statement = allocate_statement_zero(STATEMENT_CONTINUE); + statement->base.source_position = token.source_position; + eat(T_continue); expect(';'); - return statement; end_error: - return create_invalid_statement(); + return statement; } /** @@ -8119,45 +9167,37 @@ end_error: */ static statement_t *parse_break(void) { - statement_t *statement; if (current_switch == NULL && current_loop == NULL) { errorf(HERE, "break statement not within loop or switch"); - statement = create_invalid_statement(); - } else { - statement = allocate_statement_zero(STATEMENT_BREAK); - - statement->base.source_position = token.source_position; } + statement_t *statement = allocate_statement_zero(STATEMENT_BREAK); + statement->base.source_position = token.source_position; + eat(T_break); expect(';'); - return statement; end_error: - return create_invalid_statement(); + return statement; } /** * Parse a __leave statement. */ -static statement_t *parse_leave(void) +static statement_t *parse_leave_statement(void) { - statement_t *statement; if (current_try == NULL) { errorf(HERE, "__leave statement not within __try"); - statement = create_invalid_statement(); - } else { - statement = allocate_statement_zero(STATEMENT_LEAVE); - - statement->base.source_position = token.source_position; } + statement_t *statement = allocate_statement_zero(STATEMENT_LEAVE); + statement->base.source_position = token.source_position; + eat(T___leave); expect(';'); - return statement; end_error: - return create_invalid_statement(); + return statement; } /** @@ -8233,7 +9273,6 @@ static statement_t *parse_return(void) if (token.type != ';') { return_value = parse_expression(); } - expect(';'); const type_t *const func_type = current_function->type; assert(is_type_function(func_type)); @@ -8270,9 +9309,10 @@ static statement_t *parse_return(void) } statement->returns.value = return_value; - return statement; + expect(';'); + end_error: - return create_invalid_statement(); + return statement; } /** @@ -8310,9 +9350,8 @@ static statement_t *parse_expression_statement(void) expect(';'); - return statement; end_error: - return create_invalid_statement(); + return statement; } /** @@ -8322,15 +9361,18 @@ end_error: static statement_t *parse_ms_try_statment(void) { statement_t *statement = allocate_statement_zero(STATEMENT_MS_TRY); - statement->base.source_position = token.source_position; eat(T___try); + PUSH_PARENT(statement); + ms_try_statement_t *rem = current_try; current_try = &statement->ms_try; statement->ms_try.try_statement = parse_compound_statement(false); current_try = rem; + POP_PARENT; + if (token.type == T___except) { eat(T___except); expect('('); @@ -8365,8 +9407,57 @@ 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 statement; +} + +static statement_t *parse_local_label_declaration(void) { + statement_t *statement = allocate_statement_zero(STATEMENT_DECLARATION); + statement->base.source_position = token.source_position; + + eat(T___label__); + + declaration_t *begin = NULL, *end = NULL; + + while (true) { + if (token.type != T_IDENTIFIER) { + parse_error_expected("while parsing local label declaration", + T_IDENTIFIER, NULL); + goto end_error; + } + symbol_t *symbol = token.v.symbol; + declaration_t *declaration = get_declaration(symbol, NAMESPACE_LOCAL_LABEL); + if (declaration != NULL) { + errorf(HERE, "multiple definitions of '__label__ %Y' (previous definition at %P)", + symbol, &declaration->source_position); + } else { + declaration = allocate_declaration_zero(); + declaration->namespc = NAMESPACE_LOCAL_LABEL; + declaration->source_position = token.source_position; + declaration->symbol = symbol; + declaration->parent_scope = scope; + declaration->init.statement = NULL; + + if (end != NULL) + end->next = declaration; + end = declaration; + if (begin == NULL) + begin = declaration; + + local_label_push(declaration); + } + next_token(); + + if (token.type != ',') + break; + next_token(); + } eat(';'); - return create_empty_statement(); +end_error: + statement->declaration.declarations_begin = begin; + statement->declaration.declarations_end = end; + return statement; } /** @@ -8381,15 +9472,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. @@ -8404,9 +9505,13 @@ static statement_t *intern_parse_statement(void) statement = parse_declaration_statement(); break; + case T___label__: + statement = parse_local_label_declaration(); + break; + case ';': statement = parse_empty_statement(); break; case '{': statement = parse_compound_statement(false); break; - case T___leave: statement = parse_leave(); break; + case T___leave: statement = parse_leave_statement(); break; case T___try: statement = parse_ms_try_statment(); break; case T_asm: statement = parse_asm_statement(); break; case T_break: statement = parse_break(); break; @@ -8457,18 +9562,20 @@ 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('}'); int top = environment_top(); + int top_local = local_label_top(); 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)) { @@ -8478,16 +9585,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 == '}') { @@ -8521,7 +9633,9 @@ end_error: assert(scope == &statement->compound.scope); set_scope(last_scope); environment_pop_to(top); + local_label_pop_to(top_local); + POP_PARENT; return statement; } @@ -8536,13 +9650,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); } /** @@ -8639,6 +9760,7 @@ void start_parsing(void) { environment_stack = NEW_ARR_F(stack_entry_t, 0); label_stack = NEW_ARR_F(stack_entry_t, 0); + local_label_stack = NEW_ARR_F(stack_entry_t, 0); diagnostic_count = 0; error_count = 0; warning_count = 0; @@ -8670,6 +9792,7 @@ translation_unit_t *finish_parsing(void) DEL_ARR_F(environment_stack); DEL_ARR_F(label_stack); + DEL_ARR_F(local_label_stack); translation_unit_t *result = unit; unit = NULL; @@ -8679,7 +9802,7 @@ translation_unit_t *finish_parsing(void) void parse(void) { lookahead_bufpos = 0; - for(int i = 0; i < MAX_LOOKAHEAD + 2; ++i) { + for (int i = 0; i < MAX_LOOKAHEAD + 2; ++i) { next_token(); } parse_translation_unit();