#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];
/* §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) {
&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;
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);
}
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");
}
}
}
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;
}
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 */
}
}
-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);
}
}
- 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) {
}
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;
entity->declaration.type, entity->base.symbol);
}
- next_token();
return expression;
}
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 {
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();