On 2/11/26 3:14 AM, 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:
-- >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))

I'm going to shorten this to DECL_NONSTATIC_MEMBER_P.

Pushed with that tweak.

Jason

Reply via email to