diff options
author | Jason Merrill <jason@redhat.com> | 2006-06-29 21:15:56 -0400 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2006-06-29 21:15:56 -0400 |
commit | b9e75696307f710a22c726e72b00e7a7161ad89f (patch) | |
tree | 93c1ec7ec5a70cb4b7384fa239594ed2f1288585 /gcc | |
parent | dc2843f38c04c81e9f20a6e9e6ae9637ace6e08c (diff) | |
download | gcc-b9e75696307f710a22c726e72b00e7a7161ad89f.zip gcc-b9e75696307f710a22c726e72b00e7a7161ad89f.tar.gz gcc-b9e75696307f710a22c726e72b00e7a7161ad89f.tar.bz2 |
re PR c++/26905 (default-visibility class symbol improperly resolved as hidden-visibility)
PR c++/26905
PR c++/26612
PR c++/27000
PR c++/26984
PR c++/19134
* tree.c (build_decl_stat): Don't hande #pragma visibility here.
* c-common.c (c_determine_visibility): Handle it here.
* c-decl.c (finish_decl): Call c_determine_visibility for
functions, too.
* flags.h (enum symbol_visibility): Sort from most to least visibility.
* tree.h: Likewise.
* varasm.c (default_assemble_visibility): Likewise.
* c-common.c (handle_visibility_attribute): Complain about trying
to give visibility to an already defined class, or trying to change
declared visibility. Always attach the attribute.
* cp/decl2.c (determine_visibility): Overhaul.
(determine_visibility_from_class): Likewise.
(min_vis_r, type_visibility, constrain_visibility): New fns.
(constrain_visibility_for_template): Likewise.
(constrain_class_visibility): Likewise.
* cp/decl.c (cp_finish_decl): Call determine_visibility for function
decls, too.
* cp/name-lookup.c (pushtag): Call determine_visibility.
* cp/decl.c (duplicate_decls): Don't copy visibility from template to
specialization.
* cp/pt.c (check_explicit_specialization): Likewise.
(lookup_template_class, tsubst_decl): Call determine_visibility.
* cp/class.c (finish_struct_1): Call constrain_class_visibility.
PR c++/26905
PR c++/21675
PR c++/17470
* cp/parser.c (cp_parser_explicit_instantiation): Pass the attributes
to grokdeclarator.
(cp_parser_type_specifier): Allow 'enum __attribute ((...)) E'.
(cp_parser_enum_specifier): Likewise.
(cp_parser_elaborated_type_specifier): Apply attributes if this
declares only the class.
(cp_parser_class_specifier): Apply leading attributes immediately.
* cp/semantics.c (begin_class_definition): Add attributes parameter,
apply them to the type.
* attribs.c (decl_attributes): Ignore type-in-place attributes
once the type has been defined.
PR c++/21581
PR c++/25915
* cp/tree.c (decl_anon_ns_mem_p): New function.
* cp/cp-tree.h: Declare it.
* cp/decl2.c (determine_visibility): Make anonymous namespace
members static.
(min_vis_r, constrain_visibility): Likewise.
* cp/rtti.c (create_pseudo_type_info): Set TREE_PUBLIC on
pseudo-types.
* cp/decl.c (cxx_init_decl_processing): Set TREE_PUBLIC on
global_namespace.
* cp/name-lookup.c (push_namespace_with_attribs): Don't set TREE_PUBLIC
on anonymous namespaces.
From-SVN: r115086
Diffstat (limited to 'gcc')
41 files changed, 887 insertions, 207 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bd6e077..e5cc18a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,27 @@ +2006-06-29 Jason Merrill <jason@redhat.com> + + PR c++/26905 + PR c++/26612 + PR c++/27000 + PR c++/26984 + PR c++/19134 + * tree.c (build_decl_stat): Don't hande #pragma visibility here. + * c-common.c (c_determine_visibility): Handle it here. + * c-decl.c (finish_decl): Call c_determine_visibility for + functions, too. + * flags.h (enum symbol_visibility): Sort from most to least visibility. + * tree.h: Likewise. + * varasm.c (default_assemble_visibility): Likewise. + * c-common.c (handle_visibility_attribute): Complain about trying + to give visibility to an already defined class, or trying to change + declared visibility. Always attach the attribute. + + PR c++/26905 + PR c++/21675 + PR c++/17470 + * attribs.c (decl_attributes): Ignore type-in-place attributes + once the type has been defined. + 2006-06-29 Roger Sayle <roger@eyesopen.com> PR middle-end/27428 diff --git a/gcc/attribs.c b/gcc/attribs.c index 3ecc473..7377c57 100644 --- a/gcc/attribs.c +++ b/gcc/attribs.c @@ -250,6 +250,14 @@ decl_attributes (tree *node, tree attributes, int flags) } } + if (TYPE_P (*anode) + && (flags & (int) ATTR_FLAG_TYPE_IN_PLACE) + && TYPE_SIZE (*anode) != NULL_TREE) + { + warning (OPT_Wattributes, "type attributes ignored after type is already defined"); + continue; + } + if (spec->handler != NULL) returned_attrs = chainon ((*spec->handler) (anode, name, args, flags, &no_add_attrs), diff --git a/gcc/c-common.c b/gcc/c-common.c index dd03a25..ac7dd7d 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -4876,21 +4876,28 @@ handle_weakref_attribute (tree *node, tree ARG_UNUSED (name), tree args, static tree handle_visibility_attribute (tree *node, tree name, tree args, int ARG_UNUSED (flags), - bool *no_add_attrs) + bool *ARG_UNUSED (no_add_attrs)) { tree decl = *node; tree id = TREE_VALUE (args); - - *no_add_attrs = true; + enum symbol_visibility vis; if (TYPE_P (*node)) { - if (TREE_CODE (*node) != RECORD_TYPE && TREE_CODE (*node) != UNION_TYPE) - { - warning (OPT_Wattributes, "%qE attribute ignored on non-class types", - name); - return NULL_TREE; - } + if (TREE_CODE (*node) == ENUMERAL_TYPE) + /* OK */; + else if (TREE_CODE (*node) != RECORD_TYPE && TREE_CODE (*node) != UNION_TYPE) + { + warning (OPT_Wattributes, "%qE attribute ignored on non-class types", + name); + return NULL_TREE; + } + else if (TYPE_FIELDS (*node)) + { + error ("%qE attribute ignored because %qT is already defined", + name, *node); + return NULL_TREE; + } } else if (decl_function_context (decl) != 0 || !TREE_PUBLIC (decl)) { @@ -4919,23 +4926,33 @@ handle_visibility_attribute (tree *node, tree name, tree args, } if (strcmp (TREE_STRING_POINTER (id), "default") == 0) - DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT; + vis = VISIBILITY_DEFAULT; else if (strcmp (TREE_STRING_POINTER (id), "internal") == 0) - DECL_VISIBILITY (decl) = VISIBILITY_INTERNAL; + vis = VISIBILITY_INTERNAL; else if (strcmp (TREE_STRING_POINTER (id), "hidden") == 0) - DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN; + vis = VISIBILITY_HIDDEN; else if (strcmp (TREE_STRING_POINTER (id), "protected") == 0) - DECL_VISIBILITY (decl) = VISIBILITY_PROTECTED; + vis = VISIBILITY_PROTECTED; else - error ("visibility argument must be one of \"default\", \"hidden\", \"protected\" or \"internal\""); + { + error ("visibility argument must be one of \"default\", \"hidden\", \"protected\" or \"internal\""); + vis = VISIBILITY_DEFAULT; + } + + if (DECL_VISIBILITY_SPECIFIED (decl) + && vis != DECL_VISIBILITY (decl) + && lookup_attribute ("visibility", (TYPE_P (*node) + ? TYPE_ATTRIBUTES (*node) + : DECL_ATTRIBUTES (decl)))) + error ("%qD redeclared with different visibility", decl); + + DECL_VISIBILITY (decl) = vis; DECL_VISIBILITY_SPECIFIED (decl) = 1; - /* For decls only, 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 class visibility. */ - if (DECL_P (*node)) - *no_add_attrs = false; + /* 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; } @@ -4972,6 +4989,13 @@ c_determine_visibility (tree decl) return true; } + /* Set default visibility to whatever the user supplied with + visibility_specified depending on #pragma GCC visibility. */ + if (!DECL_VISIBILITY_SPECIFIED (decl)) + { + DECL_VISIBILITY (decl) = default_visibility; + DECL_VISIBILITY_SPECIFIED (decl) = visibility_options.inpragma; + } return false; } diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 22b6dab..250be0e 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -3459,18 +3459,16 @@ finish_decl (tree decl, tree init, tree asmspec_tree) /* If #pragma weak was used, mark the decl weak now. */ maybe_apply_pragma_weak (decl); - /* If this is a variable definition, determine its ELF visibility. */ - if (TREE_CODE (decl) == VAR_DECL - && TREE_STATIC (decl) - && !DECL_EXTERNAL (decl)) - c_determine_visibility (decl); - /* Output the assembler code and/or RTL code for variables and functions, unless the type is an undefined structure or union. If not, it will get done when the type is completed. */ if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL) { + /* Determine the ELF visibility. */ + if (TREE_PUBLIC (decl)) + c_determine_visibility (decl); + /* This is a no-op in c-lang.c or something real in objc-act.c. */ if (c_dialect_objc ()) objc_check_decl (decl); diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 1557a76..c9eb4b9 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,51 @@ +2006-06-29 Jason Merrill <jason@redhat.com> + + PR c++/26905 + PR c++/26612 + PR c++/27000 + PR c++/26984 + PR c++/19134 + * decl2.c (determine_visibility): Overhaul. + (determine_visibility_from_class): Likewise. + (min_vis_r, type_visibility, constrain_visibility): New fns. + (constrain_visibility_for_template): Likewise. + (constrain_class_visibility): Likewise. + * decl.c (cp_finish_decl): Call determine_visibility for function + decls, too. + * name-lookup.c (pushtag): Call determine_visibility. + * decl.c (duplicate_decls): Don't copy visibility from template to + specialization. + * pt.c (check_explicit_specialization): Likewise. + (lookup_template_class, tsubst_decl): Call determine_visibility. + * class.c (finish_struct_1): Call constrain_class_visibility. + + PR c++/26905 + PR c++/21675 + PR c++/17470 + * parser.c (cp_parser_explicit_instantiation): Pass the attributes + to grokdeclarator. + (cp_parser_type_specifier): Allow 'enum __attribute ((...)) E'. + (cp_parser_enum_specifier): Likewise. + (cp_parser_elaborated_type_specifier): Apply attributes if this + declares only the class. + (cp_parser_class_specifier): Apply leading attributes immediately. + * semantics.c (begin_class_definition): Add attributes parameter, + apply them to the type. + + PR c++/21581 + PR c++/25915 + * tree.c (decl_anon_ns_mem_p): New function. + * cp-tree.h: Declare it. + * decl2.c (determine_visibility): Make anonymous namespace + members static. + (min_vis_r, constrain_visibility): Likewise. + * rtti.c (create_pseudo_type_info): Set TREE_PUBLIC on + pseudo-types. + * decl.c (cxx_init_decl_processing): Set TREE_PUBLIC on + global_namespace. + * name-lookup.c (push_namespace_with_attribs): Don't set TREE_PUBLIC + on anonymous namespaces. + 2006-06-28 Jason Merrill <jason@redhat.com> PR c++/27424 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 84ecf77..9761c5c 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -5084,6 +5084,9 @@ finish_struct_1 (tree t) DECL_SORTED_FIELDS (TYPE_MAIN_DECL (t)) = field_vec; } + /* Complain if one of the field types requires lower visibility. */ + constrain_class_visibility (t); + /* Make the rtl for any new vtables we have created, and unmark the base types we marked. */ finish_vtbls (t); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 4e4d8ec..20e704c 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3965,6 +3965,8 @@ extern tree coerce_new_type (tree); extern tree coerce_delete_type (tree); extern void comdat_linkage (tree); extern void determine_visibility (tree); +extern void constrain_class_visibility (tree); +extern void update_member_visibility (tree); extern void import_export_decl (tree); extern tree build_cleanup (tree); extern tree build_offset_ref_call_from_tree (tree, tree); @@ -4271,7 +4273,7 @@ extern tree finish_fname (tree); extern void finish_translation_unit (void); extern tree finish_template_type_parm (tree, tree); extern tree finish_template_template_parm (tree, tree); -extern tree begin_class_definition (tree); +extern tree begin_class_definition (tree, tree); extern void finish_template_decl (tree); extern tree finish_template_type (tree, tree, int); extern tree finish_base_specifier (tree, tree, bool); @@ -4353,6 +4355,7 @@ extern tree array_type_nelts_top (tree); extern tree break_out_target_exprs (tree); extern tree get_type_decl (tree); extern tree decl_namespace_context (tree); +extern bool decl_anon_ns_mem_p (tree); extern tree lvalue_type (tree); extern tree error_type (tree); extern int varargs_function_p (tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 5a630f5..49d1920 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -1857,6 +1857,11 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) SET_DECL_TEMPLATE_SPECIALIZATION (olddecl); + /* Don't propagate visibility from the template to the + specialization here. We'll do that in determine_visibility if + appropriate. */ + DECL_VISIBILITY_SPECIFIED (olddecl) = 0; + /* [temp.expl.spec/14] We don't inline explicit specialization just because the primary template says so. */ } @@ -3119,6 +3124,7 @@ cxx_init_decl_processing (void) gcc_assert (global_namespace == NULL_TREE); global_namespace = build_lang_decl (NAMESPACE_DECL, global_scope_name, void_type_node); + TREE_PUBLIC (global_namespace) = 1; begin_scope (sk_namespace, global_namespace); current_lang_name = NULL_TREE; @@ -5240,6 +5246,9 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, else abstract_virtuals_error (decl, type); + /* This needs to happen after the linkage is set. */ + determine_visibility (decl); + if (TREE_CODE (decl) == FUNCTION_DECL || TREE_TYPE (decl) == error_mark_node) /* No initialization required. */ @@ -5263,10 +5272,6 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, initialize_local_var (decl, init); } - /* The variable is being defined, so determine its visibility. - This needs to happen after the linkage is set. */ - determine_visibility (decl); - /* If a variable is defined, and then a subsequent definition with external linkage is encountered, we will get here twice for the same variable. We want to avoid diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 80fcc29..0a12a38 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1533,6 +1533,110 @@ maybe_emit_vtables (tree ctype) return true; } +/* A special return value from type_visibility meaning internal + linkage. */ + +enum { VISIBILITY_STATIC = VISIBILITY_INTERNAL+1 }; + +/* walk_tree helper function for type_visibility. */ + +static tree +min_vis_r (tree *tp, int *walk_subtrees, void *data) +{ + int *vis_p = (int *)data; + if (! TYPE_P (*tp)) + { + *walk_subtrees = 0; + } + else if (CLASS_TYPE_P (*tp)) + { + if (!TREE_PUBLIC (TYPE_MAIN_DECL (*tp))) + { + *vis_p = VISIBILITY_STATIC; + return *tp; + } + else if (CLASSTYPE_VISIBILITY (*tp) > *vis_p) + *vis_p = CLASSTYPE_VISIBILITY (*tp); + } + return NULL; +} + +/* Returns the visibility of TYPE, which is the minimum visibility of its + component types. */ + +static int +type_visibility (tree type) +{ + int vis = VISIBILITY_DEFAULT; + walk_tree_without_duplicates (&type, min_vis_r, &vis); + return vis; +} + +/* Limit the visibility of DECL to VISIBILITY. SPECIFIED is true if the + constraint comes from an attribute or pragma; REASON is the source of + the constraint. */ + +static bool +constrain_visibility (tree decl, int visibility, bool specified, + const char *reason) +{ + if (visibility == VISIBILITY_STATIC) + { + TREE_PUBLIC (decl) = 0; + DECL_INTERFACE_KNOWN (decl) = 1; + if (DECL_LANG_SPECIFIC (decl)) + DECL_NOT_REALLY_EXTERN (decl) = 1; + } + else if (visibility > DECL_VISIBILITY (decl)) + { + if (lookup_attribute ("visibility", DECL_ATTRIBUTES (decl))) + warning (OPT_Wattributes, "%q+D: visibility attribute requests " + "greater visibility than its %s allows", decl, reason); + DECL_VISIBILITY (decl) = visibility; + if (!DECL_VISIBILITY_SPECIFIED (decl)) + DECL_VISIBILITY_SPECIFIED (decl) = specified; + return true; + } + return false; +} + +/* Constrain the visibility of DECL based on the visbility of its template + arguments. */ + +static void +constrain_visibility_for_template (tree decl, tree targs) +{ + /* If this is a template instantiation, check the innermost + template args for visibility constraints. The outer template + args are covered by the class check. */ + tree args = INNERMOST_TEMPLATE_ARGS (targs); + int i; + for (i = TREE_VEC_LENGTH (args); i > 0; --i) + { + int vis = 0; + + tree arg = TREE_VEC_ELT (args, i-1); + if (TYPE_P (arg)) + vis = type_visibility (arg); + else if (TREE_TYPE (arg) && POINTER_TYPE_P (TREE_TYPE (arg))) + { + STRIP_NOPS (arg); + if (TREE_CODE (arg) == ADDR_EXPR) + arg = TREE_OPERAND (arg, 0); + if (TREE_CODE (arg) == VAR_DECL + || TREE_CODE (arg) == FUNCTION_DECL) + { + if (! TREE_PUBLIC (arg)) + vis = VISIBILITY_STATIC; + else + vis = DECL_VISIBILITY (arg); + } + } + if (vis) + constrain_visibility (decl, vis, false, "template parameter"); + } +} + /* Like c_determine_visibility, but with additional C++-specific behavior. @@ -1544,12 +1648,18 @@ maybe_emit_vtables (tree ctype) Note that because namespaces have multiple independent definitions, namespace visibility is handled elsewhere using the #pragma visibility - machinery rather than by decorating the namespace declaration. */ + machinery rather than by decorating the namespace declaration. + + The goal is for constraints from the type to give a diagnostic, and + other constraints to be applied silently. */ void determine_visibility (tree decl) { - tree class_type; + tree class_type = NULL_TREE; + bool use_template; + + /* Remember that all decls get VISIBILITY_DEFAULT when built. */ /* Only relevant for names with external linkage. */ if (!TREE_PUBLIC (decl)) @@ -1560,9 +1670,30 @@ determine_visibility (tree decl) maybe_clone_body. */ gcc_assert (!DECL_CLONED_FUNCTION_P (decl)); - /* Give the common code a chance to make a determination. */ - if (c_determine_visibility (decl)) - return; + if (TREE_CODE (decl) == TYPE_DECL) + { + if (CLASS_TYPE_P (TREE_TYPE (decl))) + use_template = CLASSTYPE_USE_TEMPLATE (TREE_TYPE (decl)); + else if (TYPE_TEMPLATE_INFO (TREE_TYPE (decl))) + use_template = 1; + else + use_template = 0; + } + else if (DECL_LANG_SPECIFIC (decl)) + use_template = DECL_USE_TEMPLATE (decl); + else + use_template = 0; + + /* Anything that is exported must have default visibility. */ + if (TARGET_DLLIMPORT_DECL_ATTRIBUTES + && lookup_attribute ("dllexport", + TREE_CODE (decl) == TYPE_DECL + ? TYPE_ATTRIBUTES (TREE_TYPE (decl)) + : DECL_ATTRIBUTES (decl))) + { + DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT; + DECL_VISIBILITY_SPECIFIED (decl) = 1; + } /* If DECL is a member of a class, visibility specifiers on the class can influence the visibility of the DECL. */ @@ -1574,6 +1705,8 @@ determine_visibility (tree decl) class_type = TREE_TYPE (DECL_NAME (decl)); else { + /* Not a class member. */ + /* Virtual tables have DECL_CONTEXT set to their associated class, so they are automatically handled above. */ gcc_assert (TREE_CODE (decl) != VAR_DECL @@ -1581,77 +1714,138 @@ determine_visibility (tree decl) if (DECL_FUNCTION_SCOPE_P (decl)) { + /* Local statics and classes get the visibility of their + containing function. */ tree fn = DECL_CONTEXT (decl); DECL_VISIBILITY (decl) = DECL_VISIBILITY (fn); DECL_VISIBILITY_SPECIFIED (decl) = DECL_VISIBILITY_SPECIFIED (fn); - } - /* Entities not associated with any class just get the - visibility specified by their attributes. */ - return; + /* Local classes in templates have CLASSTYPE_USE_TEMPLATE set, + but have no TEMPLATE_INFO, so don't try to check it. */ + use_template = 0; + } + else if (TREE_CODE (decl) == VAR_DECL && DECL_TINFO_P (decl)) + { + /* tinfo visibility is based on the type it's for. */ + constrain_visibility + (decl, type_visibility (TREE_TYPE (DECL_NAME (decl))), + false, "type"); + } + else if (use_template) + /* Template instantiations and specializations get visibility based + on their template unless they override it with an attribute. */; + else if (! DECL_VISIBILITY_SPECIFIED (decl)) + { + /* Set default visibility to whatever the user supplied with + #pragma GCC visibility or a namespace visibility attribute. */ + DECL_VISIBILITY (decl) = default_visibility; + DECL_VISIBILITY_SPECIFIED (decl) = visibility_options.inpragma; + } } - /* By default, static data members and function members receive - the visibility of their containing class. */ - if (class_type) + if (use_template) { - determine_visibility_from_class (decl, class_type); - - /* Give the target a chance to override the visibility associated - with DECL. */ - if (TREE_CODE (decl) == VAR_DECL - && (DECL_TINFO_P (decl) - || (DECL_VTABLE_OR_VTT_P (decl) - /* Construction virtual tables are not exported because - they cannot be referred to from other object files; - their name is not standardized by the ABI. */ - && !DECL_CONSTRUCTION_VTABLE_P (decl))) - && TREE_PUBLIC (decl) - && !DECL_REALLY_EXTERN (decl) - && DECL_VISIBILITY_SPECIFIED (decl) - && (!class_type || !CLASSTYPE_VISIBILITY_SPECIFIED (class_type))) - targetm.cxx.determine_class_data_visibility (decl); + tree tinfo = (TREE_CODE (decl) == TYPE_DECL + ? TYPE_TEMPLATE_INFO (TREE_TYPE (decl)) + : DECL_TEMPLATE_INFO (decl)); + tree args = TI_ARGS (tinfo); + int depth = TMPL_ARGS_DEPTH (args); + + /* If the template has explicit visibility and the specialization + doesn't, use the visibility from the template. */ + if (!DECL_VISIBILITY_SPECIFIED (decl)) + { + tree pattern = DECL_TEMPLATE_RESULT (TI_TEMPLATE (tinfo)); + DECL_VISIBILITY (decl) = DECL_VISIBILITY (pattern); + } + + /* FIXME should TMPL_ARGS_DEPTH really return 1 for null input? */ + if (args && depth > template_class_depth (class_type)) + /* Don't let it have more visibility than its template type + arguments. */ + constrain_visibility_for_template (decl, args); } + + if (class_type) + determine_visibility_from_class (decl, class_type); + + /* Don't let it have more visibility than its type. */ + if (TREE_CODE (decl) != TYPE_DECL) + if (constrain_visibility (decl, type_visibility (TREE_TYPE (decl)), + false, "type")) + warning (OPT_Wattributes, "\ +%q+D declared with greater visibility than its type", + decl); + + if (decl_anon_ns_mem_p (decl)) + /* Names in an anonymous namespace get internal linkage. + This might change once we implement export. */ + constrain_visibility (decl, VISIBILITY_STATIC, + false, "namespace"); } +/* By default, static data members and function members receive + the visibility of their containing class. */ + static void determine_visibility_from_class (tree decl, tree class_type) { - if (TARGET_DLLIMPORT_DECL_ATTRIBUTES - && lookup_attribute ("dllexport", TYPE_ATTRIBUTES (class_type))) - { - DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT; - DECL_VISIBILITY_SPECIFIED (decl) = 1; - } - else if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_DECLARED_INLINE_P (decl) - && visibility_options.inlines_hidden) - { - /* Don't change it if it has been set explicitly by user. */ - if (!DECL_VISIBILITY_SPECIFIED (decl)) - { - DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN; - DECL_VISIBILITY_SPECIFIED (decl) = 1; - } - } - else if (CLASSTYPE_VISIBILITY_SPECIFIED (class_type)) - { - DECL_VISIBILITY (decl) = CLASSTYPE_VISIBILITY (class_type); - DECL_VISIBILITY_SPECIFIED (decl) = 1; - } - else if (TYPE_CLASS_SCOPE_P (class_type)) - determine_visibility_from_class (decl, TYPE_CONTEXT (class_type)); - else if (TYPE_FUNCTION_SCOPE_P (class_type)) - { - tree fn = TYPE_CONTEXT (class_type); - DECL_VISIBILITY (decl) = DECL_VISIBILITY (fn); - DECL_VISIBILITY_SPECIFIED (decl) = DECL_VISIBILITY_SPECIFIED (fn); - } - else if (!DECL_VISIBILITY_SPECIFIED (decl)) - { - DECL_VISIBILITY (decl) = CLASSTYPE_VISIBILITY (class_type); - DECL_VISIBILITY_SPECIFIED (decl) = 0; - } + if (visibility_options.inlines_hidden + /* Don't do this for inline templates; specializations might not be + inline, and we don't want them to inherit the hidden + visibility. We'll set it here for all inline instantiations. */ + && !processing_template_decl + && ! DECL_VISIBILITY_SPECIFIED (decl) + && TREE_CODE (decl) == FUNCTION_DECL + && DECL_DECLARED_INLINE_P (decl)) + DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN; + + /* The decl can't have more visibility than its class. */ + constrain_visibility (decl, CLASSTYPE_VISIBILITY (class_type), + CLASSTYPE_VISIBILITY_SPECIFIED (class_type), + "class"); + + /* Give the target a chance to override the visibility associated + with DECL. */ + if (TREE_CODE (decl) == VAR_DECL + && (DECL_TINFO_P (decl) + || (DECL_VTABLE_OR_VTT_P (decl) + /* Construction virtual tables are not exported because + they cannot be referred to from other object files; + their name is not standardized by the ABI. */ + && !DECL_CONSTRUCTION_VTABLE_P (decl))) + && TREE_PUBLIC (decl) + && !DECL_REALLY_EXTERN (decl) + && DECL_VISIBILITY_SPECIFIED (decl) + && (!class_type || !CLASSTYPE_VISIBILITY_SPECIFIED (class_type))) + targetm.cxx.determine_class_data_visibility (decl); +} + +/* Constrain the visibility of a class TYPE based on the visibility of its + field types. Warn if any fields require lesser visibility. */ + +void +constrain_class_visibility (tree type) +{ + tree decl = TYPE_MAIN_DECL (type); + tree binfo = TYPE_BINFO (type); + tree t; + int i; + + for (t = TYPE_FIELDS (type); t; t = TREE_CHAIN (t)) + if (TREE_CODE (t) == FIELD_DECL) + if (constrain_visibility (decl, type_visibility (TREE_TYPE (t)), + false, "field type")) + warning (OPT_Wattributes, "\ +%qT declared with greater visibility than the type of its field %qD", + type, t); + + for (i = 0; BINFO_BASE_ITERATE (binfo, i, t); ++i) + if (constrain_visibility (decl, type_visibility (TREE_TYPE (t)), + false, "base type")) + warning (OPT_Wattributes, "\ +%qT declared with greater visibility than its base %qT", + type, TREE_TYPE (t)); } /* DECL is a FUNCTION_DECL or VAR_DECL. If the object file linkage diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index ea985e4..43d74dc 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -3039,7 +3039,12 @@ push_namespace_with_attribs (tree name, tree attributes) /* Make a new namespace, binding the name to it. */ d = build_lang_decl (NAMESPACE_DECL, name, void_type_node); DECL_CONTEXT (d) = FROB_CONTEXT (current_namespace); - TREE_PUBLIC (d) = 1; + /* The name of this namespace is not visible to other translation + units if it is an anonymous namespace or member thereof. */ + if (anon || decl_anon_ns_mem_p (current_namespace)) + TREE_PUBLIC (d) = 0; + else + TREE_PUBLIC (d) = 1; pushdecl (d); if (anon) { @@ -3086,15 +3091,6 @@ push_namespace_with_attribs (tree name, tree attributes) push_visibility (TREE_STRING_POINTER (x)); goto found; } -#if 0 - if (anon) - { - /* Anonymous namespaces default to hidden visibility. This might - change once we implement export. */ - current_binding_level->has_visibility = 1; - push_visibility ("hidden"); - } -#endif found: #endif @@ -4914,6 +4910,10 @@ pushtag (tree name, tree type, tag_scope scope) gcc_assert (TREE_CODE (decl) == TYPE_DECL); TYPE_STUB_DECL (type) = decl; + /* Set type visibility now if this is a forward declaration. */ + TREE_PUBLIC (decl) = 1; + determine_visibility (decl); + POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, type); } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index deb36fe..63a6b88 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -9412,7 +9412,7 @@ cp_parser_explicit_instantiation (cp_parser* parser) if (declarator != cp_error_declarator) { decl = grokdeclarator (declarator, &decl_specifiers, - NORMAL, 0, NULL); + NORMAL, 0, &decl_specifiers.attributes); /* Turn access control back on for names used during template instantiation. */ pop_deferring_access_checks (); @@ -9561,22 +9561,11 @@ cp_parser_type_specifier (cp_parser* parser, switch (keyword) { case RID_ENUM: - /* 'enum' [identifier] '{' introduces an enum-specifier; - 'enum' <anything else> introduces an elaborated-type-specifier. */ - if (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_OPEN_BRACE - || (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME - && cp_lexer_peek_nth_token (parser->lexer, 3)->type - == CPP_OPEN_BRACE)) + /* Look for the enum-specifier. */ + type_spec = cp_parser_enum_specifier (parser); + /* If that worked, we're done. */ + if (type_spec) { - if (parser->num_template_parameter_lists) - { - error ("template declaration of %qs", "enum"); - cp_parser_skip_to_end_of_block_or_statement (parser); - type_spec = error_mark_node; - } - else - type_spec = cp_parser_enum_specifier (parser); - if (declares_class_or_enum) *declares_class_or_enum = 2; if (decl_specs) @@ -10078,6 +10067,7 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, /*type_p=*/true, is_declaration); /* For everything but enumeration types, consider a template-id. */ + /* For an enumeration type, consider only a plain identifier. */ if (tag_type != enum_type) { bool template_p = false; @@ -10109,7 +10099,6 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, type = TREE_TYPE (decl); } - /* For an enumeration type, consider only a plain identifier. */ if (!type) { identifier = cp_parser_identifier (parser); @@ -10237,11 +10226,6 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, else ts = ts_global; - /* Warn about attributes. They are ignored. */ - if (attributes) - warning (OPT_Wattributes, - "type attributes are honored only at type definition"); - template_p = (parser->num_template_parameter_lists && (cp_parser_next_token_starts_class_definition_p (parser) @@ -10254,6 +10238,21 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, type = xref_tag (tag_type, identifier, ts, template_p); } } + + /* Allow attributes on forward declarations of classes. */ + if (attributes) + { + if (tag_type != enum_type && CLASSTYPE_TEMPLATE_INSTANTIATION (type) + && ! processing_explicit_instantiation) + warning (OPT_Wattributes, + "attributes ignored on template instantiation"); + else if (is_declaration && cp_parser_declares_only_class_p (parser)) + cplus_decl_attributes (&type, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE); + else + warning (OPT_Wattributes, + "attributes ignored on elaborated-type-specifier that is not a forward declaration"); + } + if (tag_type != enum_type) cp_parser_check_class_key (tag_type, type); @@ -10270,15 +10269,22 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, enum identifier [opt] { enumerator-list [opt] } GNU Extensions: - enum identifier [opt] { enumerator-list [opt] } attributes + enum attributes[opt] identifier [opt] { enumerator-list [opt] } + attributes[opt] - Returns an ENUM_TYPE representing the enumeration. */ + Returns an ENUM_TYPE representing the enumeration, or NULL_TREE + if the token stream isn't an enum-specifier after all. */ static tree cp_parser_enum_specifier (cp_parser* parser) { tree identifier; tree type; + tree attributes; + + /* Parse tentatively so that we can back up if we don't find a + enum-specifier. */ + cp_parser_parse_tentatively (parser); /* Caller guarantees that the current token is 'enum', an identifier possibly follows, and the token after that is an opening brace. @@ -10286,11 +10292,20 @@ cp_parser_enum_specifier (cp_parser* parser) the enumeration being defined. */ cp_lexer_consume_token (parser->lexer); + attributes = cp_parser_attributes_opt (parser); + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) identifier = cp_parser_identifier (parser); else identifier = make_anon_name (); + /* Look for the `{' but don't consume it yet. */ + if (!cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + cp_parser_simulate_error (parser); + + if (!cp_parser_parse_definitely (parser)) + return NULL_TREE; + /* Issue an error message if type-definitions are forbidden here. */ cp_parser_check_type_definition (parser); @@ -10302,6 +10317,12 @@ cp_parser_enum_specifier (cp_parser* parser) /* Consume the opening brace. */ cp_lexer_consume_token (parser->lexer); + if (type == error_mark_node) + { + cp_parser_skip_to_end_of_block_or_statement (parser); + return error_mark_node; + } + /* If the next token is not '}', then there are some enumerators. */ if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE)) cp_parser_enumerator_list (parser, type); @@ -12917,7 +12938,7 @@ cp_parser_class_specifier (cp_parser* parser) scope = CP_DECL_CONTEXT (TYPE_MAIN_DECL (type)); old_scope = push_inner_scope (scope); } - type = begin_class_definition (type); + type = begin_class_definition (type, attributes); if (type == error_mark_node) /* If the type is erroneous, skip the entire body of the class. */ @@ -12934,10 +12955,7 @@ cp_parser_class_specifier (cp_parser* parser) has_trailing_semicolon = (token->type == CPP_SEMICOLON); /* Look for trailing attributes to apply to this class. */ if (cp_parser_allow_gnu_extensions_p (parser)) - { - tree sub_attr = cp_parser_attributes_opt (parser); - attributes = chainon (attributes, sub_attr); - } + attributes = cp_parser_attributes_opt (parser); if (type != error_mark_node) type = finish_struct (type, attributes); if (nested_name_specifier_p) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index a81f6a0..873ef51 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -2140,13 +2140,7 @@ check_explicit_specialization (tree declarator, template it specializes. */ TREE_PRIVATE (decl) = TREE_PRIVATE (gen_tmpl); TREE_PROTECTED (decl) = TREE_PROTECTED (gen_tmpl); - /* The specialization has the same visibility as the - template it specializes. */ - if (DECL_VISIBILITY_SPECIFIED (gen_tmpl)) - { - DECL_VISIBILITY_SPECIFIED (decl) = 1; - DECL_VISIBILITY (decl) = DECL_VISIBILITY (gen_tmpl); - } + /* If DECL is a friend declaration, declared using an unqualified name, the namespace associated with DECL may have been set incorrectly. For example, in: @@ -3592,9 +3586,9 @@ convert_nontype_argument (tree type, tree expr) if (!constant_address_p) { - error ("%qE is not a valid template argument for type %qT " - "because it is not a constant pointer", expr, type); - return NULL_TREE; + error ("%qE is not a valid template argument for type %qT " + "because it is not a constant pointer", expr, type); + return NULL_TREE; } } /* [temp.arg.nontype]/5, bullet 3 @@ -4782,6 +4776,10 @@ lookup_template_class (tree d1, code that generates debugging information will crash. */ DECL_IGNORED_P (TYPE_STUB_DECL (t)) = 1; + /* Possibly limit visibility based on template args. */ + TREE_PUBLIC (type_decl) = 1; + determine_visibility (type_decl); + POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t); } timevar_pop (TV_NAME_LOOKUP); @@ -6588,6 +6586,11 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) SET_DECL_FRIEND_CONTEXT (r, tsubst (DECL_FRIEND_CONTEXT (t), args, complain, in_decl)); + + /* Possibly limit visibility based on template args. */ + DECL_VISIBILITY (r) = VISIBILITY_DEFAULT; + DECL_VISIBILITY_SPECIFIED (r) = 0; + determine_visibility (r); } break; @@ -6760,6 +6763,13 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_DECL_WRTL)) SET_DECL_RTL (r, NULL_RTX); DECL_SIZE (r) = DECL_SIZE_UNIT (r) = 0; + if (TREE_CODE (r) == VAR_DECL) + { + /* Possibly limit visibility based on template args. */ + DECL_VISIBILITY (r) = VISIBILITY_DEFAULT; + DECL_VISIBILITY_SPECIFIED (r) = 0; + determine_visibility (r); + } if (!local_p) { diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index 469ce51..18beb79 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -1156,6 +1156,10 @@ create_pseudo_type_info (int tk, const char *real_name, ...) ti->name = get_identifier (real_name); ti->vtable = NULL_TREE; + /* Pretend this is public so determine_visibility doesn't give vtables + internal linkage. */ + TREE_PUBLIC (TYPE_MAIN_DECL (ti->type)) = 1; + va_end (ap); } diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index bb53555..c5b3fbb 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2161,7 +2161,7 @@ check_template_template_default_arg (tree argument) /* Begin a class definition, as indicated by T. */ tree -begin_class_definition (tree t) +begin_class_definition (tree t, tree attributes) { if (t == error_mark_node) return error_mark_node; @@ -2200,6 +2200,9 @@ begin_class_definition (tree t) maybe_process_partial_specialization (t); pushclass (t); TYPE_BEING_DEFINED (t) = 1; + + cplus_decl_attributes (&t, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE); + if (flag_pack_struct) { tree v; diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 7b44ad6..c1c6719 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1385,6 +1385,30 @@ decl_namespace_context (tree decl) } } +/* Returns true if decl is within an anonymous namespace, however deeply + nested, or false otherwise. */ + +bool +decl_anon_ns_mem_p (tree decl) +{ + while (1) + { + if (decl == NULL_TREE) + return false; + if (TREE_CODE (decl) == NAMESPACE_DECL + && DECL_NAME (decl) == NULL_TREE) + return true; + /* Classes and namespaces inside anonymous namespaces have + TREE_PUBLIC == 0, so we can shortcut the search. */ + else if (TYPE_P (decl)) + return (TREE_PUBLIC (TYPE_NAME (decl)) == 0); + else if (TREE_CODE (decl) == NAMESPACE_DECL) + return (TREE_PUBLIC (decl) == 0); + else + decl = DECL_CONTEXT (decl); + } +} + /* Return truthvalue of whether T1 is the same tree structure as T2. Return 1 if they are the same. Return 0 if they are different. */ @@ -2181,7 +2205,8 @@ decl_linkage (tree decl) template instantiations have internal linkage (in the object file), but the symbols should still be treated as having external linkage from the point of view of the language. */ - if (TREE_CODE (decl) != TYPE_DECL && DECL_LANG_SPECIFIC (decl) && DECL_COMDAT (decl)) + if (TREE_CODE (decl) != TYPE_DECL && DECL_LANG_SPECIFIC (decl) + && DECL_COMDAT (decl)) return lk_external; /* Things in local scope do not have linkage, if they don't have diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index f029ca2..91b5294 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -2409,10 +2409,10 @@ consistently, so that the same entity should not be declared with different settings of the attribute. In C++, the visibility attribute applies to types as well as functions -and objects, because in C++ types have linkage. There are some bugs -in the C++ support for this flag, for example a template which has a -hidden type as a parameter is not properly hidden. -@c bugzilla 26612 +and objects, because in C++ types have linkage. A class must not have +greater visibility than its non-static data member types and bases, +and class members default to the visibility of their class. Also, a +declaration must not have greater visibility than its type. In C++, you can mark member functions and static member variables of a class with the visibility attribute. This is useful if if you know a @@ -2423,6 +2423,17 @@ the One Definition Rule; for example, it is not useful to mark a method which is defined inside a class definition as hidden without marking the whole class as hidden. +A C++ namespace declaration can also have the visibility attribute. +This attribute applies only to the particular namespace body, not to +other definitions of the same namespace; it is equivalent to using +@samp{#pragma GCC visibility} before and after the namespace +definition (@pxref{Visibility Pragmas}). + +In C++, if a template argument has limited visibility, this +restriction is implicitly propagated to the template instantiation. +Otherwise, template instantiations and specializations default to the +visibility of their template. + @item warn_unused_result @cindex @code{warn_unused_result} attribute The @code{warn_unused_result} attribute causes a warning to be emitted @@ -2604,10 +2615,7 @@ does not arise there. An attribute specifier list may appear as part of a @code{struct}, @code{union} or @code{enum} specifier. It may go either immediately after the @code{struct}, @code{union} or @code{enum} keyword, or after -the closing brace. It is ignored if the content of the structure, union -or enumerated type is not defined in the specifier in which the -attribute specifier list is used---that is, in usages such as -@code{struct __attribute__((foo)) bar} with no following opening brace. +the closing brace. The former syntax is preferred. Where attribute specifiers follow the closing brace, they are considered to relate to the structure, union or enumerated type defined, not to any enclosing declaration the type specifier appears in, and the type @@ -3382,13 +3390,14 @@ placed in either the @code{.bss_below100} section or the @cindex type attributes The keyword @code{__attribute__} allows you to specify special -attributes of @code{struct} and @code{union} types when you define such -types. This keyword is followed by an attribute specification inside -double parentheses. Six attributes are currently defined for types: -@code{aligned}, @code{packed}, @code{transparent_union}, @code{unused}, -@code{deprecated} and @code{may_alias}. Other attributes are defined for -functions (@pxref{Function Attributes}) and for variables -(@pxref{Variable Attributes}). +attributes of @code{struct} and @code{union} types when you define +such types. This keyword is followed by an attribute specification +inside double parentheses. Seven attributes are currently defined for +types: @code{aligned}, @code{packed}, @code{transparent_union}, +@code{unused}, @code{deprecated}, @code{visibility}, and +@code{may_alias}. Other attributes are defined for functions +(@pxref{Function Attributes}) and for variables (@pxref{Variable +Attributes}). You may also specify any one of these attributes with @samp{__} preceding and following its keyword. This allows you to use these @@ -3396,14 +3405,13 @@ attributes in header files without being concerned about a possible macro of the same name. For example, you may use @code{__aligned__} instead of @code{aligned}. -You may specify the @code{aligned} and @code{transparent_union} -attributes either in a @code{typedef} declaration or just past the -closing curly brace of a complete enum, struct or union type -@emph{definition} and the @code{packed} attribute only past the closing -brace of a definition. +You may specify type attributes either in a @code{typedef} declaration +or in an enum, struct or union type declaration or definition. -You may also specify attributes between the enum, struct or union -tag and the name of the type rather than after the closing brace. +For an enum, struct or union type, you may specify attributes either +between the enum, struct or union tag and the name of the type, or +just past the closing curly brace of the @emph{definition}. The +former syntax is preferred. @xref{Attribute Syntax}, for details of the exact syntax for using attributes. @@ -3652,6 +3660,13 @@ declaration, the above program would abort when compiled with @option{-fstrict-aliasing}, which is on by default at @option{-O2} or above in recent GCC versions. +@item visibility + +In C++, attribute visibility (@pxref{Function Attributes}) can also be +applied to class, struct, union and enum types. Unlike other type +attributes, the attribute must appear between the initial keyword and +the name of the type; it cannot appear after the body of the type. + @subsection ARM Type Attributes On those ARM targets that support @code{dllimport} (such as Symbian @@ -9454,6 +9469,7 @@ for further explanation. * Structure-Packing Pragmas:: * Weak Pragmas:: * Diagnostic Pragmas:: +* Visibility Pragmas:: @end menu @node ARM Pragmas @@ -9750,6 +9766,26 @@ strict control over project policies. @end table +@node Visibility Pragmas +@subsection Visibility Pragmas + +@table @code +@item #pragma GCC visibility push(@var{visibility}) +@itemx #pragma GCC visibility pop +@cindex pragma, visibility + +This pragma allows the user to set the visibility for multiple +declarations without having to give each a visibility attribute +@xref{Function Attributes}, for more information about visibility and +the attribute syntax. + +In C++, @samp{#pragma GCC visibility} affects only namespace-scope +declarations. Class members and template specializations are not +affected; if you want to override the visibility for a particular +member or instantiation, you must use an attribute. + +@end table + @node Unnamed Fields @section Unnamed struct/union fields within structs/unions @cindex struct diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 30dd402..0c5e382 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -1619,16 +1619,10 @@ when used within the DSO@. Enabling this option can have a dramatic effect on load and link times of a DSO as it massively reduces the size of the dynamic export table when the library makes heavy use of templates. -The behavior of this switch is not quite the same as marking the -methods as hidden directly. Normally if there is a class with default -visibility which has a hidden method, the effect of this is that the -method must be defined in only one shared object. This switch does -not have this restriction. - You may mark a method as having a visibility explicitly to negate the effect of the switch for that method. For example, if you do want to -compare pointers to a particular inline method, you might mark it as -having default visibility. +compare pointers to a particular inline method, or the method has +local static data, you might mark it as having default visibility. @item -fno-weak @opindex fno-weak @@ -13506,6 +13500,20 @@ expecting to be compiled with visibility other than the default. You may need to explicitly say @samp{#pragma GCC visibility push(default)} before including any such headers. +@samp{extern} declarations are not affected by @samp{-fvisibility}, so +a lot of code can be recompiled with @samp{-fvisibility=hidden} with +no modifications. However, this means that calls to @samp{extern} +functions with no explicit visibility will use the PLT, so it is more +effective to use @samp{__attribute ((visibility))} and/or +@samp{#pragma GCC visibility} to tell the compiler which @samp{extern} +declarations should be treated as hidden. + +Note that @samp{-fvisibility} does affect C++ vague linkage +entities. This means that, for instance, an exception class that will +be thrown between DSOs must be explicitly marked with default +visibility so that the @samp{type_info} nodes will be unified between +the DSOs. + An overview of these techniques, their benefits and how to use them is at @w{@uref{http://gcc.gnu.org/wiki/Visibility}}. diff --git a/gcc/flags.h b/gcc/flags.h index 84d5b39..5e45834 100644 --- a/gcc/flags.h +++ b/gcc/flags.h @@ -58,15 +58,16 @@ extern enum debug_info_level debug_info_level; debugging information. */ extern bool use_gnu_debug_info_extensions; -/* Enumerate visibility settings. */ +/* Enumerate visibility settings. This is deliberately ordered from most + to least visibility. */ #ifndef SYMBOL_VISIBILITY_DEFINED #define SYMBOL_VISIBILITY_DEFINED enum symbol_visibility { VISIBILITY_DEFAULT, - VISIBILITY_INTERNAL, + VISIBILITY_PROTECTED, VISIBILITY_HIDDEN, - VISIBILITY_PROTECTED + VISIBILITY_INTERNAL }; #endif diff --git a/gcc/testsuite/g++.dg/ext/attrib14.C b/gcc/testsuite/g++.dg/ext/attrib14.C index 3a819e0..c7e5f7a 100644 --- a/gcc/testsuite/g++.dg/ext/attrib14.C +++ b/gcc/testsuite/g++.dg/ext/attrib14.C @@ -3,11 +3,11 @@ // parsing of the class, causing some variants to have it and some not. struct __attribute__((bogus)) A -{ +{ // { dg-warning "ignored" "" } virtual ~A(); void foo(const A&); void bar(const A&); -}; // { dg-warning "ignored" "" } +}; void A::foo(const A&) {} void A::bar(const A& a) { foo(a); } diff --git a/gcc/testsuite/g++.dg/ext/attrib9.C b/gcc/testsuite/g++.dg/ext/attrib9.C index d01fc12..6672f75 100644 --- a/gcc/testsuite/g++.dg/ext/attrib9.C +++ b/gcc/testsuite/g++.dg/ext/attrib9.C @@ -1,5 +1,10 @@ -class __attribute__((unused)) C; // { dg-warning "type attributes" } -struct __attribute__((unused)) S; // { dg-warning "type attributes" } -union __attribute__((unused)) U; // { dg-warning "type attributes" } +class __attribute__((unused)) C; +struct __attribute__((unused)) S; +union __attribute__((unused)) U; enum e {}; -enum __attribute__((unused)) e; // { dg-warning "type attributes" } +enum __attribute__((unused)) e; // { dg-warning "already defined" } + +struct __attribute((unused)) B *p; // { dg-warning "attributes" } + +template <class T> struct A { }; +struct __attribute((unused)) A<int>; // { dg-warning "attributes" } diff --git a/gcc/testsuite/g++.dg/ext/visibility/anon1.C b/gcc/testsuite/g++.dg/ext/visibility/anon1.C index 81e9270..16647b2 100644 --- a/gcc/testsuite/g++.dg/ext/visibility/anon1.C +++ b/gcc/testsuite/g++.dg/ext/visibility/anon1.C @@ -1,8 +1,8 @@ // PR c++/21581 -// Test for anonymous namespace default hidden visibility +// Test for anonymous namespace internal linkage -// { dg-require-visibility "" } -// { dg-final-NOT { scan-hidden "_ZN.*1fEv" } } +// { dg-do compile } +// { dg-final { scan-assembler-not "globl.*_ZN.*1fEv" } } namespace { diff --git a/gcc/testsuite/g++.dg/ext/visibility/anon2.C b/gcc/testsuite/g++.dg/ext/visibility/anon2.C new file mode 100644 index 0000000..1d8e479 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/visibility/anon2.C @@ -0,0 +1,11 @@ +// Test for propagation of anonymous namespace internal linkage + +// { dg-do compile } +// { dg-final { scan-assembler-not "globl.*_Z1fv" } } + +namespace +{ + struct A { }; +} + +A f () { } diff --git a/gcc/testsuite/g++.dg/ext/visibility/assign1.C b/gcc/testsuite/g++.dg/ext/visibility/assign1.C index cbd909e..b25999e 100644 --- a/gcc/testsuite/g++.dg/ext/visibility/assign1.C +++ b/gcc/testsuite/g++.dg/ext/visibility/assign1.C @@ -6,11 +6,12 @@ struct B { B& operator=(const B&); }; -struct D : public B { +struct __attribute__((visibility("hidden"))) D : public B { // The implicit assignment operator should be hidden. -} __attribute__((visibility("hidden"))); +}; -D d1, d2; +__attribute__((visibility("hidden"))) D d1; +__attribute__((visibility("hidden"))) D d2; void f() { d1 = d2; diff --git a/gcc/testsuite/g++.dg/ext/visibility/class1.C b/gcc/testsuite/g++.dg/ext/visibility/class1.C new file mode 100644 index 0000000..d526514 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/visibility/class1.C @@ -0,0 +1,20 @@ +// PR c++/26905 +// Init should not be hidden, so calling it should use the PLT. + +// { dg-require-visibility "" } +// { dg-options "-fpic" } +// { dg-do compile { target i?86-*-* x86_64-*-* } } +// { dg-final { scan-assembler "InitEv@PLT" } } + +#pragma GCC visibility push(hidden) +struct __attribute__ ((visibility ("default"))) nsINIParser +{ + static void Init(); +}; + +__attribute__ ((visibility ("default"))) +void +CheckCompatibility(void) +{ + nsINIParser::Init(); +} diff --git a/gcc/testsuite/g++.dg/ext/visibility/fvisibility-override2.C b/gcc/testsuite/g++.dg/ext/visibility/fvisibility-override2.C index 07f0c07..853686c 100644 --- a/gcc/testsuite/g++.dg/ext/visibility/fvisibility-override2.C +++ b/gcc/testsuite/g++.dg/ext/visibility/fvisibility-override2.C @@ -6,7 +6,7 @@ class Foo { - __attribute__ ((visibility ("default"))) void method(); + __attribute__ ((visibility ("internal"))) void method(); }; void Foo::method() { } diff --git a/gcc/testsuite/g++.dg/ext/visibility/prop1.C b/gcc/testsuite/g++.dg/ext/visibility/prop1.C new file mode 100644 index 0000000..f457482 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/visibility/prop1.C @@ -0,0 +1,23 @@ +// Test for propagation of visibility through template arguments + +// { dg-do compile } +// { dg-require-visibility "" } +// { dg-final { scan-hidden "_Z1fIN1N1AEEvT_" } } +// { dg-final { scan-hidden "_Z1hIXadL_ZN1N1iEEEEvv" } } + +namespace N __attribute ((__visibility__ ("hidden"))) +{ + struct A { }; + int i; +} + +template <class T> void f (T) { } +template <int *I> void h() { } + +void g() +{ + N::A a; + f(a); + h<&N::i>(); +} + diff --git a/gcc/testsuite/g++.dg/ext/visibility/redecl1.C b/gcc/testsuite/g++.dg/ext/visibility/redecl1.C new file mode 100644 index 0000000..75c8554 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/visibility/redecl1.C @@ -0,0 +1,7 @@ +// Test that we complain about redeclaration with different visibility + +struct __attribute((visibility("hidden"))) B; +struct __attribute((visibility("default"))) B; // { dg-warning "visibility" } + +__attribute ((visibility ("hidden"))) void f(); // { dg-warning "previous" } +__attribute ((visibility ("default"))) void f(); // { dg-warning "visibility" } diff --git a/gcc/testsuite/g++.dg/ext/visibility/template1.C b/gcc/testsuite/g++.dg/ext/visibility/template1.C new file mode 100644 index 0000000..c5cee0d --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/visibility/template1.C @@ -0,0 +1,35 @@ +// PR c++/19134 +// -fvisibility-inlines-hidden doesn't apply to non-inline specializations + +// { dg-require-visibility "" } +// { dg-options "-fvisibility-inlines-hidden" } +// { dg-final { scan-not-hidden "_ZN1AIiE3fooEv" } } +// { dg-final { scan-not-hidden "_ZN1AIiE3barEv" } } +// { dg-final { scan-hidden "_ZN1AIlE3fooEv" } } +// { dg-final { scan-hidden "_ZN1AIlE3barEv" } } +// { dg-final { scan-hidden "_ZN1AIcE3barEv" } } + +template<class T> +struct A { + void foo() {}; + __attribute ((visibility ("hidden"))) void bar(); +}; + +// This has default visibility. +template<> void A<int>::foo() {} + +// This has hidden visibility because of -fvisibility-inlines-hidden. +template<> inline void A<long>::foo() {} +// Force the inline out. +void f () { A<long> a; a.foo(); } + +// This has default visibility. +template<> __attribute ((visibility ("default"))) void A<int>::bar() {} + +// This inherits hidden visibility from its template. +template<> void A<long>::bar() { } + +// This also has hidden visibility; #pragma vis doesn't affect class members. +#pragma GCC visibility push(default) +template<> void A<char>::bar() { } +#pragma GCC visibility pop diff --git a/gcc/testsuite/g++.dg/ext/visibility/template2.C b/gcc/testsuite/g++.dg/ext/visibility/template2.C new file mode 100644 index 0000000..8db96db --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/visibility/template2.C @@ -0,0 +1,35 @@ +// PR c++/27000 +// Implicitly instantiated templates should not be affected by +// #pragma visibility. + +/* { dg-do compile } */ +/* { dg-require-visibility "" } */ +/* { dg-final { scan-not-hidden "_ZN1SIiED1Ev" } } */ +/* { dg-final { scan-not-hidden "_ZN1SIiEC1ERKi" } } */ + +template <class T> +struct S +{ + S (const T &); + ~S (); + T t; +}; + +template <class T> +S<T>::S (const T &x) +{ + t = x; +} + +template <class T> +S<T>::~S () +{ +} + +#pragma GCC visibility push(hidden) +struct U +{ + S<int> s; + U () : s (6) { } +} u; +#pragma GCC visibility pop diff --git a/gcc/testsuite/g++.dg/ext/visibility/template3.C b/gcc/testsuite/g++.dg/ext/visibility/template3.C new file mode 100644 index 0000000..69cb6ca --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/visibility/template3.C @@ -0,0 +1,22 @@ +// PR c++/17470 +// Test that we can give visibility to explicit template instantiations + +// { dg-require-visibility "" } +// { dg-final { scan-hidden "_ZN1AIlE1fEl" } } +// { dg-final { scan-hidden "_ZN1AIiE1fEi" } } +// { dg-final { scan-not-hidden "_ZN1AIcE1fEc" } } +// { dg-final { scan-hidden "_Z8identityIdET_S0_" } } +// { dg-final { scan-not-hidden "_Z8identityIiET_S0_" } } + +template <class T> T identity(T t) { return t; } +template __attribute__((visibility("hidden"))) double identity(double); +template int identity(int); + + +template <class T> struct A { void f (T); }; +template <class T> void A<T>::f (T) { } +template struct __attribute ((visibility ("hidden"))) A<int>; +template<> struct __attribute ((visibility ("hidden"))) A<long> { void f(long); }; +// inherits hidden visibility from its class +void A<long>::f (long) { } +template struct A<char>; diff --git a/gcc/testsuite/g++.dg/ext/visibility/template4.C b/gcc/testsuite/g++.dg/ext/visibility/template4.C new file mode 100644 index 0000000..add63a5 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/visibility/template4.C @@ -0,0 +1,39 @@ +// Test for explicit visibility on template vs. #pragma vis at explicit +// instantiation/specialization point for plain function templates. + +// { dg-require-visibility "" } +// { dg-final { scan-hidden "_Z3fooIdEvT_" } } +// { dg-final { scan-hidden "_Z3fooIlEvT_" } } +// { dg-final { scan-hidden "_Z3fooIcEvT_" } } +// { dg-final { scan-hidden "_Z3fooIiEvT_" } } +// { dg-final { scan-not-hidden "_Z3fooIfEvT_" } } +// { dg-final { scan-not-hidden "_Z3fooIsEvT_" } } + +// { dg-final { scan-hidden "_Z3barIdEvT_" } } +// { dg-final { scan-hidden "_Z3barIlEvT_" } } +// { dg-final { scan-hidden "_Z3barIiEvT_" } } +// { dg-final { scan-hidden "_Z3barIcEvT_" } } +// { dg-final { scan-not-hidden "_Z3barIfEvT_" } } +// { dg-final { scan-not-hidden "_Z3barIsEvT_" } } + +#pragma GCC visibility push(hidden) +template <class T> void bar(T) { } +#pragma GCC visibility pop +template void bar (long); +template<> void bar (double) { } +template __attribute ((visibility ("default"))) void bar (short); +template<> __attribute ((visibility ("default"))) void bar (float) { } +#pragma GCC visibility push(default) +template<> void bar(char) { } +template void bar(int); +#pragma GCC visibility pop + +template <class T> __attribute ((visibility ("hidden"))) void foo(T) { } +template void foo (long); +template<> void foo (double) { } +template __attribute ((visibility ("default"))) void foo (short); +template<> __attribute ((visibility ("default"))) void foo (float) { } +#pragma GCC visibility push(default) +template<> void foo(char) { } +template void foo(int); +#pragma GCC visibility pop diff --git a/gcc/testsuite/g++.dg/ext/visibility/typeinfo1.C b/gcc/testsuite/g++.dg/ext/visibility/typeinfo1.C new file mode 100644 index 0000000..99dfc1c --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/visibility/typeinfo1.C @@ -0,0 +1,19 @@ +// PR c++/26984 +// lazily generated typeinfos should not be affected by #pragma vis, but +// they should be affected by the visibility of the type they describe. + +// { dg-require-visibility "" } +// { dg-options "-fvisibility-inlines-hidden" } +// { dg-final { scan-not-hidden "_ZTIPPi" } } +// { dg-final { scan-not-hidden "_ZTSPPi" } } +// { dg-final { scan-hidden "_ZTIP1A" } } +// { dg-final { scan-hidden "_ZTSP1A" } } + +#include <typeinfo> + +#pragma GCC visibility push(hidden) +const std::type_info* t = &(typeid(int **)); +struct A { }; +#pragma GCC visibility pop + +const std::type_info* t2 = &(typeid(A *)); diff --git a/gcc/testsuite/g++.dg/ext/visibility/virtual.C b/gcc/testsuite/g++.dg/ext/visibility/virtual.C index 746c489..7706003 100644 --- a/gcc/testsuite/g++.dg/ext/visibility/virtual.C +++ b/gcc/testsuite/g++.dg/ext/visibility/virtual.C @@ -1,9 +1,15 @@ -/* Test that setting visibility for class affects virtual table. */ +/* Test that setting visibility for class affects virtual table, VTT and + type_info name and node. */ /* { dg-do compile } */ /* { dg-require-visibility "" } */ /* { dg-final { scan-hidden "ZTV3Foo" } } */ +/* { dg-final { scan-hidden "ZTT3Foo" } } */ +/* { dg-final { scan-hidden "ZTS3Foo" } } */ +/* { dg-final { scan-hidden "ZTI3Foo" } } */ -class __attribute__ ((visibility ("hidden"))) Foo +struct A { }; + +class __attribute__ ((visibility ("hidden"))) Foo: virtual public A { virtual void method(); }; diff --git a/gcc/testsuite/g++.dg/ext/visibility/warn1.C b/gcc/testsuite/g++.dg/ext/visibility/warn1.C new file mode 100644 index 0000000..3b6b85f --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/visibility/warn1.C @@ -0,0 +1,13 @@ +// Warn when a declaration is specified with greater visibility than that +// of its type. + +// { dg-do compile } +// { dg-require-visibility "" } +// { dg-final { scan-hidden "_Z1fv" } } + +namespace N __attribute ((__visibility__ ("hidden"))) +{ + struct A { }; +} + +N::A f() { } // { dg-warning "visibility" "" } diff --git a/gcc/testsuite/g++.dg/ext/visibility/warn2.C b/gcc/testsuite/g++.dg/ext/visibility/warn2.C new file mode 100644 index 0000000..1baf8b9e --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/visibility/warn2.C @@ -0,0 +1,19 @@ +// Complain when a class is specified with greater visibility than one of +// its members' types or bases, and when a declaration has greater +// visibility than its type. + +// { dg-require-visibility "" } + +namespace N __attribute ((__visibility__ ("hidden"))) +{ + struct A { }; +} + +struct B +{ // { dg-warning "visibility" } + N::A a; +}; + +B f () { } // { dg-warning "visibility" } + +struct C: public N::A { }; // { dg-warning "visibility" } diff --git a/gcc/testsuite/g++.dg/ext/visibility/warn3.C b/gcc/testsuite/g++.dg/ext/visibility/warn3.C new file mode 100644 index 0000000..705748a --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/visibility/warn3.C @@ -0,0 +1,11 @@ +// Warn when a class member is specified to have greater visibility than +// its class. + +// { dg-require-visibility "" } + +struct __attribute ((visibility ("hidden"))) A +{ + __attribute ((visibility ("default"))) void f (); // { dg-warning "visibility" } +}; + +void A::f() { } diff --git a/gcc/testsuite/g++.dg/ext/visibility/warn4.C b/gcc/testsuite/g++.dg/ext/visibility/warn4.C new file mode 100644 index 0000000..e405e7a --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/visibility/warn4.C @@ -0,0 +1,10 @@ +// Error if we try to give an instantiation visibility after it's already +// been instantiated. + +// { dg-require-visibility "" } + +template <class T> struct A { void f (T); }; +template <class T> void A<T>::f (T) { } + +A<double> ad; +template struct __attribute ((visibility ("hidden"))) A<double>; // { dg-error "already defined" } diff --git a/gcc/testsuite/g++.old-deja/g++.pt/enum5.C b/gcc/testsuite/g++.old-deja/g++.pt/enum5.C index d4eea4f..a7c5ea3 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/enum5.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/enum5.C @@ -1,4 +1,4 @@ // { dg-do assemble } -template <> // { dg-error "" } template declaration of enum -enum E {e}; +template <> +enum E {e}; // { dg-error "" } template declaration of enum @@ -3133,14 +3133,6 @@ build_decl_stat (enum tree_code code, tree name, tree type MEM_STAT_DECL) else if (code == FUNCTION_DECL) DECL_MODE (t) = FUNCTION_MODE; - if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)) - { - /* Set default visibility to whatever the user supplied with - visibility_specified depending on #pragma GCC visibility. */ - DECL_VISIBILITY (t) = default_visibility; - DECL_VISIBILITY_SPECIFIED (t) = visibility_options.inpragma; - } - return t; } @@ -1067,7 +1067,7 @@ extern void omp_clause_range_check_failed (const tree, const char *, int, #define TREE_OVERFLOW(NODE) (CST_CHECK (NODE)->common.public_flag) -/* In a VAR_DECL or FUNCTION_DECL, +/* In a VAR_DECL, FUNCTION_DECL, NAMESPACE_DECL or TYPE_DECL, nonzero means name is to be accessible from outside this module. In an IDENTIFIER_NODE, nonzero means an external declaration accessible from outside this module was previously seen @@ -2264,9 +2264,9 @@ struct tree_binfo GTY (()) enum symbol_visibility { VISIBILITY_DEFAULT, - VISIBILITY_INTERNAL, + VISIBILITY_PROTECTED, VISIBILITY_HIDDEN, - VISIBILITY_PROTECTED + VISIBILITY_INTERNAL }; #endif diff --git a/gcc/varasm.c b/gcc/varasm.c index e5abd3e..a10d954 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -5033,7 +5033,7 @@ void default_assemble_visibility (tree decl, int vis) { static const char * const visibility_types[] = { - NULL, "internal", "hidden", "protected" + NULL, "protected", "hidden", "internal" }; const char *name, *type; |