simple support for __attribute__((alias("symbol"))) alias
authorSzabolcs Nagy <nsz@port70.net>
Thu, 27 Dec 2012 15:38:52 +0000 (16:38 +0100)
committerSzabolcs Nagy <nsz@port70.net>
Thu, 27 Dec 2012 15:38:52 +0000 (16:38 +0100)
ast2firm.c
attribute.c
entity_t.h
libfirm
parser.c

index c93c67c..8d24dd7 100644 (file)
@@ -894,6 +894,8 @@ static bool declaration_is_definition(const entity_t *entity)
        switch (entity->kind) {
        case ENTITY_VARIABLE:
                return entity->declaration.storage_class != STORAGE_CLASS_EXTERN;
+// TODO: alias provides a definition
+//                    || entity->variable.alias != NULL;
        case ENTITY_FUNCTION:
                return entity->function.body != NULL;
        case ENTITY_PARAMETER:
@@ -939,8 +941,10 @@ static void handle_decl_modifiers(ir_entity *irentity, entity_t *entity)
        if ((modifiers & DM_USED) && declaration_is_definition(entity)) {
                add_entity_linkage(irentity, IR_LINKAGE_HIDDEN_USER);
        }
-       if ((modifiers & DM_WEAK) && declaration_is_definition(entity)
-           && entity->declaration.storage_class != STORAGE_CLASS_EXTERN) {
+// TODO: i dont understand this logic
+//     if ((modifiers & DM_WEAK) && declaration_is_definition(entity)
+//         && entity->declaration.storage_class != STORAGE_CLASS_EXTERN) {
+       if (modifiers & DM_WEAK) {
                add_entity_linkage(irentity, IR_LINKAGE_WEAK);
        }
 }
@@ -4675,6 +4679,18 @@ static void create_variable_initializer(entity_t *entity)
 {
        assert(entity->kind == ENTITY_VARIABLE);
        initializer_t *initializer = entity->variable.initializer;
+       if (entity->variable.alias != NULL) {
+               const namespace_tag_t namespc = (namespace_tag_t)entity->base.namespc;
+               entity_t *a = entity->variable.alias->entity;
+               for (; a != NULL; a = a->base.symbol_next) {
+                       if ((namespace_tag_t)a->base.namespc == namespc)
+                               break;
+               }
+               assert(a != NULL && a->kind == ENTITY_VARIABLE && a->variable.v.entity != NULL);
+               set_entity_alias(entity->variable.v.entity, a->variable.v.entity);
+               /* prevent usage assumption to be made about aliased variables */
+               add_entity_linkage(a->variable.v.entity, IR_LINKAGE_HIDDEN_USER);
+       }
        if (initializer == NULL)
                return;
 
@@ -5795,6 +5811,21 @@ static void create_function(entity_t *entity)
        assert(entity->kind == ENTITY_FUNCTION);
        ir_entity *function_entity = get_function_entity(entity, current_outer_frame);
 
+       if (entity->function.alias != NULL) {
+               const namespace_tag_t namespc = (namespace_tag_t)entity->base.namespc;
+               entity_t *a = entity->function.alias->entity;
+               for (; a != NULL; a = a->base.symbol_next) {
+                       if ((namespace_tag_t)a->base.namespc == namespc)
+                               break;
+               }
+// TODO: or use entitymap
+//             ir_entity *a = entitymap_get(&entitymap, entity->function.alias);
+               assert(a != NULL && a->kind == ENTITY_VARIABLE && a->function.irentity != NULL);
+               set_entity_alias(entity->function.irentity, a->function.irentity);
+               /* prevent usage assumption to be made about aliased functions */
+               add_entity_linkage(a->function.irentity, IR_LINKAGE_HIDDEN_USER);
+       }
+
        if (entity->function.body == NULL)
                return;
 
index a29299a..8059435 100644 (file)
@@ -295,6 +295,38 @@ static void handle_attribute_asm(const attribute_t *attribute,
        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) {
@@ -338,6 +370,10 @@ void handle_entity_attributes(const attribute_t *attributes, entity_t *entity)
                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;
index f2ee603..e9108bc 100644 (file)
@@ -212,6 +212,7 @@ struct variable_t {
        unsigned          elf_visibility : 2;
 
        initializer_t    *initializer;
+       symbol_t         *alias;               /**< gnu extension attribute alias */
 
        /* ast2firm info */
        union {
@@ -233,6 +234,7 @@ struct function_t {
        scope_t        parameters;
        statement_t   *body;
        symbol_t      *actual_name;        /**< gnu extension __REDIRECT */
+       symbol_t      *alias;              /**< gnu extension attribute alias */
 
        /* ast2firm info */
        union {
diff --git a/libfirm b/libfirm
index 6911c8a..828bda9 160000 (submodule)
--- a/libfirm
+++ b/libfirm
@@ -1 +1 @@
-Subproject commit 6911c8a5253d79be26f5fcb668b7fb69f1998819
+Subproject commit 828bda9d31a92928f8e7b211a1f3cf9d9de724bb
index b637dd2..38f8794 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -3755,6 +3755,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
 
        if (attributes != NULL) {
                handle_entity_attributes(attributes, entity);
+               // TODO: maybe drop alias symbol here if not file_scope
        }
 
        if (entity->kind == ENTITY_FUNCTION && !freestanding) {
@@ -3907,6 +3908,50 @@ static void merge_in_attributes(declaration_t *decl, attribute_t *attributes)
 
 static bool is_main(entity_t*);
 
+/*
+__attribute__(alias("sym")) provides a definition
+in function scope function and variable declarations
+
+the sym must be declared in the same translation unit
+but the sym declaration can come later than the alias one
+(weakref is not supported)
+
+sym must be marked used
+*/
+static struct alias {
+       struct alias *next;
+       entity_t *entity;
+       symbol_t *symbol;
+} *aliases;
+static void add_alias(entity_t *entity, symbol_t *symbol)
+{
+       struct alias *a;
+
+       assert(entity->kind == ENTITY_FUNCTION || entity->kind == ENTITY_VARIABLE);
+       a = malloc(sizeof *a);
+       a->entity = entity;
+       a->symbol = symbol;
+       a->next = aliases;
+       aliases = a;
+}
+static void mark_aliases_used(void)
+{
+       struct alias *alias;
+       for (alias = aliases; alias; alias = alias->next) {
+               const namespace_tag_t namespc = (namespace_tag_t)alias->entity->base.namespc;
+               entity_t *entity = get_entity(alias->symbol, namespc);
+               if (entity == NULL) {
+                       errorf(&alias->entity->base.pos, "'%N' is aliased to undefined symbol \"%s\"", alias->entity, alias->symbol->string);
+               } else if (entity->base.parent_scope != file_scope) {
+                       errorf(&alias->entity->base.pos, "'%N' is aliased to undefined symbol \"%s\" (TODO: scope)", alias->entity, alias->symbol->string);
+               } else {
+                       // printf("handle alias %s -> %s\n", alias->entity->base.symbol->string, alias->symbol->string);
+                       assert(entity->kind == ENTITY_FUNCTION || entity->kind == ENTITY_VARIABLE);
+                       entity->declaration.used = true;
+               }
+       }
+}
+
 /**
  * record entities for the NAMESPACE_NORMAL, and produce error messages/warnings
  * for various problems that occur for multiple definitions
@@ -3952,6 +3997,27 @@ entity_t *record_entity(entity_t *entity, const bool is_definition)
                warningf(WARN_NESTED_EXTERNS, pos, "nested extern declaration of '%#N'", entity);
        }
 
+       if (current_scope == file_scope) {
+               if (entity->kind == ENTITY_FUNCTION) {
+                       if (entity->function.alias) {
+                               if (is_definition)
+                                       errorf(pos, "definition of '%N' with alias attribute", entity);
+                               /* TODO alias provides a definition */
+                               *(bool*)&is_definition = true;
+                               add_alias(entity, entity->function.alias);
+                       }
+               }
+               if (entity->kind == ENTITY_VARIABLE) {
+                       if (entity->variable.alias) {
+                               if (is_definition)
+                                       errorf(pos, "definition of '%N' with alias attribute", entity);
+                               /* TODO alias provides a definition */
+                               *(bool*)&is_definition = true;
+                               add_alias(entity, entity->variable.alias);
+                       }
+               }
+       }
+
        if (previous_entity != NULL) {
                position_t const *const ppos = &previous_entity->base.pos;
 
@@ -4094,6 +4160,16 @@ error_redeclaration:
                                }
                        }
 
+                       /* merge alias attribute into earlier declaration */
+                       if (entity->kind == ENTITY_FUNCTION) {
+                               if (entity->function.alias)
+                                       previous_entity->function.alias = entity->function.alias;
+                       }
+                       if (entity->kind == ENTITY_VARIABLE) {
+                               if (entity->variable.alias)
+                                       previous_entity->variable.alias = entity->variable.alias;
+                       }
+
                        prev_decl->modifiers |= decl->modifiers;
                        if (entity->kind == ENTITY_FUNCTION) {
                                previous_entity->function.is_inline |= entity->function.is_inline;
@@ -10068,6 +10144,8 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
  */
 static void check_unused_globals(void)
 {
+       mark_aliases_used();
+
        if (!is_warn_on(WARN_UNUSED_FUNCTION) && !is_warn_on(WARN_UNUSED_VARIABLE))
                return;