/**
* Construct firm type from ast struct type.
- *
- * As anonymous inner structs get flattened to a single firm type, we might get
- * irtype, outer_offset and out_align passed (they represent the position of
- * the anonymous inner struct inside the resulting firm struct)
*/
-static ir_type *create_compound_type(compound_type_t *type, ir_type *irtype,
- size_t *outer_offset, size_t *outer_align,
+static ir_type *create_compound_type(compound_type_t *type,
bool incomplete, bool is_union)
{
compound_t *compound = type->compound;
return compound->irtype;
}
- size_t align_all = 1;
- size_t offset = 0;
- size_t bit_offset = 0;
- size_t size = 0;
-
- if (irtype == NULL) {
- symbol_t *symbol = compound->base.symbol;
- ident *id;
- if (symbol != NULL) {
- id = new_id_from_str(symbol->string);
- } else {
- if (is_union) {
- id = id_unique("__anonymous_union.%u");
- } else {
- id = id_unique("__anonymous_struct.%u");
- }
- }
- dbg_info *dbgi = get_dbg_info(&compound->base.source_position);
-
+ symbol_t *symbol = compound->base.symbol;
+ ident *id;
+ if (symbol != NULL) {
+ id = new_id_from_str(symbol->string);
+ } else {
if (is_union) {
- irtype = new_d_type_union(id, dbgi);
+ id = id_unique("__anonymous_union.%u");
} else {
- irtype = new_d_type_struct(id, dbgi);
+ id = id_unique("__anonymous_struct.%u");
}
+ }
+ dbg_info *dbgi = get_dbg_info(&compound->base.source_position);
- compound->irtype_complete = false;
- compound->irtype = irtype;
+ ir_type *irtype;
+ if (is_union) {
+ irtype = new_d_type_union(id, dbgi);
} else {
- offset = *outer_offset;
- align_all = *outer_align;
+ irtype = new_d_type_struct(id, dbgi);
}
+ compound->irtype_complete = false;
+ compound->irtype = irtype;
+
if (incomplete)
return irtype;
if (entry->kind != ENTITY_COMPOUND_MEMBER)
continue;
- size_t prev_offset = offset;
-
symbol_t *symbol = entry->base.symbol;
- type_t *entry_type = skip_typeref(entry->declaration.type);
- dbg_info *dbgi = get_dbg_info(&entry->base.source_position);
-
+ type_t *entry_type = entry->declaration.type;
ident *ident;
- if (symbol != NULL) {
- ident = new_id_from_str(symbol->string);
- } else {
- if (entry_type->kind == TYPE_COMPOUND_STRUCT) {
- create_compound_type(&entry_type->compound, irtype, &offset,
- &align_all, false, COMPOUND_IS_STRUCT);
- goto finished_member;
- } else if (entry_type->kind == TYPE_COMPOUND_UNION) {
- create_compound_type(&entry_type->compound, irtype, &offset,
- &align_all, false, COMPOUND_IS_UNION);
- goto finished_member;
- } else {
- assert(entry_type->kind == TYPE_BITFIELD);
- }
+ if (symbol == NULL) {
+ /* anonymous bitfield member, skip */
+ if (entry_type->kind == TYPE_BITFIELD)
+ continue;
+ assert(entry_type->kind == TYPE_COMPOUND_STRUCT
+ || entry_type->kind == TYPE_COMPOUND_UNION);
ident = id_unique("anon.%u");
- }
-
- ir_type *base_irtype;
- if (entry_type->kind == TYPE_BITFIELD) {
- base_irtype = get_ir_type(entry_type->bitfield.base_type);
} else {
- base_irtype = get_ir_type(entry_type);
+ ident = new_id_from_str(symbol->string);
}
- size_t entry_alignment = get_type_alignment_bytes(base_irtype);
- size_t misalign = offset % entry_alignment;
+ dbg_info *dbgi = get_dbg_info(&entry->base.source_position);
ir_type *entry_irtype = get_ir_type(entry_type);
ir_entity *entity = new_d_entity(irtype, ident, entry_irtype, dbgi);
- size_t base;
- size_t bits_remainder;
- if (entry_type->kind == TYPE_BITFIELD) {
- size_t size_bits = entry_type->bitfield.bit_size;
- size_t rest_size_bits = (entry_alignment - misalign)*8 - bit_offset;
-
- if (size_bits > rest_size_bits) {
- /* start a new bucket */
- offset += entry_alignment - misalign;
- bit_offset = 0;
-
- base = offset;
- bits_remainder = 0;
- } else {
- /* put into current bucket */
- base = offset - misalign;
- bits_remainder = misalign * 8 + bit_offset;
- }
-
- offset += size_bits / 8;
- bit_offset = bit_offset + (size_bits % 8);
- } else {
- size_t entry_size = get_type_size_bytes(base_irtype);
- if (misalign > 0 || bit_offset > 0)
- offset += entry_alignment - misalign;
-
- base = offset;
- bits_remainder = 0;
- offset += entry_size;
- bit_offset = 0;
- }
-
- if (entry_alignment > align_all) {
- if (entry_alignment % align_all != 0) {
- panic("uneven alignments not supported yet");
- }
- align_all = entry_alignment;
- }
-
- set_entity_offset(entity, base);
+ set_entity_offset(entity, entry->compound_member.offset);
set_entity_offset_bits_remainder(entity,
- (unsigned char) bits_remainder);
- //add_struct_member(irtype, entity);
- entry->declaration.kind = DECLARATION_KIND_COMPOUND_MEMBER;
- assert(entry->compound_member.entity == NULL);
- entry->compound_member.entity = entity;
-
-finished_member:
- if (is_union) {
- size_t entry_size = offset - prev_offset;
- if (entry_size > size) {
- size = entry_size;
- }
- offset = 0;
- bit_offset = 0;
- }
- }
-
- if (!is_union) {
- size = offset;
- }
+ entry->compound_member.bit_offset);
- size_t misalign = offset % align_all;
- if (misalign > 0 || bit_offset > 0) {
- size += align_all - misalign;
+ assert(entry->declaration.kind == DECLARATION_KIND_UNKNOWN);
+ entry->declaration.kind = DECLARATION_KIND_COMPOUND_MEMBER;
+ entry->compound_member.entity = entity;
}
- if (outer_offset != NULL) {
- if (!is_union) {
- *outer_offset = offset;
- } else {
- *outer_offset += size;
- }
-
- if (align_all > *outer_align) {
- if (align_all % *outer_align != 0) {
- panic("uneven alignments not supported yet");
- }
- *outer_align = align_all;
- }
- } else {
- set_type_alignment_bytes(irtype, align_all);
- set_type_size_bytes(irtype, size);
- set_type_state(irtype, layout_fixed);
- }
+ set_type_alignment_bytes(irtype, compound->alignment);
+ set_type_size_bytes(irtype, compound->size);
+ set_type_state(irtype, layout_fixed);
return irtype;
}
switch (type->kind) {
case TYPE_COMPOUND_STRUCT:
- return create_compound_type(&type->compound, NULL, NULL, NULL,
- true, COMPOUND_IS_STRUCT);
+ return create_compound_type(&type->compound, true, COMPOUND_IS_STRUCT);
case TYPE_COMPOUND_UNION:
- return create_compound_type(&type->compound, NULL, NULL, NULL,
- true, COMPOUND_IS_UNION);
+ return create_compound_type(&type->compound, true, COMPOUND_IS_UNION);
default:
return get_ir_type(type);
}
firm_type = create_array_type(&type->array);
break;
case TYPE_COMPOUND_STRUCT:
- firm_type = create_compound_type(&type->compound, NULL, NULL, NULL,
- false, COMPOUND_IS_STRUCT);
+ firm_type = create_compound_type(&type->compound, false, COMPOUND_IS_STRUCT);
break;
case TYPE_COMPOUND_UNION:
- firm_type = create_compound_type(&type->compound, NULL, NULL, NULL,
- false, COMPOUND_IS_UNION);
+ firm_type = create_compound_type(&type->compound, false, COMPOUND_IS_UNION);
break;
case TYPE_ENUM:
firm_type = create_enum_type(&type->enumt);
return entity;
}
+static entity_t *pack_bitfield_members(il_size_t *size, type_t *type,
+ size_t offset, entity_t *first)
+{
+ /* TODO: packed handling */
+ type_t *base_type = skip_typeref(type->bitfield.base_type);
+ size_t remaining_bits = get_type_size(base_type) * BITS_PER_BYTE;
+ size_t bit_offset = 0;
+
+ entity_t *member;
+ for (member = first; member != NULL; member = member->base.next) {
+ /* TODO: make this an assert */
+ if (member->kind != ENTITY_COMPOUND_MEMBER)
+ continue;
+
+ type_t *member_type = member->declaration.type;
+ if (member_type->kind != TYPE_BITFIELD)
+ break;
+ if (base_type != NULL
+ && skip_typeref(member_type->bitfield.base_type) != base_type)
+ break;
+
+ size_t bit_size = member_type->bitfield.bit_size;
+ if (bit_size > remaining_bits)
+ break;
+
+ member->compound_member.offset = offset;
+ member->compound_member.bit_offset = bit_offset;
+
+ bit_offset += bit_size;
+
+ /* 0-size members end current bucket. multiple 0-size buckets
+ * seem to not start-end multiple buckets */
+ if (bit_size == 0) {
+ remaining_bits = 0;
+ } else {
+ remaining_bits -= bit_size;
+ }
+ }
+ assert(member != first);
+
+ *size += (bit_offset + (BITS_PER_BYTE-1)) / BITS_PER_BYTE;
+
+ return member;
+}
+
/**
* Finish the construction of a struct type by calculating its size, offsets,
* alignment.
if (!compound->complete)
return;
- il_size_t size = 0;
il_size_t offset;
+ il_size_t size = 0;
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)
+ while (entry != NULL) {
+ if (entry->kind != ENTITY_COMPOUND_MEMBER) {
+ entry = entry->base.next;
continue;
+ }
- type_t *m_type = entry->declaration.type;
- if (! is_type_valid(skip_typeref(m_type))) {
- /* simply ignore errors here */
+ type_t *m_type = entry->declaration.type;
+ type_t *skipped = skip_typeref(m_type);
+ if (! is_type_valid(skipped)) {
+ entry = entry->base.next;
continue;
}
- il_alignment_t m_alignment = get_type_alignment(m_type);
+
+ type_t *base_type = m_type;
+ if (skipped->kind == TYPE_BITFIELD) {
+ base_type = m_type->bitfield.base_type;
+ }
+
+ il_alignment_t m_alignment = get_type_alignment(base_type);
+ il_size_t m_size = get_type_size(base_type);
if (m_alignment > alignment)
alignment = m_alignment;
if (offset > size)
need_pad = true;
- entry->compound_member.offset = offset;
- size = offset + get_type_size(m_type);
+
+ if (skipped->kind == TYPE_BITFIELD) {
+ entry = pack_bitfield_members(&size, m_type, offset, entry);
+ } else {
+ entry->compound_member.offset = offset;
+ size = offset + m_size;
+
+ entry = entry->base.next;
+ }
}
offset = (size + alignment - 1) & -alignment;
if (is_constant_expression(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) {
}
}
-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 *parse_reference(void)
{
symbol_t *const symbol = token.v.symbol;
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 (type_left->kind != TYPE_COMPOUND_STRUCT &&
+ type_left->kind != TYPE_COMPOUND_UNION) {
- if (!compound->complete) {
- errorf(HERE, "request for member '%Y' of incomplete type '%T'",
- symbol, type_left);
- goto create_error_entry;
- }
-
- 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,