diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2022-06-15 19:44:36 +0200 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2022-06-15 20:11:04 +0200 |
commit | 636b01ab4910da0b96d844301fea1a2b56c5344d (patch) | |
tree | 480d97c9a670995fe519be3a7f8b86c5e97e50cb /gcc/d | |
parent | 49d14a841fd9a798fe6d68ae49c6fbb753d21032 (diff) | |
download | gcc-636b01ab4910da0b96d844301fea1a2b56c5344d.zip gcc-636b01ab4910da0b96d844301fea1a2b56c5344d.tar.gz gcc-636b01ab4910da0b96d844301fea1a2b56c5344d.tar.bz2 |
d: Add `@visibility' and `@hidden' attributes.
The `@visibility' attribute is functionality the same as
`__attribute__((visibility))', and `@hidden' is a convenience alias to
`@visibility("hidden")' defined in the `gcc.attributes' module.
As the visibility of a symbol is also indirectly controlled by the
`export' keyword, the handling of this in the code generation pass has
been improved so that conflicts will be appropriately diagnosed.
gcc/d/ChangeLog:
* d-attribs.cc (d_langhook_attribute_table): Add visibility.
(insert_type_attribute): Use decl_attributes instead of
merge_attributes.
(insert_decl_attribute): Likewise.
(apply_user_attributes): Do nothing when no UDAs applied.
(d_handle_visibility_attribute): New function.
* d-gimplify.cc (d_gimplify_binary_expr): Adjust.
* d-tree.h (set_visibility_for_decl): Declare.
* decl.cc (get_symbol_decl): Move setting of visibility flags to...
(set_visibility_for_decl): ... here. New function.
* types.cc (TypeVisitor::visit (TypeStruct *)): Call
set_visibility_for_decl().
(TypeVisitor::visit (TypeClass *)): Likewise.
gcc/testsuite/ChangeLog:
* gdc.dg/attr_visibility1.d: New test.
* gdc.dg/attr_visibility2.d: New test.
* gdc.dg/attr_visibility3.d: New test.
libphobos/ChangeLog:
* libdruntime/gcc/attributes.d (visibility): Define.
(hidden): Define.
Diffstat (limited to 'gcc/d')
-rw-r--r-- | gcc/d/d-attribs.cc | 98 | ||||
-rw-r--r-- | gcc/d/d-gimplify.cc | 4 | ||||
-rw-r--r-- | gcc/d/d-tree.h | 1 | ||||
-rw-r--r-- | gcc/d/decl.cc | 54 | ||||
-rw-r--r-- | gcc/d/types.cc | 2 |
5 files changed, 127 insertions, 32 deletions
diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc index b8ce30c..4c6e7a7 100644 --- a/gcc/d/d-attribs.cc +++ b/gcc/d/d-attribs.cc @@ -77,6 +77,7 @@ static tree d_handle_alloc_size_attribute (tree *, tree, tree, int, bool *); static tree d_handle_cold_attribute (tree *, tree, tree, int, bool *); static tree d_handle_restrict_attribute (tree *, tree, tree, int, bool *); static tree d_handle_used_attribute (tree *, tree, tree, int, bool *); +static tree d_handle_visibility_attribute (tree *, tree, tree, int, bool *); /* Helper to define attribute exclusions. */ #define ATTR_EXCL(name, function, type, variable) \ @@ -223,6 +224,8 @@ const attribute_spec d_langhook_attribute_table[] = d_handle_restrict_attribute, NULL), ATTR_SPEC ("used", 0, 0, true, false, false, false, d_handle_used_attribute, NULL), + ATTR_SPEC ("visibility", 1, 1, false, false, false, false, + d_handle_visibility_attribute, NULL), ATTR_SPEC (NULL, 0, 0, false, false, false, false, NULL, NULL), }; @@ -238,10 +241,9 @@ insert_type_attribute (tree type, const char *attrname, tree value) if (value) value = tree_cons (NULL_TREE, value, NULL_TREE); - tree attribs = merge_attributes (TYPE_ATTRIBUTES (type), - tree_cons (ident, value, NULL_TREE)); - - return build_type_attribute_variant (type, attribs); + decl_attributes (&type, build_tree_list (ident, value), + ATTR_FLAG_TYPE_IN_PLACE); + return type; } /* Insert the decl attribute ATTRNAME with value VALUE into DECL. */ @@ -254,10 +256,9 @@ insert_decl_attribute (tree decl, const char *attrname, tree value) if (value) value = tree_cons (NULL_TREE, value, NULL_TREE); - tree attribs = merge_attributes (DECL_ATTRIBUTES (decl), - tree_cons (ident, value, NULL_TREE)); + decl_attributes (&decl, build_tree_list (ident, value), 0); - return build_decl_attribute_variant (decl, attribs); + return decl; } /* Returns TRUE if NAME is an attribute recognized as being handled by @@ -414,12 +415,7 @@ void apply_user_attributes (Dsymbol *sym, tree node) { if (!sym->userAttribDecl) - { - if (DECL_P (node) && DECL_ATTRIBUTES (node) != NULL) - decl_attributes (&node, DECL_ATTRIBUTES (node), 0); - - return; - } + return; location_t saved_location = input_location; input_location = make_location_t (sym->loc); @@ -1412,3 +1408,79 @@ d_handle_used_attribute (tree *node, tree name, tree, int, bool *no_add_attrs) return NULL_TREE; } + +/* Handle an "visibility" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +d_handle_visibility_attribute (tree *node, tree name, tree args, + int, bool *) +{ + /* If this is a type, set the visibility on the type decl. */ + tree decl = *node; + if (TYPE_P (decl)) + { + decl = TYPE_NAME (decl); + if (decl == NULL_TREE || TREE_CODE (decl) != TYPE_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored on types", name); + return NULL_TREE; + } + } + + if (decl_function_context (decl) != 0 || !TREE_PUBLIC (decl)) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + return NULL_TREE; + } + + tree id = TREE_VALUE (args); + if (TREE_CODE (id) != STRING_CST) + { + error ("visibility argument not a string"); + return NULL_TREE; + } + + enum symbol_visibility vis; + if (strcmp (TREE_STRING_POINTER (id), "default") == 0) + vis = VISIBILITY_DEFAULT; + else if (strcmp (TREE_STRING_POINTER (id), "internal") == 0) + vis = VISIBILITY_INTERNAL; + else if (strcmp (TREE_STRING_POINTER (id), "hidden") == 0) + vis = VISIBILITY_HIDDEN; + else if (strcmp (TREE_STRING_POINTER (id), "protected") == 0) + vis = VISIBILITY_PROTECTED; + else + { + error ("attribute %qE argument must be one of %qs, %qs, %qs, or %qs", + name, "default", "hidden", "protected", "internal"); + vis = VISIBILITY_DEFAULT; + } + + if (DECL_VISIBILITY_SPECIFIED (decl) && vis != DECL_VISIBILITY (decl)) + { + tree attributes = (TYPE_P (*node) + ? TYPE_ATTRIBUTES (*node) + : DECL_ATTRIBUTES (decl)); + if (lookup_attribute ("visibility", attributes)) + error ("%qD redeclared with different visibility", decl); + else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES + && lookup_attribute ("dllimport", attributes)) + error ("%qD was declared %qs which implies default visibility", + decl, "export"); + else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES + && lookup_attribute ("dllexport", attributes)) + error ("%qD was declared %qs which implies default visibility", + decl, "export"); + } + + DECL_VISIBILITY (decl) = vis; + DECL_VISIBILITY_SPECIFIED (decl) = 1; + + /* Go ahead and attach the attribute to the node as well. This is needed + so we can determine whether we have VISIBILITY_DEFAULT because the + visibility was not specified, or because it was explicitly overridden + from the containing scope. */ + + return NULL_TREE; +} diff --git a/gcc/d/d-gimplify.cc b/gcc/d/d-gimplify.cc index 36b76da..33fe65c 100644 --- a/gcc/d/d-gimplify.cc +++ b/gcc/d/d-gimplify.cc @@ -235,10 +235,10 @@ d_gimplify_binary_expr (tree *expr_p) if (bit_field_ref (op0) || bit_field_ref (op1)) { if (TREE_TYPE (op0) != TREE_TYPE (*expr_p)) - TREE_OPERAND (*expr_p, 0) = convert (TREE_TYPE (*expr_p), op0); + TREE_OPERAND (*expr_p, 0) = convert (TREE_TYPE (*expr_p), op0); if (TREE_TYPE (op1) != TREE_TYPE (*expr_p)) - TREE_OPERAND (*expr_p, 1) = convert (TREE_TYPE (*expr_p), op1); + TREE_OPERAND (*expr_p, 1) = convert (TREE_TYPE (*expr_p), op1); return GS_OK; } diff --git a/gcc/d/d-tree.h b/gcc/d/d-tree.h index 48a40a6..7517463 100644 --- a/gcc/d/d-tree.h +++ b/gcc/d/d-tree.h @@ -654,6 +654,7 @@ extern tree build_artificial_decl (tree, tree, const char * = NULL); extern tree create_field_decl (tree, const char *, int, int); extern void build_type_decl (tree, Dsymbol *); extern void set_linkage_for_decl (tree); +extern void set_visibility_for_decl (tree, Dsymbol *); /* In expr.cc. */ extern tree build_expr (Expression *, bool = false, bool = false); diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index 518d84c..8676a1b 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -1343,27 +1343,10 @@ get_symbol_decl (Declaration *decl) if (decl->storage_class & STCvolatile) TREE_THIS_VOLATILE (decl->csym) = 1; - /* Visibility attributes are used by the debugger. */ - if (decl->visibility.kind == Visibility::private_) - TREE_PRIVATE (decl->csym) = 1; - else if (decl->visibility.kind == Visibility::protected_) - TREE_PROTECTED (decl->csym) = 1; - /* Likewise, so could the deprecated attribute. */ if (decl->storage_class & STCdeprecated) TREE_DEPRECATED (decl->csym) = 1; -#if TARGET_DLLIMPORT_DECL_ATTRIBUTES - /* Have to test for import first. */ - if (decl->isImportedSymbol ()) - { - insert_decl_attribute (decl->csym, "dllimport"); - DECL_DLLIMPORT_P (decl->csym) = 1; - } - else if (decl->isExport ()) - insert_decl_attribute (decl->csym, "dllexport"); -#endif - if (decl->isDataseg () || decl->isCodeseg () || decl->isThreadlocal ()) { /* Set TREE_PUBLIC by default, but allow private template to override. */ @@ -1374,6 +1357,9 @@ get_symbol_decl (Declaration *decl) /* The decl has not been defined -- yet. */ DECL_EXTERNAL (decl->csym) = 1; + /* Visibility attributes are used by the debugger. */ + set_visibility_for_decl (decl->csym, decl); + DECL_INSTANTIATED (decl->csym) = (decl->isInstantiated () != NULL); set_linkage_for_decl (decl->csym); } @@ -2447,3 +2433,37 @@ set_linkage_for_decl (tree decl) if (DECL_ARTIFICIAL (decl)) return d_weak_linkage (decl); } + +/* NODE is a FUNCTION_DECL, VAR_DECL or RECORD_TYPE for the declaration SYM. + Set flags to reflect visibility that NODE will get in the object file. */ + +void +set_visibility_for_decl (tree node, Dsymbol *sym) +{ + Visibility visibility = sym->visible (); + if (visibility.kind == Visibility::private_) + TREE_PRIVATE (node) = 1; + else if (visibility.kind == Visibility::protected_) + TREE_PROTECTED (node) = 1; + + /* If the declaration was declared `export', append either the dllimport + or dllexport attribute. */ + if (TARGET_DLLIMPORT_DECL_ATTRIBUTES) + { + const char *attrname = NULL; + + /* Have to test for import first. */ + if (sym->isImportedSymbol ()) + attrname = "dllimport"; + else if (sym->isExport ()) + attrname = "dllexport"; + + if (attrname != NULL) + { + if (DECL_P (node)) + insert_decl_attribute (node, attrname); + else if (TYPE_P (node)) + insert_type_attribute (node, attrname); + } + } +} diff --git a/gcc/d/types.cc b/gcc/d/types.cc index 0926715..b706c91 100644 --- a/gcc/d/types.cc +++ b/gcc/d/types.cc @@ -1180,6 +1180,7 @@ public: /* Put out all fields. */ layout_aggregate_type (t->sym, t->ctype, t->sym); build_type_decl (t->ctype, t->sym); + set_visibility_for_decl (t->ctype, t->sym); apply_user_attributes (t->sym, t->ctype); finish_aggregate_type (structsize, alignsize, t->ctype); } @@ -1224,6 +1225,7 @@ public: /* Put out all fields, including from each base class. */ layout_aggregate_type (t->sym, basetype, t->sym); build_type_decl (basetype, t->sym); + set_visibility_for_decl (basetype, t->sym); apply_user_attributes (t->sym, basetype); finish_aggregate_type (t->sym->structsize, t->sym->alignsize, basetype); |