https://gcc.gnu.org/g:64627d4f8349af24f5a84c0936eb00256769b534
commit r17-1464-g64627d4f8349af24f5a84c0936eb00256769b534 Author: Marek Polacek <[email protected]> Date: Tue Jun 9 16:50:14 2026 -0400 c++/reflection: ICE with -g on reflection of ctor param [PR125498] Here we ICE because S::S(int) lost its DECL_ARGUMENTS, and so the skip_artificial_parms_for in FUNCTION_FIRST_USER_PARM in write_reflection crashes on a null tree. We've thrown away the body of S::S(int) in cgraph_node::release_body along with its DECL_ARGUMENTS: if (!keep_arguments) DECL_ARGUMENTS (decl) = NULL; This happens in finalize_compilation_unit -> analyze_functions because there are no cgraph_node::callers (so referred_to_p() is false I think), and .force_output is false. We then call mangle_decl from finalize_compilation_unit -> dwarf2out_early_finish. Instead of FUNCTION_FIRST_USER_PARM we can use DECL_PARM_INDEX, thus avoiding the need to either keep the body around or at least set keep_arguments. PR c++/125498 gcc/cp/ChangeLog: * mangle.cc (write_reflection): Use DECL_PARM_INDEX for computing the parameter index. gcc/testsuite/ChangeLog: * g++.dg/reflect/mangle7.C: New test. * g++.dg/reflect/parameters_of9.C: New test. Reviewed-by: Patrick Palka <[email protected]> Diff: --- gcc/cp/mangle.cc | 9 +--- gcc/testsuite/g++.dg/reflect/mangle7.C | 65 +++++++++++++++++++++++++++ gcc/testsuite/g++.dg/reflect/parameters_of9.C | 45 +++++++++++++++++++ 3 files changed, 112 insertions(+), 7 deletions(-) diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc index 982864ebf0c6..a287cded8aeb 100644 --- a/gcc/cp/mangle.cc +++ b/gcc/cp/mangle.cc @@ -4220,13 +4220,8 @@ write_reflection (tree refl) else if (strcmp (prefix, "pa") == 0) { tree fn = DECL_CONTEXT (arg); - tree args = FUNCTION_FIRST_USER_PARM (fn); - int idx = 0; - while (arg != args) - { - args = DECL_CHAIN (args); - ++idx; - } + /* DECL_PARM_INDEX is 1-based but here we want a 0-based index. */ + const int idx = DECL_PARM_INDEX (arg) - 1; write_compact_number (idx); write_encoding (fn); } diff --git a/gcc/testsuite/g++.dg/reflect/mangle7.C b/gcc/testsuite/g++.dg/reflect/mangle7.C new file mode 100644 index 000000000000..f6d9e3472049 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/mangle7.C @@ -0,0 +1,65 @@ +// PR c++/125498 +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } + +#include <meta> + +using namespace std::meta; + +template<info> +void +xyzzy () +{ +} + +struct S { + void fn1 (const S &) + { + xyzzy<parameters_of (^^S::fn1)[0]> (); + } + void fn2 (this S) + { + xyzzy<parameters_of (^^S::fn2)[0]> (); + } + static void fn3 (int) + { + xyzzy<parameters_of (^^S::fn3)[0]> (); + } +}; + +struct V : virtual S { + void fn1 (const V &) + { + xyzzy<parameters_of (^^V::fn1)[0]> (); + } + void fn2 (this V) + { + xyzzy<parameters_of (^^V::fn2)[0]> (); + } + static void fn3 (int) + { + xyzzy<parameters_of (^^V::fn3)[0]> (); + } +}; + +void +g (int) +{ + xyzzy<parameters_of (^^g)[0]> (); + S s; + s.fn1 (s); + s.fn2 (); + S::fn3 (42); + V v; + v.fn1 (v); + v.fn2 (); + V::fn3 (42); +} + +// { dg-final { scan-assembler "_Z5xyzzyILDmpa_N1S3fn1ERKS0_EEvv" } } +// { dg-final { scan-assembler "_Z5xyzzyILDmpa_NH1S3fn2ES0_EEvv" } } +// { dg-final { scan-assembler "_Z5xyzzyILDmpa_N1S3fn3EiEEvv" } } +// { dg-final { scan-assembler "_Z5xyzzyILDmpa_N1V3fn1ERKS0_EEvv" } } +// { dg-final { scan-assembler "_Z5xyzzyILDmpa_NH1V3fn2ES0_EEvv" } } +// { dg-final { scan-assembler "_Z5xyzzyILDmpa_N1V3fn3EiEEvv" } } +// { dg-final { scan-assembler "_Z5xyzzyILDmpa_1giEEvv" } } diff --git a/gcc/testsuite/g++.dg/reflect/parameters_of9.C b/gcc/testsuite/g++.dg/reflect/parameters_of9.C new file mode 100644 index 000000000000..ef7059a111a7 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/parameters_of9.C @@ -0,0 +1,45 @@ +// PR c++/125498 +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection -g" } + +#include <meta> + +struct tag {}; + +struct S { + S(int) {} +}; + +struct B { }; +struct A : virtual B { A(int); }; + +template <auto Param> struct GetAnnotations { + static constexpr auto value = std::define_static_array( + std::meta::annotations_of_with_type(Param, ^^tag)); +}; + +consteval bool test() { + template for (constexpr auto member : + std::define_static_array(std::meta::members_of( + ^^S, std::meta::access_context::unchecked()))) { + if constexpr (std::meta::is_constructor(member)) { + constexpr auto parameters = + std::define_static_array(std::meta::parameters_of(member)); + constexpr auto annotations = GetAnnotations<parameters[0]>::value; + return annotations.empty(); + } + } +} + +consteval bool test2() { + template for (constexpr auto member : + std::define_static_array(std::meta::members_of( + ^^A, std::meta::access_context::unchecked()))) { + if constexpr (std::meta::is_constructor(member)) { + constexpr auto parameters = + std::define_static_array(std::meta::parameters_of(member)); + constexpr auto annotations = GetAnnotations<parameters[0]>::value; + return annotations.empty(); + } + } +}
