From: Marek Polacek Date: Fri, 13 Mar 2026 12:19:26 +0000 (-0400) Subject: c++/reflection: mangling dependent splices [PR123237] X-Git-Tag: basepoints/gcc-17~212 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=16354b6adaf1d441c33239bad0dfae8a32db4fc3;p=thirdparty%2Fgcc.git c++/reflection: mangling dependent splices [PR123237] This patch adds a mangling for dependent splices. Since the ABI discussion at hasn't gelled yet, this mangling might change in the future. In this patch I'm adding ::= DS [ ] E for all dependent splices. When we have ^^T::x, we can't say what kind of reflection this will be, so this patch emits the "de" prefix. For template template parameters we emit "tt". PR c++/123237 PR c++/124771 PR c++/124842 gcc/cp/ChangeLog: * mangle.cc (write_splice): New. (write_prefix): Call write_splice for SPLICE_SCOPE. (write_type): Likewise. (write_expression): Call write_splice for dependent_splice_p. (write_reflection): Handle the "tt" and "de" prefixes. * reflect.cc (reflection_mangle_prefix): For DECL_TEMPLATE_TEMPLATE_PARM_P, use the prefix "tt". For dependent reflections, use "de". gcc/testsuite/ChangeLog: * g++.dg/reflect/mangle2.C: New test. * g++.dg/reflect/mangle3.C: New test. * g++.dg/reflect/mangle4.C: New test. * g++.dg/reflect/mangle5.C: New test. Reviewed-by: Jason Merrill --- diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc index d1301789ef4..1cd5470a8f9 100644 --- a/gcc/cp/mangle.cc +++ b/gcc/cp/mangle.cc @@ -240,6 +240,7 @@ static void write_local_name (tree, const tree, const tree); static void dump_substitution_candidates (void); static tree mangle_decl_string (const tree); static void maybe_check_abi_tags (tree, tree = NULL_TREE, int = 10); +static void write_splice (tree); /* Control functions. */ @@ -1299,7 +1300,8 @@ write_nested_name (const tree decl) ::= ::= ::= # empty - ::= */ + ::= + ::= # C++26 dependent splice [proposed] */ static void write_prefix (const tree node) @@ -1319,6 +1321,12 @@ write_prefix (const tree node) return; } + if (TREE_CODE (node) == SPLICE_SCOPE) + { + write_splice (node); + return; + } + if (find_substitution (node)) return; @@ -2444,7 +2452,7 @@ write_local_name (tree function, const tree local_entity, ::= G # imaginary (C 2000) [not supported] ::= U # vendor extended type qualifier - C++0x extensions + C++11 extensions ::= RR # rvalue reference-to ::= Dt # decltype of an id-expression or @@ -2452,6 +2460,7 @@ write_local_name (tree function, const tree local_entity, ::= DT # decltype of an expression ::= Dn # decltype of nullptr ::= Dm # decltype of ^^int + ::= # C++26 dependent splice [proposed] TYPE is a type node. */ @@ -2734,6 +2743,10 @@ write_type (tree type) ++is_builtin_type; break; + case SPLICE_SCOPE: + write_splice (type); + break; + case TYPEOF_TYPE: sorry ("mangling %, use % instead"); break; @@ -3441,7 +3454,10 @@ range_expr_nelts (tree expr) ::= L E # external name ::= st # sizeof ::= sr # dependent name - ::= sr */ + ::= sr + ::= L Dm E # C++26 reflection + # value [proposed] + ::= # C++26 dependent splice [proposed] */ static void write_expression (tree expr) @@ -3699,6 +3715,8 @@ write_expression (tree expr) write_string ("on"); write_unqualified_id (expr); } + else if (dependent_splice_p (expr)) + write_splice (expr); else if (TREE_CODE (expr) == TEMPLATE_ID_EXPR) { tree fn = TREE_OPERAND (expr, 0); @@ -4174,7 +4192,9 @@ write_expression (tree expr) ::= co [ ] # concept ::= na [ ] # namespace alias ::= ns [ ] # namespace - ::= gs # ^^:: + ::= gs # ^^:: + ::= tt # templ templ param + ::= de # dependent expr ::= ba [ ] _ # dir. base cls rel ::= ds _ [ ] _ [ ] _ [ ] _ @@ -4286,6 +4306,41 @@ write_reflection (tree refl) for (int i = 5; i < TREE_VEC_LENGTH (arg); ++i) write_template_arg (REFLECT_EXPR_HANDLE (TREE_VEC_ELT (arg, i))); } + else if (strcmp (prefix, "tt") == 0) + { + gcc_assert (DECL_TEMPLATE_TEMPLATE_PARM_P (arg)); + write_template_template_param (TREE_TYPE (arg)); + } + else if (strcmp (prefix, "de") == 0) + write_expression (arg); + else + gcc_unreachable (); +} + +/* Mangle a dependent splice. + + ::= DS [ ] E + + TODO: This is only a proposed mangling. + See . */ + +static void +write_splice (tree sp) +{ + write_string ("DS"); + + if (TREE_CODE (sp) == SPLICE_SCOPE) + sp = SPLICE_SCOPE_EXPR (sp); + gcc_assert (dependent_splice_p (sp)); + if (TREE_CODE (sp) == TEMPLATE_ID_EXPR) + { + write_expression (TREE_OPERAND (TREE_OPERAND (sp, 0), 0)); + write_template_args (TREE_OPERAND (sp, 1)); + } + else + write_expression (TREE_OPERAND (sp, 0)); + + write_char ('E'); } /* Literal subcase of non-terminal . diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc index 06bfae27748..4ef340f0726 100644 --- a/gcc/cp/reflect.cc +++ b/gcc/cp/reflect.cc @@ -9179,6 +9179,21 @@ reflection_mangle_prefix (tree refl, char prefix[3]) strcpy (prefix, "ds"); return h; } + /* We don't have a metafunction for template template parameters. */ + if (DECL_TEMPLATE_TEMPLATE_PARM_P (h)) + { + strcpy (prefix, "tt"); + return h; + } + /* For ^^T::x, we can't say what the reflection is going to be. Just say + it's something dependent. This is at the end rather than the beginning + because potential_constant_expression_1 doesn't handle codes like + TREE_BINFO. */ + if (uses_template_parms (h)) + { + strcpy (prefix, "de"); + return h; + } gcc_unreachable (); } diff --git a/gcc/testsuite/g++.dg/reflect/mangle2.C b/gcc/testsuite/g++.dg/reflect/mangle2.C new file mode 100644 index 00000000000..452e172fcf4 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/mangle2.C @@ -0,0 +1,48 @@ +// PR c++/123237 +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } + +#include + +template +using A0 = [:^^T:]; + +template +using A1 = [:parent_of (^^T):]::B; + +namespace N { + using B = int; + struct S {}; +} +namespace D { + using B = long; + struct S {}; +} + +template +using A2 = decltype (T ().[:std::meta::nonstatic_data_members_of (^^T, std::meta::access_context::unchecked ())[0]:]); + +struct B +{ + long a; + int b; +}; + +struct C +{ + int c; + long d; +}; + + +void +g () +{ + [] requires(requires { A0 {}; }) {}(); + [] requires (requires { A1 {}; }) {} (); + [] requires (requires { A2 {}; }) {} (); +} + +// { dg-final { scan-assembler "_ZZ1gvENKUlTyQrqXtlDSLDmtyT_EEEEvE_clIiEEDav" } } +// { dg-final { scan-assembler "_ZZ1gvENKUlTyQrqXtlNDSclL_ZNSt4meta9parent_ofEDmELDmtyT_EEE1BEEEvE0_clIN1N1SEEEDav" } } +// { dg-final { scan-assembler "_ZZ1gvENKUlTyQrqXtlDtdtcvT__EDScldtclL_ZNSt4meta25nonstatic_data_members_ofEDmNS0_14access_contextEELDmtyS_EclL_ZNS1_9uncheckedEvEEEL_ZNSt6vectorIDmSaIDmEEixEmELi0EEEEEEvE1_clI1CEEDav" } } diff --git a/gcc/testsuite/g++.dg/reflect/mangle3.C b/gcc/testsuite/g++.dg/reflect/mangle3.C new file mode 100644 index 00000000000..2f901c1fb94 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/mangle3.C @@ -0,0 +1,241 @@ +// PR c++/123237 +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } +// Test mangling dependent splices. + +#include +using namespace std::meta; + +int i; +int arr[] = {1, 2, 3}; +auto [a1, a2, a3] = arr; +enum Enum { A }; +using Alias = int; + +template +struct TCls { }; + +template int TVar; + +template +struct B { + T t; + constexpr T fn () { return 42; } + template + struct C { }; + template + using U = C; +}; + +struct Y { + int i; + using type = int; +}; + +struct S : Y { }; + +namespace N { + struct NY { + int i; + }; +} + +namespace NSAlias = N; +template concept Concept = requires { true; }; +constexpr auto ctx = std::meta::access_context::current (); + +template +using US = [:^^T:]; + +template +constexpr auto f1 (typename [:R:] x) { return x; } + +template +constexpr auto f2 (typename [:R:]::NY x) { return x; } + +template +constexpr auto f3 () -> TCls { return {}; } + +template +constexpr auto f4 () -> TCls { return {}; } + +template +constexpr auto f5 () -> decltype([:R:]) { return {}; } + +template +constexpr auto f6 (US y) { return y; } + +template +constexpr auto f7 (typename [:R:]<0> x) { return x; } + +template +constexpr auto f8 (typename [:^^T:] x) { return x; } + +template +constexpr typename [:R:] f9 (int i) { return i; } + +template +constexpr T foo (T t) { return t; } + +template +constexpr auto f10 () -> decltype([:R:](42)) { return {}; } + +template +constexpr auto f11 (TCls<[:R:](42)> a) { return a; } + +template +consteval info id () { return ^^T; } + +template +constexpr typename [:id():] f12 () { return 42; } + +template +constexpr auto f13 (typename [:R:]::type x) { return x; } + +template +constexpr auto f14 () -> [:R:] { return {}; } + +template +constexpr auto f15 () -> decltype(T{}.[:R:]) { return {}; } + +template +constexpr auto f16 () -> decltype(T{}.[:R:]()) { return {}; } + +template +constexpr auto f17 () -> decltype(typename [:O:]{}.[:M:]) { return {}; } + +template +constexpr auto f18 () -> decltype(Y{}.[:M:]) { return {}; } + +template class T> +constexpr auto f19 () -> [:^^T:] { return {}; } + +template +constexpr auto f20 () -> [:^^typename T::type:] { return {}; } + +template +constexpr auto f21 () -> decltype(&[:^^T::i:]) { return {}; } + +template +constexpr auto f22 () -> decltype(&[:^^T::fn:]) { return {}; } + +template +constexpr auto f23 () -> [:^^typename T::C:] { return {}; } + +template +constexpr auto f24 () -> [:^^typename T::U:] { return {}; } + +template +constexpr auto f25 () -> decltype([:R:])* { return {}; } + +template +consteval auto f26 (typename [:^^T:] x) { return x; } + +template +constexpr auto f27 (typename [:R:]::Alias x) { return x; } + +void +g (int p) +{ + f1<^^Y>(Y{ 42 }); +// { dg-final { scan-assembler "_Z2f1ILDmty1YEEDaDST_E" } } + f1<^^Enum>(A); +// { dg-final { scan-assembler "_Z2f1ILDmty4EnumEEDaDST_E" } } + f2<^^N>(N::NY{ 42 }); +// { dg-final { scan-assembler "_Z2f2ILDmns1NEEDaNDST_E2NYE" } } + f2<^^NSAlias>(NSAlias::NY{ 42 }); +// { dg-final { scan-assembler "_Z2f2ILDmna7NSAliasEEDaNDST_E2NYE" } } + f3<^^int>(); +// { dg-final { scan-assembler "_Z2f3ILDmtyiEE4TClsIXstDST_EEEv" } } + f3<^^Alias>(); +// { dg-final { scan-assembler "_Z2f3ILDmtyiEE4TClsIXstDST_EEEv" } } + f4<^^i>(); +// { dg-final { scan-assembler "_Z2f4ILDmvr1iEE4TClsIXszDST_EEEv" } } + f4<^^arr>(); +// { dg-final { scan-assembler "_Z2f4ILDmvr3arrEE4TClsIXszDST_EEEv" } } + f4<^^a1>(); +// { dg-final { scan-assembler "_Z2f4ILDmsb2a1EE4TClsIXszDST_EEEv" } } + f4<^^A>(); +// { dg-final { scan-assembler "_Z2f4ILDmen4Enum1AEE4TClsIXszDST_EEEv" } } + f4<^^TVar>(); +// { dg-final { scan-assembler "_Z2f4ILDmvt4TVarEE4TClsIXszDST_EEEv" } } + f5<^^i>(); +// { dg-final { scan-assembler "_Z2f5ILDmvr1iEEDtDST_EEv" } } + f5<^^a1>(); +// { dg-final { scan-assembler "_Z2f5ILDmsb2a1EEDtDST_EEv" } } + f5<^^A>(); +// { dg-final { scan-assembler "_Z2f5ILDmen4Enum1AEEDtDST_EEv" } } + f5<^^TVar>(); +// { dg-final { scan-assembler "_Z2f5ILDmvt4TVarEEDtDST_EEv" } } + f5<^^Concept>(); +// { dg-final { scan-assembler "_Z2f5ILDmco7ConceptEEDtDST_EEv" } } + f5<^^p>(); +// { dg-final { scan-assembler "_Z2f5ILDmvrZ1giE1pEEDtDST_EEv" } } + f5(); +// { dg-final { scan-assembler "_Z2f5ILDmvlLi42EEEDtDST_EEv" } } + f5(); +// { dg-final { scan-assembler "_Z2f5ILDmobixL_Z3arrELl1EEEDtDST_EEv" } } + f5(); +// { dg-final { scan-assembler "_Z2f5ILDmpa_1giEEDtDST_EEv" } } + f5(); +// { dg-final { scan-assembler "_Z2f5ILDmba_1SEEDtDST_EEv" } } + f6(Y{42}); +// { dg-final { scan-assembler "_Z2f6I1YEDaDSLDmtyT_EE" } } + f7<^^TCls>(TCls<0>{}); +// { dg-final { scan-assembler "_Z2f7ILDmct4TClsEEDaDST_ILi0EEE" } } + f8(42); +// { dg-final { scan-assembler "_Z2f8IiEDaDSLDmtyT_EE" } } + f8(42); +// { dg-final { scan-assembler "_Z2f8IiEDaDSLDmtyT_EE" } } + f9<^^int>(42); +// { dg-final { scan-assembler "_Z2f9ILDmtyiEEDST_Ei" } } + f9<^^Alias>(42); +// { dg-final { scan-assembler "_Z2f9ILDmtyiEEDST_Ei" } } + f10<^^foo>(); +// { dg-final { scan-assembler "_Z3f10ILDmfn3fooIiET_S1_EEDTclDST_ELi42EEEv" } } + f10<^^foo>(); +// { dg-final { scan-assembler "_Z3f10ILDmfn3fooIiET_S1_EEDTclDST_ELi42EEEv" } } + f11<^^foo>(TCls<42>{}); +// { dg-final { scan-assembler "_Z3f11ILDmfn3fooIiET_S1_EEDa4TClsIXclDST_ELi42EEEE" } } + f11<^^foo>(TCls<42>{}); +// { dg-final { scan-assembler "_Z3f11ILDmfn3fooIiET_S1_EEDa4TClsIXclDST_ELi42EEEE" } } + f12(); +// { dg-final { scan-assembler "_Z3f12IiEDScl2idIT_EEEv" } } + f12(); +// { dg-final { scan-assembler "_Z3f12IiEDScl2idIT_EEEv" } } + f13<^^Y>(42); +// { dg-final { scan-assembler "_Z3f13ILDmty1YEEDaNDST_E4typeE" } } + f14<^^int>(); +// { dg-final { scan-assembler "_Z3f14ILDmtyiEEDST_Ev" } } + f14<^^TCls<1>>(); +// { dg-final { scan-assembler "_Z3f14ILDmty4TClsILi1EEEEDST_Ev" } } + f15(); +// { dg-final { scan-assembler "_Z3f15I1YLDmdmS0_1iEEDtdttlT_EDST0_EEv" } } + f15, ^^B::t>(); +// { dg-final { scan-assembler "_Z3f15I1BIiELDmdmS1_1tEEDtdttlT_EDST0_EEv" } } + f16, ^^B::fn>(); +// { dg-final { scan-assembler "_Z3f16I1BIiELDmfnNS1_2fnEvEEDTcldttlT_EDST0_EEEv" } } + f17<^^Y, ^^Y::i>(); +// { dg-final { scan-assembler "_Z3f17ILDmty1YELDmdmS0_1iEEDtdttlDST_EEDST0_EEv" } } + f18<^^Y::i>(); +// { dg-final { scan-assembler "_Z3f18ILDmdm1Y1iEEDtdttlS0_EDST_EEv" } } + f19(); +// { dg-final { scan-assembler "_Z3f19I1BEDSLDmttT_EIiEEv" } } + f20(); +// { dg-final { scan-assembler "_Z3f20I1YEDSLDmtyNT_4typeEEEv" } } + f21(); +// { dg-final { scan-assembler "_Z3f21I1YEDTadDSLDmdesrT_1iEEEv" } } + f22>(); +// { dg-final { scan-assembler "_Z3f22I1BIiEEDTadDSLDmdesrT_2fnEEEv" } } + f23>(); +// { dg-final { scan-assembler "_Z3f23I1BIiEEDSLDmtyNT_1CIiEEEEv" } } + f24>(); +// { dg-final { scan-assembler "_Z3f24I1BIiEEDSLDmtyNT_1UIiEEEEv" } } + f24>(); +// { dg-final { scan-assembler "_Z3f24I1BIiEEDSLDmtyNT_1UIiEEEEv" } } + f25<^^arr>(); +// { dg-final { scan-assembler "_Z3f25ILDmvr3arrEEPDtDST_EEv" } } + constexpr auto r = f26({}); + f27<^^::>(42); +// { dg-final { scan-assembler "_Z3f27ILDmgsEEDaNDST_E5AliasE" } } +} diff --git a/gcc/testsuite/g++.dg/reflect/mangle4.C b/gcc/testsuite/g++.dg/reflect/mangle4.C new file mode 100644 index 00000000000..3880468daff --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/mangle4.C @@ -0,0 +1,26 @@ +// PR c++/124771 +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } + +#include +#include + +namespace std { +template + struct iterator_accessor { + using element_type = typename [: + [] { return ^^iter_value_t; }() + :]; + + constexpr iterator_accessor() noexcept = default; + constexpr operator default_accessor() noexcept + requires contiguous_iterator && (!is_const_v) + { return {}; } + }; +} + +int main() { + // ??? It's not clear which of these should error. + std::default_accessor _ = std::iterator_accessor(); + std::default_accessor _ = std::iterator_accessor(); // { dg-error "conversion" } +} diff --git a/gcc/testsuite/g++.dg/reflect/mangle5.C b/gcc/testsuite/g++.dg/reflect/mangle5.C new file mode 100644 index 00000000000..48635634f2f --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/mangle5.C @@ -0,0 +1,25 @@ +// PR c++/124842 +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } + +#include + +inline constexpr int x = 1; +template +typename[: std::meta::type_of(r) :] f() { + return 1; +} + +int +f1 () +{ + return f<^^x>(); +// { dg-final { scan-assembler "_Z1fITnDaLDmvr1xEEDScl7type_ofT_EEv" } } +} + +int +f2 () +{ + return f(); +// { dg-final { scan-assembler "_Z1fITnDaLDmvlLi1EEEDScl7type_ofT_EEv" } } +}