From: Matthias Braun Date: Sat, 7 Mar 2009 19:52:41 +0000 (+0000) Subject: rewrite of attribute handling X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=27040b8042ae6b0ac7974f52abd95d7562da6d9a;p=cparser rewrite of attribute handling [r25609] --- diff --git a/Makefile b/Makefile index adecc3d..395c693 100644 --- 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 --- 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, diff --git a/ast2firm.c b/ast2firm.c index b74308b..c17d3a4 100644 --- a/ast2firm.c +++ b/ast2firm.c @@ -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 --- 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 index 0000000..9718a21 --- /dev/null +++ b/attribute.c @@ -0,0 +1,416 @@ +/* + * This file is part of cparser. + * Copyright (C) 2007-2008 Matthias Braun + * + * 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 + +#include +#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 index 0000000..0684aa0 --- /dev/null +++ b/attribute.h @@ -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 index 0000000..1a62aeb --- /dev/null +++ b/attribute_t.h @@ -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 diff --git a/entity.h b/entity.h index 0e65930..a31cd0b 100644 --- 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 diff --git a/entity_t.h b/entity_t.h index b61be49..374d283 100644 --- a/entity_t.h +++ b/entity_t.h @@ -23,6 +23,7 @@ #include "lexer.h" #include "symbol.h" #include "entity.h" +#include "attribute.h" #include 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 diff --git a/mangle.c b/mangle.c index bcd78d6..98fc1d7 100644 --- 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 */ diff --git a/parser.c b/parser.c index aebe73a..ebecc3d 100644 --- 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(""); - 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 --- 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 --- 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 */ diff --git a/type_hash.c b/type_hash.c index 9635488..7d44d51 100644 --- a/type_hash.c +++ b/type_hash.c @@ -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: diff --git a/type_t.h b/type_t.h index b4f9220..5c703c7 100644 --- 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 --- 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);