Adapted cparser to CopyB lowering changes.
[cparser] / attribute.c
index 1a868d6..215a8e6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * 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
@@ -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) {
@@ -159,23 +166,18 @@ type_t *handle_attribute_mode(const attribute_t *attribute, type_t *orig_type)
        } 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);
+               source_position_t const *const pos = &attribute->source_position;
+               warningf(WARN_OTHER, 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)");
+               source_position_t const *const pos = &attribute->source_position;
+               warningf(WARN_OTHER, pos, "__attribute__((mode)) on pointers not implemented yet (ignored)");
                return type;
        }
 
@@ -220,17 +222,70 @@ static void handle_attribute_aligned(const attribute_t *attribute,
                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) {
-                       warningf(&attribute->source_position,
-                                        "alignment attribute specification on '%S' ignored",
-                                        entity->base.symbol);
-               }
+       default: {
+               source_position_t const *const pos  = &attribute->source_position;
+               char              const *const what = get_entity_kind_name(entity->kind);
+               symbol_t          const *const sym  = entity->base.symbol;
+               warningf(WARN_OTHER, pos, "alignment attribute specification on %s '%S' ignored", what, sym);
+               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: {
+               source_position_t const *const pos  = &attribute->source_position;
+               char              const *const what = get_entity_kind_name(entity->kind);
+               symbol_t          const *const sym  = entity->base.symbol;
+               warningf(WARN_OTHER, pos, "visibility attribute specification on %s '%S' ignored", what, sym);
+               break;
+       }
        }
 }
 
@@ -239,11 +294,9 @@ 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));
-       }
+       source_position_t const *const pos  = &attribute->source_position;
+       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,
@@ -251,10 +304,10 @@ 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);
+               source_position_t const *const pos  = &attribute->source_position;
+               char              const *const what = get_entity_kind_name(entity->kind);
+               symbol_t          const *const sym  = entity->base.symbol;
+               warningf(WARN_OTHER, pos, "packed attribute on %s '%S' ignored", what, sym);
                return;
        }
 #endif
@@ -266,14 +319,29 @@ static void handle_attribute_packed_e(const attribute_t *attribute,
 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);
+               source_position_t const *const pos  = &attribute->source_position;
+               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->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)
 {
        if (entity->kind == ENTITY_TYPEDEF) {
@@ -309,6 +377,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;
@@ -327,6 +396,14 @@ void handle_entity_attributes(const attribute_t *attributes, entity_t *entity)
                        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);
@@ -358,7 +435,7 @@ void handle_entity_attributes(const attribute_t *attributes, entity_t *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;
        }
 
@@ -377,7 +454,7 @@ type_t *handle_type_attributes(const attribute_t *attributes, type_t *type)
                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);
@@ -411,14 +488,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);
+       }
+}