/*
* This file is part of cparser.
- * Copyright (C) 2007-2008 Matthias Braun <matze@braunis.de>
+ * Copyright (C) 2007-2009 Matthias Braun <matze@braunis.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
#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) {
return
is_type_integer(type) &&
is_constant_expression(expression) &&
- fold_constant(expression) == 0;
+ !fold_constant_to_bool(expression);
}
/**
{
switch(token.type) {
case T_IDENTIFIER:
+ return token.v.symbol;
case T_auto:
case T_char:
case T_double:
case T_volatile:
case T_inline:
/* maybe we need more tokens ... add them on demand */
- return token.v.symbol;
+ return get_token_symbol(&token);
default:
return NULL;
}
&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);
}
goto failed;
}
- long index = fold_constant(array_index);
+ long index = fold_constant_to_int(array_index);
if (!used_in_offsetof) {
if (index < 0) {
errorf(&designator->source_position,
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");
}
}
}
eat(T_union);
}
- symbol_t *symbol = NULL;
- compound_t *compound = NULL;
+ symbol_t *symbol = NULL;
+ compound_t *compound = NULL;
+ attribute_t *attributes = NULL;
if (token.type == T___attribute__) {
- parse_attributes(NULL);
+ attributes = parse_attributes(NULL);
}
entity_kind_tag_t const kind = is_struct ? ENTITY_STRUCT : ENTITY_UNION;
entity_t *entity = allocate_entity_zero(kind);
compound = &entity->compound;
+ compound->alignment = 1;
compound->base.namespc = NAMESPACE_TAG;
compound->base.source_position = token.source_position;
compound->base.symbol = symbol;
if (token.type == '{') {
parse_compound_type_entries(compound);
- parse_attributes(NULL);
/* ISO/IEC 14882:1998(E) §7.1.3:5 */
if (symbol == NULL) {
}
}
+ if (attributes != NULL) {
+ handle_entity_attributes(attributes, (entity_t*) compound);
+ }
+
return compound;
}
return entity;
}
-/**
- * Finish the construction of a struct type by calculating its size, offsets,
- * alignment.
- */
-static void finish_struct_type(compound_type_t *type)
-{
- assert(type->compound != NULL);
-
- compound_t *compound = type->compound;
- if (!compound->complete)
- return;
-
- il_size_t size = 0;
- il_size_t offset;
- il_alignment_t alignment = compound->alignment;
- bool need_pad = false;
-
- entity_t *entry = compound->members.entities;
- for (; entry != NULL; entry = entry->base.next) {
- if (entry->kind != ENTITY_COMPOUND_MEMBER)
- continue;
-
- type_t *m_type = entry->declaration.type;
- if (! is_type_valid(skip_typeref(m_type))) {
- /* simply ignore errors here */
- continue;
- }
- il_alignment_t m_alignment = get_type_alignment(m_type);
- if (m_alignment > alignment)
- alignment = m_alignment;
-
- offset = (size + m_alignment - 1) & -m_alignment;
-
- if (offset > size)
- need_pad = true;
- entry->compound_member.offset = offset;
- size = offset + get_type_size(m_type);
- }
-
- offset = (size + alignment - 1) & -alignment;
- if (offset > size)
- need_pad = true;
-
- if (need_pad) {
- if (warning.padded) {
- warningf(&compound->base.source_position, "'%T' needs padding",
- type);
- }
- } else if (compound->packed && warning.packed) {
- warningf(&compound->base.source_position,
- "superfluous packed attribute on '%T'", type);
- }
-
- compound->size = offset;
- compound->alignment = alignment;
-}
-
-/**
- * Finish the construction of an union type by calculating
- * its size and alignment.
- */
-static void finish_union_type(compound_type_t *type)
-{
- assert(type->compound != NULL);
-
- compound_t *compound = type->compound;
- if (! compound->complete)
- return;
-
- il_size_t size = 0;
- il_alignment_t alignment = compound->alignment;
-
- entity_t *entry = compound->members.entities;
- for (; entry != NULL; entry = entry->base.next) {
- if (entry->kind != ENTITY_COMPOUND_MEMBER)
- continue;
-
- type_t *m_type = entry->declaration.type;
- if (! is_type_valid(skip_typeref(m_type)))
- continue;
-
- entry->compound_member.offset = 0;
- il_size_t m_size = get_type_size(m_type);
- if (m_size > size)
- size = m_size;
- il_alignment_t m_alignment = get_type_alignment(m_type);
- if (m_alignment > alignment)
- alignment = m_alignment;
- }
- size = (size + alignment - 1) & -alignment;
-
- compound->size = size;
- compound->alignment = alignment;
-}
-
static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
{
type_t *type = NULL;
type = allocate_type_zero(TYPE_COMPOUND_STRUCT);
type->compound.compound = parse_compound_type_specifier(true);
- finish_struct_type(&type->compound);
break;
case T_union:
CHECK_DOUBLE_TYPE();
type = allocate_type_zero(TYPE_COMPOUND_UNION);
type->compound.compound = parse_compound_type_specifier(false);
- finish_union_type(&type->compound);
break;
case T_enum:
CHECK_DOUBLE_TYPE();
!is_typedef_symbol(token.v.symbol)) {
token_type_t la1_type = (token_type_t)look_ahead(1)->type;
if (la1_type == ',' || la1_type == ')') {
- type->kr_style_parameters = true;
- type->unspecified_parameters = true;
+ type->kr_style_parameters = true;
parse_identifier_list(scope);
goto parameters_finished;
}
type_t *type = allocate_type_zero(TYPE_FUNCTION);
function_type_t *ftype = &type->function;
- ftype->linkage = current_linkage;
-
-#if 0
- switch (modifiers & (DM_CDECL | DM_STDCALL | DM_FASTCALL | DM_THISCALL)) {
- case DM_NONE: break;
- case DM_CDECL: ftype->calling_convention = CC_CDECL; break;
- case DM_STDCALL: ftype->calling_convention = CC_STDCALL; break;
- case DM_FASTCALL: ftype->calling_convention = CC_FASTCALL; break;
- case DM_THISCALL: ftype->calling_convention = CC_THISCALL; break;
-
- default:
- errorf(HERE, "multiple calling conventions in declaration");
- break;
- }
-#endif
+ ftype->linkage = current_linkage;
+ ftype->calling_convention = CC_DEFAULT;
parse_parameters(ftype, scope);
if (size_expression != NULL) {
if (is_constant_expression(size_expression)) {
- long const size = fold_constant(size_expression);
+ long const size
+ = fold_constant_to_int(size_expression);
array_type->array.size = size;
array_type->array.size_constant = true;
/* §6.7.5.2:1 If the expression is a constant expression, it shall
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;
}
* @param decl the declaration to check
* @param type the function type of the declaration
*/
-static void check_type_of_main(const entity_t *entity)
+static void check_main(const entity_t *entity)
{
const source_position_t *pos = &entity->base.source_position;
if (entity->kind != ENTITY_FUNCTION) {
if (warning.main && current_scope == file_scope
&& is_sym_main(symbol)) {
- check_type_of_main(entity);
+ check_main(entity);
}
}
&previous_entity->base.source_position);
} else {
unsigned old_storage_class = prev_decl->storage_class;
+
if (warning.redundant_decls &&
is_definition &&
!prev_decl->used &&
if (!type->function.kr_style_parameters)
return;
-
add_anchor_token('{');
/* push function parameters */
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;
semantic_parameter_incomplete(parameter);
- /*
- * we need the default promoted types for the function type
- */
- 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;
}
- /* §6.9.1.7: A K&R style parameter list does NOT act as a function
- * prototype */
- new_type->function.parameters = parameters;
- new_type->function.unspecified_parameters = true;
-
+ new_type->function.parameters = parameters;
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('{');
{
return
!is_constant_expression(cond) ? 0 :
- fold_constant(cond) != 0 ? 1 :
+ fold_constant_to_bool(cond) ? 1 :
-1;
}
return;
if (is_constant_expression(expr)) {
- long const val = fold_constant(expr);
+ long const val = fold_constant_to_int(expr);
case_label_statement_t * defaults = NULL;
for (case_label_statement_t *i = switchs->first_case; i != NULL; i = i->next) {
if (i->expression == NULL) {
/* §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);
}
if (is_constant_expression(size)) {
- long v = fold_constant(size);
+ long v = fold_constant_to_int(size);
+ const symbol_t *user_symbol = symbol == NULL ? sym_anonymous : symbol;
if (v < 0) {
- errorf(source_position, "negative width in bit-field '%Y'", symbol);
- } else if (v == 0) {
- errorf(source_position, "zero width for bit-field '%Y'", symbol);
+ errorf(source_position, "negative width in bit-field '%Y'",
+ user_symbol);
+ } else if (v == 0 && symbol != NULL) {
+ errorf(source_position, "zero width for bit-field '%Y'",
+ user_symbol);
} else if (bit_size > 0 && (il_size_t)v > bit_size) {
- errorf(source_position, "width of '%Y' exceeds its type", symbol);
+ errorf(source_position, "width of '%Y' exceeds its type",
+ user_symbol);
} else {
type->bitfield.bit_size = v;
}
if (iter->base.symbol == symbol) {
return iter;
} else if (iter->base.symbol == NULL) {
+ /* search in anonymous structs and unions */
type_t *type = skip_typeref(iter->declaration.type);
if (is_type_compound(type)) {
- entity_t *result
- = find_compound_entry(type->compound.compound, symbol);
- if (result != NULL)
- return result;
+ if (find_compound_entry(type->compound.compound, symbol)
+ != NULL)
+ return iter;
}
continue;
}
return NULL;
}
+static void check_deprecated(const source_position_t *source_position,
+ const entity_t *entity)
+{
+ if (!warning.deprecated_declarations)
+ return;
+ if (!is_declaration(entity))
+ return;
+ if ((entity->declaration.modifiers & DM_DEPRECATED) == 0)
+ return;
+
+ char const *const prefix = get_entity_kind_name(entity->kind);
+ const char *deprecated_string
+ = get_deprecated_string(entity->declaration.attributes);
+ if (deprecated_string != NULL) {
+ warningf(source_position, "%s '%Y' is deprecated (declared %P): \"%s\"",
+ prefix, entity->base.symbol, &entity->base.source_position,
+ deprecated_string);
+ } else {
+ warningf(source_position, "%s '%Y' is deprecated (declared %P)", prefix,
+ entity->base.symbol, &entity->base.source_position);
+ }
+}
+
+
+static expression_t *create_select(const source_position_t *pos,
+ expression_t *addr,
+ type_qualifiers_t qualifiers,
+ entity_t *entry)
+{
+ assert(entry->kind == ENTITY_COMPOUND_MEMBER);
+
+ check_deprecated(pos, entry);
+
+ expression_t *select = allocate_expression_zero(EXPR_SELECT);
+ select->select.compound = addr;
+ select->select.compound_entry = entry;
+
+ type_t *entry_type = entry->declaration.type;
+ type_t *res_type = get_qualified_type(entry_type, qualifiers);
+
+ /* we always do the auto-type conversions; the & and sizeof parser contains
+ * code to revert this! */
+ select->base.type = automatic_type_conversion(res_type);
+ if (res_type->kind == TYPE_BITFIELD) {
+ select->base.type = res_type->bitfield.base_type;
+ }
+
+ return select;
+}
+
+/**
+ * Find entry with symbol in compound. Search anonymous structs and unions and
+ * creates implicit select expressions for them.
+ * Returns the adress for the innermost compound.
+ */
+static expression_t *find_create_select(const source_position_t *pos,
+ expression_t *addr,
+ type_qualifiers_t qualifiers,
+ compound_t *compound, symbol_t *symbol)
+{
+ entity_t *iter = compound->members.entities;
+ for (; iter != NULL; iter = iter->base.next) {
+ if (iter->kind != ENTITY_COMPOUND_MEMBER)
+ continue;
+
+ symbol_t *iter_symbol = iter->base.symbol;
+ if (iter_symbol == NULL) {
+ type_t *type = iter->declaration.type;
+ if (type->kind != TYPE_COMPOUND_STRUCT
+ && type->kind != TYPE_COMPOUND_UNION)
+ continue;
+
+ compound_t *sub_compound = type->compound.compound;
+
+ if (find_compound_entry(sub_compound, symbol) == NULL)
+ continue;
+
+ expression_t *sub_addr = create_select(pos, addr, qualifiers, iter);
+ sub_addr->base.source_position = *pos;
+ sub_addr->select.implicit = true;
+ return find_create_select(pos, sub_addr, qualifiers, sub_compound,
+ symbol);
+ }
+
+ if (iter_symbol == symbol) {
+ return create_select(pos, addr, qualifiers, iter);
+ }
+ }
+
+ return NULL;
+}
+
static void parse_compound_declarators(compound_t *compound,
const declaration_specifiers_t *specifiers)
{
expression_t *size = parse_constant_expression();
type_t *type = make_bitfield_type(base_type, size,
- &source_position, sym_anonymous);
+ &source_position, NULL);
attribute_t *attributes = parse_attributes(NULL);
if (attributes != NULL) {
entity->base.symbol = symbol;
entity->base.source_position = *source_position;
- bool strict_prototypes_old = warning.strict_prototypes;
- warning.strict_prototypes = false;
- record_entity(entity, false);
- warning.strict_prototypes = strict_prototypes_old;
+ if (current_scope != NULL) {
+ bool strict_prototypes_old = warning.strict_prototypes;
+ warning.strict_prototypes = false;
+ record_entity(entity, false);
+ warning.strict_prototypes = strict_prototypes_old;
+ }
return entity;
}
return identify_new_type(type);
}
+/**
+ * Creates a return_type (func)(argument_type, ...) function type if not
+ * already exists.
+ *
+ * @param return_type the return type
+ * @param argument_type the argument type
+ */
static type_t *make_function_1_type_variadic(type_t *return_type, type_t *argument_type)
{
- type_t *res = make_function_1_type(return_type, argument_type);
- res->function.variadic = 1;
- return res;
+ function_parameter_t *const parameter = allocate_parameter(argument_type);
+
+ type_t *type = allocate_type_zero(TYPE_FUNCTION);
+ type->function.return_type = return_type;
+ type->function.parameters = parameter;
+ type->function.variadic = true;
+
+ return identify_new_type(type);
}
/**
}
}
-static void check_deprecated(const source_position_t *source_position,
- const entity_t *entity)
+/**
+ * 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)
{
- if (!warning.deprecated_declarations)
- return;
- if (!is_declaration(entity))
- return;
- if ((entity->declaration.modifiers & DM_DEPRECATED) == 0)
- return;
+ if (scope == NULL) {
+ return get_entity(symbol, namespc);
+ }
- char const *const prefix = get_entity_kind_name(entity->kind);
- const char *deprecated_string
- = get_deprecated_string(entity->declaration.attributes);
- if (deprecated_string != NULL) {
- warningf(source_position, "%s '%Y' is deprecated (declared %P): \"%s\"",
- prefix, entity->base.symbol, &entity->base.source_position,
- deprecated_string);
- } else {
- warningf(source_position, "%s '%Y' is deprecated (declared %P)", prefix,
- entity->base.symbol, &entity->base.source_position);
+ /* 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 expression_t *parse_reference(void)
+static entity_t *parse_qualified_identifier(void)
{
- symbol_t *const symbol = token.v.symbol;
+ /* namespace containing the symbol */
+ symbol_t *symbol;
+ const scope_t *lookup_scope = NULL;
- entity_t *entity = get_entity(symbol, NAMESPACE_NORMAL);
+ 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 {
return create_invalid_expression();
}
-#if 0
-/**
- * Parses a __builtin_expect(, end_error) expression.
- */
-static expression_t *parse_builtin_expect(void, end_error)
-{
- expression_t *expression
- = allocate_expression_zero(EXPR_BINARY_BUILTIN_EXPECT);
-
- eat(T___builtin_expect);
-
- expect('(', end_error);
- expression->binary.left = parse_assignment_expression();
- expect(',', end_error);
- expression->binary.right = parse_constant_expression();
- expect(')', end_error);
-
- expression->base.type = expression->binary.left->base.type;
-
- return expression;
-end_error:
- return create_invalid_expression();
-}
-#endif
-
/**
* Parses a MS assume() expression.
*/
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();
return parse_typeprop(EXPR_ALIGNOF);
}
-static expression_t *parse_select_expression(expression_t *compound)
+static expression_t *parse_select_expression(expression_t *addr)
{
- expression_t *select = allocate_expression_zero(EXPR_SELECT);
- select->select.compound = compound;
-
assert(token.type == '.' || token.type == T_MINUSGREATER);
- bool is_pointer = (token.type == T_MINUSGREATER);
+ bool select_left_arrow = (token.type == T_MINUSGREATER);
next_token();
if (token.type != T_IDENTIFIER) {
parse_error_expected("while parsing select", T_IDENTIFIER, NULL);
- return select;
+ return create_invalid_expression();
}
symbol_t *symbol = token.v.symbol;
next_token();
- type_t *const orig_type = compound->base.type;
+ type_t *const orig_type = addr->base.type;
type_t *const type = skip_typeref(orig_type);
type_t *type_left;
bool saw_error = false;
if (is_type_pointer(type)) {
- if (!is_pointer) {
+ if (!select_left_arrow) {
errorf(HERE,
"request for member '%Y' in something not a struct or union, but '%T'",
symbol, orig_type);
}
type_left = skip_typeref(type->pointer.points_to);
} else {
- if (is_pointer && is_type_valid(type)) {
+ if (select_left_arrow && is_type_valid(type)) {
errorf(HERE, "left hand side of '->' is not a pointer, but '%T'", orig_type);
saw_error = true;
}
type_left = type;
}
- entity_t *entry;
- if (type_left->kind == TYPE_COMPOUND_STRUCT ||
- type_left->kind == TYPE_COMPOUND_UNION) {
- compound_t *compound = type_left->compound.compound;
-
- if (!compound->complete) {
- errorf(HERE, "request for member '%Y' of incomplete type '%T'",
- symbol, type_left);
- goto create_error_entry;
- }
+ if (type_left->kind != TYPE_COMPOUND_STRUCT &&
+ type_left->kind != TYPE_COMPOUND_UNION) {
- entry = find_compound_entry(compound, symbol);
- if (entry == NULL) {
- errorf(HERE, "'%T' has no member named '%Y'", orig_type, symbol);
- goto create_error_entry;
- }
- } else {
if (is_type_valid(type_left) && !saw_error) {
errorf(HERE,
"request for member '%Y' in something not a struct or union, but '%T'",
symbol, type_left);
}
-create_error_entry:
- entry = create_error_entity(symbol, ENTITY_COMPOUND_MEMBER);
+ return create_invalid_expression();
}
- assert(is_declaration(entry));
- select->select.compound_entry = entry;
-
- check_deprecated(HERE, entry);
-
- type_t *entry_type = entry->declaration.type;
- type_t *res_type
- = get_qualified_type(entry_type, type_left->base.qualifiers);
+ compound_t *compound = type_left->compound.compound;
+ if (!compound->complete) {
+ errorf(HERE, "request for member '%Y' in incomplete type '%T'",
+ symbol, type_left);
+ return create_invalid_expression();
+ }
- /* we always do the auto-type conversions; the & and sizeof parser contains
- * code to revert this! */
- select->base.type = automatic_type_conversion(res_type);
+ type_qualifiers_t qualifiers = type_left->base.qualifiers;
+ expression_t *result
+ = find_create_select(HERE, addr, qualifiers, compound, symbol);
- type_t *skipped = skip_typeref(res_type);
- if (skipped->kind == TYPE_BITFIELD) {
- select->base.type = skipped->bitfield.base_type;
+ if (result == NULL) {
+ errorf(HERE, "'%T' has no member named '%Y'", orig_type, symbol);
+ return create_invalid_expression();
}
- return select;
+ return result;
}
static void check_call_argument(type_t *expected_type,
/* The type of the right operand can be different for /= */
if (is_type_integer(right->base.type) &&
is_constant_expression(right) &&
- fold_constant(right) == 0) {
+ !fold_constant_to_bool(right)) {
warningf(&expression->base.source_position, "division by zero");
}
}
type_left = promote_integer(type_left);
if (is_constant_expression(right)) {
- long count = fold_constant(right);
+ long count = fold_constant_to_int(right);
if (count < 0) {
warningf(&right->base.source_position,
"shift count must be non-negative");
{
return
!is_constant_expression(expr) ||
- fold_constant(expr) < 0;
+ fold_constant_to_int(expr) < 0;
}
/**
}
statement->case_label.is_bad = true;
} else {
- long const val = fold_constant(expression);
+ long const val = fold_constant_to_int(expression);
statement->case_label.first_case = val;
statement->case_label.last_case = val;
}
}
statement->case_label.is_bad = true;
} else {
- long const val = fold_constant(end_range);
+ long const val = fold_constant_to_int(end_range);
statement->case_label.last_case = val;
if (warning.other && val < statement->case_label.first_case) {
for (; entry != NULL && entry->kind == ENTITY_ENUM_VALUE;
entry = entry->base.next) {
const expression_t *expression = entry->enum_value.value;
- long value = expression != NULL ? fold_constant(expression) : last_value + 1;
+ long value = expression != NULL ? fold_constant_to_int(expression) : last_value + 1;
bool found = false;
for (const case_label_statement_t *l = statement->first_case; l != NULL; l = l->next) {
if (l->expression == NULL)
size_t const top = environment_top();
scope_t *old_scope = scope_push(&statement->fors.scope);
- bool old_gcc_extension;
+ bool old_gcc_extension = in_gcc_extension;
while (token.type == T___extension__) {
next_token();
in_gcc_extension = true;
}
}
+void prepare_main_collect2(entity_t *entity)
+{
+ // create call to __main
+ symbol_t *symbol = symbol_table_insert("__main");
+ entity_t *subsubmain_ent
+ = create_implicit_function(symbol, &builtin_source_position);
+
+ expression_t *ref = allocate_expression_zero(EXPR_REFERENCE);
+ type_t *ftype = subsubmain_ent->declaration.type;
+ ref->base.source_position = builtin_source_position;
+ ref->base.type = make_pointer_type(ftype, TYPE_QUALIFIER_NONE);
+ ref->reference.entity = subsubmain_ent;
+
+ expression_t *call = allocate_expression_zero(EXPR_CALL);
+ call->base.source_position = builtin_source_position;
+ call->base.type = type_void;
+ call->call.function = ref;
+
+ statement_t *expr_statement = allocate_statement_zero(STATEMENT_EXPRESSION);
+ expr_statement->base.source_position = builtin_source_position;
+ expr_statement->expression.expression = call;
+
+ statement_t *statement = entity->function.statement;
+ assert(statement->kind == STATEMENT_COMPOUND);
+ compound_statement_t *compounds = &statement->compound;
+
+ expr_statement->base.next = compounds->statements;
+ compounds->statements = expr_statement;
+}
+
void parse(void)
{
lookahead_bufpos = 0;