https://gcc.gnu.org/g:a1e81f838a38e37d7a659406f8fea1dba8f26406
commit r16-7445-ga1e81f838a38e37d7a659406f8fea1dba8f26406 Author: Boris Staletic <[email protected]> Date: Wed Feb 11 16:20:49 2026 +0900 c++/reflection: Allow address-splicing of non-static members [PR123660, PR123661] In case of expressions like `&[:expr:]` where `expr` depends on a template parameter, and the splice expression represents a `FIELD_DECL` or a non-static member `FUNCTION_DECL`, that's exactly what we'd pass on. However, `build_x_unary_op()` for these expressions is expecting an `OFFSET_REF`. `OFFSET_REF` is also what gets passed to `build_x_unary_op()` when templates are not involved. There's also a difference between the template argument being a type and using `members_of()` to get to the reflections of members (in which case evaluating the `SPLICE_EXPR` returns a `FUNCTION_DECL` - `splice10.C` test) and passing `^^T::member` as the template argument (in which case evaluating the `SPLICE_EXPR` returns a `BASELINK` - `splice11.C`). Signed-off-by: Boris Staletic <[email protected]> PR c++/123660 PR c++/123661 gcc/cp/ChangeLog: * pt.cc (tsubst_splice_expr): Handle pointers to non-static members from splice expressions gcc/testsuite/ChangeLog: * g++.dg/reflect/splice10.C: New test. * g++.dg/reflect/splice11.C: New test. Diff: --- gcc/cp/pt.cc | 11 +++++++++++ gcc/testsuite/g++.dg/reflect/splice10.C | 28 ++++++++++++++++++++++++++++ gcc/testsuite/g++.dg/reflect/splice11.C | 29 +++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 7c6577b48eff..20fd30a8b473 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -16771,6 +16771,17 @@ tsubst_splice_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) SPLICE_EXPR_MEMBER_ACCESS_P (t), (complain & tf_error))) return error_mark_node; + + if (SPLICE_EXPR_ADDRESS_P (t)) + { + if (BASELINK_P (op)) + op = build_offset_ref (BINFO_TYPE (BASELINK_ACCESS_BINFO (op)), op, + /*address_p=*/true, complain); + else if (DECL_NONSTATIC_MEMBER_P (op)) + op = build_offset_ref (DECL_CONTEXT (op), op, + /*address_p=*/true, complain); + } + if (outer_automatic_var_p (op)) op = process_outer_var_ref (op, complain); /* Like in cp_parser_splice_expression, for foo.[: bar :] diff --git a/gcc/testsuite/g++.dg/reflect/splice10.C b/gcc/testsuite/g++.dg/reflect/splice10.C new file mode 100644 index 000000000000..2f335ea8fcf2 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/splice10.C @@ -0,0 +1,28 @@ +// PR c++/123660 +// PR c++/123661 +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } + +#include <meta> + +struct s { + int get_z(this s) { return 4; } + static int get_y() { return 4; } + int get_x() { return 3; } + int xx; + static int xxx; +}; + +int s::xxx = 5; + +template<typename T, decltype(0uz) I> +constexpr auto test() { + constexpr auto ctx = std::meta::access_context::current(); + return &[:members_of(^^T, ctx)[I]:]; +} + +static_assert(test<s, 0uz>() == &s::get_z); +static_assert(test<s, 1uz>() == &s::get_y); +static_assert(test<s, 2uz>() == &s::get_x); +static_assert(test<s, 3uz>() == &s::xx); +static_assert(test<s, 4uz>() == &s::xxx); diff --git a/gcc/testsuite/g++.dg/reflect/splice11.C b/gcc/testsuite/g++.dg/reflect/splice11.C new file mode 100644 index 000000000000..b62fdcc5ee5b --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/splice11.C @@ -0,0 +1,29 @@ +// PR c++/123660 +// PR c++/123661 +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } + +#include <meta> + +void f() {} +struct s { + int get_z(this s) { return 4; } + static int get_y() { return 4; } + int get_x() { return 3; } + int xx; + static int xxx; +}; + +int s::xxx = 5; + +template<std::meta::info refl_expr> +constexpr auto test() { + return &[:refl_expr:]; +} + +static_assert(test<^^s::get_z>() == &s::get_z); +static_assert(test<^^s::get_y>() == &s::get_y); +static_assert(test<^^s::get_x>() == &s::get_x); +static_assert(test<^^s::xx>() == &s::xx); +static_assert(test<^^s::xxx>() == &s::xxx); +static_assert(test<^^f>() == &f);
