/*
* This file is part of cparser.
- * Copyright (C) 2007-2008 Matthias Braun <matze@braunis.de>
+ * 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
#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] = {
/* 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) {
break;
case ENTITY_STRUCT:
case ENTITY_UNION:
- if (alignment > entity->compound.alignment) {
+ if (alignment > (int)entity->compound.alignment) {
entity->compound.alignment = alignment;
}
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);
+ "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,
+ "visibility attribute specification on %s '%S' ignored",
+ what, entity->base.symbol);
}
break;
}
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)
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;
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);
static type_t *change_calling_convention(type_t *type, cc_kind_t cconv)
{
- if (!is_type_function(type)) {
+ if (is_typeref(type) || !is_type_function(type)) {
return 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(type, CC_CDECL);
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);
+ }
+}