Bootstrapped and tested on x86_64-pc-linux-gnu. -- >8 -- 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` - `splice8.C` test) and passing `^^T::member` as the template argument (in which case evaluating the `SPLICE_EXPR` returns a `BASELINK` - `splice9.C`). 2026-02-08 Boris Staletic <[email protected]> PR c++/123660 PR c++/123661 * pt.cc (tsubst_expr): Handle pointers to non-static members from splice expressions. * g++.dg/reflect/splice10.C: New test. * g++.dg/reflect/splice11.C: New test. Signed-off-by: Boris Staletic <[email protected]> --- gcc/cp/pt.cc | 23 +++++++++++++++++-- gcc/testsuite/g++.dg/reflect/splice10.C | 30 +++++++++++++++++++++++++ gcc/testsuite/g++.dg/reflect/splice11.C | 29 ++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/reflect/splice10.C create mode 100644 gcc/testsuite/g++.dg/reflect/splice11.C diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 049bbf07e0..fb1cd386e8 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -21454,8 +21454,27 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) op1 = tsubst_qualified_id (op1, args, complain, in_decl, /*done=*/true, /*address_p=*/true); else - op1 = tsubst_non_call_postfix_expression (op1, args, complain, - in_decl); + { + tree old_op1 = op1; + op1 = tsubst_non_call_postfix_expression (op1, args, complain, + in_decl); + if (TREE_CODE (old_op1) == SPLICE_EXPR) + { + if (TREE_CODE (op1) == BASELINK) + { + tree fn = BASELINK_FUNCTIONS (op1); + if (TREE_CODE (fn) == FUNCTION_DECL && + TREE_CODE (TREE_TYPE (op1) ) == METHOD_TYPE && + !TREE_STATIC (op1)) + op1 = fn; + } + if (TREE_CODE (op1) == FIELD_DECL || + (TREE_CODE (op1) == FUNCTION_DECL && + TREE_CODE (TREE_TYPE (op1)) == METHOD_TYPE && + !TREE_STATIC (TREE_TYPE (op1)))) + op1 = build_offset_ref(DECL_CONTEXT(op1), op1, true, complain); + } + } RETURN (build_x_unary_op (input_location, ADDR_EXPR, op1, templated_operator_saved_lookups (t), complain|decltype_flag)); diff --git a/gcc/testsuite/g++.dg/reflect/splice10.C b/gcc/testsuite/g++.dg/reflect/splice10.C new file mode 100644 index 0000000000..cbed421021 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/splice10.C @@ -0,0 +1,30 @@ +// PR c++/123660 +// PR c++/123661 +// { dg-do run { 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]:]; +} + +int main() { + 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 0000000000..6568afed07 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/splice11.C @@ -0,0 +1,29 @@ +// { dg-do run { 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:]; +} + +int main() { + 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); +} -- 2.51.1
