By treating a namespace name as an ABI tag we can avoid most of the need
for tagging class types.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 65b7f772bb3240688aae6af41d0a1200972885ae
Author: Jason Merrill <ja...@redhat.com>
Date: Tue Dec 2 17:11:37 2014 -0500
* cp-tree.h (NAMESPACE_ABI_TAG): New.
* name-lookup.c (handle_namespace_attrs): Set it.
* class.c (check_tag): Split out from find_abi_tags_r.
(find_abi_tags_r): Also check namespace tags.
(mark_type_abi_tags): Also mark namespace tags.
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index c83c8ad..07bbc69 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -1352,18 +1352,73 @@ handle_using_decl (tree using_decl, tree t)
alter_access (t, decl, access);
}
+/* Data structure for find_abi_tags_r, below. */
+
+struct abi_tag_data
+{
+ tree t; // The type that we're checking for missing tags.
+ tree subob; // The subobject of T that we're getting tags from.
+ tree tags; // error_mark_node for diagnostics, or a list of missing tags.
+};
+
+/* Subroutine of find_abi_tags_r. Handle a single TAG found on the class TP
+ in the context of P. TAG can be either an identifier (the DECL_NAME of
+ a tag NAMESPACE_DECL) or a STRING_CST (a tag attribute). */
+
+static void
+check_tag (tree tag, tree *tp, abi_tag_data *p)
+{
+ tree id;
+
+ if (TREE_CODE (tag) == STRING_CST)
+ id = get_identifier (TREE_STRING_POINTER (tag));
+ else
+ {
+ id = tag;
+ tag = NULL_TREE;
+ }
+
+ if (!IDENTIFIER_MARKED (id))
+ {
+ if (!tag)
+ tag = build_string (IDENTIFIER_LENGTH (id) + 1,
+ IDENTIFIER_POINTER (id));
+ if (p->tags != error_mark_node)
+ {
+ /* We're collecting tags from template arguments. */
+ p->tags = tree_cons (NULL_TREE, tag, p->tags);
+ ABI_TAG_IMPLICIT (p->tags) = true;
+
+ /* Don't inherit this tag multiple times. */
+ IDENTIFIER_MARKED (id) = true;
+ }
+
+ /* Otherwise we're diagnosing missing tags. */
+ else if (TYPE_P (p->subob))
+ {
+ if (warning (OPT_Wabi_tag, "%qT does not have the %E abi tag "
+ "that base %qT has", p->t, tag, p->subob))
+ inform (location_of (p->subob), "%qT declared here",
+ p->subob);
+ }
+ else
+ {
+ if (warning (OPT_Wabi_tag, "%qT does not have the %E abi tag "
+ "that %qT (used in the type of %qD) has",
+ p->t, tag, *tp, p->subob))
+ {
+ inform (location_of (p->subob), "%qD declared here",
+ p->subob);
+ inform (location_of (*tp), "%qT declared here", *tp);
+ }
+ }
+ }
+}
+
/* walk_tree callback for check_abi_tags: if the type at *TP involves any
types with abi tags, add the corresponding identifiers to the VEC in
*DATA and set IDENTIFIER_MARKED. */
-struct abi_tag_data
-{
- tree t;
- tree subob;
- // error_mark_node to get diagnostics; otherwise collect missing tags here
- tree tags;
-};
-
static tree
find_abi_tags_r (tree *tp, int *walk_subtrees, void *data)
{
@@ -1374,48 +1429,21 @@ find_abi_tags_r (tree *tp, int *walk_subtrees, void *data)
anyway, but let's make sure of it. */
*walk_subtrees = false;
+ abi_tag_data *p = static_cast<struct abi_tag_data*>(data);
+
+ for (tree ns = decl_namespace_context (*tp);
+ ns != global_namespace;
+ ns = CP_DECL_CONTEXT (ns))
+ if (NAMESPACE_ABI_TAG (ns))
+ check_tag (DECL_NAME (ns), tp, p);
+
if (tree attributes = lookup_attribute ("abi_tag", TYPE_ATTRIBUTES (*tp)))
{
- struct abi_tag_data *p = static_cast<struct abi_tag_data*>(data);
for (tree list = TREE_VALUE (attributes); list;
list = TREE_CHAIN (list))
{
tree tag = TREE_VALUE (list);
- tree id = get_identifier (TREE_STRING_POINTER (tag));
- if (!IDENTIFIER_MARKED (id))
- {
- if (p->tags != error_mark_node)
- {
- /* We're collecting tags from template arguments. */
- tree str = build_string (IDENTIFIER_LENGTH (id),
- IDENTIFIER_POINTER (id));
- p->tags = tree_cons (NULL_TREE, str, p->tags);
- ABI_TAG_IMPLICIT (p->tags) = true;
-
- /* Don't inherit this tag multiple times. */
- IDENTIFIER_MARKED (id) = true;
- }
-
- /* Otherwise we're diagnosing missing tags. */
- else if (TYPE_P (p->subob))
- {
- if (warning (OPT_Wabi_tag, "%qT does not have the %E abi tag "
- "that base %qT has", p->t, tag, p->subob))
- inform (location_of (p->subob), "%qT declared here",
- p->subob);
- }
- else
- {
- if (warning (OPT_Wabi_tag, "%qT does not have the %E abi tag "
- "that %qT (used in the type of %qD) has",
- p->t, tag, *tp, p->subob))
- {
- inform (location_of (p->subob), "%qD declared here",
- p->subob);
- inform (location_of (*tp), "%qT declared here", *tp);
- }
- }
- }
+ check_tag (tag, tp, p);
}
}
return NULL_TREE;
@@ -1427,6 +1455,12 @@ find_abi_tags_r (tree *tp, int *walk_subtrees, void *data)
static void
mark_type_abi_tags (tree t, bool val)
{
+ for (tree ns = decl_namespace_context (t);
+ ns != global_namespace;
+ ns = CP_DECL_CONTEXT (ns))
+ if (NAMESPACE_ABI_TAG (ns))
+ IDENTIFIER_MARKED (DECL_NAME (ns)) = val;
+
tree attributes = lookup_attribute ("abi_tag", TYPE_ATTRIBUTES (t));
if (attributes)
{
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ad1cc71..e851660 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -151,6 +151,7 @@ c-common.h, not after.
DECL_MUTABLE_P (in FIELD_DECL)
DECL_DEPENDENT_P (in USING_DECL)
LABEL_DECL_BREAK (in LABEL_DECL)
+ NAMESPACE_ABI_TAG (in NAMESPACE_DECL)
1: C_TYPEDEF_EXPLICITLY_SIGNED (in TYPE_DECL).
DECL_TEMPLATE_INSTANTIATED (in a VAR_DECL or a FUNCTION_DECL)
DECL_MEMBER_TEMPLATE_P (in TEMPLATE_DECL)
@@ -2642,6 +2643,11 @@ struct GTY(()) lang_decl {
#define LOCAL_CLASS_P(NODE) \
(decl_function_context (TYPE_MAIN_DECL (NODE)) != NULL_TREE)
+/* 1 iff this NAMESPACE_DECL should also be treated as an ABI tag for
+ -Wabi-tag. */
+#define NAMESPACE_ABI_TAG(NODE) \
+ DECL_LANG_FLAG_0 (NAMESPACE_DECL_CHECK (NODE))
+
/* For a NAMESPACE_DECL: the list of using namespace directives
The PURPOSE is the used namespace, the value is the namespace
that is the common ancestor. */
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 71b359e..b982451 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -3610,10 +3610,8 @@ current_decl_namespace (void)
return result;
}
-/* Process any ATTRIBUTES on a namespace definition. Currently only
- attribute visibility is meaningful, which is a property of the syntactic
- block rather than the namespace as a whole, so we don't touch the
- NAMESPACE_DECL at all. Returns true if attribute visibility is seen. */
+/* Process any ATTRIBUTES on a namespace definition. Returns true if
+ attribute visibility is seen. */
bool
handle_namespace_attrs (tree ns, tree attributes)
@@ -3628,6 +3626,9 @@ handle_namespace_attrs (tree ns, tree attributes)
if (is_attribute_p ("visibility", name))
{
+ /* attribute visibility is a property of the syntactic block
+ rather than the namespace as a whole, so we don't touch the
+ NAMESPACE_DECL at all. */
tree x = args ? TREE_VALUE (args) : NULL_TREE;
if (x == NULL_TREE || TREE_CODE (x) != STRING_CST || TREE_CHAIN (args))
{
@@ -3645,6 +3646,10 @@ handle_namespace_attrs (tree ns, tree attributes)
push_visibility (TREE_STRING_POINTER (x), 1);
saw_vis = true;
}
+ else if (is_attribute_p ("abi_tag", name))
+ {
+ NAMESPACE_ABI_TAG (ns) = true;
+ }
else
{
warning (OPT_Wattributes, "%qD attribute directive ignored",
diff --git a/gcc/testsuite/g++.dg/abi/abi-tag12.C b/gcc/testsuite/g++.dg/abi/abi-tag12.C
new file mode 100644
index 0000000..74dffa0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/abi-tag12.C
@@ -0,0 +1,8 @@
+// { dg-options "-Wabi-tag" }
+
+inline namespace A __attribute ((abi_tag)) {
+ struct Foo { }; // { dg-message "declared here" }
+ struct Baz: Foo { };
+}
+
+struct Bar: Foo { }; // { dg-warning "tag" }