https://gcc.gnu.org/g:99b63e4ac7ee06e2f5030b72dc876bf35e9842ca
commit r16-7649-g99b63e4ac7ee06e2f5030b72dc876bf35e9842ca Author: Marek Polacek <[email protected]> Date: Tue Feb 17 17:08:52 2026 -0500 c++/reflection: ICE with missing OVERLOAD [PR124150] A function template is supposed to be wrapped in an OVERLOAD. Since in certain cases like members_of it is not, splice makes sure to add the OVERLOAD if needed. But it wasn't looking into TEMPLATE_ID_EXPRs and so we ended up with a "naked" TEMPLATE_DECL and crashed. We can add the missing OVERLOAD in eval_substitute. PR c++/124150 gcc/cp/ChangeLog: * reflect.cc (eval_substitute): Add an OVERLOAD around a DECL_FUNCTION_TEMPLATE_P. gcc/testsuite/ChangeLog: * g++.dg/reflect/substitute4.C: New test. Reviewed-by: Jason Merrill <[email protected]> Diff: --- gcc/cp/reflect.cc | 6 ++- gcc/testsuite/g++.dg/reflect/substitute4.C | 68 ++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc index a80f7ca0a141..522b7c06a293 100644 --- a/gcc/cp/reflect.cc +++ b/gcc/cp/reflect.cc @@ -5394,7 +5394,11 @@ eval_substitute (location_t loc, const constexpr_ctx *ctx, ret = finish_template_variable (ret, tf_none); } else - ret = lookup_template_function (r, rvec); + { + if (DECL_FUNCTION_TEMPLATE_P (r)) + r = ovl_make (r, NULL_TREE); + ret = lookup_template_function (r, rvec); + } return get_reflection_raw (loc, ret); } diff --git a/gcc/testsuite/g++.dg/reflect/substitute4.C b/gcc/testsuite/g++.dg/reflect/substitute4.C new file mode 100644 index 000000000000..ff9cd403e4b9 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/substitute4.C @@ -0,0 +1,68 @@ +// PR c++/124150 +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } + +#include <meta> +using namespace std; + +template <typename T> +consteval meta::info find_non_static_template_function() { + for (auto r : meta::members_of(^^T, meta::access_context::current())) { + if (meta::identifier_of(r) == "non_static_function") { + return r; + } + } + return ^^void; +} +template <typename T> +consteval meta::info find_static_template_member_func() { + for (auto r : meta::members_of(^^T, meta::access_context::current())) { + if (meta::identifier_of(r) == "static_function") { + return r; + } + } + return ^^void; +} +template <typename T> +consteval meta::info find_non_template_member_func() { + for (auto r : meta::members_of(^^T, meta::access_context::current())) { + if (meta::identifier_of(r) == "non_template_member_func") { + return r; + } + } + return ^^void; +} + +template <typename T, typename Ts, meta::info static_func, meta::info non_static_func, + meta::info non_template_func> +void call_member_template_functions(Ts* ptr) { + [:substitute(static_func, {^^T}):](); + ptr->[:substitute(non_static_func, {^^T}):](); + ptr->[:non_template_func:](); +} + +struct A { + template <typename T> + static void static_function() { } + template <typename T> + void non_static_function() { } + void non_template_member_func() { } +}; + +template <typename T, meta::info r> +void call_non_member_template_function() { + [:meta::substitute(r, {^^T}):](); +} + +template <typename T> +void non_member_template_function() { } + +int +main () +{ + A a; + call_member_template_functions<int, A, find_static_template_member_func<A>(), + find_non_static_template_function<A>(), + find_non_template_member_func<A>()>(&a); + call_non_member_template_function<int, ^^non_member_template_function>(); +}
