X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=1686f34e6c5a9a0de68a855211185b52b5831aee;hb=22d24ddd2209686fa723a62ccc19b7c2eea2d172;hp=07886f4aa0503feebde1d29d80e57774125f5df9;hpb=093e3d311cce006ccf99531fb0c6b5d64d691be9;p=cparser diff --git a/parser.c b/parser.c index 07886f4..1686f34 100644 --- a/parser.c +++ b/parser.c @@ -114,7 +114,7 @@ static declaration_t **incomplete_arrays; #define POP_PARENT ((void)(current_parent = prev_parent)) /** special symbol used for anonymous entities. */ -static const symbol_t *sym_anonymous = NULL; +static symbol_t *sym_anonymous = NULL; /** The token anchor set */ static unsigned char token_anchor_set[T_LAST_TOKEN]; @@ -796,7 +796,7 @@ static entity_t *get_entity(const symbol_t *const symbol, /* §6.2.3:1 24) There is only one name space for tags even though three are * possible. */ static entity_t *get_tag(symbol_t const *const symbol, - entity_kind_tag_t const kind) + entity_kind_tag_t const kind) { entity_t *entity = get_entity(symbol, NAMESPACE_TAG); if (entity != NULL && entity->kind != kind) { @@ -1840,11 +1840,6 @@ static initializer_t *initializer_from_expression(type_t *orig_type, &expression->base.source_position); initializer_t *const result = allocate_initializer_zero(INITIALIZER_VALUE); -#if 0 - if (type->kind == TYPE_BITFIELD) { - type = type->bitfield.base_type; - } -#endif result->value.value = create_implicit_cast(expression, type); return result; @@ -1882,7 +1877,7 @@ static initializer_t *parse_scalar_initializer(type_t *type, mark_vars_read(expression, NULL); if (must_be_constant && !is_initializer_constant(expression)) { errorf(&expression->base.source_position, - "Initialisation expression '%E' is not constant", + "initialisation expression '%E' is not constant", expression); } @@ -2382,10 +2377,10 @@ finish_designator: error_excess: if (warning.other) { if (env->entity != NULL) { - warningf(HERE, "excess elements in struct initializer for '%Y'", - env->entity->base.symbol); + warningf(HERE, "excess elements in initializer for '%Y'", + env->entity->base.symbol); } else { - warningf(HERE, "excess elements in struct initializer"); + warningf(HERE, "excess elements in initializer"); } } } @@ -4163,7 +4158,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, storage_class_t storage_class = specifiers->storage_class; entity->declaration.declared_storage_class = storage_class; - if (storage_class == STORAGE_CLASS_NONE && current_scope != file_scope) + if (storage_class == STORAGE_CLASS_NONE && current_function != NULL) storage_class = STORAGE_CLASS_AUTO; entity->declaration.storage_class = storage_class; } @@ -4766,10 +4761,6 @@ static void parse_kr_declaration_list(entity_t *entity) if (!type->function.kr_style_parameters) return; - entity_t *proto_type = get_entity(entity->base.symbol, NAMESPACE_NORMAL); - if (proto_type != NULL && proto_type->kind != ENTITY_FUNCTION) - proto_type = NULL; - add_anchor_token('{'); /* push function parameters */ @@ -4811,8 +4802,30 @@ decl_list_end: function_parameter_t *parameters = NULL; function_parameter_t **anchor = ¶meters; + /* did we have an earlier prototype? */ + entity_t *proto_type = get_entity(entity->base.symbol, NAMESPACE_NORMAL); + if (proto_type != NULL && proto_type->kind != ENTITY_FUNCTION) + proto_type = NULL; + + function_parameter_t *proto_parameter = NULL; + if (proto_type != NULL) { + type_t *proto_type_type = proto_type->declaration.type; + proto_parameter = proto_type_type->function.parameters; + /* If a K&R function definition has a variadic prototype earlier, then + * make the function definition variadic, too. This should conform to + * §6.7.5.3:15 and §6.9.1:8. */ + new_type->function.variadic = proto_type_type->function.variadic; + } else { + /* §6.9.1.7: A K&R style parameter list does NOT act as a function + * prototype */ + new_type->function.unspecified_parameters = true; + } + + bool need_incompatible_warning = false; parameter = entity->function.parameters.entities; - for (; parameter != NULL; parameter = parameter->base.next) { + for (; parameter != NULL; parameter = parameter->base.next, + proto_parameter = + proto_parameter == NULL ? NULL : proto_parameter->next) { if (parameter->kind != ENTITY_PARAMETER) continue; @@ -4834,31 +4847,42 @@ decl_list_end: semantic_parameter_incomplete(parameter); - /* - * we need the default promoted types for the function type - */ - if (proto_type == NULL) - parameter_type = get_default_promoted_type(parameter_type); - - function_parameter_t *const parameter = - allocate_parameter(parameter_type); + /* we need the default promoted types for the function type */ + type_t *not_promoted = parameter_type; + parameter_type = get_default_promoted_type(parameter_type); + + /* gcc special: if the type of the prototype matches the unpromoted + * type don't promote */ + if (!strict_mode && proto_parameter != NULL) { + type_t *proto_p_type = skip_typeref(proto_parameter->type); + type_t *promo_skip = skip_typeref(parameter_type); + type_t *param_skip = skip_typeref(not_promoted); + if (!types_compatible(proto_p_type, promo_skip) + && types_compatible(proto_p_type, param_skip)) { + /* don't promote */ + need_incompatible_warning = true; + parameter_type = not_promoted; + } + } + function_parameter_t *const parameter + = allocate_parameter(parameter_type); *anchor = parameter; anchor = ¶meter->next; } new_type->function.parameters = parameters; - if (proto_type != NULL) { - /* compatibility with the prototype will be checked later ... */ - new_type->function.prototyped = true; - } else { - /* §6.9.1.7: A K&R style parameter list does NOT act as a function - * prototype */ - new_type->function.unspecified_parameters = true; - } - new_type = identify_new_type(new_type); + if (warning.other && need_incompatible_warning) { + type_t *proto_type_type = proto_type->declaration.type; + warningf(HERE, + "declaration '%#T' is incompatible with '%#T' (declared %P)", + proto_type_type, proto_type->base.symbol, + new_type, entity->base.symbol, + &proto_type->base.source_position); + } + entity->declaration.type = new_type; rem_anchor_token('{'); @@ -5680,8 +5704,7 @@ static void parse_external_declaration(void) /* §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->function.parameters == NULL) { type_t *copy = duplicate_type(type); copy->function.unspecified_parameters = false; type = identify_new_type(copy); @@ -6425,14 +6448,73 @@ type_t *revert_automatic_type_conversion(const expression_t *expression) } } -static expression_t *parse_reference(void) +/** + * Find an entity matching a symbol in a scope. + * Uses current scope if scope is NULL + */ +static entity_t *lookup_entity(const scope_t *scope, symbol_t *symbol, + namespace_tag_t namespc) { - symbol_t *const symbol = token.v.symbol; + if (scope == NULL) { + return get_entity(symbol, namespc); + } - entity_t *entity = get_entity(symbol, NAMESPACE_NORMAL); + /* we should optimize here, if scope grows above a certain size we should + construct a hashmap here... */ + entity_t *entity = scope->entities; + for ( ; entity != NULL; entity = entity->base.next) { + if (entity->base.symbol == symbol && entity->base.namespc == namespc) + break; + } + + return entity; +} + +static entity_t *parse_qualified_identifier(void) +{ + /* namespace containing the symbol */ + symbol_t *symbol; + const scope_t *lookup_scope = NULL; + + if (token.type == T_COLONCOLON) { + next_token(); + lookup_scope = &unit->scope; + } + + entity_t *entity; + while (true) { + if (token.type != T_IDENTIFIER) { + parse_error_expected("while parsing identifier", T_IDENTIFIER, NULL); + return create_error_entity(sym_anonymous, ENTITY_VARIABLE); + } + symbol = token.v.symbol; + next_token(); + + /* lookup entity */ + entity = lookup_entity(lookup_scope, symbol, NAMESPACE_NORMAL); + + if (token.type != T_COLONCOLON) + break; + next_token(); + + switch (entity->kind) { + case ENTITY_NAMESPACE: + lookup_scope = &entity->namespacee.members; + break; + case ENTITY_STRUCT: + case ENTITY_UNION: + case ENTITY_CLASS: + lookup_scope = &entity->compound.members; + break; + default: + errorf(HERE, "'%Y' must be a namespace, class, struct or union (but is a %s)", + symbol, get_entity_kind_name(entity->kind)); + goto end_error; + } + } if (entity == NULL) { - if (!strict_mode && look_ahead(1)->type == '(') { + if (!strict_mode && token.type == '(') { /* an implicitly declared function */ if (warning.error_implicit_function_declaration) { errorf(HERE, "implicit declaration of function '%Y'", symbol); @@ -6447,8 +6529,25 @@ static expression_t *parse_reference(void) } } - type_t *orig_type; + return entity; + +end_error: + /* skip further qualifications */ + while (token.type == T_IDENTIFIER) { + next_token(); + if (token.type != T_COLONCOLON) + break; + next_token(); + } + + return create_error_entity(sym_anonymous, ENTITY_VARIABLE); +} + +static expression_t *parse_reference(void) +{ + entity_t *entity = parse_qualified_identifier(); + type_t *orig_type; if (is_declaration(entity)) { orig_type = entity->declaration.type; } else if (entity->kind == ENTITY_ENUM_VALUE) { @@ -6475,8 +6574,9 @@ static expression_t *parse_reference(void) } if (entity->base.parent_scope != file_scope - && (current_function != NULL && entity->base.parent_scope->depth < current_function->parameters.depth) - && is_type_valid(orig_type) && !is_type_function(orig_type)) { + && (current_function != NULL + && entity->base.parent_scope->depth < current_function->parameters.depth) + && (entity->kind == ENTITY_VARIABLE || entity->kind == ENTITY_PARAMETER)) { if (entity->kind == ENTITY_VARIABLE) { /* access of a variable from an outer function */ entity->variable.address_taken = true; @@ -6495,7 +6595,6 @@ static expression_t *parse_reference(void) entity->declaration.type, entity->base.symbol); } - next_token(); return expression; } @@ -6840,9 +6939,12 @@ static expression_t *parse_va_start(void) expression_t *const expr = parse_assignment_expression(); if (expr->kind == EXPR_REFERENCE) { entity_t *const entity = expr->reference.entity; - if (entity->base.parent_scope != ¤t_function->parameters - || entity->base.next != NULL - || entity->kind != ENTITY_PARAMETER) { + if (!current_function->base.type->function.variadic) { + errorf(&expr->base.source_position, + "'va_start' used in non-variadic function"); + } else if (entity->base.parent_scope != ¤t_function->parameters || + entity->base.next != NULL || + entity->kind != ENTITY_PARAMETER) { errorf(&expr->base.source_position, "second argument of 'va_start' must be last parameter of the current function"); } else { @@ -7177,6 +7279,8 @@ static expression_t *parse_primary_expression(void) case T___noop: return parse_noop_expression(); /* Gracefully handle type names while parsing expressions. */ + case T_COLONCOLON: + return parse_reference(); case T_IDENTIFIER: if (!is_typedef_symbol(token.v.symbol)) { return parse_reference();