demangler: Templated lambda demangling

Templated lambdas have a template-head, which is part of their
signature.  GCC ABI 18 mangles that into the lambda name.  This adds
support to the demangler.  We have to introduce artificial template
parameter names, as we need to refer to them from later components of
the lambda signature. We use $T:n, $N:n and $TT:n for type, non-type
and template parameters.  Non-type parameter names are not shown in
the strictly correct location -- for instance 'int (&NT) ()' would be
shown as 'int (&) $N:n'.  That's unfortunate, but an orthogonal issue.
The 'is_lambda_arg' field is now repurposed as indicating the number
of explicit template parameters (1-based).

	include/
	* demangle.h (enum demangle_component_type): Add
	DEMANGLE_COMPONENT_TEMPLATE_HEAD,
	DEMANGLE_COMPONENT_TEMPLATE_TYPE_PARM,
	DEMANGLE_COMPONENT_TEMPLATE_NON_TYPE_PARM,
	DEMANGLE_COMPONENT_TEMPLATE_TEMPLATE_PARM,
	DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM.
	libiberty/
	* cp-demangle.c (struct d_print_info): Rename is_lambda_arg to
	lambda_tpl_parms.  Augment semantics.
	(d_make_comp): Add checks for new components.
	(d_template_parm, d_template_head): New.
	(d_lambda): Add templated lambda support.
	(d_print_init): Adjust.
	(d_print_lambda_parm_name): New.
	(d_print_comp_inner): Support templated lambdas,
	* testsuite/demangle-expected: Add testcases.
This commit is contained in:
Nathan Sidwell 2022-11-07 11:24:14 -05:00
parent ee08aa9ab4
commit 46c3d9c8e8
3 changed files with 295 additions and 24 deletions

View File

@ -458,6 +458,12 @@ enum demangle_component_type
DEMANGLE_COMPONENT_MODULE_ENTITY,
DEMANGLE_COMPONENT_MODULE_INIT,
DEMANGLE_COMPONENT_TEMPLATE_HEAD,
DEMANGLE_COMPONENT_TEMPLATE_TYPE_PARM,
DEMANGLE_COMPONENT_TEMPLATE_NON_TYPE_PARM,
DEMANGLE_COMPONENT_TEMPLATE_TEMPLATE_PARM,
DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM,
/* A builtin type with argument. This holds the builtin type
information. */
DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE

View File

