X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=5e5b41931ec0bd0be913ad4fa53db04e02cf15ee;hb=5415928cc4c29c1754b6562bad26ab7d7f23882d;hp=a8748dd425f9456c890dd3557efd527e9c67a80f;hpb=1d434014f6a6e6f5a44ad1057953862f7a3a3f8a;p=cparser diff --git a/parser.c b/parser.c index a8748dd..5e5b419 100644 --- a/parser.c +++ b/parser.c @@ -76,8 +76,9 @@ struct declaration_specifiers_t { source_position_t source_position; storage_class_t storage_class; unsigned char alignment; /**< Alignment, 0 if not set. */ - bool is_inline : 1; - bool deprecated : 1; + bool is_inline : 1; + bool thread_local : 1; /**< GCC __thread */ + bool deprecated : 1; decl_modifiers_t modifiers; /**< declaration modifiers */ gnu_attribute_t *gnu_attributes; /**< list of GNU attributes */ const char *deprecated_string; /**< can be set if declaration was marked deprecated. */ @@ -192,7 +193,8 @@ static void parse_compound_type_entries(compound_t *compound_declaration); typedef enum declarator_flags_t { DECL_FLAGS_NONE = 0, DECL_MAY_BE_ABSTRACT = 1U << 0, - DECL_CREATE_COMPOUND_MEMBER = 1U << 1 + DECL_CREATE_COMPOUND_MEMBER = 1U << 1, + DECL_IS_PARAMETER = 1U << 2 } declarator_flags_t; static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, @@ -3567,7 +3569,6 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION; switch (token.type) { - /* storage class */ #define MATCH_STORAGE_CLASS(token, class) \ case token: \ @@ -3575,6 +3576,8 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) errorf(HERE, "multiple storage classes in declaration specifiers"); \ } \ specifiers->storage_class = class; \ + if (specifiers->thread_local) \ + goto check_thread_storage_class; \ next_token(); \ break; @@ -3594,22 +3597,25 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) break; case T___thread: - switch (specifiers->storage_class) { - case STORAGE_CLASS_NONE: - specifiers->storage_class = STORAGE_CLASS_THREAD; - break; - - case STORAGE_CLASS_EXTERN: - specifiers->storage_class = STORAGE_CLASS_THREAD_EXTERN; - break; - - case STORAGE_CLASS_STATIC: - specifiers->storage_class = STORAGE_CLASS_THREAD_STATIC; - break; + if (specifiers->thread_local) { + errorf(HERE, "duplicate '__thread'"); + } else { + specifiers->thread_local = true; +check_thread_storage_class: + switch (specifiers->storage_class) { + case STORAGE_CLASS_EXTERN: + case STORAGE_CLASS_NONE: + case STORAGE_CLASS_STATIC: + break; - default: - errorf(HERE, "multiple storage classes in declaration specifiers"); - break; + char const* wrong; + case STORAGE_CLASS_AUTO: wrong = "auto"; goto wrong_thread_stoarge_class; + case STORAGE_CLASS_REGISTER: wrong = "register"; goto wrong_thread_stoarge_class; + case STORAGE_CLASS_TYPEDEF: wrong = "typedef"; goto wrong_thread_stoarge_class; +wrong_thread_stoarge_class: + errorf(HERE, "'__thread' used with '%s'", wrong); + break; + } } next_token(); break; @@ -4022,8 +4028,6 @@ static void parse_identifier_list(scope_t *scope) } while (token.type == T_IDENTIFIER); } -static type_t *automatic_type_conversion(type_t *orig_type); - static void semantic_parameter(declaration_t *declaration) { /* TODO: improve error messages */ @@ -4043,22 +4047,13 @@ static void semantic_parameter(declaration_t *declaration) break; } - type_t *const orig_type = declaration->type; - /* §6.7.5.3:7 A declaration of a parameter as ``array of type'' shall be - * adjusted to ``qualified pointer to type'', [...] - * §6.7.5.3:8 A declaration of a parameter as ``function returning type'' - * shall be adjusted to ``pointer to function returning type'', - * as in 6.3.2.1. - */ - type_t *const type = automatic_type_conversion(orig_type); - declaration->type = type; - /* §6.7.5.3:4 After adjustment, the parameters in a parameter type list in * a function declarator that is part of a definition of that * function shall not have incomplete type. */ + type_t *type = declaration->type; if (is_type_incomplete(skip_typeref(type))) { errorf(pos, "parameter '%#T' has incomplete type", - orig_type, declaration->base.symbol); + type, declaration->base.symbol); } } @@ -4069,7 +4064,8 @@ static entity_t *parse_parameter(void) parse_declaration_specifiers(&specifiers); - entity_t *entity = parse_declarator(&specifiers, DECL_MAY_BE_ABSTRACT); + entity_t *entity = parse_declarator(&specifiers, + DECL_MAY_BE_ABSTRACT | DECL_IS_PARAMETER); anonymous_entity = NULL; return entity; } @@ -4639,6 +4635,8 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, type_ return type; } +static type_t *automatic_type_conversion(type_t *orig_type); + static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, declarator_flags_t flags) { @@ -4679,13 +4677,44 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, } } else { if (flags & DECL_CREATE_COMPOUND_MEMBER) { - entity = allocate_entity_zero(ENTITY_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 (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) { + /* §6.7.5.3:7 A declaration of a parameter as ``array of type'' + * shall be adjusted to ``qualified pointer to type'', + * [...] + * §6.7.5.3:8 A declaration of a parameter as ``function returning + * type'' shall be adjusted to ``pointer to function + * returning type'', as in 6.3.2.1. */ + orig_type = automatic_type_conversion(type); + goto create_variable; } else if (is_type_function(type)) { entity = allocate_entity_zero(ENTITY_FUNCTION); 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); + } } else { +create_variable: entity = allocate_entity_zero(ENTITY_VARIABLE); entity->variable.get_property_sym = specifiers->get_property_sym; @@ -4695,9 +4724,29 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, entity->variable.alignment = specifiers->alignment; } - if (warning.other && specifiers->is_inline && is_type_valid(type)) { - warningf(&env.source_position, - "variable '%Y' declared 'inline'\n", env.symbol); + 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; + } + } 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); } } @@ -5051,8 +5100,7 @@ error_redeclaration: && entity->kind == ENTITY_VARIABLE && current_scope == file_scope) { declaration_t *declaration = &entity->declaration; - if (declaration->storage_class == STORAGE_CLASS_NONE || - declaration->storage_class == STORAGE_CLASS_THREAD) { + if (declaration->storage_class == STORAGE_CLASS_NONE) { warningf(pos, "no previous declaration for '%#T'", declaration->type, symbol); } @@ -5112,8 +5160,7 @@ static void parse_init_declarator_rest(entity_t *entity) } bool must_be_constant = false; - if (declaration->storage_class == STORAGE_CLASS_STATIC || - declaration->storage_class == STORAGE_CLASS_THREAD_STATIC || + if (declaration->storage_class == STORAGE_CLASS_STATIC || entity->base.parent_scope == file_scope) { must_be_constant = true; } @@ -5150,7 +5197,8 @@ static void parse_anonymous_declaration_rest( anonymous_entity = NULL; if (warning.other) { - if (specifiers->storage_class != STORAGE_CLASS_NONE) { + if (specifiers->storage_class != STORAGE_CLASS_NONE || + specifiers->thread_local) { warningf(&specifiers->source_position, "useless storage class in empty declaration"); } @@ -5208,11 +5256,16 @@ static void parse_declaration_rest(entity_t *ndeclaration, if (token.type == '=') { parse_init_declarator_rest(entity); } else if (entity->kind == ENTITY_VARIABLE) { - type_t *type = entity->declaration.type; - if (is_type_reference(skip_typeref(type))) { - errorf(&entity->base.source_position, - "reference '%#T' must be initialized", - type, entity->base.symbol); + /* ISO/IEC 14882:1998(E) §8.5.3:3 The initializer can be omitted + * [...] where the extern specifier is explicitly used. */ + declaration_t *decl = &entity->declaration; + if (decl->storage_class != STORAGE_CLASS_EXTERN) { + type_t *type = decl->type; + if (is_type_reference(skip_typeref(type))) { + errorf(&entity->base.source_position, + "reference '%#T' must be initialized", + type, entity->base.symbol); + } } } @@ -6324,7 +6377,8 @@ static type_t *parse_typename(void) declaration_specifiers_t specifiers; memset(&specifiers, 0, sizeof(specifiers)); parse_declaration_specifiers(&specifiers); - if (specifiers.storage_class != STORAGE_CLASS_NONE) { + if (specifiers.storage_class != STORAGE_CLASS_NONE || + specifiers.thread_local) { /* TODO: improve error message, user does probably not know what a * storage class is... */ @@ -8231,11 +8285,16 @@ static bool is_lvalue(const expression_t *expression) case EXPR_UNARY_DEREFERENCE: return true; - default: + default: { + type_t *type = skip_typeref(expression->base.type); + return + /* ISO/IEC 14882:1998(E) §3.10:3 */ + is_type_reference(type) || /* Claim it is an lvalue, if the type is invalid. There was a parse * error before, which maybe prevented properly recognizing it as * lvalue. */ - return !is_type_valid(skip_typeref(expression->base.type)); + !is_type_valid(type); + } } }