Index: gcc/doc/extend.texi =================================================================== --- gcc/doc/extend.texi (revision 116505) +++ gcc/doc/extend.texi (revision 116507) @@ -2346,6 +2346,9 @@ Otherwise, template instantiations and specializations default to the visibility of their template. +If both the template and enclosing class have explicit visibility, the +visibility from the template is used. + @item warn_unused_result @cindex @code{warn_unused_result} attribute The @code{warn_unused_result} attribute causes a warning to be emitted @@ -3465,6 +3468,13 @@ attributes, the attribute must appear between the initial keyword and the name of the type; it cannot appear after the body of the type. +Note that the type visibility is applied to vague linkage entities +associated with the class (vtable, typeinfo node, etc.). In +particular, if a class is thrown as an exception in one shared object +and caught in another, the class must have default visibility. +Otherwise the two shared objects will be unable to use the same +typeinfo node and exception handling will break. + @subsection ARM Type Attributes On those ARM targets that support @code{dllimport} (such as Symbian Index: gcc/tree.c =================================================================== --- gcc/tree.c (revision 116505) +++ gcc/tree.c (revision 116507) @@ -3461,6 +3461,28 @@ return NULL_TREE; } +/* Remove any instances of attribute ATTR_NAME in LIST and return the + modified list. */ + +tree +remove_attribute (const char *attr_name, tree list) +{ + tree *p; + size_t attr_len = strlen (attr_name); + + for (p = &list; *p; ) + { + tree l = *p; + gcc_assert (TREE_CODE (TREE_PURPOSE (l)) == IDENTIFIER_NODE); + if (is_attribute_with_length_p (attr_name, attr_len, TREE_PURPOSE (l))) + *p = TREE_CHAIN (l); + else + p = &TREE_CHAIN (l); + } + + return list; +} + /* Return an attribute list that is the union of a1 and a2. */ tree Index: gcc/tree.h =================================================================== --- gcc/tree.h (revision 116505) +++ gcc/tree.h (revision 116507) @@ -3613,6 +3613,11 @@ extern tree lookup_attribute (const char *, tree); +/* Remove any instances of attribute ATTR_NAME in LIST and return the + modified list. */ + +extern tree remove_attribute (const char *, tree); + /* Given two attributes lists, return a list of their union. */ extern tree merge_attributes (tree, tree); Index: gcc/testsuite/g++.dg/ext/visibility/template6.C =================================================================== --- gcc/testsuite/g++.dg/ext/visibility/template6.C (revision 0) +++ gcc/testsuite/g++.dg/ext/visibility/template6.C (revision 116507) @@ -0,0 +1,17 @@ +// Test for explicit visibility taking precedence + +// { dg-require-visibility "" } +// { dg-final { scan-not-hidden "_ZN1AIiE1fEv" } } + +template struct A +{ + // This attribute takes precedence over... + __attribute ((visibility ("default"))) void f (); +}; + +template +void A::f () +{ } + +// ...this attribute. +template struct __attribute ((visibility ("hidden"))) A; Index: gcc/testsuite/g++.dg/ext/visibility/warn2.C =================================================================== --- gcc/testsuite/g++.dg/ext/visibility/warn2.C (revision 116505) +++ gcc/testsuite/g++.dg/ext/visibility/warn2.C (revision 116507) @@ -14,6 +14,6 @@ N::A a; }; -B f () { } // { dg-warning "visibility" } +N::A f () { } // { dg-warning "visibility" } struct C: public N::A { }; // { dg-warning "visibility" } Index: gcc/testsuite/g++.dg/ext/visibility/warn3.C =================================================================== --- gcc/testsuite/g++.dg/ext/visibility/warn3.C (revision 116505) +++ gcc/testsuite/g++.dg/ext/visibility/warn3.C (revision 116507) @@ -1,11 +1,32 @@ -// Warn when a class member is specified to have greater visibility than -// its class. +// Tests for various visibility mismatch situations. // { dg-require-visibility "" } +// { dg-final { scan-not-hidden "_ZN1A1fEv" } } + struct __attribute ((visibility ("hidden"))) A { - __attribute ((visibility ("default"))) void f (); // { dg-warning "visibility" } + // This is OK, A::f gets default visibility. + __attribute ((visibility ("default"))) void f (); }; void A::f() { } + +// This gets a warning; it should have explicit visibility of some sort. +A* afactory1() { return new A; } // { dg-warning "visibility" } + +// This is OK. +__attribute ((visibility ("default"))) A* +afactory2 () { return new A; } + +// This gets a warning. +struct B +{ // { dg-warning "visibility" } + A a; +}; + +// This one has explicit visibility, so it doesn't get a warning. +struct __attribute ((visibility ("default"))) C +{ + A a; +}; Index: gcc/testsuite/g++.dg/lookup/anon5.C =================================================================== --- gcc/testsuite/g++.dg/lookup/anon5.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/anon5.C (revision 116507) @@ -0,0 +1,21 @@ +// PR c++/28409 +// shouldIbevisible should be emitted because it's an extern "C" decl with +// external linkage, even though it's in the anonymous namespace. + +namespace +{ + extern "C" int shouldIbevisible() + { + return 0; + } +} + +namespace t +{ + extern "C" int shouldIbevisible(void); +} + +int main(void) +{ + return t::shouldIbevisible(); +} Index: gcc/testsuite/g++.dg/template/anon3.C =================================================================== --- gcc/testsuite/g++.dg/template/anon3.C (revision 0) +++ gcc/testsuite/g++.dg/template/anon3.C (revision 116507) @@ -0,0 +1,20 @@ +// PR c++/28370 +// { dg-do run } + +namespace +{ + template struct A { static int *a; }; + template int *A::a = 0; +} + +int * +foo () +{ + return A::a; +} + +int +main () +{ + return foo() != 0; +} Index: gcc/testsuite/g++.dg/template/anon4.C =================================================================== --- gcc/testsuite/g++.dg/template/anon4.C (revision 0) +++ gcc/testsuite/g++.dg/template/anon4.C (revision 116507) @@ -0,0 +1,10 @@ +// PR c++/28407 +// A declaration in the anonymous namespace still has external linkage. + +template class A { }; +namespace +{ + int i; +} + +A<&i> a; Index: gcc/cp/decl.c =================================================================== --- gcc/cp/decl.c (revision 116505) +++ gcc/cp/decl.c (revision 116507) @@ -5274,6 +5274,14 @@ determine_visibility (decl); layout_var_decl (decl); maybe_commonize_var (decl); + if (DECL_NAMESPACE_SCOPE_P (decl) && !TREE_PUBLIC (decl) + && !DECL_THIS_STATIC (decl) && !DECL_ARTIFICIAL (decl)) + { + /* This is a const variable with implicit 'static'. Set + DECL_THIS_STATIC so we can tell it from variables that are + !TREE_PUBLIC because of the anonymous namespace. */ + DECL_THIS_STATIC (decl) = 1; + } make_rtl_for_nonlocal_decl (decl, init, /*asmspec=*/NULL); } Index: gcc/cp/tree.c =================================================================== --- gcc/cp/tree.c (revision 116505) +++ gcc/cp/tree.c (revision 116507) @@ -2189,7 +2189,10 @@ /* Things that are TREE_PUBLIC have external linkage. */ if (TREE_PUBLIC (decl)) return lk_external; - + + if (TREE_CODE (decl) == NAMESPACE_DECL) + return lk_external; + /* Linkage of a CONST_DECL depends on the linkage of the enumeration type. */ if (TREE_CODE (decl) == CONST_DECL) @@ -2209,6 +2212,14 @@ if (decl_function_context (decl)) return lk_none; + /* Members of the anonymous namespace also have TREE_PUBLIC unset, but + are considered to have external linkage for language purposes. DECLs + really meant to have internal linkage have DECL_THIS_STATIC set. */ + if (TREE_CODE (decl) == TYPE_DECL + || ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL) + && !DECL_THIS_STATIC (decl))) + return lk_external; + /* Everything else has internal linkage. */ return lk_internal; } Index: gcc/cp/pt.c =================================================================== --- gcc/cp/pt.c (revision 116505) +++ gcc/cp/pt.c (revision 116507) @@ -6609,7 +6609,12 @@ /* Possibly limit visibility based on template args. */ DECL_VISIBILITY (r) = VISIBILITY_DEFAULT; - DECL_VISIBILITY_SPECIFIED (r) = 0; + if (DECL_VISIBILITY_SPECIFIED (t)) + { + DECL_VISIBILITY_SPECIFIED (r) = 0; + DECL_ATTRIBUTES (r) + = remove_attribute ("visibility", DECL_ATTRIBUTES (r)); + } determine_visibility (r); } break; @@ -6811,7 +6816,12 @@ { /* Possibly limit visibility based on template args. */ DECL_VISIBILITY (r) = VISIBILITY_DEFAULT; - DECL_VISIBILITY_SPECIFIED (r) = 0; + if (DECL_VISIBILITY_SPECIFIED (t)) + { + DECL_VISIBILITY_SPECIFIED (r) = 0; + DECL_ATTRIBUTES (r) + = remove_attribute ("visibility", DECL_ATTRIBUTES (r)); + } determine_visibility (r); } Index: gcc/cp/decl2.c =================================================================== --- gcc/cp/decl2.c (revision 116505) +++ gcc/cp/decl2.c (revision 116507) @@ -737,14 +737,6 @@ } } -/* Like note_vague_linkage_fn but for variables. */ - -static void -note_vague_linkage_var (tree var) -{ - VEC_safe_push (tree, gc, pending_statics, var); -} - /* We have just processed the DECL, which is a static data member. The other parameters are as for cp_finish_decl. */ @@ -763,8 +755,8 @@ if (!asmspec_tree && current_class_type) DECL_INITIAL (decl) = error_mark_node; - if (! processing_template_decl && TREE_PUBLIC (decl)) - note_vague_linkage_var (decl); + if (! processing_template_decl) + VEC_safe_push (tree, gc, pending_statics, decl); if (LOCAL_CLASS_P (current_class_type)) pedwarn ("local class %q#T shall not have static data member %q#D", @@ -1579,7 +1571,7 @@ /* A special return value from type_visibility meaning internal linkage. */ -enum { VISIBILITY_STATIC = VISIBILITY_INTERNAL+1 }; +enum { VISIBILITY_ANON = VISIBILITY_INTERNAL+1 }; /* walk_tree helper function for type_visibility. */ @@ -1595,7 +1587,7 @@ { if (!TREE_PUBLIC (TYPE_MAIN_DECL (*tp))) { - *vis_p = VISIBILITY_STATIC; + *vis_p = VISIBILITY_ANON; return *tp; } else if (CLASSTYPE_VISIBILITY (*tp) > *vis_p) @@ -1615,29 +1607,28 @@ 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. */ +/* Limit the visibility of DECL to VISIBILITY, if not explicitly + specified (or if VISIBILITY is static). */ static bool -constrain_visibility (tree decl, int visibility, bool specified, - const char *reason) +constrain_visibility (tree decl, int visibility) { - if (visibility == VISIBILITY_STATIC) + if (visibility == VISIBILITY_ANON) { - TREE_PUBLIC (decl) = 0; - DECL_INTERFACE_KNOWN (decl) = 1; - if (DECL_LANG_SPECIFIC (decl)) - DECL_NOT_REALLY_EXTERN (decl) = 1; + /* extern "C" declarations aren't affected by the anonymous + namespace. */ + if (!DECL_EXTERN_C_P (decl)) + { + 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)) + else if (visibility > DECL_VISIBILITY (decl) + && !DECL_VISIBILITY_SPECIFIED (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; @@ -1670,13 +1661,13 @@ || TREE_CODE (arg) == FUNCTION_DECL) { if (! TREE_PUBLIC (arg)) - vis = VISIBILITY_STATIC; + vis = VISIBILITY_ANON; else vis = DECL_VISIBILITY (arg); } } if (vis) - constrain_visibility (decl, vis, false, "template parameter"); + constrain_visibility (decl, vis); } } @@ -1771,8 +1762,7 @@ { /* tinfo visibility is based on the type it's for. */ constrain_visibility - (decl, type_visibility (TREE_TYPE (DECL_NAME (decl))), - false, "type"); + (decl, type_visibility (TREE_TYPE (DECL_NAME (decl)))); } else if (use_template) /* Template instantiations and specializations get visibility based @@ -1788,24 +1778,25 @@ if (use_template) { + /* If the specialization doesn't specify visibility, use the + visibility from the template. */ 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); + tree pattern = DECL_TEMPLATE_RESULT (TI_TEMPLATE (tinfo)); - /* 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); + DECL_VISIBILITY_SPECIFIED (decl) + = DECL_VISIBILITY_SPECIFIED (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. */ + /* Limit visibility based on its template arguments. */ constrain_visibility_for_template (decl, args); } @@ -1814,17 +1805,15 @@ /* 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")) + if (constrain_visibility (decl, type_visibility (TREE_TYPE (decl)))) warning (OPT_Wattributes, "\ -%q+D declared with greater visibility than its type", +lowering visibility of %q+D to match 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"); + constrain_visibility (decl, VISIBILITY_ANON); } /* By default, static data members and function members receive @@ -1842,12 +1831,14 @@ && TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl)) DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN; + else if (!DECL_VISIBILITY_SPECIFIED (decl)) + { + /* Default to the class visibility. */ + DECL_VISIBILITY (decl) = CLASSTYPE_VISIBILITY (class_type); + DECL_VISIBILITY_SPECIFIED (decl) + = CLASSTYPE_VISIBILITY_SPECIFIED (class_type); + } - /* 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 @@ -1859,8 +1850,8 @@ && !DECL_CONSTRUCTION_VTABLE_P (decl))) && TREE_PUBLIC (decl) && !DECL_REALLY_EXTERN (decl) - && DECL_VISIBILITY_SPECIFIED (decl) - && (!class_type || !CLASSTYPE_VISIBILITY_SPECIFIED (class_type))) + && !DECL_VISIBILITY_SPECIFIED (decl) + && !CLASSTYPE_VISIBILITY_SPECIFIED (class_type)) targetm.cxx.determine_class_data_visibility (decl); } @@ -1870,25 +1861,50 @@ void constrain_class_visibility (tree type) { - tree decl = TYPE_MAIN_DECL (type); - tree binfo = TYPE_BINFO (type); + tree binfo; tree t; int i; + int vis = type_visibility (type); + + if (vis == VISIBILITY_ANON) + return; + + /* Don't warn about visibility if the class has explicit visibility. */ + if (CLASSTYPE_VISIBILITY_SPECIFIED (type)) + vis = VISIBILITY_INTERNAL; + 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, "\ + if (TREE_CODE (t) == FIELD_DECL && TREE_TYPE (t) != error_mark_node) + { + int subvis = type_visibility (TREE_TYPE (t)); + + if (subvis == VISIBILITY_ANON) + warning (0, "\ +%qT has a field %qD whose type uses the anonymous namespace", + type, t); + else if (vis < VISIBILITY_HIDDEN + && subvis >= VISIBILITY_HIDDEN) + warning (OPT_Wattributes, "\ %qT declared with greater visibility than the type of its field %qD", - type, t); + type, t); + } + binfo = TYPE_BINFO (type); 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, "\ + { + int subvis = type_visibility (TREE_TYPE (t)); + + if (subvis == VISIBILITY_ANON) + warning (0, "\ +%qT has a base %qT whose type uses the anonymous namespace", + type, TREE_TYPE (t)); + else if (vis < VISIBILITY_HIDDEN + && subvis >= VISIBILITY_HIDDEN) + warning (OPT_Wattributes, "\ %qT declared with greater visibility than its base %qT", - type, TREE_TYPE (t)); + type, TREE_TYPE (t)); + } } /* DECL is a FUNCTION_DECL or VAR_DECL. If the object file linkage