[PATCH v2] c++/reflection: ICE with &template [:members_of():] [PR124794]

Marek Polacek <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
On Thu, Jul 30, 2026 at 09:35:26AM -0400, Jason Merrill wrote:
> On 7/28/26 1:34 PM, Marek Polacek wrote:
> > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/16?
> > 
> > -- >8 --
> > Given
> > 
> >    struct C { template <class T> void f(T); };
> > 
> > we handle "&template [:^^C::f:]" correctly because the spliced
> > expression is
> > 
> >    BASELINK<OVERLOAD<TEMPLATE_DECL f>>, binfo C>
> > 
> > which is fine: we have an OVERLOAD around the TEMPLATE_DECL and
> > lookup_member wrapped the whole thing in a BASELINK.  But when
> > we're splicing members_of(^^C, ac)[0], we ended up with
> > 
> >    OVERLOAD<TEMPLATE_DECL f>>
> > 
> > and then go down the wrong path in cp_parser_splice_expression.
> > 
> > splice already correctly adds the missing OVERLOAD but it also
> > needs to (maybe) add a BASELINK.
> 
> Yes, though I'm nervous about the use of currently_open_derived_class in
> baselink_for_fns.  Does that cause trouble with a splice after ->?

We test a splice after -> in e.g. member1.C and member3.C and they still pass.

And given

  struct C {
    void g (int);
  };

  C *pc = ...;

this

  auto a = &pc->[: ^^C::g :];

is invalid (clang++ also rejects).

...but we don't have a test for a valid &p->[: x :] so this
version adds it.

-- >8 --
Given

  struct C { template <class T> void f(T); };

we handle "&template [:^^C::f:]" correctly because the spliced
expression is

  BASELINK<OVERLOAD<TEMPLATE_DECL f>>, binfo C>

which is fine: we have an OVERLOAD around the TEMPLATE_DECL and
lookup_member wrapped the whole thing in a BASELINK.  But when
we're splicing members_of(^^C, ac)[0], we ended up with

  OVERLOAD<TEMPLATE_DECL f>>

and then go down the wrong path in cp_parser_splice_expression.

splice already correctly adds the missing OVERLOAD but it also
needs to (maybe) add a BASELINK.

	PR c++/124794

gcc/cp/ChangeLog:

	* reflect.cc (splice): Call baselink_for_fns.

gcc/testsuite/ChangeLog:

	* g++.dg/reflect/splice17.C: New test.
---
 gcc/cp/reflect.cc                       |  3 +++
 gcc/testsuite/g++.dg/reflect/splice17.C | 28 +++++++++++++++++++++++++
 2 files changed, 31 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/reflect/splice17.C

diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc
index 989d7cebc77..4677672526b 100644
--- a/gcc/cp/reflect.cc
+++ b/gcc/cp/reflect.cc
@@ -8790,6 +8790,9 @@ splice (tree refl)
      it comes from e.g. members_of it is not.  */
   if (DECL_FUNCTION_TEMPLATE_P (refl))
     refl = ovl_make (refl, NULL_TREE);
+  /* Also add a BASELINK so that we handle &[:R:].  */
+  if (is_overloaded_fn (refl))
+    refl = baselink_for_fns (refl);
 
   return refl;
 }
diff --git a/gcc/testsuite/g++.dg/reflect/splice17.C b/gcc/testsuite/g++.dg/reflect/splice17.C
new file mode 100644
index 00000000000..da3841100c6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/splice17.C
@@ -0,0 +1,28 @@
+// PR c++/124794
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+struct C {
+  template <class T> void f(T);
+  void g (int);
+
+  static constexpr int val = 42;
+};
+constexpr auto ac = std::meta::access_context::current();
+constexpr auto f1 = members_of(^^C, ac)[0];
+constexpr auto f2 = ^^C::f;
+void (C::*p1)(int) = &template [:f1:];
+void (C::*p2)(int) = &template [:f2:];
+
+constexpr auto g1 = members_of(^^C, ac)[1];
+constexpr auto g2 = ^^C::g;
+void (C::*p3)(int) = &[:g1:];
+void (C::*p4)(int) = &[:g2:];
+
+void
+g (C *pc)
+{
+  const int *p = &pc->[: ^^C::val :];
+}

base-commit: 667c1b70ac3955c9ac7ccab60cc10b32d4bed5ff
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.