https://gcc.gnu.org/g:81c6df47c35012621dd3d8e2ef247e9031a304d5

commit r16-8528-g81c6df47c35012621dd3d8e2ef247e9031a304d5
Author: Marek Polacek <[email protected]>
Date:   Fri Mar 27 17:54:17 2026 -0400

    c++/reflection: static memfn templs of class templs [PR124617]
    
    Here meta::extract either wrongly throws or we crash.  The problem is
    that it got a partial specialization, with which it can't do much.
    
    When we have
    
      template <class F>
      struct S {
          template <int I>
          static constexpr int visit(F&&) { return 42; }
    
          static constexpr std::meta::info fptrs = ^^visit<0>;
      };
    
    and do get_reflection -> resolve_nondeduced_context for ^^visit<0>,
    we should already have substituted F, otherwise we only substitute
    I with 0 and are left with a partial specialization.  F should have
    been substituted in tsubst_expr/REFLECT_EXPR, but the reflection is
    
      REFLECT_EXPR<TEMPLATE_ID_EXPR<OVERLOAD, 0>>
    
    and tsubst_expr doesn't do much with an OVERLOAD.  This thing should
    be
    
      REFLECT_EXPR<BASELINK<TEMPLATE_ID_EXPR<OVERLOAD, 0>>>
    
    so that we go to tsubst_baselink and properly substitute the
    TEMPLATE_DECL in the OVERLOAD.
    
    cp_parser_reflect_expression doesn't call finish_id_expression which
    would add the BASELINK for reason mentioned in the comment there.  So
    I think we can do the following: just call baselink_for_fns to create
    the BASELINK if needed.
    
            PR c++/124617
    
    gcc/cp/ChangeLog:
    
            * parser.cc (cp_parser_reflect_expression): Call baselink_for_fns.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/reflect/dep12.C: New test.
            * g++.dg/reflect/dep13.C: New test.
    
    Reviewed-by: Jason Merrill <[email protected]>

Diff:
---
 gcc/cp/parser.cc                     |  2 ++
 gcc/testsuite/g++.dg/reflect/dep12.C | 15 +++++++++++++++
 gcc/testsuite/g++.dg/reflect/dep13.C | 25 +++++++++++++++++++++++++
 3 files changed, 42 insertions(+)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index d854d0f40c84..b3a241148693 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -10190,6 +10190,8 @@ cp_parser_reflect_expression (cp_parser *parser)
        && variable_template_p (TREE_OPERAND (t, 0))
        && !concept_check_p (t))
       t = finish_template_variable (t);
+    else if (is_overloaded_fn (t))
+      t = baselink_for_fns (t);
     if (cp_parser_parse_definitely (parser))
       return get_reflection (loc, t);
   }
diff --git a/gcc/testsuite/g++.dg/reflect/dep12.C 
b/gcc/testsuite/g++.dg/reflect/dep12.C
new file mode 100644
index 000000000000..22dfc37b48bd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/dep12.C
@@ -0,0 +1,15 @@
+// PR c++/124617
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+template <class T>
+struct S {
+  template <class U>
+  static void f() {}
+
+  static constexpr auto p = ^^f<int>;
+};
+
+constexpr void (*p)() = extract<void(*)()>(S<int>::p);
diff --git a/gcc/testsuite/g++.dg/reflect/dep13.C 
b/gcc/testsuite/g++.dg/reflect/dep13.C
new file mode 100644
index 000000000000..8d262a4a878e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/dep13.C
@@ -0,0 +1,25 @@
+// PR c++/124617
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+template <class F>
+struct S {
+    template <int I>
+    static constexpr int visit(F&&) { return 42; }
+
+    using Ptr = decltype(&visit<0>);
+    static constexpr std::meta::info fptrs = ^^visit<0>;
+};
+
+template <class F>
+constexpr int foo(F&& f) {
+    using Impl = S<F>;
+    auto which = Impl::fptrs;
+    auto func = std::meta::extract<typename Impl::Ptr>(which);
+    return func((F&&)f);
+}
+
+struct Plus { };
+static_assert(foo(Plus{}) == 42);

Reply via email to