https://gcc.gnu.org/g:2fb21bacf7b4b78ccba27ec5e01396c46c58c019
commit r16-8430-g2fb21bacf7b4b78ccba27ec5e01396c46c58c019 Author: Marek Polacek <[email protected]> Date: Wed Apr 1 16:06:58 2026 -0400 c++/reflection: fix wrong-code with members_of [PR124646, PR124645] My r16-8235 change should have set DECL_EXTERNAL only in the !at_function_scope_p block, before rest_of_decl_compilation. Setting DECL_EXTERNAL on the temporary var for both at_function_scope_p and !at_function_scope_p cases causes issues: in members_of11.C, we wrongly initialize 'mem' in the loop to A::a both times, insted of A::a and B::b. Similarly in members_of12.C we wrongly initialize member when inspecting ns2. I couldn't track down where *exactly* things go wrong, but the point of r16-8235 was to set DECL_EXTERNAL only for the rest_of_decl_compilation call. PR c++/124646 PR c++/124645 gcc/cp/ChangeLog: * call.cc (set_up_extended_ref_temp): Move setting DECL_EXTERNAL to the !at_function_scope_p block. gcc/testsuite/ChangeLog: * g++.dg/reflect/members_of11.C: New test. * g++.dg/reflect/members_of12.C: New test. Reviewed-by: Jason Merrill <[email protected]> Diff: --- gcc/cp/call.cc | 8 +++---- gcc/testsuite/g++.dg/reflect/members_of11.C | 26 ++++++++++++++++++++ gcc/testsuite/g++.dg/reflect/members_of12.C | 37 +++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 36703c587eb5..92c3a23ab8d9 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -14351,10 +14351,6 @@ set_up_extended_ref_temp (tree decl, tree expr, vec<tree, va_gc> **cleanups, /* Any reference temp has a non-trivial initializer. */ DECL_NONTRIVIALLY_INITIALIZED_P (var) = true; - /* Don't output reflection variables. */ - if (consteval_only_p (var)) - DECL_EXTERNAL (var) = true; - /* If the initializer is constant, put it in DECL_INITIAL so we get static initialization and use in constant expressions. */ init = maybe_constant_init (expr, var, /*manifestly_const_eval=*/true); @@ -14467,6 +14463,10 @@ set_up_extended_ref_temp (tree decl, tree expr, vec<tree, va_gc> **cleanups, } else { + /* Don't output reflection variables. */ + if (consteval_only_p (var)) + DECL_EXTERNAL (var) = true; + rest_of_decl_compilation (var, /*toplev=*/1, at_eof); if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) { diff --git a/gcc/testsuite/g++.dg/reflect/members_of11.C b/gcc/testsuite/g++.dg/reflect/members_of11.C new file mode 100644 index 000000000000..098981910fc6 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/members_of11.C @@ -0,0 +1,26 @@ +// PR c++/124646 +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } + +#include <meta> + +struct A { int a; }; +struct B { int b; }; + +consteval auto nsdms(std::meta::info i) { + return define_static_array(nonstatic_data_members_of(i, std::meta::access_context::unchecked())); +} + +consteval void print_nsdms(std::meta::info i) { + auto msg = std::string("members of ") + display_string_of(i) + " are:"; + for (auto mem : nsdms(i)) { + msg += " "; + msg += display_string_of(mem); + } + __builtin_constexpr_diag(0, "", msg); // { dg-message "members of B are: B::b" } +} + +consteval { + print_nsdms(^^A); + print_nsdms(^^B); +} diff --git a/gcc/testsuite/g++.dg/reflect/members_of12.C b/gcc/testsuite/g++.dg/reflect/members_of12.C new file mode 100644 index 000000000000..198ef3354214 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/members_of12.C @@ -0,0 +1,37 @@ +// PR c++/124645 +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } + +#include <meta> + +namespace reg +{ +template <auto namespace_info> +struct derived_type_registry +{ + static consteval auto + reflected_types(std::meta::info scope = namespace_info) + { + std::vector<std::meta::info> infos; + + for(auto member : members_of(scope, std::meta::access_context::unchecked())) + { + if (member == std::meta::info{}) continue; + } + + return infos; + } +}; +} + +namespace ns1 { + struct test {}; +} + +namespace ns2 { +} + +static_assert(reg::derived_type_registry<^^ns1>::reflected_types().empty()); +static_assert(reg::derived_type_registry<^^ns1>::reflected_types().size() == 0); +static_assert(reg::derived_type_registry<^^ns2>::reflected_types().empty()); +static_assert(reg::derived_type_registry<^^ns2>::reflected_types().size() == 0);
