On Mon, Feb 09, 2026 at 11:03:14PM +0900, Jason Merrill wrote: > On 2/8/26 6:43 PM, Boris Staletic wrote: > > 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`). > > Thanks for the patch! A few commments below.
Also thanks for your bug reports! Note that the PR is in the ASSIGNED state indicating that someone, in this case me, is already working on the problem. I didn't get to this PR yet so it's fine -- I thought it would depend on another bug fix that is on my plate, namely, not passing ctx to finish_id_expression. Looks like it doesn't. > > 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. Note that we have separate ChangeLogs for cp/ and for testsuite/. It's best to use gcc-mklog to auto-generate a ChangeLog skeleton. Feel free to contact me off-list. > > 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; > > + } > > It should be fine to just pass the BASELINK on to build_offset_ref. You can > use BINFO_TYPE (BINFO_ACCESS_BINFO as the type argument. BASELINK_ACCESS_BINFO > > + if (TREE_CODE (op1) == FIELD_DECL || > > + (TREE_CODE (op1) == FUNCTION_DECL && > > + TREE_CODE (TREE_TYPE (op1)) == METHOD_TYPE && > > + !TREE_STATIC (TREE_TYPE (op1)))) > > Operators like ||/&& go at the beginning of the line in our coding style. > > > + op1 = build_offset_ref(DECL_CONTEXT(op1), op1, true, complain); > > And space before (. I would like this to be moved to tsubst_splice_expr (and I guess check SPLICE_EXPR_ADDRESS_P). > > + } > > + } > > 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 } } I don't think this test needs to be dg-run, dg-compile should be enough. > > +// { 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 @@ I'd also add // PR c++/123661 here. > > +// { dg-do run { target c++26 } } Also dg-compile. > > +// { 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); > > +} > Marek
