On Tue, Feb 10, 2026 at 06:14:02PM +0000, Boris Staletic wrote: > On Tuesday, February 10th, 2026 at 5:38 PM, Marek Polacek > <[email protected]> wrote: > > > On Tue, Feb 10, 2026 at 05:32:22PM +0000, Boris Staletic wrote: > > > On Tuesday, February 10th, 2026 at 4:49 PM, Marek Polacek > > > <[email protected]> wrote: > > > > > > > On Tue, Feb 10, 2026 at 03:26:37PM +0000, Boris Staletic wrote: > > > > > On Tuesday, February 10th, 2026 at 2:05 PM, Jason Merrill > > > > > <[email protected]> wrote: > > > > > > > > > > > > > > > > > > > > > > > > > > > Snipped older discussions for brevity. > > > > > > > > > > > > > > > > > > > Here's a v2 of the patch, 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` - > > > > > > > `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. > > > > > > > --- > > > > > > > gcc/cp/pt.cc | 14 ++++++++++++ > > > > > > > gcc/testsuite/g++.dg/reflect/splice10.C | 28 > > > > > > > ++++++++++++++++++++++++ > > > > > > > gcc/testsuite/g++.dg/reflect/splice11.C | 29 > > > > > > > +++++++++++++++++++++++++ > > > > > > > 3 files changed, 71 insertions(+) > > > > > > > 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..0c0076c9a4 100644 > > > > > > > --- a/gcc/cp/pt.cc > > > > > > > +++ b/gcc/cp/pt.cc > > > > > > > @@ -16755,6 +16755,20 @@ tsubst_splice_expr (tree t, tree args, > > > > > > > tsubst_flags_t complain, tree in_decl) > > > > > > > op = splice (op); > > > > > > > if (op == error_mark_node) > > > > > > > return error_mark_node; > > > > > > > + > > > > > > > + if (SPLICE_EXPR_ADDRESS_P (t) && !TREE_STATIC (TREE_TYPE (op))) > > > > > > > > > > > > > > > > > > TREE_STATIC on a type isn't meaningful, the checks below are enough. > > > > > > > > > > I thought that was fishy... You're right, everything works without > > > > > that check. > > > > > > > > > > > > > > > > > > + { > > > > > > > + if (TREE_CODE (op) == BASELINK > > > > > > > + && TREE_CODE (TREE_TYPE (op)) == METHOD_TYPE) > > > > > > > > > > > > > > > > > > It shouldn't be necessary to check for METHOD_TYPE; any class > > > > > > member is > > > > > > suitable for passing to build_offset_ref. If the argument is static, > > > > > > it'll return it unchanged rather than actually build an OFFSET_REF. > > > > > > > > > > If I drop the METHOD_TYPE check, I get an ICE in both splice10.C and > > > > > splice11.C. > > > > > splice10.C ICEs when calling `build_offset_ref()` on a static member > > > > > function (s::get_y). > > > > > splice11.C ICEs when calling `build_offset_ref()` on a free function > > > > > (::f). > > > > > > > > > > That's why I was initially looking for a way to do this only for > > > > > non-static members. > > > > > > > > I think Jason meant the check for METHOD_TYPE for a BASELINK, which > > > > is certainly not needed. Please also use BASELINK_P instead of > > > > TREE_CODE == BASELINK. > > > > > > > > We shouldn't call build_offset_ref on static member functions or > > > > free functions. So I think the second call to build_offset_ref > > > > should be guarded by > > > > > > > > TREE_CODE (op) == FIELD_DECL || DECL_OBJECT_MEMBER_FUNCTION_P (op) > > > > > > > > But maybe Jason prefers something else. > > > > > > > > > > > > I would also move the SPLICE_EXPR_ADDRESS_P block after checking > > > > dependent_splice_p and after check_splice_expr. > > > > > > Okay, all of that works. One question: > > > Would it be more correct to guard the whole block with > > > > > > if (SPLICE_EXPR_ADDRESS_P (t)) > > > > > > or > > > > > > if (SPLICE_EXPR_ADDRESS_P (op)) > > > > > > Given what's in the dependent_splice_p block, I'm thinking latter, but > > > I'm not sure. > > > > It should check t, because op won't be a SPLICE_EXPR (except in the > > dependent_splice_p block). > > > > Marek > > > > In that case, here's the updated patch:
Thanks, the patch looks good to me now (but I can't approve it). This seems like your first patch to GCC, and I'm not sure these changes are trivial. As documented at <https://gcc.gnu.org/contribute.html#legal> we need either a copyright assignment with the FSF, or DCO (Developer Certificate of Origin) sign-off (<https://gcc.gnu.org/dco.html>). Since you've included the Signed-off-by trailer it seems like you want to contribute under the terms of the DCO. > -- >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` - `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. > --- > gcc/cp/pt.cc | 12 ++++++++++ > gcc/testsuite/g++.dg/reflect/splice10.C | 28 ++++++++++++++++++++++++ > gcc/testsuite/g++.dg/reflect/splice11.C | 29 +++++++++++++++++++++++++ > 3 files changed, 69 insertions(+) > 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..333ecc3130 100644 > --- a/gcc/cp/pt.cc > +++ b/gcc/cp/pt.cc > @@ -16771,6 +16771,18 @@ 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 (TREE_CODE (op) == FIELD_DECL > + || DECL_OBJECT_MEMBER_FUNCTION_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 0000000000..2f335ea8fc > --- /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 0000000000..b62fdcc5ee > --- /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); > -- > 2.51.1 > Marek
