rewrite of attribute handling
authorMatthias Braun <matze@braunis.de>
Sat, 7 Mar 2009 19:52:41 +0000 (19:52 +0000)
committerMatthias Braun <matze@braunis.de>
Sat, 7 Mar 2009 19:52:41 +0000 (19:52 +0000)
[r25609]

16 files changed:
Makefile
ast.c
ast2firm.c
ast_t.h
attribute.c [new file with mode: 0644]
attribute.h [new file with mode: 0644]
attribute_t.h [new file with mode: 0644]
entity.h
entity_t.h
mangle.c
parser.c
type.c
type.h
type_hash.c
type_t.h
types.c

index adecc3d..395c693 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -28,6 +28,8 @@ SOURCES := \
        adt/obstack_printf.c \
        adt/strset.c \
        adt/xmalloc.c \
+       attribute.c \
+       parser.c \
        ast.c \
        ast2firm.c \
        diagnostic.c \
@@ -42,7 +44,6 @@ SOURCES := \
        lexer.c \
        main.c \
        mangle.c \
-       parser.c \
        preprocessor.c \
        symbol_table.c \
        token.c \
diff --git a/ast.c b/ast.c
index 7c1ea6a..108e157 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -1349,6 +1349,7 @@ void print_initializer(const initializer_t *initializer)
        panic("invalid initializer kind found");
 }
 
+#if 0
 /**
  * Print microsoft extended declaration modifiers.
  */
@@ -1440,6 +1441,7 @@ static void print_ms_modifiers(const declaration_t *declaration)
        if (ds_shown)
                fputs(") ", out);
 }
+#endif
 
 static void print_scope(const scope_t *scope)
 {
@@ -1490,7 +1492,7 @@ void print_declaration(const entity_t *entity)
                        }
                }
        }
