Skip to content

Commit d1b6b2f

Browse files
committed
Demangle explicitly named object parameters
This is a patch that allows for the ability to demangle code like: ``` struct Foo { void bar(this Foo && self); }; ``` An example mangling is `_ZNH1S3fooES_` which then demangles to `S::foo(this S)`. The proposal can be found here: itanium-cxx-abi/cxx-abi#148
1 parent 15bbde1 commit d1b6b2f

File tree

2 files changed

+97
-21
lines changed

2 files changed

+97
-21
lines changed

src/ast.rs

Lines changed: 86 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,8 @@ where
556556
// argument pack.
557557
is_template_argument_pack: bool,
558558

559+
is_explicit_obj_param: bool,
560+
559561
// Whether to show function parameters.
560562
// This must be set to true before calling `demangle` on `Encoding`
561563
// unless that call is via the toplevel call to `MangledName::demangle`.
@@ -615,6 +617,7 @@ where
615617
is_template_prefix: false,
616618
is_template_prefix_in_nested_name: false,
617619
is_template_argument_pack: false,
620+
is_explicit_obj_param: false,
618621
show_params: !options.no_params,
619622
show_return_type: !options.no_return_type,
620623
show_expression_literal_types: !options.hide_expression_literal_types,
@@ -1037,6 +1040,12 @@ where
10371040
}
10381041

