+ }
+}
+
+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;
+ }
+ }