https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125680
Bug ID: 125680
Summary: [meta] ICE in nested_anon_class_index, at
cp/mangle.cc:1814 with C++26 reflection and anonymous
struct array inside lambda within template for loop
Product: gcc
Version: 16.1.1
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: berningchen at gmail dot com
Target Milestone: ---
When using C++26 experimental reflection (-freflection), the compiler triggers
an Internal Compiler Error (ICE) during the mangling phase
(nested_anon_class_index, at cp/mangle.cc). This happens when we query the type
of an element of an array of an anonymous struct (or nested unnamed
union/struct) via decltype inside a lambda closure expression evaluated within
a template metaprogramming context (such as template for), and then attempt to
pass that escaped type reflection info (std::meta::info) to instantiate a
downstream class template.
Compilation options:
-std=c++26 -freflection
Example 1:
#include <concepts>
#include <memory>
#include <meta>
#include <ranges>
namespace detail
{
template <typename Tp> struct is_shared_ptr : std::false_type
{
};
template <typename Tp> struct is_shared_ptr<std::shared_ptr<Tp>> :
std::true_type
{
};
template <typename T> struct ReflectionUtils
{
static constexpr auto get_members()
{
if constexpr (std::is_array_v<T>)
return std::define_static_array(std::views::iota(0u,
std::meta::extent(^^T)));
else if constexpr (std::is_class_v<T>)
return
std::define_static_array(std::meta::nonstatic_data_members_of(^^T,
std::meta::access_context::unchecked()));
else
return std::define_static_array(std::vector<std::meta::info>{});
}
static constexpr auto ranges = get_members();
};
} // namespace detail
template <typename Tp> struct Reflection
{
static constexpr bool enabled = false;
};
template <typename Tp>
requires(std::is_arithmetic_v<std::remove_const_t<Tp>>)
struct Reflection<Tp>
{
static constexpr bool enabled = true;
};
template <typename T> class ReflectionPanel
{
public:
void updateGUI() { _panel->updateGUI(); }
ReflectionPanel(std::shared_ptr<T> target) : _target(target) { buildUI(); }
private:
template <std::meta::info currField, typename ParentPanelType> class
ReflectionSubPanel
{
auto getSelf()
{
auto p = [&]()
{
if constexpr (std::meta::is_type(currField))
return _parent->getField(0);
else
return _parent->template getField<currField>();
}();
if constexpr
(detail::is_shared_ptr<std::remove_pointer_t<decltype(p)>>::value)
return p->get();
else
return p;
}
public:
ReflectionSubPanel(ParentPanelType *parent)
requires(!std::meta::is_type(currField))
: _parent(parent)
{
buildUI();
}
ReflectionSubPanel(ParentPanelType *parent, int index)
requires(std::meta::is_type(currField))
: _parent(parent)
{
buildUI();
}
private:
ParentPanelType *_parent;
void buildUI()
{
using SelfType =
std::remove_pointer_t<decltype(std::declval<ReflectionSubPanel>().getSelf())>;
constexpr bool isArray = std::is_array_v<SelfType>;
template for (constexpr auto member :
detail::ReflectionUtils<SelfType>::ranges)
{
constexpr auto fieldTypeInfo = [member]()
{
if constexpr (isArray)
{
using MemberType =
std::remove_pointer_t<decltype(getField(0))>;
return ^^MemberType;
}
else
{
using MemberType =
std::remove_pointer_t<decltype(getField<member>())>;
return ^^MemberType;
}
}();
if constexpr (!Reflection<typename[:fieldTypeInfo:]>::enabled)
if constexpr (isArray)
ReflectionSubPanel<fieldTypeInfo,
ReflectionSubPanel>(this, member);
else
ReflectionSubPanel<member, ReflectionSubPanel>(this);
}
}
public:
template <std::meta::info internalField> auto getField() //
{dependency, pointer}
{
return std::addressof(getSelf()->[:internalField:]);
}
auto getField(std::size_t index) // {dependency, pointer}
{
return std::addressof((*getSelf())[index]);
}
};
std::shared_ptr<T> _target;
std::shared_ptr<ReflectionSubPanel<^^_target, ReflectionPanel>> _panel;
template <std::meta::info field> std::shared_ptr<T> *getField() //
{dependency, pointer}
{
return std::addressof(_target);
}
void buildUI() { ReflectionSubPanel<^^_target, ReflectionPanel>(this); }
};
;
struct TestStruct
{
struct
{
int b;
} a[4];
};
int main()
{
std::make_shared<ReflectionPanel<TestStruct>>(std::make_shared<TestStruct>());
return 0;
}
Output:
<source>: In instantiation of
'ReflectionPanel<T>::ReflectionSubPanel<currField,
ParentPanelType>::ReflectionSubPanel(ParentPanelType*, int) requires
is_type(std::meta::info'meta_type' not supported by
direct_abstract_declarator)(currField) [with std::meta::info currField =
^^MemberType; ParentPanelType =
ReflectionPanel<TestStruct>::ReflectionSubPanel<^^TestStruct::a,
ReflectionPanel<TestStruct>::ReflectionSubPanel<^^ReflectionPanel<TestStruct>::_target,
ReflectionPanel<TestStruct> > >; T = TestStruct]':
<source>:106:25: required from 'void
ReflectionPanel<T>::ReflectionSubPanel<currField, ParentPanelType>::buildUI()
[with std::meta::info currField = ^^TestStruct::a; ParentPanelType =
ReflectionPanel<TestStruct>::ReflectionSubPanel<^^ReflectionPanel<TestStruct>::_target,
ReflectionPanel<TestStruct> >; T = TestStruct]'
106 | ReflectionSubPanel<fieldTypeInfo,
ReflectionSubPanel>(this, member);
|
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:71:13: required from
'ReflectionPanel<T>::ReflectionSubPanel<currField,
ParentPanelType>::ReflectionSubPanel(ParentPanelType*) requires !
is_type(std::meta::info'meta_type' not supported by
direct_abstract_declarator)(currField) [with std::meta::info currField =
^^TestStruct::a; ParentPanelType =
ReflectionPanel<TestStruct>::ReflectionSubPanel<^^ReflectionPanel<TestStruct>::_target,
ReflectionPanel<TestStruct> >; T = TestStruct]'
71 | buildUI();
| ^~~~~~~
<source>:108:25: required from 'void
ReflectionPanel<T>::ReflectionSubPanel<currField, ParentPanelType>::buildUI()
[with std::meta::info currField = ^^ReflectionPanel<TestStruct>::_target;
ParentPanelType = ReflectionPanel<TestStruct>; T = TestStruct]'
108 | ReflectionSubPanel<member,
ReflectionSubPanel>(this);
|
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:71:13: required from
'ReflectionPanel<T>::ReflectionSubPanel<currField,
ParentPanelType>::ReflectionSubPanel(ParentPanelType*) requires !
is_type(std::meta::info'meta_type' not supported by
direct_abstract_declarator)(currField) [with std::meta::info currField =
^^ReflectionPanel<TestStruct>::_target; ParentPanelType =
ReflectionPanel<TestStruct>; T = TestStruct]'
71 | buildUI();
| ^~~~~~~
<source>:131:22: required from 'void ReflectionPanel<T>::buildUI() [with T =
TestStruct]'
131 | void buildUI() { ReflectionSubPanel<^^_target,
ReflectionPanel>(this); }
|
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:45:68: [ skipping 3 instantiation contexts, use
-ftemplate-backtrace-limit=0 to disable ]
45 | ReflectionPanel(std::shared_ptr<T> target) : _target(target) {
buildUI(); }
|
^~~~~~~
/cefs/97/97a4e8c0f997d8d8242b8779_gcc-trunk-20260608/include/c++/17.0.0/bits/shared_ptr_base.h:638:39:
required from 'std::_Sp_counted_ptr_inplace<_Tp, _Alloc,
_Lp>::_Sp_counted_ptr_inplace(_Alloc, _Args&& ...) [with _Args =
{std::shared_ptr<TestStruct>}; _Tp = ReflectionPanel<TestStruct>; _Alloc =
std::allocator<void>; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]'
638 | allocator_traits<_Alloc>::construct(__a, _M_ptr(),
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~
639 | std::forward<_Args>(__args)...); // might throw
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/cefs/97/97a4e8c0f997d8d8242b8779_gcc-trunk-20260608/include/c++/17.0.0/bits/shared_ptr_base.h:1000:16:
required from 'std::__shared_count<_Lp>::__shared_count(_Tp*&,
std::_Sp_alloc_shared_tag<_Alloc>, _Args&& ...) [with _Tp =
ReflectionPanel<TestStruct>; _Alloc = std::allocator<void>; _Args =
{std::shared_ptr<TestStruct>}; __gnu_cxx::_Lock_policy _Lp =
__gnu_cxx::_S_atomic]'
1000 | auto __pi = ::new (__mem)
| ^~~~~~~~~~~~~
1001 | _Sp_cp_type(__a._M_a, std::forward<_Args>(__args)...);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/cefs/97/97a4e8c0f997d8d8242b8779_gcc-trunk-20260608/include/c++/17.0.0/bits/shared_ptr_base.h:1776:14:
required from 'std::__shared_ptr<_Tp,
_Lp>::__shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc =
std::allocator<void>; _Args = {std::shared_ptr<TestStruct>}; _Tp =
ReflectionPanel<TestStruct>; __gnu_cxx::_Lock_policy _Lp =
__gnu_cxx::_S_atomic]'
1776 | : _M_ptr(), _M_refcount(_M_ptr, __tag,
std::forward<_Args>(__args)...)
|
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/cefs/97/97a4e8c0f997d8d8242b8779_gcc-trunk-20260608/include/c++/17.0.0/bits/shared_ptr.h:445:59:
required from
'std::shared_ptr<_Tp>::shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...)
[with _Alloc = std::allocator<void>; _Args = {std::shared_ptr<TestStruct>}; _Tp
= ReflectionPanel<TestStruct>]'
445 | : __shared_ptr<_Tp>(__tag, std::forward<_Args>(__args)...)
| ^
/cefs/97/97a4e8c0f997d8d8242b8779_gcc-trunk-20260608/include/c++/17.0.0/bits/shared_ptr.h:1047:14:
required from 'std::shared_ptr<std::_NonArray<_Tp> > std::make_shared(_Args&&
...) [with _Tp = ReflectionPanel<TestStruct>; _Args = {shared_ptr<TestStruct>};
_NonArray<_Tp> = ReflectionPanel<TestStruct>]'
1047 | return shared_ptr<_Tp>(_Sp_alloc_shared_tag<_Alloc>{__a},
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1048 | std::forward<_Args>(__args)...);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:145:50: required from here
145 |
std::make_shared<ReflectionPanel<TestStruct>>(std::make_shared<TestStruct>());
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:73:9: internal compiler error: in nested_anon_class_index, at
cp/mangle.cc:1814
73 | ReflectionSubPanel(ParentPanelType *parent, int index)
| ^~~~~~~~~~~~~~~~~~
0x29f5248 diagnostics::context::diagnostic_impl(rich_location*,
diagnostics::metadata const*, diagnostics::option_id, char const*,
__va_list_tag (*) [1], diagnostics::kind)
???:0
0x29e9e8b internal_error(char const*, ...)
???:0
0xb33f5c fancy_abort(char const*, int, char const*)
???:0
0xca0999 mangle_decl(tree_node*)
???:0
0x18fbac5 decl_assembler_name(tree_node*)
???:0
0xd15065 maybe_clone_body(tree_node*)
???:0
0xe2bf0e expand_or_defer_fn(tree_node*)
???:0
0xdec1bd instantiate_decl(tree_node*, bool, bool)
???:0
0xdf5efa instantiate_pending_templates(int)
???:0
0xc59be8 c_parse_final_cleanups()
???:0
0xf17588 c_common_parse_file()
???:0