re PR c++/28407 (Issue with anonymous namespace)

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.

From-SVN: r115622
This commit is contained in:
Jason Merrill 2006-07-20 12:02:57 -04:00 committed by Jason Merrill
parent e67b81d140
commit b70f0f48c7
14 changed files with 248 additions and 63 deletions

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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;
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);
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 && 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);
}
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

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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

View file

@ -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>;

View file

@ -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" }

View file

@ -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;
};

View file

@ -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();
}

View file

@ -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;

View file

@ -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

View file

@ -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);