/*
* This file is part of cparser.
- * Copyright (C) 2007-2009 Matthias Braun <matze@braunis.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
+ * Copyright (C) 2012 Matthias Braun <matze@braunis.de>
*/
#include <config.h>
#include <assert.h>
+
+#include "adt/bitfiddle.h"
+#include "adt/strutil.h"
+#include "ast_t.h"
#include "diagnostic.h"
#include "warning.h"
#include "attribute_t.h"
#include "symbol_t.h"
#include "adt/error.h"
+#include "entity_t.h"
+#include "symbol_table.h"
#include "type_t.h"
static const char *const attribute_names[ATTRIBUTE_LAST+1] = {
- [ATTRIBUTE_GNU_CONST] = "const",
- [ATTRIBUTE_GNU_VOLATILE] = "volatile",
+ [ATTRIBUTE_GNU_ALIAS] = "alias",
+ [ATTRIBUTE_GNU_ALIGNED] = "aligned",
+ [ATTRIBUTE_GNU_ALWAYS_INLINE] = "always_inline",
[ATTRIBUTE_GNU_CDECL] = "cdecl",
- [ATTRIBUTE_GNU_STDCALL] = "stdcall",
- [ATTRIBUTE_GNU_FASTCALL] = "fastcall",
+ [ATTRIBUTE_GNU_COMMON] = "common",
+ [ATTRIBUTE_GNU_CONST] = "const",
+ [ATTRIBUTE_GNU_CONSTRUCTOR] = "constructor",
[ATTRIBUTE_GNU_DEPRECATED] = "deprecated",
+ [ATTRIBUTE_GNU_DESTRUCTOR] = "destructor",
+ [ATTRIBUTE_GNU_DLLEXPORT] = "dllexport",
+ [ATTRIBUTE_GNU_DLLIMPORT] = "dllimport",
+ [ATTRIBUTE_GNU_EIGTHBIT_DATA] = "eightbit_data",
+ [ATTRIBUTE_GNU_EXTERNALLY_VISIBLE] = "externally_visible",
+ [ATTRIBUTE_GNU_FAR] = "far",
+ [ATTRIBUTE_GNU_FASTCALL] = "fastcall",
+ [ATTRIBUTE_GNU_FLATTEN] = "flatten",
+ [ATTRIBUTE_GNU_FORMAT_ARG] = "format_arg",
+ [ATTRIBUTE_GNU_FORMAT] = "format",
+ [ATTRIBUTE_GNU_FUNCTION_VECTOR] = "function_vector",
+ [ATTRIBUTE_GNU_GCC_STRUCT] = "gcc_struct",
+ [ATTRIBUTE_GNU_INTERRUPT_HANDLER] = "interrupt_handler",
+ [ATTRIBUTE_GNU_INTERRUPT] = "interrupt",
+ [ATTRIBUTE_GNU_LEAF] = "leaf",
+ [ATTRIBUTE_GNU_LONGCALL] = "longcall",
+ [ATTRIBUTE_GNU_LONG_CALL] = "long_call",
+ [ATTRIBUTE_GNU_MALLOC] = "malloc",
+ [ATTRIBUTE_GNU_MAY_ALIAS] = "may_alias",
+ [ATTRIBUTE_GNU_MODEL] = "model",
+ [ATTRIBUTE_GNU_MODE] = "mode",
+ [ATTRIBUTE_GNU_MS_STRUCT] = "ms_struct",
+ [ATTRIBUTE_GNU_NAKED] = "naked",
+ [ATTRIBUTE_GNU_NEAR] = "near",
+ [ATTRIBUTE_GNU_NESTING] = "nesting",
+ [ATTRIBUTE_GNU_NMI_HANDLER] = "nmi_handler",
+ [ATTRIBUTE_GNU_NOCOMMON] = "nocommon",
[ATTRIBUTE_GNU_NOINLINE] = "noinline",
- [ATTRIBUTE_GNU_RETURNS_TWICE] = "returns_twice",
+ [ATTRIBUTE_GNU_NO_INSTRUMENT_FUNCTION] = "no_instrument_function",
+ [ATTRIBUTE_GNU_NONNULL] = "nonnull",
[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_NOTSHARED] = "notshared",
[ATTRIBUTE_GNU_PACKED] = "packed",
+ [ATTRIBUTE_GNU_PURE] = "pure",
+ [ATTRIBUTE_GNU_REGPARM] = "regparm",
+ [ATTRIBUTE_GNU_RETURNS_TWICE] = "returns_twice",
+ [ATTRIBUTE_GNU_SAVEALL] = "saveall",
+ [ATTRIBUTE_GNU_SECTION] = "section",
+ [ATTRIBUTE_GNU_SENTINEL] = "sentinel",
[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_SP_SWITCH] = "sp_switch",
[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_STDCALL] = "stdcall",
+ [ATTRIBUTE_GNU_TINY_DATA] = "tiny_data",
[ATTRIBUTE_GNU_TLS_MODEL] = "tls_model",
- [ATTRIBUTE_GNU_VISIBILITY] = "visibility",
- [ATTRIBUTE_GNU_REGPARM] = "regparm",
- [ATTRIBUTE_GNU_MODE] = "mode",
- [ATTRIBUTE_GNU_MODEL] = "model",
+ [ATTRIBUTE_GNU_TRANSPARENT_UNION] = "transparent_union",
[ATTRIBUTE_GNU_TRAP_EXIT] = "trap_exit",
- [ATTRIBUTE_GNU_SP_SWITCH] = "sp_switch",
- [ATTRIBUTE_GNU_SENTINEL] = "sentinel",
+ [ATTRIBUTE_GNU_UNUSED] = "unused",
+ [ATTRIBUTE_GNU_USED] = "used",
+ [ATTRIBUTE_GNU_VISIBILITY] = "visibility",
+ [ATTRIBUTE_GNU_VOLATILE] = "volatile",
+ [ATTRIBUTE_GNU_WARN_UNUSED_RESULT] = "warn_unused_result",
+ [ATTRIBUTE_GNU_WEAKREF] = "weakref",
+ [ATTRIBUTE_GNU_WEAK] = "weak",
[ATTRIBUTE_MS_ALIGN] = "align",
[ATTRIBUTE_MS_ALLOCATE] = "allocate",
- [ATTRIBUTE_MS_DLLIMPORT] = "dllimport",
+ [ATTRIBUTE_MS_DEPRECATED] = "deprecated",
[ATTRIBUTE_MS_DLLEXPORT] = "dllexport",
+ [ATTRIBUTE_MS_DLLIMPORT] = "dllimport",
[ATTRIBUTE_MS_NAKED] = "naked",
+ [ATTRIBUTE_MS_NOALIAS] = "noalias",
[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_RESTRICT] = "restrict",
+ [ATTRIBUTE_MS_RETURNS_TWICE] = "returns_twice",
[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)
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);
/* 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);
+ attribute_argument_t *arg = attribute->a.arguments;
+ if (arg == NULL) {
+ errorf(&attribute->pos, "__attribute__((mode(X))) misses argument");
+ return orig_type;
+ }
+
+ 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) {
+ if (streq_underscore("QI", symbol_str) ||
+ streq_underscore("byte", symbol_str)) {
akind = sign ? ATOMIC_TYPE_CHAR : ATOMIC_TYPE_UCHAR;
- } else if (strcmp_underscore("HI", symbol_str) == 0) {
+ } else if (streq_underscore("HI", symbol_str)) {
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) {
+ } else if (streq_underscore("SI", symbol_str)
+ || streq_underscore("word", symbol_str)
+ || streq_underscore("pointer", symbol_str)) {
akind = sign ? ATOMIC_TYPE_INT : ATOMIC_TYPE_UINT;
- } else if (strcmp_underscore("DI", symbol_str) == 0) {
+ } else if (streq_underscore("DI", symbol_str)) {
akind = sign ? ATOMIC_TYPE_LONGLONG : ATOMIC_TYPE_ULONGLONG;
} else {
- if (warning.other)
- warningf(&attribute->source_position, "ignoring unknown mode '%s'",
- symbol_str);
+ warningf(WARN_OTHER, &attribute->pos, "ignoring unknown mode '%s'",
+ symbol_str);
return orig_type;
}
- if (type->kind == TYPE_ATOMIC) {
+ if (type->kind == TYPE_ATOMIC || type->kind == TYPE_ENUM) {
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)");
+ warningf(WARN_OTHER, &attribute->pos, "__attribute__((mode)) on pointers not implemented yet (ignored)");
return type;
}
- errorf(&attribute->source_position,
+ errorf(&attribute->pos,
"__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)
{
}
if (!is_po2(alignment)) {
- errorf(&attribute->source_position,
- "alignment must be a power of 2 but is %d\n",
- alignment);
+ errorf(&attribute->pos, "alignment must be a power of 2 but is %d", alignment);
return;
}
if (alignment <= 0) {
- errorf(&attribute->source_position,
- "alignment must be bigger than 0 but is %d\n",
- alignment);
+ errorf(&attribute->pos, "alignment must be bigger than 0 but is %d", alignment);
return;
}
switch (entity->kind) {
- DECLARATION_KIND_CASES
+ case 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;
- }
+ entity->compound.alignment = MAX(entity->compound.alignment, (il_alignment_t)alignment);
break;
+
default:
- if (warning.other) {
- warningf(&attribute->source_position,
- "alignment attribute specification on '%S' ignored",
- entity->base.symbol);
- }
+ warningf(WARN_OTHER, &attribute->pos, "alignment attribute specification on '%N' ignored", entity);
+ break;
+ }
+}
+
+static const char *get_argument_string(const attribute_argument_t *argument)
+{
+ 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_literal.value.begin;
+}
+
+static void handle_attribute_visibility(const attribute_t *attribute,
+ entity_t *entity)
+{
+ /* 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;
+ if (arg == NULL) {
+ errorf(&attribute->pos,
+ "__attribute__((visibility(X))) misses argument");
+ return;
+ }
+ const char *string = get_argument_string(arg);
+ if (string == NULL) {
+ errorf(&attribute->pos,
+ "__attribute__((visibility(X))) argument is not a string");
+ return;
+ }
+ elf_visibility_tag_t visibility = get_elf_visibility_from_string(string);
+ if (visibility == ELF_VISIBILITY_ERROR) {
+ errorf(&attribute->pos,
+ "unknown visibility type '%s'", string);
+ return;
+ }
+
+ switch (entity->kind) {
+ case ENTITY_VARIABLE:
+ entity->variable.elf_visibility = visibility;
+ break;
+ case ENTITY_FUNCTION:
+ entity->function.elf_visibility = visibility;
+ break;
+
+ default:
+ warningf(WARN_OTHER, &attribute->pos, "visibility attribute specification on '%N' ignored", entity);
break;
}
}
if (attribute->a.arguments == NULL)
return;
- if (warning.other) {
- warningf(&attribute->source_position,
- "attribute '%s' needs no attributes",
- get_attribute_name(attribute->kind));
- }
+ position_t const *const pos = &attribute->pos;
+ char const *const what = get_attribute_name(attribute->kind);
+ warningf(WARN_OTHER, pos, "attribute '%s' needs no arguments", what);
}
static void handle_attribute_packed_e(const attribute_t *attribute,
{
#if 0
if (entity->kind != ENTITY_STRUCT) {
- warningf(&attribute->source_position,
- "packed attribute on %s '%s' ignored",
- get_entity_kind_name(entity->kind),
- entity->base.symbol->string);
+ warningf(WARN_OTHER, &attribute->pos, "packed attribute on '%N' ignored", entity);
return;
}
#endif
static void handle_attribute_packed(const attribute_t *attribute, type_t *type)
{
if (type->kind != TYPE_COMPOUND_STRUCT) {
- warningf(&attribute->source_position,
- "packed attribute on type '%T' ignored", type);
+ position_t const *const pos = &attribute->pos;
+ warningf(WARN_OTHER, pos, "packed attribute on type '%T' ignored", type);
return;
}
handle_attribute_packed_e(attribute, (entity_t*) type->compound.compound);
}
+static void handle_attribute_asm(const attribute_t *attribute,
+ entity_t *entity)
+{
+ attribute_argument_t *argument = attribute->a.arguments;
+ assert (argument->kind == ATTRIBUTE_ARGUMENT_EXPRESSION);
+ expression_t *expression = argument->v.expression;
+ if (expression->kind != EXPR_STRING_LITERAL)
+ errorf(&attribute->pos, "Invalid asm attribute expression");
+ symbol_t *sym = symbol_table_insert(expression->string_literal.value.begin);
+ entity->function.actual_name = sym;
+ assert(argument->next == NULL);
+ return;
+}
+
+static void handle_attribute_alias(const attribute_t *attribute,
+ entity_t *entity)
+{
+ // TODO: return if not at function_scope
+ attribute_argument_t *arg = attribute->a.arguments;
+ if (arg == NULL) {
+ errorf(&attribute->pos,
+ "__attribute__((alias(X))) misses argument");
+ return;
+ }
+ const char *string = get_argument_string(arg);
+ if (string == NULL) {
+ errorf(&attribute->pos,
+ "__attribute__((alias(X))) argument is not a string");
+ return;
+ }
+ symbol_t *symbol = symbol_table_insert(string);
+
+ switch (entity->kind) {
+ case ENTITY_VARIABLE:
+ entity->variable.alias = symbol;
+ break;
+ case ENTITY_FUNCTION:
+ entity->function.alias = symbol;
+ break;
+ default:
+ warningf(WARN_OTHER, &attribute->pos, "alias attribute on '%N' ignored", entity);
+ break;
+ }
+ return;
+}
+
void handle_entity_attributes(const attribute_t *attributes, entity_t *entity)
{
if (entity->kind == ENTITY_TYPEDEF) {
decl_modifiers_t modifiers = 0;
const attribute_t *attribute = attributes;
for ( ; attribute != NULL; attribute = attribute->next) {
- switch(attribute->kind) {
+ 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_UNUSED: modifiers |= DM_UNUSED; break;
case ATTRIBUTE_GNU_DLLIMPORT: modifiers |= DM_DLLIMPORT; break;
case ATTRIBUTE_GNU_DLLEXPORT: modifiers |= DM_DLLEXPORT; break;
+ case ATTRIBUTE_GNU_WEAK: modifiers |= DM_WEAK; break;
+ case ATTRIBUTE_GNU_LEAF: modifiers |= DM_LEAF; 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_ALIAS:
+ handle_attribute_alias(attribute, entity);
+ break;
+
case ATTRIBUTE_GNU_PACKED:
handle_attribute_packed_e(attribute, entity);
break;
+ case ATTRIBUTE_GNU_ASM:
+ handle_attribute_asm(attribute, entity);
+ break;
+
+ case ATTRIBUTE_GNU_VISIBILITY:
+ handle_attribute_visibility(attribute, entity);
+ break;
+
case ATTRIBUTE_MS_ALIGN:
case ATTRIBUTE_GNU_ALIGNED:
handle_attribute_aligned(attribute, entity);
}
if (modifiers != 0) {
- switch(entity->kind) {
+ switch (entity->kind) {
case ENTITY_TYPEDEF:
entity->typedefe.modifiers |= modifiers;
break;
return identify_new_type(new_type);
}
+static type_t *add_modifiers(type_t *type, decl_modifiers_t modifiers)
+{
+ if (is_typeref(type) || !is_type_function(type)) {
+ return type;
+ }
+
+ if ((type->function.modifiers & modifiers) == modifiers)
+ return type;
+
+ type_t* new_type = duplicate_type(type);
+ new_type->function.modifiers |= modifiers;
+ 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) {
+ switch (attribute->kind) {
case ATTRIBUTE_GNU_PACKED:
handle_attribute_packed(attribute, type);
- break;
+ break;
case ATTRIBUTE_GNU_CDECL:
case ATTRIBUTE_MS_CDECL:
type = change_calling_convention(type, CC_CDECL);
case ATTRIBUTE_MS_THISCALL:
type = change_calling_convention(type, CC_THISCALL);
break;
+ case ATTRIBUTE_GNU_RETURNS_TWICE:
+ case ATTRIBUTE_MS_RETURNS_TWICE:
+ type = add_modifiers(type, DM_RETURNS_TWICE);
+ break;
+ case ATTRIBUTE_GNU_NORETURN:
+ case ATTRIBUTE_MS_NORETURN:
+ type = add_modifiers(type, DM_NORETURN);
+ break;
+ case ATTRIBUTE_GNU_MALLOC:
+ case ATTRIBUTE_MS_ALLOCATE:
+ type = add_modifiers(type, DM_MALLOC);
+ break;
+ case ATTRIBUTE_GNU_NOTHROW:
+ case ATTRIBUTE_MS_NOTHROW:
+ type = add_modifiers(type, DM_NOTHROW);
+ break;
case ATTRIBUTE_GNU_MODE:
type = handle_attribute_mode(attribute, type);
break;
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 get_argument_string(argument);
}
return NULL;
}
/* TODO */
return false;
}
- panic("Unknown argument type found");
+ panic("unknown argument type");
}
static bool attribute_arguments_equal(const attribute_argument_t *args1,