-       print_ms_modifiers(declaration);
+       //print_ms_modifiers(declaration);
        switch (entity->kind) {
                case ENTITY_FUNCTION:
                        print_type_ext(entity->declaration.type, entity->base.symbol,
index b74308b..c17d3a4 100644 (file)
@@ -260,13 +260,13 @@ static ir_node *get_vla_size(array_type_t *const type)
 /**
  * Return a node representing the size of a type.
  */
-static ir_node *get_type_size(type_t *type)
+static ir_node *get_type_size_node(type_t *type)
 {
        type = skip_typeref(type);
 
        if (is_type_array(type) && type->array.is_vla) {
                ir_node *size_node = get_vla_size(&type->array);
-               ir_node *elem_size = get_type_size(type->array.element_type);
+               ir_node *elem_size = get_type_size_node(type->array.element_type);
                ir_mode *mode      = get_irn_mode(size_node);
                ir_node *real_size = new_d_Mul(NULL, size_node, elem_size, mode);
                return real_size;
@@ -290,28 +290,15 @@ static unsigned count_parameters(const function_type_t *function_type)
        return count;
 }
 
-static type_t *get_aligned_type(type_t *type, int alignment)
-{
-       if (alignment == 0)
-               return type;
-
-       type = skip_typeref(type);
-       if (alignment > type->base.alignment) {
-               type_t *copy         = duplicate_type(type);
-               copy->base.alignment = alignment;
-               type                 = identify_new_type(copy);
-       }
-       return type;
-}
-
 /**
  * Creates a Firm type for an atomic type
  */
-static ir_type *create_atomic_type(atomic_type_kind_t akind, int alignment)
+static ir_type *create_atomic_type(atomic_type_kind_t akind)
 {
-       ir_mode            *mode   = atomic_modes[akind];
-       ident              *id     = get_mode_ident(mode);
-       ir_type            *irtype = new_type_primitive(id, mode);
+       ir_mode        *mode      = atomic_modes[akind];
+       ident          *id        = get_mode_ident(mode);
+       ir_type        *irtype    = new_type_primitive(id, mode);
+       il_alignment_t  alignment = get_atomic_type_alignment(akind);
 
        set_type_alignment_bytes(irtype, alignment);
 
@@ -342,8 +329,9 @@ static ir_type *create_imaginary_type(const imaginary_type_t *type)
        ir_mode            *mode      = atomic_modes[kind];
        ident              *id        = get_mode_ident(mode);
        ir_type            *irtype    = new_type_primitive(id, mode);
+       il_alignment_t      alignment = get_type_alignment((const type_t*) type);
 
-       set_type_alignment_bytes(irtype, type->base.alignment);
+       set_type_alignment_bytes(irtype, alignment);
 
        return irtype;
 }
@@ -352,10 +340,11 @@ static ir_type *create_imaginary_type(const imaginary_type_t *type)
  * return type of a parameter (and take transparent union gnu extension into
  * account)
  */
-static type_t *get_parameter_type(type_t *type)
+static type_t *get_parameter_type(type_t *orig_type)
 {
-       type = skip_typeref(type);
-       if (type->base.modifiers & TYPE_MODIFIER_TRANSPARENT_UNION) {
+       type_t *type = skip_typeref(orig_type);
+       if (is_type_union(type)
+                       && get_type_modifiers(orig_type) & DM_TRANSPARENT_UNION) {
                compound_t *compound = type->compound.compound;
                type                 = compound->members.entities->declaration.type;
        }
@@ -635,8 +624,6 @@ static ir_type *create_compound_type(compound_type_t *type, ir_type *irtype,
 
                symbol_t *symbol     = entry->base.symbol;
                type_t   *entry_type = skip_typeref(entry->declaration.type);
-               entry_type
-                       = get_aligned_type(entry_type, entry->compound_member.alignment);
                dbg_info *dbgi       = get_dbg_info(&entry->base.source_position);
 
                ident    *ident;
@@ -790,7 +777,7 @@ static ir_type *create_enum_type(enum_type_t *const type)
 
        constant_folding = constant_folding_old;
 
-       return create_atomic_type(type->akind, type->base.alignment);
+       return create_atomic_type(type->akind);
 }
 
 static ir_type *get_ir_type_incomplete(type_t *type)
@@ -830,11 +817,10 @@ ir_type *get_ir_type(type_t *type)
        switch (type->kind) {
        case TYPE_ERROR:
                /* Happens while constant folding, when there was an error */
-               return create_atomic_type(ATOMIC_TYPE_VOID, 0);
+               return create_atomic_type(ATOMIC_TYPE_VOID);
 
        case TYPE_ATOMIC:
-               firm_type = create_atomic_type(type->atomic.akind,
-                                              type->base.alignment);
+               firm_type = create_atomic_type(type->atomic.akind);
                break;
        case TYPE_COMPLEX:
                firm_type = create_complex_type(&type->complex);
@@ -1005,7 +991,7 @@ static ident* (*create_ld_ident)(entity_t*) = create_name_linux_elf;
  * @param ent   the entity
  * @param decl  the routine declaration
  */
-static void handle_gnu_attributes_ent(ir_entity *irentity, entity_t *entity)
+static void handle_decl_modifiers(ir_entity *irentity, entity_t *entity)
 {
        assert(is_declaration(entity));
        decl_modifiers_t modifiers = entity->declaration.modifiers;
@@ -1104,7 +1090,7 @@ static ir_entity *get_function_entity(entity_t *entity, ir_type *owner_type)
                ld_id = create_ld_ident(entity);
        set_entity_ld_ident(irentity, ld_id);
 
-       handle_gnu_attributes_ent(irentity, entity);
+       handle_decl_modifiers(irentity, entity);
 
        if (! nested_function) {
                /* static inline             => local
@@ -2356,7 +2342,7 @@ static ir_node *create_incdec(const unary_expression_t *expression)
        ir_node *offset;
        if (is_type_pointer(type)) {
                pointer_type_t *pointer_type = &type->pointer;
-               offset                       = get_type_size(pointer_type->points_to);
+               offset = get_type_size_node(pointer_type->points_to);
        } else {
                assert(is_type_arithmetic(type));
                offset = new_Const(get_mode_one(mode));
@@ -2654,7 +2640,7 @@ static ir_node *adjust_for_pointer_arithmetic(dbg_info *dbgi,
        assert(is_type_pointer(type));
        pointer_type_t *const pointer_type = &type->pointer;
        type_t         *const points_to    = skip_typeref(pointer_type->points_to);
-       ir_node        *      elem_size    = get_type_size(points_to);
+       ir_node        *      elem_size    = get_type_size_node(points_to);
        elem_size                          = create_conv(dbgi, elem_size, mode);
        value                              = create_conv(dbgi, value,     mode);
        ir_node        *const mul          = new_d_Mul(dbgi, value, elem_size, mode);
@@ -2684,7 +2670,7 @@ static ir_node *create_op(dbg_info *dbgi, const binary_expression_t *expression,
                        const pointer_type_t *const ptr_type = &type_left->pointer;
 
                        mode = get_ir_mode_arithmetic(expression->base.type);
-                       ir_node *const elem_size = get_type_size(ptr_type->points_to);
+                       ir_node *const elem_size = get_type_size_node(ptr_type->points_to);
                        ir_node *const conv_size = new_d_Conv(dbgi, elem_size, mode);
                        ir_node *const sub       = new_d_Sub(dbgi, left, right, mode);
                        ir_node *const no_mem    = new_NoMem();
@@ -3045,7 +3031,7 @@ static ir_node *sizeof_to_firm(const typeprop_expression_t *expression)
                expression_to_firm(expression->tp_expression);
        }
 
-       return get_type_size(type);
+       return get_type_size_node(type);
 }
 
 static entity_t *get_expression_entity(const expression_t *expression)
@@ -3056,54 +3042,46 @@ static entity_t *get_expression_entity(const expression_t *expression)
        return expression->reference.entity;
 }
 
+static unsigned get_cparser_entity_alignment(const entity_t *entity)
+{
+       switch(entity->kind) {
+       DECLARATION_KIND_CASES
+               return entity->declaration.alignment;
+       case ENTITY_STRUCT:
+       case ENTITY_UNION:
+               return entity->compound.alignment;
+       case ENTITY_TYPEDEF:
+               return entity->typedefe.alignment;
+       default:
+               break;
+       }
+       return 0;
+}
+
 /**
  * Transform an alignof expression into Firm code.
  */
 static ir_node *alignof_to_firm(const typeprop_expression_t *expression)
 {
-       ir_entity *irentity = NULL;
+       unsigned alignment = 0;
 
        const expression_t *tp_expression = expression->tp_expression;
        if (tp_expression != NULL) {
                entity_t *entity = get_expression_entity(tp_expression);
-               if (entity != NULL && is_declaration(entity)) {
-                       switch (entity->declaration.kind) {
-                       case DECLARATION_KIND_UNKNOWN:
-                               panic("unknown entity reference found");
-                       case DECLARATION_KIND_COMPOUND_MEMBER:
-                               irentity = entity->compound_member.entity;
-                               break;
-                       case DECLARATION_KIND_GLOBAL_VARIABLE:
-                       case DECLARATION_KIND_LOCAL_VARIABLE_ENTITY:
-                               irentity = entity->variable.v.entity;
-                               break;
-                       case DECLARATION_KIND_PARAMETER_ENTITY:
-                               irentity = entity->parameter.v.entity;
-                               break;
-                       case DECLARATION_KIND_FUNCTION:
-                       case DECLARATION_KIND_INNER_FUNCTION:
-                               irentity = entity->function.entity;
-                               break;
-                       case DECLARATION_KIND_PARAMETER:
-                       case DECLARATION_KIND_LOCAL_VARIABLE:
-                       case DECLARATION_KIND_VARIABLE_LENGTH_ARRAY:
-                               break;
-                       }
+               if (entity != NULL) {
+                       alignment = get_cparser_entity_alignment(entity);
                }
        }
 
-       ir_type *irtype;
-       if (irentity != NULL) {
-               irtype = get_entity_type(irentity);
-       } else {
+       if (alignment == 0) {
                type_t *type = expression->type;
-               irtype = get_ir_type(type);
+               alignment = get_type_alignment(type);
        }
 
-       ir_mode *const mode = get_ir_mode_arithmetic(expression->base.type);
-       symconst_symbol sym;
-       sym.type_p = irtype;
-       return new_SymConst(mode, sym, symconst_type_align);
+       dbg_info *dbgi = get_dbg_info(&expression->base.source_position);
+       ir_mode  *mode = get_ir_mode_arithmetic(expression->base.type);
+       tarval   *tv   = new_tarval_from_long(alignment, mode);
+       return new_d_Const(dbgi, tv);
 }
 
 static void init_ir_types(void);
@@ -3403,7 +3381,8 @@ static ir_node *va_start_expression_to_firm(
        ir_node   *const arg_sel     =
                new_d_simpleSel(dbgi, no_mem, frame, parm_ent);
 
-       ir_node   *const cnst        = get_type_size(expr->parameter->base.type);
+       type_t    *const param_type  = expr->parameter->base.type;
+       ir_node   *const cnst        = get_type_size_node(param_type);
        ir_mode   *const mode        = get_irn_mode(cnst);
        ir_node   *const c1          = new_Const_long(mode, stack_param_align - 1);
        ir_node   *const c2          = new_d_Add(dbgi, cnst, c1, mode);
@@ -3424,7 +3403,7 @@ static ir_node *va_arg_expression_to_firm(const va_arg_expression_t *const expr)
        dbg_info     *const dbgi    = get_dbg_info(&expr->base.source_position);
        ir_node      *const res     = deref_address(dbgi, type, ap);
 
-       ir_node      *const cnst    = get_type_size(expr->base.type);
+       ir_node      *const cnst    = get_type_size_node(expr->base.type);
        ir_mode      *const mode    = get_irn_mode(cnst);
        ir_node      *const c1      = new_Const_long(mode, stack_param_align - 1);
        ir_node      *const c2      = new_d_Add(dbgi, cnst, c1, mode);
@@ -3764,22 +3743,22 @@ static ir_node *create_condition_evaluation(const expression_t *expression,
        return cond_expr;
 }
 
-
 static void create_variable_entity(entity_t *variable,
                                    declaration_kind_t declaration_kind,
                                    ir_type *parent_type)
 {
        assert(variable->kind == ENTITY_VARIABLE);
        type_t    *type = skip_typeref(variable->declaration.type);
-       type            = get_aligned_type(type, variable->variable.alignment);
 
-       ident     *const id       = new_id_from_str(variable->base.symbol->string);
-       ir_type   *const irtype   = get_ir_type(type);
-       dbg_info  *const dbgi     = get_dbg_info(&variable->base.source_position);
+       ident     *const id        = new_id_from_str(variable->base.symbol->string);
+       ir_type   *const irtype    = get_ir_type(type);
+       dbg_info  *const dbgi      = get_dbg_info(&variable->base.source_position);
+       ir_entity *const irentity  = new_d_entity(parent_type, id, irtype, dbgi);
+       unsigned         alignment = variable->declaration.alignment;
 
-       ir_entity *const irentity = new_d_entity(parent_type, id, irtype, dbgi);
+       set_entity_alignment(irentity, alignment);
 
-       handle_gnu_attributes_ent(irentity, variable);
+       handle_decl_modifiers(irentity, variable);
 
        variable->declaration.kind  = (unsigned char) declaration_kind;
        variable->variable.v.entity = irentity;
@@ -4421,7 +4400,6 @@ static void create_initializer_local_variable_entity(entity_t *entity)
        ir_entity     *irentity    = entity->variable.v.entity;
        type_t        *type        = entity->declaration.type;
 
-       type = get_aligned_type(type, entity->variable.alignment);
        create_local_initializer(initializer, dbgi, irentity, type);
 }
 
@@ -4507,7 +4485,7 @@ static void allocate_variable_length_array(entity_t *entity)
        ir_type  *el_type   = get_ir_type(type->array.element_type);
 
        /* make sure size_node is calculated */
-       get_type_size(type);
+       get_type_size_node(type);
        ir_node  *elems = type->array.size_node;
        ir_node  *mem   = get_store();
        ir_node  *alloc = new_d_Alloc(dbgi, mem, elems, el_type, stack_alloc);
@@ -4560,13 +4538,11 @@ static void create_local_static_variable(entity_t *entity)
        assert(entity->kind == ENTITY_VARIABLE);
        assert(entity->declaration.kind == DECLARATION_KIND_UNKNOWN);
 
-       type_t    *type = skip_typeref(entity->declaration.type);
-       type            = get_aligned_type(type, entity->variable.alignment);
-
-       ir_type   *const var_type = entity->variable.thread_local ?
+       type_t   *type           = skip_typeref(entity->declaration.type);
+       ir_type  *const var_type = entity->variable.thread_local ?
                get_tls_type() : get_glob_type();
-       ir_type   *const irtype   = get_ir_type(type);
-       dbg_info  *const dbgi     = get_dbg_info(&entity->base.source_position);
+       ir_type  *const irtype   = get_ir_type(type);
+       dbg_info *const dbgi     = get_dbg_info(&entity->base.source_position);
 
        size_t l = strlen(entity->base.symbol->string);
        char   buf[l + sizeof(".%u")];
@@ -5734,7 +5710,8 @@ static void initialize_function_parameters(entity_t *entity)
  * @param irg            the IR-graph
  * @param dec_modifiers  additional modifiers
  */
-static void handle_decl_modifier_irg(ir_graph_ptr irg, decl_modifiers_t decl_modifiers)
+static void handle_decl_modifier_irg(ir_graph_ptr irg,
+                                     decl_modifiers_t decl_modifiers)
 {
        if (decl_modifiers & DM_RETURNS_TWICE) {
                /* TRUE if the declaration includes __attribute__((returns_twice)) */
diff --git a/ast_t.h b/ast_t.h
index af807be..7a08c2a 100644 (file)
--- a/ast_t.h
+++ b/ast_t.h
@@ -465,79 +465,6 @@ union initializer_t {
        initializer_designator_t  designator;
 };
 
-/**
- * GNU attributes.
- */
-typedef enum gnu_attribute_kind_t {
-       GNU_AK_CONST,
-       GNU_AK_VOLATILE,
-       GNU_AK_CDECL,
-       GNU_AK_STDCALL,
-       GNU_AK_FASTCALL,
-       GNU_AK_DEPRECATED,
-       GNU_AK_NOINLINE,
-       GNU_AK_RETURNS_TWICE,
-       GNU_AK_NORETURN,
-       GNU_AK_NAKED,
-       GNU_AK_PURE,
-       GNU_AK_ALWAYS_INLINE,
-       GNU_AK_MALLOC,
-       GNU_AK_WEAK,
-       GNU_AK_CONSTRUCTOR,
-       GNU_AK_DESTRUCTOR,
-       GNU_AK_NOTHROW,
-       GNU_AK_TRANSPARENT_UNION,
-       GNU_AK_COMMON,
-       GNU_AK_NOCOMMON,
-       GNU_AK_PACKED,
-       GNU_AK_SHARED,
-       GNU_AK_NOTSHARED,
-       GNU_AK_USED,
-       GNU_AK_UNUSED,
-       GNU_AK_NO_INSTRUMENT_FUNCTION,
-       GNU_AK_WARN_UNUSED_RESULT,
-       GNU_AK_LONGCALL,
-       GNU_AK_SHORTCALL,
-       GNU_AK_LONG_CALL,
-       GNU_AK_SHORT_CALL,
-       GNU_AK_FUNCTION_VECTOR,
-       GNU_AK_INTERRUPT,
-       GNU_AK_INTERRUPT_HANDLER,
-       GNU_AK_NMI_HANDLER,
-       GNU_AK_NESTING,
-       GNU_AK_NEAR,
-       GNU_AK_FAR,
-       GNU_AK_SIGNAL,
-       GNU_AK_EIGTHBIT_DATA,
-       GNU_AK_TINY_DATA,
-       GNU_AK_SAVEALL,
-       GNU_AK_FLATTEN,
-       GNU_AK_SSEREGPARM,
-       GNU_AK_EXTERNALLY_VISIBLE,
-       GNU_AK_RETURN_TWICE,
-       GNU_AK_MAY_ALIAS,
-       GNU_AK_MS_STRUCT,
-       GNU_AK_GCC_STRUCT,
-       GNU_AK_DLLIMPORT,
-       GNU_AK_DLLEXPORT,
-       GNU_AK_ALIGNED,
-       GNU_AK_ALIAS,
-       GNU_AK_SECTION,
-       GNU_AK_FORMAT,
-       GNU_AK_FORMAT_ARG,
-       GNU_AK_WEAKREF,
-       GNU_AK_NONNULL,
-       GNU_AK_TLS_MODEL,
-       GNU_AK_VISIBILITY,
-       GNU_AK_REGPARM,
-       GNU_AK_MODEL,
-       GNU_AK_MODE,
-       GNU_AK_TRAP_EXIT,
-       GNU_AK_SP_SWITCH,
-       GNU_AK_SENTINEL,
-       GNU_AK_LAST
-} gnu_attribute_kind_t;
-
 /**
  * The statement kinds.
  */
@@ -748,7 +675,6 @@ bool is_invalid_statement(statement_t *statement)
        return statement->base.kind == STATEMENT_INVALID;
 }
 
-
 #define allocate_ast(size)                 _allocate_ast(size)
 
 #endif
diff --git a/attribute.c b/attribute.c
new file mode 100644 (file)
index 0000000..9718a21
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * This file is part of cparser.
+ * Copyright (C) 2007-2008 Matthias Braun <matze@braunis.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include <config.h>
+
+#include <assert.h>
+#include "diagnostic.h"
+#include "warning.h"
+#include "attribute_t.h"
+#include "symbol_t.h"
+#include "type_t.h"
+
+static const char *const attribute_names[ATTRIBUTE_LAST+1] = {
+       [ATTRIBUTE_GNU_CONST]                  = "const",
+       [ATTRIBUTE_GNU_VOLATILE]               = "volatile",
+       [ATTRIBUTE_GNU_CDECL]                  = "cdecl",
+       [ATTRIBUTE_GNU_STDCALL]                = "stdcall",
+       [ATTRIBUTE_GNU_FASTCALL]               = "fastcall",
+       [ATTRIBUTE_GNU_DEPRECATED]             = "deprecated",
+       [ATTRIBUTE_GNU_NOINLINE]               = "noinline",
+       [ATTRIBUTE_GNU_RETURNS_TWICE]          = "returns_twice",
+       [ATTRIBUTE_GNU_NORETURN]               = "noreturn",
+       [ATTRIBUTE_GNU_NAKED]                  = "naked",
+       [ATTRIBUTE_GNU_PURE]                   = "pure",
+       [ATTRIBUTE_GNU_ALWAYS_INLINE]          = "always_inline",
+       [ATTRIBUTE_GNU_MALLOC]                 = "malloc",
+       [ATTRIBUTE_GNU_WEAK]                   = "weak",
+       [ATTRIBUTE_GNU_CONSTRUCTOR]            = "constructor",
+       [ATTRIBUTE_GNU_DESTRUCTOR]             = "destructor",
+       [ATTRIBUTE_GNU_NOTHROW]                = "nothrow",
+       [ATTRIBUTE_GNU_TRANSPARENT_UNION]      = "transparent_union",
+       [ATTRIBUTE_GNU_COMMON]                 = "common",
+       [ATTRIBUTE_GNU_NOCOMMON]               = "nocommon",
+       [ATTRIBUTE_GNU_PACKED]                 = "packed",
+       [ATTRIBUTE_GNU_SHARED]                 = "shared",
+       [ATTRIBUTE_GNU_NOTSHARED]              = "notshared",
+       [ATTRIBUTE_GNU_USED]                   = "used",
+       [ATTRIBUTE_GNU_UNUSED]                 = "unused",
+       [ATTRIBUTE_GNU_NO_INSTRUMENT_FUNCTION] = "no_instrument_function",
+       [ATTRIBUTE_GNU_WARN_UNUSED_RESULT]     = "warn_unused_result",
+       [ATTRIBUTE_GNU_LONGCALL]               = "longcall",
+       [ATTRIBUTE_GNU_SHORTCALL]              = "shortcall",
+       [ATTRIBUTE_GNU_LONG_CALL]              = "long_call",
+       [ATTRIBUTE_GNU_SHORT_CALL]             = "short_call",
+       [ATTRIBUTE_GNU_FUNCTION_VECTOR]        = "function_vector",
+       [ATTRIBUTE_GNU_INTERRUPT]              = "interrupt",
+       [ATTRIBUTE_GNU_INTERRUPT_HANDLER]      = "interrupt_handler",
+       [ATTRIBUTE_GNU_NMI_HANDLER]            = "nmi_handler",
+       [ATTRIBUTE_GNU_NESTING]                = "nesting",
+       [ATTRIBUTE_GNU_NEAR]                   = "near",
+       [ATTRIBUTE_GNU_FAR]                    = "far",
+       [ATTRIBUTE_GNU_SIGNAL]                 = "signal",
+       [ATTRIBUTE_GNU_EIGTHBIT_DATA]          = "eightbit_data",
+       [ATTRIBUTE_GNU_TINY_DATA]              = "tiny_data",
+       [ATTRIBUTE_GNU_SAVEALL]                = "saveall",
+       [ATTRIBUTE_GNU_FLATTEN]                = "flatten",
+       [ATTRIBUTE_GNU_SSEREGPARM]             = "sseregparm",
+       [ATTRIBUTE_GNU_EXTERNALLY_VISIBLE]     = "externally_visible",
+       [ATTRIBUTE_GNU_MAY_ALIAS]              = "may_alias",
+       [ATTRIBUTE_GNU_MS_STRUCT]              = "ms_struct",
+       [ATTRIBUTE_GNU_GCC_STRUCT]             = "gcc_struct",
+       [ATTRIBUTE_GNU_DLLIMPORT]              = "dllimport",
+       [ATTRIBUTE_GNU_DLLEXPORT]              = "dllexport",
+       [ATTRIBUTE_GNU_ALIGNED]                = "aligned",
+       [ATTRIBUTE_GNU_ALIAS]                  = "alias",
+       [ATTRIBUTE_GNU_SECTION]                = "section",
+       [ATTRIBUTE_GNU_FORMAT]                 = "format",
+       [ATTRIBUTE_GNU_FORMAT_ARG]             = "format_arg",
+       [ATTRIBUTE_GNU_WEAKREF]                = "weakref",
+       [ATTRIBUTE_GNU_NONNULL]                = "nonnull",
+       [ATTRIBUTE_GNU_TLS_MODEL]              = "tls_model",
+       [ATTRIBUTE_GNU_VISIBILITY]             = "visibility",
+       [ATTRIBUTE_GNU_REGPARM]                = "regparm",
+       [ATTRIBUTE_GNU_MODE]                   = "mode",
+       [ATTRIBUTE_GNU_MODEL]                  = "model",
+       [ATTRIBUTE_GNU_TRAP_EXIT]              = "trap_exit",
+       [ATTRIBUTE_GNU_SP_SWITCH]              = "sp_switch",
+       [ATTRIBUTE_GNU_SENTINEL]               = "sentinel",
+
+       [ATTRIBUTE_MS_ALIGN]                   = "align",
+       [ATTRIBUTE_MS_ALLOCATE]                = "allocate",
+       [ATTRIBUTE_MS_DLLIMPORT]               = "dllimport",
+       [ATTRIBUTE_MS_DLLEXPORT]               = "dllexport",
+       [ATTRIBUTE_MS_NAKED]                   = "naked",
+       [ATTRIBUTE_MS_NOINLINE]                = "noinline",
+       [ATTRIBUTE_MS_RETURNS_TWICE]           = "returns_twice",
+       [ATTRIBUTE_MS_NORETURN]                = "noreturn",
+       [ATTRIBUTE_MS_NOTHROW]                 = "nothrow",
+       [ATTRIBUTE_MS_NOVTABLE]                = "novtable",
+       [ATTRIBUTE_MS_PROPERTY]                = "property",
+       [ATTRIBUTE_MS_SELECTANY]               = "selectany",
+       [ATTRIBUTE_MS_THREAD]                  = "thread",
+       [ATTRIBUTE_MS_UUID]                    = "uuid",
+       [ATTRIBUTE_MS_DEPRECATED]              = "deprecated",
+       [ATTRIBUTE_MS_RESTRICT]                = "restrict",
+       [ATTRIBUTE_MS_NOALIAS]                 = "noalias",
+};
+
+const char *get_attribute_name(attribute_kind_t kind)
+{
+       assert(kind <= ATTRIBUTE_LAST);
+       return attribute_names[kind];
+}
+
+/**
+ * compare two string, ignoring double underscores on the second.
+ */
+static int strcmp_underscore(const char *s1, const char *s2)
+{
+       if (s2[0] == '_' && s2[1] == '_') {
+               size_t len2 = strlen(s2);
+               size_t len1 = strlen(s1);
+               if (len1 == len2-4 && s2[len2-2] == '_' && s2[len2-1] == '_') {
+                       return strncmp(s1, s2+2, len2-4);
+               }
+       }
+
+       return strcmp(s1, s2);
+}
+
+type_t *handle_attribute_mode(const attribute_t *attribute, type_t *orig_type)
+{
+       type_t *type = skip_typeref(orig_type);
+
+       /* at least: byte, word, pointer, list of machine modes
+        * __XXX___ is interpreted as XXX */
+
+       /* This isn't really correct, the backend should provide a list of machine
+        * specific modes (according to gcc philosophy that is...) */
+       attribute_argument_t *arg        = attribute->a.arguments;
+       const char           *symbol_str = arg->v.symbol->string;
+       bool                  sign       = is_type_signed(type);
+       atomic_type_kind_t  akind;
+       if (strcmp_underscore("QI",   symbol_str) == 0 ||
+           strcmp_underscore("byte", symbol_str) == 0) {
+               akind = sign ? ATOMIC_TYPE_CHAR : ATOMIC_TYPE_UCHAR;
+       } else if (strcmp_underscore("HI", symbol_str) == 0) {
+               akind = sign ? ATOMIC_TYPE_SHORT : ATOMIC_TYPE_USHORT;
+       } else if (strcmp_underscore("SI",      symbol_str) == 0
+               || strcmp_underscore("word",    symbol_str) == 0
+               || strcmp_underscore("pointer", symbol_str) == 0) {
+               akind = sign ? ATOMIC_TYPE_INT : ATOMIC_TYPE_UINT;
+       } else if (strcmp_underscore("DI", symbol_str) == 0) {
+               akind = sign ? ATOMIC_TYPE_LONGLONG : ATOMIC_TYPE_ULONGLONG;
+       } else {
+               if (warning.other)
+                       warningf(&attribute->source_position, "ignoring unknown mode '%s'",
+                                symbol_str);
+               return orig_type;
+       }
+
+       if (type->kind == TYPE_ATOMIC) {
+               type_t *copy       = duplicate_type(type);
+               copy->atomic.akind = akind;
+               return identify_new_type(copy);
+       } else if (type->kind == TYPE_ENUM) {
+               type_t *copy      = duplicate_type(type);
+               copy->enumt.akind = akind;
+               return identify_new_type(copy);
+       } else if (is_type_pointer(type)) {
+               warningf(&attribute->source_position,
+                        "__attribute__((mode)) on pointers not implemented yet (ignored)");
+               return type;
+       }
+
+       errorf(&attribute->source_position,
+              "__attribute__((mode)) only allowed on integer, enum or pointer type");
+       return orig_type;
+}
+
+static inline bool is_po2(unsigned x)
+{
+       return (x & (x-1)) == 0;
+}
+
+static void handle_attribute_aligned(const attribute_t *attribute,
+                                     entity_t *entity)
+{
+       int alignment = 32; /* TODO: fill in maximum useful alignment for
+                                                  target machine */
+       if (attribute->a.arguments) {
+               attribute_argument_t *argument = attribute->a.arguments;
+               alignment = fold_constant(argument->v.expression);
+       }
+
+       if (!is_po2(alignment)) {
+               errorf(&attribute->source_position,
+                          "alignment must be a power of 2 but is %d\n",
+                          alignment);
+               return;
+       }
+       if (alignment <= 0) {
+               errorf(&attribute->source_position,
+                          "alignment must be bigger than 0 but is %d\n",
+                          alignment);
+               return;
+       }
+
+       switch (entity->kind) {
+       DECLARATION_KIND_CASES
+               entity->declaration.alignment = alignment;
+       case ENTITY_TYPEDEF:
+               entity->typedefe.alignment = alignment;
+               break;
+       case ENTITY_STRUCT:
+       case ENTITY_UNION:
+               if (alignment > entity->compound.alignment) {
+                       entity->compound.alignment = alignment;
+               }
+               break;
+       default:
+               if (warning.other) {
+                       warningf(&attribute->source_position,
+                                        "alignment attribute specification on '%S' ignored",
+                                        entity->base.symbol);
+               }
+               break;
+       }
+}
+
+static void warn_arguments(const attribute_t *attribute)
+{
+       if (attribute->a.arguments == NULL)
+               return;
+
+       if (warning.other) {
+               warningf(&attribute->source_position,
+                                "attribute '%s' needs no attributes",
+                                get_attribute_name(attribute->kind));
+       }
+}
+
+static void handle_attribute_packed(const attribute_t *attribute,
+                                    entity_t *entity)
+{
+       warn_arguments(attribute);
+
+       if (entity->kind == ENTITY_STRUCT) {
+               entity->compound.packed = true;
+       } else if (warning.other) {
+               warningf(&attribute->source_position,
+                        "packed attribute on %s ignored",
+                                get_entity_kind_name(entity->kind));
+       }
+}
+
+void handle_entity_attributes(const attribute_t *attributes, entity_t *entity)
+{
+       if (entity->kind == ENTITY_TYPEDEF) {
+               type_t *type = entity->typedefe.type;
+               type = handle_type_attributes(attributes, type);
+               entity->typedefe.type = type;
+       } else if (is_declaration(entity)) {
+               type_t *type = entity->declaration.type;
+               type = handle_type_attributes(attributes, type);
+               entity->declaration.type = type;
+       }
+
+       decl_modifiers_t modifiers = 0;
+       const attribute_t *attribute = attributes;
+       for ( ; attribute != NULL; attribute = attribute->next) {
+               switch(attribute->kind) {
+               case ATTRIBUTE_GNU_CONST:         modifiers |= DM_CONST; break;
+               case ATTRIBUTE_GNU_DEPRECATED:    modifiers |= DM_DEPRECATED; break;
+               case ATTRIBUTE_GNU_NOINLINE:      modifiers |= DM_NOINLINE; break;
+               case ATTRIBUTE_GNU_RETURNS_TWICE: modifiers |= DM_RETURNS_TWICE; break;
+               case ATTRIBUTE_GNU_NORETURN:      modifiers |= DM_NORETURN; break;
+               case ATTRIBUTE_GNU_NAKED:         modifiers |= DM_NAKED; break;
+               case ATTRIBUTE_GNU_PURE:          modifiers |= DM_PURE; break;
+               case ATTRIBUTE_GNU_ALWAYS_INLINE: modifiers |= DM_FORCEINLINE; break;
+               case ATTRIBUTE_GNU_MALLOC:        modifiers |= DM_MALLOC; break;
+               case ATTRIBUTE_GNU_CONSTRUCTOR:   modifiers |= DM_CONSTRUCTOR; break;
+               case ATTRIBUTE_GNU_DESTRUCTOR:    modifiers |= DM_DESTRUCTOR; break;
+               case ATTRIBUTE_GNU_NOTHROW:       modifiers |= DM_NOTHROW; break;
+               case ATTRIBUTE_GNU_TRANSPARENT_UNION:
+                                                                                 modifiers |= DM_TRANSPARENT_UNION;
+                                                                                 break;
+               case ATTRIBUTE_GNU_USED:          modifiers |= DM_USED; break;
+               case ATTRIBUTE_GNU_UNUSED:        modifiers |= DM_UNUSED; break;
+               case ATTRIBUTE_GNU_DLLIMPORT:     modifiers |= DM_DLLIMPORT; break;
+               case ATTRIBUTE_GNU_DLLEXPORT:     modifiers |= DM_DLLEXPORT; break;
+
+               case ATTRIBUTE_MS_ALLOCATE:      modifiers |= DM_MALLOC; break;
+               case ATTRIBUTE_MS_DLLIMPORT:     modifiers |= DM_DLLIMPORT; break;
+               case ATTRIBUTE_MS_DLLEXPORT:     modifiers |= DM_DLLEXPORT; break;
+               case ATTRIBUTE_MS_NAKED:         modifiers |= DM_NAKED; break;
+               case ATTRIBUTE_MS_NOINLINE:      modifiers |= DM_NOINLINE; break;
+               case ATTRIBUTE_MS_RETURNS_TWICE: modifiers |= DM_RETURNS_TWICE; break;
+               case ATTRIBUTE_MS_NORETURN:      modifiers |= DM_NORETURN; break;
+               case ATTRIBUTE_MS_NOTHROW:       modifiers |= DM_NOTHROW; break;
+               case ATTRIBUTE_MS_THREAD:        modifiers |= DM_THREAD; break;
+               case ATTRIBUTE_MS_DEPRECATED:    modifiers |= DM_DEPRECATED; break;
+               case ATTRIBUTE_MS_RESTRICT:      modifiers |= DM_RESTRICT; break;
+               case ATTRIBUTE_MS_NOALIAS:       modifiers |= DM_NOALIAS; break;
+
+               case ATTRIBUTE_GNU_PACKED:
+                       handle_attribute_packed(attribute, entity);
+                       break;
+               case ATTRIBUTE_MS_ALIGN:
+               case ATTRIBUTE_GNU_ALIGNED:
+                       handle_attribute_aligned(attribute, entity);
+                       break;
+               default: break;
+               }
+       }
+
+       if (modifiers != 0) {
+               switch(entity->kind) {
+               case ENTITY_TYPEDEF:
+                       entity->typedefe.modifiers |= modifiers;
+                       break;
+               case ENTITY_UNION:
+               case ENTITY_STRUCT:
+                       entity->compound.modifiers |= modifiers;
+                       break;
+               case ENTITY_COMPOUND_MEMBER:
+               case ENTITY_VARIABLE:
+               case ENTITY_FUNCTION:
+                       entity->declaration.modifiers |= modifiers;
+                       break;
+               default:
+                       /* TODO: warning */
+                       break;
+               }
+       }
+}
+
+static type_t *change_calling_convention(const source_position_t *pos,
+                                         type_t *type, cc_kind_t cconv)
+{
+       if (!is_type_function(type)) {
+               if (warning.other) {
+                       warningf(pos,
+                                "Calling convention specified on non-function type '%T'",
+                                type);
+               }
+               return type;
+       }
+
+       if (type->function.calling_convention == cconv)
+               return type;
+
+       type_t* new_type = duplicate_type(type);
+       new_type->function.calling_convention = cconv;
+       return identify_new_type(new_type);
+}
+
+type_t *handle_type_attributes(const attribute_t *attributes, type_t *type)
+{
+       const attribute_t *attribute = attributes;
+       for ( ; attribute != NULL; attribute = attribute->next) {
+               switch(attribute->kind) {
+               case ATTRIBUTE_GNU_CDECL:
+               case ATTRIBUTE_MS_CDECL:
+                       type = change_calling_convention(&attribute->source_position,
+                                                        type, CC_CDECL);
+                       break;
+               case ATTRIBUTE_MS_STDCALL:
+               case ATTRIBUTE_GNU_STDCALL:
+                       type = change_calling_convention(&attribute->source_position,
+                                                        type, CC_STDCALL);
+                       break;
+               case ATTRIBUTE_MS_FASTCALL:
+               case ATTRIBUTE_GNU_FASTCALL:
+                       type = change_calling_convention(&attribute->source_position,
+                                                        type, CC_FASTCALL);
+                       break;
+               case ATTRIBUTE_MS_THISCALL:
+                       type = change_calling_convention(&attribute->source_position,
+                                                        type, CC_THISCALL);
+                       break;
+               case ATTRIBUTE_GNU_MODE:
+                       type = handle_attribute_mode(attribute, type);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return type;
+}
+
+const char *get_deprecated_string(const attribute_t *attribute)
+{
+       for ( ; attribute != NULL; attribute = attribute->next) {
+               if (attribute->kind != ATTRIBUTE_MS_DEPRECATED)
+                       continue;
+
+               attribute_argument_t *argument = attribute->a.arguments;
+               if (argument == NULL)
+                       return NULL;
+               if (argument->kind != ATTRIBUTE_ARGUMENT_EXPRESSION)
+                       return NULL;
+               expression_t *expression = argument->v.expression;
+               if (expression->kind != EXPR_STRING_LITERAL)
+                       return NULL;
+               return expression->string.value.begin;
+       }
+       return NULL;
+}
diff --git a/attribute.h b/attribute.h
new file mode 100644 (file)
index 0000000..0684aa0
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef ATTRIBUTE_H
+#define ATTRIBUTE_H
+
+#include "entity.h"
+#include "type.h"
+
+typedef struct attribute_t attribute_t;
+
+const char *get_deprecated_string(const attribute_t *attribute);
+
+type_t *handle_type_attributes(const attribute_t *attributes, type_t *type);
+void handle_entity_attributes(const attribute_t *attributes, entity_t *entity);
+type_t *handle_attribute_mode(const attribute_t *attribute, type_t *orig_type);
+
+#endif
diff --git a/attribute_t.h b/attribute_t.h
new file mode 100644 (file)
index 0000000..1a62aeb
--- /dev/null
@@ -0,0 +1,146 @@
+#ifndef ATTRIBUTE_T_H
+#define ATTRIBUTE_T_H
+
+#include "attribute.h"
+#include "ast.h"
+#include "symbol.h"
+#include "type.h"
+
+/**
+ * GNU attributes.
+ */
+typedef enum attribute_kind_t {
+       ATTRIBUTE_ERROR,
+       ATTRIBUTE_UNKNOWN,
+       ATTRIBUTE_GNU_FIRST,
+       ATTRIBUTE_GNU_CONST = ATTRIBUTE_GNU_FIRST,
+       ATTRIBUTE_GNU_VOLATILE,
+       ATTRIBUTE_GNU_CDECL,
+       ATTRIBUTE_GNU_STDCALL,
+       ATTRIBUTE_GNU_FASTCALL,
+       ATTRIBUTE_GNU_DEPRECATED,
+       ATTRIBUTE_GNU_NOINLINE,
+       ATTRIBUTE_GNU_RETURNS_TWICE,
+       ATTRIBUTE_GNU_NORETURN,
+       ATTRIBUTE_GNU_NAKED,
+       ATTRIBUTE_GNU_PURE,
+       ATTRIBUTE_GNU_ALWAYS_INLINE,
+       ATTRIBUTE_GNU_MALLOC,
+       ATTRIBUTE_GNU_WEAK,
+       ATTRIBUTE_GNU_CONSTRUCTOR,
+       ATTRIBUTE_GNU_DESTRUCTOR,
+       ATTRIBUTE_GNU_NOTHROW,
+       ATTRIBUTE_GNU_TRANSPARENT_UNION,
+       ATTRIBUTE_GNU_COMMON,
+       ATTRIBUTE_GNU_NOCOMMON,
+       ATTRIBUTE_GNU_PACKED,
+       ATTRIBUTE_GNU_SHARED,
+       ATTRIBUTE_GNU_NOTSHARED,
+       ATTRIBUTE_GNU_USED,
+       ATTRIBUTE_GNU_UNUSED,
+       ATTRIBUTE_GNU_NO_INSTRUMENT_FUNCTION,
+       ATTRIBUTE_GNU_WARN_UNUSED_RESULT,
+       ATTRIBUTE_GNU_LONGCALL,
+       ATTRIBUTE_GNU_SHORTCALL,
+       ATTRIBUTE_GNU_LONG_CALL,
+       ATTRIBUTE_GNU_SHORT_CALL,
+       ATTRIBUTE_GNU_FUNCTION_VECTOR,
+       ATTRIBUTE_GNU_INTERRUPT,
+       ATTRIBUTE_GNU_INTERRUPT_HANDLER,
+       ATTRIBUTE_GNU_NMI_HANDLER,
+       ATTRIBUTE_GNU_NESTING,
+       ATTRIBUTE_GNU_NEAR,
+       ATTRIBUTE_GNU_FAR,
+       ATTRIBUTE_GNU_SIGNAL,
+       ATTRIBUTE_GNU_EIGTHBIT_DATA,
+       ATTRIBUTE_GNU_TINY_DATA,
+       ATTRIBUTE_GNU_SAVEALL,
+       ATTRIBUTE_GNU_FLATTEN,
+       ATTRIBUTE_GNU_SSEREGPARM,
+       ATTRIBUTE_GNU_EXTERNALLY_VISIBLE,
+       ATTRIBUTE_GNU_RETURN_TWICE,
+       ATTRIBUTE_GNU_MAY_ALIAS,
+       ATTRIBUTE_GNU_MS_STRUCT,
+       ATTRIBUTE_GNU_GCC_STRUCT,
+       ATTRIBUTE_GNU_DLLIMPORT,
+       ATTRIBUTE_GNU_DLLEXPORT,
+       ATTRIBUTE_GNU_ALIGNED,
+       ATTRIBUTE_GNU_ALIAS,
+       ATTRIBUTE_GNU_SECTION,
+       ATTRIBUTE_GNU_FORMAT,
+       ATTRIBUTE_GNU_FORMAT_ARG,
+       ATTRIBUTE_GNU_WEAKREF,
+       ATTRIBUTE_GNU_NONNULL,
+       ATTRIBUTE_GNU_TLS_MODEL,
+       ATTRIBUTE_GNU_VISIBILITY,
+       ATTRIBUTE_GNU_REGPARM,
+       ATTRIBUTE_GNU_MODEL,
+       ATTRIBUTE_GNU_MODE,
+       ATTRIBUTE_GNU_TRAP_EXIT,
+       ATTRIBUTE_GNU_SP_SWITCH,
+       ATTRIBUTE_GNU_SENTINEL,
+       ATTRIBUTE_GNU_ASM,
+       ATTRIBUTE_GNU_LAST = ATTRIBUTE_GNU_ASM,
+       ATTRIBUTE_MS_FIRST,
+       ATTRIBUTE_MS_BASED = ATTRIBUTE_MS_FIRST,
+       ATTRIBUTE_MS_ALIGN,
+       ATTRIBUTE_MS_ALLOCATE,
+       ATTRIBUTE_MS_CDECL,
+       ATTRIBUTE_MS_FASTCALL,
+       ATTRIBUTE_MS_STDCALL,
+       ATTRIBUTE_MS_THISCALL,
+       ATTRIBUTE_MS_RESTRICT,
+       ATTRIBUTE_MS_DLLIMPORT,
+       ATTRIBUTE_MS_DLLEXPORT,
+       ATTRIBUTE_MS_THREAD,
+       ATTRIBUTE_MS_NAKED,
+       ATTRIBUTE_MS_FORCEINLINE,
+       ATTRIBUTE_MS_NOINLINE,
+       ATTRIBUTE_MS_RETURNS_TWICE,
+       ATTRIBUTE_MS_NORETURN,
+       ATTRIBUTE_MS_NOTHROW,
+       ATTRIBUTE_MS_NOVTABLE,
+       ATTRIBUTE_MS_PROPERTY,
+       ATTRIBUTE_MS_SELECTANY,
+       ATTRIBUTE_MS_UUID,
+       ATTRIBUTE_MS_DEPRECATED,
+       ATTRIBUTE_MS_NOALIAS,
+       ATTRIBUTE_MS_LAST = ATTRIBUTE_MS_NOALIAS,
+       ATTRIBUTE_LAST = ATTRIBUTE_MS_LAST
+} attribute_kind_t;
+
+typedef enum attribute_argument_kind_t {
+       ATTRIBUTE_ARGUMENT_SYMBOL,
+       ATTRIBUTE_ARGUMENT_EXPRESSION
+} attribute_argument_kind_t;
+
+/** this argument type should be fine for 99% of the arguments */
+typedef struct attribute_argument_t attribute_argument_t;
+struct attribute_argument_t {
+       attribute_argument_t      *next;
+       attribute_argument_kind_t  kind;
+       union {
+               symbol_t     *symbol;
+               expression_t *expression;
+       } v;
+};
+
+typedef struct attribute_property_argument_t attribute_property_argument_t;
+struct attribute_property_argument_t {
+       symbol_t *put_symbol;
+       symbol_t *get_symbol;
+};
+
+struct attribute_t {
+       source_position_t     source_position;
+       attribute_t          *next;
+       attribute_kind_t      kind;         /**< The kind of the GNU attribute. */
+       union {
+               attribute_argument_t          *arguments;
+               attribute_property_argument_t *property;
+       } a;
+};
+
+const char *get_attribute_name(attribute_kind_t kind);
+
+#endif
index 0e65930..a31cd0b 100644 (file)
--- a/entity.h
+++ b/entity.h
@@ -36,4 +36,6 @@ typedef struct function_t                   function_t;
 typedef struct compound_member_t            compound_member_t;
 typedef union  entity_t                     entity_t;
 
+typedef unsigned                            decl_modifiers_t;
+
 #endif
index b61be49..374d283 100644 (file)
@@ -23,6 +23,7 @@
 #include "lexer.h"
 #include "symbol.h"
 #include "entity.h"
+#include "attribute.h"
 #include <libfirm/firm_types.h>
 
 typedef enum {
@@ -75,24 +76,22 @@ typedef enum decl_modifier_t {
        DM_NOINLINE          = 1 << 10,
        DM_RESTRICT          = 1 << 11,
        DM_NOALIAS           = 1 << 12,
-       DM_PACKED            = 1 << 13,
-       DM_TRANSPARENT_UNION = 1 << 14,
-       DM_CONST             = 1 << 15,
-       DM_PURE              = 1 << 16,
-       DM_CONSTRUCTOR       = 1 << 17,
-       DM_DESTRUCTOR        = 1 << 18,
-       DM_UNUSED            = 1 << 19,
-       DM_USED              = 1 << 20,
-       DM_CDECL             = 1 << 21,
-       DM_FASTCALL          = 1 << 22,
-       DM_STDCALL           = 1 << 23,
-       DM_THISCALL          = 1 << 24,
-       DM_DEPRECATED        = 1 << 25,
-       DM_RETURNS_TWICE     = 1 << 26,
+       DM_TRANSPARENT_UNION = 1 << 13,
+       DM_CONST             = 1 << 14,
+       DM_PURE              = 1 << 15,
+       DM_CONSTRUCTOR       = 1 << 16,
+       DM_DESTRUCTOR        = 1 << 17,
+       DM_UNUSED            = 1 << 18,
+       DM_USED              = 1 << 19,
+       DM_CDECL             = 1 << 20,
+       DM_FASTCALL          = 1 << 21,
+       DM_STDCALL           = 1 << 22,
+       DM_THISCALL          = 1 << 23,
+       DM_DEPRECATED        = 1 << 24,
+       DM_RETURNS_TWICE     = 1 << 25,
+       DM_MALLOC            = 1 << 26,
 } decl_modifier_t;
 
-typedef unsigned decl_modifiers_t;
-
 /**
  * A scope containing entities.
  */
@@ -127,6 +126,11 @@ struct compound_t {
        scope_t           members;
        decl_modifiers_t  modifiers;
        bool              complete            : 1;
+       bool              transparent_union   : 1;
+       bool              packed              : 1;
+
+       il_alignment_t    alignment;
+       il_size_t         size;
 
        /* ast2firm info */
        ir_type          *irtype;
@@ -170,28 +174,29 @@ struct typedef_t {
        entity_base_t     base;
        decl_modifiers_t  modifiers;
        type_t           *type;
+       il_alignment_t    alignment;
        bool              builtin : 1;
 };
 
 struct declaration_t {
        entity_base_t     base;
+       type_t           *type;
        storage_class_t   declared_storage_class;
        storage_class_t   storage_class;
        decl_modifiers_t  modifiers;
-       const char       *deprecated_string;  /**< MS deprecated string if any. */
-       bool              used          : 1;  /**< Set if the declaration is used. */
-       bool              implicit      : 1;  /**< Set for implicit (not found in source code) declarations. */
-       type_t           *type;
+       il_alignment_t    alignment;
+       attribute_t      *attributes;
+       bool              used     : 1;  /**< Set if the declaration is used. */
+       bool              implicit : 1;  /**< Set for implicit (not found in source code) declarations. */
 
        /* ast2firm info */
        unsigned char     kind;
 };
 
 struct compound_member_t {
-       declaration_t  base;
-       unsigned char  alignment;
-       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. */
 
        /* ast2firm info */
        ir_entity *entity;
@@ -199,15 +204,16 @@ struct compound_member_t {
 };
 
 struct variable_t {
-       declaration_t  base;
-       bool           thread_local  : 1;  /**< GCC __thread */
-       bool           address_taken : 1;  /**< Set if the address of this declaration was taken. */
-       bool           read          : 1;
-       unsigned char  alignment;
-       symbol_t      *get_property_sym;   /**< MS get property. */
-       symbol_t      *put_property_sym;   /**< MS put property. */
+       declaration_t     base;
+       bool              thread_local  : 1;  /**< GCC __thread */
+       bool              restricta     : 1;
+       bool              deprecated    : 1;
+       bool              noalias       : 1;
+
+       bool              address_taken : 1;  /**< Set if the address of this declaration was taken. */
+       bool              read          : 1;
 
-       initializer_t *initializer;
+       initializer_t    *initializer;
 
        /* ast2firm info */
        union {
@@ -286,6 +292,7 @@ typedef enum builtin_kind_t {
 struct function_t {
        declaration_t  base;
        bool           is_inline     : 1;
+
        bool           need_closure  : 1;  /**< Inner function needs closure. */
        bool           goto_to_outer : 1;  /**< Inner function has goto to outer function. */
 
@@ -317,14 +324,22 @@ union entity_t {
        compound_member_t  compound_member;
 };
 
+#define DECLARATION_KIND_CASES        \
+       case ENTITY_FUNCTION:             \
+       case ENTITY_VARIABLE:             \
+       case ENTITY_PARAMETER:            \
+       case ENTITY_COMPOUND_MEMBER:
+
 static inline bool is_declaration(const entity_t *entity)
 {
-       return entity->kind == ENTITY_FUNCTION || entity->kind == ENTITY_VARIABLE
-               || entity->kind == ENTITY_PARAMETER
-               || entity->kind == ENTITY_COMPOUND_MEMBER;
+       switch(entity->kind) {
+       DECLARATION_KIND_CASES
+               return true;
+       default:
+               return false;
+       }
 }
 
-
 const char *get_entity_kind_name(entity_kind_t kind);
 
 #endif
index bcd78d6..98fc1d7 100644 (file)
--- a/mangle.c
+++ b/mangle.c
@@ -261,12 +261,11 @@ ident *create_name_win32(entity_t *entity)
 
        assert(is_declaration(entity));
 
-       if (entity->declaration.modifiers & DM_DLLIMPORT) {
-               /* add prefix for imported symbols */
-               obstack_printf(o, "__imp_");
-       }
-
        if (entity->kind == ENTITY_FUNCTION) {
+               if (entity->declaration.modifiers & DM_DLLIMPORT)
+                       /* add prefix for imported symbols */
+                       obstack_printf(o, "__imp_");
+
                cc_kind_t cc = entity->declaration.type->function.calling_convention;
 
                /* calling convention prefix */
index aebe73a..ebecc3d 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -34,6 +34,7 @@
 #include "type_hash.h"
 #include "ast_t.h"
 #include "entity_t.h"
+#include "attribute_t.h"
 #include "lang_features.h"
 #include "walk_statements.h"
 #include "warning.h"
@@ -50,27 +51,6 @@ typedef struct {
        entity_namespace_t  namespc;
 } stack_entry_t;
 
-typedef struct argument_list_t argument_list_t;
-struct argument_list_t {
-       long              argument;
-       argument_list_t  *next;
-};
-
-typedef struct gnu_attribute_t gnu_attribute_t;
-struct gnu_attribute_t {
-       gnu_attribute_kind_t kind;          /**< The kind of the GNU attribute. */
-       gnu_attribute_t     *next;
-       bool                 invalid;       /**< Set if this attribute had argument errors, */
-       bool                 has_arguments; /**< True, if this attribute has arguments. */
-       union {
-               size_t              value;
-               string_t            string;
-               symbol_t           *symbol;
-               long                argument;  /**< Single argument. */
-               argument_list_t    *arguments; /**< List of argument expressions. */
-       } u;
-};
-
 typedef struct declaration_specifiers_t  declaration_specifiers_t;
 struct declaration_specifiers_t {
        source_position_t  source_position;
@@ -79,11 +59,7 @@ struct declaration_specifiers_t {
        bool               is_inline    : 1;
        bool               thread_local : 1;  /**< GCC __thread */
        bool               deprecated   : 1;
-       decl_modifiers_t   modifiers;         /**< declaration modifiers */
-       gnu_attribute_t   *gnu_attributes;    /**< list of GNU attributes */
-       const char        *deprecated_string; /**< can be set if declaration was marked deprecated. */
-       symbol_t          *get_property_sym;  /**< the name of the get property if set. */
-       symbol_t          *put_property_sym;  /**< the name of the put property if set. */
+       attribute_t       *attributes;        /**< list of attributes */
        type_t            *type;
 };
 
@@ -141,27 +117,6 @@ static declaration_t      **incomplete_arrays;
 /** special symbol used for anonymous entities. */
 static const symbol_t *sym_anonymous = NULL;
 
-/* symbols for Microsoft extended-decl-modifier */
-static const symbol_t *sym_align         = NULL;
-static const symbol_t *sym_allocate      = NULL;
-static const symbol_t *sym_dllimport     = NULL;
-static const symbol_t *sym_dllexport     = NULL;
-static const symbol_t *sym_naked         = NULL;
-static const symbol_t *sym_noinline      = NULL;
-static const symbol_t *sym_returns_twice = NULL;
-static const symbol_t *sym_noreturn      = NULL;
-static const symbol_t *sym_nothrow       = NULL;
-static const symbol_t *sym_novtable      = NULL;
-static const symbol_t *sym_property      = NULL;
-static const symbol_t *sym_get           = NULL;
-static const symbol_t *sym_put           = NULL;
-static const symbol_t *sym_selectany     = NULL;
-static const symbol_t *sym_thread        = NULL;
-static const symbol_t *sym_uuid          = NULL;
-static const symbol_t *sym_deprecated    = NULL;
-static const symbol_t *sym_restrict      = NULL;
-static const symbol_t *sym_noalias       = NULL;
-
 /** The token anchor set */
 static unsigned char token_anchor_set[T_LAST_TOKEN];
 
@@ -245,6 +200,11 @@ static void create_microsoft_intrinsics(void);
        case T_unsigned:          \
        case T_void:              \
        case T_wchar_t:           \
+       case T__int8:             \
+       case T__int16:            \
+       case T__int32:            \
+       case T__int64:            \
+       case T__int128:           \
        COMPLEX_SPECIFIERS        \
        IMAGINARY_SPECIFIERS
 
@@ -1230,75 +1190,6 @@ static string_t parse_string_literals(void)
        return result;
 }
 
-static const char *const gnu_attribute_names[GNU_AK_LAST] = {
-       [GNU_AK_CONST]                  = "const",
-       [GNU_AK_VOLATILE]               = "volatile",
-       [GNU_AK_CDECL]                  = "cdecl",
-       [GNU_AK_STDCALL]                = "stdcall",
-       [GNU_AK_FASTCALL]               = "fastcall",
-       [GNU_AK_DEPRECATED]             = "deprecated",
-       [GNU_AK_NOINLINE]               = "noinline",
-       [GNU_AK_RETURNS_TWICE]          = "returns_twice",
-       [GNU_AK_NORETURN]               = "noreturn",
-       [GNU_AK_NAKED]                  = "naked",
-       [GNU_AK_PURE]                   = "pure",
-       [GNU_AK_ALWAYS_INLINE]          = "always_inline",
-       [GNU_AK_MALLOC]                 = "malloc",
-       [GNU_AK_WEAK]                   = "weak",
-       [GNU_AK_CONSTRUCTOR]            = "constructor",
-       [GNU_AK_DESTRUCTOR]             = "destructor",
-       [GNU_AK_NOTHROW]                = "nothrow",
-       [GNU_AK_TRANSPARENT_UNION]      = "transparent_union",
-       [GNU_AK_COMMON]                 = "common",
-       [GNU_AK_NOCOMMON]               = "nocommon",
-       [GNU_AK_PACKED]                 = "packed",
-       [GNU_AK_SHARED]                 = "shared",
-       [GNU_AK_NOTSHARED]              = "notshared",
-       [GNU_AK_USED]                   = "used",
-       [GNU_AK_UNUSED]                 = "unused",
-       [GNU_AK_NO_INSTRUMENT_FUNCTION] = "no_instrument_function",
-       [GNU_AK_WARN_UNUSED_RESULT]     = "warn_unused_result",
-       [GNU_AK_LONGCALL]               = "longcall",
-       [GNU_AK_SHORTCALL]              = "shortcall",
-       [GNU_AK_LONG_CALL]              = "long_call",
-       [GNU_AK_SHORT_CALL]             = "short_call",
-       [GNU_AK_FUNCTION_VECTOR]        = "function_vector",
-       [GNU_AK_INTERRUPT]              = "interrupt",
-       [GNU_AK_INTERRUPT_HANDLER]      = "interrupt_handler",
-       [GNU_AK_NMI_HANDLER]            = "nmi_handler",
-       [GNU_AK_NESTING]                = "nesting",
-       [GNU_AK_NEAR]                   = "near",
-       [GNU_AK_FAR]                    = "far",
-       [GNU_AK_SIGNAL]                 = "signal",
-       [GNU_AK_EIGTHBIT_DATA]          = "eightbit_data",
-       [GNU_AK_TINY_DATA]              = "tiny_data",
-       [GNU_AK_SAVEALL]                = "saveall",
-       [GNU_AK_FLATTEN]                = "flatten",
-       [GNU_AK_SSEREGPARM]             = "sseregparm",
-       [GNU_AK_EXTERNALLY_VISIBLE]     = "externally_visible",
-       [GNU_AK_RETURN_TWICE]           = "return_twice",
-       [GNU_AK_MAY_ALIAS]              = "may_alias",
-       [GNU_AK_MS_STRUCT]              = "ms_struct",
-       [GNU_AK_GCC_STRUCT]             = "gcc_struct",
-       [GNU_AK_DLLIMPORT]              = "dllimport",
-       [GNU_AK_DLLEXPORT]              = "dllexport",
-       [GNU_AK_ALIGNED]                = "aligned",
-       [GNU_AK_ALIAS]                  = "alias",
-       [GNU_AK_SECTION]                = "section",
-       [GNU_AK_FORMAT]                 = "format",
-       [GNU_AK_FORMAT_ARG]             = "format_arg",
-       [GNU_AK_WEAKREF]                = "weakref",
-       [GNU_AK_NONNULL]                = "nonnull",
-       [GNU_AK_TLS_MODEL]              = "tls_model",
-       [GNU_AK_VISIBILITY]             = "visibility",
-       [GNU_AK_REGPARM]                = "regparm",
-       [GNU_AK_MODE]                   = "mode",
-       [GNU_AK_MODEL]                  = "model",
-       [GNU_AK_TRAP_EXIT]              = "trap_exit",
-       [GNU_AK_SP_SWITCH]              = "sp_switch",
-       [GNU_AK_SENTINEL]               = "sentinel"
-};
-
 /**
  * compare two string, ignoring double underscores on the second.
  */
@@ -1315,620 +1206,281 @@ static int strcmp_underscore(const char *s1, const char *s2)
        return strcmp(s1, s2);
 }
 
-/**
- * Allocate a new gnu temporal attribute of given kind.
- */
-static gnu_attribute_t *allocate_gnu_attribute(gnu_attribute_kind_t kind)
+static attribute_t *allocate_attribute_zero(attribute_kind_t kind)
 {
-       gnu_attribute_t *attribute = obstack_alloc(&temp_obst, sizeof(*attribute));
-       attribute->kind            = kind;
-       attribute->next            = NULL;
-       attribute->invalid         = false;
-       attribute->has_arguments   = false;
-
+       attribute_t *attribute = allocate_ast_zero(sizeof(*attribute));
+       attribute->kind        = kind;
        return attribute;
 }
 
 /**
- * Parse one constant expression argument of the given attribute.
+ * Parse (gcc) attribute argument. From gcc comments in gcc source:
+ *
+ *  attribute:
+ *    __attribute__ ( ( attribute-list ) )
+ *
+ *  attribute-list:
+ *    attrib
+ *    attribute_list , attrib
+ *
+ *  attrib:
+ *    empty
+ *    any-word
+ *    any-word ( identifier )
+ *    any-word ( identifier , nonempty-expr-list )
+ *    any-word ( expr-list )
+ *
+ *  where the "identifier" must not be declared as a type, and
+ *  "any-word" may be any identifier (including one declared as a
+ *  type), a reserved word storage class specifier, type specifier or
+ *  type qualifier.  ??? This still leaves out most reserved keywords
+ *  (following the old parser), shouldn't we include them, and why not
+ *  allow identifiers declared as types to start the arguments?
+ *
+ *  Matze: this all looks confusing and little systematic, so we're even less
+ *  strict and parse any list of things which are identifiers or
+ *  (assignment-)expressions.
  */
-static void parse_gnu_attribute_const_arg(gnu_attribute_t *attribute)
+static attribute_argument_t *parse_attribute_arguments(void)
 {
-       expression_t *expression;
-       add_anchor_token(')');
-       expression = parse_constant_expression();
-       rem_anchor_token(')');
-       expect(')', end_error);
-       attribute->u.argument = fold_constant(expression);
-       return;
-end_error:
-       attribute->invalid = true;
-}
+       if (token.type == ')')
+               return NULL;
 
-/**
- * Parse a list of constant expressions arguments of the given attribute.
- */
-static void parse_gnu_attribute_const_arg_list(gnu_attribute_t *attribute)
-{
-       argument_list_t **list = &attribute->u.arguments;
-       argument_list_t  *entry;
-       expression_t     *expression;
-       add_anchor_token(')');
-       add_anchor_token(',');
+       attribute_argument_t *first = NULL;
+       attribute_argument_t *last  = NULL;
        while (true) {
-               expression = parse_constant_expression();
-               entry = obstack_alloc(&temp_obst, sizeof(entry));
-               entry->argument = fold_constant(expression);
-               entry->next     = NULL;
-               *list = entry;
-               list = &entry->next;
-               if (token.type != ',')
-                       break;
-               next_token();
-       }
-       rem_anchor_token(',');
-       rem_anchor_token(')');
-       expect(')', end_error);
-       return;
-end_error:
-       attribute->invalid = true;
-}
-
-/**
- * Parse one string literal argument of the given attribute.
- */
-static void parse_gnu_attribute_string_arg(gnu_attribute_t *attribute,
-                                           string_t *string)
-{
-       add_anchor_token('(');
-       if (token.type != T_STRING_LITERAL) {
-               parse_error_expected("while parsing attribute directive",
-                                    T_STRING_LITERAL, NULL);
-               goto end_error;
-       }
-       *string = parse_string_literals();
-       rem_anchor_token('(');
-       expect(')', end_error);
-       return;
-end_error:
-       attribute->invalid = true;
-}
+               attribute_argument_t *argument = allocate_ast_zero(sizeof(*argument));
+
+               /* is it an identifier */
+               if (token.type == T_IDENTIFIER
+                               && (look_ahead(1)->type == ',' || look_ahead(1)->type == ')')) {
+                       symbol_t *symbol   = token.v.symbol;
+                       argument->kind     = ATTRIBUTE_ARGUMENT_SYMBOL;
+                       argument->v.symbol = symbol;
+                       next_token();
+               } else {
+                       /* must be an expression */
+                       expression_t *expression = parse_assignment_expression();
 
-/**
- * Parse one tls model of the given attribute.
- */
-static void parse_gnu_attribute_tls_model_arg(gnu_attribute_t *attribute)
-{
-       static const char *const tls_models[] = {
-               "global-dynamic",
-               "local-dynamic",
-               "initial-exec",
-               "local-exec"
-       };
-       string_t string = { NULL, 0 };
-       parse_gnu_attribute_string_arg(attribute, &string);
-       if (string.begin != NULL) {
-               for (size_t i = 0; i < 4; ++i) {
-                       if (strcmp(tls_models[i], string.begin) == 0) {
-                               attribute->u.value = i;
-                               return;
-                       }
+                       argument->kind         = ATTRIBUTE_ARGUMENT_EXPRESSION;
+                       argument->v.expression = expression;
                }
-               errorf(HERE, "'%s' is an unrecognized tls model", string.begin);
-       }
-       attribute->invalid = true;
-}
 
-/**
- * Parse one tls model of the given attribute.
- */
-static void parse_gnu_attribute_visibility_arg(gnu_attribute_t *attribute)
-{
-       static const char *const visibilities[] = {
-               "default",
-               "protected",
-               "hidden",
-               "internal"
-       };
-       string_t string = { NULL, 0 };
-       parse_gnu_attribute_string_arg(attribute, &string);
-       if (string.begin != NULL) {
-               for (size_t i = 0; i < 4; ++i) {
-                       if (strcmp(visibilities[i], string.begin) == 0) {
-                               attribute->u.value = i;
-                               return;
-                       }
+               /* append argument */
+               if (last == NULL) {
+                       first = argument;
+               } else {
+                       last->next = argument;
                }
-               errorf(HERE, "'%s' is an unrecognized visibility", string.begin);
-       }
-       attribute->invalid = true;
-}
+               last = argument;
 
-/**
- * Parse one (code) model of the given attribute.
- */
-static void parse_gnu_attribute_model_arg(gnu_attribute_t *attribute)
-{
-       static const char *const visibilities[] = {
-               "small",
-               "medium",
-               "large"
-       };
-       string_t string = { NULL, 0 };
-       parse_gnu_attribute_string_arg(attribute, &string);
-       if (string.begin != NULL) {
-               for (int i = 0; i < 3; ++i) {
-                       if (strcmp(visibilities[i], string.begin) == 0) {
-                               attribute->u.value = i;
-                               return;
-                       }
+               if (token.type == ',') {
+                       next_token();
+                       continue;
                }
-               errorf(HERE, "'%s' is an unrecognized model", string.begin);
+               expect(')', end_error);
+               break;
        }
-       attribute->invalid = true;
+
+       return first;
+
+end_error:
+       /* TODO... */
+       return first;
 }
 
-/**
- * Parse one mode of the given attribute.
- */
-static void parse_gnu_attribute_mode_arg(gnu_attribute_t *attribute)
+static attribute_t *parse_attribute_asm(void)
 {
-       add_anchor_token(')');
+       eat(T_asm);
 
-       if (token.type != T_IDENTIFIER) {
-               expect(T_IDENTIFIER, end_error);
-       }
+       attribute_t *attribute = allocate_attribute_zero(ATTRIBUTE_GNU_ASM);
 
-       attribute->u.symbol = token.v.symbol;
-       next_token();
+       expect('(', end_error);
+       attribute->a.arguments = parse_attribute_arguments();
+       return attribute;
 
-       rem_anchor_token(')');
-       expect(')', end_error);
-       return;
 end_error:
-       attribute->invalid = true;
+       return NULL;
 }
 
-/**
- * Parse one interrupt argument of the given attribute.
- */
-static void parse_gnu_attribute_interrupt_arg(gnu_attribute_t *attribute)
+static symbol_t *get_symbol_from_token(void)
 {
-       static const char *const interrupts[] = {
-               "IRQ",
-               "FIQ",
-               "SWI",
-               "ABORT",
-               "UNDEF"
-       };
-       string_t string = { NULL, 0 };
-       parse_gnu_attribute_string_arg(attribute, &string);
-       if (string.begin != NULL) {
-               for (size_t i = 0; i < 5; ++i) {
-                       if (strcmp(interrupts[i], string.begin) == 0) {
-                               attribute->u.value = i;
-                               return;
-                       }
-               }
-               errorf(HERE, "'%s' is not an interrupt", string.begin);
+       switch(token.type) {
+       case T_IDENTIFIER:
+       case T_auto:
+       case T_char:
+       case T_double:
+       case T_enum:
+       case T_extern:
+       case T_float:
+       case T_int:
+       case T_long:
+       case T_register:
+       case T_short:
+       case T_static:
+       case T_struct:
+       case T_union:
+       case T_unsigned:
+       case T_void:
+       case T_bool:
+       case T__Bool:
+       case T_class:
+       case T_explicit:
+       case T_export:
+       case T_wchar_t:
+       case T_const:
+       case T_signed:
+       case T___real__:
+       case T___imag__:
+       case T_restrict:
+       case T_volatile:
+       case T_inline:
+               /* maybe we need more tokens ... add them on demand */
+               return token.v.symbol;
+       default:
+               return NULL;
        }
-       attribute->invalid = true;
 }
 
-/**
- * Parse ( identifier, const expression, const expression )
- */
-static void parse_gnu_attribute_format_args(gnu_attribute_t *attribute)
+static attribute_t *parse_attribute_gnu_single(void)
 {
-       static const char *const format_names[] = {
-               "printf",
-               "scanf",
-               "strftime",
-               "strfmon"
-       };
-       int i;
-
-       if (token.type != T_IDENTIFIER) {
-               parse_error_expected("while parsing format attribute directive", T_IDENTIFIER, NULL);
+       /* parse "any-word" */
+       symbol_t *symbol = get_symbol_from_token();
+       if (symbol == NULL) {
+               parse_error_expected("while parsing attribute((", T_IDENTIFIER, NULL);
                goto end_error;
        }
-       const char *name = token.v.symbol->string;
-       for (i = 0; i < 4; ++i) {
-               if (strcmp_underscore(format_names[i], name) == 0)
+
+       const char *name = symbol->string;
+       next_token();
+
+       attribute_kind_t kind;
+       for (kind = ATTRIBUTE_GNU_FIRST; kind <= ATTRIBUTE_GNU_LAST; ++kind) {
+               const char *attribute_name = get_attribute_name(kind);
+               if (attribute_name != NULL
+                               && strcmp_underscore(attribute_name, name) == 0)
                        break;
        }
-       if (i >= 4) {
-               if (warning.attribute)
-                       warningf(HERE, "'%s' is an unrecognized format function type", name);
+
+       if (kind >= ATTRIBUTE_GNU_LAST) {
+               if (warning.attribute) {
+                       warningf(HERE, "unknown attribute '%s' ignored", name);
+               }
+               /* TODO: we should still save the attribute in the list... */
+               kind = ATTRIBUTE_UNKNOWN;
        }
-       next_token();
 
-       expect(',', end_error);
-       add_anchor_token(')');
-       add_anchor_token(',');
-       parse_constant_expression();
-       rem_anchor_token(',');
-       rem_anchor_token(')');
+       attribute_t *attribute = allocate_attribute_zero(kind);
 
-       expect(',', end_error);
-       add_anchor_token(')');
-       parse_constant_expression();
-       rem_anchor_token(')');
-       expect(')', end_error);
-       return;
-end_error:
-       attribute->u.value = true;
-}
+       /* parse arguments */
+       if (token.type == '(') {
+               next_token();
+               attribute->a.arguments = parse_attribute_arguments();
+       }
 
-/**
- * Check that a given GNU attribute has no arguments.
- */
-static void check_no_argument(gnu_attribute_t *attribute, const char *name)
-{
-       if (!attribute->has_arguments)
-               return;
+       return attribute;
 
-       /* should have no arguments */
-       errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
-       eat_until_matching_token('(');
-       /* we have already consumed '(', so we stop before ')', eat it */
-       next_token();
-       attribute->invalid = true;
+end_error:
+       return NULL;
 }
 
-/**
- * Parse one GNU attribute.
- *
- * Note that attribute names can be specified WITH or WITHOUT
- * double underscores, ie const or __const__.
- *
- * The following attributes are parsed without arguments
- *  const
- *  volatile
- *  cdecl
- *  stdcall
- *  fastcall
- *  deprecated
- *  noinline
- *  noreturn
- *  naked
- *  pure
- *  always_inline
- *  malloc
- *  weak
- *  constructor
- *  destructor
- *  nothrow
- *  transparent_union
- *  common
- *  nocommon
- *  packed
- *  shared
- *  notshared
- *  used
- *  unused
- *  no_instrument_function
- *  warn_unused_result
- *  longcall
- *  shortcall
- *  long_call
- *  short_call
- *  function_vector
- *  interrupt_handler
- *  nmi_handler
- *  nesting
- *  near
- *  far
- *  signal
- *  eightbit_data
- *  tiny_data
- *  saveall
- *  flatten
- *  sseregparm
- *  externally_visible
- *  return_twice
- *  may_alias
- *  ms_struct
- *  gcc_struct
- *  dllimport
- *  dllexport
- *
- * The following attributes are parsed with arguments
- *  aligned( const expression )
- *  alias( string literal )
- *  section( string literal )
- *  format( identifier, const expression, const expression )
- *  format_arg( const expression )
- *  tls_model( string literal )
- *  visibility( string literal )
- *  regparm( const expression )
- *  model( string leteral )
- *  trap_exit( const expression )
- *  sp_switch( string literal )
- *
- * The following attributes might have arguments
- *  weak_ref( string literal )
- *  non_null( const expression // ',' )
- *  interrupt( string literal )
- *  sentinel( constant expression )
- */
-static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes)
+static attribute_t *parse_attribute_gnu(void)
 {
-       gnu_attribute_t *head      = *attributes;
-       gnu_attribute_t *last      = *attributes;
-       decl_modifiers_t modifiers = 0;
-       gnu_attribute_t *attribute;
+       attribute_t *first = NULL;
+       attribute_t *last  = NULL;
 
        eat(T___attribute__);
        expect('(', end_error);
        expect('(', end_error);
 
-       if (token.type != ')') {
-               /* find the end of the list */
-               if (last != NULL) {
-                       while (last->next != NULL)
-                               last = last->next;
-               }
-
-               /* non-empty attribute list */
-               while (true) {
-                       const char *name;
-                       if (token.type == T_const) {
-                               name = "const";
-                       } else if (token.type == T_volatile) {
-                               name = "volatile";
-                       } else if (token.type == T_cdecl) {
-                               /* __attribute__((cdecl)), WITH ms mode */
-                               name = "cdecl";
-                       } else if (token.type == T_IDENTIFIER) {
-                               const symbol_t *sym = token.v.symbol;
-                               name = sym->string;
-                       } else {
-                               parse_error_expected("while parsing GNU attribute", T_IDENTIFIER, NULL);
-                               break;
-                       }
-
-                       next_token();
-
-                       int i;
-                       for (i = 0; i < GNU_AK_LAST; ++i) {
-                               if (strcmp_underscore(gnu_attribute_names[i], name) == 0)
-                                       break;
-                       }
-                       gnu_attribute_kind_t kind = (gnu_attribute_kind_t)i;
-
-                       attribute = NULL;
-                       if (kind == GNU_AK_LAST) {
-                               if (warning.attribute)
-                                       warningf(HERE, "'%s' attribute directive ignored", name);
-
-                               /* skip possible arguments */
-                               if (token.type == '(') {
-                                       eat_until_matching_token(')');
-                                       next_token(); /* skip the ')' */
-                               }
-                       } else {
-                               /* check for arguments */
-                               attribute = allocate_gnu_attribute(kind);
-                               if (token.type == '(') {
-                                       next_token();
-                                       if (token.type == ')') {
-                                               /* empty args are allowed */
-                                               next_token();
-                                       } else
-                                               attribute->has_arguments = true;
-                               }
-
-                               switch (kind) {
-                               case GNU_AK_VOLATILE:
-                               case GNU_AK_NAKED:
-                               case GNU_AK_MALLOC:
-                               case GNU_AK_WEAK:
-                               case GNU_AK_COMMON:
-                               case GNU_AK_NOCOMMON:
-                               case GNU_AK_SHARED:
-                               case GNU_AK_NOTSHARED:
-                               case GNU_AK_NO_INSTRUMENT_FUNCTION:
-                               case GNU_AK_WARN_UNUSED_RESULT:
-                               case GNU_AK_LONGCALL:
-                               case GNU_AK_SHORTCALL:
-                               case GNU_AK_LONG_CALL:
-                               case GNU_AK_SHORT_CALL:
-                               case GNU_AK_FUNCTION_VECTOR:
-                               case GNU_AK_INTERRUPT_HANDLER:
-                               case GNU_AK_NMI_HANDLER:
-                               case GNU_AK_NESTING:
-                               case GNU_AK_NEAR:
-                               case GNU_AK_FAR:
-                               case GNU_AK_SIGNAL:
-                               case GNU_AK_EIGTHBIT_DATA:
-                               case GNU_AK_TINY_DATA:
-                               case GNU_AK_SAVEALL:
-                               case GNU_AK_FLATTEN:
-                               case GNU_AK_SSEREGPARM:
-                               case GNU_AK_EXTERNALLY_VISIBLE:
-                               case GNU_AK_RETURN_TWICE:
-                               case GNU_AK_MAY_ALIAS:
-                               case GNU_AK_MS_STRUCT:
-                               case GNU_AK_GCC_STRUCT:
-                                       goto no_arg;
-
-                               case GNU_AK_CDECL:             modifiers |= DM_CDECL;             goto no_arg;
-                               case GNU_AK_FASTCALL:          modifiers |= DM_FASTCALL;          goto no_arg;
-                               case GNU_AK_STDCALL:           modifiers |= DM_STDCALL;           goto no_arg;
-                               case GNU_AK_UNUSED:            modifiers |= DM_UNUSED;            goto no_arg;
-                               case GNU_AK_USED:              modifiers |= DM_USED;              goto no_arg;
-                               case GNU_AK_PURE:              modifiers |= DM_PURE;              goto no_arg;
-                               case GNU_AK_CONST:             modifiers |= DM_CONST;             goto no_arg;
-                               case GNU_AK_ALWAYS_INLINE:     modifiers |= DM_FORCEINLINE;       goto no_arg;
-                               case GNU_AK_DLLIMPORT:         modifiers |= DM_DLLIMPORT;         goto no_arg;
-                               case GNU_AK_DLLEXPORT:         modifiers |= DM_DLLEXPORT;         goto no_arg;
-                               case GNU_AK_PACKED:            modifiers |= DM_PACKED;            goto no_arg;
-                               case GNU_AK_NOINLINE:          modifiers |= DM_NOINLINE;          goto no_arg;
-                               case GNU_AK_RETURNS_TWICE:     modifiers |= DM_RETURNS_TWICE;     goto no_arg;
-                               case GNU_AK_NORETURN:          modifiers |= DM_NORETURN;          goto no_arg;
-                               case GNU_AK_NOTHROW:           modifiers |= DM_NOTHROW;           goto no_arg;
-                               case GNU_AK_TRANSPARENT_UNION: modifiers |= DM_TRANSPARENT_UNION; goto no_arg;
-                               case GNU_AK_CONSTRUCTOR:       modifiers |= DM_CONSTRUCTOR;       goto no_arg;
-                               case GNU_AK_DESTRUCTOR:        modifiers |= DM_DESTRUCTOR;        goto no_arg;
-                               case GNU_AK_DEPRECATED:        modifiers |= DM_DEPRECATED;        goto no_arg;
-
-                               case GNU_AK_ALIGNED:
-                                       /* __align__ may be used without an argument */
-                                       if (attribute->has_arguments) {
-                                               parse_gnu_attribute_const_arg(attribute);
-                                       }
-                                       break;
+       if (token.type == ')') {
+               next_token();
+               expect(')', end_error);
+               return first;
+       }
 
-                               case GNU_AK_FORMAT_ARG:
-                               case GNU_AK_REGPARM:
-                               case GNU_AK_TRAP_EXIT:
-                                       if (!attribute->has_arguments) {
-                                               /* should have arguments */
-                                               errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
-                                               attribute->invalid = true;
-                                       } else
-                                               parse_gnu_attribute_const_arg(attribute);
-                                       break;
-                               case GNU_AK_ALIAS:
-                               case GNU_AK_SECTION:
-                               case GNU_AK_SP_SWITCH:
-                                       if (!attribute->has_arguments) {
-                                               /* should have arguments */
-                                               errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
-                                               attribute->invalid = true;
-                                       } else
-                                               parse_gnu_attribute_string_arg(attribute, &attribute->u.string);
-                                       break;
-                               case GNU_AK_FORMAT:
-                                       if (!attribute->has_arguments) {
-                                               /* should have arguments */
-                                               errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
-                                               attribute->invalid = true;
-                                       } else
-                                               parse_gnu_attribute_format_args(attribute);
-                                       break;
-                               case GNU_AK_WEAKREF:
-                                       /* may have one string argument */
-                                       if (attribute->has_arguments)
-                                               parse_gnu_attribute_string_arg(attribute, &attribute->u.string);
-                                       break;
-                               case GNU_AK_NONNULL:
-                                       if (attribute->has_arguments)
-                                               parse_gnu_attribute_const_arg_list(attribute);
-                                       break;
-                               case GNU_AK_TLS_MODEL:
-                                       if (!attribute->has_arguments) {
-                                               /* should have arguments */
-                                               errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
-                                       } else
-                                               parse_gnu_attribute_tls_model_arg(attribute);
-                                       break;
-                               case GNU_AK_VISIBILITY:
-                                       if (!attribute->has_arguments) {
-                                               /* should have arguments */
-                                               errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
-                                       } else
-                                               parse_gnu_attribute_visibility_arg(attribute);
-                                       break;
-                               case GNU_AK_MODEL:
-                                       if (!attribute->has_arguments) {
-                                               /* should have arguments */
-                                               errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
-                                       } else {
-                                               parse_gnu_attribute_model_arg(attribute);
-                                       }
-                                       break;
-                               case GNU_AK_MODE:
-                                       if (!attribute->has_arguments) {
-                                               /* should have arguments */
-                                               errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
-                                       } else {
-                                               parse_gnu_attribute_mode_arg(attribute);
-                                       }
-                                       break;
-                               case GNU_AK_INTERRUPT:
-                                       /* may have one string argument */
-                                       if (attribute->has_arguments)
-                                               parse_gnu_attribute_interrupt_arg(attribute);
-                                       break;
-                               case GNU_AK_SENTINEL:
-                                       /* may have one string argument */
-                                       if (attribute->has_arguments)
-                                               parse_gnu_attribute_const_arg(attribute);
-                                       break;
-                               case GNU_AK_LAST:
-                                       /* already handled */
-                                       break;
+       while (true) {
+               attribute_t *attribute = parse_attribute_gnu_single();
+               if (attribute == NULL)
+                       goto end_error;
 
-no_arg:
-                                       check_no_argument(attribute, name);
-                               }
-                       }
-                       if (attribute != NULL) {
-                               if (last != NULL) {
-                                       last->next = attribute;
-                                       last       = attribute;
-                               } else {
-                                       head = last = attribute;
-                               }
-                       }
+               if (last == NULL) {
+                       first = attribute;
+               } else {
+                       last->next = attribute;
+               }
+               last = attribute;
 
-                       if (token.type != ',')
-                               break;
+               if (token.type == ')') {
                        next_token();
+                       break;
                }
+               expect(',', end_error);
        }
        expect(')', end_error);
-       expect(')', end_error);
-end_error:
-       *attributes = head;
 
-       return modifiers;
+end_error:
+       return first;
 }
 
-/**
- * Parse GNU attributes.
- */
-static decl_modifiers_t parse_attributes(gnu_attribute_t **attributes)
+/** Parse attributes. */
+static attribute_t *parse_attributes(attribute_t *first)
 {
-       decl_modifiers_t modifiers = 0;
-
+       attribute_t *last = first;
        while (true) {
+               if (last != NULL) {
+                       while (last->next != NULL)
+                               last = last->next;
+               }
+
+               attribute_t *attribute;
                switch (token.type) {
                case T___attribute__:
-                       modifiers |= parse_gnu_attribute(attributes);
-                       continue;
+                       attribute = parse_attribute_gnu();
+                       break;
 
                case T_asm:
+                       attribute = parse_attribute_asm();
+                       break;
+
+               case T_cdecl:
                        next_token();
-                       expect('(', end_error);
-                       if (token.type != T_STRING_LITERAL) {
-                               parse_error_expected("while parsing assembler attribute",
-                                                    T_STRING_LITERAL, NULL);
-                               eat_until_matching_token('(');
-                               break;
-                       } else {
-                               parse_string_literals();
-                       }
-                       expect(')', end_error);
-                       continue;
+                       attribute = allocate_attribute_zero(ATTRIBUTE_MS_CDECL);
+                       break;
+
+               case T__fastcall:
+                       next_token();
+                       attribute = allocate_attribute_zero(ATTRIBUTE_MS_FASTCALL);
+                       break;
 
-               case T_cdecl:     modifiers |= DM_CDECL;    break;
-               case T__fastcall: modifiers |= DM_FASTCALL; break;
-               case T__stdcall:  modifiers |= DM_STDCALL;  break;
+               case T__forceinline:
+                       next_token();
+                       attribute = allocate_attribute_zero(ATTRIBUTE_MS_FORCEINLINE);
+                       break;
+
+               case T__stdcall:
+                       next_token();
+                       attribute = allocate_attribute_zero(ATTRIBUTE_MS_STDCALL);
+                       break;
 
                case T___thiscall:
+                       next_token();
                        /* TODO record modifier */
                        if (warning.other)
                                warningf(HERE, "Ignoring declaration modifier %K", &token);
+                       attribute = allocate_attribute_zero(ATTRIBUTE_MS_THISCALL);
                        break;
 
-end_error:
-               default: return modifiers;
+               default:
+                       return first;
                }
 
-               next_token();
+               if (last == NULL) {
+                       first = attribute;
+               } else {
+                       last->next = attribute;
+               }
+               last = attribute;
        }
 }
 
@@ -2641,18 +2193,6 @@ static void advance_current_object(type_path_t *path, size_t top_path_level)
        }
 }
 
-/**
- * skip until token is found.
- */
-static void skip_until(int type)
-{
-       while (token.type != type) {
-               if (token.type == T_EOF)
-                       return;
-               next_token();
-       }
-}
-
 /**
  * skip any {...} blocks until a closing bracket is reached.
  */
@@ -2986,8 +2526,6 @@ static void append_entity(scope_t *scope, entity_t *entity)
 
 static compound_t *parse_compound_type_specifier(bool is_struct)
 {
-       gnu_attribute_t  *attributes = NULL;
-       decl_modifiers_t  modifiers  = 0;
        if (is_struct) {
                eat(T_struct);
        } else {
@@ -2998,7 +2536,7 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
        compound_t *compound = NULL;
 
        if (token.type == T___attribute__) {
-               modifiers |= parse_attributes(&attributes);
+               parse_attributes(NULL);
        }
 
        entity_kind_tag_t const kind = is_struct ? ENTITY_STRUCT : ENTITY_UNION;
@@ -3052,7 +2590,7 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
 
        if (token.type == '{') {
                parse_compound_type_entries(compound);
-               modifiers |= parse_attributes(&attributes);
+               parse_attributes(NULL);
 
                /* ISO/IEC 14882:1998(E) Â§7.1.3:5 */
                if (symbol == NULL) {
@@ -3061,7 +2599,6 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
                }
        }
 
-       compound->modifiers |= modifiers;
        return compound;
 }
 
@@ -3116,7 +2653,6 @@ end_error:
 
 static type_t *parse_enum_specifier(void)
 {
-       gnu_attribute_t *attributes = NULL;
        entity_t        *entity;
        symbol_t        *symbol;
 
@@ -3166,7 +2702,7 @@ static type_t *parse_enum_specifier(void)
                entity->enume.complete = true;
 
                parse_enum_entries(type);
-               parse_attributes(&attributes);
+               parse_attributes(NULL);
 
                /* ISO/IEC 14882:1998(E) Â§7.1.3:5 */
                if (symbol == NULL) {
@@ -3287,167 +2823,142 @@ static type_t *get_typedef_type(symbol_t *symbol)
        return type;
 }
 
-/**
- * check for the allowed MS alignment values.
- */
-static bool check_alignment_value(long long intvalue)
+static attribute_t *parse_attribute_ms_property(attribute_t *attribute)
 {
-       if (intvalue < 1 || intvalue > 8192) {
-               errorf(HERE, "illegal alignment value");
-               return false;
-       }
-       unsigned v = (unsigned)intvalue;
-       for (unsigned i = 1; i <= 8192; i += i) {
-               if (i == v)
-                       return true;
+       expect('(', end_error);
+
+       attribute_property_argument_t *property
+               = allocate_ast_zero(sizeof(*property));
+
+       while (true) {
+               if (token.type != T_IDENTIFIER) {
+                       parse_error_expected("while parsing property declspec",
+                                            T_IDENTIFIER, NULL);
+                       goto end_error;
+               }
+
+               bool is_put;
+               symbol_t *symbol = token.v.symbol;
+               next_token();
+               if (strcmp(symbol->string, "put") == 0) {
+                       is_put = true;
+               } else if (strcmp(symbol->string, "get") == 0) {
+                       is_put = false;
+               } else {
+                       errorf(HERE, "expected put or get in property declspec");
+                       goto end_error;
+               }
+               expect('=', end_error);
+               if (token.type != T_IDENTIFIER) {
+                       parse_error_expected("while parsing property declspec",
+                                            T_IDENTIFIER, NULL);
+                       goto end_error;
+               }
+               if (is_put) {
+                       property->put_symbol = token.v.symbol;
+               } else {
+                       property->get_symbol = token.v.symbol;
+               }
+               next_token();
+               if (token.type == ')')
+                       break;
+               expect(',', end_error);
        }
-       errorf(HERE, "alignment must be power of two");
-       return false;
+
+       attribute->a.property = property;
+
+       expect(')', end_error);
+
+end_error:
+       return attribute;
 }
 
-#define DET_MOD(name, tag) do { \
-       if (*modifiers & tag && warning.other) warningf(HERE, #name " used more than once"); \
-       *modifiers |= tag; \
-} while (0)
+static attribute_t *parse_microsoft_extended_decl_modifier_single(void)
+{
+       attribute_kind_t kind = ATTRIBUTE_UNKNOWN;
+       if (token.type == T_restrict) {
+               kind = ATTRIBUTE_MS_RESTRICT;
+               next_token();
+       } else if (token.type == T_IDENTIFIER) {
+               const char *name = token.v.symbol->string;
+               next_token();
+               for (attribute_kind_t k = ATTRIBUTE_MS_FIRST; k <= ATTRIBUTE_MS_LAST;
+                    ++k) {
+                       const char *attribute_name = get_attribute_name(k);
+                       if (attribute_name != NULL && strcmp(attribute_name, name) == 0) {
+                               kind = k;
+                               break;
+                       }
+               }
+
+               if (kind == ATTRIBUTE_UNKNOWN && warning.attribute) {
+                       warningf(HERE, "unknown __declspec '%s' ignored", name);
+               }
+       } else {
+               parse_error_expected("while parsing __declspec", T_IDENTIFIER, NULL);
+               return NULL;
+       }
+
+       attribute_t *attribute = allocate_attribute_zero(kind);
+
+       if (kind == ATTRIBUTE_MS_PROPERTY) {
+               return parse_attribute_ms_property(attribute);
+       }
+
+       /* parse arguments */
+       if (token.type == '(') {
+               next_token();
+               attribute->a.arguments = parse_attribute_arguments();
+       }
+
+       return attribute;
+}
 
-static void parse_microsoft_extended_decl_modifier(declaration_specifiers_t *specifiers)
+static attribute_t *parse_microsoft_extended_decl_modifier(attribute_t *first)
 {
-       decl_modifiers_t *modifiers = &specifiers->modifiers;
+       eat(T__declspec);
+
+       expect('(', end_error);
 
+       if (token.type == ')') {
+               next_token();
+               return NULL;
+       }
+
+       add_anchor_token(')');
+
+       attribute_t *last = first;
        while (true) {
-               if (token.type == T_restrict) {
-                       next_token();
-                       DET_MOD(restrict, DM_RESTRICT);
-                       goto end_loop;
-               } else if (token.type != T_IDENTIFIER)
-                       break;
-               symbol_t *symbol = token.v.symbol;
-               if (symbol == sym_align) {
-                       next_token();
-                       expect('(', end_error);
-                       if (token.type != T_INTEGER)
-                               goto end_error;
-                       if (check_alignment_value(token.v.intvalue)) {
-                               if (specifiers->alignment != 0 && warning.other)
-                                       warningf(HERE, "align used more than once");
-                               specifiers->alignment = (unsigned char)token.v.intvalue;
-                       }
-                       next_token();
-                       expect(')', end_error);
-               } else if (symbol == sym_allocate) {
-                       next_token();
-                       expect('(', end_error);
-                       if (token.type != T_IDENTIFIER)
-                               goto end_error;
-                       (void)token.v.symbol;
-                       expect(')', end_error);
-               } else if (symbol == sym_dllimport) {
-                       next_token();
-                       DET_MOD(dllimport, DM_DLLIMPORT);
-               } else if (symbol == sym_dllexport) {
-                       next_token();
-                       DET_MOD(dllexport, DM_DLLEXPORT);
-               } else if (symbol == sym_thread) {
-                       next_token();
-                       DET_MOD(thread, DM_THREAD);
-               } else if (symbol == sym_naked) {
-                       next_token();
-                       DET_MOD(naked, DM_NAKED);
-               } else if (symbol == sym_noinline) {
-                       next_token();
-                       DET_MOD(noinline, DM_NOINLINE);
-               } else if (symbol == sym_returns_twice) {
-                       next_token();
-                       DET_MOD(returns_twice, DM_RETURNS_TWICE);
-               } else if (symbol == sym_noreturn) {
-                       next_token();
-                       DET_MOD(noreturn, DM_NORETURN);
-               } else if (symbol == sym_nothrow) {
-                       next_token();
-                       DET_MOD(nothrow, DM_NOTHROW);
-               } else if (symbol == sym_novtable) {
-                       next_token();
-                       DET_MOD(novtable, DM_NOVTABLE);
-               } else if (symbol == sym_property) {
-                       next_token();
-                       expect('(', end_error);
-                       for (;;) {
-                               bool is_get = false;
-                               if (token.type != T_IDENTIFIER)
-                                       goto end_error;
-                               if (token.v.symbol == sym_get) {
-                                       is_get = true;
-                               } else if (token.v.symbol == sym_put) {
-                               } else {
-                                       errorf(HERE, "Bad property name '%Y'", token.v.symbol);
-                                       goto end_error;
-                               }
-                               next_token();
-                               expect('=', end_error);
-                               if (token.type != T_IDENTIFIER)
-                                       goto end_error;
-                               if (is_get) {
-                                       if (specifiers->get_property_sym != NULL) {
-                                               errorf(HERE, "get property name already specified");
-                                       } else {
-                                               specifiers->get_property_sym = token.v.symbol;
-                                       }
-                               } else {
-                                       if (specifiers->put_property_sym != NULL) {
-                                               errorf(HERE, "put property name already specified");
-                                       } else {
-                                               specifiers->put_property_sym = token.v.symbol;
-                                       }
-                               }
-                               next_token();
-                               if (token.type == ',') {
-                                       next_token();
-                                       continue;
-                               }
-                               break;
-                       }
-                       expect(')', end_error);
-               } else if (symbol == sym_selectany) {
-                       next_token();
-                       DET_MOD(selectany, DM_SELECTANY);
-               } else if (symbol == sym_uuid) {
-                       next_token();
-                       expect('(', end_error);
-                       if (token.type != T_STRING_LITERAL)
-                               goto end_error;
-                       next_token();
-                       expect(')', end_error);
-               } else if (symbol == sym_deprecated) {
-                       next_token();
-                       if (specifiers->deprecated != 0 && warning.other)
-                               warningf(HERE, "deprecated used more than once");
-                       specifiers->deprecated = true;
-                       if (token.type == '(') {
-                               next_token();
-                               if (token.type == T_STRING_LITERAL) {
-                                       specifiers->deprecated_string = token.v.string.begin;
-                                       next_token();
-                               } else {
-                                       errorf(HERE, "string literal expected");
-                               }
-                               expect(')', end_error);
-                       }
-               } else if (symbol == sym_noalias) {
-                       next_token();
-                       DET_MOD(noalias, DM_NOALIAS);
+               if (last != NULL) {
+                       while (last->next != NULL)
+                               last = last->next;
+               }
+
+               attribute_t *attribute
+                       = parse_microsoft_extended_decl_modifier_single();
+               if (attribute == NULL)
+                       goto end_error;
+
+               if (last == NULL) {
+                       first = attribute;
                } else {
-                       if (warning.other)
-                               warningf(HERE, "Unknown modifier '%Y' ignored", token.v.symbol);
-                       next_token();
-                       if (token.type == '(')
-                               skip_until(')');
+                       last->next = attribute;
                }
-end_loop:
-               if (token.type == ',')
-                       next_token();
+               last = attribute;
+
+               if (token.type == ')') {
+                       break;
+               }
+               expect(',', end_error);
        }
+
+       rem_anchor_token(')');
+       expect(')', end_error);
+       return first;
+
 end_error:
-       return;
+       rem_anchor_token(')');
+       return first;
 }
 
 static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind)
@@ -3467,39 +2978,9 @@ static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind)
        return entity;
 }
 
-static variable_t *parse_microsoft_based(void)
-{
-       if (token.type != T_IDENTIFIER) {
-               parse_error_expected("while parsing __based", T_IDENTIFIER, NULL);
-               return NULL;
-       }
-       symbol_t *symbol = token.v.symbol;
-       entity_t *entity = get_entity(symbol, NAMESPACE_NORMAL);
-
-       variable_t *variable;
-       if (entity == NULL || entity->base.kind != ENTITY_VARIABLE) {
-               errorf(HERE, "'%Y' is not a variable name.", symbol);
-               variable = &create_error_entity(symbol, ENTITY_VARIABLE)->variable;
-       } else {
-               variable = &entity->variable;
-
-               type_t *const type = variable->base.type;
-               if (is_type_valid(type)) {
-                       if (! is_type_pointer(skip_typeref(type))) {
-                               errorf(HERE, "variable in __based modifier must have pointer type instead of '%T'", type);
-                       }
-                       if (variable->base.base.parent_scope != file_scope) {
-                               errorf(HERE, "a nonstatic local variable may not be used in a __based specification");
-                       }
-               }
-       }
-       next_token();
-       return variable;
-}
-
 /**
- * Finish the construction of a struct type by calculating
- * its size, offsets, alignment.
+ * Finish the construction of a struct type by calculating its size, offsets,
+ * alignment.
  */
 static void finish_struct_type(compound_type_t *type)
 {
@@ -3509,22 +2990,22 @@ static void finish_struct_type(compound_type_t *type)
        if (!compound->complete)
                return;
 
-       il_size_t      size           = 0;
+       il_size_t      size = 0;
        il_size_t      offset;
-       il_alignment_t alignment      = 1;
-       bool           need_pad       = false;
+       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)
                        continue;
 
-               type_t *m_type = skip_typeref(entry->declaration.type);
-               if (! is_type_valid(m_type)) {
+               type_t *m_type = entry->declaration.type;
+               if (! is_type_valid(skip_typeref(m_type))) {
                        /* simply ignore errors here */
                        continue;
                }
-               il_alignment_t m_alignment = m_type->base.alignment;
+               il_alignment_t m_alignment = get_type_alignment(m_type);
                if (m_alignment > alignment)
                        alignment = m_alignment;
 
@@ -3533,10 +3014,7 @@ static void finish_struct_type(compound_type_t *type)
                if (offset > size)
                        need_pad = true;
                entry->compound_member.offset = offset;
-               size = offset + m_type->base.size;
-       }
-       if (type->base.alignment != 0) {
-               alignment = type->base.alignment;
+               size = offset + get_type_size(m_type);
        }
 
        offset = (size + alignment - 1) & -alignment;
@@ -3545,17 +3023,16 @@ static void finish_struct_type(compound_type_t *type)
 
        if (need_pad) {
                if (warning.padded) {
-                       warningf(&compound->base.source_position, "'%T' needs padding", type);
-               }
-       } else {
-               if (compound->modifiers & DM_PACKED && warning.packed) {
-                       warningf(&compound->base.source_position,
-                                       "superfluous packed attribute on '%T'", type);
+                       warningf(&compound->base.source_position, "'%T' needs padding",
+                                type);
                }
+       } else if (compound->packed && warning.packed) {
+               warningf(&compound->base.source_position,
+                        "superfluous packed attribute on '%T'", type);
        }
 
-       type->base.size      = offset;
-       type->base.alignment = alignment;
+       compound->size      = offset;
+       compound->alignment = alignment;
 }
 
 /**
@@ -3571,108 +3048,35 @@ static void finish_union_type(compound_type_t *type)
                return;
 
        il_size_t      size      = 0;
-       il_alignment_t alignment = 1;
+       il_alignment_t alignment = compound->alignment;
 
        entity_t *entry = compound->members.entities;
        for (; entry != NULL; entry = entry->base.next) {
                if (entry->kind != ENTITY_COMPOUND_MEMBER)
                        continue;
 
-               type_t *m_type = skip_typeref(entry->declaration.type);
+               type_t *m_type = entry->declaration.type;
                if (! is_type_valid(m_type))
                        continue;
 
                entry->compound_member.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;
+               il_size_t m_size = get_type_size(m_type);
+               if (m_size > size)
+                       size = m_size;
+               il_alignment_t m_alignment = get_type_alignment(m_type);
+               if (m_alignment > alignment)
+                       alignment = m_alignment;
        }
        size = (size + alignment - 1) & -alignment;
-       type->base.size      = size;
-       type->base.alignment = alignment;
-}
-
-static type_t *handle_attribute_mode(const gnu_attribute_t *attribute,
-                                     type_t *orig_type)
-{
-       type_t *type = skip_typeref(orig_type);
-
-       /* at least: byte, word, pointer, list of machine modes
-        * __XXX___ is interpreted as XXX */
-
-       /* This isn't really correct, the backend should provide a list of machine
-        * specific modes (according to gcc philosophy that is...) */
-       const char         *symbol_str = attribute->u.symbol->string;
-       bool                sign       = is_type_signed(type);
-       atomic_type_kind_t  akind;
-       if (strcmp_underscore("QI",   symbol_str) == 0 ||
-           strcmp_underscore("byte", symbol_str) == 0) {
-               akind = sign ? ATOMIC_TYPE_CHAR : ATOMIC_TYPE_UCHAR;
-       } else if (strcmp_underscore("HI", symbol_str) == 0) {
-               akind = sign ? ATOMIC_TYPE_SHORT : ATOMIC_TYPE_USHORT;
-       } else if (strcmp_underscore("SI",      symbol_str) == 0
-               || strcmp_underscore("word",    symbol_str) == 0
-               || strcmp_underscore("pointer", symbol_str) == 0) {
-               akind = sign ? ATOMIC_TYPE_INT : ATOMIC_TYPE_UINT;
-       } else if (strcmp_underscore("DI", symbol_str) == 0) {
-               akind = sign ? ATOMIC_TYPE_LONGLONG : ATOMIC_TYPE_ULONGLONG;
-       } else {
-               if (warning.other)
-                       warningf(HERE, "ignoring unknown mode '%s'", symbol_str);
-               return orig_type;
-       }
 
-       if (type->kind == TYPE_ATOMIC) {
-               type_t *copy       = duplicate_type(type);
-               copy->atomic.akind = akind;
-               return identify_new_type(copy);
-       } else if (type->kind == TYPE_ENUM) {
-               type_t *copy      = duplicate_type(type);
-               copy->enumt.akind = akind;
-               return identify_new_type(copy);
-       } else if (is_type_pointer(type)) {
-               warningf(HERE, "__attribute__((mode)) on pointers not implemented yet (ignored)");
-               return type;
-       }
-
-       errorf(HERE, "__attribute__((mode)) only allowed on integer, enum or pointer type");
-       return orig_type;
-}
-
-static type_t *handle_type_attributes(const gnu_attribute_t *attributes,
-                                      type_t *type)
-{
-       const gnu_attribute_t *attribute = attributes;
-       for ( ; attribute != NULL; attribute = attribute->next) {
-               if (attribute->invalid)
-                       continue;
-
-               if (attribute->kind == GNU_AK_MODE) {
-                       type = handle_attribute_mode(attribute, type);
-               } else if (attribute->kind == GNU_AK_ALIGNED) {
-                       int alignment = 32; /* TODO: fill in maximum useful alignment for
-                                              target machine */
-                       if (attribute->has_arguments)
-                               alignment = attribute->u.argument;
-
-                       type_t *copy         = duplicate_type(type);
-                       copy->base.alignment = attribute->u.argument;
-                       type                 = identify_new_type(copy);
-               }
-       }
-
-       return type;
+       compound->size      = size;
+       compound->alignment = alignment;
 }
 
 static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
 {
        type_t            *type              = NULL;
        type_qualifiers_t  qualifiers        = TYPE_QUALIFIER_NONE;
-       type_modifiers_t   modifiers         = TYPE_MODIFIER_NONE;
        unsigned           type_specifiers   = 0;
        bool               newtype           = false;
        bool               saw_error         = false;
@@ -3681,8 +3085,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
        specifiers->source_position = token.source_position;
 
        while (true) {
-               specifiers->modifiers
-                       |= parse_attributes(&specifiers->gnu_attributes);
+               specifiers->attributes = parse_attributes(specifiers->attributes);
 
                switch (token.type) {
                /* storage class */
@@ -3704,12 +3107,8 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                MATCH_STORAGE_CLASS(T_register, STORAGE_CLASS_REGISTER)
 
                case T__declspec:
-                       next_token();
-                       expect('(', end_error);
-                       add_anchor_token(')');
-                       parse_microsoft_extended_decl_modifier(specifiers);
-                       rem_anchor_token(')');
-                       expect(')', end_error);
+                       specifiers->attributes
+                               = parse_microsoft_extended_decl_modifier(specifiers->attributes);
                        break;
 
                case T___thread:
@@ -3787,16 +3186,18 @@ wrong_thread_stoarge_class:
                MATCH_SPECIFIER(T_void,       SPECIFIER_VOID,      "void");
                MATCH_SPECIFIER(T_wchar_t,    SPECIFIER_WCHAR_T,   "wchar_t");
 
-               case T__forceinline:
-                       /* only in microsoft mode */
-                       specifiers->modifiers |= DM_FORCEINLINE;
-                       /* FALLTHROUGH */
-
                case T_inline:
                        next_token();
                        specifiers->is_inline = true;
                        break;
 
+#if 0
+               case T__forceinline:
+                       next_token();
+                       specifiers->modifiers |= DM_FORCEINLINE;
+                       break;
+#endif
+
                case T_long:
                        if (type_specifiers & SPECIFIER_LONG_LONG) {
                                errorf(HERE, "multiple type specifiers given");
@@ -3808,28 +3209,33 @@ wrong_thread_stoarge_class:
                        next_token();
                        break;
 
-               case T_struct: {
+#define CHECK_DOUBLE_TYPE()        \
+                       if ( type != NULL)     \
+                               errorf(HERE, "multiple data types in declaration specifiers");
+
+               case T_struct:
+                       CHECK_DOUBLE_TYPE();
                        type = allocate_type_zero(TYPE_COMPOUND_STRUCT);
 
                        type->compound.compound = parse_compound_type_specifier(true);
                        finish_struct_type(&type->compound);
                        break;
-               }
-               case T_union: {
+               case T_union:
+                       CHECK_DOUBLE_TYPE();
                        type = allocate_type_zero(TYPE_COMPOUND_UNION);
                        type->compound.compound = parse_compound_type_specifier(false);
-                       if (type->compound.compound->modifiers & DM_TRANSPARENT_UNION)
-                               modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
                        finish_union_type(&type->compound);
                        break;
-               }
                case T_enum:
+                       CHECK_DOUBLE_TYPE();
                        type = parse_enum_specifier();
                        break;
                case T___typeof__:
+                       CHECK_DOUBLE_TYPE();
                        type = parse_typeof();
                        break;
                case T___builtin_va_list:
+                       CHECK_DOUBLE_TYPE();
                        type = duplicate_type(type_valist);
                        next_token();
                        break;
@@ -3903,8 +3309,7 @@ wrong_thread_stoarge_class:
        }
 
 finish_specifiers:
-       specifiers->modifiers
-               |= parse_attributes(&specifiers->gnu_attributes);
+       specifiers->attributes = parse_attributes(specifiers->attributes);
 
        in_gcc_extension = old_gcc_extension;
 
@@ -4083,21 +3488,13 @@ warn_about_long_long:
                        type                 = allocate_type_zero(TYPE_ATOMIC);
                        type->atomic.akind   = atomic_type;
                }
-               type->base.alignment = get_atomic_type_alignment(atomic_type);
-               unsigned const size  = get_atomic_type_size(atomic_type);
-               type->base.size      =
-                       type_specifiers & SPECIFIER_COMPLEX ? size * 2 : size;
                newtype = true;
        } else if (type_specifiers != 0) {
                errorf(HERE, "multiple datatypes in declaration");
        }
 
        /* FIXME: check type qualifiers here */
-
-       if (specifiers->modifiers & DM_TRANSPARENT_UNION)
-               modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
        type->base.qualifiers = qualifiers;
-       type->base.modifiers  = modifiers;
 
        if (newtype) {
                type = identify_new_type(type);
@@ -4105,7 +3502,8 @@ warn_about_long_long:
                type = typehash_insert(type);
        }
 
-       type = handle_type_attributes(specifiers->gnu_attributes, type);
+       if (specifiers->attributes != NULL)
+               type = handle_type_attributes(specifiers->attributes, type);
        specifiers->type = type;
        return;
 
@@ -4309,7 +3707,7 @@ typedef struct construct_type_base_t {
 typedef struct parsed_pointer_t {
        construct_type_base_t  base;
        type_qualifiers_t      type_qualifiers;
-       variable_t             *base_variable;  /**< MS __based extension. */
+       variable_t            *base_variable;  /**< MS __based extension. */
 } parsed_pointer_t;
 
 typedef struct parsed_reference_t {
@@ -4338,18 +3736,17 @@ union construct_type_t {
        parsed_array_t            array;
 };
 
-static construct_type_t *parse_pointer_declarator(variable_t *base_variable)
+static construct_type_t *parse_pointer_declarator(void)
 {
        eat('*');
 
-       construct_type_t *cons    = obstack_alloc(&temp_obst, sizeof(cons->pointer));
-       parsed_pointer_t *pointer = &cons->pointer;
-       memset(pointer, 0, sizeof(*pointer));
-       cons->kind               = CONSTRUCT_POINTER;
+       parsed_pointer_t *pointer = obstack_alloc(&temp_obst, sizeof(pointer[0]));
+       memset(pointer, 0, sizeof(pointer[0]));
+       pointer->base.kind       = CONSTRUCT_POINTER;
        pointer->type_qualifiers = parse_type_qualifiers();
-       pointer->base_variable   = base_variable;
+       //pointer->base_variable       = base_variable;
 
-       return cons;
+       return (construct_type_t*) pointer;
 }
 
 static construct_type_t *parse_reference_declarator(void)
@@ -4414,14 +3811,14 @@ end_error:
        return cons;
 }
 
-static construct_type_t *parse_function_declarator(scope_t *scope,
-                                                   decl_modifiers_t modifiers)
+static construct_type_t *parse_function_declarator(scope_t *scope)
 {
        type_t          *type  = allocate_type_zero(TYPE_FUNCTION);
        function_type_t *ftype = &type->function;
 
        ftype->linkage = current_linkage;
 
+#if 0
        switch (modifiers & (DM_CDECL | DM_STDCALL | DM_FASTCALL | DM_THISCALL)) {
                case DM_NONE:     break;
                case DM_CDECL:    ftype->calling_convention = CC_CDECL;    break;
@@ -4433,6 +3830,7 @@ static construct_type_t *parse_function_declarator(scope_t *scope,
                        errorf(HERE, "multiple calling conventions in declaration");
                        break;
        }
+#endif
 
        parse_parameters(ftype, scope);
 
@@ -4446,26 +3844,27 @@ static construct_type_t *parse_function_declarator(scope_t *scope,
 }
 
 typedef struct parse_declarator_env_t {
+       bool               may_be_abstract : 1;
+       bool               must_be_abstract : 1;
        decl_modifiers_t   modifiers;
        symbol_t          *symbol;
        source_position_t  source_position;
        scope_t            parameters;
+       attribute_t       *attributes;
 } parse_declarator_env_t;
 
-static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env,
-               bool may_be_abstract)
+static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env)
 {
        /* construct a single linked list of construct_type_t's which describe
         * how to construct the final declarator type */
        construct_type_t  *first      = NULL;
        construct_type_t **anchor     = &first;
-       gnu_attribute_t   *attributes = NULL;
 
-       decl_modifiers_t modifiers = parse_attributes(&attributes);
+       env->attributes = parse_attributes(env->attributes);
 
        for (;;) {
                construct_type_t *type;
-               variable_t       *based = NULL; /* MS __based extension */
+               //variable_t       *based = NULL; /* MS __based extension */
                switch (token.type) {
                        case '&':
                                if (!(c_mode & _CXX))
@@ -4474,6 +3873,7 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env,
                                break;
 
                        case T__based: {
+#if 0
                                source_position_t const pos = *HERE;
                                next_token();
                                expect('(', end_error);
@@ -4490,11 +3890,14 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env,
                                        }
                                        continue;
                                }
+#else
+                               panic("based currently disabled");
+#endif
                                /* FALLTHROUGH */
                        }
 
                        case '*':
-                               type = parse_pointer_declarator(based);
+                               type = parse_pointer_declarator();
                                break;
 
                        default:
@@ -4505,20 +3908,20 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env,
                anchor  = &type->base.next;
 
                /* TODO: find out if this is correct */
-               modifiers |= parse_attributes(&attributes);
+               env->attributes = parse_attributes(env->attributes);
        }
-ptr_operator_end:
 
-       if (env != NULL) {
-               modifiers      |= env->modifiers;
-               env->modifiers  = modifiers;
-       }
+ptr_operator_end: ;
+#if 0
+       modifiers      |= env->modifiers;
+       env->modifiers  = modifiers;
+#endif
 
        construct_type_t *inner_types = NULL;
 
        switch (token.type) {
        case T_IDENTIFIER:
-               if (env == NULL) {
+               if (env->must_be_abstract) {
                        errorf(HERE, "no identifier expected in typename");
                } else {
                        env->symbol          = token.v.symbol;
@@ -4533,17 +3936,17 @@ ptr_operator_end:
                if (look_ahead(1)->type != ')') {
                        next_token();
                        add_anchor_token(')');
-                       inner_types = parse_inner_declarator(env, may_be_abstract);
+                       inner_types = parse_inner_declarator(env);
                        if (inner_types != NULL) {
                                /* All later declarators only modify the return type */
-                               env = NULL;
+                               env->must_be_abstract = true;
                        }
                        rem_anchor_token(')');
                        expect(')', end_error);
                }
                break;
        default:
-               if (may_be_abstract)
+               if (env->may_be_abstract)
                        break;
                parse_error_expected("while parsing declarator", T_IDENTIFIER, '(', NULL);
                eat_until_anchor();
@@ -4557,10 +3960,11 @@ ptr_operator_end:
                switch (token.type) {
                case '(': {
                        scope_t *scope = NULL;
-                       if (env != NULL)
+                       if (!env->must_be_abstract) {
                                scope = &env->parameters;
+                       }
 
-                       type = parse_function_declarator(scope, modifiers);
+                       type = parse_function_declarator(scope);
                        break;
                }
                case '[':
@@ -4587,69 +3991,6 @@ end_error:
        return NULL;
 }
 
-static void parse_declaration_attributes(entity_t *entity)
-{
-       gnu_attribute_t  *attributes = NULL;
-       decl_modifiers_t  modifiers  = parse_attributes(&attributes);
-
-       if (entity == NULL)
-               return;
-
-       type_t *type;
-       if (entity->kind == ENTITY_TYPEDEF) {
-               modifiers |= entity->typedefe.modifiers;
-               type       = entity->typedefe.type;
-       } else {
-               assert(is_declaration(entity));
-               modifiers |= entity->declaration.modifiers;
-               type       = entity->declaration.type;
-       }
-       if (type == NULL)
-               return;
-
-       gnu_attribute_t *attribute = attributes;
-       for ( ; attribute != NULL; attribute = attribute->next) {
-               if (attribute->invalid)
-                       continue;
-
-               if (attribute->kind == GNU_AK_MODE) {
-                       type = handle_attribute_mode(attribute, type);
-               } else if (attribute->kind == GNU_AK_ALIGNED) {
-                       int alignment = 32; /* TODO: fill in maximum usefull alignment for target machine */
-                       if (attribute->has_arguments)
-                               alignment = attribute->u.argument;
-
-                       if (entity->kind == ENTITY_TYPEDEF) {
-                               type_t *copy         = duplicate_type(type);
-                               copy->base.alignment = attribute->u.argument;
-                               type                 = identify_new_type(copy);
-                       } else if(entity->kind == ENTITY_VARIABLE) {
-                               entity->variable.alignment = alignment;
-                       } else if(entity->kind == ENTITY_COMPOUND_MEMBER) {
-                               entity->compound_member.alignment = alignment;
-                       }
-               }
-       }
-
-       type_modifiers_t type_modifiers = type->base.modifiers;
-       if (modifiers & DM_TRANSPARENT_UNION)
-               type_modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
-
-       if (type->base.modifiers != type_modifiers) {
-               type_t *copy         = duplicate_type(type);
-               copy->base.modifiers = type_modifiers;
-               type                 = identify_new_type(copy);
-       }
-
-       if (entity->kind == ENTITY_TYPEDEF) {
-               entity->typedefe.type      = type;
-               entity->typedefe.modifiers = modifiers;
-       } else {
-               entity->declaration.type      = type;
-               entity->declaration.modifiers = modifiers;
-       }
-}
-
 static type_t *construct_declarator_type(construct_type_t *construct_list, type_t *type)
 {
        construct_type_t *iter = construct_list;
@@ -4795,10 +4136,9 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
 {
        parse_declarator_env_t env;
        memset(&env, 0, sizeof(env));
-       env.modifiers = specifiers->modifiers;
+       env.may_be_abstract = (flags & DECL_MAY_BE_ABSTRACT) != 0;
 
-       construct_type_t *construct_type =
-               parse_inner_declarator(&env, (flags & DECL_MAY_BE_ABSTRACT) != 0);
+       construct_type_t *construct_type = parse_inner_declarator(&env);
        type_t           *orig_type      =
                construct_declarator_type(construct_type, specifiers->type);
        type_t           *type           = skip_typeref(orig_type);
@@ -4807,6 +4147,18 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                obstack_free(&temp_obst, construct_type);
        }
 
+       attribute_t *attributes = parse_attributes(env.attributes);
+       /* append (shared) specifier attribute behind attributes of this
+          declarator */
+       if (attributes != NULL) {
+               attribute_t *last = attributes;
+               while (last->next != NULL)
+                       last = last->next;
+               last->next = specifiers->attributes;
+       } else {
+               attributes = specifiers->attributes;
+       }
+
        entity_t *entity;
        if (specifiers->storage_class == STORAGE_CLASS_TYPEDEF) {
                entity                       = allocate_entity_zero(ENTITY_TYPEDEF);
@@ -4873,9 +4225,6 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                } else {
                        entity = allocate_entity_zero(ENTITY_VARIABLE);
 
-                       entity->variable.get_property_sym = specifiers->get_property_sym;
-                       entity->variable.put_property_sym = specifiers->put_property_sym;
-
                        entity->variable.thread_local = specifiers->thread_local;
 
                        if (env.symbol != NULL) {
@@ -4910,10 +4259,11 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                } else {
                        entity->base.source_position = specifiers->source_position;
                }
-               entity->base.namespc                  = NAMESPACE_NORMAL;
-               entity->declaration.type              = orig_type;
-               entity->declaration.modifiers         = env.modifiers;
-               entity->declaration.deprecated_string = specifiers->deprecated_string;
+               entity->base.namespc           = NAMESPACE_NORMAL;
+               entity->declaration.type       = orig_type;
+               entity->declaration.alignment  = get_type_alignment(orig_type);
+               entity->declaration.modifiers  = env.modifiers;
+               entity->declaration.attributes = attributes;
 
                storage_class_t storage_class = specifiers->storage_class;
                entity->declaration.declared_storage_class = storage_class;
@@ -4923,19 +4273,27 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                entity->declaration.storage_class = storage_class;
        }
 
-       parse_declaration_attributes(entity);
+       if (attributes != NULL) {
+               handle_entity_attributes(attributes, entity);
+       }
 
        return entity;
 }
 
 static type_t *parse_abstract_declarator(type_t *base_type)
 {
-       construct_type_t *construct_type = parse_inner_declarator(NULL, 1);
+       parse_declarator_env_t env;
+       memset(&env, 0, sizeof(env));
+       env.may_be_abstract = true;
+       env.must_be_abstract = true;
+
+       construct_type_t *construct_type = parse_inner_declarator(&env);
 
        type_t *result = construct_declarator_type(construct_type, base_type);
        if (construct_type != NULL) {
                obstack_free(&temp_obst, construct_type);
        }
+       result = handle_type_attributes(env.attributes, result);
 
        return result;
 }
@@ -5117,7 +4475,6 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition)
                                prev_decl->storage_class          = decl->storage_class;
                                prev_decl->declared_storage_class = decl->declared_storage_class;
                                prev_decl->modifiers              = decl->modifiers;
-                               prev_decl->deprecated_string      = decl->deprecated_string;
                                return previous_entity;
                        }
 
@@ -6521,7 +5878,7 @@ static type_t *make_bitfield_type(type_t *base_type, expression_t *size,
                        base_type);
                bit_size = 0;
        } else {
-               bit_size = skipped_type->base.size * 8;
+               bit_size = get_type_size(base_type) * 8;
        }
 
        if (is_constant_expression(size)) {
@@ -6586,7 +5943,6 @@ static void parse_compound_declarators(compound_t *compound,
                        entity->base.source_position               = source_position;
                        entity->declaration.declared_storage_class = STORAGE_CLASS_NONE;
                        entity->declaration.storage_class          = STORAGE_CLASS_NONE;
-                       entity->declaration.modifiers              = specifiers->modifiers;
                        entity->declaration.type                   = type;
                        append_entity(&compound->members, entity);
                } else {
@@ -6949,9 +6305,7 @@ static type_t *make_function_0_type_noreturn(type_t *return_type)
        type_t *type               = allocate_type_zero(TYPE_FUNCTION);
        type->function.return_type = return_type;
        type->function.parameters  = NULL;
-       type->function.base.modifiers |= DM_NORETURN;
-       return type;
-
+       type->function.modifiers  |= DM_NORETURN;
        return identify_new_type(type);
 }
 
@@ -7088,7 +6442,7 @@ static expression_t *parse_reference(void)
        }
 
        if (entity->base.parent_scope != file_scope
-               && entity->base.parent_scope->depth < current_function->parameters.depth
+               && (current_function != NULL && entity->base.parent_scope->depth < current_function->parameters.depth)
                && is_type_valid(orig_type) && !is_type_function(orig_type)) {
                if (entity->kind == ENTITY_VARIABLE) {
                        /* access of a variable from an outer function */
@@ -7103,15 +6457,15 @@ static expression_t *parse_reference(void)
        if (warning.deprecated_declarations
                && is_declaration(entity)
                && entity->declaration.modifiers & DM_DEPRECATED) {
-               declaration_t *declaration = &entity->declaration;
 
                char const *const prefix = entity->kind == ENTITY_FUNCTION ?
                        "function" : "variable";
-
-               if (declaration->deprecated_string != NULL) {
+               const char *deprecated_string
+                       = get_deprecated_string(entity->declaration.attributes);
+               if (deprecated_string != NULL) {
                        warningf(HERE, "%s '%Y' is deprecated (declared %P): \"%s\"",
                                 prefix, entity->base.symbol, &entity->base.source_position,
-                                declaration->deprecated_string);
+                                deprecated_string);
                } else {
                        warningf(HERE, "%s '%Y' is deprecated (declared %P)", prefix,
                                 entity->base.symbol, &entity->base.source_position);
@@ -8069,8 +7423,7 @@ static void check_call_argument(type_t          *expected_type,
 
        /* handle transparent union gnu extension */
        if (is_type_union(expected_type_skip)
-                       && (expected_type_skip->base.modifiers
-                               & TYPE_MODIFIER_TRANSPARENT_UNION)) {
+                       && (get_type_modifiers(expected_type) & DM_TRANSPARENT_UNION)) {
                compound_t *union_decl  = expected_type_skip->compound.compound;
                type_t     *best_type   = NULL;
                entity_t   *entry       = union_decl->members.entities;
@@ -11663,28 +11016,6 @@ void init_parser(void)
 {
        sym_anonymous = symbol_table_insert("<anonymous>");
 
-       if (c_mode & _MS) {
-               /* add predefined symbols for extended-decl-modifier */
-               sym_align         = symbol_table_insert("align");
-               sym_allocate      = symbol_table_insert("allocate");
-               sym_dllimport     = symbol_table_insert("dllimport");
-               sym_dllexport     = symbol_table_insert("dllexport");
-               sym_naked         = symbol_table_insert("naked");
-               sym_noinline      = symbol_table_insert("noinline");
-               sym_returns_twice = symbol_table_insert("returns_twice");
-               sym_noreturn      = symbol_table_insert("noreturn");
-               sym_nothrow       = symbol_table_insert("nothrow");
-               sym_novtable      = symbol_table_insert("novtable");
-               sym_property      = symbol_table_insert("property");
-               sym_get           = symbol_table_insert("get");
-               sym_put           = symbol_table_insert("put");
-               sym_selectany     = symbol_table_insert("selectany");
-               sym_thread        = symbol_table_insert("thread");
-               sym_uuid          = symbol_table_insert("uuid");
-               sym_deprecated    = symbol_table_insert("deprecated");
-               sym_restrict      = symbol_table_insert("restrict");
-               sym_noalias       = symbol_table_insert("noalias");
-       }
        memset(token_anchor_set, 0, sizeof(token_anchor_set));
 
        init_expression_parsers();
diff --git a/type.c b/type.c
index cd6f559..2a52894 100644 (file)
--- a/type.c
+++ b/type.c
@@ -731,10 +731,6 @@ static void intern_print_type_post(const type_t *const type)
        case TYPE_TYPEDEF:
                break;
        }
-
-       if (type->base.modifiers & DM_TRANSPARENT_UNION) {
-               fputs("__attribute__((__transparent_union__))", out);
-       }
 }
 
 /**
@@ -772,7 +768,7 @@ void print_type_ext(const type_t *const type, const symbol_t *symbol,
  *
  * @param type  The type.
  */
-static size_t get_type_size(const type_t *type)
+static size_t get_type_struct_size(const type_t *type)
 {
        switch(type->kind) {
        case TYPE_ATOMIC:          return sizeof(atomic_type_t);
@@ -805,7 +801,7 @@ static size_t get_type_size(const type_t *type)
  */
 type_t *duplicate_type(const type_t *type)
 {
-       size_t size = get_type_size(type);
+       size_t size = get_type_struct_size(type);
 
        type_t *copy = obstack_alloc(type_obst, size);
        memcpy(copy, type, size);
@@ -1194,7 +1190,11 @@ bool types_compatible(const type_t *type1, const type_t *type2)
        }
 
        case TYPE_COMPOUND_STRUCT:
-       case TYPE_COMPOUND_UNION:
+       case TYPE_COMPOUND_UNION: {
+
+
+               break;
+       }
        case TYPE_ENUM:
        case TYPE_BUILTIN:
                /* TODO: not implemented */
@@ -1225,19 +1225,13 @@ bool types_compatible(const type_t *type1, const type_t *type2)
 type_t *skip_typeref(type_t *type)
 {
        type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE;
-       type_modifiers_t  modifiers  = TYPE_MODIFIER_NONE;
-       il_alignment_t    alignment  = 0;
 
        while (true) {
-               if (alignment < type->base.alignment)
-                       alignment = type->base.alignment;
-
                switch (type->kind) {
                case TYPE_ERROR:
                        return type;
                case TYPE_TYPEDEF: {
                        qualifiers |= type->base.qualifiers;
-                       modifiers  |= type->base.modifiers;
 
                        const typedef_type_t *typedef_type = &type->typedeft;
                        if (typedef_type->resolved_type != NULL) {
@@ -1249,7 +1243,6 @@ type_t *skip_typeref(type_t *type)
                }
                case TYPE_TYPEOF:
                        qualifiers |= type->base.qualifiers;
-                       modifiers  |= type->base.modifiers;
                        type        = type->typeoft.typeof_type;
                        continue;
                default:
@@ -1258,9 +1251,7 @@ type_t *skip_typeref(type_t *type)
                break;
        }
 
-       if (qualifiers != TYPE_QUALIFIER_NONE ||
-                       modifiers  != TYPE_MODIFIER_NONE  ||
-                       alignment  >  type->base.alignment) {
+       if (qualifiers != TYPE_QUALIFIER_NONE) {
                type_t *const copy = duplicate_type(type);
 
                /* for const with typedefed array type the element type has to be
@@ -1269,13 +1260,9 @@ type_t *skip_typeref(type_t *type)
                        type_t *element_type           = copy->array.element_type;
                        element_type                   = duplicate_type(element_type);
                        element_type->base.qualifiers |= qualifiers;
-                       element_type->base.modifiers  |= modifiers;
-                       element_type->base.alignment   = alignment;
                        copy->array.element_type       = element_type;
                } else {
                        copy->base.qualifiers |= qualifiers;
-                       copy->base.modifiers  |= modifiers;
-                       copy->base.alignment   = alignment;
                }
 
                type = identify_new_type(copy);
@@ -1284,6 +1271,137 @@ type_t *skip_typeref(type_t *type)
        return type;
 }
 
+unsigned get_type_size(const type_t *type)
+{
+       switch (type->kind) {
+       case TYPE_INVALID:
+               break;
+       case TYPE_ERROR:
+               return 0;
+       case TYPE_ATOMIC:
+               return get_atomic_type_size(type->atomic.akind);
+       case TYPE_COMPLEX:
+               return get_atomic_type_size(type->complex.akind) * 2;
+       case TYPE_IMAGINARY:
+               return get_atomic_type_size(type->imaginary.akind);
+       case TYPE_COMPOUND_UNION:
+       case TYPE_COMPOUND_STRUCT:
+               return type->compound.compound->size;
+       case TYPE_ENUM:
+               return get_atomic_type_size(type->enumt.akind);
+       case TYPE_FUNCTION:
+               return 0; /* non-const (but "address-const") */
+       case TYPE_REFERENCE:
+       case TYPE_POINTER:
+               /* TODO: make configurable by backend */
+               return 4;
+       case TYPE_ARRAY: {
+               /* TODO: correct if element_type is aligned? */
+               il_size_t element_size = get_type_size(type->array.element_type);
+               return type->array.size * element_size;
+       }
+       case TYPE_BITFIELD:
+               return 0;
+       case TYPE_BUILTIN:
+               return get_type_size(type->builtin.real_type);
+       case TYPE_TYPEDEF:
+               return get_type_size(type->typedeft.typedefe->type);
+       case TYPE_TYPEOF:
+               if (type->typeoft.typeof_type) {
+                       return get_type_size(type->typeoft.typeof_type);
+               } else {
+                       return get_type_size(type->typeoft.expression->base.type);
+               }
+       }
+       panic("invalid type in get_type_size");
+}
+
+unsigned get_type_alignment(const type_t *type)
+{
+       switch (type->kind) {
+       case TYPE_INVALID:
+               break;
+       case TYPE_ERROR:
+               return 0;
+       case TYPE_ATOMIC:
+               return get_atomic_type_alignment(type->atomic.akind);
+       case TYPE_COMPLEX:
+               return get_atomic_type_alignment(type->complex.akind);
+       case TYPE_IMAGINARY:
+               return get_atomic_type_alignment(type->imaginary.akind);
+       case TYPE_COMPOUND_UNION:
+       case TYPE_COMPOUND_STRUCT:
+               return type->compound.compound->alignment;
+       case TYPE_ENUM:
+               return get_atomic_type_alignment(type->enumt.akind);
+       case TYPE_FUNCTION:
+               /* what is correct here? */
+               return 4;
+       case TYPE_REFERENCE:
+       case TYPE_POINTER:
+               /* TODO: make configurable by backend */
+               return 4;
+       case TYPE_ARRAY:
+               return get_type_alignment(type->array.element_type);
+       case TYPE_BITFIELD:
+               return 0;
+       case TYPE_BUILTIN:
+               return get_type_alignment(type->builtin.real_type);
+       case TYPE_TYPEDEF: {
+               il_alignment_t alignment
+                       = get_type_alignment(type->typedeft.typedefe->type);
+               if (type->typedeft.typedefe->alignment > alignment)
+                       alignment = type->typedeft.typedefe->alignment;
+
+               return alignment;
+       }
+       case TYPE_TYPEOF:
+               if (type->typeoft.typeof_type) {
+                       return get_type_alignment(type->typeoft.typeof_type);
+               } else {
+                       return get_type_alignment(type->typeoft.expression->base.type);
+               }
+       }
+       panic("invalid type in get_type_alignment");
+}
+
+decl_modifiers_t get_type_modifiers(const type_t *type)
+{
+       switch(type->kind) {
+       case TYPE_INVALID:
+       case TYPE_ERROR:
+               break;
+       case TYPE_COMPOUND_STRUCT:
+       case TYPE_COMPOUND_UNION:
+               return type->compound.compound->modifiers;
+       case TYPE_FUNCTION:
+               return type->function.modifiers;
+       case TYPE_ENUM:
+       case TYPE_ATOMIC:
+       case TYPE_COMPLEX:
+       case TYPE_IMAGINARY:
+       case TYPE_REFERENCE:
+       case TYPE_POINTER:
+       case TYPE_BITFIELD:
+       case TYPE_ARRAY:
+               return 0;
+       case TYPE_BUILTIN:
+               return get_type_modifiers(type->builtin.real_type);
+       case TYPE_TYPEDEF: {
+               decl_modifiers_t modifiers = type->typedeft.typedefe->modifiers;
+               modifiers |= get_type_modifiers(type->typedeft.typedefe->type);
+               return modifiers;
+       }
+       case TYPE_TYPEOF:
+               if (type->typeoft.typeof_type) {
+                       return get_type_modifiers(type->typeoft.typeof_type);
+               } else {
+                       return get_type_modifiers(type->typeoft.expression->base.type);
+               }
+       }
+       panic("invalid type found in get_type_modifiers");
+}
+
 type_qualifiers_t get_type_qualifier(const type_t *type, bool skip_array_type)
 {
        type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE;
@@ -1436,8 +1554,6 @@ 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.size       = get_atomic_type_size(akind);
-       type->base.alignment  = get_atomic_type_alignment(akind);
        type->base.qualifiers = qualifiers;
        type->atomic.akind    = akind;
 
@@ -1457,7 +1573,6 @@ type_t *make_complex_type(atomic_type_kind_t akind, type_qualifiers_t qualifiers
 
        type->kind            = TYPE_COMPLEX;
        type->base.qualifiers = qualifiers;
-       type->base.alignment  = get_atomic_type_alignment(akind);
        type->complex.akind   = akind;
 
        return identify_new_type(type);
@@ -1476,7 +1591,6 @@ type_t *make_imaginary_type(atomic_type_kind_t akind, type_qualifiers_t qualifie
 
        type->kind            = TYPE_IMAGINARY;
        type->base.qualifiers = qualifiers;
-       type->base.alignment  = get_atomic_type_alignment(akind);
        type->imaginary.akind = akind;
 
        return identify_new_type(type);
@@ -1495,7 +1609,6 @@ type_t *make_pointer_type(type_t *points_to, type_qualifiers_t qualifiers)
 
        type->kind                  = TYPE_POINTER;
        type->base.qualifiers       = qualifiers;
-       type->base.alignment        = 0;
        type->pointer.points_to     = points_to;
        type->pointer.base_variable = NULL;
 
@@ -1514,7 +1627,6 @@ type_t *make_reference_type(type_t *refers_to)
 
        type->kind                = TYPE_REFERENCE;
        type->base.qualifiers     = 0;
-       type->base.alignment      = 0;
        type->reference.refers_to = refers_to;
 
        return identify_new_type(type);
@@ -1535,7 +1647,6 @@ type_t *make_based_pointer_type(type_t *points_to,
 
        type->kind                  = TYPE_POINTER;
        type->base.qualifiers       = qualifiers;
-       type->base.alignment        = 0;
        type->pointer.points_to     = points_to;
        type->pointer.base_variable = variable;
 
@@ -1551,7 +1662,6 @@ type_t *make_array_type(type_t *element_type, size_t size,
 
        type->kind                = TYPE_ARRAY;
        type->base.qualifiers     = qualifiers;
-       type->base.alignment      = 0;
        type->array.element_type  = element_type;
        type->array.size          = size;
        type->array.size_constant = true;
diff --git a/type.h b/type.h
index 6bf52cf..cf0e5a1 100644 (file)
--- a/type.h
+++ b/type.h
@@ -192,6 +192,10 @@ unsigned get_atomic_type_size(atomic_type_kind_t kind);
  */
 unsigned get_atomic_type_alignment(atomic_type_kind_t kind);
 
+unsigned         get_type_alignment(const type_t *type);
+unsigned         get_type_size(const type_t *type);
+decl_modifiers_t get_type_modifiers(const type_t *type);
+
 /**
  * returns flags of an atomic type kind
  */
index 9635488..7d44d51 100644 (file)
@@ -101,6 +101,7 @@ static unsigned hash_function_type(const function_type_t *type)
                result   ^= hash_ptr(parameter->type);
                parameter = parameter->next;
        }
+       result += type->modifiers;
        result += type->linkage;
        result += type->calling_convention;
 
@@ -216,6 +217,8 @@ static bool function_types_equal(const function_type_t *type1,
                return false;
        if (type1->linkage != type2->linkage)
                return false;
+       if (type1->modifiers != type2->modifiers)
+               return false;
        if (type1->calling_convention != type2->calling_convention)
                return false;
 
@@ -320,8 +323,6 @@ static bool types_equal(const type_t *type1, const type_t *type2)
                return false;
        if (type1->base.qualifiers != type2->base.qualifiers)
                return false;
-       if (type1->base.modifiers != type2->base.modifiers)
-               return false;
 
        switch (type1->kind) {
        case TYPE_ERROR:
index b4f9220..5c703c7 100644 (file)
--- a/type_t.h
+++ b/type_t.h
@@ -52,19 +52,11 @@ typedef enum type_kind_t {
        TYPE_TYPEOF,
 } type_kind_t;
 
-typedef enum type_modifier_t {
-       TYPE_MODIFIER_NONE              = 0,
-       TYPE_MODIFIER_TRANSPARENT_UNION = 1 << 0,
-} type_modifier_t;
-typedef unsigned short type_modifiers_t;
-
 struct type_base_t {
        type_kind_t       kind;
-       il_size_t         size;           /**< The size of this type. */
        type_qualifiers_t qualifiers;
-       type_modifiers_t  modifiers;
-       il_alignment_t    alignment;      /**< The extra alignment of the type, 0 for default. */
 
+       /* cached ast2firm infos */
        ir_type          *firm_type;
 };
 
@@ -148,6 +140,7 @@ struct function_type_t {
        function_parameter_t *parameters;         /**< A list of the parameter types. */
        linkage_kind_t        linkage;
        cc_kind_t             calling_convention; /**< The specified calling convention. */
+       decl_modifiers_t      modifiers;
        bool                  variadic : 1;
        bool                  unspecified_parameters : 1;
        bool                  kr_style_parameters : 1;
diff --git a/types.c b/types.c
index 98fd054..9f07888 100644 (file)
--- a/types.c
+++ b/types.c
@@ -98,8 +98,7 @@ type_t *type_int64_ptr;
 
 void init_basic_types(void)
 {
-       static const type_base_t error = { TYPE_ERROR, 0, TYPE_QUALIFIER_NONE,
-                                          TYPE_MODIFIER_NONE, 0, NULL };
+       static const type_base_t error = { TYPE_ERROR, TYPE_QUALIFIER_NONE, NULL };
 
        type_error_type         = (type_t*)&error;
        type_bool               = make_atomic_type(ATOMIC_TYPE_BOOL,        TYPE_QUALIFIER_NONE);