X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=5e5b41931ec0bd0be913ad4fa53db04e02cf15ee;hb=5415928cc4c29c1754b6562bad26ab7d7f23882d;hp=7bfe3970fb3fe47f69dacd369a090cba74f72356;hpb=f2574a4844325b4157b3e6f0682e8ee32184eb64;p=cparser diff --git a/parser.c b/parser.c index 7bfe397..5e5b419 100644 --- a/parser.c +++ b/parser.c @@ -76,15 +76,15 @@ 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. */ symbol_t *get_property_sym; /**< the name of the get property if set. */ symbol_t *put_property_sym; /**< the name of the put property if set. */ type_t *type; - variable_t *based_variable; /**< Microsoft __based variable. */ }; /** @@ -98,6 +98,14 @@ typedef struct parse_initializer_env_t { bool must_be_constant; } parse_initializer_env_t; +/** + * Capture a MS __base extension. + */ +typedef struct based_spec_t { + source_position_t source_position; + variable_t *base_variable; +} based_spec_t; + typedef entity_t* (*parsed_declaration_func) (entity_t *declaration, bool is_definition); /** The current token. */ @@ -129,6 +137,7 @@ static bool in_type_prop = false; /** true in we are in a __extension__ context. */ static bool in_gcc_extension = false; static struct obstack temp_obst; +static entity_t *anonymous_entity; #define PUSH_PARENT(stmt) \ @@ -180,20 +189,24 @@ static void parse_externals(void); static void parse_external(void); 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_IS_PARAMETER = 1U << 2 +} declarator_flags_t; + static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, - bool may_be_abstract, - bool create_compound_member); + declarator_flags_t flags); + static entity_t *record_entity(entity_t *entity, bool is_definition); static void semantic_comparison(binary_expression_t *expression); -#define STORAGE_CLASSES \ - case T_typedef: \ - case T_extern: \ - case T_static: \ - case T_auto: \ - case T_register: \ - case T___thread: +#define STORAGE_CLASSES \ + STORAGE_CLASSES_NO_EXTERN \ + case T_extern: #define STORAGE_CLASSES_NO_EXTERN \ case T_typedef: \ @@ -736,15 +749,6 @@ void parse_error_expected(const char *message, ...) va_end(ap); } -/** - * Report a type error. - */ -static void type_error(const char *msg, const source_position_t *source_position, - type_t *type) -{ - errorf(source_position, "%s, but found type '%T'", msg, type); -} - /** * Report an incompatible type. */ @@ -2946,7 +2950,7 @@ static compound_t *parse_compound_type_specifier(bool is_struct) eat(T_union); } - symbol_t *symbol = NULL; + symbol_t *symbol = NULL; compound_t *compound = NULL; if (token.type == T___attribute__) { @@ -3008,6 +3012,11 @@ static compound_t *parse_compound_type_specifier(bool is_struct) if (token.type == '{') { parse_compound_type_entries(compound); modifiers |= parse_attributes(&attributes); + + if (symbol == NULL) { + assert(anonymous_entity == NULL); + anonymous_entity = (entity_t*)compound; + } } compound->modifiers |= modifiers; @@ -3019,8 +3028,8 @@ static void parse_enum_entries(type_t *const enum_type) eat('{'); if (token.type == '}') { - next_token(); errorf(HERE, "empty enum not allowed"); + next_token(); return; } @@ -3109,6 +3118,11 @@ static type_t *parse_enum_specifier(void) parse_enum_entries(type); parse_attributes(&attributes); + + if (symbol == NULL) { + assert(anonymous_entity == NULL); + anonymous_entity = entity; + } } else if (!entity->enume.complete && !(c_mode & _GNUC)) { errorf(HERE, "enum %Y used before definition (incomplete enumes are a GNU extension)", symbol); @@ -3403,7 +3417,7 @@ static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind) return entity; } -static void parse_microsoft_based(declaration_specifiers_t *specifiers) +static void parse_microsoft_based(based_spec_t *based_spec) { if (token.type != T_IDENTIFIER) { parse_error_expected("while parsing __based", T_IDENTIFIER, NULL); @@ -3418,10 +3432,11 @@ static void parse_microsoft_based(declaration_specifiers_t *specifiers) } else { variable_t *variable = &entity->variable; - if (specifiers->based_variable != NULL) { + if (based_spec->base_variable != NULL) { errorf(HERE, "__based type qualifier specified more than once"); } - specifiers->based_variable = variable; + based_spec->source_position = token.source_position; + based_spec->base_variable = variable; type_t *const type = variable->base.type; @@ -3554,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: \ @@ -3562,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; @@ -3580,32 +3596,26 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) expect(')'); break; - case T__based: - next_token(); - expect('('); - add_anchor_token(')'); - parse_microsoft_based(specifiers); - rem_anchor_token(')'); - expect(')'); - 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; @@ -3722,6 +3732,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) case T_inline: case T__forceinline: /* ^ DECLARATION_START except for __attribute__ */ case T_IDENTIFIER: + case '&': case '*': errorf(HERE, "discarding stray %K in declaration specifier", &token); next_token(); @@ -3741,6 +3752,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) switch (la1_type) { DECLARATION_START case T_IDENTIFIER: + case '&': case '*': { errorf(HERE, "%K does not name a type", &token); @@ -3752,7 +3764,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) next_token(); saw_error = true; - if (la1_type == '*') + if (la1_type == '&' || la1_type == '*') goto finish_specifiers; continue; } @@ -4016,14 +4028,14 @@ 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 */ source_position_t const* const pos = &declaration->base.source_position; - /* §6.9.1:6 */ + /* §6.9.1:6 The declarations in the declaration list shall contain no + * storage-class specifier other than register and no + * initializations. */ switch (declaration->declared_storage_class) { /* Allowed storage classes */ case STORAGE_CLASS_NONE: @@ -4035,18 +4047,13 @@ static void semantic_parameter(declaration_t *declaration) break; } - type_t *const orig_type = declaration->type; - /* §6.7.5.3(7): Array as last part of a parameter type is just syntactic - * sugar. Turn it into a pointer. - * §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' is of incomplete type", - orig_type, declaration->base.symbol); + errorf(pos, "parameter '%#T' has incomplete type", + type, declaration->base.symbol); } } @@ -4057,7 +4064,9 @@ static entity_t *parse_parameter(void) parse_declaration_specifiers(&specifiers); - entity_t *entity = parse_declarator(&specifiers, true, false); + entity_t *entity = parse_declarator(&specifiers, + DECL_MAY_BE_ABSTRACT | DECL_IS_PARAMETER); + anonymous_entity = NULL; return entity; } @@ -4157,6 +4166,7 @@ end_error: typedef enum construct_type_kind_t { CONSTRUCT_INVALID, CONSTRUCT_POINTER, + CONSTRUCT_REFERENCE, CONSTRUCT_FUNCTION, CONSTRUCT_ARRAY } construct_type_kind_t; @@ -4171,6 +4181,12 @@ typedef struct parsed_pointer_t parsed_pointer_t; struct parsed_pointer_t { construct_type_t construct_type; type_qualifiers_t type_qualifiers; + variable_t *base_variable; /**< MS __based extension. */ +}; + +typedef struct parsed_reference_t parsed_reference_t; +struct parsed_reference_t { + construct_type_t construct_type; }; typedef struct construct_function_type_t construct_function_type_t; @@ -4194,7 +4210,7 @@ struct construct_base_type_t { type_t *type; }; -static construct_type_t *parse_pointer_declarator(void) +static construct_type_t *parse_pointer_declarator(variable_t *base_variable) { eat('*'); @@ -4202,8 +4218,20 @@ static construct_type_t *parse_pointer_declarator(void) memset(pointer, 0, sizeof(pointer[0])); pointer->construct_type.kind = CONSTRUCT_POINTER; pointer->type_qualifiers = parse_type_qualifiers(); + pointer->base_variable = base_variable; - return (construct_type_t*) pointer; + return &pointer->construct_type; +} + +static construct_type_t *parse_reference_declarator(void) +{ + eat('&'); + + parsed_reference_t *reference = obstack_alloc(&temp_obst, sizeof(reference[0])); + memset(reference, 0, sizeof(reference[0])); + reference->construct_type.kind = CONSTRUCT_REFERENCE; + + return (construct_type_t*)reference; } static construct_type_t *parse_array_declarator(void) @@ -4240,7 +4268,7 @@ static construct_type_t *parse_array_declarator(void) expect(']'); end_error: - return (construct_type_t*) array; + return &array->construct_type; } static construct_type_t *parse_function_declarator(scope_t *scope, @@ -4292,9 +4320,43 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env, decl_modifiers_t modifiers = parse_attributes(&attributes); - /* pointers */ - while (token.type == '*') { - construct_type_t *type = parse_pointer_declarator(); + /* MS __based extension */ + based_spec_t base_spec; + base_spec.base_variable = NULL; + + for (;;) { + construct_type_t *type; + switch (token.type) { + case '&': + if (!(c_mode & _CXX)) + errorf(HERE, "references are only available for C++"); + if (base_spec.base_variable != NULL && warning.other) { + warningf(&base_spec.source_position, + "__based does not precede a pointer operator, ignored"); + } + type = parse_reference_declarator(); + /* consumed */ + base_spec.base_variable = NULL; + break; + + case '*': + type = parse_pointer_declarator(base_spec.base_variable); + /* consumed */ + base_spec.base_variable = NULL; + break; + + case T__based: + next_token(); + expect('('); + add_anchor_token(')'); + parse_microsoft_based(&base_spec); + rem_anchor_token(')'); + expect(')'); + continue; + + default: + goto ptr_operator_end; + } if (last == NULL) { first = type; @@ -4307,6 +4369,11 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env, /* TODO: find out if this is correct */ modifiers |= parse_attributes(&attributes); } +ptr_operator_end: + if (base_spec.base_variable != NULL && warning.other) { + warningf(&base_spec.source_position, + "__based does not precede a pointer operator, ignored"); + } if (env != NULL) { modifiers |= env->modifiers; @@ -4465,8 +4532,7 @@ static void parse_declaration_attributes(entity_t *entity) } } -static type_t *construct_declarator_type(construct_type_t *construct_list, - type_t *type, variable_t *variable) +static type_t *construct_declarator_type(construct_type_t *construct_list, type_t *type) { construct_type_t *iter = construct_list; for (; iter != NULL; iter = iter->next) { @@ -4499,12 +4565,25 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, } case CONSTRUCT_POINTER: { + if (is_type_reference(skip_typeref(type))) + errorf(HERE, "cannot declare a pointer to reference"); + parsed_pointer_t *parsed_pointer = (parsed_pointer_t*) iter; - type = make_based_pointer_type(type, parsed_pointer->type_qualifiers, variable); + type = make_based_pointer_type(type, parsed_pointer->type_qualifiers, parsed_pointer->base_variable); continue; } + case CONSTRUCT_REFERENCE: + if (is_type_reference(skip_typeref(type))) + errorf(HERE, "cannot declare a reference to reference"); + + type = make_reference_type(type); + continue; + case CONSTRUCT_ARRAY: { + if (is_type_reference(skip_typeref(type))) + errorf(HERE, "cannot declare an array of references"); + parsed_array_t *parsed_array = (parsed_array_t*) iter; type_t *array_type = allocate_type_zero(TYPE_ARRAY); @@ -4556,17 +4635,20 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, return type; } +static type_t *automatic_type_conversion(type_t *orig_type); + static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, - bool may_be_abstract, - bool create_compound_member) + declarator_flags_t flags) { parse_declarator_env_t env; memset(&env, 0, sizeof(env)); env.modifiers = specifiers->modifiers; - construct_type_t *construct_type - = parse_inner_declarator(&env, may_be_abstract); - type_t *type = construct_declarator_type(construct_type, specifiers->type, specifiers->based_variable); + construct_type_t *construct_type = + parse_inner_declarator(&env, (flags & DECL_MAY_BE_ABSTRACT) != 0); + type_t *orig_type = + construct_declarator_type(construct_type, specifiers->type); + type_t *type = skip_typeref(orig_type); if (construct_type != NULL) { obstack_free(&temp_obst, construct_type); @@ -4577,16 +4659,62 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, entity = allocate_entity_zero(ENTITY_TYPEDEF); entity->base.symbol = env.symbol; entity->base.source_position = env.source_position; - entity->typedefe.type = type; + entity->typedefe.type = orig_type; + + if (anonymous_entity != NULL) { + if (is_type_compound(type)) { + assert(anonymous_entity->compound.alias == NULL); + assert(anonymous_entity->kind == ENTITY_STRUCT || + anonymous_entity->kind == ENTITY_UNION); + anonymous_entity->compound.alias = entity; + anonymous_entity = NULL; + } else if (is_type_enum(type)) { + assert(anonymous_entity->enume.alias == NULL); + assert(anonymous_entity->kind == ENTITY_ENUM); + anonymous_entity->enume.alias = entity; + anonymous_entity = NULL; + } + } } else { - if (create_compound_member) { - entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER); - } else if (is_type_function(skip_typeref(type))) { + 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 (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; @@ -4596,16 +4724,36 @@ 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); } } entity->base.source_position = env.source_position; entity->base.symbol = env.symbol; entity->base.namespc = NAMESPACE_NORMAL; - entity->declaration.type = type; + entity->declaration.type = orig_type; entity->declaration.modifiers = env.modifiers; entity->declaration.deprecated_string = specifiers->deprecated_string; @@ -4628,7 +4776,7 @@ static type_t *parse_abstract_declarator(type_t *base_type) { construct_type_t *construct_type = parse_inner_declarator(NULL, 1); - type_t *result = construct_declarator_type(construct_type, base_type, NULL); + type_t *result = construct_declarator_type(construct_type, base_type); if (construct_type != NULL) { obstack_free(&temp_obst, construct_type); } @@ -4952,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); } @@ -5013,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; } @@ -5048,9 +5194,11 @@ static void parse_anonymous_declaration_rest( const declaration_specifiers_t *specifiers) { eat(';'); + 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"); } @@ -5076,6 +5224,26 @@ static void parse_anonymous_declaration_rest( } } +static void check_variable_type_complete(entity_t *ent) +{ + if (ent->kind != ENTITY_VARIABLE) + return; + + /* §6.7:7 If an identifier for an object is declared with no linkage, the + * type for the object shall be complete [...] */ + declaration_t *decl = &ent->declaration; + if (decl->storage_class != STORAGE_CLASS_NONE) + return; + + type_t *type = decl->type; + if (!is_type_incomplete(skip_typeref(type))) + return; + + errorf(&ent->base.source_position, "variable '%#T' has incomplete type", + type, ent->base.symbol); +} + + static void parse_declaration_rest(entity_t *ndeclaration, const declaration_specifiers_t *specifiers, parsed_declaration_func finished_declaration) @@ -5087,19 +5255,34 @@ static void parse_declaration_rest(entity_t *ndeclaration, if (token.type == '=') { parse_init_declarator_rest(entity); + } else if (entity->kind == ENTITY_VARIABLE) { + /* 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); + } + } } + check_variable_type_complete(entity); + if (token.type != ',') break; eat(','); add_anchor_token('='); - ndeclaration = parse_declarator(specifiers, /*may_be_abstract=*/false, false); + ndeclaration = parse_declarator(specifiers, DECL_FLAGS_NONE); rem_anchor_token('='); } expect(';'); end_error: + anonymous_entity = NULL; rem_anchor_token(';'); rem_anchor_token(','); } @@ -5140,7 +5323,7 @@ static void parse_declaration(parsed_declaration_func finished_declaration) if (token.type == ';') { parse_anonymous_declaration_rest(&specifiers); } else { - entity_t *entity = parse_declarator(&specifiers, /*may_be_abstract=*/false, false); + entity_t *entity = parse_declarator(&specifiers, DECL_FLAGS_NONE); parse_declaration_rest(entity, &specifiers, finished_declaration); } } @@ -5879,7 +6062,7 @@ static void parse_external_declaration(void) add_anchor_token('{'); /* declarator is common to both function-definitions and declarations */ - entity_t *ndeclaration = parse_declarator(&specifiers, /*may_be_abstract=*/false, false); + entity_t *ndeclaration = parse_declarator(&specifiers, DECL_FLAGS_NONE); rem_anchor_token('{'); rem_anchor_token(';'); @@ -6107,7 +6290,8 @@ static void parse_compound_declarators(compound_t *compound, entity->declaration.modifiers = specifiers->modifiers; entity->declaration.type = type; } else { - entity = parse_declarator(specifiers,/*may_be_abstract=*/true, true); + entity = parse_declarator(specifiers, + DECL_MAY_BE_ABSTRACT | DECL_CREATE_COMPOUND_MEMBER); assert(entity->kind == ENTITY_COMPOUND_MEMBER); if (token.type == ':') { @@ -6162,7 +6346,7 @@ static void parse_compound_declarators(compound_t *compound, expect(';'); end_error: - ; + anonymous_entity = NULL; } static void parse_compound_type_entries(compound_t *compound) @@ -6193,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... */ @@ -7797,6 +7982,18 @@ static void warn_reference_address_as_bool(expression_t const* expr) } } +static void semantic_condition(expression_t const *const expr, + char const *const context) +{ + type_t *const type = skip_typeref(expr->base.type); + if (is_type_scalar(type)) { + warn_reference_address_as_bool(expr); + } else if (is_type_valid(type)) { + errorf(&expr->base.source_position, + "%s must have scalar type", context); + } +} + /** * Parse a conditional expression, ie. 'expression ? ... : ...'. * @@ -7809,18 +8006,11 @@ static expression_t *parse_conditional_expression(expression_t *expression) conditional_expression_t *conditional = &result->conditional; conditional->condition = expression; - warn_reference_address_as_bool(expression); - eat('?'); add_anchor_token(':'); - /* 6.5.15.2 */ - type_t *const condition_type_orig = expression->base.type; - type_t *const condition_type = skip_typeref(condition_type_orig); - if (!is_type_scalar(condition_type) && is_type_valid(condition_type)) { - type_error("expected a scalar type in conditional condition", - &expression->base.source_position, condition_type_orig); - } + /* §6.5.15:2 The first operand shall have scalar type. */ + semantic_condition(expression, "condition of conditional operator"); expression_t *true_expression = expression; bool gnu_cond = false; @@ -8095,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); + } } } @@ -8151,15 +8346,8 @@ static void semantic_unexpr_plus(unary_expression_t *expression) static void semantic_not(unary_expression_t *expression) { - type_t *const orig_type = expression->value->base.type; - type_t *const type = skip_typeref(orig_type); - if (!is_type_scalar(type) && is_type_valid(type)) { - errorf(&expression->base.source_position, - "operand of ! must be of scalar type"); - } - - warn_reference_address_as_bool(expression->value); - + /* §6.5.3.3:1 The operand [...] of the ! operator, scalar type. */ + semantic_condition(expression->value, "operand of !"); expression->base.type = c_mode & _CXX ? type_bool : type_int; } @@ -8748,25 +8936,10 @@ static void semantic_arithmetic_addsubb_assign(binary_expression_t *expression) */ static void semantic_logical_op(binary_expression_t *expression) { - expression_t *const left = expression->left; - expression_t *const right = expression->right; - type_t *const orig_type_left = left->base.type; - type_t *const orig_type_right = right->base.type; - type_t *const type_left = skip_typeref(orig_type_left); - type_t *const type_right = skip_typeref(orig_type_right); - - warn_reference_address_as_bool(left); - warn_reference_address_as_bool(right); - - if (!is_type_scalar(type_left) || !is_type_scalar(type_right)) { - /* TODO: improve error message */ - if (is_type_valid(type_left) && is_type_valid(type_right)) { - errorf(&expression->base.source_position, - "operation needs scalar types"); - } - return; - } - + /* §6.5.13:2 Each of the operands shall have scalar type. + * §6.5.14:2 Each of the operands shall have scalar type. */ + semantic_condition(expression->left, "left operand of logical operator"); + semantic_condition(expression->right, "right operand of logical operator"); expression->base.type = c_mode & _CXX ? type_bool : type_int; } @@ -9541,7 +9714,9 @@ static statement_t *parse_if(void) add_anchor_token(')'); expression_t *const expr = parse_expression(); statement->ifs.condition = expr; - warn_reference_address_as_bool(expr); + /* §6.8.4.1:1 The controlling expression of an if statement shall have + * scalar type. */ + semantic_condition(expr, "condition of 'if'-statment"); mark_vars_read(expr, NULL); rem_anchor_token(')'); expect(')'); @@ -9682,7 +9857,9 @@ static statement_t *parse_while(void) add_anchor_token(')'); expression_t *const cond = parse_expression(); statement->whiles.condition = cond; - warn_reference_address_as_bool(cond); + /* §6.8.5:2 The controlling expression of an iteration statement shall + * have scalar type. */ + semantic_condition(cond, "condition of 'while'-statement"); mark_vars_read(cond, NULL); rem_anchor_token(')'); expect(')'); @@ -9716,7 +9893,9 @@ static statement_t *parse_do(void) add_anchor_token(')'); expression_t *const cond = parse_expression(); statement->do_while.condition = cond; - warn_reference_address_as_bool(cond); + /* §6.8.5:2 The controlling expression of an iteration statement shall + * have scalar type. */ + semantic_condition(cond, "condition of 'do-while'-statement"); mark_vars_read(cond, NULL); rem_anchor_token(')'); expect(')'); @@ -9746,22 +9925,20 @@ static statement_t *parse_for(void) expect('('); add_anchor_token(')'); - if (token.type != ';') { - if (is_declaration_specifier(&token, false)) { - parse_declaration(record_entity); - } else { - add_anchor_token(';'); - expression_t *const init = parse_expression(); - statement->fors.initialisation = init; - mark_vars_read(init, VAR_ANY); - if (warning.unused_value && !expression_has_effect(init)) { - warningf(&init->base.source_position, - "initialisation of 'for'-statement has no effect"); - } - rem_anchor_token(';'); - expect(';'); - } + if (token.type == ';') { + next_token(); + } else if (is_declaration_specifier(&token, false)) { + parse_declaration(record_entity); } else { + add_anchor_token(';'); + expression_t *const init = parse_expression(); + statement->fors.initialisation = init; + mark_vars_read(init, VAR_ANY); + if (warning.unused_value && !expression_has_effect(init)) { + warningf(&init->base.source_position, + "initialisation of 'for'-statement has no effect"); + } + rem_anchor_token(';'); expect(';'); } @@ -9769,7 +9946,9 @@ static statement_t *parse_for(void) add_anchor_token(';'); expression_t *const cond = parse_expression(); statement->fors.condition = cond; - warn_reference_address_as_bool(cond); + /* §6.8.5:2 The controlling expression of an iteration statement shall + * have scalar type. */ + semantic_condition(cond, "condition of 'for'-statement"); mark_vars_read(cond, NULL); rem_anchor_token(';'); } @@ -10239,6 +10418,7 @@ static statement_t *intern_parse_statement(void) * declaration types, so we guess a bit here to improve robustness * for incorrect programs */ switch (la1_type) { + case '&': case '*': if (get_entity(token.v.symbol, NAMESPACE_NORMAL) != NULL) goto expression_statment; @@ -10266,7 +10446,7 @@ expression_statment: } while (token.type == T___extension__); bool old_gcc_extension = in_gcc_extension; in_gcc_extension = true; - statement = parse_statement(); + statement = intern_parse_statement(); in_gcc_extension = old_gcc_extension; break;