X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=3c1001362c37fd0f8ca179a1da1763e1e73ee011;hb=1cd9fac9d1a48d012cf3084c8edc4130e75a1ea5;hp=847478b9a877328ec728aa6f9374763cd21cc9db;hpb=52efd89ee4332abc51a174cc94909db06d32d500;p=cparser diff --git a/parser.c b/parser.c index 847478b..3c10013 100644 --- a/parser.c +++ b/parser.c @@ -103,17 +103,19 @@ 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; @@ -170,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); @@ -314,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]; @@ -478,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. */ @@ -763,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); @@ -771,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 */ @@ -781,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 */ @@ -831,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 @@ -847,6 +880,18 @@ 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; @@ -1092,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; @@ -1807,7 +1853,7 @@ static decl_modifiers_t parse_attributes(gnu_attribute_t **attributes) eat_until_matching_token('('); break; } else { - string_t asm_string = parse_string_literals(); + parse_string_literals(); } expect(')'); continue; @@ -2725,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; @@ -3064,16 +3110,105 @@ static declaration_t *create_error_declaration(symbol_t *symbol, storage_class_t { 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->declared_storage_class = decl->storage_class; decl->symbol = symbol; decl->implicit = true; - record_declaration(decl); + 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; @@ -3213,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: { @@ -3221,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(); @@ -3577,7 +3714,7 @@ static void semantic_parameter(declaration_t *declaration) declaration->type = type; if (is_type_incomplete(skip_typeref(type))) { - errorf(pos, "incomplete type '%T' not allowed for parameter '%Y'", + errorf(pos, "parameter '%#T' is of incomplete type", orig_type, declaration->symbol); } } @@ -3602,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; @@ -3894,8 +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); - /* All later declarators only modify the return type, not declaration */ - declaration = NULL; + if (inner_types != NULL) { + /* All later declarators only modify the return type, not declaration */ + declaration = NULL; + } rem_anchor_token(')'); expect(')'); break; @@ -4204,7 +4344,7 @@ 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) { @@ -4377,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) { @@ -4431,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(';'); @@ -4491,7 +4621,7 @@ static void parse_anonymous_declaration_rest( break; } - finished_declaration(declaration); + append_declaration(declaration); } static void parse_declaration_rest(declaration_t *ndeclaration, @@ -4502,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); @@ -4532,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) { @@ -4541,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); @@ -4552,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; @@ -4559,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); } } @@ -4570,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); @@ -4705,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; @@ -4910,9 +5049,16 @@ found_break_parent: } case STATEMENT_GOTO: - next = stmt->gotos.label->init.statement; - if (next == NULL) /* missing label */ - return; + 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: @@ -4962,9 +5108,28 @@ found_break_parent: break; } - case STATEMENT_MS_TRY: - case STATEMENT_LEAVE: - panic("unimplemented"); + 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) { @@ -5073,7 +5238,9 @@ continue_for:; } case STATEMENT_MS_TRY: - panic("unimplemented"); + last = next; + next = next->ms_try.final_statement; + break; } } @@ -5171,12 +5338,15 @@ static void check_unreachable(statement_t const* const stmt) } } - check_unreachable(stmt->fors.body); + check_unreachable(fors->body); break; } - case STATEMENT_MS_TRY: - panic("unimplemented"); + 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) @@ -5196,7 +5366,7 @@ static void parse_external_declaration(void) /* must be a declaration */ if (token.type == ';') { - parse_anonymous_declaration_rest(&specifiers, append_declaration); + parse_anonymous_declaration_rest(&specifiers); return; } @@ -5215,11 +5385,8 @@ static void parse_external_declaration(void) switch (token.type) { case ',': case ';': - parse_declaration_rest(ndeclaration, &specifiers, record_declaration); - return; - case '=': - parse_declaration_rest(ndeclaration, &specifiers, record_definition); + parse_declaration_rest(ndeclaration, &specifiers, record_declaration); return; } @@ -5250,6 +5417,14 @@ static void parse_external_declaration(void) 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) */ @@ -5266,7 +5441,7 @@ static void parse_external_declaration(void) ndeclaration->type = type; } - declaration_t *const declaration = record_definition(ndeclaration); + declaration_t *const declaration = record_declaration(ndeclaration, true); if (ndeclaration != declaration) { declaration->scope = ndeclaration->scope; } @@ -5377,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 == ':') { @@ -5418,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); @@ -5432,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); } } } @@ -5475,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); @@ -5687,7 +5862,7 @@ static declaration_t *create_implicit_function(symbol_t *symbol, 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; @@ -5821,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; @@ -5920,6 +6098,12 @@ static expression_t *parse_reference(void) 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; } @@ -6467,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. */ @@ -6544,6 +6793,10 @@ 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_parenthesized_expression(); case T___noop: return parse_noop_expression(); @@ -6707,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->base.type = automatic_type_conversion(res_type); - select->select.compound_entry = iter; - select->base.type = expression_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; } @@ -6765,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) @@ -6803,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 */ + } + } } /** @@ -6848,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(); @@ -6874,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) { @@ -7017,13 +7307,8 @@ static expression_t *parse_conditional_expression(unsigned precedence, 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(&conditional->base.source_position, @@ -7123,6 +7408,20 @@ static bool check_pointer_arithmetic(const source_position_t *source_position, 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; + } +} + static void semantic_incdec(unary_expression_t *expression) { type_t *const orig_type = expression->value->base.type; @@ -7138,6 +7437,10 @@ static void semantic_incdec(unary_expression_t *expression) "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; } @@ -7149,7 +7452,7 @@ static void semantic_unexpr_arithmetic(unary_expression_t *expression) if (is_type_valid(type)) { /* TODO: improve error message */ errorf(&expression->base.source_position, - "operation needs an arithmetic type"); + "operation needs an arithmetic type"); } return; } @@ -7157,6 +7460,14 @@ static void semantic_unexpr_arithmetic(unary_expression_t *expression) expression->base.type = orig_type; } +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; @@ -7191,7 +7502,7 @@ static void semantic_dereference(unary_expression_t *expression) if (!is_type_pointer(type)) { if (is_type_valid(type)) { errorf(&expression->base.source_position, - "Unary '*' needs pointer or arrray type, but type '%T' given", orig_type); + "Unary '*' needs pointer or array type, but type '%T' given", orig_type); } return; } @@ -7201,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) @@ -7254,7 +7571,7 @@ 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_not) CREATE_UNARY_EXPRESSION_PARSER('*', EXPR_UNARY_DEREFERENCE, @@ -7591,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); @@ -7739,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; @@ -7776,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; @@ -8448,32 +8749,6 @@ end_error: 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. */ @@ -8491,9 +8766,9 @@ static statement_t *parse_label_statement(void) PUSH_PARENT(statement); - /* if source position is already set then the label is defined twice, - * otherwise it was just mentioned in a goto so far */ - if (label->source_position.input_name != NULL) { + /* 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 { @@ -8630,6 +8905,13 @@ static statement_t *parse_switch(void) 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); @@ -8804,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) { @@ -8841,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; } /** @@ -8864,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; } /** @@ -8978,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)); @@ -9015,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; } /** @@ -9055,9 +9350,8 @@ static statement_t *parse_expression_statement(void) expect(';'); - return statement; end_error: - return create_invalid_statement(); + return statement; } /** @@ -9067,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('('); @@ -9115,6 +9412,54 @@ static statement_t *parse_empty_statement(void) 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(';'); +end_error: + statement->declaration.declarations_begin = begin; + statement->declaration.declarations_end = end; + return statement; +} + /** * Parse a statement. * There's also parse_statement() which additionally checks for @@ -9160,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; @@ -9221,6 +9570,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) add_anchor_token('}'); int top = environment_top(); + int top_local = local_label_top(); scope_t *last_scope = scope; set_scope(&statement->compound.scope); @@ -9283,6 +9633,7 @@ 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; @@ -9409,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; @@ -9440,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; @@ -9449,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();