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);
