- started implementation of size and alignment for types
authorMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Sat, 13 Sep 2008 18:09:19 +0000 (18:09 +0000)
committerMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Sat, 13 Sep 2008 18:09:19 +0000 (18:09 +0000)
- implemented -Wpacked, -Wpadded

[r21929]

ast_t.h
parser.c
type.c
type.h
type_t.h
types.c
warning.c
warning.h

diff --git a/ast_t.h b/ast_t.h
index d014754..508f19a 100644 (file)
--- a/ast_t.h
+++ b/ast_t.h
@@ -546,12 +546,14 @@ struct declaration_t {
        const char         *deprecated_string;  /**< MS deprecated string if any. */
        symbol_t           *get_property_sym;   /**< MS get property. */
        symbol_t           *put_property_sym;   /**< MS put property. */
-       unsigned int        address_taken : 1;
+       unsigned int        address_taken : 1;  /**< Set if the address of this declaration was taken. */
        unsigned int        is_inline     : 1;
        unsigned int        used          : 1;  /**< Set if the declaration is used. */
-       unsigned int        implicit      : 1;
+       unsigned int        implicit      : 1;  /**< Set for implicit (not found in source code) declarations. */
        type_t             *type;
+       il_size_t           offset;             /**< The offset of this member inside a compound. */
        symbol_t           *symbol;
+       string_t           *asm_name;           /**< GCC extension: ASM label. */
        source_position_t   source_position;
        union {
                bool            complete;           /**< used to indicate whether struct/union types are already defined or if just the name is declared */
@@ -655,8 +657,9 @@ struct switch_statement_t {
 
 struct goto_statement_t {
        statement_base_t  base;
-       declaration_t    *label;     /**< The destination label. */
-       goto_statement_t *next;      /**< links all goto statements of a function */
+       declaration_t    *label;      /**< The destination label. */
+       expression_t     *expression; /**< The expression for an assigned goto. */
+       goto_statement_t *next;       /**< links all goto statements of a function */
 };
 
 struct case_label_statement_t {
index ffc742f..c11906c 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -3076,6 +3076,95 @@ static declaration_t *create_error_declaration(symbol_t *symbol, storage_class_t
        return decl;
 }
 
+/**
+ * Finish the construction of a struct type by calculating
+ * its size, offsets, alignment.
+ */
+static void finish_struct_type(compound_type_t *type) {
+       if (type->declaration == NULL)
+               return;
+       declaration_t *struct_decl = type->declaration;
+       if (! struct_decl->init.complete)
+               return;
+
+       il_size_t      size      = 0;
+       il_size_t      new_size;
+       il_alignment_t alignment = 1;
+       bool           need_pad  = false;
+
+       declaration_t *entry = struct_decl->scope.declarations;
+       for (; entry != NULL; entry = entry->next) {
+               if (entry->namespc != NAMESPACE_NORMAL)
+                       continue;
+
+               type_t         *m_type      = skip_typeref(entry->type);
+               il_alignment_t  m_alignment = m_type->base.alignment;
+
+               new_size = (size + m_alignment - 1) & -m_alignment;
+               if (m_alignment > alignment)
+                       alignment = m_alignment;
+               if (new_size > size)
+                       need_pad = true;
+               entry->offset = new_size;
+               size = new_size + m_type->base.size;
+       }
+       if (type->base.alignment != 0) {
+               alignment = type->base.alignment;
+       }
+
+       new_size = (size + alignment - 1) & -alignment;
+       if (new_size > size)
+               need_pad = true;
+
+       if (warning.padded && need_pad) {
+               warningf(&struct_decl->source_position,
+                       "'%#T' needs padding", type, struct_decl->symbol);
+       }
+       if (warning.packed && !need_pad) {
+               warningf(&struct_decl->source_position,
+                       "superfluous packed attribute on '%#T'",
+                       type, struct_decl->symbol);
+       }
+
+       type->base.size      = new_size;
+       type->base.alignment = alignment;
+}
+
+/**
+ * Finish the construction of an union type by calculating
+ * its size and alignment.
+ */
+static void finish_union_type(compound_type_t *type) {
+       if (type->declaration == NULL)
+               return;
+       declaration_t *union_decl = type->declaration;
+       if (! union_decl->init.complete)
+               return;
+
+       il_size_t      size      = 0;
+       il_alignment_t alignment = 1;
+
+       declaration_t *entry = union_decl->scope.declarations;
+       for (; entry != NULL; entry = entry->next) {
+               if (entry->namespc != NAMESPACE_NORMAL)
+                       continue;
+
+               type_t *m_type = skip_typeref(entry->type);
+
+               entry->offset = 0;
+               if (m_type->base.size > size)
+                       size = m_type->base.size;
+               if (m_type->base.alignment > alignment)
+                       alignment = m_type->base.alignment;
+       }
+       if (type->base.alignment != 0) {
+               alignment = type->base.alignment;
+       }
+       size = (size + alignment - 1) & -alignment;
+       type->base.size      = size;
+       type->base.alignment = alignment;
+}
+
 static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
 {
        type_t            *type            = NULL;
@@ -3215,6 +3304,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                        type = allocate_type_zero(TYPE_COMPOUND_STRUCT, HERE);
 
                        type->compound.declaration = parse_compound_type_specifier(true);
+                       finish_struct_type(&type->compound);
                        break;
                }
                case T_union: {
@@ -3223,6 +3313,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                        if (type->compound.declaration->modifiers & DM_TRANSPARENT_UNION)
                                modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
                        break;
+                       finish_union_type(&type->compound);
                }
                case T_enum:
                        type = parse_enum_specifier();
@@ -5404,12 +5495,12 @@ static void parse_compound_declarators(declaration_t *struct_declaration,
 {
        declaration_t *last_declaration = struct_declaration->scope.declarations;
        if (last_declaration != NULL) {
-               while(last_declaration->next != NULL) {
+               while (last_declaration->next != NULL) {
                        last_declaration = last_declaration->next;
                }
        }
 
-       while(1) {
+       while (true) {
                declaration_t *declaration;
 
                if (token.type == ':') {
@@ -5502,7 +5593,7 @@ static void parse_compound_type_entries(declaration_t *compound_declaration)
        eat('{');
        add_anchor_token('}');
 
-       while(token.type != '}' && token.type != T_EOF) {
+       while (token.type != '}' && token.type != T_EOF) {
                declaration_specifiers_t specifiers;
                memset(&specifiers, 0, sizeof(specifiers));
                parse_declaration_specifiers(&specifiers);
diff --git a/type.c b/type.c
index 2a9aba5..085a6b9 100644 (file)
--- a/type.c
+++ b/type.c
@@ -1089,7 +1089,7 @@ bool types_compatible(const type_t *type1, const type_t *type2)
        if (type1->kind != type2->kind)
                return false;
 
-       switch(type1->kind) {
+       switch (type1->kind) {
        case TYPE_FUNCTION:
                return function_types_compatible(&type1->function, &type2->function);
        case TYPE_ATOMIC:
@@ -1141,8 +1141,8 @@ type_t *skip_typeref(type_t *type)
        type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE;
        type_modifiers_t  modifiers  = TYPE_MODIFIER_NONE;
 
-       while(true) {
-               switch(type->kind) {
+       while (true) {
+               switch (type->kind) {
                case TYPE_ERROR:
                        return type;
                case TYPE_TYPEDEF: {
@@ -1313,8 +1313,9 @@ type_t *make_atomic_type(atomic_type_kind_t akind, type_qualifiers_t qualifiers)
        memset(type, 0, sizeof(atomic_type_t));
 
        type->kind            = TYPE_ATOMIC;
-       type->base.qualifiers = qualifiers;
+       type->base.size       = get_atomic_type_size(akind);
        type->base.alignment  = get_atomic_type_alignment(akind);
+       type->base.qualifiers = qualifiers;
        type->atomic.akind    = akind;
 
        return identify_new_type(type);
diff --git a/type.h b/type.h
index 2dba894..92baa7d 100644 (file)
--- a/type.h
+++ b/type.h
 #include "ast.h"
 #include "symbol.h"
 
+/** Type used to express sizes. */
+typedef unsigned long il_size_t;
+typedef unsigned char il_alignment_t;
+
 /* note that the constant values represent the rank of the types as defined
  * in ยง 6.3.1 */
 typedef enum atomic_type_kind_t {
index 4df727e..ec5b9a2 100644 (file)
--- a/type_t.h
+++ b/type_t.h
@@ -59,10 +59,11 @@ typedef unsigned short type_modifiers_t;
 
 struct type_base_t {
        type_kind_t       kind;
+       source_position_t source_position;
+       il_size_t         size;           /**< The size of this type. */
        type_qualifiers_t qualifiers;
        type_modifiers_t  modifiers;
-       unsigned char     alignment;      /**< The extra alignment of the type, 0 for default. */
-       source_position_t source_position;
+       il_alignment_t    alignment;      /**< The extra alignment of the type, 0 for default. */
 
        ir_type          *firm_type;
 };
diff --git a/types.c b/types.c
index 1f06895..82bdd0b 100644 (file)
--- a/types.c
+++ b/types.c
@@ -91,9 +91,8 @@ type_t *type_unsigned_int64;
 
 void init_basic_types(void)
 {
-       static const type_base_t error = { TYPE_ERROR, TYPE_QUALIFIER_NONE,
-                                          TYPE_MODIFIER_NONE, 0, { NULL, 0 },
-                                          NULL };
+       static const type_base_t error = { TYPE_ERROR, { NULL, 0 }, 0, TYPE_QUALIFIER_NONE,
+                                          TYPE_MODIFIER_NONE, 0, NULL };
 
        type_error_type         = (type_t*)&error;
        type_signed_char        = make_atomic_type(ATOMIC_TYPE_SCHAR,       TYPE_QUALIFIER_NONE);
index e695a89..954d2fc 100644 (file)
--- a/warning.c
+++ b/warning.c
@@ -47,6 +47,8 @@ warning_t warning = {
        .nested_externs                = false,
        .nonnull                       = true,
        .old_style_definition          = false,
+       .packed                        = false,
+       .padded                        = false,
        .pointer_arith                 = true,
        .redundant_decls               = true,
        .return_type                   = true,
@@ -153,6 +155,8 @@ void set_warning_opt(const char *const opt)
        OPT("nested-externs",                nested_externs);
        OPT("nonnull",                       nonnull);
        OPT("old-style-definition",          old_style_definition);
+       OPT("packed",                        packed);
+       OPT("padded",                        padded);
        OPT("pointer_arith",                 pointer_arith);
        OPT("redundant-decls",               redundant_decls);
        OPT("return-type",                   return_type);
index 5ce30b9..4cacecf 100644 (file)
--- a/warning.h
+++ b/warning.h
@@ -71,9 +71,9 @@ typedef struct warning_t {
        bool nested_externs:1;                /**< Warn if an 'extern' declaration is encountered within a function. */
        bool nonnull:1;                       /**< Warn about passing a null pointer for arguments marked nonnull. */
        bool old_style_definition:1;          /**< Warn if an old-style function definition is used. */
-#if 0 // TODO
        bool packed:1;                        /**< Warn if a structure is given the packed attribute, but the packed attribute has no effect on the layout or size of the structure */
        bool padded:1;                        /**< Warn if padding is included in a structure, either to align an element of the structure or to align the whole structure */
+#if 0 // TODO
        bool parentheses:1;                   /**< Warn if parentheses are omitted in certain contexts (assignment where truth value is expected, if-else-braces) */
 #endif
        bool pointer_arith:1;                 /**< Warn about anything that depends on the "size of" a function type or of 'void' */