DECL_VISIBILITY_SPECIFIED is set if the decl occurs after a #pragma visibility or within a namespace with explicit visibility. In these cases, we want the visibility of template arguments to be able to further restrict the visibility of template specializations. But if the specialization itself has explicitly specified visibility, we should respect that.

This patch will also mean that an attribute on the template will override argument visibility, which I could go either way on. But if this is a problem for users they can use a pragma instead.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit e3f4b4e6d7c54ec96c77aa3e36fe9d38b7922391
Author: Jason Merrill <ja...@redhat.com>
Date:   Mon Jan 23 14:31:23 2012 -0500

    	PR c++/51930
    	* decl2.c (determine_visibility): Check for visibility attribute
    	on template specialization.

diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index f51790c..bdc962a 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -2177,8 +2177,14 @@ determine_visibility (tree decl)
 		    ? TYPE_TEMPLATE_INFO (TREE_TYPE (decl))
 		    : DECL_TEMPLATE_INFO (decl));
       tree args = TI_ARGS (tinfo);
+      tree attribs = (TREE_CODE (decl) == TYPE_DECL
+		      ? TYPE_ATTRIBUTES (TREE_TYPE (decl))
+		      : DECL_ATTRIBUTES (decl));
       
-      if (args != error_mark_node)
+      if (args != error_mark_node
+	  /* Template argument visibility outweighs #pragma or namespace
+	     visibility, but not an explicit attribute.  */
+	  && !lookup_attribute ("visibility", attribs))
 	{
 	  int depth = TMPL_ARGS_DEPTH (args);
 	  tree pattern = DECL_TEMPLATE_RESULT (TI_TEMPLATE (tinfo));
diff --git a/gcc/testsuite/g++.dg/ext/visibility/template10.C b/gcc/testsuite/g++.dg/ext/visibility/template10.C
new file mode 100644
index 0000000..01108aa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/visibility/template10.C
@@ -0,0 +1,16 @@
+// PR c++/51930
+// { dg-require-visibility }
+// { dg-options -fvisibility=hidden }
+// { dg-final { scan-not-hidden "_Z8testfuncI3fooEvv" } }
+
+struct foo { };
+
+template<typename T>
+__attribute__ ((visibility("default")))
+void testfunc();
+
+template<typename T> void testfunc() { }
+
+template
+__attribute__ ((visibility("default")))
+void testfunc<foo>();

Reply via email to