diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 553a05976cf..72e28aa391b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,13 @@ +2014-04-01 Jason Merrill + + PR c++/60642 + * decl2.c (is_late_template_attribute): Don't defer abi_tag. + * mangle.c (write_unqualified_name): Fix abi_tag on templates. + * pt.c (get_template_info): Handle NAMESPACE_DECL. + (most_general_template): Handle more kinds of template. + * tree.c (handle_abi_tag_attribute): Ignore abi_tag on template + instantiations and specializations. + 2014-03-31 Patrick Palka patrick@parcs.ath.cx PR c++/44859 diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index dfc532d5b0e..6c52e53bca0 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1169,8 +1169,9 @@ is_late_template_attribute (tree attr, tree decl) /* Also defer most attributes on dependent types. This is not necessary in all cases, but is the better default. */ else if (dependent_type_p (type) - /* But attribute visibility specifically works on - templates. */ + /* But attributes abi_tag and visibility specifically apply + to templates. */ + && !is_attribute_p ("abi_tag", name) && !is_attribute_p ("visibility", name)) return true; else diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 251edb14d16..da82dd6acda 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -180,7 +180,7 @@ static void write_unscoped_template_name (const tree); static void write_nested_name (const tree); static void write_prefix (const tree); static void write_template_prefix (const tree); -static void write_unqualified_name (const tree); +static void write_unqualified_name (tree); static void write_conversion_operator_name (const tree); static void write_source_name (tree); static void write_literal_operator_name (tree); @@ -1195,7 +1195,7 @@ write_unqualified_id (tree identifier) } static void -write_unqualified_name (const tree decl) +write_unqualified_name (tree decl) { MANGLE_TRACE_TREE ("unqualified-name", decl); @@ -1280,10 +1280,21 @@ write_unqualified_name (const tree decl) 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)); + /* We use the ABI tags from the primary template, ignoring tags on any + specializations. This is necessary because C++ doesn't require a + specialization to be declared before it is used unless the use + requires a complete type, but we need to get the tags right on + incomplete types as well. */ + if (tree tmpl = most_general_template (decl)) + decl = DECL_TEMPLATE_RESULT (tmpl); + /* Don't crash on an unbound class template. */ + if (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. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index c791d031ae1..bfb49d7f824 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -320,6 +320,9 @@ get_template_info (const_tree t) if (!t || t == error_mark_node) return NULL; + if (TREE_CODE (t) == NAMESPACE_DECL) + return NULL; + if (DECL_P (t) && DECL_LANG_SPECIFIC (t)) tinfo = DECL_TEMPLATE_INFO (t); @@ -18758,23 +18761,18 @@ most_specialized_instantiation (tree templates) tree most_general_template (tree decl) { - /* If DECL is a FUNCTION_DECL, find the TEMPLATE_DECL of which it is - an immediate specialization. */ - if (TREE_CODE (decl) == FUNCTION_DECL) + if (TREE_CODE (decl) != TEMPLATE_DECL) { - if (DECL_TEMPLATE_INFO (decl)) { - decl = DECL_TI_TEMPLATE (decl); - - /* The DECL_TI_TEMPLATE can be an IDENTIFIER_NODE for a - template friend. */ - if (TREE_CODE (decl) != TEMPLATE_DECL) - return NULL_TREE; - } else + if (tree tinfo = get_template_info (decl)) + decl = TI_TEMPLATE (tinfo); + /* The TI_TEMPLATE can be an IDENTIFIER_NODE for a + template friend, or a FIELD_DECL for a capture pack. */ + if (TREE_CODE (decl) != TEMPLATE_DECL) return NULL_TREE; } /* Look for more and more general templates. */ - while (DECL_TEMPLATE_INFO (decl)) + while (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)) { /* The DECL_TI_TEMPLATE can be an IDENTIFIER_NODE in some cases. (See cp-tree.h for details.) */ diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 5567253a61a..3429d2396f2 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -3364,6 +3364,18 @@ handle_abi_tag_attribute (tree* node, tree name, tree args, name, *node); goto fail; } + else if (CLASSTYPE_TEMPLATE_INSTANTIATION (*node)) + { + warning (OPT_Wattributes, "ignoring %qE attribute applied to " + "template instantiation %qT", name, *node); + goto fail; + } + else if (CLASSTYPE_TEMPLATE_SPECIALIZATION (*node)) + { + warning (OPT_Wattributes, "ignoring %qE attribute applied to " + "template specialization %qT", name, *node); + goto fail; + } tree attributes = TYPE_ATTRIBUTES (*node); tree decl = TYPE_NAME (*node); diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index f9114ab0744..2c84e407995 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -17542,6 +17542,10 @@ unimportant. A redeclaration of a function or class must not add new ABI tags, since doing so would change the mangled name. +The ABI tags apply to a name, so all instantiations and +specializations of a template have the same tags. The attribute will +be ignored if applied to an explicit specialization or instantiation. + The @option{-Wabi-tag} flag enables a warning about a class which does not have all the ABI tags used by its subobjects and virtual functions; for users with code that needs to coexist with an earlier ABI, using this option can help diff --git a/gcc/testsuite/g++.dg/abi/abi-tag3.C b/gcc/testsuite/g++.dg/abi/abi-tag3.C index 05fd58e9402..13cb3c2f2e9 100644 --- a/gcc/testsuite/g++.dg/abi/abi-tag3.C +++ b/gcc/testsuite/g++.dg/abi/abi-tag3.C @@ -1,5 +1,4 @@ -// An explicit specialization doesn't get the tag from its template unless -// it is specified there, too. +// An explicit specialization gets the tag from its template. // { dg-final { scan-assembler "_ZN3FooB5cxx11IcE1fEv" } } template @@ -12,12 +11,12 @@ struct __attribute ((abi_tag("cxx11"))) Foo template<> struct __attribute ((abi_tag("cxx11"))) -Foo +Foo // { dg-warning "attribute" } { int f(); }; -// { dg-final { scan-assembler "_ZN3FooIdE1fEv" } } +// { dg-final { scan-assembler "_ZN3FooB5cxx11IdE1fEv" } } template<> struct Foo diff --git a/gcc/testsuite/g++.dg/abi/abi-tag6.C b/gcc/testsuite/g++.dg/abi/abi-tag6.C new file mode 100644 index 00000000000..94ea2f37b6b --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/abi-tag6.C @@ -0,0 +1,25 @@ +// PR c++/60642 + +struct __attribute((abi_tag("test"))) foo +{ + void f(); + virtual ~foo(); +}; + +template +struct __attribute((abi_tag("test"))) bar +{ + void f(); + virtual ~bar(); +}; + +int main() +{ + foo f; + f.f(); + + bar b; + b.f(); +} + +// { dg-final { scan-assembler "_ZTV3barB4testIiE" } } diff --git a/gcc/testsuite/g++.dg/abi/abi-tag7.C b/gcc/testsuite/g++.dg/abi/abi-tag7.C new file mode 100644 index 00000000000..4c47725c536 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/abi-tag7.C @@ -0,0 +1,9 @@ +// PR c++/60642 + +template +class __attribute((abi_tag("foo"))) test{ }; + +template class __attribute((abi_tag("foo"))) test; // { dg-warning "attribute" } + +void f(test*) {} +// { dg-final { scan-assembler "_Z1fP4testB3fooIcE" } }