Index: gcc/testsuite/g++.dg/ext/visibility/local1.C =================================================================== --- gcc/testsuite/g++.dg/ext/visibility/local1.C (revision 0) +++ gcc/testsuite/g++.dg/ext/visibility/local1.C (revision 116504) @@ -0,0 +1,25 @@ +// PR c++/19238 +// Test that hidden visibility on an inline function is inherited by static +// local variables and local classes. + +// { dg-require-visibility "" } +// { dg-final { scan-hidden "_Z1fv" } } +// { dg-final { scan-hidden "_ZZ1fvE1i" } } +// { dg-final { scan-hidden "_ZZ1fvEN1A1fEv" } } + +__attribute ((visibility ("hidden"))) inline int +f() +{ + static int i = 2; + struct A + { + void f () { } + } a; + a.f(); + return i; +} + +int main() +{ + f(); +} Index: gcc/testsuite/g++.dg/ext/visibility/namespace1.C =================================================================== --- gcc/testsuite/g++.dg/ext/visibility/namespace1.C (revision 0) +++ gcc/testsuite/g++.dg/ext/visibility/namespace1.C (revision 116504) @@ -0,0 +1,30 @@ +// PR c++/21764 +// Test for namespace visibility attribute semantics. + +// { dg-require-visibility "" } +// { dg-final { scan-hidden "_ZN3foo1fEv" } } +// { dg-final { scan-hidden "_ZN3foo1gEv" } } +// { dg-final { scan-hidden "_ZN3foo1A1mEv" } } +// { dg-final { scan-hidden "_ZN3foo1tIiEEvv" } } +// { dg-final { scan-not-hidden "_ZN3foo1hEv" } } + +namespace foo __attribute ((visibility ("hidden"))) +{ + int f() { } + void g(); + template void t() { } + class A + { + void m (); + }; +} + +namespace foo +{ + void h() {} +} + +void foo::g() { t (); } + +void foo::A::m() { } + Index: gcc/cp/decl.c =================================================================== --- gcc/cp/decl.c (revision 116503) +++ gcc/cp/decl.c (revision 116504) @@ -5243,9 +5243,6 @@ the class specifier. */ if (!DECL_EXTERNAL (decl)) var_definition_p = true; - /* The variable is being defined, so determine its - visibility. */ - determine_visibility (decl); } /* If the variable has an array type, lay out the type, even if there is no initializer. It is valid to index through the @@ -5310,6 +5307,10 @@ 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 @@ -10497,12 +10498,6 @@ maybe_apply_pragma_weak (decl1); } - /* Determine the ELF visibility attribute for the function. We must - not do this before calling "pushdecl", as we must allow - "duplicate_decls" to merge any attributes appropriately. */ - if (!DECL_CLONED_FUNCTION_P (decl1)) - determine_visibility (decl1); - /* Reset these in case the call to pushdecl changed them. */ current_function_decl = decl1; cfun->decl = decl1; @@ -10621,6 +10616,13 @@ DECL_INTERFACE_KNOWN (decl1) = 1; } + /* Determine the ELF visibility attribute for the function. We must not + do this before calling "pushdecl", as we must allow "duplicate_decls" + to merge any attributes appropriately. We also need to wait until + linkage is set. */ + if (!DECL_CLONED_FUNCTION_P (decl1)) + determine_visibility (decl1); + begin_scope (sk_function_parms, decl1); ++function_depth; Index: gcc/cp/cp-tree.h =================================================================== --- gcc/cp/cp-tree.h (revision 116503) +++ gcc/cp/cp-tree.h (revision 116504) @@ -1966,6 +1966,8 @@ /* NULL_TREE in DECL_CONTEXT represents the global namespace. */ #define CP_DECL_CONTEXT(NODE) \ (DECL_CONTEXT (NODE) ? DECL_CONTEXT (NODE) : global_namespace) +#define CP_TYPE_CONTEXT(NODE) \ + (TYPE_CONTEXT (NODE) ? TYPE_CONTEXT (NODE) : global_namespace) #define FROB_CONTEXT(NODE) ((NODE) == global_namespace ? NULL_TREE : (NODE)) /* 1 iff NODE has namespace scope, including the global namespace. */ @@ -1973,15 +1975,25 @@ (!DECL_TEMPLATE_PARM_P (NODE) \ && TREE_CODE (CP_DECL_CONTEXT (NODE)) == NAMESPACE_DECL) +#define TYPE_NAMESPACE_SCOPE_P(NODE) \ + (TREE_CODE (CP_TYPE_CONTEXT (NODE)) == NAMESPACE_DECL) + /* 1 iff NODE is a class member. */ #define DECL_CLASS_SCOPE_P(NODE) \ (DECL_CONTEXT (NODE) && TYPE_P (DECL_CONTEXT (NODE))) +#define TYPE_CLASS_SCOPE_P(NODE) \ + (TYPE_CONTEXT (NODE) && TYPE_P (TYPE_CONTEXT (NODE))) + /* 1 iff NODE is function-local. */ #define DECL_FUNCTION_SCOPE_P(NODE) \ (DECL_CONTEXT (NODE) \ && TREE_CODE (DECL_CONTEXT (NODE)) == FUNCTION_DECL) +#define TYPE_FUNCTION_SCOPE_P(NODE) \ + (TYPE_CONTEXT (NODE) \ + && TREE_CODE (TYPE_CONTEXT (NODE)) == FUNCTION_DECL) + /* 1 iff VAR_DECL node NODE is a type-info decl. This flag is set for both the primary typeinfo object and the associated NTBS name. */ #define DECL_TINFO_P(NODE) TREE_LANG_FLAG_4 (VAR_DECL_CHECK (NODE)) Index: gcc/cp/name-lookup.c =================================================================== --- gcc/cp/name-lookup.c (revision 116503) +++ gcc/cp/name-lookup.c (revision 116504) @@ -31,6 +31,7 @@ #include "toplev.h" #include "diagnostic.h" #include "debug.h" +#include "c-pragma.h" /* The bindings for a particular name in a particular scope. */ @@ -1344,11 +1345,16 @@ is_class_level = 0; } +#ifdef HANDLE_PRAGMA_VISIBILITY + if (scope->has_visibility) + pop_visibility (); +#endif + /* Move one nesting level up. */ current_binding_level = scope->level_chain; /* Namespace-scopes are left most probably temporarily, not - completely; they can be reopen later, e.g. in namespace-extension + completely; they can be reopened later, e.g. in namespace-extension or any name binding activity that requires us to resume a namespace. For classes, we cache some binding levels. For other scopes, we just make the structure available for reuse. */ @@ -2971,6 +2977,15 @@ void push_namespace (tree name) { + push_namespace_with_attribs (name, NULL_TREE); +} + +/* Same, but specify attributes to apply to the namespace. The attributes + only apply to the current namespace-body, not to any later extensions. */ + +void +push_namespace_with_attribs (tree name, tree attributes) +{ tree d = NULL_TREE; int need_new = 1; int implicit_use = 0; @@ -3017,6 +3032,7 @@ /* 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; pushdecl (d); if (anon) { @@ -3034,6 +3050,36 @@ /* Enter the name space. */ current_namespace = d; +#ifdef HANDLE_PRAGMA_VISIBILITY + /* Clear has_visibility in case a previous namespace-definition had a + visibility attribute and this one doesn't. */ + current_binding_level->has_visibility = 0; + for (d = attributes; d; d = TREE_CHAIN (d)) + { + tree name = TREE_PURPOSE (d); + tree args = TREE_VALUE (d); + tree x; + + if (! is_attribute_p ("visibility", name)) + { + warning (OPT_Wattributes, "%qs attribute directive ignored", + IDENTIFIER_POINTER (name)); + continue; + } + + x = args ? TREE_VALUE (args) : NULL_TREE; + if (x == NULL_TREE || TREE_CODE (x) != STRING_CST) + { + warning (OPT_Wattributes, "%qs attribute requires an NTBS argument", + IDENTIFIER_POINTER (name)); + continue; + } + + current_binding_level->has_visibility = 1; + push_visibility (TREE_STRING_POINTER (x)); + } +#endif + timevar_pop (TV_NAME_LOOKUP); } Index: gcc/cp/decl2.c =================================================================== --- gcc/cp/decl2.c (revision 116503) +++ gcc/cp/decl2.c (revision 116504) @@ -82,6 +82,7 @@ static void write_out_vars (tree); static void import_export_class (tree); static tree get_guard_bits (tree); +static void determine_visibility_from_class (tree, tree); /* A list of static class variables. This is needed, because a static class variable can be declared inside the class without @@ -1578,13 +1579,27 @@ } /* Like c_determine_visibility, but with additional C++-specific - behavior. */ + behavior. + Function-scope entities can rely on the function's visibility because + it is set in start_preparsed_function. + + Class-scope entities cannot rely on the class's visibility until the end + of the enclosing class definition. + + 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. */ + void determine_visibility (tree decl) { tree class_type; + /* Only relevant for names with external linkage. */ + if (!TREE_PUBLIC (decl)) + return; + /* Cloned constructors and destructors get the same visibility as the underlying function. That should be set up in maybe_clone_body. */ @@ -1608,6 +1623,14 @@ so they are automatically handled above. */ gcc_assert (TREE_CODE (decl) != VAR_DECL || !DECL_VTABLE_OR_VTT_P (decl)); + + if (DECL_FUNCTION_SCOPE_P (decl)) + { + 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; @@ -1617,34 +1640,63 @@ the visibility of their containing class. */ if (class_type) { - if (TARGET_DLLIMPORT_DECL_ATTRIBUTES - && lookup_attribute ("dllexport", TYPE_ATTRIBUTES (class_type))) + 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); + } +} + +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_DEFAULT; + DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN; 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 (!DECL_VISIBILITY_SPECIFIED (decl)) - { - DECL_VISIBILITY (decl) = CLASSTYPE_VISIBILITY (class_type); - DECL_VISIBILITY_SPECIFIED (decl) = 0; - } } + 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; + } } /* DECL is a FUNCTION_DECL or VAR_DECL. If the object file linkage @@ -1911,21 +1963,6 @@ comdat_linkage (decl); } - /* 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); - DECL_INTERFACE_KNOWN (decl) = 1; } Index: gcc/cp/name-lookup.h =================================================================== --- gcc/cp/name-lookup.h (revision 116503) +++ gcc/cp/name-lookup.h (revision 116504) @@ -259,7 +259,11 @@ unsigned more_cleanups_ok : 1; unsigned have_cleanups : 1; - /* 22 bits left to fill a 32-bit word. */ + /* Nonzero if this level has associated visibility which we should pop + when leaving the scope. */ + unsigned has_visibility : 1; + + /* 23 bits left to fill a 32-bit word. */ }; /* The binding level currently in effect. */ @@ -307,6 +311,7 @@ extern void push_binding_level (struct cp_binding_level *); extern void push_namespace (tree); +extern void push_namespace_with_attribs (tree, tree); extern void pop_namespace (void); extern void push_nested_namespace (tree); extern void pop_nested_namespace (tree); Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 116503) +++ gcc/cp/parser.c (revision 116504) @@ -7112,7 +7112,7 @@ && (/* A named namespace definition. */ (token2.type == CPP_NAME && (cp_lexer_peek_nth_token (parser->lexer, 3)->type - == CPP_OPEN_BRACE)) + != CPP_EQ)) /* An unnamed namespace definition. */ || token2.type == CPP_OPEN_BRACE)) cp_parser_namespace_definition (parser); @@ -10471,7 +10471,7 @@ static void cp_parser_namespace_definition (cp_parser* parser) { - tree identifier; + tree identifier, attribs; /* Look for the `namespace' keyword. */ cp_parser_require_keyword (parser, RID_NAMESPACE, "`namespace'"); @@ -10485,10 +10485,13 @@ else identifier = NULL_TREE; + /* Parse any specified attributes. */ + attribs = cp_parser_attributes_opt (parser); + /* Look for the `{' to start the namespace. */ cp_parser_require (parser, CPP_OPEN_BRACE, "`{'"); /* Start the namespace. */ - push_namespace (identifier); + push_namespace_with_attribs (identifier, attribs); /* Parse the body of the namespace. */ cp_parser_namespace_body (parser); /* Finish the namespace. */ Index: gcc/c-pragma.c =================================================================== --- gcc/c-pragma.c (revision 116503) +++ gcc/c-pragma.c (revision 116504) @@ -596,9 +596,42 @@ typedef enum symbol_visibility visibility; DEF_VEC_I (visibility); DEF_VEC_ALLOC_I (visibility, heap); +static VEC (visibility, heap) *visstack; +/* Push the visibility indicated by STR onto the top of the #pragma + visibility stack. */ + +void +push_visibility (const char *str) +{ + VEC_safe_push (visibility, heap, visstack, + default_visibility); + if (!strcmp (str, "default")) + default_visibility = VISIBILITY_DEFAULT; + else if (!strcmp (str, "internal")) + default_visibility = VISIBILITY_INTERNAL; + else if (!strcmp (str, "hidden")) + default_visibility = VISIBILITY_HIDDEN; + else if (!strcmp (str, "protected")) + default_visibility = VISIBILITY_PROTECTED; + else + GCC_BAD ("#pragma GCC visibility push() must specify default, internal, hidden or protected"); + visibility_options.inpragma = 1; +} + +/* Pop a level of the #pragma visibility stack. */ + +void +pop_visibility (void) +{ + default_visibility = VEC_pop (visibility, visstack); + visibility_options.inpragma + = VEC_length (visibility, visstack) != 0; +} + /* Sets the default visibility for symbols to something other than that specified on the command line. */ + static void handle_pragma_visibility (cpp_reader *dummy ATTRIBUTE_UNUSED) { @@ -606,7 +639,6 @@ tree x; enum cpp_ttype token; enum { bad, push, pop } action = bad; - static VEC (visibility, heap) *visstack; token = pragma_lex (&x); if (token == CPP_NAME) @@ -624,15 +656,9 @@ if (pop == action) { if (!VEC_length (visibility, visstack)) - { - GCC_BAD ("no matching push for %<#pragma GCC visibility pop%>"); - } + GCC_BAD ("no matching push for %<#pragma GCC visibility pop%>"); else - { - default_visibility = VEC_pop (visibility, visstack); - visibility_options.inpragma - = VEC_length (visibility, visstack) != 0; - } + pop_visibility (); } else { Index: gcc/c-pragma.h =================================================================== --- gcc/c-pragma.h (revision 116503) +++ gcc/c-pragma.h (revision 116504) @@ -75,6 +75,8 @@ visibility is not supported on the host OS platform the statements are ignored. */ #define HANDLE_PRAGMA_VISIBILITY 1 +extern void push_visibility (const char *); +extern void pop_visibility (void); extern void init_pragma (void);