diff mbox

C++ PATCH for c++/60642 (abi_tag and templates)

Message ID 533AFC26.30701@redhat.com
State New
Headers show

Commit Message

Jason Merrill April 1, 2014, 5:49 p.m. UTC
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.
diff mbox

Patch

commit cd57276dfd0e397ec5d3033ff24ca6c0a6afe8ae
Author: Jason Merrill <jason@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" } }