diff options
author | Chris Mihelich <cmihelic@google.com> | 2024-05-23 08:41:31 -0700 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2024-05-23 08:42:45 -0700 |
commit | 414929371ba51c475d0512e0354d911bf1d00598 (patch) | |
tree | 4db3226033a86277ad1d2e363579bcaf78cfcef9 | |
parent | 1a31b81c0a467c1c8e229b9fc172a4eb0db5bd85 (diff) |
Recognize dyn-trait-type in Rust demangling.
PiperOrigin-RevId: 636563266
Change-Id: Id4ee907c30d7dac400f1f85776cc5f1fcb3e20b7
-rw-r--r-- | absl/debugging/internal/demangle_rust.cc | 61 | ||||
-rw-r--r-- | absl/debugging/internal/demangle_rust_test.cc | 44 |
2 files changed, 104 insertions, 1 deletions
diff --git a/absl/debugging/internal/demangle_rust.cc b/absl/debugging/internal/demangle_rust.cc index b8cc1803..06ee7a4b 100644 --- a/absl/debugging/internal/demangle_rust.cc +++ b/absl/debugging/internal/demangle_rust.cc @@ -277,7 +277,7 @@ class RustSymbolParser { goto type; } if (Eat('F')) goto fn_type; - if (Eat('D')) return false; // dyn-trait-type not yet implemented + if (Eat('D')) goto dyn_trait_type; if (Eat('B')) goto type_backref; goto path; @@ -349,6 +349,54 @@ class RustSymbolParser { --silence_depth_; continue; + // dyn-trait-type -> D dyn-bounds lifetime (D already consumed) + // dyn-bounds -> binder? dyn-trait* E + // + // The grammar strangely allows an empty trait list, even though the + // compiler should never output one. We follow existing demanglers in + // rendering DEL_ as "dyn ". + // + // Because auto traits lengthen a type name considerably without + // providing much value to a search for related source code, it would be + // desirable to abbreviate + // dyn main::Trait + std::marker::Copy + std::marker::Send + // to + // dyn main::Trait + ..., + // eliding the auto traits. But it is difficult to do so correctly, in + // part because there is no guarantee that the mangling will list the + // main trait first. So we just print all the traits in their order of + // appearance in the mangled name. + dyn_trait_type: + if (!Emit("dyn ")) return false; + if (!ParseOptionalBinder()) return false; + if (!Eat('E')) { + ABSL_DEMANGLER_RECURSE(dyn_trait, kBeginAutoTraits); + while (!Eat('E')) { + if (!Emit(" + ")) return false; + ABSL_DEMANGLER_RECURSE(dyn_trait, kContinueAutoTraits); + } + } + if (!ParseRequiredLifetime()) return false; + continue; + + // dyn-trait -> path dyn-trait-assoc-binding* + // dyn-trait-assoc-binding -> p undisambiguated-identifier type + // + // We render nonempty binding lists as <>, omitting their contents as + // for generic-args. + dyn_trait: + ABSL_DEMANGLER_RECURSE(path, kContinueDynTrait); + if (Peek() == 'p') { + if (!Emit("<>")) return false; + ++silence_depth_; + while (Eat('p')) { + if (!ParseUndisambiguatedIdentifier()) return false; + ABSL_DEMANGLER_RECURSE(type, kContinueAssocBinding); + } + --silence_depth_; + } + continue; + // const -> type const-data | p | backref // // const is a C++ keyword, so we use the label `constant` instead. @@ -477,6 +525,10 @@ class RustSymbolParser { kAfterSubsequentTupleElement, kContinueParameterList, kFinishFn, + kBeginAutoTraits, + kContinueAutoTraits, + kContinueDynTrait, + kContinueAssocBinding, kConstData, kBeginGenericArgList, kContinueGenericArgList, @@ -750,6 +802,13 @@ class RustSymbolParser { return ParseBase62Number(ignored_de_bruijn_index); } + // Consumes a lifetime just like ParseOptionalLifetime, but returns false if + // there is no lifetime here. + ABSL_MUST_USE_RESULT bool ParseRequiredLifetime() { + if (Peek() != 'L') return false; + return ParseOptionalLifetime(); + } + // Pushes ns onto the namespace stack and returns true if the stack is not // full, else returns false. ABSL_MUST_USE_RESULT bool PushNamespace(char ns) { diff --git a/absl/debugging/internal/demangle_rust_test.cc b/absl/debugging/internal/demangle_rust_test.cc index 34b78134..00bba780 100644 --- a/absl/debugging/internal/demangle_rust_test.cc +++ b/absl/debugging/internal/demangle_rust_test.cc @@ -534,6 +534,50 @@ TEST(DemangleRust, LifetimeInGenericArgs) { "c::f::<>"); } +TEST(DemangleRust, EmptyDynTrait) { + // This shouldn't happen, but the grammar allows it and existing demanglers + // accept it. + EXPECT_DEMANGLING("_RNvYDEL_NtC1c1t1f", + "<dyn as c::t>::f"); +} + +TEST(DemangleRust, SimpleDynTrait) { + EXPECT_DEMANGLING("_RNvYDNtC1c1tEL_NtC1d1u1f", + "<dyn c::t as d::u>::f"); +} + +TEST(DemangleRust, DynTraitWithOneAssociatedType) { + EXPECT_DEMANGLING( + "_RNvYDNtC1c1tp1xlEL_NtC1d1u1f", // <dyn c::t<x = i32> as d::u>::f + "<dyn c::t<> as d::u>::f"); +} + +TEST(DemangleRust, DynTraitWithTwoAssociatedTypes) { + EXPECT_DEMANGLING( + // <dyn c::t<x = i32, y = u32> as d::u>::f + "_RNvYDNtC1c1tp1xlp1ymEL_NtC1d1u1f", + "<dyn c::t<> as d::u>::f"); +} + +TEST(DemangleRust, DynTraitPlusAutoTrait) { + EXPECT_DEMANGLING( + "_RNvYDNtC1c1tNtNtC3std6marker4SendEL_NtC1d1u1f", + "<dyn c::t + std::marker::Send as d::u>::f"); +} + +TEST(DemangleRust, DynTraitPlusTwoAutoTraits) { + EXPECT_DEMANGLING( + "_RNvYDNtC1c1tNtNtC3std6marker4CopyNtBc_4SyncEL_NtC1d1u1f", + "<dyn c::t + std::marker::Copy + std::marker::Sync as d::u>::f"); +} + +TEST(DemangleRust, HigherRankedDynTrait) { + EXPECT_DEMANGLING( + // <dyn for<'a> c::t::<&'a i32> as d::u>::f + "_RNvYDG_INtC1c1tRL0_lEEL_NtC1d1u1f", + "<dyn c::t::<> as d::u>::f"); +} + } // namespace } // namespace debugging_internal ABSL_NAMESPACE_END |