Example from StackOverflow (https://stackoverflow.com/q/47606810/2069064): template<void(*)()> struct A{}; int main() { constexpr auto fp = +[]{}; A<fp>{}; } As of N4268, this should be accepted (linkage is no longer a requirement), but gcc rejects with: prog.cc: In function 'int main()': prog.cc:6:9: error: 'main()::<lambda()>::_FUN' is not a valid template argument for type 'void (*)()' because 'static constexpr void main()::<lambda()>::_FUN()' has no linkage A<fp>{}; ^
*** Bug 84981 has been marked as a duplicate of this bug. ***
With this patch: --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -6259,7 +6259,8 @@ convert_nontype_argument_function (tree type, tree expr, } linkage = decl_linkage (fn_no_ptr); - if (cxx_dialect >= cxx11 ? linkage == lk_none : linkage != lk_external) + if ((cxx_dialect < cxx11 && linkage != lk_external) + || (cxx_dialect < cxx17 && linkage == lk_none)) { if (complain & tf_error) { We accept Barry's testcase in C++17 mode. I think we also need this for some non-type arguments without linkage: @@ -6979,7 +6980,8 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) /* DR 1155 allows internal linkage in C++11 and up. */ linkage_kind linkage = decl_linkage (expr); - if (linkage < (cxx_dialect >= cxx11 ? lk_internal : lk_external)) + if ((cxx_dialect < cxx11 && linkage < lk_external) + || (cxx_dialect < cxx17 && linkage < lk_internal)) { if (complain & tf_error) error ("%qE is not a valid template argument for type %qT " but that second change causes a new ice-on-invalid for this in C++17 mode (but seems to correctly compile it when VALID is defined): template <typename T, const T &val> struct TestClass { TestClass() : _val(val) { } T _val; }; extern constexpr float e = 2.72; // external linkage static constexpr float pi = 3.14; // internal linkage int main() { #ifdef VALID static #endif constexpr float one = 1; // no linkage TestClass<float, e> test1; TestClass<float, pi> test2; TestClass<float, one> test3; } linkage.cc: In constructor 'TestClass<T, val>::TestClass() [with T = float; const T& val = one]': linkage.cc:3:3: error: Local declaration from a different function TestClass() : _val(val) { } ^~~~~~~~~ one linkage.cc:3:25: note: in statement TestClass() : _val(val) { } ^ one.2_1 = one; during GIMPLE pass: cfg linkage.cc:3:3: internal compiler error: verify_gimple failed TestClass() : _val(val) { } ^~~~~~~~~ 0xdfad0d verify_gimple_in_cfg(function*, bool) /home/jwakely/src/gcc/gcc/gcc/tree-cfg.c:5579 0xcc6956 execute_function_todo /home/jwakely/src/gcc/gcc/gcc/passes.c:1994 0xcc79d2 execute_todo /home/jwakely/src/gcc/gcc/gcc/passes.c:2048 Please submit a full bug report, with preprocessed source if appropriate. Please include the complete backtrace with any bug report. See <https://gcc.gnu.org/bugs/> for instructions.
*** Bug 85589 has been marked as a duplicate of this bug. ***
Testcase from Bug 85589: template<auto& v> struct foo {}; int main() { static auto v = "str"; (void) foo<v> {}; }
As an anti-example, making the client a template works: template<void(*)()> struct A{}; template<int=0> void f() { constexpr auto fp = +[]{}; A<fp>{}; } int main() { f(); }
*** Bug 92320 has been marked as a duplicate of this bug. ***
My example in Comment #5 works in 9.2 but not in (Compiler Explorer's) trunk.
Still failing in 10.2 (original reproducer).
I think Bug 97700 is also a duplicate of this.
Another workaround, extended from Bug 92320's example. See https://godbolt.org/z/69onWf. You can wrap the closure object in a template function which itself invokes the closure object and converts to a function pointer that GCC accepts. ```C++ template<auto V> void templ() {} void dummy(){} template<auto F> void fn(){F();} void foo() { constexpr int a = 7 + 3; templ<a>(); templ<dummy>(); typedef void(FPtr)(); constexpr FPtr * b = &dummy; templ<b>(); constexpr auto l = []{}; constexpr void (*d)()=fn<l>; templ<d>(); constexpr FPtr * c = [](){}; templ<c>(); } ```
(In reply to Jonathan Wakely from comment #4) > Testcase from Bug 85589: > > template<auto& v> struct foo {}; > > int main() { > static auto v = "str"; > (void) foo<v> {}; > } Note comment #4 is already fixed (I reopened PR 85589 to close it was fixed [or as a dup if I can find one]). The rest of the testcases still fail on the trunk.
(In reply to Johel Ernesto Guerrero Peña from comment #9) > I think Bug 97700 is also a duplicate of this. Well, it seems related enough, at least...
The master branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>: https://gcc.gnu.org/g:c3afdb8ba8f1839544c414f57e41a58c8fda5349 commit r14-708-gc3afdb8ba8f1839544c414f57e41a58c8fda5349 Author: Patrick Palka <ppalka@redhat.com> Date: Thu May 11 10:04:25 2023 -0400 c++: converted lambda as template argument [PR83258, ...] r8-1253-g3d2e25a240c711 removed the template argument linkage requirement in convert_nontype_argument for C++17 (which r9-3836-g4be5c72cf3ea3e later factored out into invalid_tparm_referent_p), but we need to also remove the one in convert_nontype_argument_function for benefit of the first and third testcase which we currently reject even in C++17/20 mode. And in invalid_tparm_referent_p we're inadvertendly returning false for the address of a lambda's static op() since it's DECL_ARTIFICIAL, which currently causes us to reject the second (C++20) testcase. But this DECL_ARTIFICIAL check seems to be relevant only for VAR_DECL, and in fact this code path was originally reachable only for VAR_DECL until recently (r13-6970-gb5e38b1c166357). So this patch restricts the check to VAR_DECL. Co-authored-by: Jonathan Wakely <jwakely@redhat.com> PR c++/83258 PR c++/80488 PR c++/97700 gcc/cp/ChangeLog: * pt.cc (convert_nontype_argument_function): Remove linkage requirement for C++17 and later. (invalid_tparm_referent_p) <case ADDR_EXPR>: Restrict DECL_ARTIFICIAL rejection test to VAR_DECL. gcc/testsuite/ChangeLog: * g++.dg/ext/visibility/anon8.C: Don't expect a "no linkage" error for the template argument &B2:fn in C++17 mode. * g++.dg/cpp0x/lambda/lambda-conv15.C: New test. * g++.dg/cpp2a/nontype-class56.C: New test. * g++.dg/template/function2.C: New test.
Fixed on trunk so far.
The master branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>: https://gcc.gnu.org/g:10098788ff61467f5a499f01c5443fb53ff564dd commit r14-787-g10098788ff61467f5a499f01c5443fb53ff564dd Author: Patrick Palka <ppalka@redhat.com> Date: Fri May 12 08:37:54 2023 -0400 c++: remove redundant testcase [PR83258] I noticed only after the fact that the new testcase template/function2.C (from r14-708-gc3afdb8ba8f183) is just a subset of ext/visibility/anon8.C, so let's get rid of it. PR c++/83258 gcc/testsuite/ChangeLog: * g++.dg/ext/visibility/anon8.C: Mention PR83258. * g++.dg/template/function2.C: Removed.
The releases/gcc-13 branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>: https://gcc.gnu.org/g:42f9b481be3527b336b800128247d053fd18d121 commit r13-7324-g42f9b481be3527b336b800128247d053fd18d121 Author: Patrick Palka <ppalka@redhat.com> Date: Thu May 11 10:04:25 2023 -0400 c++: converted lambda as template argument [PR83258, ...] r8-1253-g3d2e25a240c711 removed the template argument linkage requirement in convert_nontype_argument for C++17 (which r9-3836-g4be5c72cf3ea3e later factored out into invalid_tparm_referent_p), but we need to also remove the one in convert_nontype_argument_function for benefit of the first and third testcase which we currently reject even in C++17/20 mode. And in invalid_tparm_referent_p we're inadvertendly returning false for the address of a lambda's static op() since it's DECL_ARTIFICIAL, which currently causes us to reject the second (C++20) testcase. But this DECL_ARTIFICIAL check seems to be relevant only for VAR_DECL, and in fact this code path was originally reachable only for VAR_DECL until recently (r13-6970-gb5e38b1c166357). So this patch restricts the check to VAR_DECL. Co-authored-by: Jonathan Wakely <jwakely@redhat.com> PR c++/83258 PR c++/80488 PR c++/97700 gcc/cp/ChangeLog: * pt.cc (convert_nontype_argument_function): Remove linkage requirement for C++17 and later. (invalid_tparm_referent_p) <case ADDR_EXPR>: Restrict DECL_ARTIFICIAL rejection test to VAR_DECL. gcc/testsuite/ChangeLog: * g++.dg/ext/visibility/anon8.C: Don't expect a "no linkage" error for the template argument &B2:fn in C++17 mode. * g++.dg/cpp0x/lambda/lambda-conv15.C: New test. * g++.dg/cpp2a/nontype-class56.C: New test. * g++.dg/template/function2.C: New test. (cherry picked from commit c3afdb8ba8f1839544c414f57e41a58c8fda5349)
The releases/gcc-13 branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>: https://gcc.gnu.org/g:20b1e1d8a79356e03f50f53e2fa02b376d56d7d7 commit r13-7327-g20b1e1d8a79356e03f50f53e2fa02b376d56d7d7 Author: Patrick Palka <ppalka@redhat.com> Date: Fri May 12 08:37:54 2023 -0400 c++: remove redundant testcase [PR83258] I noticed only after the fact that the new testcase template/function2.C (from r14-708-gc3afdb8ba8f183) is just a subset of ext/visibility/anon8.C, so let's get rid of it. PR c++/83258 gcc/testsuite/ChangeLog: * g++.dg/ext/visibility/anon8.C: Mention PR83258. * g++.dg/template/function2.C: Removed. (cherry picked from commit 10098788ff61467f5a499f01c5443fb53ff564dd)
Fixed for GCC 13.2