https://gcc.gnu.org/g:694d048d87457e7728b9b5484a9b97cb0e617e40
commit r17-391-g694d048d87457e7728b9b5484a9b97cb0e617e40 Author: Marek Polacek <[email protected]> Date: Thu May 7 09:51:53 2026 -0400 c++/reflection: ICE with bases_of [PR125206] Here we crash in strip_typedefs_expr because we recurse on a REFLECT_EXPR with TREE_BINFO as its operand, which is not a code this function handles. It seems to me that we don't need to recurse for REFLECT_EXPRs at all. Alternatively, we could just handle TREE_BINFO. PR c++/125206 gcc/cp/ChangeLog: * tree.cc (strip_typedefs_expr) <case REFLECT_EXPR>: Always return instead of recursing. gcc/testsuite/ChangeLog: * g++.dg/reflect/bases_of4.C: New test. Reviewed-by: Jason Merrill <[email protected]> Diff: --- gcc/cp/tree.cc | 7 ++--- gcc/testsuite/g++.dg/reflect/bases_of4.C | 45 ++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index c510a5bf2d0b..2e96d65eecd7 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -2155,12 +2155,9 @@ strip_typedefs_expr (tree t, bool *remove_attributes, unsigned int flags) case LAMBDA_EXPR: case STMT_EXPR: - return t; - + /* ^^alias represents the alias itself, not the underlying type. */ case REFLECT_EXPR: - /* ^^alias represents the alias itself, not the underlying type. */ - if (TYPE_P (REFLECT_EXPR_HANDLE (t))) - return t; + return t; default: break; diff --git a/gcc/testsuite/g++.dg/reflect/bases_of4.C b/gcc/testsuite/g++.dg/reflect/bases_of4.C new file mode 100644 index 000000000000..843f0e53c4e0 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/bases_of4.C @@ -0,0 +1,45 @@ +// PR c++/125206 +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } + +#include <meta> +#include <type_traits> + +template<auto...> struct mp_list_v +{ +}; + +template<class...> struct mp_list +{ +}; + +template<auto V> using mp_value = std::integral_constant<decltype(V), V>; + +template<class L, template<class...> class B> struct mp_rename_impl; + +template<template<class...> class L, class... T, template<class...> class B> struct mp_rename_impl<L<T...>, B> +{ + using type = B<T...>; +}; + +template<template<auto...> class L, auto... A, template<class...> class B> struct mp_rename_impl<L<A...>, B> +{ + using type = B<mp_value<A>...>; +}; + +template<class L, template<class...> class B> using mp_rename = typename mp_rename_impl<L, B>::type; + +class X1 +{ +}; + +class Z: public X1 +{ +}; + +int main() +{ + constexpr auto all = std::meta::access_context::unchecked(); + constexpr auto L1 = ^^mp_list_v< bases_of(^^Z, all)[0] >; + using L2 = mp_rename<typename [: L1 :], mp_list>; +}
