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 */
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 {
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;
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: {
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();
{
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 == ':') {
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);
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:
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: {
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);
#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 {
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;
};
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);
.nested_externs = false,
.nonnull = true,
.old_style_definition = false,
+ .packed = false,
+ .padded = false,
.pointer_arith = true,
.redundant_decls = true,
.return_type = true,
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);
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' */