10391042
let mut need_comma = false;
1043+
1044+
// Only the first param should have `this`.
1045+
if ctx.is_explicit_obj_param {
1046+
write!(ctx, "this ")?;
1047+
}
1048+
10401049
for arg in self.iter() {
10411050
if need_comma {
10421051
write!(ctx, ", ")?;
@@ -1938,19 +1947,28 @@ impl<'a> GetLeafName<'a> for UnscopedTemplateName {
19381947
/// ```text
19391948
/// <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
19401949
/// ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
1950+
/// ::= N H <prefix> <unqualified-name> E
1951+
/// ::= N H <template-prefix> <template-args> E
1952+
19411953
/// ```
19421954
#[derive(Clone, Debug, PartialEq, Eq)]
19431955
pub enum NestedName {
19441956
/// A nested name.
19451957
Unqualified(
19461958
CvQualifiers,
19471959
Option<RefQualifier>,
1960+
Option<ExplicitObjectParameter>,
19481961
PrefixHandle,
19491962
UnqualifiedName,
19501963
),
19511964

19521965
/// A nested template name. The `<template-args>` are part of the `PrefixHandle`.
1953-
Template(CvQualifiers, Option<RefQualifier>, PrefixHandle),
1966+
Template(
1967+
CvQualifiers,
1968+
Option<RefQualifier>,
1969+
Option<ExplicitObjectParameter>,
1970+
PrefixHandle,
1971+
),
19541972
}
19551973

19561974
impl Parse for NestedName {
@@ -1963,19 +1981,28 @@ impl Parse for NestedName {
19631981

19641982
let tail = consume(b"N", input)?;
19651983

1966-
let (cv_qualifiers, tail) =
1967-
if let Ok((q, tail)) = try_recurse!(CvQualifiers::parse(ctx, subs, tail)) {
1968-
(q, tail)
1969-
} else {
1970-
(Default::default(), tail)
1971-
};
1984+
let (cv_qualifiers, ref_qualifier, explicit_obj_param, tail) = match tail.peek() {
1985+
Some(b'H') => {
1986+
let (explicit_obj_param, tail) = ExplicitObjectParameter::parse(ctx, subs, tail)?;
1987+
(Default::default(), None, Some(explicit_obj_param), tail)
1988+
}
1989+
_ => {
1990+
let (cv_qualifiers, tail) =
1991+
if let Ok((q, tail)) = try_recurse!(CvQualifiers::parse(ctx, subs, tail)) {
1992+
(q, tail)
1993+
} else {
1994+
(Default::default(), tail)
1995+
};
19721996

1973-
let (ref_qualifier, tail) =
1974-
if let Ok((r, tail)) = try_recurse!(RefQualifier::parse(ctx, subs, tail)) {
1975-
(Some(r), tail)
1976-
} else {
1977-
(None, tail)
1978-
};
1997+
let (ref_qualifier, tail) =
1998+
if let Ok((r, tail)) = try_recurse!(RefQualifier::parse(ctx, subs, tail)) {
1999+
(Some(r), tail)
2000+
} else {
2001+
(None, tail)
2002+
};
2003+
(cv_qualifiers, ref_qualifier, None, tail)
2004+
}
2005+
};
19792006

19802007
let (prefix, tail) = PrefixHandle::parse(ctx, subs, tail)?;
19812008
let tail = consume(b"E", tail)?;
@@ -1988,11 +2015,17 @@ impl Parse for NestedName {
19882015

19892016
match substitutable {
19902017
Some(&Substitutable::Prefix(Prefix::Nested(ref prefix, ref name))) => Ok((
1991-
NestedName::Unqualified(cv_qualifiers, ref_qualifier, prefix.clone(), name.clone()),
2018+
NestedName::Unqualified(
2019+
cv_qualifiers,
2020+
ref_qualifier,
2021+
explicit_obj_param,
2022+
prefix.clone(),
2023+
name.clone(),
2024+
),
19922025
tail,
19932026
)),
19942027
Some(&Substitutable::Prefix(Prefix::Template(..))) => Ok((
1995-
NestedName::Template(cv_qualifiers, ref_qualifier, prefix),
2028+
NestedName::Template(cv_qualifiers, ref_qualifier, explicit_obj_param, prefix),
19962029
tail,
19972030
)),
19982031
_ => Err(error::Error::UnexpectedText),
@@ -2017,12 +2050,20 @@ impl NestedName {
20172050
}
20182051
}
20192052

2053+
/// Get the ref-qualifier for this name, if one exists.
2054+
pub fn has_explicit_obj_param(&self) -> bool {
2055+
match *self {
2056+
NestedName::Unqualified(_, _, Some(ref _r), ..)
2057+
| NestedName::Template(_, _, Some(ref _r), ..) => true,
2058+
_ => false,
2059+
}
2060+
}
20202061
// Not public because the prefix means different things for different
20212062
// variants, and for `::Template` it actually contains part of what
20222063
// conceptually belongs to `<nested-name>`.
20232064
fn prefix(&self) -> &PrefixHandle {
20242065
match *self {
2025-
NestedName::Unqualified(_, _, ref p, _) | NestedName::Template(_, _, ref p) => p,
2066+
NestedName::Unqualified(_, _, _, ref p, _) | NestedName::Template(_, _, _, ref p) => p,
20262067
}
20272068
}
20282069
}
@@ -2039,7 +2080,7 @@ where
20392080
let ctx = try_begin_demangle!(self, ctx, scope);
20402081

20412082
match *self {
2042-
NestedName::Unqualified(_, _, ref p, ref name) => {
2083+
NestedName::Unqualified(_, _, _, ref p, ref name) => {
20432084
ctx.push_demangle_node(DemangleNodeType::NestedName);
20442085
p.demangle(ctx, scope)?;
20452086
if name.accepts_double_colon() {
@@ -2048,13 +2089,17 @@ where
20482089
name.demangle(ctx, scope)?;
20492090
ctx.pop_demangle_node();
20502091
}
2051-
NestedName::Template(_, _, ref p) => {
2092+
NestedName::Template(_, _, _, ref p) => {
20522093
ctx.is_template_prefix_in_nested_name = true;
20532094
p.demangle(ctx, scope)?;
20542095
ctx.is_template_prefix_in_nested_name = false;
20552096
}
20562097
}
20572098

2099+
if self.has_explicit_obj_param() {
2100+
ctx.is_explicit_obj_param = true;
2101+
}
2102+
20582103
if let Some(inner) = ctx.pop_inner() {
20592104
inner.demangle_as_inner(ctx, scope)?;
20602105
}
@@ -2075,7 +2120,7 @@ where
20752120
impl GetTemplateArgs for NestedName {
20762121
fn get_template_args<'a>(&'a self, subs: &'a SubstitutionTable) -> Option<&'a TemplateArgs> {
20772122
match *self {
2078-
NestedName::Template(_, _, ref prefix) => prefix.get_template_args(subs),
2123+
NestedName::Template(_, _, _, ref prefix) => prefix.get_template_args(subs),
20792124
_ => None,
20802125
}
20812126
}
@@ -2084,10 +2129,10 @@ impl GetTemplateArgs for NestedName {
20842129
impl<'a> GetLeafName<'a> for NestedName {
20852130
fn get_leaf_name(&'a self, subs: &'a SubstitutionTable) -> Option<LeafName<'a>> {
20862131
match *self {
2087-
NestedName::Unqualified(_, _, ref prefix, ref name) => name
2132+
NestedName::Unqualified(_, _, _, ref prefix, ref name) => name
20882133
.get_leaf_name(subs)
20892134
.or_else(|| prefix.get_leaf_name(subs)),
2090-
NestedName::Template(_, _, ref prefix) => prefix.get_leaf_name(subs),
2135+
NestedName::Template(_, _, _, ref prefix) => prefix.get_leaf_name(subs),
20912136
}
20922137
}
20932138
}
@@ -4018,6 +4063,19 @@ define_vocabulary! {
40184063
}
40194064
}
40204065

4066+
define_vocabulary! {
4067+
/// A <ref-qualifier> production.
4068+
///
4069+
/// ```text
4070+
/// <ref-qualifier> ::= R # & ref-qualifier
4071+
/// ::= O # && ref-qualifier
4072+
/// ```
4073+
#[derive(Clone, Debug, PartialEq, Eq)]
4074+
pub enum ExplicitObjectParameter {
4075+
ExplicitObjectParameter(b"H", "this")
4076+
}
4077+
}
4078+
40214079
define_vocabulary! {
40224080
/// A one of the standard variants of the <builtin-type> production.
40234081
///
@@ -8538,6 +8596,7 @@ mod tests {
85388596
Ok => {
85398597
b"NS0_3abcE..." => {
85408598
Name::Nested(NestedName::Unqualified(CvQualifiers::default(),
8599+
None,
85418600
None,
85428601
PrefixHandle::BackReference(1),
85438602
UnqualifiedName::Source(SourceName(Identifier {
@@ -8660,6 +8719,7 @@ mod tests {
86608719
const_: true,
86618720
},
86628721
Some(RefQualifier::RValueRef),
8722+
None,
86638723
PrefixHandle::BackReference(0),
86648724
UnqualifiedName::Source(
86658725
SourceName(Identifier {
@@ -8677,6 +8737,7 @@ mod tests {
86778737
const_: false,
86788738
},
86798739
Some(RefQualifier::RValueRef),
8740+
None,
86808741
PrefixHandle::BackReference(0),
86818742
UnqualifiedName::Source(
86828743
SourceName(Identifier {
@@ -8694,6 +8755,7 @@ mod tests {
86948755
const_: false,
86958756
},
86968757
None,
8758+
None,
86978759
PrefixHandle::BackReference(0),
86988760
UnqualifiedName::Source(
86998761
SourceName(Identifier {
@@ -8711,6 +8773,7 @@ mod tests {
87118773
const_: true,
87128774
},
87138775
Some(RefQualifier::RValueRef),
8776+
None,
87148777
PrefixHandle::NonSubstitution(NonSubstitution(0))),
87158778
b"...",
87168779
[
@@ -8732,6 +8795,7 @@ mod tests {
87328795
const_: false,
87338796
},
87348797
Some(RefQualifier::RValueRef),
8798+
None,
87358799
PrefixHandle::NonSubstitution(NonSubstitution(0))),
87368800
b"...",
87378801
[
@@ -8753,6 +8817,7 @@ mod tests {
87538817
const_: false,
87548818
},
87558819
None,
8820+
None,
87568821
PrefixHandle::NonSubstitution(NonSubstitution(0))),
87578822
b"...",
87588823
[

tests/tests.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,17 @@ demangles!(
617617
"deluge::gui::menu_item::MasterTranspose::MenuItem(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)"
618618
);
619619

620+
demangles!(_ZNH1S3fooES_, "S::foo(this S)");
621+
622+
demangles!(_ZNH1S3barILi5EiEEvS_T0_, "void S::bar<5, int>(this S, int)");
623+
624+
demangles!(_ZNH1S3bazERKS_, "S::baz(this S const&)");
625+
626+
demangles!(
627+
_ZZNH2ns3Foo3fooES0_iENH4Foo24foo2EOKS1_,
628+
"ns::Foo::foo(this ns::Foo, int)::Foo2::foo2(this Foo2 const&&)"
629+
);
630+
620631
// This symbol previously ran into some mutual recursion and unbounded growth of the substitution table.
621632
// See <https://github.com/gimli-rs/cpp_demangle/issues/277> and <https://github.com/getsentry/symbolic/issues/477>
622633
#[test]

0 commit comments

Comments
 (0)