Commit 7dbb85a7 by Jason Merrill Committed by Jason Merrill

Add C++ attribute abi_tag and -Wabi-tag option.

gcc/
	* attribs.c (lookup_attribute_spec): Handle getting a TREE_LIST.
gcc/c-family/
	* c.opt (Wabi-tag): New.
gcc/cp/
	* tree.c (cxx_attribute_table): Add abi_tag attribute.
	(check_abi_tag_redeclaration, handle_abi_tag_attribute): New.
	* class.c (find_abi_tags_r, check_abi_tags): New.
	(check_bases, check_field_decl): Call check_abi_tags.
	* decl.c (redeclaration_error_message): Call
	check_abi_tag_redeclaration.
	* mangle.c (tree_string_cmp, write_abi_tags): New.
	(write_unqualified_name): Call write_abi_tags.
include/
	* demangle.h (enum demangle_component_type): Add
	DEMANGLE_COMPONENT_TAGGED_NAME.
libiberty/
	* cp-demangle.c (d_dump): Handle DEMANGLE_COMPONENT_TAGGED_NAME.
	(d_make_comp, d_find_pack, d_print_comp): Likewise.
	(d_abi_tags): New.
	(d_name): Call it.

From-SVN: r193367
parent 52dccf7a
2012-11-09 Jason Merrill <jason@redhat.com>
* attribs.c (lookup_attribute_spec): Handle getting a TREE_LIST.
2012-11-09 Vladimir Makarov <vmakarov@redhat.com>
PR tree-optimization/55154
......@@ -325,12 +325,21 @@ lookup_scoped_attribute_spec (const_tree ns, const_tree name)
substring_hash (attr.str, attr.length));
}
/* Return the spec for the attribute named NAME. */
/* Return the spec for the attribute named NAME. If NAME is a TREE_LIST,
it also specifies the attribute namespace. */
const struct attribute_spec *
lookup_attribute_spec (const_tree name)
{
return lookup_scoped_attribute_spec (get_identifier ("gnu"), name);
tree ns;
if (TREE_CODE (name) == TREE_LIST)
{
ns = TREE_PURPOSE (name);
name = TREE_VALUE (name);
}
else
ns = get_identifier ("gnu");
return lookup_scoped_attribute_spec (ns, name);
}
......
2012-11-09 Jason Merrill <jason@redhat.com>
* c.opt (Wabi-tag): New.
2012-11-09 Andi Kleen <ak@linux.intel.com>
PR 55139
......
......@@ -257,6 +257,10 @@ Wabi
C ObjC C++ ObjC++ LTO Var(warn_abi) Warning
Warn about things that will change when compiling with an ABI-compliant compiler
Wabi-tag
C++ ObjC++ Var(warn_abi_tag) Warning
Warn if a subobject has an abi_tag attribute that the complete object type does not have
Wpsabi
C ObjC C++ ObjC++ LTO Var(warn_psabi) Init(1) Undocumented
......
2012-11-09 Jason Merrill <jason@redhat.com>
* tree.c (cxx_attribute_table): Add abi_tag attribute.
(check_abi_tag_redeclaration, handle_abi_tag_attribute): New.
* class.c (find_abi_tags_r, check_abi_tags): New.
(check_bases, check_field_decl): Call check_abi_tags.
* decl.c (redeclaration_error_message): Call
check_abi_tag_redeclaration.
* mangle.c (tree_string_cmp, write_abi_tags): New.
(write_unqualified_name): Call write_abi_tags.
2012-11-07 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/55226
......
......@@ -1302,6 +1302,89 @@ handle_using_decl (tree using_decl, tree t)
alter_access (t, decl, access);
}
/* 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;
};
static tree
find_abi_tags_r (tree *tp, int */*walk_subtrees*/, void *data)
{
if (!TAGGED_TYPE_P (*tp))
return NULL_TREE;
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 (TYPE_P (p->subob))
{
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
{
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;
}
/* Check that class T has all the abi tags that subobject SUBOB has, or
warn if not. */
static void
check_abi_tags (tree t, tree subob)
{
tree attributes = lookup_attribute ("abi_tag", TYPE_ATTRIBUTES (t));
if (attributes)
{
for (tree list = TREE_VALUE (attributes); list;
list = TREE_CHAIN (list))
{
tree tag = TREE_VALUE (list);
tree id = get_identifier (TREE_STRING_POINTER (tag));
IDENTIFIER_MARKED (id) = true;
}
}
tree subtype = TYPE_P (subob) ? subob : TREE_TYPE (subob);
struct abi_tag_data data = { t, subob };
cp_walk_tree_without_duplicates (&subtype, find_abi_tags_r, &data);
if (attributes)
{
for (tree list = TREE_VALUE (attributes); list;
list = TREE_CHAIN (list))
{
tree tag = TREE_VALUE (list);
tree id = get_identifier (TREE_STRING_POINTER (tag));
IDENTIFIER_MARKED (id) = false;
}
}
}
/* Run through the base classes of T, updating CANT_HAVE_CONST_CTOR_P,
and NO_CONST_ASN_REF_P. Also set flag bits in T based on
properties of the bases. */
......@@ -1431,6 +1514,8 @@ check_bases (tree t,
if (tm_attr)
seen_tm_mask |= tm_attr_to_mask (tm_attr);
}
check_abi_tags (t, basetype);
}
/* If one of the base classes had TM attributes, and the current class
......@@ -3147,6 +3232,9 @@ check_field_decl (tree field,
&& !TYPE_HAS_CONST_COPY_ASSIGN (type))
*no_const_asn_ref = 1;
}
check_abi_tags (t, field);
if (DECL_INITIAL (field) != NULL_TREE)
{
/* `build_class_init_list' does not recognize
......
......@@ -5749,6 +5749,7 @@ extern bool type_has_nontrivial_default_init (const_tree);
extern bool type_has_nontrivial_copy_init (const_tree);
extern bool class_tmpl_impl_spec_p (const_tree);
extern int zero_init_p (const_tree);
extern bool check_abi_tag_redeclaration (const_tree, const_tree, const_tree);
extern tree strip_typedefs (tree);
extern tree strip_typedefs_expr (tree);
extern tree copy_binfo (tree, tree, tree,
......
......@@ -2480,6 +2480,10 @@ redeclaration_error_message (tree newdecl, tree olddecl)
}
}
check_abi_tag_redeclaration
(olddecl, lookup_attribute ("abi_tag", DECL_ATTRIBUTES (olddecl)),
lookup_attribute ("abi_tag", DECL_ATTRIBUTES (newdecl)));
return NULL;
}
else if (TREE_CODE (newdecl) == TEMPLATE_DECL)
......
......@@ -173,6 +173,7 @@ static void mangle_call_offset (const tree, const tree);
static void write_mangled_name (const tree, bool);
static void write_encoding (const tree);
static void write_name (tree, const int);
static void write_abi_tags (tree);
static void write_unscoped_name (const tree);
static void write_unscoped_template_name (const tree);
static void write_nested_name (const tree);
......@@ -1192,15 +1193,17 @@ write_unqualified_name (const tree decl)
return;
}
bool found = false;
if (DECL_NAME (decl) == NULL_TREE)
{
found = true;
gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
write_source_name (DECL_ASSEMBLER_NAME (decl));
return;
}
else if (DECL_DECLARES_FUNCTION_P (decl))
{
bool found = true;
found = true;
if (DECL_CONSTRUCTOR_P (decl))
write_special_name_constructor (decl);
else if (DECL_DESTRUCTOR_P (decl))
......@@ -1234,14 +1237,13 @@ write_unqualified_name (const tree decl)
write_literal_operator_name (DECL_NAME (decl));
else
found = false;
if (found)
return;
}
if (VAR_OR_FUNCTION_DECL_P (decl) && ! TREE_PUBLIC (decl)
&& DECL_NAMESPACE_SCOPE_P (decl)
&& decl_linkage (decl) == lk_internal)
if (found)
/* OK */;
else if (VAR_OR_FUNCTION_DECL_P (decl) && ! TREE_PUBLIC (decl)
&& DECL_NAMESPACE_SCOPE_P (decl)
&& decl_linkage (decl) == lk_internal)
{
MANGLE_TRACE_TREE ("local-source-name", decl);
write_char ('L');
......@@ -1262,6 +1264,11 @@ write_unqualified_name (const tree decl)
else
write_source_name (DECL_NAME (decl));
}
tree attrs = (TREE_CODE (decl) == TYPE_DECL
? TYPE_ATTRIBUTES (TREE_TYPE (decl))
: DECL_ATTRIBUTES (decl));
write_abi_tags (lookup_attribute ("abi_tag", attrs));
}
/* Write the unqualified-name for a conversion operator to TYPE. */
......@@ -1291,6 +1298,51 @@ write_source_name (tree identifier)
write_identifier (IDENTIFIER_POINTER (identifier));
}
/* Compare two TREE_STRINGs like strcmp. */
int
tree_string_cmp (const void *p1, const void *p2)
{
if (p1 == p2)
return 0;
tree s1 = *(const tree*)p1;
tree s2 = *(const tree*)p2;
return strcmp (TREE_STRING_POINTER (s1),
TREE_STRING_POINTER (s2));
}
/* ID is the name of a function or type with abi_tags attribute TAGS.
Write out the name, suitably decorated. */
static void
write_abi_tags (tree tags)
{
if (tags == NULL_TREE)
return;
tags = TREE_VALUE (tags);
VEC(tree,gc)* vec = make_tree_vector();
for (tree t = tags; t; t = TREE_CHAIN (t))
{
tree str = TREE_VALUE (t);
VEC_safe_push (tree, gc, vec, str);
}
VEC_qsort (tree, vec, tree_string_cmp);
unsigned i; tree str;
FOR_EACH_VEC_ELT (tree, vec, i, str)
{
write_string ("B");
write_unsigned_number (TREE_STRING_LENGTH (str) - 1);
write_identifier (TREE_STRING_POINTER (str));
}
release_tree_vector (vec);
}
/* Write a user-defined literal operator.
::= li <source-name> # "" <source-name>
IDENTIFIER is an LITERAL_IDENTIFIER_NODE. */
......
......@@ -49,6 +49,7 @@ static tree build_local_temp (tree);
static tree handle_java_interface_attribute (tree *, tree, tree, int, bool *);
static tree handle_com_interface_attribute (tree *, tree, tree, int, bool *);
static tree handle_init_priority_attribute (tree *, tree, tree, int, bool *);
static tree handle_abi_tag_attribute (tree *, tree, tree, int, bool *);
/* If REF is an lvalue, returns the kind of lvalue that REF is.
Otherwise, returns clk_none. */
......@@ -3000,6 +3001,8 @@ const struct attribute_spec cxx_attribute_table[] =
handle_com_interface_attribute, false },
{ "init_priority", 1, 1, true, false, false,
handle_init_priority_attribute, false },
{ "abi_tag", 1, -1, false, false, false,
handle_abi_tag_attribute, true },
{ NULL, 0, 0, false, false, false, NULL, false }
};
......@@ -3131,6 +3134,96 @@ handle_init_priority_attribute (tree* node,
}
}
/* DECL is being redeclared; the old declaration had the abi tags in OLD,
and the new one has the tags in NEW_. Give an error if there are tags
in NEW_ that weren't in OLD. */
bool
check_abi_tag_redeclaration (const_tree decl, const_tree old, const_tree new_)
{
if (old && TREE_CODE (TREE_VALUE (old)) == TREE_LIST)
old = TREE_VALUE (old);
if (new_ && TREE_CODE (TREE_VALUE (new_)) == TREE_LIST)
new_ = TREE_VALUE (new_);
bool err = false;
for (const_tree t = new_; t; t = TREE_CHAIN (t))
{
tree str = TREE_VALUE (t);
for (const_tree in = old; in; in = TREE_CHAIN (in))
{
tree ostr = TREE_VALUE (in);
if (cp_tree_equal (str, ostr))
goto found;
}
error ("redeclaration of %qD adds abi tag %E", decl, str);
err = true;
found:;
}
if (err)
{
inform (DECL_SOURCE_LOCATION (decl), "previous declaration here");
return false;
}
return true;
}
/* Handle an "abi_tag" attribute; arguments as in
struct attribute_spec.handler. */
static tree
handle_abi_tag_attribute (tree* node, tree name, tree args,
int flags, bool* no_add_attrs)
{
if (TYPE_P (*node))
{
if (!TAGGED_TYPE_P (*node))
{
error ("%qE attribute applied to non-class, non-enum type %qT",
name, *node);
goto fail;
}
else if (!(flags & (int)ATTR_FLAG_TYPE_IN_PLACE))
{
error ("%qE attribute applied to %qT after its definition",
name, *node);
goto fail;
}
tree attributes = TYPE_ATTRIBUTES (*node);
tree decl = TYPE_NAME (*node);
/* Make sure all declarations have the same abi tags. */
if (DECL_SOURCE_LOCATION (decl) != input_location)
{
if (!check_abi_tag_redeclaration (decl,
lookup_attribute ("abi_tag",
attributes),
args))
goto fail;
}
}
else
{
if (TREE_CODE (*node) != FUNCTION_DECL)
{
error ("%qE attribute applied to non-function %qD", name, *node);
goto fail;
}
else if (DECL_LANGUAGE (*node) == lang_c)
{
error ("%qE attribute applied to extern \"C\" function %qD",
name, *node);
goto fail;
}
}
return NULL_TREE;
fail:
*no_add_attrs = true;
return NULL_TREE;
}
/* Return a new PTRMEM_CST of the indicated TYPE. The MEMBER is the
thing pointed to by the constant. */
......
......@@ -15598,6 +15598,27 @@ You must specify @option{-Wno-pmf-conversions} to use this extension.
Some attributes only make sense for C++ programs.
@table @code
@item abi_tag ("@var{tag}", ...)
@cindex @code{abi_tag} attribute
The @code{abi_tag} attribute can be applied to a function or class
declaration. It modifies the mangled name of the function or class to
incorporate the tag name, in order to distinguish the function or
class from an earlier version with a different ABI; perhaps the class
has changed size, or the function has a different return type that is
not encoded in the mangled name.
The argument can be a list of strings of arbitrary length. The
strings are sorted on output, so the order of the list is
unimportant.
A redeclaration of a function or class must not add new ABI tags,
since doing so would change the mangled name.
The @option{-Wabi-tag} flag enables a warning about a class which does
not have all the ABI tags used by its subobjects; for users with code
that needs to coexist with an earlier ABI, using this option can help
to find all affected types that need to be tagged.
@item init_priority (@var{priority})
@cindex @code{init_priority} attribute
......
2012-11-09 Jason Merrill <jason@redhat.com>
* g++.dg/abi/abi-tag1.C: New.
* g++.dg/abi/abi-tag2.C: New.
2012-11-09 Vladimir Makarov <vmakarov@redhat.com>
PR rtl-optimization/55154
......
// { dg-options "-Wabi-tag" }
// { dg-final { scan-assembler "_Z1fB3barB3fooi" } }
void f(int) __attribute ((abi_tag ("foo","bar")));
struct __attribute ((abi_tag ("bar"))) A { };
struct B: A { }; // { dg-warning "bar. abi tag" }
struct D { A* ap; }; // { dg-warning "bar. abi tag" }
// { dg-final { scan-assembler "_Z1gB3baz1AB3bar" } }
void g(A) __attribute ((abi_tag ("baz")));
void g(A) __attribute ((abi_tag ("baz")));
int main()
{
f(42);
g(A());
}
void f(int);
void f(int) __attribute ((abi_tag ("foo"))); // { dg-error "adds abi tag" }
struct C;
struct __attribute ((abi_tag ("foo"))) C; // { dg-error "adds abi tag" }
2012-11-09 Jason Merrill <jason@redhat.com>
* demangle.h (enum demangle_component_type): Add
DEMANGLE_COMPONENT_TAGGED_NAME.
2012-10-29 Sterling Augustine <saugustine@google.com>
Cary Coutant <ccoutant@google.com>
......
......@@ -420,6 +420,8 @@ enum demangle_component_type
DEMANGLE_COMPONENT_NONTRANSACTION_CLONE,
/* A pack expansion. */
DEMANGLE_COMPONENT_PACK_EXPANSION,
/* A name with an ABI tag. */
DEMANGLE_COMPONENT_TAGGED_NAME,
/* A cloned function. */
DEMANGLE_COMPONENT_CLONE
};
......
2012-11-09 Jason Merrill <jason@redhat.com>
* cp-demangle.c (d_dump): Handle DEMANGLE_COMPONENT_TAGGED_NAME.
(d_make_comp, d_find_pack, d_print_comp): Likewise.
(d_abi_tags): New.
(d_name): Call it.
2012-10-08 Jason Merrill <jason@redhat.com>
* cp-demangle.c (d_special_name, d_dump): Handle TH and TW.
......
......@@ -508,6 +508,11 @@ d_dump (struct demangle_component *dc, int indent)
case DEMANGLE_COMPONENT_NAME:
printf ("name '%.*s'\n", dc->u.s_name.len, dc->u.s_name.s);
return;
case DEMANGLE_COMPONENT_TAGGED_NAME:
printf ("tagged name\n");
d_dump (dc->u.s_binary.left, indent + 2);
d_dump (dc->u.s_binary.right, indent + 2);
return;
case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
printf ("template parameter %ld\n", dc->u.s_number.number);
return;
......@@ -809,6 +814,7 @@ d_make_comp (struct d_info *di, enum demangle_component_type type,
case DEMANGLE_COMPONENT_QUAL_NAME:
case DEMANGLE_COMPONENT_LOCAL_NAME:
case DEMANGLE_COMPONENT_TYPED_NAME:
case DEMANGLE_COMPONENT_TAGGED_NAME:
case DEMANGLE_COMPONENT_TEMPLATE:
case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
......@@ -1202,6 +1208,23 @@ d_encoding (struct d_info *di, int top_level)
}
}
/* <tagged-name> ::= <name> B <source-name> */
static struct demangle_component *
d_abi_tags (struct d_info *di, struct demangle_component *dc)
{
char peek;
while (peek = d_peek_char (di),
peek == 'B')
{
struct demangle_component *tag;
d_advance (di, 1);
tag = d_source_name (di);
dc = d_make_comp (di, DEMANGLE_COMPONENT_TAGGED_NAME, dc, tag);
}
return dc;
}
/* <name> ::= <nested-name>
::= <unscoped-name>
::= <unscoped-template-name> <template-args>
......@@ -1223,14 +1246,17 @@ d_name (struct d_info *di)
switch (peek)
{
case 'N':
return d_nested_name (di);
dc = d_nested_name (di);
break;
case 'Z':
return d_local_name (di);
dc = d_local_name (di);
break;
case 'L':
case 'U':
return d_unqualified_name (di);
dc = d_unqualified_name (di);
break;
case 'S':
{
......@@ -1272,7 +1298,7 @@ d_name (struct d_info *di)
d_template_args (di));
}
return dc;
break;
}
default:
......@@ -1287,8 +1313,12 @@ d_name (struct d_info *di)
dc = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, dc,
d_template_args (di));
}
return dc;
break;
}
if (d_peek_char (di) == 'B')
dc = d_abi_tags (di, dc);
return dc;
}
/* <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
......@@ -3745,6 +3775,7 @@ d_find_pack (struct d_print_info *dpi,
case DEMANGLE_COMPONENT_LAMBDA:
case DEMANGLE_COMPONENT_NAME:
case DEMANGLE_COMPONENT_TAGGED_NAME:
case DEMANGLE_COMPONENT_OPERATOR:
case DEMANGLE_COMPONENT_BUILTIN_TYPE:
case DEMANGLE_COMPONENT_SUB_STD:
......@@ -3830,6 +3861,13 @@ d_print_comp (struct d_print_info *dpi, int options,
d_print_java_identifier (dpi, dc->u.s_name.s, dc->u.s_name.len);
return;
case DEMANGLE_COMPONENT_TAGGED_NAME:
d_print_comp (dpi, options, d_left (dc));
d_append_string (dpi, "[abi:");
d_print_comp (dpi, options, d_right (dc));
d_append_char (dpi, ']');
return;
case DEMANGLE_COMPONENT_QUAL_NAME:
case DEMANGLE_COMPONENT_LOCAL_NAME:
d_print_comp (dpi, options, d_left (dc));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment