From: Michael Beck Date: Sat, 13 Sep 2008 18:09:19 +0000 (+0000) Subject: - started implementation of size and alignment for types X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=5ba6c59ce75fd069dfbfac1ce4d9a261c99251f6;p=cparser - started implementation of size and alignment for types - implemented -Wpacked, -Wpadded [r21929] --- diff --git a/ast_t.h b/ast_t.h index d014754..508f19a 100644 --- 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 { diff --git a/parser.c b/parser.c index ffc742f..c11906c 100644 --- 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 --- 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 --- a/type.h +++ b/type.h @@ -25,6 +25,10 @@ #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 { diff --git a/type_t.h b/type_t.h index 4df727e..ec5b9a2 100644 --- 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 --- 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); diff --git a/warning.c b/warning.c index e695a89..954d2fc 100644 --- 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); diff --git a/warning.h b/warning.h index 5ce30b9..4cacecf 100644 --- 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' */