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);

Reply via email to