X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=77c5884acbb8765442f7d5ae46aa83dc1d66f2f6;hb=38ab672b23c1de6fff8e672fde96509e113507e7;hp=380d2072e9dbf4fc828c4aa80fd0aa369efacd7c;hpb=2a1d7cdc9a02a4f20abf4c630a91051704ae3a12;p=cparser diff --git a/parser.c b/parser.c index 380d207..77c5884 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; @@ -132,6 +134,9 @@ static struct obstack temp_obst; static source_position_t null_position = { NULL, 0 }; +/** special symbol used for anonymous entities. */ +static const symbol_t *sym_anonymous = NULL; + /* symbols for Microsoft extended-decl-modifier */ static const symbol_t *sym_align = NULL; static const symbol_t *sym_allocate = NULL; @@ -170,7 +175,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 +319,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 +484,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. */ @@ -541,6 +555,7 @@ static void restore_anchor_state(int token_type, int count) static void rem_anchor_token(int token_type) { assert(0 <= token_type && token_type < T_LAST_TOKEN); + assert(token_anchor_set[token_type] != 0); --token_anchor_set[token_type]; } @@ -628,16 +643,6 @@ static void eat_block(void) next_token(); } -/** - * eat all token until a ';' is reached or a stop token is found. - */ -static void eat_statement(void) -{ - eat_until_matching_token(';'); - if (token.type == ';') - next_token(); -} - #define eat(token_type) do { assert(token.type == token_type); next_token(); } while (0) /** @@ -682,18 +687,18 @@ static void type_error_incompatible(const char *msg, * If not, generate an error, eat the current statement, * and goto the end_error label. */ -#define expect(expected) \ - do { \ - if (UNLIKELY(token.type != (expected))) { \ - parse_error_expected(NULL, (expected), NULL); \ - add_anchor_token(expected); \ - eat_until_anchor(); \ - if (token.type == expected) \ - next_token(); \ - rem_anchor_token(expected); \ - goto end_error; \ - } \ - next_token(); \ +#define expect(expected) \ + do { \ + if (UNLIKELY(token.type != (expected))) { \ + parse_error_expected(NULL, (expected), NULL); \ + add_anchor_token(expected); \ + eat_until_anchor(); \ + if (token.type == expected) \ + next_token(); \ + rem_anchor_token(expected); \ + goto end_error; \ + } \ + next_token(); \ } while (0) static void set_scope(scope_t *new_scope) @@ -763,6 +768,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 +781,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 +791,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 +852,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 +874,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; @@ -985,7 +1024,7 @@ static void report_assign_error(assign_error_t error, type_t *orig_type_left, case ASSIGN_WARNING_POINTER_FROM_INT: warningf(source_position, - "%s makes integer '%T' from pointer '%T' without a cast", + "%s makes pointer '%T' from integer '%T' without a cast", context, orig_type_left, orig_type_right); return; @@ -1094,7 +1133,7 @@ static type_t *make_global_typedef(const char *name, type_t *type) 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; @@ -1452,12 +1491,12 @@ static void parse_gnu_attribute_format_args(gnu_attribute_t *attribute) add_anchor_token(','); parse_constant_expression(); rem_anchor_token(','); - rem_anchor_token('('); + rem_anchor_token(')'); expect(','); add_anchor_token(')'); parse_constant_expression(); - rem_anchor_token('('); + rem_anchor_token(')'); expect(')'); return; end_error: @@ -2103,8 +2142,6 @@ static void descend_into_subtype(type_path_t *path) type_t *orig_top_type = path->top_type; type_t *top_type = skip_typeref(orig_top_type); - assert(is_type_compound(top_type) || is_type_array(top_type)); - type_path_entry_t *top = append_to_type_path(path); top->type = top_type; @@ -2118,11 +2155,11 @@ static void descend_into_subtype(type_path_t *path) } else { path->top_type = NULL; } - } else { - assert(is_type_array(top_type)); - + } else if (is_type_array(top_type)) { top->v.index = 0; path->top_type = top_type->array.element_type; + } else { + assert(!is_type_valid(top_type)); } } @@ -2428,6 +2465,10 @@ finish_designator: if (type == NULL) { /* we are already outside, ... */ + if (is_type_compound(outer_type) && + !outer_type->compound.declaration->init.complete) { + goto error_parse_next; + } goto error_excess; } @@ -2726,7 +2767,7 @@ static void parse_enum_entries(type_t *const enum_type) /* TODO semantic */ } - record_declaration(entry); + record_declaration(entry, false); if (token.type != ',') break; @@ -3071,10 +3112,106 @@ static declaration_t *create_error_declaration(symbol_t *symbol, storage_class_t storage_class : STORAGE_CLASS_AUTO; 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 offset; + 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); + if (! is_type_valid(m_type)) { + /* simply ignore errors here */ + continue; + } + il_alignment_t m_alignment = m_type->base.alignment; + if (m_alignment > alignment) + alignment = m_alignment; + + offset = (size + m_alignment - 1) & -m_alignment; + + if (offset > size) + need_pad = true; + entry->offset = offset; + size = offset + m_type->base.size; + } + if (type->base.alignment != 0) { + alignment = type->base.alignment; + } + + offset = (size + alignment - 1) & -alignment; + if (offset > 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 = offset; + 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); + if (! is_type_valid(m_type)) + continue; + + 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; @@ -3214,6 +3351,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: { @@ -3222,6 +3360,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(); @@ -3439,10 +3578,8 @@ warn_about_long_long: default: /* invalid specifier combination, give an error message */ if (type_specifiers == 0) { - if (saw_error) { - specifiers->type = type_error_type; - return; - } + if (saw_error) + goto end_error; if (!strict_mode) { if (warning.implicit_int) { @@ -3461,15 +3598,13 @@ warn_about_long_long: } else { errorf(HERE, "multiple datatypes in declaration"); } - atomic_type = ATOMIC_TYPE_INVALID; + goto end_error; } - if (type_specifiers & SPECIFIER_COMPLEX && - atomic_type != ATOMIC_TYPE_INVALID) { + if (type_specifiers & SPECIFIER_COMPLEX) { type = allocate_type_zero(TYPE_COMPLEX, &builtin_source_position); type->complex.akind = atomic_type; - } else if (type_specifiers & SPECIFIER_IMAGINARY && - atomic_type != ATOMIC_TYPE_INVALID) { + } else if (type_specifiers & SPECIFIER_IMAGINARY) { type = allocate_type_zero(TYPE_IMAGINARY, &builtin_source_position); type->imaginary.akind = atomic_type; } else { @@ -3492,7 +3627,10 @@ warn_about_long_long: } specifiers->type = result; + return; + end_error: + specifiers->type = type_error_type; return; } @@ -3578,7 +3716,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); } } @@ -3605,7 +3743,7 @@ static declaration_t *parse_parameters(function_type_t *type) if (token.type == T_IDENTIFIER && !is_typedef_symbol(token.v.symbol)) { - token_type_t la1_type = look_ahead(1)->type; + 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(); @@ -3766,9 +3904,8 @@ static construct_type_t *parse_array_declarator(void) rem_anchor_token(']'); expect(']'); - return (construct_type_t*) array; end_error: - return NULL; + return (construct_type_t*) array; } static construct_type_t *parse_function_declarator(declaration_t *declaration) @@ -3896,8 +4033,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; @@ -3905,13 +4044,7 @@ static construct_type_t *parse_inner_declarator(declaration_t *declaration, if (may_be_abstract) break; parse_error_expected("while parsing declarator", T_IDENTIFIER, '(', NULL); - /* avoid a loop in the outermost scope, because eat_statement doesn't - * eat '}' */ - if (token.type == '}' && current_function == NULL) { - next_token(); - } else { - eat_statement(); - } + eat_until_anchor(); return NULL; } @@ -4010,15 +4143,19 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, function_type->function.return_type = type; type_t *skipped_return_type = skip_typeref(type); + /* §6.7.5.3(1) */ if (is_type_function(skipped_return_type)) { errorf(HERE, "function returning function is not allowed"); - type = type_error_type; } else if (is_type_array(skipped_return_type)) { errorf(HERE, "function returning array is not allowed"); - type = type_error_type; } else { - type = function_type; + if (skipped_return_type->base.qualifiers != 0) { + warningf(HERE, + "type qualifiers in return type of function type are meaningless"); + } } + + type = function_type; break; } @@ -4059,12 +4196,13 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, } type_t *skipped_type = skip_typeref(type); - if (is_type_atomic(skipped_type, ATOMIC_TYPE_VOID)) { - errorf(HERE, "array of void is not allowed"); - type = type_error_type; - } else { - type = array_type; + /* §6.7.5.2(1) */ + if (is_type_incomplete(skipped_type)) { + errorf(HERE, "array of incomplete type '%T' is not allowed", type); + } else if (is_type_function(skipped_type)) { + errorf(HERE, "array of functions is not allowed"); } + type = array_type; break; } } @@ -4161,7 +4299,7 @@ static void check_type_of_main(const declaration_t *const decl, const function_t warningf(&decl->source_position, "'main' is normally a non-static function"); } - if (skip_typeref(func_type->return_type) != type_int) { + if (!types_compatible(skip_typeref(func_type->return_type), type_int)) { warningf(&decl->source_position, "return type of 'main' should be 'int', but is '%T'", func_type->return_type); @@ -4206,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) { @@ -4224,7 +4362,7 @@ static declaration_t *internal_record_declaration( previous_declaration == NULL) { warningf(&declaration->source_position, "function declaration '%#T' is not a prototype", - orig_type, declaration->symbol); + orig_type, symbol); } if (warning.main && is_type_function(type) && is_sym_main(symbol)) { @@ -4314,8 +4452,9 @@ static declaration_t *internal_record_declaration( if (old_storage_class == STORAGE_CLASS_EXTERN && new_storage_class == STORAGE_CLASS_EXTERN) { warn_redundant_declaration: - if (!is_definition && - warning.redundant_decls && + if (!is_definition && + warning.redundant_decls && + is_type_valid(prev_type) && strcmp(previous_declaration->source_position.input_name, "") != 0) { warningf(&declaration->source_position, "redundant declaration for '%Y' (declared %P)", @@ -4333,14 +4472,16 @@ warn_redundant_declaration: } else { goto warn_redundant_declaration; } - } else if (old_storage_class == new_storage_class) { - errorf(&declaration->source_position, - "redeclaration of '%Y' (declared %P)", - symbol, &previous_declaration->source_position); - } else { - errorf(&declaration->source_position, - "redeclaration of '%Y' with different linkage (declared %P)", - symbol, &previous_declaration->source_position); + } else if (is_type_valid(prev_type)) { + if (old_storage_class == new_storage_class) { + errorf(&declaration->source_position, + "redeclaration of '%Y' (declared %P)", + symbol, &previous_declaration->source_position); + } else { + errorf(&declaration->source_position, + "redeclaration of '%Y' with different linkage (declared %P)", + symbol, &previous_declaration->source_position); + } } } @@ -4379,16 +4520,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) { @@ -4433,53 +4564,46 @@ 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 declarator '%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(';'); - declaration_t *const declaration = allocate_declaration_zero(); - declaration->type = specifiers->type; - declaration->declared_storage_class = specifiers->declared_storage_class; - declaration->source_position = specifiers->source_position; - declaration->modifiers = specifiers->modifiers; - - if (declaration->declared_storage_class != STORAGE_CLASS_NONE) { - warningf(&declaration->source_position, + if (specifiers->declared_storage_class != STORAGE_CLASS_NONE) { + warningf(&specifiers->source_position, "useless storage class in empty declaration"); } - declaration->storage_class = STORAGE_CLASS_NONE; - type_t *type = declaration->type; + type_t *type = specifiers->type; switch (type->kind) { case TYPE_COMPOUND_STRUCT: case TYPE_COMPOUND_UNION: { if (type->compound.declaration->symbol == NULL) { - warningf(&declaration->source_position, + warningf(&specifiers->source_position, "unnamed struct/union that defines no instances"); } break; @@ -4489,11 +4613,20 @@ static void parse_anonymous_declaration_rest( break; default: - warningf(&declaration->source_position, "empty declaration"); + warningf(&specifiers->source_position, "empty declaration"); break; } - finished_declaration(declaration); +#ifdef RECORD_EMPTY_DECLARATIONS + declaration_t *const declaration = allocate_declaration_zero(); + declaration->type = specifiers->type; + declaration->declared_storage_class = specifiers->declared_storage_class; + declaration->source_position = specifiers->source_position; + declaration->modifiers = specifiers->modifiers; + declaration->storage_class = STORAGE_CLASS_NONE; + + append_declaration(declaration); +#endif } static void parse_declaration_rest(declaration_t *ndeclaration, @@ -4504,7 +4637,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); @@ -4534,7 +4668,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) { @@ -4543,7 +4677,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); @@ -4554,6 +4688,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; @@ -4561,7 +4699,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); } } @@ -4569,10 +4707,13 @@ static void parse_declaration(parsed_declaration_func finished_declaration) { declaration_specifiers_t specifiers; memset(&specifiers, 0, sizeof(specifiers)); + + add_anchor_token(';'); parse_declaration_specifiers(&specifiers); + rem_anchor_token(';'); 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); @@ -4707,6 +4848,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; @@ -4912,9 +5057,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: @@ -5222,13 +5374,13 @@ 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; } add_anchor_token(','); add_anchor_token('='); - rem_anchor_token(';'); + add_anchor_token(';'); /* declarator is common to both function-definitions and declarations */ declaration_t *ndeclaration = parse_declarator(&specifiers, /*may_be_abstract=*/false); @@ -5241,11 +5393,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; } @@ -5276,6 +5425,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) */ @@ -5292,7 +5449,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; } @@ -5361,12 +5518,40 @@ static void parse_external_declaration(void) } static type_t *make_bitfield_type(type_t *base_type, expression_t *size, - source_position_t *source_position) + source_position_t *source_position, + const symbol_t *symbol) { type_t *type = allocate_type_zero(TYPE_BITFIELD, source_position); - type->bitfield.base_type = base_type; - type->bitfield.size = size; + type->bitfield.base_type = base_type; + type->bitfield.size_expression = size; + + il_size_t bit_size; + type_t *skipped_type = skip_typeref(base_type); + if (!is_type_integer(skipped_type)) { + errorf(HERE, "bitfield base type '%T' is not an integer type", + base_type); + bit_size = 0; + } else { + bit_size = skipped_type->base.size * 8; + } + + if (is_constant_expression(size)) { + long v = fold_constant(size); + + if (v < 0) { + errorf(source_position, "negative width in bit-field '%Y'", + symbol); + } else if (v == 0) { + errorf(source_position, "zero width for bit-field '%Y'", + symbol); + } else if (bit_size > 0 && (il_size_t)v > bit_size) { + errorf(source_position, "width of '%Y' exceeds its type", + symbol); + } else { + type->bitfield.bit_size = v; + } + } return type; } @@ -5403,12 +5588,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,12 +5603,8 @@ static void parse_compound_declarators(declaration_t *struct_declaration, type_t *base_type = specifiers->type; expression_t *size = parse_constant_expression(); - if (!is_type_integer(skip_typeref(base_type))) { - errorf(HERE, "bitfield base type '%T' is not an integer type", - base_type); - } - - type_t *type = make_bitfield_type(base_type, size, &source_position); + type_t *type = make_bitfield_type(base_type, size, + &source_position, sym_anonymous); declaration = allocate_declaration_zero(); declaration->namespc = NAMESPACE_NORMAL; @@ -5443,12 +5624,8 @@ static void parse_compound_declarators(declaration_t *struct_declaration, next_token(); expression_t *size = parse_constant_expression(); - if (!is_type_integer(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); + type_t *bitfield_type = make_bitfield_type(orig_type, size, + &source_position, declaration->symbol); declaration->type = bitfield_type; } else { /* TODO we ignore arrays for now... what is missing is a check @@ -5501,7 +5678,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); @@ -5713,7 +5890,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; @@ -5847,7 +6024,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; @@ -5896,21 +6076,15 @@ static expression_t *parse_reference(void) declaration_t *declaration = get_declaration(symbol, NAMESPACE_NORMAL); - source_position_t source_position = token.source_position; - next_token(); - if (declaration == NULL) { - if (token.type == '(') { + if (!strict_mode && look_ahead(1)->type == '(') { /* an implicitly declared function */ - if (strict_mode) { - errorf(HERE, "unknown symbol '%Y' found.", symbol); - } else if (warning.implicit_function_declaration) { + if (warning.implicit_function_declaration) { warningf(HERE, "implicit declaration of function '%Y'", symbol); } - declaration = create_implicit_function(symbol, - &source_position); + declaration = create_implicit_function(symbol, HERE); } else { errorf(HERE, "unknown symbol '%Y' found.", symbol); declaration = create_error_declaration(symbol, STORAGE_CLASS_NONE); @@ -5936,17 +6110,21 @@ static expression_t *parse_reference(void) "function" : "variable"; if (declaration->deprecated_string != NULL) { - warningf(&source_position, - "%s '%Y' is deprecated (declared %P): \"%s\"", prefix, - declaration->symbol, &declaration->source_position, + warningf(HERE, "%s '%Y' is deprecated (declared %P): \"%s\"", + prefix, declaration->symbol, &declaration->source_position, declaration->deprecated_string); } else { - warningf(&source_position, - "%s '%Y' is deprecated (declared %P)", prefix, + warningf(HERE, "%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(HERE, "variable '%#T' is initialized by itself", + declaration->type, declaration->symbol); + } + next_token(); return expression; } @@ -6021,11 +6199,12 @@ static expression_t *parse_compound_literal(type_t *type) */ static expression_t *parse_cast(void) { + add_anchor_token(')'); + source_position_t source_position = token.source_position; type_t *type = parse_typename(); - /* matching add_anchor_token() is at call site */ rem_anchor_token(')'); expect(')'); @@ -6054,6 +6233,8 @@ end_error: */ static expression_t *parse_statement_expression(void) { + add_anchor_token(')'); + expression_t *expression = allocate_expression_zero(EXPR_STATEMENT); statement_t *statement = parse_compound_statement(true); @@ -6075,11 +6256,11 @@ static expression_t *parse_statement_expression(void) } expression->base.type = type; + rem_anchor_token(')'); expect(')'); - return expression; end_error: - return create_invalid_expression(); + return expression; } /** @@ -6088,7 +6269,6 @@ end_error: static expression_t *parse_parenthesized_expression(void) { eat('('); - add_anchor_token(')'); switch(token.type) { case '{': @@ -6104,13 +6284,13 @@ static expression_t *parse_parenthesized_expression(void) } } + add_anchor_token(')'); expression_t *result = parse_expression(); rem_anchor_token(')'); expect(')'); - return result; end_error: - return create_invalid_expression(); + return result; } static expression_t *parse_function_keyword(void) @@ -6287,17 +6467,15 @@ static expression_t *parse_va_start(void) expression_t *const expr = parse_assignment_expression(); if (expr->kind == EXPR_REFERENCE) { declaration_t *const decl = expr->reference.declaration; - if (decl == NULL) - return create_invalid_expression(); - if (decl->parent_scope == ¤t_function->scope && - decl->next == NULL) { - expression->va_starte.parameter = decl; - expect(')'); - return expression; + if (decl->parent_scope != ¤t_function->scope || decl->next != NULL) { + errorf(&expr->base.source_position, + "second argument of 'va_start' must be last parameter of the current function"); } + expression->va_starte.parameter = decl; + expect(')'); + return expression; } - errorf(&expr->base.source_position, - "second argument of 'va_start' must be last parameter of the current function"); + expect(')'); end_error: return create_invalid_expression(); } @@ -6493,6 +6671,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. */ @@ -6570,6 +6813,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(); @@ -6633,19 +6880,18 @@ static expression_t *parse_array_expression(unsigned precedence, orig_type_left, orig_type_inside); } return_type = type_error_type; - array_access->array_ref = create_invalid_expression(); + array_access->array_ref = left; + array_access->index = inside; } + expression->base.type = automatic_type_conversion(return_type); + rem_anchor_token(']'); - if (token.type != ']') { + if (token.type == ']') { + next_token(); + } else { parse_error_expected("Problem while parsing array access", ']', NULL); - return expression; } - next_token(); - - return_type = automatic_type_conversion(return_type); - expression->base.type = return_type; - return expression; } @@ -6653,12 +6899,16 @@ static expression_t *parse_typeprop(expression_kind_t const kind, source_position_t const pos, unsigned const precedence) { - expression_t *tp_expression = allocate_expression_zero(kind); + expression_t *tp_expression = allocate_expression_zero(kind); tp_expression->base.type = type_size_t; tp_expression->base.source_position = pos; char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof"; + /* we only refer to a type property, not the value, so do not warn + * when using current_init_decl */ + declaration_t *old = current_init_decl; + current_init_decl = NULL; if (token.type == '(' && is_declaration_specifier(look_ahead(1), true)) { next_token(); add_anchor_token(')'); @@ -6698,9 +6948,9 @@ static expression_t *parse_typeprop(expression_kind_t const kind, tp_expression->typeprop.tp_expression = expression; } - return tp_expression; end_error: - return create_invalid_expression(); + current_init_decl = old; + return tp_expression; } static expression_t *parse_sizeof(unsigned precedence) @@ -6739,24 +6989,23 @@ static expression_t *parse_select_expression(unsigned precedence, type_t *const orig_type = compound->base.type; type_t *const type = skip_typeref(orig_type); - type_t *type_left = type; + 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, type_left); + symbol, orig_type); saw_error = true; } - type_left = type->pointer.points_to; - } else if (is_pointer) { - if (is_type_valid(type)) { + 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; } type_left = type; } - type_left = skip_typeref(type_left); declaration_t *entry; if (type_left->kind == TYPE_COMPOUND_STRUCT || @@ -6766,7 +7015,7 @@ static expression_t *parse_select_expression(unsigned precedence, if (!declaration->init.complete) { errorf(HERE, "request for member '%Y' of incomplete type '%T'", symbol, type_left); - return create_invalid_expression(); + goto create_error_entry; } entry = find_compound_entry(declaration, symbol); @@ -6786,11 +7035,15 @@ create_error_entry: } 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! */ - select->base.type = automatic_type_conversion(entry->type); + select->base.type = automatic_type_conversion(res_type); - type_t *skipped = skip_typeref(entry->type); + type_t *skipped = skip_typeref(res_type); if (skipped->kind == TYPE_BITFIELD) { select->base.type = skipped->bitfield.base_type; } @@ -6799,12 +7052,13 @@ create_error_entry: } 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) @@ -6837,9 +7091,23 @@ 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) { + type_t *const promoted_type = get_default_promoted_type(arg_type); + if (!types_compatible(expected_type_skip, promoted_type) && + !types_compatible(expected_type_skip, type_void_ptr) && + !types_compatible(type_void_ptr, promoted_type)) { + /* Deliberately show the skipped types in this warning */ + warningf(&arg_expr->base.source_position, + "passing call argument %u as '%T' rather than '%T' due to prototype", + pos, expected_type_skip, promoted_type); + } + } } /** @@ -6882,7 +7150,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(); @@ -6908,9 +7176,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) { @@ -6938,9 +7206,8 @@ static expression_t *parse_call_expression(unsigned precedence, "function call has aggregate value"); } - return result; end_error: - return create_invalid_expression(); + return result; } static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right); @@ -7051,13 +7318,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, @@ -7201,7 +7463,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; } @@ -7209,6 +7471,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; @@ -7243,7 +7513,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; } @@ -7312,7 +7582,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, @@ -7355,6 +7625,9 @@ static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right) { /* TODO: handle complex + imaginary types */ + type_left = get_unqualified_type(type_left); + type_right = get_unqualified_type(type_right); + /* § 6.3.1.8 Usual arithmetic conversions */ if (type_left == type_long_double || type_right == type_long_double) { return type_long_double; @@ -7441,10 +7714,15 @@ static void semantic_binexpr_arithmetic(binary_expression_t *expression) 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) { + if (!warning.div_by_zero || + !is_type_integer(expression->base.type)) + return; + + expression_t const *const right = expression->right; + /* The type of the right operand can be different for /= */ + if (is_type_integer(right->base.type) && + is_constant_expression(right) && + fold_constant(right) == 0) { warningf(&expression->base.source_position, "division by zero"); } } @@ -7783,9 +8061,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; @@ -7820,6 +8095,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; @@ -8372,12 +8648,18 @@ static statement_t *parse_case_statement(void) source_position_t *const pos = &statement->base.source_position; *pos = token.source_position; - statement->case_label.expression = parse_expression(); - if (! is_constant_expression(statement->case_label.expression)) { - errorf(pos, "case label does not reduce to an integer constant"); + expression_t *const expression = parse_expression(); + statement->case_label.expression = expression; + if (!is_constant_expression(expression)) { + /* This check does not prevent the error message in all cases of an + * prior error while parsing the expression. At least it catches the + * common case of a mistyped enum entry. */ + if (is_type_valid(expression->base.type)) { + 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); + long const val = fold_constant(expression); statement->case_label.first_case = val; statement->case_label.last_case = val; } @@ -8385,16 +8667,22 @@ static statement_t *parse_case_statement(void) 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"); + expression_t *const end_range = parse_expression(); + statement->case_label.end_range = end_range; + if (!is_constant_expression(end_range)) { + /* This check does not prevent the error message in all cases of an + * prior error while parsing the expression. At least it catches the + * common case of a mistyped enum entry. */ + if (is_type_valid(end_range->base.type)) { + 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); + long const val = fold_constant(end_range); statement->case_label.last_case = val; if (val < statement->case_label.first_case) { - statement->case_label.is_empty = true; + statement->case_label.is_empty_range = true; warningf(pos, "empty range specified"); } } @@ -8410,7 +8698,7 @@ static statement_t *parse_case_statement(void) /* 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) + if (l->is_bad || l->is_empty_range || l->expression == NULL) continue; if (c->last_case < l->first_case || c->first_case > l->last_case) @@ -8492,32 +8780,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. */ @@ -8535,9 +8797,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 { @@ -8674,6 +8936,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); @@ -8848,22 +9117,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->gotos.label = label; + 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_until_anchor(); + goto end_error; + } + symbol_t *symbol = token.v.symbol; + next_token(); + + 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) { @@ -8921,7 +9215,7 @@ end_error: /** * Parse a __leave statement. */ -static statement_t *parse_leave(void) +static statement_t *parse_leave_statement(void) { if (current_try == NULL) { errorf(HERE, "__leave statement not within __try"); @@ -9062,7 +9356,10 @@ static statement_t *parse_declaration_statement(void) statement->base.source_position = token.source_position; declaration_t *before = last_declaration; - parse_declaration(record_declaration); + if (c_mode & _GNUC) + parse_external_declaration(); + else + parse_declaration(record_declaration); if (before == NULL) { statement->declaration.declarations_begin = scope->declarations; @@ -9149,6 +9446,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 @@ -9168,13 +9513,18 @@ static statement_t *intern_parse_statement(void) } else if (is_typedef_symbol(token.v.symbol)) { statement = parse_declaration_statement(); } else switch (la1_type) { + case '*': + if (get_declaration(token.v.symbol, NAMESPACE_NORMAL) != NULL) + goto expression_statment; + /* FALLTHROUGH */ + DECLARATION_START case T_IDENTIFIER: - case '*': statement = parse_declaration_statement(); break; default: +expression_statment: statement = parse_expression_statement(); break; } @@ -9194,9 +9544,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; @@ -9210,7 +9564,58 @@ static statement_t *intern_parse_statement(void) case T_return: statement = parse_return(); break; case T_switch: statement = parse_switch(); break; case T_while: statement = parse_while(); break; - default: statement = parse_expression_statement(); break; + + case '!': + case '&': + case '(': + case '*': + case '+': + case '-': + case '~': + case T_ANDAND: + case T_CHARACTER_CONSTANT: + case T_FLOATINGPOINT: + case T_INTEGER: + case T_MINUSMINUS: + case T_PLUSPLUS: + case T_STRING_LITERAL: + case T_WIDE_CHARACTER_CONSTANT: + case T_WIDE_STRING_LITERAL: + case T___FUNCDNAME__: + case T___FUNCSIG__: + case T___FUNCTION__: + case T___PRETTY_FUNCTION__: + case T___builtin_alloca: + case T___builtin_classify_type: + case T___builtin_constant_p: + case T___builtin_expect: + case T___builtin_huge_val: + case T___builtin_isgreater: + case T___builtin_isgreaterequal: + case T___builtin_isless: + case T___builtin_islessequal: + case T___builtin_islessgreater: + case T___builtin_isunordered: + case T___builtin_nan: + case T___builtin_nand: + case T___builtin_nanf: + case T___builtin_offsetof: + case T___builtin_prefetch: + case T___builtin_va_arg: + case T___builtin_va_end: + case T___builtin_va_start: + case T___func__: + case T___noop: + case T__assume: + statement = parse_expression_statement(); + break; + + default: + errorf(HERE, "unexpected token %K while parsing statement", &token); + statement = create_invalid_statement(); + if (!at_anchor()) + next_token(); + break; } rem_anchor_token(';'); @@ -9255,6 +9660,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); @@ -9317,6 +9723,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; @@ -9405,32 +9812,47 @@ end_error:; */ static void parse_translation_unit(void) { - for (;;) switch (token.type) { - DECLARATION_START - case T_IDENTIFIER: - case T___extension__: - parse_external_declaration(); - break; + for (;;) { +#ifndef NDEBUG + bool anchor_leak = false; + for (token_type_t i = 0; i != T_LAST_TOKEN; ++i) { + unsigned char count = token_anchor_set[i]; + if (count != 0) { + errorf(HERE, "Leaked anchor token %k %d times", i, count); + anchor_leak = true; + } + } + if (anchor_leak) + abort(); +#endif - case T_asm: - parse_global_asm(); - break; + switch (token.type) { + DECLARATION_START + case T_IDENTIFIER: + case T___extension__: + parse_external_declaration(); + break; - case T_EOF: - return; + case T_asm: + parse_global_asm(); + break; - case ';': - /* TODO error in strict mode */ - warningf(HERE, "stray ';' outside of function"); - next_token(); - break; + case T_EOF: + return; - default: - errorf(HERE, "stray %K outside of function", &token); - if (token.type == '(' || token.type == '{' || token.type == '[') - eat_until_matching_token(token.type); - next_token(); - break; + case ';': + /* TODO error in strict mode */ + warningf(HERE, "stray ';' outside of function"); + next_token(); + break; + + default: + errorf(HERE, "stray %K outside of function", &token); + if (token.type == '(' || token.type == '{' || token.type == '[') + eat_until_matching_token(token.type); + next_token(); + break; + } } } @@ -9443,6 +9865,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; @@ -9474,6 +9897,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; @@ -9483,7 +9907,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(); @@ -9494,6 +9918,8 @@ void parse(void) */ void init_parser(void) { + sym_anonymous = symbol_table_insert(""); + if (c_mode & _MS) { /* add predefined symbols for extended-decl-modifier */ sym_align = symbol_table_insert("align");