cp-tree.h (NAMESPACE_ABI_TAG): New.

* 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.

From-SVN: r218684
This commit is contained in:
Jason Merrill 2014-12-12 12:52:21 -05:00 committed by Jason Merrill
parent 9c89d52a8d
commit e3501bab81
5 changed files with 108 additions and 47 deletions

View File

@ -1,3 +1,11 @@
2014-12-12 Jason Merrill <jason@redhat.com>
* 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.
2014-12-12 Kai Tietz <ktietz@redhat.com> 2014-12-12 Kai Tietz <ktietz@redhat.com>
PR c++/63996 PR c++/63996

View File

@ -1352,18 +1352,73 @@ handle_using_decl (tree using_decl, tree t)
alter_access (t, decl, access); alter_access (t, decl, access);
} }
/* walk_tree callback for check_abi_tags: if the type at *TP involves any /* Data structure for find_abi_tags_r, below. */
types with abi tags, add the corresponding identifiers to the VEC in
*DATA and set IDENTIFIER_MARKED. */
struct abi_tag_data struct abi_tag_data
{ {
tree t; tree t; // The type that we're checking for missing tags.
tree subob; tree subob; // The subobject of T that we're getting tags from.
// error_mark_node to get diagnostics; otherwise collect missing tags here tree tags; // error_mark_node for diagnostics, or a list of missing tags.
tree 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. */
static tree static tree
find_abi_tags_r (tree *tp, int *walk_subtrees, void *data) 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. */ anyway, but let's make sure of it. */
*walk_subtrees = false; *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))) 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; for (tree list = TREE_VALUE (attributes); list;
list = TREE_CHAIN (list)) list = TREE_CHAIN (list))
{ {
tree tag = TREE_VALUE (list); tree tag = TREE_VALUE (list);
tree id = get_identifier (TREE_STRING_POINTER (tag)); check_tag (tag, tp, p);
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);
}
}
}
} }
} }
return NULL_TREE; return NULL_TREE;
@ -1427,6 +1455,12 @@ find_abi_tags_r (tree *tp, int *walk_subtrees, void *data)
static void static void
mark_type_abi_tags (tree t, bool val) 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)); tree attributes = lookup_attribute ("abi_tag", TYPE_ATTRIBUTES (t));
if (attributes) if (attributes)
{ {

View File

@ -151,6 +151,7 @@ c-common.h, not after.
DECL_MUTABLE_P (in FIELD_DECL) DECL_MUTABLE_P (in FIELD_DECL)
DECL_DEPENDENT_P (in USING_DECL) DECL_DEPENDENT_P (in USING_DECL)
LABEL_DECL_BREAK (in LABEL_DECL) LABEL_DECL_BREAK (in LABEL_DECL)
NAMESPACE_ABI_TAG (in NAMESPACE_DECL)
1: C_TYPEDEF_EXPLICITLY_SIGNED (in TYPE_DECL). 1: C_TYPEDEF_EXPLICITLY_SIGNED (in TYPE_DECL).
DECL_TEMPLATE_INSTANTIATED (in a VAR_DECL or a FUNCTION_DECL) DECL_TEMPLATE_INSTANTIATED (in a VAR_DECL or a FUNCTION_DECL)
DECL_MEMBER_TEMPLATE_P (in TEMPLATE_DECL) DECL_MEMBER_TEMPLATE_P (in TEMPLATE_DECL)
@ -2642,6 +2643,11 @@ struct GTY(()) lang_decl {
#define LOCAL_CLASS_P(NODE) \ #define LOCAL_CLASS_P(NODE) \
(decl_function_context (TYPE_MAIN_DECL (NODE)) != NULL_TREE) (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 /* For a NAMESPACE_DECL: the list of using namespace directives
The PURPOSE is the used namespace, the value is the namespace The PURPOSE is the used namespace, the value is the namespace
that is the common ancestor. */ that is the common ancestor. */

View File

@ -3610,10 +3610,8 @@ current_decl_namespace (void)
return result; return result;
} }
/* Process any ATTRIBUTES on a namespace definition. Currently only /* Process any ATTRIBUTES on a namespace definition. Returns true if
attribute visibility is meaningful, which is a property of the syntactic attribute visibility is seen. */
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. */
bool bool
handle_namespace_attrs (tree ns, tree attributes) handle_namespace_attrs (tree ns, tree attributes)
@ -3628,6 +3626,9 @@ handle_namespace_attrs (tree ns, tree attributes)
if (is_attribute_p ("visibility", name)) 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; tree x = args ? TREE_VALUE (args) : NULL_TREE;
if (x == NULL_TREE || TREE_CODE (x) != STRING_CST || TREE_CHAIN (args)) 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); push_visibility (TREE_STRING_POINTER (x), 1);
saw_vis = true; saw_vis = true;
} }
else if (is_attribute_p ("abi_tag", name))
{
NAMESPACE_ABI_TAG (ns) = true;
}
else else
{ {
warning (OPT_Wattributes, "%qD attribute directive ignored", warning (OPT_Wattributes, "%qD attribute directive ignored",

View File

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