From 16aa5d37a8d0246aa390ee0ac561c509e677ab94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristj=C3=A1n=20Valur=20J=C3=B3nsson?= Date: Tue, 14 Apr 2026 14:36:35 +0000 Subject: [PATCH 1/9] cpp_demangle: support local-source-name template args in nested prefixes --- src/ast.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index c64d698..b2206e0 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -2372,6 +2372,19 @@ impl Parse for PrefixHandle { current = Some(save(subs, prefix, tail_tail)); tail = consume(b"M", tail_tail).unwrap(); } else { + // Keep substitution ordering stable for local source + // names with template-args that are followed by `M` + // data-member prefixes. + let current = if matches!( + name, + UnqualifiedName::LocalSourceName(_, Some(_), ..) + ) { + let nested = Prefix::Nested(current.unwrap(), name.clone()); + Some(save(subs, nested, tail_tail)) + } else { + current + }; + let prefix = match current { None => Prefix::Unqualified(name), Some(handle) => Prefix::Nested(handle, name), @@ -2548,6 +2561,7 @@ pub enum MemberLikeFriend { /// # I think this is from an older version of the standard. It isn't in the /// # current version, but all the other demanglers support it, so we will too. /// ::= L [] +/// ::= L [] /// ``` #[derive(Clone, Debug, PartialEq, Eq)] pub enum UnqualifiedName { @@ -2557,8 +2571,8 @@ pub enum UnqualifiedName { CtorDtor(CtorDtorName, AbiTags), /// A source name. Source(SourceName, MemberLikeFriend, AbiTags), - /// A local source name. - LocalSourceName(SourceName, Option, AbiTags), + /// A local source name, with optional template args and discriminator. + LocalSourceName(SourceName, Option, Option, AbiTags), /// A generated name for an unnamed type. UnnamedType(UnnamedTypeName, AbiTags), /// A closure type name @@ -2588,6 +2602,12 @@ impl Parse for UnqualifiedName { if let Ok(tail) = consume(b"L", input) { let (name, tail) = SourceName::parse(ctx, subs, tail)?; + let (template_args, tail) = + if let Ok((args, tail)) = try_recurse!(TemplateArgs::parse(ctx, subs, tail)) { + (Some(args), tail) + } else { + (None, tail) + }; let (discr, tail) = if let Ok((d, t)) = try_recurse!(Discriminator::parse(ctx, subs, tail)) { (Some(d), t) @@ -2596,7 +2616,7 @@ impl Parse for UnqualifiedName { }; let (abi_tags, tail) = AbiTags::parse(ctx, subs, tail)?; return Ok(( - UnqualifiedName::LocalSourceName(name, discr, abi_tags), + UnqualifiedName::LocalSourceName(name, template_args, discr, abi_tags), tail, )); } @@ -2659,8 +2679,11 @@ where name.demangle(ctx, scope)?; abi_tags.demangle(ctx, scope) } - UnqualifiedName::LocalSourceName(ref name, _, ref abi_tags) => { + UnqualifiedName::LocalSourceName(ref name, ref template_args, _, ref abi_tags) => { name.demangle(ctx, scope)?; + if let Some(ref template_args) = *template_args { + template_args.demangle(ctx, scope)?; + } abi_tags.demangle(ctx, scope) } UnqualifiedName::UnnamedType(ref unnamed, ref abi_tags) => { @@ -12094,11 +12117,29 @@ mod tests { start: 2, end: 5 }), + None, Some(Discriminator(0)), AbiTags::default(), ), "..." } + b"L3fooIiE..." => { + UnqualifiedName::LocalSourceName( + SourceName(Identifier { + start: 2, + end: 5 + }), + Some(TemplateArgs { + args: vec![TemplateArg::Type(TypeHandle::Builtin( + BuiltinType::Standard(StandardBuiltinType::Int) + ))], + requires_clause: ConstraintExpression(None), + }), + None, + AbiTags::default(), + ), + "..." + } b"L3foo..." => { UnqualifiedName::LocalSourceName( SourceName(Identifier { @@ -12106,6 +12147,7 @@ mod tests { end: 5 }), None, + None, AbiTags::default(), ), "..." @@ -12216,6 +12258,7 @@ mod tests { start: 2, end: 5 }), + None, Some(Discriminator(0)), AbiTags(vec![AbiTag( SourceName( @@ -12235,6 +12278,7 @@ mod tests { end: 5 }), None, + None, AbiTags(vec![ AbiTag( SourceName( From 0da78b6566d478596df45f60f0a67db953b34a47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristj=C3=A1n=20Valur=20J=C3=B3nsson?= Date: Tue, 14 Apr 2026 16:43:28 +0000 Subject: [PATCH 2/9] cpp_demangle: fix template-arg scope for local names in demangle --- src/ast.rs | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/src/ast.rs b/src/ast.rs index b2206e0..e94b0ba 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1775,7 +1775,7 @@ impl GetTemplateArgs for Name { Name::UnscopedTemplate(_, ref args) => Some(args), Name::Nested(ref nested) => nested.get_template_args(subs), Name::Local(ref local) => local.get_template_args(subs), - Name::Unscoped(_) => None, + Name::Unscoped(ref unscoped) => unscoped.get_template_args(subs), } } } @@ -1874,6 +1874,16 @@ impl<'a> GetLeafName<'a> for UnscopedName { } } +impl GetTemplateArgs for UnscopedName { + fn get_template_args<'a>(&'a self, subs: &'a SubstitutionTable) -> Option<&'a TemplateArgs> { + match *self { + UnscopedName::Unqualified(ref name) | UnscopedName::Std(ref name) => { + name.get_template_args(subs) + } + } + } +} + impl IsCtorDtorConversion for UnscopedName { fn is_ctor_dtor_conversion(&self, subs: &SubstitutionTable) -> bool { match *self { @@ -2682,6 +2692,7 @@ where UnqualifiedName::LocalSourceName(ref name, ref template_args, _, ref abi_tags) => { name.demangle(ctx, scope)?; if let Some(ref template_args) = *template_args { + let scope = scope.push(template_args); template_args.demangle(ctx, scope)?; } abi_tags.demangle(ctx, scope) @@ -2726,6 +2737,19 @@ impl IsCtorDtorConversion for UnqualifiedName { } } +impl GetTemplateArgs for UnqualifiedName { + fn get_template_args<'a>(&'a self, _: &'a SubstitutionTable) -> Option<&'a TemplateArgs> { + match *self { + UnqualifiedName::LocalSourceName(_, ref template_args, ..) => template_args.as_ref(), + UnqualifiedName::Operator(..) + | UnqualifiedName::CtorDtor(..) + | UnqualifiedName::Source(..) + | UnqualifiedName::UnnamedType(..) + | UnqualifiedName::ClosureType(..) => None, + } + } +} + impl UnqualifiedName { #[inline] fn starts_with(byte: u8, first: bool, input: &IndexStr) -> bool { @@ -8624,6 +8648,7 @@ mod tests { use crate::error::Error; use crate::index_str::IndexStr; use crate::subs::{Substitutable, SubstitutionTable}; + use crate::Symbol; use alloc::boxed::Box; use alloc::string::String; use core::fmt::Debug; @@ -10179,6 +10204,53 @@ mod tests { }); } + #[test] + fn parse_realworld_makesharedbufferviewwithouter_full_mangled_name_probe() { + let mut subs = SubstitutionTable::new(); + let ctx = ParseContext::new(Default::default()); + let input = IndexStr::new( + b"_ZL29MakeSharedBufferViewWithOuterIRK13FSharedBufferTnPDTcvS0_cl7DeclValIT_EEELPS0_0EES0_11TMemoryViewIKvEOS3_", + ); + + match MangledName::parse(&ctx, &mut subs, input) { + Ok((_name, tail)) => assert!( + tail.is_empty(), + "makesharedbufferviewwithouter full parse left tail: {:?}", + String::from_utf8_lossy(tail.as_ref()) + ), + Err(err) => panic!( + "failed makesharedbufferviewwithouter full mangled name: {:?}", + err + ), + } + } + + #[test] + fn demangle_realworld_makesharedbufferviewwithouter_probe() { + let mangled = b"_ZL29MakeSharedBufferViewWithOuterIRK13FSharedBufferTnPDTcvS0_cl7DeclValIT_EEELPS0_0EES0_11TMemoryViewIKvEOS3_"; + let sym = Symbol::new(&mangled[..]).expect("symbol parse"); + match sym.demangle() { + Ok(_) => {} + Err(err) => panic!( + "failed makesharedbufferviewwithouter demangle: {:?}", + err + ), + } + } + + #[test] + fn demangle_realworld_objparser_parsematerialproperty_probe() { + let mangled = b"_ZN2UE11Interchange14ObjParserUtilsL21ParseMaterialPropertyIiTnMN8FObjData13FMaterialDataET_XadL_ZNS4_17IlluminationModelEEEEEbRS3_11TStringViewIDsE"; + let sym = Symbol::new(&mangled[..]).expect("symbol parse"); + match sym.demangle() { + Ok(_) => {} + Err(err) => panic!( + "failed objparser parsematerialproperty demangle: {:?}", + err + ), + } + } + #[test] fn parse_template_arg() { assert_parse!(TemplateArg { From ae8870b7d80c867bee9c868f455ae50cd2dedab3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristj=C3=A1n=20Valur=20J=C3=B3nsson?= Date: Tue, 14 Apr 2026 14:36:39 +0000 Subject: [PATCH 3/9] cpp_demangle: resolve nested unqualified template-arg scope --- src/ast.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/ast.rs b/src/ast.rs index e94b0ba..57699ec 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -2176,7 +2176,13 @@ impl GetTemplateArgs for NestedName { match *self { NestedName::Template(_, _, ref prefix) | NestedName::TemplateExplicitObject(ref prefix, _) => prefix.get_template_args(subs), - _ => None, + // For nested unqualified names, the trailing unqualified component + // (for example local-source-name `L...I...E`) may carry the active + // template arguments; prefer those before falling back to prefix. + NestedName::Unqualified(_, _, ref prefix, ref name) + | NestedName::UnqualifiedExplicitObject(ref prefix, ref name, _) => name + .get_template_args(subs) + .or_else(|| prefix.as_ref().and_then(|p| p.get_template_args(subs))), } } } @@ -10251,6 +10257,19 @@ mod tests { } } + #[test] + fn demangle_realworld_foreachimpl_dispatch_probe() { + let mangled = b"_ZN11ForEachImplL8DispatchI10FPolygonID24FFixAttributesSizeHelperIS1_ELj0EEEv5FNameT0_P26FMeshAttributeArraySetBase"; + let sym = Symbol::new(&mangled[..]).expect("symbol parse"); + match sym.demangle() { + Ok(_) => {} + Err(err) => panic!( + "failed foreachimpl dispatch demangle: {:?}", + err + ), + } + } + #[test] fn parse_template_arg() { assert_parse!(TemplateArg { From 7b792cdb39716def8a16b30f1474fa1dc7bf0120 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristj=C3=A1n=20Valur=20J=C3=B3nsson?= Date: Tue, 14 Apr 2026 14:36:40 +0000 Subject: [PATCH 4/9] cpp_demangle: normalize local-source template-arg names in Name parse Follow-up to local-source template-arg support work (de6f393) and subsequent nested template-arg scope adjustments (70ded5f). When compatibility local-source names carry embedded template args (L), reinterpret them as unscoped-template names during Name parsing so substitution numbering aligns with S0/S1 references. Adds FindBounds regression probes for parse+demangle. --- src/ast.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/ast.rs b/src/ast.rs index 57699ec..70403ef 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1723,6 +1723,25 @@ impl Parse for Name { } if let Ok((name, tail)) = try_recurse!(UnscopedName::parse(ctx, subs, input)) { + if let UnscopedName::Unqualified(UnqualifiedName::LocalSourceName( + source, + Some(args), + discr, + abi_tags, + )) = name + { + // Compatibility local-source names may carry template-args + // directly (`L`). Reinterpret + // that shape as an unscoped-template-name so substitution + // numbering matches real-world compiler output. + let base = UnscopedName::Unqualified(UnqualifiedName::LocalSourceName( + source, None, discr, abi_tags, + )); + let idx = subs.insert(Substitutable::UnscopedTemplateName(UnscopedTemplateName(base))); + let handle = UnscopedTemplateNameHandle::BackReference(idx); + return Ok((Name::UnscopedTemplate(handle, args), tail)); + } + if tail.peek() == Some(b'I') { let name = UnscopedTemplateName(name); let idx = subs.insert(Substitutable::UnscopedTemplateName(name)); @@ -10244,6 +10263,32 @@ mod tests { } } + #[test] + fn parse_realworld_findbounds_full_mangled_name_probe() { + let mut subs = SubstitutionTable::new(); + let ctx = ParseContext::new(Default::default()); + let input = IndexStr::new(b"_ZL10FindBoundsIfEvRT_S1_S0_S0_fS0_S0_fb"); + + match MangledName::parse(&ctx, &mut subs, input) { + Ok((_name, tail)) => assert!( + tail.is_empty(), + "findbounds full parse left tail: {:?}", + String::from_utf8_lossy(tail.as_ref()) + ), + Err(err) => panic!("failed findbounds full mangled name: {:?}", err), + } + } + + #[test] + fn demangle_realworld_findbounds_probe() { + let mangled = b"_ZL10FindBoundsIfEvRT_S1_S0_S0_fS0_S0_fb"; + let sym = Symbol::new(&mangled[..]).expect("symbol parse"); + match sym.demangle() { + Ok(_) => {} + Err(err) => panic!("failed findbounds demangle: {:?}", err), + } + } + #[test] fn demangle_realworld_objparser_parsematerialproperty_probe() { let mangled = b"_ZN2UE11Interchange14ObjParserUtilsL21ParseMaterialPropertyIiTnMN8FObjData13FMaterialDataET_XadL_ZNS4_17IlluminationModelEEEEEbRS3_11TStringViewIDsE"; From 35b8e999ec2846ba3b4ae1e0e7f290ece0c4f13a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristj=C3=A1n=20Valur=20J=C3=B3nsson?= Date: Tue, 14 Apr 2026 16:44:53 +0000 Subject: [PATCH 5/9] cpp_demangle: normalize local-source template prefix in nested names --- src/ast.rs | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 70403ef..11318ca 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -2410,17 +2410,22 @@ impl Parse for PrefixHandle { // Keep substitution ordering stable for local source // names with template-args that are followed by `M` // data-member prefixes. - let current = if matches!( + let normalized_current = if matches!( name, UnqualifiedName::LocalSourceName(_, Some(_), ..) ) { - let nested = Prefix::Nested(current.unwrap(), name.clone()); - Some(save(subs, nested, tail_tail)) + match current.take() { + Some(handle) => { + let nested = Prefix::Nested(handle, name.clone()); + Some(save(subs, nested, tail_tail)) + } + None => None, + } } else { - current + current.take() }; - let prefix = match current { + let prefix = match normalized_current { None => Prefix::Unqualified(name), Some(handle) => Prefix::Nested(handle, name), }; @@ -10289,6 +10294,35 @@ mod tests { } } + #[test] + fn parse_realworld_serialize_uint_delta_full_mangled_name_probe() { + let mut subs = SubstitutionTable::new(); + let ctx = ParseContext::new(Default::default()); + let input = IndexStr::new( + b"_ZN2UE3Net7PrivateL22SerializeUintDeltaImplIyEEvRNS0_19FNetBitStreamWriterET_S5_PKhjh", + ); + + match MangledName::parse(&ctx, &mut subs, input) { + Ok((_name, tail)) => assert!( + tail.is_empty(), + "serialize uint delta full parse left tail: {:?}", + String::from_utf8_lossy(tail.as_ref()) + ), + Err(err) => panic!("failed serialize uint delta full mangled name: {:?}", err), + } + } + + #[test] + fn demangle_realworld_serialize_uint_delta_probe() { + let mangled = + b"_ZN2UE3Net7PrivateL22SerializeUintDeltaImplIyEEvRNS0_19FNetBitStreamWriterET_S5_PKhjh"; + let sym = Symbol::new(&mangled[..]).expect("symbol parse"); + match sym.demangle() { + Ok(_) => {} + Err(err) => panic!("failed serialize uint delta demangle: {:?}", err), + } + } + #[test] fn demangle_realworld_objparser_parsematerialproperty_probe() { let mangled = b"_ZN2UE11Interchange14ObjParserUtilsL21ParseMaterialPropertyIiTnMN8FObjData13FMaterialDataET_XadL_ZNS4_17IlluminationModelEEEEEbRS3_11TStringViewIDsE"; From c34c0b2b13654e097d547752245fdefd26da8dfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristj=C3=A1n=20Valur=20J=C3=B3nsson?= Date: Tue, 14 Apr 2026 16:53:05 +0000 Subject: [PATCH 6/9] cpp_demangle: avoid return-type regression in nested template-arg lookup --- src/ast.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 11318ca..4e445c2 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -2197,11 +2197,12 @@ impl GetTemplateArgs for NestedName { | NestedName::TemplateExplicitObject(ref prefix, _) => prefix.get_template_args(subs), // For nested unqualified names, the trailing unqualified component // (for example local-source-name `L...I...E`) may carry the active - // template arguments; prefer those before falling back to prefix. + // template arguments. NestedName::Unqualified(_, _, ref prefix, ref name) - | NestedName::UnqualifiedExplicitObject(ref prefix, ref name, _) => name - .get_template_args(subs) - .or_else(|| prefix.as_ref().and_then(|p| p.get_template_args(subs))), + | NestedName::UnqualifiedExplicitObject(ref prefix, ref name, _) => { + let _ = prefix; + name.get_template_args(subs) + } } } } From d329ca8469822581bf83b9ed37c3512ba18feb01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristj=C3=A1n=20Valur=20J=C3=B3nsson?= Date: Wed, 15 Apr 2026 09:36:46 +0000 Subject: [PATCH 7/9] cpp_demangle: keep LocalSourceName AST shape semver-compatible --- src/ast.rs | 70 ++++++------------------------------------------------ 1 file changed, 7 insertions(+), 63 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 4e445c2..992b119 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1723,25 +1723,6 @@ impl Parse for Name { } if let Ok((name, tail)) = try_recurse!(UnscopedName::parse(ctx, subs, input)) { - if let UnscopedName::Unqualified(UnqualifiedName::LocalSourceName( - source, - Some(args), - discr, - abi_tags, - )) = name - { - // Compatibility local-source names may carry template-args - // directly (`L`). Reinterpret - // that shape as an unscoped-template-name so substitution - // numbering matches real-world compiler output. - let base = UnscopedName::Unqualified(UnqualifiedName::LocalSourceName( - source, None, discr, abi_tags, - )); - let idx = subs.insert(Substitutable::UnscopedTemplateName(UnscopedTemplateName(base))); - let handle = UnscopedTemplateNameHandle::BackReference(idx); - return Ok((Name::UnscopedTemplate(handle, args), tail)); - } - if tail.peek() == Some(b'I') { let name = UnscopedTemplateName(name); let idx = subs.insert(Substitutable::UnscopedTemplateName(name)); @@ -2411,20 +2392,7 @@ impl Parse for PrefixHandle { // Keep substitution ordering stable for local source // names with template-args that are followed by `M` // data-member prefixes. - let normalized_current = if matches!( - name, - UnqualifiedName::LocalSourceName(_, Some(_), ..) - ) { - match current.take() { - Some(handle) => { - let nested = Prefix::Nested(handle, name.clone()); - Some(save(subs, nested, tail_tail)) - } - None => None, - } - } else { - current.take() - }; + let normalized_current = current.take(); let prefix = match normalized_current { None => Prefix::Unqualified(name), @@ -2602,7 +2570,6 @@ pub enum MemberLikeFriend { /// # I think this is from an older version of the standard. It isn't in the /// # current version, but all the other demanglers support it, so we will too. /// ::= L [] -/// ::= L [] /// ``` #[derive(Clone, Debug, PartialEq, Eq)] pub enum UnqualifiedName { @@ -2612,8 +2579,8 @@ pub enum UnqualifiedName { CtorDtor(CtorDtorName, AbiTags), /// A source name. Source(SourceName, MemberLikeFriend, AbiTags), - /// A local source name, with optional template args and discriminator. - LocalSourceName(SourceName, Option, Option, AbiTags), + /// A local source name. + LocalSourceName(SourceName, Option, AbiTags), /// A generated name for an unnamed type. UnnamedType(UnnamedTypeName, AbiTags), /// A closure type name @@ -2643,12 +2610,6 @@ impl Parse for UnqualifiedName { if let Ok(tail) = consume(b"L", input) { let (name, tail) = SourceName::parse(ctx, subs, tail)?; - let (template_args, tail) = - if let Ok((args, tail)) = try_recurse!(TemplateArgs::parse(ctx, subs, tail)) { - (Some(args), tail) - } else { - (None, tail) - }; let (discr, tail) = if let Ok((d, t)) = try_recurse!(Discriminator::parse(ctx, subs, tail)) { (Some(d), t) @@ -2656,10 +2617,7 @@ impl Parse for UnqualifiedName { (None, tail) }; let (abi_tags, tail) = AbiTags::parse(ctx, subs, tail)?; - return Ok(( - UnqualifiedName::LocalSourceName(name, template_args, discr, abi_tags), - tail, - )); + return Ok((UnqualifiedName::LocalSourceName(name, discr, abi_tags), tail)); } if let Ok((source, tail)) = try_recurse!(SourceName::parse(ctx, subs, input)) { @@ -2720,12 +2678,8 @@ where name.demangle(ctx, scope)?; abi_tags.demangle(ctx, scope) } - UnqualifiedName::LocalSourceName(ref name, ref template_args, _, ref abi_tags) => { + UnqualifiedName::LocalSourceName(ref name, _, ref abi_tags) => { name.demangle(ctx, scope)?; - if let Some(ref template_args) = *template_args { - let scope = scope.push(template_args); - template_args.demangle(ctx, scope)?; - } abi_tags.demangle(ctx, scope) } UnqualifiedName::UnnamedType(ref unnamed, ref abi_tags) => { @@ -2771,9 +2725,9 @@ impl IsCtorDtorConversion for UnqualifiedName { impl GetTemplateArgs for UnqualifiedName { fn get_template_args<'a>(&'a self, _: &'a SubstitutionTable) -> Option<&'a TemplateArgs> { match *self { - UnqualifiedName::LocalSourceName(_, ref template_args, ..) => template_args.as_ref(), UnqualifiedName::Operator(..) | UnqualifiedName::CtorDtor(..) + | UnqualifiedName::LocalSourceName(..) | UnqualifiedName::Source(..) | UnqualifiedName::UnnamedType(..) | UnqualifiedName::ClosureType(..) => None, @@ -12288,7 +12242,6 @@ mod tests { start: 2, end: 5 }), - None, Some(Discriminator(0)), AbiTags::default(), ), @@ -12300,16 +12253,10 @@ mod tests { start: 2, end: 5 }), - Some(TemplateArgs { - args: vec![TemplateArg::Type(TypeHandle::Builtin( - BuiltinType::Standard(StandardBuiltinType::Int) - ))], - requires_clause: ConstraintExpression(None), - }), None, AbiTags::default(), ), - "..." + "IiE..." } b"L3foo..." => { UnqualifiedName::LocalSourceName( @@ -12318,7 +12265,6 @@ mod tests { end: 5 }), None, - None, AbiTags::default(), ), "..." @@ -12429,7 +12375,6 @@ mod tests { start: 2, end: 5 }), - None, Some(Discriminator(0)), AbiTags(vec![AbiTag( SourceName( @@ -12449,7 +12394,6 @@ mod tests { end: 5 }), None, - None, AbiTags(vec![ AbiTag( SourceName( From 4ff04047f73b33e73a74c8f4b6756463c3fdcc53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristj=C3=A1n=20Valur=20J=C3=B3nsson?= Date: Wed, 15 Apr 2026 16:44:26 +0000 Subject: [PATCH 8/9] apply PR4 readability review cleanups --- src/ast.rs | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 992b119..9d6843a 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -2179,11 +2179,8 @@ impl GetTemplateArgs for NestedName { // For nested unqualified names, the trailing unqualified component // (for example local-source-name `L...I...E`) may carry the active // template arguments. - NestedName::Unqualified(_, _, ref prefix, ref name) - | NestedName::UnqualifiedExplicitObject(ref prefix, ref name, _) => { - let _ = prefix; - name.get_template_args(subs) - } + NestedName::Unqualified(_, _, _, ref name) + | NestedName::UnqualifiedExplicitObject(_, ref name, _) => name.get_template_args(subs), } } } @@ -2392,9 +2389,9 @@ impl Parse for PrefixHandle { // Keep substitution ordering stable for local source // names with template-args that are followed by `M` // data-member prefixes. - let normalized_current = current.take(); + let prev_current = current.take(); - let prefix = match normalized_current { + let prefix = match prev_current { None => Prefix::Unqualified(name), Some(handle) => Prefix::Nested(handle, name), }; @@ -2724,14 +2721,8 @@ impl IsCtorDtorConversion for UnqualifiedName { impl GetTemplateArgs for UnqualifiedName { fn get_template_args<'a>(&'a self, _: &'a SubstitutionTable) -> Option<&'a TemplateArgs> { - match *self { - UnqualifiedName::Operator(..) - | UnqualifiedName::CtorDtor(..) - | UnqualifiedName::LocalSourceName(..) - | UnqualifiedName::Source(..) - | UnqualifiedName::UnnamedType(..) - | UnqualifiedName::ClosureType(..) => None, - } + // Unqualified names do not directly carry template arguments in this AST. + None } } From 270769696b601bea96e3a8f74b1f7ebe87cf191a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristj=C3=A1n=20Valur=20J=C3=B3nsson?= Date: Fri, 17 Apr 2026 09:13:55 +0000 Subject: [PATCH 9/9] Apply rustfmt --- src/ast.rs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 9d6843a..cb4941c 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -2614,7 +2614,10 @@ impl Parse for UnqualifiedName { (None, tail) }; let (abi_tags, tail) = AbiTags::parse(ctx, subs, tail)?; - return Ok((UnqualifiedName::LocalSourceName(name, discr, abi_tags), tail)); + return Ok(( + UnqualifiedName::LocalSourceName(name, discr, abi_tags), + tail, + )); } if let Ok((source, tail)) = try_recurse!(SourceName::parse(ctx, subs, input)) { @@ -10207,10 +10210,7 @@ mod tests { let sym = Symbol::new(&mangled[..]).expect("symbol parse"); match sym.demangle() { Ok(_) => {} - Err(err) => panic!( - "failed makesharedbufferviewwithouter demangle: {:?}", - err - ), + Err(err) => panic!("failed makesharedbufferviewwithouter demangle: {:?}", err), } } @@ -10275,10 +10275,7 @@ mod tests { let sym = Symbol::new(&mangled[..]).expect("symbol parse"); match sym.demangle() { Ok(_) => {} - Err(err) => panic!( - "failed objparser parsematerialproperty demangle: {:?}", - err - ), + Err(err) => panic!("failed objparser parsematerialproperty demangle: {:?}", err), } } @@ -10288,10 +10285,7 @@ mod tests { let sym = Symbol::new(&mangled[..]).expect("symbol parse"); match sym.demangle() { Ok(_) => {} - Err(err) => panic!( - "failed foreachimpl dispatch demangle: {:?}", - err - ), + Err(err) => panic!("failed foreachimpl dispatch demangle: {:?}", err), } }