summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Chris Mihelich <cmihelic@google.com>2024-05-23 08:41:31 -0700
committerGravatar Copybara-Service <copybara-worker@google.com>2024-05-23 08:42:45 -0700
commit414929371ba51c475d0512e0354d911bf1d00598 (patch)
tree4db3226033a86277ad1d2e363579bcaf78cfcef9
parent1a31b81c0a467c1c8e229b9fc172a4eb0db5bd85 (diff)
Recognize dyn-trait-type in Rust demangling.
PiperOrigin-RevId: 636563266 Change-Id: Id4ee907c30d7dac400f1f85776cc5f1fcb3e20b7
-rw-r--r--absl/debugging/internal/demangle_rust.cc61
-rw-r--r--absl/debugging/internal/demangle_rust_test.cc44
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