[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