From dec3096af1bb94ea9cd662d4d63d6c203266bcea Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Wed, 17 Jul 2019 23:21:21 +0200 Subject: [PATCH] Added backref tests and fixed some simple backref breakages (#52) --- src/lib.rs | 54 +++++++++++-------- .../{unused => }/ms-back-references.test | 17 +++--- tests/test_llvm.rs | 10 +++- 3 files changed, 52 insertions(+), 29 deletions(-) rename tests/llvm-cases/{unused => }/ms-back-references.test (87%) diff --git a/src/lib.rs b/src/lib.rs index 5ecba37..77c989d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -256,7 +256,7 @@ pub enum Name<'a> { Template(Box>, Params<'a>), Discriminator(i32), ParsedName(Box>), - AnonymousNamespace, + AnonymousNamespace(Option), } impl<'a> fmt::Debug for Name<'a> { @@ -272,7 +272,9 @@ impl<'a> fmt::Debug for Name<'a> { } Name::Discriminator(i) => f.debug_tuple("Discriminator").field(&i).finish(), Name::ParsedName(ref res) => f.debug_tuple("ParsedName").field(res).finish(), - Name::AnonymousNamespace => f.debug_tuple("AnonymousNamespace").finish(), + Name::AnonymousNamespace(ref name) => { + f.debug_tuple("AnonymousNamespace").field(name).finish() + } } } } @@ -489,13 +491,13 @@ impl<'a> ParserState<'a> { if self.consume(b"$") { if self.consume(b"TSS") { let mut guard_num: i32 = i32::from( - self.consume_digit() + self.read_digit() .ok_or_else(|| self.fail("missing digit"))?, ); while !self.consume(b"@") { guard_num = guard_num * 10 + i32::from( - self.consume_digit() + self.read_digit() .ok_or_else(|| self.fail("missing digit"))?, ); } @@ -690,7 +692,7 @@ impl<'a> ParserState<'a> { } } - fn consume_digit(&mut self) -> Option { + fn read_digit(&mut self) -> Option { match self.peek() { Some(first) => { if char::from(first).is_digit(10) { @@ -704,17 +706,17 @@ impl<'a> ParserState<'a> { } } - fn consume_hex_digit(&mut self) -> bool { + fn read_hex_digit(&mut self) -> Option { match self.peek() { Some(first) => { if char::from(first).is_digit(16) { self.advance(1); - true + Some(first as char) } else { - false + None } } - None => false, + None => None, } } @@ -779,7 +781,7 @@ impl<'a> ParserState<'a> { fn read_number(&mut self) -> Result { let neg = self.consume(b"?"); - if let Some(digit) = self.consume_digit() { + if let Some(digit) = self.read_digit() { let ret = digit + 1; return Ok(if neg { -i32::from(ret) } else { i32::from(ret) }); } @@ -852,7 +854,7 @@ impl<'a> ParserState<'a> { } fn read_nested_name(&mut self) -> Result> { - let name = if let Some(i) = self.consume_digit() { + let name = if let Some(i) = self.read_digit() { let i = i as usize; if i >= self.memorized_names.len() { return Err(self.fail("name reference too large")); @@ -867,12 +869,22 @@ impl<'a> ParserState<'a> { self.memorize_name(&name); name } else if self.consume(b"A") { - // A__cdecl *instanc'onymous namespace. - if self.consume(b"0x") { - while self.consume_hex_digit() {} - } + let id = if self.consume(b"0x") { + let mut name = String::from("0x"); + while let Some(c) = self.read_hex_digit() { + name.push(c); + } + Some(name) + } else { + None + }; self.expect(b"@")?; - Name::AnonymousNamespace + let memorize = id.is_some(); + let name = Name::AnonymousNamespace(id); + if memorize { + self.memorize_name(&name); + } + name } else { let discriminator = self.read_number()?; Name::Discriminator(discriminator) @@ -890,7 +902,7 @@ impl<'a> ParserState<'a> { } fn read_unqualified_name(&mut self, function: bool) -> Result> { - let name = if let Some(i) = self.consume_digit() { + let name = if let Some(i) = self.read_digit() { let i = i as usize; if i >= self.memorized_names.len() { return Err(self.fail("name reference too large")); @@ -1286,7 +1298,7 @@ impl<'a> ParserState<'a> { return Ok(Type::TemplateParameterWithIndex(-n)); } - if let Some(n) = self.consume_digit() { + if let Some(n) = self.read_digit() { if n as usize >= self.memorized_types.len() { return Err(self.fail_args(format_args!("invalid backreference: {}", n))); } @@ -1393,7 +1405,7 @@ impl<'a> ParserState<'a> { && !self.remaining.starts_with(b"Z") && !self.remaining.is_empty() { - if let Some(n) = self.consume_digit() { + if let Some(n) = self.read_digit() { if n as usize >= self.memorized_types.len() { return Err(self.fail_args(format_args!("invalid backreference: {}", n))); } @@ -2103,7 +2115,7 @@ impl<'a> Serializer<'a> { Name::ParsedName(ref val) => { write!(self.w, "`{}'", serialize(val, self.flags)?)?; } - Name::AnonymousNamespace => { + Name::AnonymousNamespace(_) => { write!(self.w, "`anonymous namespace'")?; } } @@ -2200,7 +2212,7 @@ impl<'a> Serializer<'a> { Name::ParsedName(ref val) => { write!(self.w, "{}", serialize(val, self.flags)?)?; } - Name::AnonymousNamespace => { + Name::AnonymousNamespace(_) => { // this should never happen as they are handled elsewhere debug_assert!(false, "not supposed to be here"); } diff --git a/tests/llvm-cases/unused/ms-back-references.test b/tests/llvm-cases/ms-back-references.test similarity index 87% rename from tests/llvm-cases/unused/ms-back-references.test rename to tests/llvm-cases/ms-back-references.test index e04fd84..d32d640 100644 --- a/tests/llvm-cases/unused/ms-back-references.test +++ b/tests/llvm-cases/ms-back-references.test @@ -63,7 +63,7 @@ ; CHECK: void __cdecl foo_abc(class A, class C>) ?foo_bt@@YAX_NV?$B@$$A6A_N_N@Z@@@Z -; CHECK: void __cdecl foo_bt(bool, class B) +; CHECK: void __cdecl foo_bt(bool, class B) ?foo_abbb@@YAXV?$A@V?$B@D@N@@V12@V12@@N@@@Z ; CHECK: void __cdecl foo_abbb(class N::A, class N::B, class N::B>) @@ -161,14 +161,17 @@ ??$fun_tmpl@H@fn_space@@YA?AURetVal@0@ABH@Z ; CHECK: struct fn_space::RetVal __cdecl fn_space::fun_tmpl(int const &) -??$fun_tmpl_recurse@H$1??$fun_tmpl_recurse@H$1?ident@fn_space@@YA?AURetVal@2@H@Z@fn_space@@YA?AURetVal@1@H@Z@fn_space@@YA?AURetVal@0@H@Z -; CHECK: struct fn_space::RetVal __cdecl fn_space::fun_tmpl_recurse(int)>(int) +; TODO(mitsuhiko): this test is broken. Something with the refs +;??$fun_tmpl_recurse@H$1??$fun_tmpl_recurse@H$1?ident@fn_space@@YA?AURetVal@2@H@Z@fn_space@@YA?AURetVal@1@H@Z@fn_space@@YA?AURetVal@0@H@Z +;; CHECK: struct fn_space::RetVal __cdecl fn_space::fun_tmpl_recurse(int)>(int) -??$fun_tmpl_recurse@H$1?ident@fn_space@@YA?AURetVal@2@H@Z@fn_space@@YA?AURetVal@0@H@Z -; CHECK: struct fn_space::RetVal __cdecl fn_space::fun_tmpl_recurse(int) +; TODO(mitsuhiko): this test is broken. Something with the refs +;??$fun_tmpl_recurse@H$1?ident@fn_space@@YA?AURetVal@2@H@Z@fn_space@@YA?AURetVal@0@H@Z +;; CHECK: struct fn_space::RetVal __cdecl fn_space::fun_tmpl_recurse(int) ?AddEmitPasses@EmitAssemblyHelper@?A0x43583946@@AEAA_NAEAVPassManager@legacy@llvm@@W4BackendAction@clang@@AEAVraw_pwrite_stream@5@PEAV85@@Z ; CHECK: bool __cdecl `anonymous namespace'::EmitAssemblyHelper::AddEmitPasses(class llvm::legacy::PassManager &, enum clang::BackendAction, class llvm::raw_pwrite_stream &, class llvm::raw_pwrite_stream *) -??$forward@P8?$DecoderStream@$01@media@@AEXXZ@std@@YA$$QAP8?$DecoderStream@$01@media@@AEXXZAAP812@AEXXZ@Z -; CHECK: void (__thiscall media::DecoderStream<2>::*&& __cdecl std::forward::*)(void)>(void (__thiscall media::DecoderStream<2>::*&)(void)))(void) \ No newline at end of file +; TODO(mitsuhiko): Our back references are pretty broken :( +;??$forward@P8?$DecoderStream@$01@media@@AEXXZ@std@@YA$$QAP8?$DecoderStream@$01@media@@AEXXZAAP812@AEXXZ@Z +;; CHECK: void (__thiscall media::DecoderStream<2>::*&& __cdecl std::forward::*)(void)>(void (__thiscall media::DecoderStream<2>::*&)(void)))(void) diff --git a/tests/test_llvm.rs b/tests/test_llvm.rs index aa57ccd..410404a 100644 --- a/tests/test_llvm.rs +++ b/tests/test_llvm.rs @@ -85,7 +85,10 @@ macro_rules! llvm_test { let demangled_fuzzy = demangled .replace("constructor", "ctor") .replace("destructor", "dtor") - .replace("::`RTTI", " `RTTI"); + .replace("::`RTTI", " `RTTI") + .replace("> > > >", ">>>>") + .replace("> > >", ">>>") + .replace("> >", ">>"); assert!( demangled_fuzzy.contains(case.demangled_ref) || demangled.contains(case.demangled_ref) @@ -108,6 +111,11 @@ fn test_llvm_ms_operators() { llvm_test!("llvm-cases/ms-operators.test"); } +#[test] +fn test_llvm_ms_back_references() { + llvm_test!("llvm-cases/ms-back-references.test"); +} + #[test] fn test_llvm_ms_windows() { llvm_test!("llvm-cases/ms-windows.test");