@ -347,9 +347,9 @@ struct d_print_info
/* Number of times d_print_comp was recursively called. Should not
be bigger than MAX_RECURSION_COUNT. */
int recursion;
/* Non-zero if we're printing a lambda argument. A template
parameter reference actually means 'auto', a pack expansion means T... */
int is_lambda_arg;
/* 1 more than the number of explicit template parms of a lambda. Template
parm references >= are actually 'auto'. */
int lambda_tpl_parms;
/* The current index into any template argument packs we are using
for printing, or -1 to print the whole pack. */
int pack_index;
@ -491,6 +491,10 @@ static struct demangle_component *d_local_name (struct d_info *);
static int d_discriminator (struct d_info *);
static struct demangle_component *d_template_parm (struct d_info *, int *bad);
static struct demangle_component *d_template_head (struct d_info *, int *bad);
static struct demangle_component *d_lambda (struct d_info *);
static struct demangle_component *d_unnamed_type (struct d_info *);
@ -1028,6 +1032,10 @@ d_make_comp (struct d_info *di, enum demangle_component_type type,
case DEMANGLE_COMPONENT_TPARM_OBJ:
case DEMANGLE_COMPONENT_STRUCTURED_BINDING:
case DEMANGLE_COMPONENT_MODULE_INIT:
case DEMANGLE_COMPONENT_TEMPLATE_HEAD:
case DEMANGLE_COMPONENT_TEMPLATE_NON_TYPE_PARM:
case DEMANGLE_COMPONENT_TEMPLATE_TEMPLATE_PARM:
case DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM:
if (left == NULL)
return NULL;
break;
@ -1050,6 +1058,7 @@ d_make_comp (struct d_info *di, enum demangle_component_type type,
case DEMANGLE_COMPONENT_CONST:
case DEMANGLE_COMPONENT_ARGLIST:
case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
case DEMANGLE_COMPONENT_TEMPLATE_TYPE_PARM:
FNQUAL_COMPONENT_CASE:
break;
@ -3877,32 +3886,120 @@ d_discriminator (struct d_info *di)
return 1;
}
/* <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ */
/* <template-parm> ::= Ty
::= Tn <type>
::= Tt <template-head> E
::= Tp <template-parm> */
static struct demangle_component *
d_template_parm (struct d_info *di, int *bad)
{
if (d_peek_char (di) != 'T')
return NULL;
struct demangle_component *op;
enum demangle_component_type kind;
switch (d_peek_next_char (di))
{
default:
return NULL;
case 'p': /* Pack */
d_advance (di, 2);
op = d_template_parm (di, bad);
kind = DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM;
if (!op)
{
*bad = 1;
return NULL;
}
break;
case 'y': /* Typename */
d_advance (di, 2);
op = NULL;
kind = DEMANGLE_COMPONENT_TEMPLATE_TYPE_PARM;
break;
case 'n': /* Non-Type */
d_advance (di, 2);
op = cplus_demangle_type (di);
kind = DEMANGLE_COMPONENT_TEMPLATE_NON_TYPE_PARM;
if (!op)
{
*bad = 1;
return NULL;
}
break;
case 't': /* Template */
d_advance (di, 2);
op = d_template_head (di, bad);
kind = DEMANGLE_COMPONENT_TEMPLATE_TEMPLATE_PARM;
if (!op || !d_check_char (di, 'E'))
{
*bad = 1;
return NULL;
}
}
return d_make_comp (di, kind, op, NULL);
}
/* <template-head> ::= <template-head>? <template-parm> */
static struct demangle_component *
d_template_head (struct d_info *di, int *bad)
{
struct demangle_component *res = NULL, **slot = &res;
struct demangle_component *op;
while ((op = d_template_parm (di, bad)))
{
*slot = op;
slot = &d_right (op);
}
/* Wrap it in a template head, to make concatenating with any parm list, and
printing simpler. */
if (res)
res = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE_HEAD, res, NULL);
return res;
}
/* <closure-type-name> ::= Ul <template-head>? <lambda-sig> E [ <nonnegative number> ] _ */
static struct demangle_component *
d_lambda (struct d_info *di)
{
struct demangle_component *tl;
struct demangle_component *ret;
int num;
if (! d_check_char (di, 'U'))
return NULL;
if (! d_check_char (di, 'l'))
return NULL;
tl = d_parmlist (di);
int bad = 0;
struct demangle_component *head = d_template_head (di, &bad);
if (bad)
return NULL;
struct demangle_component *tl = d_parmlist (di);
if (tl == NULL)
return NULL;
if (head)
{
d_right (head) = tl;
tl = head;
}
if (! d_check_char (di, 'E'))
return NULL;
num = d_compact_number (di);
int num = d_compact_number (di);
if (num < 0)
return NULL;
ret = d_make_empty (di);
struct demangle_component *ret = d_make_empty (di);
if (ret)
{
ret->type = DEMANGLE_COMPONENT_LAMBDA;
@ -4254,6 +4351,11 @@ d_count_templates_scopes (struct d_print_info *dpi,
case DEMANGLE_COMPONENT_MODULE_PARTITION:
case DEMANGLE_COMPONENT_MODULE_INIT:
case DEMANGLE_COMPONENT_FIXED_TYPE:
case DEMANGLE_COMPONENT_TEMPLATE_HEAD:
case DEMANGLE_COMPONENT_TEMPLATE_TYPE_PARM:
case DEMANGLE_COMPONENT_TEMPLATE_NON_TYPE_PARM:
case DEMANGLE_COMPONENT_TEMPLATE_TEMPLATE_PARM:
case DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM:
break;
case DEMANGLE_COMPONENT_TEMPLATE:
@ -4384,7 +4486,7 @@ d_print_init (struct d_print_info *dpi, demangle_callbackref callback,
dpi->demangle_failure = 0;
dpi->recursion = 0;
dpi->is_lambda_arg = 0;
dpi->lambda_tpl_parms = 0;
dpi->component_stack = NULL;
@ -4881,6 +4983,33 @@ d_maybe_print_designated_init (struct d_print_info *dpi, int options,
return 1;
}
static void
d_print_lambda_parm_name (struct d_print_info *dpi, int type, unsigned index)
{
const char *str;
switch (type)
{
default:
dpi->demangle_failure = 1;
str = "";
break;
case DEMANGLE_COMPONENT_TEMPLATE_TYPE_PARM:
str = "$T";
break;
case DEMANGLE_COMPONENT_TEMPLATE_NON_TYPE_PARM:
str = "$N";
break;
case DEMANGLE_COMPONENT_TEMPLATE_TEMPLATE_PARM:
str = "$TT";
break;
}
d_append_string (dpi, str);
d_append_num (dpi, index);
}
/* Subroutine to handle components. */
static void
@ -5135,7 +5264,21 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
}
case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
if (dpi->is_lambda_arg)
if (dpi->lambda_tpl_parms > dc->u.s_number.number + 1)
{
const struct demangle_component *a
= d_left (dpi->templates->template_decl);
unsigned c;
for (c = dc->u.s_number.number; a && c; c--)
a = d_right (a);
if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM)
a = d_left (a);
if (!a)
dpi->demangle_failure = 1;
else
d_print_lambda_parm_name (dpi, a->type, dc->u.s_number.number);
}
else if (dpi->lambda_tpl_parms)
{
/* Show the template parm index, as that's how g++ displays
these, and future proofs us against potential
@ -5316,7 +5459,7 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
{
/* Handle reference smashing: & + && = &. */
struct demangle_component *sub = d_left (dc);
if (!dpi->is_lambda_arg
if (!dpi->lambda_tpl_parms
&& sub->type == DEMANGLE_COMPONENT_TEMPLATE_PARAM)
{
struct d_saved_scope *scope = d_get_saved_scope (dpi, sub);
@ -5942,7 +6085,7 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
{
struct demangle_component *a = NULL;
if (!dpi->is_lambda_arg)
if (!dpi->lambda_tpl_parms)
a = d_find_pack (dpi, d_left (dc));
if (a == NULL)
{
@ -5994,15 +6137,50 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
return;
case DEMANGLE_COMPONENT_LAMBDA:
d_append_string (dpi, "{lambda(");
/* Generic lambda auto parms are mangled as the template type
parm they are. */
dpi->is_lambda_arg++;
d_print_comp (dpi, options, dc->u.s_unary_num.sub);
dpi->is_lambda_arg--;
d_append_string (dpi, ")#");
d_append_num (dpi, dc->u.s_unary_num.num + 1);
d_append_char (dpi, '}');
{
d_append_string (dpi, "{lambda");
struct demangle_component *parms = dc->u.s_unary_num.sub;
struct d_print_template dpt;
/* Generic lambda auto parms are mangled as the (synthedic) template
type parm they are. We need to tell the printer that (a) we're in
a lambda, and (b) the number of synthetic parms. */
int saved_tpl_parms = dpi->lambda_tpl_parms;
dpi->lambda_tpl_parms = 0;
/* Hang any lambda head as-if template args. */
dpt.template_decl = NULL;
dpt.next = dpi->templates;
dpi->templates = &dpt;
if (parms && parms->type == DEMANGLE_COMPONENT_TEMPLATE_HEAD)
{
dpt.template_decl = parms;
d_append_char (dpi, '<');
struct demangle_component *parm;
for (parm = d_left (parms); parm; parm = d_right (parm))
{
if (dpi->lambda_tpl_parms++)
d_append_string (dpi, ", ");
d_print_comp (dpi, options, parm);
d_append_char (dpi, ' ');
if (parm->type == DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM)
parm = d_left (parm);
d_print_lambda_parm_name (dpi, parm->type,
dpi->lambda_tpl_parms - 1);
}
d_append_char (dpi, '>');
parms = d_right (parms);
}
dpi->lambda_tpl_parms++;
d_append_char (dpi, '(');
d_print_comp (dpi, options, parms);
dpi->lambda_tpl_parms = saved_tpl_parms;
dpi->templates = dpt.next;
d_append_string (dpi, ")#");
d_append_num (dpi, dc->u.s_unary_num.num + 1);
d_append_char (dpi, '}');
}
return;
case DEMANGLE_COMPONENT_UNNAMED_TYPE:
@ -6018,6 +6196,40 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
d_append_char (dpi, ']');
return;
case DEMANGLE_COMPONENT_TEMPLATE_HEAD:
{
d_append_char (dpi, '<');
int count = 0;
struct demangle_component *parm;
for (parm = d_left (dc); parm; parm = d_right (parm))
{
if (count++)
d_append_string (dpi, ", ");
d_print_comp (dpi, options, parm);
}
d_append_char (dpi, '>');
}
return;
case DEMANGLE_COMPONENT_TEMPLATE_TYPE_PARM:
d_append_string (dpi, "typename");
return;
case DEMANGLE_COMPONENT_TEMPLATE_NON_TYPE_PARM:
d_print_comp (dpi, options, d_left (dc));
return;
case DEMANGLE_COMPONENT_TEMPLATE_TEMPLATE_PARM:
d_append_string (dpi, "template");
d_print_comp (dpi, options, d_left (dc));
d_append_string (dpi, " class");
return;
case DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM:
d_print_comp (dpi, options, d_left (dc));
d_append_string (dpi, "...");
return;
default:
d_print_error (dpi);
return;

View File

@ -1606,3 +1606,56 @@ int foo<q::{lambda()#1}, q::{lambda()#2}>(q::{lambda()#1}&&, q::{lambda()#2}&&)
_ZNK2L1MUlDpT_E_clIJiPiEEEvS1_
void L1::{lambda((auto:1)...)#1}::operator()<int, int*>(int, int*) const
_ZZN1XIfLj0EE2FnEvENKUlTyfT_E_clIiEEDafS1_
auto X<float, 0u>::Fn()::{lambda<typename $T0>(float, $T0)#1}::operator()<int>(float, int) const
_ZZN1XIfLj0EE2FnEvENKUlTyT_E_clIiEEDaS1_
auto X<float, 0u>::Fn()::{lambda<typename $T0>($T0)#1}::operator()<int>(int) const
_ZZN1XIfLj1EE2FnEvENKUlTyfT_E_clIiEEDafS1_
auto X<float, 1u>::Fn()::{lambda<typename $T0>(float, $T0)#1}::operator()<int>(float, int) const
_ZZN1XIfLj1EE2FnEvENKUlTyT_E_clIiEEDaS1_
auto X<float, 1u>::Fn()::{lambda<typename $T0>($T0)#1}::operator()<int>(int) const
_ZZN1XIiLj0EE2FnEvENKUlTyiT_E_clIiEEDaiS1_
auto X<int, 0u>::Fn()::{lambda<typename $T0>(int, $T0)#1}::operator()<int>(int, int) const
_ZZN1XIiLj0EE2FnEvENKUlTyT_E_clIiEEDaS1_
auto X<int, 0u>::Fn()::{lambda<typename $T0>($T0)#1}::operator()<int>(int) const
_ZNK10l_tpl_autoMUlTyT_T0_E_clIiiEEDaS0_S1_
auto l_tpl_auto::{lambda<typename $T0>($T0, auto:2)#1}::operator()<int, int>(int, int) const
_ZNK12l_tpl_nt_aryMUlTniRAT__iE_clILi2EEEDaS1_
auto l_tpl_nt_ary::{lambda<int $N0>(int (&) [$N0])#1}::operator()<2>(int (&) [2]) const
_ZNK13l_tpl_nt_autoMUlTnDavE_clILi0EEEDav
auto l_tpl_nt_auto::{lambda<auto $N0>()#1}::operator()<0>() const
_ZNK9l_tpl_tplMUlTtTyTnjER3TPLIT_EE_clI1UEEDaS3_
auto l_tpl_tpl::{lambda<template<typename, unsigned int> class $TT0>(TPL<$TT0>&)#1}::operator()<U>(TPL<U>&) const
_ZNK13l_tpl_tpl_tplMUlTtTtTyTnjEER6TPLTPLIT_EE_clI3TPLEEDaS3_
auto l_tpl_tpl_tpl::{lambda<template<template<typename, unsigned int> class> class $TT0>(TPLTPL<$TT0>&)#1}::operator()<TPL>(TPLTPL<TPL>&) const
_ZNK5l_varMUlTpTyDpT_E_clIJiiiEEEDaS1_
auto l_var::{lambda<typename... $T0>(($T0)...)#1}::operator()<int, int, int>(int, int, int) const
_ZNK6l_var2MUlTpTniDpRAT__iE_clIJLi2ELi2EEEEDaS2_
auto l_var2::{lambda<int... $N0>((int (&) [$N0])...)#1}::operator()<2, 2>(int (&) [2], int (&) [2]) const
_ZNK6l_var3MUlTtTpTniETpTniRT_IJXspT0_EEEE_clI1XJLi1ELi2ELi3EEEEDaS2_
auto l_var3::{lambda<template<int...> class $TT0, int... $N1>($TT0<($N1)...>&)#1}::operator()<X, 1, 2, 3>(X<1, 2, 3>&) const
_ZNK6l_var4MUlTpTtTyTnjER1YIJDpT_EEE_clIJ1US7_EEEDaS4_
auto l_var4::{lambda<template<typename, unsigned int> class... $TT0>(Y<($TT0)...>&)#1}::operator()<U, U>(Y<U, U>&) const
_ZZ2FnILi1EEvvENKUlTyT_E_clIiEEDaS0_
auto Fn<1>()::{lambda<typename $T0>($T0)#1}::operator()<int>(int) const
_ZZ1fvENKUlTyP1XIT_EPS_IiEE_clIcEEDaS2_S4_
auto f()::{lambda<typename $T0>(X<$T0>*, X<int>*)#1}::operator()<char>(X<char>*, X<int>*) const
_ZZN1XIiE1FEvENKUliE_clEi
X<int>::F()::{lambda(int)#1}::operator()(int) const