Do not get the break block of a switch before it is sure that a jump there is actuall...
[cparser] / attribute.c
index 2c5e90b..1ccdc5d 100644 (file)
@@ -20,6 +20,7 @@
 #include <config.h>
 
 #include <assert.h>
+#include "adt/strutil.h"
 #include "diagnostic.h"
 #include "warning.h"
 #include "attribute_t.h"
@@ -119,22 +120,6 @@ 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);
@@ -144,39 +129,40 @@ 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) {
+       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);
+               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;
        }
 
@@ -214,25 +200,78 @@ static void handle_attribute_aligned(const attribute_t *attribute,
        }
 
        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) {
+               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;
+       }
+       }
 }
 
 static void warn_arguments(const attribute_t *attribute)
@@ -240,11 +279,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 arguments",
-                                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,
@@ -252,10 +289,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
@@ -267,8 +304,8 @@ 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;
        }
 
@@ -309,15 +346,11 @@ void handle_entity_attributes(const attribute_t *attributes, entity_t *entity)
                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;
@@ -327,14 +360,10 @@ void handle_entity_attributes(const attribute_t *attributes, entity_t *entity)
                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_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;
@@ -348,6 +377,10 @@ void handle_entity_attributes(const attribute_t *attributes, entity_t *entity)
                        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);
@@ -391,6 +424,20 @@ static type_t *change_calling_convention(type_t *type, cc_kind_t cconv)
        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;
@@ -414,6 +461,22 @@ type_t *handle_type_attributes(const attribute_t *attributes, type_t *type)
                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;
@@ -432,14 +495,7 @@ 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->literal.value.begin;
+               return get_argument_string(argument);
        }
        return NULL;
 }