DR 1155 allows variables and functions with internal linkage to be used
as template arguments.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit bd15c5ecefbb9f8a3a44d2547c3a6a9881a47f31
Author: Jason Merrill <ja...@redhat.com>
Date: Thu Nov 10 21:59:59 2011 -0500
PR c++/50372
* pt.c (convert_nontype_argument_function): Allow functions with
internal linkage in C++11.
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index da5497e..9ce7854 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -5324,6 +5324,7 @@ convert_nontype_argument_function (tree type, tree expr)
{
tree fns = expr;
tree fn, fn_no_ptr;
+ linkage_kind linkage;
fn = instantiate_type (type, fns, tf_none);
if (fn == error_mark_node)
@@ -5340,12 +5341,19 @@ convert_nontype_argument_function (tree type, tree expr)
A template-argument for a non-type, non-template template-parameter
shall be one of:
[...]
- -- the address of an object or function with external linkage. */
- if (!DECL_EXTERNAL_LINKAGE_P (fn_no_ptr))
+ -- the address of an object or function with external [C++11: or
+ internal] linkage. */
+ linkage = decl_linkage (fn_no_ptr);
+ if (cxx_dialect >= cxx0x ? linkage == lk_none : linkage != lk_external)
{
- error ("%qE is not a valid template argument for type %qT "
- "because function %qD has not external linkage",
- expr, type, fn_no_ptr);
+ if (cxx_dialect >= cxx0x)
+ error ("%qE is not a valid template argument for type %qT "
+ "because function %qD has no linkage",
+ expr, type, fn_no_ptr);
+ else
+ error ("%qE is not a valid template argument for type %qT "
+ "because function %qD doesn't have external linkage",
+ expr, type, fn_no_ptr);
return NULL_TREE;
}
diff --git a/gcc/testsuite/g++.dg/ext/visibility/anon8.C b/gcc/testsuite/g++.dg/ext/visibility/anon8.C
index 8ef8d68..5e58b55 100644
--- a/gcc/testsuite/g++.dg/ext/visibility/anon8.C
+++ b/gcc/testsuite/g++.dg/ext/visibility/anon8.C
@@ -26,10 +26,8 @@ int main ()
static void fn2 () {}
};
call<&B1::fn1> ();
- call<&B2::fn2> (); // { dg-error "not external linkage|no matching" }
- // { dg-message "candidate" "candidate note" { target *-*-* } 29 }
+ call<&B2::fn2> (); // { dg-error "linkage|no matching" }
call<&fn3> ();
call<&B1::fn4> ();
- call<&fn5> (); // { dg-error "not external linkage|no matching" }
- // { dg-message "candidate" "candidate note" { target *-*-* } 33 }
+ call<&fn5> (); // { dg-error "linkage|no matching" "" { target c++98 } }
}
diff --git a/gcc/testsuite/g++.dg/template/linkage1.C b/gcc/testsuite/g++.dg/template/linkage1.C
new file mode 100644
index 0000000..02aa967
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/linkage1.C
@@ -0,0 +1,18 @@
+// PR c++/50372
+// Test that a template instantiation has the same linkage as its argument.
+// { dg-final { scan-assembler "(weak|glob)\[^\n\]*_Z3fooIXadL_Z13external_funcvEEEvv" } }
+// { dg-final { scan-assembler-not "(weak|glob)\[^\n\]*_Z3fooIXadL_ZL11static_funcvEEEvv" } }
+
+template<void (*fptr)(void)>
+void foo() { }
+
+static void static_func() {}
+void external_func() { }
+
+void test()
+{
+#if __cplusplus > 199711L
+ foo<&static_func>();
+#endif
+ foo<&external_func>();
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.other/linkage4.C b/gcc/testsuite/g++.old-deja/g++.other/linkage4.C
index 7531f45..450733f 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/linkage4.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/linkage4.C
@@ -8,4 +8,4 @@ void f () {}
// Check that the strlen declaration here is given internal linkage by
// using it as a non-type template argument, and expecting an error.
-template void f<strlen>(); // { dg-error "" } no matching template
+template void f<strlen>(); // { dg-error "" "" { target c++98 } } no matching template