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:
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);
}
}
{
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;
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;
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) {
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;
unsigned elf_visibility : 2;
initializer_t *initializer;
+ symbol_t *alias; /**< gnu extension attribute alias */
/* ast2firm info */
union {
scope_t parameters;
statement_t *body;
symbol_t *actual_name; /**< gnu extension __REDIRECT */
+ symbol_t *alias; /**< gnu extension attribute alias */
/* ast2firm info */
union {
-Subproject commit 6911c8a5253d79be26f5fcb668b7fb69f1998819
+Subproject commit 828bda9d31a92928f8e7b211a1f3cf9d9de724bb
if (attributes != NULL) {
handle_entity_attributes(attributes, entity);
+ // TODO: maybe drop alias symbol here if not file_scope
}
if (entity->kind == ENTITY_FUNCTION && !freestanding) {
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
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;
}
}
+ /* 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;
*/
static void check_unused_globals(void)
{
+ mark_aliases_used();
+
if (!is_warn_on(WARN_UNUSED_FUNCTION) && !is_warn_on(WARN_UNUSED_VARIABLE))
return;