X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=cca652ef7d266832e293a9c46dfc0b9be8967ea8;hb=b532880c7cfe1c5e69040f4e365c30e13d7c4c7d;hp=d6a38d96f8b756719842be8c9544060cc9c2bd50;hpb=074274666e17a204d4435d92e75fa73cfa2a22e0;p=cparser diff --git a/parser.c b/parser.c index d6a38d9..cca652e 100644 --- a/parser.c +++ b/parser.c @@ -58,14 +58,14 @@ struct argument_list_t { typedef struct gnu_attribute_t gnu_attribute_t; struct gnu_attribute_t { - gnu_attribute_kind_t kind; /**< The kind of the GNU attribute. */ + gnu_attribute_kind_t kind; /**< The kind of the GNU attribute. */ gnu_attribute_t *next; - bool invalid; /**< Set if this attribute had argument errors, */ - bool have_arguments; /**< True, if this attribute has arguments. */ + bool invalid; /**< Set if this attribute had argument errors, */ + bool has_arguments; /**< True, if this attribute has arguments. */ union { size_t value; string_t string; - atomic_type_kind_t akind; + symbol_t *symbol; long argument; /**< Single argument. */ argument_list_t *arguments; /**< List of argument expressions. */ } u; @@ -381,7 +381,6 @@ static size_t get_statement_struct_size(statement_kind_t kind) [STATEMENT_COMPOUND] = sizeof(compound_statement_t), [STATEMENT_RETURN] = sizeof(return_statement_t), [STATEMENT_DECLARATION] = sizeof(declaration_statement_t), - [STATEMENT_LOCAL_LABEL] = sizeof(local_label_statement_t), [STATEMENT_IF] = sizeof(if_statement_t), [STATEMENT_SWITCH] = sizeof(switch_statement_t), [STATEMENT_EXPRESSION] = sizeof(expression_statement_t), @@ -580,14 +579,6 @@ static initializer_t *allocate_initializer_zero(initializer_kind_t kind) return result; } -/** - * Free a type from the type obstack. - */ -static void free_type(void *type) -{ - obstack_free(type_obst, type); -} - /** * Returns the index of the top element of the environment stack. */ @@ -758,7 +749,7 @@ static void eat_block(void) next_token(); } -#define eat(token_type) do { assert(token.type == (token_type)); next_token(); } while (0) +#define eat(token_type) (assert(token.type == (token_type)), next_token()) /** * Report a parse error because an expected token was not found. @@ -978,13 +969,8 @@ static int get_akind_rank(atomic_type_kind_t akind) static int get_rank(const type_t *type) { assert(!is_typeref(type)); - /* The C-standard allows promoting enums to int or unsigned int (see § 7.2.2 - * and esp. footnote 108). However we can't fold constants (yet), so we - * can't decide whether unsigned int is possible, while int always works. - * (unsigned int would be preferable when possible... for stuff like - * struct { enum { ... } bla : 4; } ) */ if (type->kind == TYPE_ENUM) - return get_akind_rank(ATOMIC_TYPE_INT); + return get_akind_rank(type->enumt.akind); assert(type->kind == TYPE_ATOMIC); return get_akind_rank(type->atomic.akind); @@ -1032,21 +1018,18 @@ static expression_t *create_cast_expression(expression_t *expression, static bool is_null_pointer_constant(const expression_t *expression) { /* skip void* cast */ - if (expression->kind == EXPR_UNARY_CAST - || expression->kind == EXPR_UNARY_CAST_IMPLICIT) { - expression = expression->unary.value; + if (expression->kind == EXPR_UNARY_CAST || + expression->kind == EXPR_UNARY_CAST_IMPLICIT) { + type_t *const type = skip_typeref(expression->base.type); + if (types_compatible(type, type_void_ptr)) + expression = expression->unary.value; } - /* TODO: not correct yet, should be any constant integer expression - * which evaluates to 0 */ - if (expression->kind != EXPR_CONST) - return false; - type_t *const type = skip_typeref(expression->base.type); - if (!is_type_integer(type)) - return false; - - return expression->conste.v.int_value == 0; + return + is_type_integer(type) && + is_constant_expression(expression) && + fold_constant(expression) == 0; } /** @@ -1328,7 +1311,7 @@ static gnu_attribute_t *allocate_gnu_attribute(gnu_attribute_kind_t kind) attribute->kind = kind; attribute->next = NULL; attribute->invalid = false; - attribute->have_arguments = false; + attribute->has_arguments = false; return attribute; } @@ -1477,35 +1460,13 @@ static void parse_gnu_attribute_model_arg(gnu_attribute_t *attribute) */ static void parse_gnu_attribute_mode_arg(gnu_attribute_t *attribute) { - /* TODO: find out what is allowed here... */ - - /* at least: byte, word, pointer, list of machine modes - * __XXX___ is interpreted as XXX */ add_anchor_token(')'); if (token.type != T_IDENTIFIER) { expect(T_IDENTIFIER, end_error); } - /* This isn't really correct, the backend should provide a list of machine - * specific modes (according to gcc philosophy that is...) */ - const char *symbol_str = token.v.symbol->string; - if (strcmp_underscore("QI", symbol_str) == 0 || - strcmp_underscore("byte", symbol_str) == 0) { - attribute->u.akind = ATOMIC_TYPE_CHAR; - } else if (strcmp_underscore("HI", symbol_str) == 0) { - attribute->u.akind = ATOMIC_TYPE_SHORT; - } else if (strcmp_underscore("SI", symbol_str) == 0 - || strcmp_underscore("word", symbol_str) == 0 - || strcmp_underscore("pointer", symbol_str) == 0) { - attribute->u.akind = ATOMIC_TYPE_INT; - } else if (strcmp_underscore("DI", symbol_str) == 0) { - attribute->u.akind = ATOMIC_TYPE_LONGLONG; - } else { - if (warning.other) - warningf(HERE, "ignoring unknown mode '%s'", symbol_str); - attribute->invalid = true; - } + attribute->u.symbol = token.v.symbol; next_token(); rem_anchor_token(')'); @@ -1591,7 +1552,7 @@ end_error: */ static void check_no_argument(gnu_attribute_t *attribute, const char *name) { - if (!attribute->have_arguments) + if (!attribute->has_arguments) return; /* should have no arguments */ @@ -1741,7 +1702,7 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) /* empty args are allowed */ next_token(); } else - attribute->have_arguments = true; + attribute->has_arguments = true; } switch (kind) { @@ -1800,7 +1761,7 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) case GNU_AK_ALIGNED: /* __align__ may be used without an argument */ - if (attribute->have_arguments) { + if (attribute->has_arguments) { parse_gnu_attribute_const_arg(attribute); } break; @@ -1808,7 +1769,7 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) case GNU_AK_FORMAT_ARG: case GNU_AK_REGPARM: case GNU_AK_TRAP_EXIT: - if (!attribute->have_arguments) { + if (!attribute->has_arguments) { /* should have arguments */ errorf(HERE, "wrong number of arguments specified for '%s' attribute", name); attribute->invalid = true; @@ -1818,7 +1779,7 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) case GNU_AK_ALIAS: case GNU_AK_SECTION: case GNU_AK_SP_SWITCH: - if (!attribute->have_arguments) { + if (!attribute->has_arguments) { /* should have arguments */ errorf(HERE, "wrong number of arguments specified for '%s' attribute", name); attribute->invalid = true; @@ -1826,7 +1787,7 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) parse_gnu_attribute_string_arg(attribute, &attribute->u.string); break; case GNU_AK_FORMAT: - if (!attribute->have_arguments) { + if (!attribute->has_arguments) { /* should have arguments */ errorf(HERE, "wrong number of arguments specified for '%s' attribute", name); attribute->invalid = true; @@ -1835,29 +1796,29 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) break; case GNU_AK_WEAKREF: /* may have one string argument */ - if (attribute->have_arguments) + if (attribute->has_arguments) parse_gnu_attribute_string_arg(attribute, &attribute->u.string); break; case GNU_AK_NONNULL: - if (attribute->have_arguments) + if (attribute->has_arguments) parse_gnu_attribute_const_arg_list(attribute); break; case GNU_AK_TLS_MODEL: - if (!attribute->have_arguments) { + if (!attribute->has_arguments) { /* should have arguments */ errorf(HERE, "wrong number of arguments specified for '%s' attribute", name); } else parse_gnu_attribute_tls_model_arg(attribute); break; case GNU_AK_VISIBILITY: - if (!attribute->have_arguments) { + if (!attribute->has_arguments) { /* should have arguments */ errorf(HERE, "wrong number of arguments specified for '%s' attribute", name); } else parse_gnu_attribute_visibility_arg(attribute); break; case GNU_AK_MODEL: - if (!attribute->have_arguments) { + if (!attribute->has_arguments) { /* should have arguments */ errorf(HERE, "wrong number of arguments specified for '%s' attribute", name); } else { @@ -1865,7 +1826,7 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) } break; case GNU_AK_MODE: - if (!attribute->have_arguments) { + if (!attribute->has_arguments) { /* should have arguments */ errorf(HERE, "wrong number of arguments specified for '%s' attribute", name); } else { @@ -1874,12 +1835,12 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) break; case GNU_AK_INTERRUPT: /* may have one string argument */ - if (attribute->have_arguments) + if (attribute->has_arguments) parse_gnu_attribute_interrupt_arg(attribute); break; case GNU_AK_SENTINEL: /* may have one string argument */ - if (attribute->have_arguments) + if (attribute->has_arguments) parse_gnu_attribute_const_arg(attribute); break; case GNU_AK_LAST: @@ -2946,7 +2907,7 @@ static initializer_t *parse_initializer(parse_initializer_env_t *env) result = parse_scalar_initializer(type, env->must_be_constant); } - /* § 6.7.8 (22) array initializers for arrays with unknown size determine + /* § 6.7.8:22 array initializers for arrays with unknown size determine * the array type size */ if (is_type_array(type) && type->array.size_expression == NULL && result != NULL) { @@ -3033,8 +2994,8 @@ static compound_t *parse_compound_type_specifier(bool is_struct) compound = &entity->compound; if (compound->base.parent_scope != current_scope && (token.type == '{' || token.type == ';')) { - /* we're in an inner scope and have a definition. Override - existing definition in outer scope */ + /* we're in an inner scope and have a definition. Shadow + * existing definition in outer scope */ compound = NULL; } else if (compound->complete && token.type == '{') { assert(symbol != NULL); @@ -3148,7 +3109,18 @@ static type_t *parse_enum_specifier(void) next_token(); entity = get_entity(symbol, NAMESPACE_ENUM); - assert(entity == NULL || entity->kind == ENTITY_ENUM); + if (entity != NULL) { + assert(entity->kind == ENTITY_ENUM); + if (entity->base.parent_scope != current_scope && + (token.type == '{' || token.type == ';')) { + /* we're in an inner scope and have a definition. Shadow + * existing definition in outer scope */ + entity = NULL; + } else if (entity->enume.complete && token.type == '{') { + errorf(HERE, "multiple definitions of 'enum %Y' (previous definition %P)", + symbol, &entity->base.source_position); + } + } } else if (token.type != '{') { parse_error_expected("while parsing enum type specifier", T_IDENTIFIER, '{', NULL); @@ -3168,12 +3140,9 @@ static type_t *parse_enum_specifier(void) type_t *const type = allocate_type_zero(TYPE_ENUM); type->enumt.enume = &entity->enume; + type->enumt.akind = ATOMIC_TYPE_INT; if (token.type == '{') { - if (entity->enume.complete) { - errorf(HERE, "multiple definitions of 'enum %Y' (previous definition %P)", - symbol, &entity->base.source_position); - } if (symbol != NULL) { environment_push(entity); } @@ -3286,13 +3255,7 @@ static type_t *create_builtin_type(symbol_t *const symbol, type_t *type = allocate_type_zero(TYPE_BUILTIN); type->builtin.symbol = symbol; type->builtin.real_type = real_type; - - type_t *result = typehash_insert(type); - if (type != result) { - free_type(type); - } - - return result; + return identify_new_type(type); } static type_t *get_typedef_type(symbol_t *symbol) @@ -3621,6 +3584,78 @@ static void finish_union_type(compound_type_t *type) type->base.alignment = alignment; } +static type_t *handle_attribute_mode(const gnu_attribute_t *attribute, + type_t *orig_type) +{ + type_t *type = skip_typeref(orig_type); + + /* at least: byte, word, pointer, list of machine modes + * __XXX___ is interpreted as XXX */ + + /* This isn't really correct, the backend should provide a list of machine + * specific modes (according to gcc philosophy that is...) */ + const char *symbol_str = attribute->u.symbol->string; + bool sign = is_type_signed(type); + atomic_type_kind_t akind; + if (strcmp_underscore("QI", symbol_str) == 0 || + strcmp_underscore("byte", symbol_str) == 0) { + akind = sign ? ATOMIC_TYPE_CHAR : ATOMIC_TYPE_UCHAR; + } else if (strcmp_underscore("HI", symbol_str) == 0) { + akind = sign ? ATOMIC_TYPE_SHORT : ATOMIC_TYPE_USHORT; + } else if (strcmp_underscore("SI", symbol_str) == 0 + || strcmp_underscore("word", symbol_str) == 0 + || strcmp_underscore("pointer", symbol_str) == 0) { + akind = sign ? ATOMIC_TYPE_INT : ATOMIC_TYPE_UINT; + } else if (strcmp_underscore("DI", symbol_str) == 0) { + akind = sign ? ATOMIC_TYPE_LONGLONG : ATOMIC_TYPE_ULONGLONG; + } else { + if (warning.other) + warningf(HERE, "ignoring unknown mode '%s'", symbol_str); + return orig_type; + } + + if (type->kind == TYPE_ATOMIC) { + type_t *copy = duplicate_type(type); + copy->atomic.akind = akind; + return identify_new_type(copy); + } else if (type->kind == TYPE_ENUM) { + type_t *copy = duplicate_type(type); + copy->enumt.akind = akind; + return identify_new_type(copy); + } else if (is_type_pointer(type)) { + warningf(HERE, "__attribute__((mode)) on pointers not implemented yet (ignored)"); + return type; + } + + errorf(HERE, "__attribute__((mode)) only allowed on integer, enum or pointer type"); + return orig_type; +} + +static type_t *handle_type_attributes(const gnu_attribute_t *attributes, + type_t *type) +{ + const gnu_attribute_t *attribute = attributes; + for ( ; attribute != NULL; attribute = attribute->next) { + if (attribute->invalid) + continue; + + if (attribute->kind == GNU_AK_MODE) { + type = handle_attribute_mode(attribute, type); + } else if (attribute->kind == GNU_AK_ALIGNED) { + int alignment = 32; /* TODO: fill in maximum useful alignment for + target machine */ + if (attribute->has_arguments) + alignment = attribute->u.argument; + + type_t *copy = duplicate_type(type); + copy->base.alignment = attribute->u.argument; + type = identify_new_type(copy); + } + } + + return type; +} + static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) { type_t *type = NULL; @@ -3636,8 +3671,6 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) while (true) { specifiers->modifiers |= parse_attributes(&specifiers->gnu_attributes); - if (specifiers->modifiers & DM_TRANSPARENT_UNION) - modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION; switch (token.type) { /* storage class */ @@ -3858,6 +3891,9 @@ wrong_thread_stoarge_class: } finish_specifiers: + specifiers->modifiers + |= parse_attributes(&specifiers->gnu_attributes); + in_gcc_extension = old_gcc_extension; if (type == NULL || (saw_error && type_specifiers != 0)) { @@ -4032,9 +4068,13 @@ warn_about_long_long: type = allocate_type_zero(TYPE_IMAGINARY); type->imaginary.akind = atomic_type; } else { - type = allocate_type_zero(TYPE_ATOMIC); - type->atomic.akind = atomic_type; + type = allocate_type_zero(TYPE_ATOMIC); + type->atomic.akind = atomic_type; } + type->base.alignment = get_atomic_type_alignment(atomic_type); + unsigned const size = get_atomic_type_size(atomic_type); + type->base.size = + type_specifiers & SPECIFIER_COMPLEX ? size * 2 : size; newtype = true; } else if (type_specifiers != 0) { errorf(HERE, "multiple datatypes in declaration"); @@ -4042,15 +4082,15 @@ warn_about_long_long: /* FIXME: check type qualifiers here */ + if (specifiers->modifiers & DM_TRANSPARENT_UNION) + modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION; type->base.qualifiers = qualifiers; type->base.modifiers = modifiers; - type_t *result = typehash_insert(type); - if (newtype && result != type) { - free_type(type); - } + type = identify_new_type(type); - specifiers->type = result; + type = handle_type_attributes(specifiers->gnu_attributes, type); + specifiers->type = type; return; end_error: @@ -4550,34 +4590,28 @@ static void parse_declaration_attributes(entity_t *entity) if (type == NULL) return; - /* handle these strange/stupid mode attributes */ gnu_attribute_t *attribute = attributes; for ( ; attribute != NULL; attribute = attribute->next) { - if (attribute->kind != GNU_AK_MODE || attribute->invalid) + if (attribute->invalid) continue; - atomic_type_kind_t akind = attribute->u.akind; - if (!is_type_signed(type)) { - switch (akind) { - case ATOMIC_TYPE_CHAR: akind = ATOMIC_TYPE_UCHAR; break; - case ATOMIC_TYPE_SHORT: akind = ATOMIC_TYPE_USHORT; break; - case ATOMIC_TYPE_INT: akind = ATOMIC_TYPE_UINT; break; - case ATOMIC_TYPE_LONGLONG: akind = ATOMIC_TYPE_ULONGLONG; break; - default: - panic("invalid akind in mode attribute"); - } - } else { - switch (akind) { - case ATOMIC_TYPE_CHAR: akind = ATOMIC_TYPE_SCHAR; break; - case ATOMIC_TYPE_SHORT: akind = ATOMIC_TYPE_SHORT; break; - case ATOMIC_TYPE_INT: akind = ATOMIC_TYPE_INT; break; - case ATOMIC_TYPE_LONGLONG: akind = ATOMIC_TYPE_LONGLONG; break; - default: - panic("invalid akind in mode attribute"); + if (attribute->kind == GNU_AK_MODE) { + type = handle_attribute_mode(attribute, type); + } else if (attribute->kind == GNU_AK_ALIGNED) { + int alignment = 32; /* TODO: fill in maximum usefull alignment for target machine */ + if (attribute->has_arguments) + alignment = attribute->u.argument; + + if (entity->kind == ENTITY_TYPEDEF) { + type_t *copy = duplicate_type(type); + copy->base.alignment = attribute->u.argument; + type = identify_new_type(copy); + } else if(entity->kind == ENTITY_VARIABLE) { + entity->variable.alignment = alignment; + } else if(entity->kind == ENTITY_COMPOUND_MEMBER) { + entity->compound_member.alignment = alignment; } } - - type = make_atomic_type(akind, type->base.qualifiers); } type_modifiers_t type_modifiers = type->base.modifiers; @@ -4585,13 +4619,9 @@ static void parse_declaration_attributes(entity_t *entity) type_modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION; if (type->base.modifiers != type_modifiers) { - type_t *copy = duplicate_type(type); + type_t *copy = duplicate_type(type); copy->base.modifiers = type_modifiers; - - type = typehash_insert(copy); - if (type != copy) { - obstack_free(type_obst, copy); - } + type = identify_new_type(copy); } if (entity->kind == ENTITY_TYPEDEF) { @@ -4619,7 +4649,7 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, type_ function_type->function.return_type = type; type_t *skipped_return_type = skip_typeref(type); - /* §6.7.5.3(1) */ + /* §6.7.5.3:1 */ if (is_type_function(skipped_return_type)) { errorf(HERE, "function returning function is not allowed"); } else if (is_type_array(skipped_return_type)) { @@ -4681,7 +4711,7 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, type_ } type_t *skipped_type = skip_typeref(type); - /* §6.7.5.2(1) */ + /* §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)) { @@ -4692,14 +4722,12 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, type_ } } - type_t *hashed_type = typehash_insert(type); - if (hashed_type != type) { - /* the function type was constructed earlier freeing it here will - * destroy other types... */ - if (iter->kind != CONSTRUCT_FUNCTION) { - free_type(type); - } - type = hashed_type; + /* The function type was constructed earlier. Freeing it here will + * destroy other types. */ + if (iter->kind == CONSTRUCT_FUNCTION) { + type = typehash_insert(type); + } else { + type = identify_new_type(type); } } @@ -4784,16 +4812,18 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, if (flags & DECL_CREATE_COMPOUND_MEMBER) { entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER); - if (specifiers->is_inline && is_type_valid(type)) { - errorf(&env.source_position, - "compound member '%Y' declared 'inline'", env.symbol); - } + if (env.symbol != NULL) { + if (specifiers->is_inline && is_type_valid(type)) { + errorf(&env.source_position, + "compound member '%Y' declared 'inline'", env.symbol); + } - if (specifiers->thread_local || - specifiers->storage_class != STORAGE_CLASS_NONE) { - errorf(&env.source_position, - "compound member '%Y' must have no storage class", - env.symbol); + if (specifiers->thread_local || + specifiers->storage_class != STORAGE_CLASS_NONE) { + errorf(&env.source_position, + "compound member '%Y' must have no storage class", + env.symbol); + } } } else if (flags & DECL_IS_PARAMETER) { orig_type = semantic_parameter(&env.source_position, orig_type, @@ -4806,47 +4836,47 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, entity->function.is_inline = specifiers->is_inline; entity->function.parameters = env.parameters; - if (specifiers->thread_local || ( - specifiers->storage_class != STORAGE_CLASS_EXTERN && - specifiers->storage_class != STORAGE_CLASS_NONE && - specifiers->storage_class != STORAGE_CLASS_STATIC) - ) { - errorf(&env.source_position, - "invalid storage class for function '%Y'", env.symbol); + if (env.symbol != NULL) { + if (specifiers->thread_local || ( + specifiers->storage_class != STORAGE_CLASS_EXTERN && + specifiers->storage_class != STORAGE_CLASS_NONE && + specifiers->storage_class != STORAGE_CLASS_STATIC + )) { + errorf(&env.source_position, + "invalid storage class for function '%Y'", env.symbol); + } } } else { entity = allocate_entity_zero(ENTITY_VARIABLE); entity->variable.get_property_sym = specifiers->get_property_sym; entity->variable.put_property_sym = specifiers->put_property_sym; - if (specifiers->alignment != 0) { - /* TODO: add checks here */ - entity->variable.alignment = specifiers->alignment; - } - - if (specifiers->is_inline && is_type_valid(type)) { - errorf(&env.source_position, - "variable '%Y' declared 'inline'", env.symbol); - } entity->variable.thread_local = specifiers->thread_local; - bool invalid_storage_class = false; - if (current_scope == file_scope) { - if (specifiers->storage_class != STORAGE_CLASS_EXTERN && - specifiers->storage_class != STORAGE_CLASS_NONE && - specifiers->storage_class != STORAGE_CLASS_STATIC) { - invalid_storage_class = true; + if (env.symbol != NULL) { + if (specifiers->is_inline && is_type_valid(type)) { + errorf(&env.source_position, + "variable '%Y' declared 'inline'", env.symbol); } - } else { - if (specifiers->thread_local && - specifiers->storage_class == STORAGE_CLASS_NONE) { - invalid_storage_class = true; + + bool invalid_storage_class = false; + if (current_scope == file_scope) { + if (specifiers->storage_class != STORAGE_CLASS_EXTERN && + specifiers->storage_class != STORAGE_CLASS_NONE && + specifiers->storage_class != STORAGE_CLASS_STATIC) { + invalid_storage_class = true; + } + } else { + if (specifiers->thread_local && + specifiers->storage_class == STORAGE_CLASS_NONE) { + invalid_storage_class = true; + } + } + if (invalid_storage_class) { + errorf(&env.source_position, + "invalid storage class for variable '%Y'", env.symbol); } - } - if (invalid_storage_class) { - errorf(&env.source_position, - "invalid storage class for variable '%Y'", env.symbol); } } @@ -5260,7 +5290,7 @@ static void parse_init_declarator_rest(entity_t *entity) current_init_decl = NULL; if (entity->kind == ENTITY_VARIABLE) { - /* § 6.7.5 (22) array initializers for arrays with unknown size + /* § 6.7.5:22 array initializers for arrays with unknown size * determine the array type size */ declaration->type = env.type; entity->variable.initializer = initializer; @@ -5527,12 +5557,9 @@ decl_list_end: new_type->function.parameters = parameters; new_type->function.unspecified_parameters = true; - type = typehash_insert(new_type); - if (type != new_type) { - obstack_free(type_obst, new_type); - } + new_type = identify_new_type(new_type); - entity->declaration.type = type; + entity->declaration.type = new_type; rem_anchor_token('{'); } @@ -5803,7 +5830,6 @@ static void check_reachable(statement_t *const stmt) switch (stmt->kind) { case STATEMENT_INVALID: case STATEMENT_EMPTY: - case STATEMENT_LOCAL_LABEL: case STATEMENT_ASM: next = stmt->base.next; break; @@ -6082,7 +6108,6 @@ found_break_parent: case STATEMENT_INVALID: case STATEMENT_EMPTY: case STATEMENT_DECLARATION: - case STATEMENT_LOCAL_LABEL: case STATEMENT_EXPRESSION: case STATEMENT_ASM: case STATEMENT_RETURN: @@ -6344,18 +6369,15 @@ static void parse_external_declaration(void) ndeclaration->base.symbol); } - /* § 6.7.5.3 (14) a function definition with () means no + /* § 6.7.5.3:14 a function definition with () means no * parameters (and not unspecified parameters) */ - if (type->function.unspecified_parameters - && type->function.parameters == NULL - && !type->function.kr_style_parameters) { - type_t *duplicate = duplicate_type(type); - duplicate->function.unspecified_parameters = false; + if (type->function.unspecified_parameters && + type->function.parameters == NULL && + !type->function.kr_style_parameters) { + type_t *copy = duplicate_type(type); + copy->function.unspecified_parameters = false; + type = identify_new_type(copy); - type = typehash_insert(duplicate); - if (type != duplicate) { - obstack_free(type_obst, duplicate); - } ndeclaration->declaration.type = type; } @@ -6796,11 +6818,7 @@ static entity_t *create_implicit_function(symbol_t *symbol, ntype->function.return_type = type_int; ntype->function.unspecified_parameters = true; ntype->function.linkage = LINKAGE_C; - - type_t *type = typehash_insert(ntype); - if (type != ntype) { - free_type(ntype); - } + type_t *type = identify_new_type(ntype); entity_t *entity = allocate_entity_zero(ENTITY_FUNCTION); entity->declaration.storage_class = STORAGE_CLASS_EXTERN; @@ -6840,12 +6858,7 @@ static type_t *make_function_2_type(type_t *return_type, type_t *argument_type1, type->function.return_type = return_type; type->function.parameters = parameter1; - type_t *result = typehash_insert(type); - if (result != type) { - free_type(type); - } - - return result; + return identify_new_type(type); } /** @@ -6866,12 +6879,7 @@ static type_t *make_function_1_type(type_t *return_type, type_t *argument_type) type->function.return_type = return_type; type->function.parameters = parameter; - type_t *result = typehash_insert(type); - if (result != type) { - free_type(type); - } - - return result; + return identify_new_type(type); } static type_t *make_function_0_type(type_t *return_type) @@ -6880,12 +6888,7 @@ static type_t *make_function_0_type(type_t *return_type) type->function.return_type = return_type; type->function.parameters = NULL; - type_t *result = typehash_insert(type); - if (result != type) { - free_type(type); - } - - return result; + return identify_new_type(type); } /** @@ -8533,7 +8536,7 @@ static bool check_pointer_arithmetic(const source_position_t *source_position, static bool is_lvalue(const expression_t *expression) { - /* TODO: doesn't seem to be consistent with §6.3.2.1 (1) */ + /* TODO: doesn't seem to be consistent with §6.3.2.1:1 */ switch (expression->kind) { case EXPR_ARRAY_ACCESS: case EXPR_COMPOUND_LITERAL: @@ -11369,9 +11372,7 @@ static void complete_incomplete_arrays(void) new_type->array.has_implicit_size = true; new_type->array.size = 1; - type_t *const result = typehash_insert(new_type); - if (type != result) - free_type(type); + type_t *const result = identify_new_type(new_type); decl->type = result; }