X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=attribute.c;h=651c6ee5d91a3015e5cab4f1964d5b87f28aba83;hb=68bd88f459bc5d6031d3960629da6af5b164c2ab;hp=9718a213d4ec65e6db736b4a4bf584419a4eceb5;hpb=27040b8042ae6b0ac7974f52abd95d7562da6d9a;p=cparser diff --git a/attribute.c b/attribute.c index 9718a21..651c6ee 100644 --- a/attribute.c +++ b/attribute.c @@ -1,6 +1,6 @@ /* * This file is part of cparser. - * Copyright (C) 2007-2008 Matthias Braun + * Copyright (C) 2007-2009 Matthias Braun * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -24,6 +24,7 @@ #include "warning.h" #include "attribute_t.h" #include "symbol_t.h" +#include "adt/error.h" #include "type_t.h" static const char *const attribute_names[ATTRIBUTE_LAST+1] = { @@ -143,9 +144,15 @@ type_t *handle_attribute_mode(const attribute_t *attribute, type_t *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->source_position, + "__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) { @@ -196,7 +203,7 @@ static void handle_attribute_aligned(const attribute_t *attribute, target machine */ if (attribute->a.arguments) { attribute_argument_t *argument = attribute->a.arguments; - alignment = fold_constant(argument->v.expression); + alignment = fold_constant_to_int(argument->v.expression); } if (!is_po2(alignment)) { @@ -226,9 +233,64 @@ static void handle_attribute_aligned(const attribute_t *attribute, break; default: if (warning.other) { + const char *what = get_entity_kind_name(entity->kind); + warningf(&attribute->source_position, + "alignment attribute specification on %s '%S' ignored", + what, entity->base.symbol); + } + 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->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->source_position, + "__attribute__((visibility(X))) misses argument"); + return; + } + const char *string = get_argument_string(arg); + if (string == NULL) { + errorf(&attribute->source_position, + "__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->source_position, + "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: + if (warning.other) { + const char *what = get_entity_kind_name(entity->kind); warningf(&attribute->source_position, - "alignment attribute specification on '%S' ignored", - entity->base.symbol); + "visibility attribute specification on %s '%S' ignored", + what, entity->base.symbol); } break; } @@ -241,23 +303,52 @@ static void warn_arguments(const attribute_t *attribute) if (warning.other) { warningf(&attribute->source_position, - "attribute '%s' needs no attributes", + "attribute '%s' needs no arguments", get_attribute_name(attribute->kind)); } } -static void handle_attribute_packed(const attribute_t *attribute, - entity_t *entity) +static void handle_attribute_packed_e(const attribute_t *attribute, + entity_t *entity) { +#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); + return; + } +#endif + warn_arguments(attribute); + entity->compound.packed = true; +} - if (entity->kind == ENTITY_STRUCT) { - entity->compound.packed = true; - } else if (warning.other) { +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 %s ignored", - get_entity_kind_name(entity->kind)); + "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->source_position, + "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; } void handle_entity_attributes(const attribute_t *attributes, entity_t *entity) @@ -295,6 +386,7 @@ void handle_entity_attributes(const attribute_t *attributes, entity_t *entity) 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_MS_ALLOCATE: modifiers |= DM_MALLOC; break; case ATTRIBUTE_MS_DLLIMPORT: modifiers |= DM_DLLIMPORT; break; @@ -310,8 +402,17 @@ void handle_entity_attributes(const attribute_t *attributes, entity_t *entity) case ATTRIBUTE_MS_NOALIAS: modifiers |= DM_NOALIAS; break; case ATTRIBUTE_GNU_PACKED: - handle_attribute_packed(attribute, entity); - break; + 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); @@ -341,15 +442,9 @@ void handle_entity_attributes(const attribute_t *attributes, entity_t *entity) } } -static type_t *change_calling_convention(const source_position_t *pos, - type_t *type, cc_kind_t cconv) +static type_t *change_calling_convention(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); - } + if (is_typeref(type) || !is_type_function(type)) { return type; } @@ -366,24 +461,23 @@ 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_PACKED: + handle_attribute_packed(attribute, type); + break; case ATTRIBUTE_GNU_CDECL: case ATTRIBUTE_MS_CDECL: - type = change_calling_convention(&attribute->source_position, - type, CC_CDECL); + type = change_calling_convention(type, CC_CDECL); break; case ATTRIBUTE_MS_STDCALL: case ATTRIBUTE_GNU_STDCALL: - type = change_calling_convention(&attribute->source_position, - type, CC_STDCALL); + type = change_calling_convention(type, CC_STDCALL); break; case ATTRIBUTE_MS_FASTCALL: case ATTRIBUTE_GNU_FASTCALL: - type = change_calling_convention(&attribute->source_position, - type, CC_FASTCALL); + type = change_calling_convention(type, CC_FASTCALL); break; case ATTRIBUTE_MS_THISCALL: - type = change_calling_convention(&attribute->source_position, - type, CC_THISCALL); + type = change_calling_convention(type, CC_THISCALL); break; case ATTRIBUTE_GNU_MODE: type = handle_attribute_mode(attribute, type); @@ -403,14 +497,56 @@ const char *get_deprecated_string(const attribute_t *attribute) 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; } + +static bool property_attribute_equal(const attribute_property_argument_t *prop1, + const attribute_property_argument_t *prop2) +{ + return prop1->put_symbol == prop2->put_symbol + && prop1->get_symbol == prop2->get_symbol; +} + +static bool attribute_argument_equal(const attribute_argument_t *arg1, + const attribute_argument_t *arg2) +{ + if (arg1->kind != arg2->kind) + return false; + + switch (arg1->kind) { + case ATTRIBUTE_ARGUMENT_SYMBOL: + return arg1->v.symbol == arg2->v.symbol; + case ATTRIBUTE_ARGUMENT_EXPRESSION: + /* TODO */ + return false; + } + panic("Unknown argument type found"); +} + +static bool attribute_arguments_equal(const attribute_argument_t *args1, + const attribute_argument_t *args2) +{ + for ( ; args1 != NULL && args2 != NULL; + args1 = args1->next, args2 = args2->next) { + if (!attribute_argument_equal(args1, args2)) + return false; + } + /* both should be NULL now */ + return args1 == args2; +} + +bool attributes_equal(const attribute_t *attr1, const attribute_t *attr2) +{ + if (attr1->kind != attr2->kind) + return false; + + switch (attr1->kind) { + case ATTRIBUTE_MS_PROPERTY: + return property_attribute_equal(attr1->a.property, attr2->a.property); + default: + return attribute_arguments_equal(attr1->a.arguments, + attr2->a.arguments); + } +}