Rework compound type handling:
authorMatthias Braun <matze@braunis.de>
Sun, 8 Mar 2009 16:19:00 +0000 (16:19 +0000)
committerMatthias Braun <matze@braunis.de>
Sun, 8 Mar 2009 16:19:00 +0000 (16:19 +0000)
- type layout is calculated completely in parser.c now. No more code duplication  in ast2firm.c
- anonymous structs/unions are not flattened anymore, but implicit select
  expressions are created

[r25637]

TODO
ast2firm.c
ast_t.h
entity_t.h
lang_features.h
parser.c

diff --git a/TODO b/TODO
index 9446615..961121d 100644 (file)
--- a/TODO
+++ b/TODO
@@ -22,8 +22,6 @@ Parser:
 
 ast2firm:
 - output source file positions for panics.
-- handle bitfield members with 0 correctly (standard says they finish the
-  current unit)
 
 Missing Errors:
 - goto over VLA declarations
index 99fdca0..222965c 100644 (file)
@@ -563,13 +563,8 @@ enum {
 
 /**
  * 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;
@@ -578,38 +573,29 @@ static ir_type *create_compound_type(compound_type_t *type, ir_type *irtype,
                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;
 
@@ -620,128 +606,37 @@ static ir_type *create_compound_type(compound_type_t *type, ir_type *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;
 }
@@ -792,11 +687,9 @@ static ir_type *get_ir_type_incomplete(type_t *type)
 
        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);
        }
@@ -841,12 +734,10 @@ ir_type *get_ir_type(type_t *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);
diff --git a/ast_t.h b/ast_t.h
index 7a08c2a..ed0e0f9 100644 (file)
--- a/ast_t.h
+++ b/ast_t.h
@@ -233,9 +233,9 @@ struct expression_base_t {
        expression_kind_t   kind;            /**< The expression kind. */
        type_t             *type;            /**< The type of the expression. */
        source_position_t   source_position; /**< The source position of this expression. */
-       bool                parenthesized;
+       bool                parenthesized : 1;
 #ifndef NDEBUG
-       bool                transformed;     /**< Set if this expression was transformed. */
+       bool                transformed : 1;     /**< Set if this expression was transformed. */
 #endif
 };
 
@@ -323,6 +323,8 @@ struct select_expression_t {
        expression_base_t  base;
        expression_t      *compound;
        entity_t          *compound_entry;
+       bool               implicit : 1; /**< compiler generated select
+                                             (for anonymous struct/union) */
 };
 
 struct array_access_expression_t {
index 374d283..76ce5e6 100644 (file)
@@ -125,9 +125,9 @@ struct compound_t {
        entity_t         *alias; /* used for name mangling of anonymous types */
        scope_t           members;
        decl_modifiers_t  modifiers;
-       bool              complete            : 1;
-       bool              transparent_union   : 1;
-       bool              packed              : 1;
+       bool              complete          : 1;
+       bool              transparent_union : 1;
+       bool              packed            : 1;
 
        il_alignment_t    alignment;
        il_size_t         size;
@@ -194,13 +194,14 @@ struct declaration_t {
 };
 
 struct compound_member_t {
-       declaration_t    base;
-       bool             read          : 1;
-       bool             address_taken : 1;  /**< Set if the address of this declaration was taken. */
+       declaration_t  base;
+       bool           read          : 1;
+       bool           address_taken : 1;  /**< Set if the address of this declaration was taken. */
+       unsigned short offset;     /**< the offset of this member in the compound */
+       unsigned char  bit_offset; /**< extra bit offset for bitfield members */
 
        /* ast2firm info */
        ir_entity *entity;
-       il_size_t  offset;  /**< The offset of this member inside a compound. */
 };
 
 struct variable_t {
index c024f22..ba21085 100644 (file)
@@ -22,6 +22,8 @@
 
 #include "type.h"
 
+#define BITS_PER_BYTE    8
+
 typedef enum lang_features_t {
        _C89  = 1U << 0,
        _ANSI = 1U << 1,
index 078291d..7321f2d 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -2978,6 +2978,51 @@ static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind)
        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.
@@ -2990,22 +3035,32 @@ static void finish_struct_type(compound_type_t *type)
        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;
 
@@ -3013,8 +3068,15 @@ static void finish_struct_type(compound_type_t *type)
 
                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;
@@ -5884,13 +5946,17 @@ static type_t *make_bitfield_type(type_t *base_type, expression_t *size,
 
        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;
                }
@@ -5909,12 +5975,12 @@ static entity_t *find_compound_entry(compound_t *compound, symbol_t *symbol)
                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;
                }
@@ -5923,6 +5989,98 @@ static entity_t *find_compound_entry(compound_t *compound, symbol_t *symbol)
        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)
 {
@@ -5937,7 +6095,7 @@ static void parse_compound_declarators(compound_t *compound,
                        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) {
@@ -6411,29 +6569,6 @@ type_t *revert_automatic_type_conversion(const expression_t *expression)
        }
 }
 
-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;
@@ -7356,29 +7491,26 @@ static expression_t *parse_alignof(void)
        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);
@@ -7386,58 +7518,41 @@ static expression_t *parse_select_expression(expression_t *compound)
                }
                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,