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>();