Commit aaed9b4a by Chris Mihelich Committed by Copybara-Service

Recognize fn-type and lifetimes in Rust demangling.

PiperOrigin-RevId: 636152885
Change-Id: If545903854ea39cc4b5c51c88cd555072d27d89e
parent e7f1a950
...@@ -260,12 +260,12 @@ class RustSymbolParser { ...@@ -260,12 +260,12 @@ class RustSymbolParser {
if (Eat('T')) goto tuple_type; if (Eat('T')) goto tuple_type;
if (Eat('R')) { if (Eat('R')) {
if (!Emit("&")) return false; if (!Emit("&")) return false;
if (Eat('L')) return false; // lifetime not yet implemented if (!ParseOptionalLifetime()) return false;
goto type; goto type;
} }
if (Eat('Q')) { if (Eat('Q')) {
if (!Emit("&mut ")) return false; if (!Emit("&mut ")) return false;
if (Eat('L')) return false; // lifetime not yet implemented if (!ParseOptionalLifetime()) return false;
goto type; goto type;
} }
if (Eat('P')) { if (Eat('P')) {
...@@ -276,7 +276,7 @@ class RustSymbolParser { ...@@ -276,7 +276,7 @@ class RustSymbolParser {
if (!Emit("*mut ")) return false; if (!Emit("*mut ")) return false;
goto type; goto type;
} }
if (Eat('F')) return false; // fn-type not yet implemented if (Eat('F')) goto fn_type;
if (Eat('D')) return false; // dyn-trait-type not yet implemented if (Eat('D')) return false; // dyn-trait-type not yet implemented
if (Eat('B')) goto type_backref; if (Eat('B')) goto type_backref;
goto path; goto path;
...@@ -328,6 +328,27 @@ class RustSymbolParser { ...@@ -328,6 +328,27 @@ class RustSymbolParser {
--silence_depth_; --silence_depth_;
continue; continue;
// fn-type -> F fn-sig (F already consumed)
// fn-sig -> binder? U? (K abi)? type* E type
// abi -> C | undisambiguated-identifier
//
// We follow the C++ demangler in suppressing details of function
// signatures. Every function type is rendered "fn...".
fn_type:
if (!Emit("fn...")) return false;
++silence_depth_;
if (!ParseOptionalBinder()) return false;
(void)Eat('U');
if (Eat('K')) {
if (!Eat('C') && !ParseUndisambiguatedIdentifier()) return false;
}
while (!Eat('E')) {
ABSL_DEMANGLER_RECURSE(type, kContinueParameterList);
}
ABSL_DEMANGLER_RECURSE(type, kFinishFn);
--silence_depth_;
continue;
// const -> type const-data | p | backref // const -> type const-data | p | backref
// //
// const is a C++ keyword, so we use the label `constant` instead. // const is a C++ keyword, so we use the label `constant` instead.
...@@ -386,7 +407,10 @@ class RustSymbolParser { ...@@ -386,7 +407,10 @@ class RustSymbolParser {
// generic-arg -> lifetime | type | K const // generic-arg -> lifetime | type | K const
generic_arg: generic_arg:
if (Eat('L')) return false; // lifetime not yet implemented if (Peek() == 'L') {
if (!ParseOptionalLifetime()) return false;
continue;
}
if (Eat('K')) goto constant; if (Eat('K')) goto constant;
goto type; goto type;
...@@ -451,6 +475,8 @@ class RustSymbolParser { ...@@ -451,6 +475,8 @@ class RustSymbolParser {
kAfterSecondTupleElement, kAfterSecondTupleElement,
kAfterThirdTupleElement, kAfterThirdTupleElement,
kAfterSubsequentTupleElement, kAfterSubsequentTupleElement,
kContinueParameterList,
kFinishFn,
kConstData, kConstData,
kBeginGenericArgList, kBeginGenericArgList,
kContinueGenericArgList, kContinueGenericArgList,
...@@ -612,6 +638,20 @@ class RustSymbolParser { ...@@ -612,6 +638,20 @@ class RustSymbolParser {
int disambiguator = 0; int disambiguator = 0;
if (!ParseDisambiguator(disambiguator)) return false; if (!ParseDisambiguator(disambiguator)) return false;
return ParseUndisambiguatedIdentifier(uppercase_namespace, disambiguator);
}
// Consumes from the input an identifier with no preceding disambiguator,
// returning true on success.
//
// When ParseIdentifier calls this, it passes the N<namespace> character and
// disambiguator value so that "{closure#42}" and similar forms can be
// rendered correctly.
//
// At other appearances of undisambiguated-identifier in the grammar, this
// treatment is not applicable, and the call site omits both arguments.
ABSL_MUST_USE_RESULT bool ParseUndisambiguatedIdentifier(
char uppercase_namespace = '\0', int disambiguator = 0) {
// undisambiguated-identifier -> u? decimal-number _? bytes // undisambiguated-identifier -> u? decimal-number _? bytes
const bool is_punycoded = Eat('u'); const bool is_punycoded = Eat('u');
if (!IsDigit(Peek())) return false; if (!IsDigit(Peek())) return false;
...@@ -686,6 +726,30 @@ class RustSymbolParser { ...@@ -686,6 +726,30 @@ class RustSymbolParser {
return true; return true;
} }
// Consumes a binder of higher-ranked lifetimes if one is present. On success
// returns true and discards the encoded lifetime count. On parse failure
// returns false.
ABSL_MUST_USE_RESULT bool ParseOptionalBinder() {
// binder -> G base-62-number
if (!Eat('G')) return true;
int ignored_binding_count;
return ParseBase62Number(ignored_binding_count);
}
// Consumes a lifetime if one is present.
//
// On success returns true and discards the lifetime index. We do not print
// or even range-check lifetimes because they are a finer detail than other
// things we omit from output, such as the entire contents of generic-args.
//
// On parse failure returns false.
ABSL_MUST_USE_RESULT bool ParseOptionalLifetime() {
// lifetime -> L base-62-number
if (!Eat('L')) return true;
int ignored_de_bruijn_index;
return ParseBase62Number(ignored_de_bruijn_index);
}
// Pushes ns onto the namespace stack and returns true if the stack is not // Pushes ns onto the namespace stack and returns true if the stack is not
// full, else returns false. // full, else returns false.
ABSL_MUST_USE_RESULT bool PushNamespace(char ns) { ABSL_MUST_USE_RESULT bool PushNamespace(char ns) {
......
...@@ -478,6 +478,62 @@ TEST(DemangleRust, TraitImplWithNonpathSelfType) { ...@@ -478,6 +478,62 @@ TEST(DemangleRust, TraitImplWithNonpathSelfType) {
"<&i32 as my_crate::my_trait>::my_func"); "<&i32 as my_crate::my_trait>::my_func");
} }
TEST(DemangleRust, ThunkType) {
EXPECT_DEMANGLING("_RNvYFEuNtC1c1t1f", // <fn() as c::t>::f
"<fn... as c::t>::f");
}
TEST(DemangleRust, NontrivialFunctionReturnType) {
EXPECT_DEMANGLING(
"_RNvYFERTlmENtC1c1t1f", // <fn() -> &(i32, u32) as c::t>::f
"<fn... as c::t>::f");
}
TEST(DemangleRust, OneParameterType) {
EXPECT_DEMANGLING("_RNvYFlEuNtC1c1t1f", // <fn(i32) as c::t>::f
"<fn... as c::t>::f");
}
TEST(DemangleRust, TwoParameterTypes) {
EXPECT_DEMANGLING("_RNvYFlmEuNtC1c1t1f", // <fn(i32, u32) as c::t>::f
"<fn... as c::t>::f");
}
TEST(DemangleRust, ExternC) {
EXPECT_DEMANGLING("_RNvYFKCEuNtC1c1t1f", // <extern "C" fn() as c::t>>::f
"<fn... as c::t>::f");
}
TEST(DemangleRust, ExternOther) {
EXPECT_DEMANGLING(
"_RNvYFK5not_CEuNtC1c1t1f", // <extern "not-C" fn() as c::t>::f
"<fn... as c::t>::f");
}
TEST(DemangleRust, Unsafe) {
EXPECT_DEMANGLING("_RNvYFUEuNtC1c1t1f", // <unsafe fn() as c::t>::f
"<fn... as c::t>::f");
}
TEST(DemangleRust, Binder) {
EXPECT_DEMANGLING(
// <for<'a> fn(&'a i32) -> &'a i32 as c::t>::f
"_RNvYFG_RL0_lEB5_NtC1c1t1f",
"<fn... as c::t>::f");
}
TEST(DemangleRust, AllFnSigFeaturesInOrder) {
EXPECT_DEMANGLING(
// <for<'a> unsafe extern "C" fn(&'a i32) -> &'a i32 as c::t>::f
"_RNvYFG_UKCRL0_lEB8_NtC1c1t1f",
"<fn... as c::t>::f");
}
TEST(DemangleRust, LifetimeInGenericArgs) {
EXPECT_DEMANGLING("_RINvC1c1fINtB2_1sL_EE", // c::f::<c::s::<'_>>
"c::f::<>");
}
} // namespace } // namespace
} // namespace debugging_internal } // namespace debugging_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment