diff options
author | jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-07-20 16:02:57 +0000 |
---|---|---|
committer | jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-07-20 16:02:57 +0000 |
commit | 6a47600ccb509de8d9fc9f603e91990ae71479c1 (patch) | |
tree | 2668380ba111a9cfdf1beb690c74127fc5593651 /gcc | |
parent | d249588e4325dd5715ee30acfd2e97701407b5fa (diff) | |
download | gcc-6a47600ccb509de8d9fc9f603e91990ae71479c1.tar.gz |
PR c++/28407
* cp/decl.c (grokvardecl): Set DECL_THIS_STATIC on file-scope
const variables with implicit internal linkage.
* cp/tree.c (decl_linkage): Only return lk_external if it's set.
PR c++/28409
* cp/decl2.c (constrain_visibility): Ignore the anonymous namespace
for extern C decls.
(VISIBILITY_STATIC): Rename to VISIBILITY_ANON.
Don't override explicit visibility.
* cp/decl2.c (constrain_visibility): Remove specified and reason
parameters. Don't touch decls that already have explicit visibility.
(determine_visibility): Do copy DECL_VISIBILITY_SPECIFIED from
template.
(determine_visibility_from_class): Reverse sense of
DECL_VISIBILITY_SPECIFIED test for target-specific visibility rules.
(constrain_class_visibility): Only complain about member visibility
if the member type is another class. Don't change visibility of the
current class.
* tree.c (remove_attribute): New fn.
* tree.h: Declare it.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@115622 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/cp/ChangeLog | 22 | ||||
-rw-r--r-- | gcc/cp/decl.c | 8 | ||||
-rw-r--r-- | gcc/cp/decl2.c | 126 | ||||
-rw-r--r-- | gcc/cp/pt.c | 14 | ||||
-rw-r--r-- | gcc/cp/tree.c | 11 | ||||
-rw-r--r-- | gcc/doc/extend.texi | 18 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/visibility/template6.C | 17 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/visibility/warn2.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/visibility/warn3.C | 27 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/lookup/anon5.C | 21 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/anon4.C | 10 | ||||
-rw-r--r-- | gcc/tree.c | 22 | ||||
-rw-r--r-- | gcc/tree.h | 5 |
14 files changed, 246 insertions, 61 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5d9e52ecac1..7163d753157 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,7 @@ +2006-07-20 Jason Merrill <jason@redhat.com> + + * tree.c (remove_attribute): New fn. + 2006-07-20 Paul Brook <paul@codesourcery.com> PR 27363 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index da9ab491c73..309a060c3a2 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,25 @@ +2006-07-20 Jason Merrill <jason@redhat.com> + + PR c++/28407 + * decl.c (grokvardecl): Set DECL_THIS_STATIC on file-scope + const variables with implicit internal linkage. + * tree.c (decl_linkage): Only return lk_external if it's set. + + PR c++/28409 + * decl2.c (constrain_visibility): Ignore the anonymous namespace + for extern "C" decls. + (VISIBILITY_STATIC): Rename to VISIBILITY_ANON. + + * decl2.c (constrain_visibility): Remove specified and reason + parameters. Don't touch decls that already have explicit visibility. + (determine_visibility): Do copy DECL_VISIBILITY_SPECIFIED from + template. + (determine_visibility_from_class): Reverse sense of + DECL_VISIBILITY_SPECIFIED test for target-specific visibility rules. + (constrain_class_visibility): Only complain about member visibility + if the member type is another class. Don't change visibility of the + current class. + 2006-07-19 Mark Mitchell <mark@codesourcery.com> PR c++/28338 diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 124e0448c63..78838b06b2b 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5246,6 +5246,14 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, { 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); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 385f8d96c8f..351de049f4c 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1536,7 +1536,7 @@ maybe_emit_vtables (tree ctype) /* 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. */ @@ -1552,7 +1552,7 @@ min_vis_r (tree *tp, int *walk_subtrees, void *data) { if (!TREE_PUBLIC (TYPE_MAIN_DECL (*tp))) { - *vis_p = VISIBILITY_STATIC; + *vis_p = VISIBILITY_ANON; return *tp; } else if (CLASSTYPE_VISIBILITY (*tp) > *vis_p) @@ -1572,29 +1572,28 @@ type_visibility (tree type) 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; @@ -1627,13 +1626,13 @@ constrain_visibility_for_template (tree decl, tree targs) || 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); } } @@ -1735,8 +1734,7 @@ determine_visibility (tree decl) { /* 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 @@ -1752,43 +1750,42 @@ determine_visibility (tree decl) 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); } - + 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")) + 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 @@ -1806,11 +1803,13 @@ determine_visibility_from_class (tree decl, tree class_type) && 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"); + 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); + } /* Give the target a chance to override the visibility associated with DECL. */ @@ -1823,8 +1822,8 @@ determine_visibility_from_class (tree decl, tree class_type) && !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); } @@ -1834,25 +1833,50 @@ determine_visibility_from_class (tree decl, tree class_type) 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 diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 7c099644d35..f65d0ce25a6 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -6589,7 +6589,12 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) /* 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; @@ -6791,7 +6796,12 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) { /* 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); } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index c1c6719e8ef..0d42502da76 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -2195,6 +2195,9 @@ decl_linkage (tree decl) 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) @@ -2214,6 +2217,14 @@ decl_linkage (tree decl) 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; } diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 7314e520ab5..e6e5e1718c6 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -2413,16 +2413,16 @@ In C++, the visibility attribute applies to types as well as functions 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. +declaration without explicit visibility is limited to the visibility +of 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 particular method or static member variable should only be used from one shared object; then you can mark it hidden while the rest of the class has default visibility. Care must be taken to avoid breaking -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. +the One Definition Rule; for example, it is usually not useful to mark +an inline method 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 @@ -2435,6 +2435,9 @@ restriction is implicitly propagated to the template instantiation. 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 @@ -3668,6 +3671,13 @@ 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. +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 diff --git a/gcc/testsuite/g++.dg/ext/visibility/template6.C b/gcc/testsuite/g++.dg/ext/visibility/template6.C new file mode 100644 index 00000000000..7892a46e2aa --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/visibility/template6.C @@ -0,0 +1,17 @@ +// Test for explicit visibility taking precedence + +// { dg-require-visibility "" } +// { dg-final { scan-not-hidden "_ZN1AIiE1fEv" } } + +template <class T> struct A +{ + // This attribute takes precedence over... + __attribute ((visibility ("default"))) void f (); +}; + +template <class T> +void A<T>::f () +{ } + +// ...this attribute. +template struct __attribute ((visibility ("hidden"))) A<int>; diff --git a/gcc/testsuite/g++.dg/ext/visibility/warn2.C b/gcc/testsuite/g++.dg/ext/visibility/warn2.C index 1baf8b9e83a..54354b52311 100644 --- a/gcc/testsuite/g++.dg/ext/visibility/warn2.C +++ b/gcc/testsuite/g++.dg/ext/visibility/warn2.C @@ -14,6 +14,6 @@ struct B N::A a; }; -B f () { } // { dg-warning "visibility" } +N::A 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 index 705748ad711..de64217fd3b 100644 --- a/gcc/testsuite/g++.dg/ext/visibility/warn3.C +++ b/gcc/testsuite/g++.dg/ext/visibility/warn3.C @@ -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; +}; diff --git a/gcc/testsuite/g++.dg/lookup/anon5.C b/gcc/testsuite/g++.dg/lookup/anon5.C new file mode 100644 index 00000000000..c3d36c20f53 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/anon5.C @@ -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(); +} diff --git a/gcc/testsuite/g++.dg/template/anon4.C b/gcc/testsuite/g++.dg/template/anon4.C new file mode 100644 index 00000000000..59bfee1e814 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/anon4.C @@ -0,0 +1,10 @@ +// PR c++/28407 +// A declaration in the anonymous namespace still has external linkage. + +template <int *P> class A { }; +namespace +{ + int i; +} + +A<&i> a; diff --git a/gcc/tree.c b/gcc/tree.c index 48f4614ceae..dc78ad775af 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -3499,6 +3499,28 @@ lookup_attribute (const char *attr_name, tree list) 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 diff --git a/gcc/tree.h b/gcc/tree.h index dfea92adc1d..5e47dacc56d 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -3696,6 +3696,11 @@ extern int is_attribute_p (const char *, tree); 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); |