summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>2006-07-20 16:02:57 +0000
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>2006-07-20 16:02:57 +0000
commit6a47600ccb509de8d9fc9f603e91990ae71479c1 (patch)
tree2668380ba111a9cfdf1beb690c74127fc5593651 /gcc
parentd249588e4325dd5715ee30acfd2e97701407b5fa (diff)
downloadgcc-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/ChangeLog4
-rw-r--r--gcc/cp/ChangeLog22
-rw-r--r--gcc/cp/decl.c8
-rw-r--r--gcc/cp/decl2.c126
-rw-r--r--gcc/cp/pt.c14
-rw-r--r--gcc/cp/tree.c11
-rw-r--r--gcc/doc/extend.texi18
-rw-r--r--gcc/testsuite/g++.dg/ext/visibility/template6.C17
-rw-r--r--gcc/testsuite/g++.dg/ext/visibility/warn2.C2
-rw-r--r--gcc/testsuite/g++.dg/ext/visibility/warn3.C27
-rw-r--r--gcc/testsuite/g++.dg/lookup/anon5.C21
-rw-r--r--gcc/testsuite/g++.dg/template/anon4.C10
-rw-r--r--gcc/tree.c22
-rw-r--r--gcc/tree.h5
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);