On 03/31/2014 02:49 PM, Jason Merrill wrote:
This bug report pointed out that we weren't properly decorating template
mangled names with the appropriate abi_tags.  This patch fixes this by
making sure that the mangler only looks at the abi_tag from the
template, and the parser warns that we'll ignore tags on specializations
and instantiations.  This means a change of mangling in abi-tag3.C, but
this is necessary to handle incomplete types properly; we need to be
able to name the type without requiring it to be defined.

After sending this mail it occurred to me that we want to warn about trying to attach a tag to an instantiation or specialization, so this patch does that, and only looks at the template for ABI tags.

Tested x86_64-pc-linux-gnu, applying to trunk.


commit cd57276dfd0e397ec5d3033ff24ca6c0a6afe8ae
Author: Jason Merrill <ja...@redhat.com>
Date:   Wed Mar 26 16:19:32 2014 -0400

    	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.

diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index dfc532d..6c52e53 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 251edb1..da82dd6 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 c791d03..bfb49d7 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 5567253..3429d23 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 f9114ab..2c84e40 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 05fd58e..13cb3c2 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<typename T>
@@ -12,12 +11,12 @@ struct __attribute ((abi_tag("cxx11"))) Foo
 template<>
 struct
 __attribute ((abi_tag("cxx11")))
-Foo<int>
+Foo<int>			// { dg-warning "attribute" }
 {
   int f();
 };
 
-// { dg-final { scan-assembler "_ZN3FooIdE1fEv" } }
+// { dg-final { scan-assembler "_ZN3FooB5cxx11IdE1fEv" } }
 template<>
 struct
 Foo<double>
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 0000000..94ea2f3
--- /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<typename>
+struct __attribute((abi_tag("test"))) bar
+{
+  void f();
+  virtual ~bar();
+};
+
+int main()
+{
+  foo f;
+  f.f();
+
+  bar<int> 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 0000000..4c47725
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/abi-tag7.C
@@ -0,0 +1,9 @@
+// PR c++/60642
+
+template<typename T>
+class __attribute((abi_tag("foo"))) test{  };
+
+template class __attribute((abi_tag("foo"))) test<int>; // { dg-warning "attribute" }
+
+void f(test<char>*) {}
+// { dg-final { scan-assembler "_Z1fP4testB3fooIcE" } }

Reply via email to