c++, demangle: Implement https://github.com/itanium-cxx-abi/cxx-abi/issues/148 non-proposal
Checks
Commit Message
Hi!
The following patch attempts to implement what apparently clang++
implemented for explicit object member function mangling, but nobody
actually proposed in patch form in
https://github.com/itanium-cxx-abi/cxx-abi/issues/148
Ok for trunk if it passes full bootstrap/regtest? So far just tested
on the new testcases.
2024-01-12 Jakub Jelinek <jakub@redhat.com>
gcc/cp/
* mangle.cc (write_nested_name): Mangle explicit object
member functions with H as per
https://github.com/itanium-cxx-abi/cxx-abi/issues/148 non-proposal.
gcc/testsuite/
* g++.dg/abi/mangle79.C: New test.
include/
* demangle.h (enum demangle_component_type): Add
DEMANGLE_COMPONENT_XOBJ_MEMBER_FUNCTION.
libiberty/
* cp-demangle.c (FNQUAL_COMPONENT_CASE): Add case for
DEMANGLE_COMPONENT_XOBJ_MEMBER_FUNCTION.
(d_dump): Handle DEMANGLE_COMPONENT_XOBJ_MEMBER_FUNCTION.
(d_nested_name): Parse H after N in nested name.
(d_count_templates_scopes): Handle
DEMANGLE_COMPONENT_XOBJ_MEMBER_FUNCTION.
(d_print_mod): Likewise.
(d_print_function_type): Likewise.
* testsuite/demangle-expected: Add tests for explicit object
member functions.
Jakub
Comments
On 1/12/24 07:45, Jakub Jelinek wrote:
> Hi!
>
> The following patch attempts to implement what apparently clang++
> implemented for explicit object member function mangling, but nobody
> actually proposed in patch form in
> https://github.com/itanium-cxx-abi/cxx-abi/issues/148
>
> Ok for trunk if it passes full bootstrap/regtest? So far just tested
> on the new testcases.
OK, thanks.
> 2024-01-12 Jakub Jelinek <jakub@redhat.com>
>
> gcc/cp/
> * mangle.cc (write_nested_name): Mangle explicit object
> member functions with H as per
> https://github.com/itanium-cxx-abi/cxx-abi/issues/148 non-proposal.
> gcc/testsuite/
> * g++.dg/abi/mangle79.C: New test.
> include/
> * demangle.h (enum demangle_component_type): Add
> DEMANGLE_COMPONENT_XOBJ_MEMBER_FUNCTION.
> libiberty/
> * cp-demangle.c (FNQUAL_COMPONENT_CASE): Add case for
> DEMANGLE_COMPONENT_XOBJ_MEMBER_FUNCTION.
> (d_dump): Handle DEMANGLE_COMPONENT_XOBJ_MEMBER_FUNCTION.
> (d_nested_name): Parse H after N in nested name.
> (d_count_templates_scopes): Handle
> DEMANGLE_COMPONENT_XOBJ_MEMBER_FUNCTION.
> (d_print_mod): Likewise.
> (d_print_function_type): Likewise.
> * testsuite/demangle-expected: Add tests for explicit object
> member functions.
>
> --- gcc/cp/mangle.cc.jj 2024-01-12 10:07:31.248231747 +0100
> +++ gcc/cp/mangle.cc 2024-01-12 11:37:35.790915463 +0100
> @@ -1247,6 +1247,8 @@ write_nested_name (const tree decl)
> write_char ('R');
> }
> }
> + else if (DECL_XOBJ_MEMBER_FUNCTION_P (decl))
> + write_char ('H');
>
> /* Is this a template instance? */
> if (tree info = maybe_template_info (decl))
> --- gcc/testsuite/g++.dg/abi/mangle79.C.jj 2024-01-12 13:18:20.782917924 +0100
> +++ gcc/testsuite/g++.dg/abi/mangle79.C 2024-01-12 13:26:01.297433970 +0100
> @@ -0,0 +1,61 @@
> +// { dg-do compile { target c++11 } }
> +// { dg-options "" }
> +
> +struct S {
> + static void foo (S);
> + void foo (this S); // { dg-warning "explicit object member function only available with" "" { target c++20_down } }
> + template <int N, typename T>
> + static void bar (S, T);
> + template <int N, typename T>
> + void bar (this S, T); // { dg-warning "explicit object member function only available with" "" { target c++20_down } }
> + static void baz (const S &);
> + void baz (this const S &); // { dg-warning "explicit object member function only available with" "" { target c++20_down } }
> +};
> +
> +void
> +S::foo (S)
> +{
> +}
> +
> +void
> +S::foo (this S) // { dg-warning "explicit object member function only available with" "" { target c++20_down } }
> +{
> +}
> +
> +template <int N, typename T>
> +void
> +S::bar (S, T)
> +{
> +}
> +
> +template <int N, typename T>
> +void
> +S::bar (this S, T) // { dg-warning "explicit object member function only available with" "" { target c++20_down } }
> +{
> +}
> +
> +void
> +S::baz (const S &)
> +{
> +}
> +
> +void
> +S::baz (this const S &) // { dg-warning "explicit object member function only available with" "" { target c++20_down } }
> +{
> +}
> +
> +void
> +qux (S *p)
> +{
> + S::foo (*p);
> + p->foo ();
> + S::bar <5> (*p, 0);
> + p->bar <5> (0);
> +}
> +
> +// { dg-final { scan-assembler "_ZN1S3fooES_" } }
> +// { dg-final { scan-assembler "_ZNH1S3fooES_" } }
> +// { dg-final { scan-assembler "_ZN1S3barILi5EiEEvS_T0_" } }
> +// { dg-final { scan-assembler "_ZNH1S3barILi5EiEEvS_T0_" } }
> +// { dg-final { scan-assembler "_ZN1S3bazERKS_" } }
> +// { dg-final { scan-assembler "_ZNH1S3bazERKS_" } }
> --- include/demangle.h.jj 2024-01-03 12:07:25.330409694 +0100
> +++ include/demangle.h 2024-01-12 11:43:27.543915280 +0100
> @@ -314,6 +314,8 @@ enum demangle_component_type
> /* C++11: An rvalue reference modifying a member function. The one
> subtree is the type which is being referenced. */
> DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS,
> + /* C++23: A member function with explict object parameter. */
> + DEMANGLE_COMPONENT_XOBJ_MEMBER_FUNCTION,
> /* A vendor qualifier. The left subtree is the type which is being
> qualified, and the right subtree is the name of the
> qualifier. */
> --- libiberty/cp-demangle.c.jj 2024-01-03 12:07:48.498085118 +0100
> +++ libiberty/cp-demangle.c 2024-01-12 13:06:04.526281733 +0100
> @@ -581,6 +581,7 @@ static char *d_demangle (const char *, i
> case DEMANGLE_COMPONENT_CONST_THIS: \
> case DEMANGLE_COMPONENT_REFERENCE_THIS: \
> case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: \
> + case DEMANGLE_COMPONENT_XOBJ_MEMBER_FUNCTION: \
> case DEMANGLE_COMPONENT_TRANSACTION_SAFE: \
> case DEMANGLE_COMPONENT_NOEXCEPT: \
> case DEMANGLE_COMPONENT_THROW_SPEC
> @@ -749,6 +750,9 @@ d_dump (struct demangle_component *dc, i
> case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
> printf ("rvalue reference this\n");
> break;
> + case DEMANGLE_COMPONENT_XOBJ_MEMBER_FUNCTION:
> + printf ("explicit object parameter\n");
> + break;
> case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
> printf ("transaction_safe this\n");
> break;
> @@ -1547,6 +1551,8 @@ d_name (struct d_info *di, int substable
>
> /* <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
> ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
> + ::= N H <prefix> <unqualified-name> E
> + ::= N H <template-prefix> <template-args> E
> */
>
> static struct demangle_component *
> @@ -1559,13 +1565,24 @@ d_nested_name (struct d_info *di)
> if (! d_check_char (di, 'N'))
> return NULL;
>
> - pret = d_cv_qualifiers (di, &ret, 1);
> - if (pret == NULL)
> - return NULL;
> + if (d_peek_char (di) == 'H')
> + {
> + d_advance (di, 1);
> + di->expansion += sizeof "this";
> + pret = &ret;
> + rqual = d_make_comp (di, DEMANGLE_COMPONENT_XOBJ_MEMBER_FUNCTION,
> + NULL, NULL);
> + }
> + else
> + {
> + pret = d_cv_qualifiers (di, &ret, 1);
> + if (pret == NULL)
> + return NULL;
>
> - /* Parse the ref-qualifier now and then attach it
> - once we have something to attach it to. */
> - rqual = d_ref_qualifier (di, NULL);
> + /* Parse the ref-qualifier now and then attach it
> + once we have something to attach it to. */
> + rqual = d_ref_qualifier (di, NULL);
> + }
>
> *pret = d_prefix (di, 1);
> if (*pret == NULL)
> @@ -4427,6 +4444,7 @@ d_count_templates_scopes (struct d_print
> case DEMANGLE_COMPONENT_CONST_THIS:
> case DEMANGLE_COMPONENT_REFERENCE_THIS:
> case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
> + case DEMANGLE_COMPONENT_XOBJ_MEMBER_FUNCTION:
> case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
> case DEMANGLE_COMPONENT_NOEXCEPT:
> case DEMANGLE_COMPONENT_THROW_SPEC:
> @@ -6521,6 +6539,8 @@ d_print_mod (struct d_print_info *dpi, i
> case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
> d_append_string (dpi, "&&");
> return;
> + case DEMANGLE_COMPONENT_XOBJ_MEMBER_FUNCTION:
> + return;
> case DEMANGLE_COMPONENT_COMPLEX:
> d_append_string (dpi, " _Complex");
> return;
> @@ -6559,11 +6579,13 @@ d_print_function_type (struct d_print_in
> {
> int need_paren;
> int need_space;
> + int xobj_memfn;
> struct d_print_mod *p;
> struct d_print_mod *hold_modifiers;
>
> need_paren = 0;
> need_space = 0;
> + xobj_memfn = 0;
> for (p = mods; p != NULL; p = p->next)
> {
> if (p->printed)
> @@ -6586,7 +6608,8 @@ d_print_function_type (struct d_print_in
> need_space = 1;
> need_paren = 1;
> break;
> - FNQUAL_COMPONENT_CASE:
> + case DEMANGLE_COMPONENT_XOBJ_MEMBER_FUNCTION:
> + xobj_memfn = 1;
> break;
> default:
> break;
> @@ -6617,6 +6640,8 @@ d_print_function_type (struct d_print_in
> d_append_char (dpi, ')');
>
> d_append_char (dpi, '(');
> + if (xobj_memfn)
> + d_append_string (dpi, "this ");
>
> if (d_right (dc) != NULL)
> d_print_comp (dpi, options, d_right (dc));
> --- libiberty/testsuite/demangle-expected.jj 2023-12-03 17:44:57.266453553 +0100
> +++ libiberty/testsuite/demangle-expected 2024-01-12 12:22:56.647587418 +0100
> @@ -1700,3 +1700,12 @@ void f<int>() requires C<int>
> # requires after ()
> _Z1fIiEvvQ1CIT_E
> void f<int>() requires C<int>
> +
> +_ZNH1S3fooES_
> +S::foo(this S)
> +
> +_ZNH1S3barILi5EiEEvS_T0_
> +void S::bar<5, int>(this S, int)
> +
> +_ZNH1S3bazERKS_
> +S::baz(this S const&)
>
> Jakub
>
@@ -1247,6 +1247,8 @@ write_nested_name (const tree decl)
write_char ('R');
}
}
+ else if (DECL_XOBJ_MEMBER_FUNCTION_P (decl))
+ write_char ('H');
/* Is this a template instance? */
if (tree info = maybe_template_info (decl))
@@ -0,0 +1,61 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct S {
+ static void foo (S);
+ void foo (this S); // { dg-warning "explicit object member function only available with" "" { target c++20_down } }
+ template <int N, typename T>
+ static void bar (S, T);
+ template <int N, typename T>
+ void bar (this S, T); // { dg-warning "explicit object member function only available with" "" { target c++20_down } }
+ static void baz (const S &);
+ void baz (this const S &); // { dg-warning "explicit object member function only available with" "" { target c++20_down } }
+};
+
+void
+S::foo (S)
+{
+}
+
+void
+S::foo (this S) // { dg-warning "explicit object member function only available with" "" { target c++20_down } }
+{
+}
+
+template <int N, typename T>
+void
+S::bar (S, T)
+{
+}
+
+template <int N, typename T>
+void
+S::bar (this S, T) // { dg-warning "explicit object member function only available with" "" { target c++20_down } }
+{
+}
+
+void
+S::baz (const S &)
+{
+}
+
+void
+S::baz (this const S &) // { dg-warning "explicit object member function only available with" "" { target c++20_down } }
+{
+}
+
+void
+qux (S *p)
+{
+ S::foo (*p);
+ p->foo ();
+ S::bar <5> (*p, 0);
+ p->bar <5> (0);
+}
+
+// { dg-final { scan-assembler "_ZN1S3fooES_" } }
+// { dg-final { scan-assembler "_ZNH1S3fooES_" } }
+// { dg-final { scan-assembler "_ZN1S3barILi5EiEEvS_T0_" } }
+// { dg-final { scan-assembler "_ZNH1S3barILi5EiEEvS_T0_" } }
+// { dg-final { scan-assembler "_ZN1S3bazERKS_" } }
+// { dg-final { scan-assembler "_ZNH1S3bazERKS_" } }
@@ -314,6 +314,8 @@ enum demangle_component_type
/* C++11: An rvalue reference modifying a member function. The one
subtree is the type which is being referenced. */
DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS,
+ /* C++23: A member function with explict object parameter. */
+ DEMANGLE_COMPONENT_XOBJ_MEMBER_FUNCTION,
/* A vendor qualifier. The left subtree is the type which is being
qualified, and the right subtree is the name of the
qualifier. */
@@ -581,6 +581,7 @@ static char *d_demangle (const char *, i
case DEMANGLE_COMPONENT_CONST_THIS: \
case DEMANGLE_COMPONENT_REFERENCE_THIS: \
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: \
+ case DEMANGLE_COMPONENT_XOBJ_MEMBER_FUNCTION: \
case DEMANGLE_COMPONENT_TRANSACTION_SAFE: \
case DEMANGLE_COMPONENT_NOEXCEPT: \
case DEMANGLE_COMPONENT_THROW_SPEC
@@ -749,6 +750,9 @@ d_dump (struct demangle_component *dc, i
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
printf ("rvalue reference this\n");
break;
+ case DEMANGLE_COMPONENT_XOBJ_MEMBER_FUNCTION:
+ printf ("explicit object parameter\n");
+ break;
case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
printf ("transaction_safe this\n");
break;
@@ -1547,6 +1551,8 @@ d_name (struct d_info *di, int substable
/* <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
+ ::= N H <prefix> <unqualified-name> E
+ ::= N H <template-prefix> <template-args> E
*/
static struct demangle_component *
@@ -1559,13 +1565,24 @@ d_nested_name (struct d_info *di)
if (! d_check_char (di, 'N'))
return NULL;
- pret = d_cv_qualifiers (di, &ret, 1);
- if (pret == NULL)
- return NULL;
+ if (d_peek_char (di) == 'H')
+ {
+ d_advance (di, 1);
+ di->expansion += sizeof "this";
+ pret = &ret;
+ rqual = d_make_comp (di, DEMANGLE_COMPONENT_XOBJ_MEMBER_FUNCTION,
+ NULL, NULL);
+ }
+ else
+ {
+ pret = d_cv_qualifiers (di, &ret, 1);
+ if (pret == NULL)
+ return NULL;
- /* Parse the ref-qualifier now and then attach it
- once we have something to attach it to. */
- rqual = d_ref_qualifier (di, NULL);
+ /* Parse the ref-qualifier now and then attach it
+ once we have something to attach it to. */
+ rqual = d_ref_qualifier (di, NULL);
+ }
*pret = d_prefix (di, 1);
if (*pret == NULL)
@@ -4427,6 +4444,7 @@ d_count_templates_scopes (struct d_print
case DEMANGLE_COMPONENT_CONST_THIS:
case DEMANGLE_COMPONENT_REFERENCE_THIS:
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_XOBJ_MEMBER_FUNCTION:
case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
case DEMANGLE_COMPONENT_NOEXCEPT:
case DEMANGLE_COMPONENT_THROW_SPEC:
@@ -6521,6 +6539,8 @@ d_print_mod (struct d_print_info *dpi, i
case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
d_append_string (dpi, "&&");
return;
+ case DEMANGLE_COMPONENT_XOBJ_MEMBER_FUNCTION:
+ return;
case DEMANGLE_COMPONENT_COMPLEX:
d_append_string (dpi, " _Complex");
return;
@@ -6559,11 +6579,13 @@ d_print_function_type (struct d_print_in
{
int need_paren;
int need_space;
+ int xobj_memfn;
struct d_print_mod *p;
struct d_print_mod *hold_modifiers;
need_paren = 0;
need_space = 0;
+ xobj_memfn = 0;
for (p = mods; p != NULL; p = p->next)
{
if (p->printed)
@@ -6586,7 +6608,8 @@ d_print_function_type (struct d_print_in
need_space = 1;
need_paren = 1;
break;
- FNQUAL_COMPONENT_CASE:
+ case DEMANGLE_COMPONENT_XOBJ_MEMBER_FUNCTION:
+ xobj_memfn = 1;
break;
default:
break;
@@ -6617,6 +6640,8 @@ d_print_function_type (struct d_print_in
d_append_char (dpi, ')');
d_append_char (dpi, '(');
+ if (xobj_memfn)
+ d_append_string (dpi, "this ");
if (d_right (dc) != NULL)
d_print_comp (dpi, options, d_right (dc));
@@ -1700,3 +1700,12 @@ void f<int>() requires C<int>
# requires after ()
_Z1fIiEvvQ1CIT_E
void f<int>() requires C<int>
+
+_ZNH1S3fooES_
+S::foo(this S)
+
+_ZNH1S3barILi5EiEEvS_T0_
+void S::bar<5, int>(this S, int)
+
+_ZNH1S3bazERKS_
+S::baz(this S const&)