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

Reply via email to