https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124617
Bug ID: 124617
Summary: meta::extract fails (or ICEs) for static member
function templates of class templates
Product: gcc
Version: 16.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: barry.revzin at gmail dot com
Target Milestone: ---
This example (sorry I tried to reproduce, but couldn't, see below) fails to be
a constant expression due to the meta::extract call throwing — saying I got the
type wrong. But the type is correct, and the constexpr output (incredible!)
seems to just not substitute the types into the static member function template
(https://compiler-explorer.com/z/qboM8shM1):
#include <array>
#include <meta>
template <class T, class U>
struct Variant {
union {
T t;
U u;
};
int index;
constexpr Variant(T t) : t(t), index(0) { }
constexpr Variant(U u) : u(u), index(1) { }
template <int I> requires (I < 2)
constexpr auto get() const -> auto const& {
if constexpr (I == 0) return t;
else if constexpr (I == 1) return u;
}
};
#ifdef __clang__
#define __builtin_constexpr_diag(...)
#endif
template <class R, class F, class V0, class V1>
struct binary_vtable_impl {
template <int I, int J>
static constexpr auto visit(F&& f, V0 const& v0, V1 const& v1) -> R {
return f(v0.template get<I>(), v1.template get<J>());
}
static constexpr auto get_array() {
return std::array{
std::array{^^visit<0, 0>, ^^visit<0, 1>},
std::array{^^visit<1, 0>, ^^visit<1, 1>}
};
}
using Ptr = decltype(&visit<0, 0>);
// This constexpr variable will be initialized to
// an array of pointers to consteval functions.
static constexpr std::array fptrs = get_array();
};
template <class R, class F, class V0, class V1>
constexpr auto visit(F&& f, V0 const& v0, V1 const& v1) -> R {
using Impl = binary_vtable_impl<R, F, V0, V1>;
auto which = Impl::fptrs[v0.index][v1.index];
__builtin_constexpr_diag(0, "aa", display_string_of(type_of(which)));
__builtin_constexpr_diag(0, "bb", display_string_of(dealias(^^typename
Impl::Ptr)));
auto func = std::meta::extract<typename Impl::Ptr>(which);
return func((F&&)f, v0, v1);
}
struct Plus {
consteval auto operator()(auto x, auto y) const {
return x + y;
}
};
consteval auto func(const Variant<int, long>& v1, const Variant<int, long>& v2)
{
return visit<int>(Plus{}, v1, v2);
}
static_assert(func(Variant<int, long>{42}, Variant<int, long>{1729}) == 1771);
-------
I attempted to reduce the example to this:
#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);
which ICEs:
<source>: In instantiation of 'constexpr std::meta::info S<int>::p':
<source>:11:43: required from here
11 | constexpr void (*p)() = extract<void(*)()>(^^S<int>::p);
| ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~
<source>:8:31: internal compiler error: in filter_memfn_lookup, at
cp/pt.cc:17940
8 | static constexpr auto p = ^^f<int>;
| ^
0x2967e18 diagnostics::context::diagnostic_impl(rich_location*,
diagnostics::metadata const*, diagnostics::option_id, char const*,
__va_list_tag (*) [1], diagnostics::kind)
???:0
0x295ca5b internal_error(char const*, ...)
???:0
0xb22cf4 fancy_abort(char const*, int, char const*)
???:0
0xdd1f5d instantiate_decl(tree_node*, bool, bool)
???:0
0xc3e0a3 maybe_instantiate_decl(tree_node*)
???:0
0xc3e0ef decl_constant_var_p(tree_node*)
???:0
0xb8fb79 cxx_eval_constant_expression(constexpr_ctx const*, tree_node*,
value_cat, bool*, bool*, tree_node**)
???:0
0xdf47f0 process_metafunction(constexpr_ctx const*, tree_node*, tree_node*,
bool*, bool*, tree_node**)
???:0
0xb9046c cxx_eval_constant_expression(constexpr_ctx const*, tree_node*,
value_cat, bool*, bool*, tree_node**)
???:0
0xba94a9 maybe_constant_value(tree_node*, tree_node*, mce_value)
???:0
0xe78937 store_init_value(tree_node*, tree_node*, vec<tree_node*, va_gc,
vl_embed>**, int)
???:0
0xc2fff6 cp_finish_decl(tree_node*, tree_node*, bool, tree_node*, int,
cp_decomp*)
???:0
0xd6f583 c_parse_file()
???:0
0xef9b29 c_common_parse_file()
???:0