msvc-demangler-0.10.1/.cargo_vcs_info.json0000644000000001360000000000100140170ustar { "git": { "sha1": "8bf673ed6310f8b4f687b9de972b99f1c1abc34b" }, "path_in_vcs": "" }msvc-demangler-0.10.1/.github/workflows/rust.yml000064400000000000000000000006521046102023000177270ustar 00000000000000name: Rust on: push: branches: - main pull_request: env: CARGO_TERM_COLOR: always jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Build run: cargo build --verbose - name: Test run: cargo test --verbose - name: Check formatting run: cargo fmt -- --check --verbose - name: Clippy run: cargo clippy --verbose -- -Dwarnings msvc-demangler-0.10.1/.gitignore000064400000000000000000000000401046102023000145710ustar 00000000000000 /target/ **/*.rs.bk Cargo.lock msvc-demangler-0.10.1/.travis.yml000064400000000000000000000002711046102023000147200ustar 00000000000000language: rust rust: - stable matrix: include: - name: "check" script: make check - name: "lint" script: make lint - name: "test" script: make test msvc-demangler-0.10.1/Cargo.lock0000644000000005770000000000100120030ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "bitflags" version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] name = "msvc-demangler" version = "0.10.1" dependencies = [ "bitflags", ] msvc-demangler-0.10.1/Cargo.toml0000644000000020140000000000100120120ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] name = "msvc-demangler" version = "0.10.1" authors = [ "Markus Stange ", "Jeff Muizelaar ", ] description = "A rust library that demangles / undecorates C++ symbols mangled by MSVC" documentation = "https://docs.rs/msvc-demangler/" readme = "README.md" keywords = [ "demangle", "undecorate", "c-plus-plus", "msvc", ] license = "MIT/NCSA" repository = "https://github.com/mstange/msvc-demangler-rust" [[bin]] name = "undname" path = "src/bin/undname.rs" [dependencies.bitflags] version = "2" msvc-demangler-0.10.1/Cargo.toml.orig000064400000000000000000000010231046102023000154720ustar 00000000000000[package] authors = ["Markus Stange ", "Jeff Muizelaar "] name = "msvc-demangler" version = "0.10.1" keywords = ["demangle", "undecorate", "c-plus-plus", "msvc"] license = "MIT/NCSA" documentation = "https://docs.rs/msvc-demangler/" description = "A rust library that demangles / undecorates C++ symbols mangled by MSVC" repository = "https://github.com/mstange/msvc-demangler-rust" readme = "README.md" [dependencies] bitflags = "2" [[bin]] name = "undname" path = "src/bin/undname.rs" msvc-demangler-0.10.1/LICENSE.LLVM000064400000000000000000000061701046102023000143710ustar 00000000000000============================================================================== LLVM Release License ============================================================================== University of Illinois/NCSA Open Source License Copyright (c) 2003-2017 University of Illinois at Urbana-Champaign. All rights reserved. Developed by: LLVM Team University of Illinois at Urbana-Champaign http://llvm.org Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal with the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution. * Neither the names of the LLVM Team, University of Illinois at Urbana-Champaign, nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior written permission. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. ============================================================================== Copyrights and Licenses for Third Party Software Distributed with LLVM: ============================================================================== The LLVM software contains code written by third parties. Such software will have its own individual LICENSE.TXT file in the directory in which it appears. This file will describe the copyrights, license, and restrictions which apply to that code. The disclaimer of warranty in the University of Illinois Open Source License applies to all code in the LLVM Distribution, and nothing in any of the other licenses gives permission to use the names of the LLVM Team or the University of Illinois to endorse or promote products derived from this Software. The following pieces of software have additional or alternate copyrights, licenses, and/or restrictions: Program Directory ------- --------- Google Test llvm/utils/unittest/googletest OpenBSD regex llvm/lib/Support/{reg*, COPYRIGHT.regex} pyyaml tests llvm/test/YAMLParser/{*.data, LICENSE.TXT} ARM contributions llvm/lib/Target/ARM/LICENSE.TXT md5 contributions llvm/lib/Support/MD5.cpp llvm/include/llvm/Support/MD5.h msvc-demangler-0.10.1/LICENSE.MIT000064400000000000000000000020441046102023000142440ustar 00000000000000Copyright 2017-2018 Google, Mozilla Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. msvc-demangler-0.10.1/Makefile000064400000000000000000000014011046102023000142430ustar 00000000000000all: check test .PHONY: all check-source: @cargo check .PHONY: check-source check-format: @rustup component add rustfmt --toolchain stable 2> /dev/null @cargo +stable fmt -- --check .PHONY: check-format check: check-source check-format .PHONY: check test-cargo: @cargo test .PHONY: test-cargo test-wasm-build: @rustup target add wasm32-unknown-unknown --toolchain stable 2> /dev/null @cargo build --target=wasm32-unknown-unknown .PHONY: test-cargo test: test-cargo test-wasm-build .PHONY: test lint: @rustup component add clippy --toolchain stable 2> /dev/null @cargo +stable clippy --all --tests -- -D clippy::all .PHONY: lint update-readme: @cargo-readme -V &> /dev/null || cargo install cargo-readme @cargo readme > README.md .PHONY: update-readme msvc-demangler-0.10.1/README.md000064400000000000000000000014661046102023000140750ustar 00000000000000# msvc-demangler msvc-demangler is a crate for Rust that can demangle C++ symbols which use the MSVC mangling scheme. These are emitted by the Microsoft C++ compiler for Windows as well as some others. ## Example ```rust use msvc_demangler; let flags = msvc_demangler::DemangleFlags::llvm(); let result = msvc_demangler::demangle("??_0klass@@QEAAHH@Z", flags).unwrap(); println!("{}", result); ``` ## Behavior It's functionality is similar to `undname` on Windows and the underlying `UnDecorateSymbolName` function. Since Microsoft does not document the mangling scheme this is likely not to be entirely accurate. When unclear the implementation tries to follow what LLVM does. ## License This msvc-demangler is dual licensed under the MIT and the University of Illinois Open Source Licenses. License: MIT/NCSA msvc-demangler-0.10.1/examples/msvc-demangle.rs000064400000000000000000000007241046102023000175200ustar 00000000000000use std::env; extern crate msvc_demangler; use msvc_demangler::*; fn main() { let args: Vec = env::args().collect(); if args.len() != 2 { println!("{} ", args[0]); std::process::exit(1); } match demangle(&args[1], DemangleFlags::COMPLETE) { Ok(s) => { println!("{}", s); } Err(err) => { eprintln!("error: {:?}", err); std::process::exit(1); } } } msvc-demangler-0.10.1/src/bin/undname.rs000064400000000000000000000025251046102023000161470ustar 00000000000000extern crate msvc_demangler; use std::env; use std::io; use std::io::BufRead; fn main() { let mut args: Vec<_> = env::args().collect(); args.remove(0); let verbose = if args.first().map(|x| x.as_str()) == Some("-v") { args.remove(0); true } else { false }; let print_demangled = |sym: &str| { let parsed = match msvc_demangler::parse(sym) { Ok(parsed) => parsed, Err(err) => { eprintln!("error: {}", err); println!("{}", sym); return; } }; if verbose { eprintln!("{:#?}", &parsed); } let flags = msvc_demangler::DemangleFlags::llvm(); let demangled = msvc_demangler::serialize(&parsed, flags); match demangled { Ok(ref string) => println!("{}", string), Err(err) => { eprintln!("error: {}", err); println!("{}", sym); } } }; if args.is_empty() { let stdin = io::stdin(); let handle = stdin.lock(); for line in handle.lines() { match line { Ok(line) => print_demangled(&line), _ => continue, } } } else { for arg in args { print_demangled(&arg); } } } msvc-demangler-0.10.1/src/lib.rs000064400000000000000000002540031046102023000145160ustar 00000000000000//! msvc-demangler is a crate for Rust that can demangle C++ symbols which use //! the MSVC mangling scheme. These are emitted by the Microsoft C++ compiler //! for Windows as well as some others. //! //! # Example //! //! ``` //! use msvc_demangler; //! let flags = msvc_demangler::DemangleFlags::llvm(); //! let result = msvc_demangler::demangle("??_0klass@@QEAAHH@Z", flags).unwrap(); //! println!("{}", result); //! ``` //! //! # Behavior //! //! It's functionality is similar to `undname` on Windows and the underlying //! `UnDecorateSymbolName` function. Since Microsoft does not document the //! mangling scheme this is likely not to be entirely accurate. When unclear //! the implementation tries to follow what LLVM does. //! //! # License //! //! This msvc-demangler is dual licensed under the MIT and the University of //! Illinois Open Source Licenses. #![deny(missing_debug_implementations)] #![deny(unsafe_code)] #[macro_use] extern crate bitflags; use std::borrow::Cow; use std::cmp::min; use std::error; use std::fmt; use std::io; use std::io::Write; use std::mem; use std::result; use std::str; use std::str::Utf8Error; use std::string::FromUtf8Error; pub struct Error { repr: ErrorRepr, } impl fmt::Debug for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&self.repr, f) } } #[derive(Debug)] pub enum ErrorRepr { FromUtf8(FromUtf8Error), Utf8(Utf8Error), Io(io::Error), ParseError(Cow<'static, str>, String, usize), Other(String), } impl Error { /// Creates a simple error message. pub fn new>(s: S) -> Error { Error { repr: ErrorRepr::Other(s.into()), } } fn new_parse_error(s: Cow<'static, str>, input: &str, offset: usize) -> Error { let context = Cow::Borrowed(input.as_bytes().get(offset..).unwrap_or(&[])); let context = if context.len() > 20 { Cow::Owned(format!("{}...", String::from_utf8_lossy(&context[..20]))) } else { String::from_utf8_lossy(&context) }; Error { repr: ErrorRepr::ParseError(s, context.to_string(), offset), } } /// Returns the offset in the input where the error happened. pub fn offset(&self) -> Option { match self.repr { ErrorRepr::ParseError(_, _, offset) => Some(offset), _ => None, } } } impl From for Error { fn from(err: Utf8Error) -> Error { Error { repr: ErrorRepr::Utf8(err), } } } impl From for Error { fn from(err: FromUtf8Error) -> Error { Error { repr: ErrorRepr::FromUtf8(err), } } } impl From for Error { fn from(err: std::io::Error) -> Error { Error { repr: ErrorRepr::Io(err), } } } impl error::Error for Error { fn source(&self) -> Option<&(dyn error::Error + 'static)> { match self.repr { ErrorRepr::FromUtf8(ref e) => Some(e), ErrorRepr::Utf8(ref e) => Some(e), ErrorRepr::Io(ref e) => Some(e), ErrorRepr::ParseError(..) => None, ErrorRepr::Other(_) => None, } } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.repr { ErrorRepr::FromUtf8(ref e) => fmt::Display::fmt(e, f), ErrorRepr::Utf8(ref e) => fmt::Display::fmt(e, f), ErrorRepr::Io(ref e) => fmt::Display::fmt(e, f), ErrorRepr::ParseError(ref msg, ref context, offset) => { write!(f, "{} (offset: {}, remaining: {:?})", msg, offset, context) } ErrorRepr::Other(ref msg) => write!(f, "{}", msg), } } } type Result = result::Result; bitflags! { #[derive(Clone, Copy, Debug, PartialEq)] pub struct StorageClass: u32 { const CONST = 0b0_0000_0001; const VOLATILE = 0b0_0000_0010; const FAR = 0b0_0000_0100; const HUGE = 0b0_0000_1000; const UNALIGNED = 0b0_0001_0000; const RESTRICT = 0b0_0010_0000; const PTR64 = 0b0_0100_0000; const LVALUE_QUAL = 0b0_1000_0000; const RVALUE_QUAL = 0b1_0000_0000; } } bitflags! { #[derive(Clone, Copy)] pub struct DemangleFlags: u32 { /// Undecorate 32-bit decorated names. const DECODE_32_BIT = 0x0800; /// Enable full undecoration. const COMPLETE = 0x0000; /// Undecorate only the name for primary declaration. Returns [scope::]name. Does expand template parameters. const NAME_ONLY = 0x1000; /// Disable expansion of access specifiers for members. const NO_ACCESS_SPECIFIERS = 0x0080; // /// Disable expansion of the declaration language specifier. // const NO_ALLOCATION_LANGUAGE = 0x0010; // /// Disable expansion of the declaration model. // const NO_ALLOCATION_MODEL = 0x0008; // /// Do not undecorate function arguments. // const NO_ARGUMENTS = 0x2000; /// Disable expansion of CodeView modifiers on the this type for primary declaration. const NO_CV_THISTYPE = 0x0040; /// Disable expansion of return types for primary declarations. const NO_FUNCTION_RETURNS = 0x0004; // /// Remove leading underscores from Microsoft keywords. // const NO_LEADING_UNDERSCORES = 0x0001; /// Disable expansion of the static or virtual attribute of members. const NO_MEMBER_TYPE = 0x0200; /// Disable expansion of Microsoft keywords. const NO_MS_KEYWORDS = 0x0002; /// Disable expansion of Microsoft keywords on the this type for primary declaration. const NO_MS_THISTYPE = 0x0020; /// Enable Microsoft type names. const MS_TYPENAMES = 0x0400; // /// Disable expansion of the Microsoft model for user-defined type returns. // const NO_RETURN_UDT_MODEL = 0x0400; // /// Do not undecorate special names, such as vtable, vcall, vector, metatype, and so on. // const NO_SPECIAL_SYMS = 0x4000; /// Disable all modifiers on the this type. const NO_THISTYPE = Self::NO_MS_THISTYPE.bits() | Self::NO_CV_THISTYPE.bits(); // /// Disable expansion of throw-signatures for functions and pointers to functions. // const NO_THROW_SIGNATURES = 0x0100; /// Disable output of struct/union/class/enum specifiers. // (Not sure if this duplicates an existing flag) const NO_CLASS_TYPE = 0x10_0000; /// Insert a space after each comma. const SPACE_AFTER_COMMA = 0x20_0000; /// Make * and & hug the type name. const HUG_TYPE = 0x40_0000; /// Insert a space before pointers. const SPACE_BEFORE_POINTER = 0x80_0000; /// Add ptr64 to output. This is disabled by default because it's also not /// added by LLVM. This is in a way the inverse of the DIA `UNDNAME_NO_PTR64` const WITH_PTR64 = 0x100_0000; } } impl DemangleFlags { pub fn llvm() -> DemangleFlags { DemangleFlags::COMPLETE | DemangleFlags::SPACE_AFTER_COMMA | DemangleFlags::SPACE_BEFORE_POINTER | DemangleFlags::MS_TYPENAMES | DemangleFlags::HUG_TYPE } } // Calling conventions #[derive(Clone, Copy, Debug, PartialEq)] pub enum CallingConv { Cdecl, Pascal, Thiscall, Stdcall, Fastcall, _Regcall, } bitflags! { #[derive(Clone, Debug, PartialEq)] pub struct FuncClass: u32 { const PUBLIC = 0b0000_0001; const PROTECTED = 0b0000_0010; const PRIVATE = 0b0000_0100; const GLOBAL = 0b0000_1000; const STATIC = 0b0001_0000; const VIRTUAL = 0b0010_0000; const FAR = 0b0100_0000; const THUNK = 0b1000_0000; } } // The kind of variable storage. In LLVM this is called storage class. #[derive(Clone, Copy, Debug, PartialEq)] pub enum VarStorageKind { PrivateStatic, ProtectedStatic, PublicStatic, Global, FunctionLocalStatic, } // Represents an identifier which may be a template. #[derive(Clone, PartialEq)] pub enum Name<'a> { Md5(&'a [u8]), Operator(Operator<'a>), NonTemplate(&'a [u8]), AsInterface(&'a [u8]), Template(Box>, Params<'a>), Discriminator(i32), ParsedName(Box>), AnonymousNamespace(Option), } impl<'a> fmt::Debug for Name<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Name::Md5(s) => f .debug_tuple("Md5") .field(&String::from_utf8_lossy(s)) .finish(), Name::Operator(ref op) => f.debug_tuple("Operator").field(&op).finish(), Name::NonTemplate(s) => f .debug_tuple("NonTemplate") .field(&String::from_utf8_lossy(s)) .finish(), Name::AsInterface(s) => f .debug_tuple("AsInterface") .field(&String::from_utf8_lossy(s)) .finish(), Name::Template(ref name, ref params) => { f.debug_tuple("Template").field(name).field(params).finish() } Name::Discriminator(i) => f.debug_tuple("Discriminator").field(&i).finish(), Name::ParsedName(ref res) => f.debug_tuple("ParsedName").field(res).finish(), Name::AnonymousNamespace(ref name) => { f.debug_tuple("AnonymousNamespace").field(name).finish() } } } } #[derive(Clone, Debug, PartialEq)] pub enum Operator<'a> { Ctor, Dtor, New, Delete, Equal, RShift, LShift, Bang, EqualEqual, BangEqual, Subscript, Conversion, // TODO Arrow, Star, PlusPlus, MinusMinus, Minus, Plus, Amp, ArrowStar, Slash, Percent, Less, LessEqual, Greater, GreaterEqual, Comma, Call, Tilde, Caret, Pipe, AmpAmp, PipePipe, StarEqual, PlusEqual, MinusEqual, SlashEqual, PercentEqual, GreaterGreaterEqual, LessLessEqual, AmpEqual, PipeEqual, CaretEqual, VFTable, VBTable, VCall, Typeof, LocalStaticGuard(Option), String, VBaseDtor, VectorDeletingDtor, DefaultCtorClosure, ScalarDeletingDtor, VectorCtorIterator, VectorDtorIterator, VectorVBaseCtorIterator, VirtualDisplacementMap, EHVectorCtorIterator, EHVectorDtorIterator, EHVectorVBaseCtorIterator, CopyCtorClosure, LocalVFTable, LocalVFTableCtorClosure, ArrayNew, ArrayDelete, PlacementDeleteClosure, PlacementArrayDeleteClosure, CoroutineAwait, LiteralOperatorName, RTTITypeDescriptor(StorageClass, Box>), RTTIBaseClassDescriptor(i32, i32, i32, i32), RTTIBaseClassArray, RTTIClassHierarchyDescriptor, RTTIClassCompleteObjectLocator, DynamicInitializer, DynamicAtexitDtor, LocalStaticThreadGuard(Option), } #[derive(Clone, Debug, PartialEq)] pub struct NameSequence<'a> { pub names: Vec>, } #[derive(Clone, Debug, PartialEq)] pub struct Params<'a> { pub types: Vec>, } #[derive(Clone, Debug, PartialEq)] pub struct Symbol<'a> { pub name: Name<'a>, pub scope: NameSequence<'a>, } // The type class. Mangled symbols are first parsed and converted to // this type and then converted to string. #[derive(Clone, Debug, PartialEq)] pub enum Type<'a> { None, MemberFunction( FuncClass, CallingConv, Params<'a>, StorageClass, Box>, ), // StorageClass is for the 'this' pointer MemberFunctionPointer( Symbol<'a>, FuncClass, CallingConv, Params<'a>, StorageClass, Box>, ), NonMemberFunction(CallingConv, Params<'a>, StorageClass, Box>), CXXVBTable(NameSequence<'a>, StorageClass), CXXVFTable(NameSequence<'a>, StorageClass), VCallThunk(i32, CallingConv), TemplateParameterWithIndex(i32), ThreadSafeStaticGuard(i32), Constant(i32), ConstantString(Vec), Ptr(Box>, StorageClass), Ref(Box>, StorageClass), RValueRef(Box>, StorageClass), Array(i32, Box>, StorageClass), Var(Box>, VarStorageKind, StorageClass), Alias(Symbol<'a>, StorageClass), Struct(Symbol<'a>, StorageClass), Union(Symbol<'a>, StorageClass), Class(Symbol<'a>, StorageClass), Enum(Symbol<'a>, StorageClass), Void(StorageClass), Bool(StorageClass), Char(StorageClass), Schar(StorageClass), Uchar(StorageClass), Short(StorageClass), Ushort(StorageClass), Int(StorageClass), Uint(StorageClass), Long(StorageClass), Ulong(StorageClass), Int64(StorageClass), Uint64(StorageClass), Int128(StorageClass), Uint128(StorageClass), Wchar(StorageClass), Char8(StorageClass), Char16(StorageClass), Char32(StorageClass), Float(StorageClass), Double(StorageClass), Ldouble(StorageClass), VarArgs, EmptyParameterPack, Nullptr, RTTIType, } #[derive(Debug, Clone, PartialEq)] pub struct ParseResult<'a> { pub symbol: Symbol<'a>, pub symbol_type: Type<'a>, } // Demangler class takes the main role in demangling symbols. // It has a set of functions to parse mangled symbols into Type instnaces. // It also has a set of functions to cnovert Type instances to strings. struct ParserState<'a> { // Mangled symbol. read_* functions shorten this string // as they parse it. remaining: &'a [u8], // The original input input: &'a str, // how many bytes we advanced offset: usize, // The first 10 names in a mangled name can be back-referenced by // special name @[0-9]. This is a storage for the first 10 names. memorized_names: Vec>, memorized_types: Vec>, } impl<'a> ParserState<'a> { fn fail(&self, s: &'static str) -> Error { Error::new_parse_error(Cow::Borrowed(s), self.input, self.offset) } fn fail_args(&self, args: fmt::Arguments) -> Error { Error::new_parse_error(Cow::Owned(format!("{}", args)), self.input, self.offset) } fn parse(&mut self) -> Result> { // MSVC-style mangled symbols must start with b'?'. if !self.consume(b"?") { return Err(self.fail("does not start with b'?'")); } if self.consume(b"?@") { let name = self.read_md5_name()?; return Ok(ParseResult { symbol: Symbol { name, scope: NameSequence { names: Vec::new() }, }, symbol_type: Type::None, }); } if self.consume(b"$") { if self.consume(b"TSS") { let mut guard_num: i32 = i32::from( self.read_digit() .ok_or_else(|| self.fail("missing digit"))?, ); while !self.consume(b"@") { guard_num = guard_num * 10 + i32::from( self.read_digit() .ok_or_else(|| self.fail("missing digit"))?, ); } let name = self.read_nested_name()?; let scope = self.read_scope()?; self.expect(b"4HA")?; return Ok(ParseResult { symbol: Symbol { name, scope }, symbol_type: Type::ThreadSafeStaticGuard(guard_num), }); } let name = self.read_template_name()?; return Ok(ParseResult { symbol: Symbol { name, scope: NameSequence { names: Vec::new() }, }, symbol_type: Type::None, }); } // What follows is a main symbol name. This may include // namespaces or class names. let mut symbol = self.read_name(true)?; // Special case for some weird cases where extra data is tacked on // after the main symbol but belongs into the symbol. match symbol.name { Name::Operator(Operator::LocalStaticGuard(ref mut scope_index)) | Name::Operator(Operator::LocalStaticThreadGuard(ref mut scope_index)) => { let _is_visible = if self.consume(b"4IA") { false } else if self.consume(b"5") { true } else { return Err(self.fail("unexpected local guard marker")); }; if !self.remaining.is_empty() { *scope_index = Some(self.read_unsigned()?); }; } _ => {} } if let Ok(c) = self.get() { let symbol_type = match c { b'0'..=b'4' => { // Read a variable. let kind = match c { b'0' => VarStorageKind::PrivateStatic, b'1' => VarStorageKind::ProtectedStatic, b'2' => VarStorageKind::PublicStatic, b'3' => VarStorageKind::Global, b'4' => VarStorageKind::FunctionLocalStatic, _ => unreachable!(), }; let ty = self.read_var_type(StorageClass::empty())?; let sc = self.read_storage_class(); Type::Var(Box::new(ty), kind, sc) } b'6' => { let access_class = self.read_qualifier(); let scope = self.read_scope()?; Type::CXXVFTable(scope, access_class) } b'7' => { let access_class = self.read_qualifier(); let scope = self.read_scope()?; Type::CXXVBTable(scope, access_class) } b'9' => { // extern "C" names have their class and type omitted. Type::None } b'Y' => { // Read a non-member function. let calling_conv = self.read_calling_conv()?; let storage_class = self.read_storage_class_for_return()?; let return_type = self.read_var_type(storage_class)?; let params = self.read_func_params()?; Type::NonMemberFunction( calling_conv, params, StorageClass::empty(), Box::new(return_type), ) } b'_' => { // Read an encoded string. let char_bytes = match self.get()? { b'0' => 1, // char b'1' => 2, // wchar_t _ => { return Err(self.fail("unknown string character type")); } }; self.read_encoded_string(char_bytes)? } b'$' => { self.expect(b"B")?; let vftable_offset = self.read_number()?; self.expect(b"A")?; let calling_conv = self.read_calling_conv()?; Type::VCallThunk(vftable_offset, calling_conv) } b'8' => Type::RTTIType, c => { // Read a member function. let func_class = self.read_func_class(c)?; let access_class = if func_class.contains(FuncClass::STATIC) { StorageClass::empty() } else { self.read_func_qualifiers()? }; let calling_conv = self.read_calling_conv()?; let storage_class_for_return = self.read_storage_class_for_return()?; let return_type = self.read_func_return_type(storage_class_for_return)?; let params = self.read_func_params()?; Type::MemberFunction( func_class, calling_conv, params, access_class, Box::new(return_type), ) } }; Ok(ParseResult { symbol, symbol_type, }) } else { Ok(ParseResult { symbol, symbol_type: Type::None, }) } } fn peek(&self) -> Option { self.remaining.first().cloned() } fn get(&mut self) -> Result { match self.peek() { Some(first) => { self.advance(1); Ok(first) } None => Err(self.fail("unexpected end of input")), } } fn consume(&mut self, s: &[u8]) -> bool { if self.remaining.starts_with(s) { self.advance(s.len()); true } else { false } } fn advance(&mut self, len: usize) { let new_remaining = self.remaining.get(len..).unwrap_or(&[]); self.offset += self.remaining.len() - new_remaining.len(); self.remaining = new_remaining; } fn expect(&mut self, s: &[u8]) -> Result<()> { if !self.consume(s) { Err(self.fail_args(format_args!("{} expected", str::from_utf8(s)?,))) } else { Ok(()) } } /// An MD5 mangled name is `??@` followed by 32 characters and a terminating `@`. /// /// See https://github.com/llvm/llvm-project/blob/818cf30b83305fa4a2f75821349210b0f7aff4a4/llvm/lib/Demangle/MicrosoftDemangle.cpp#L754 fn read_md5_name(&mut self) -> Result> { let start_offset = self.offset; while self.read_hex_digit().is_some() {} let end_offset = self.offset; if self.offset - start_offset != 32 || !self.consume(b"@") { return Err(self.fail("expected MD5 mangled name of length 32")); } Ok(Name::Md5(&self.input.as_bytes()[start_offset..end_offset])) } fn read_digit(&mut self) -> Option { match self.peek() { Some(first) => { if char::from(first).is_ascii_digit() { self.advance(1); Some(first - b'0') } else { None } } None => None, } } fn read_hex_digit(&mut self) -> Option { match self.peek() { Some(first) => { if char::from(first).is_ascii_hexdigit() { self.advance(1); Some(first as char) } else { None } } None => None, } } fn read_encoded_string(&mut self, char_bytes: i32) -> Result> { let byte_length = self.read_number()?; // including null terminator let _crc = self.read_number()?; let bytes = min(byte_length, char_bytes * 32); let mut collected = vec![]; for _i in 0..bytes { let c = self.get()?; let byte: u8 = match c { b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z' | b'_' | b'$' => c, b'?' => { let c = self.get()?; match c { b'A'..=b'Z' => c - b'A' + 0xe1, b'a'..=b'z' => c - b'A' + 0xc1, b'0'..=b'9' => { let v = &[ b',', b'/', b'\\', b':', b'.', b' ', b'\n', b'\t', b'\'', b'-', ]; v[(c - b'0') as usize] } b'$' => { let high = self.get()? - b'A'; let low = self.get()? - b'A'; high << 4 | low } _ => { return Err(self.fail_args(format_args!( "unknown escaped encoded string character {}", char::from(c) ))); } } } _ => { return Err(self.fail_args(format_args!( "unknown escaped encoded string character {}", char::from(c) ))); } }; collected.push(byte); } Ok(Type::ConstantString(collected)) } // Sometimes numbers are encoded in mangled symbols. For example, // "int (*x)[20]" is a valid C type (x is a pointer to an array of // length 20), so we need some way to embed numbers as part of symbols. // This function parses it. // // ::= [?] // // ::= # when 1 <= Number <= 10 // ::= + @ # when Numbrer == 0 or >= 10 // // ::= [A-P] # A = 0, B = 1, ... fn read_number(&mut self) -> Result { let neg = self.consume(b"?"); if let Some(digit) = self.read_digit() { let ret = digit + 1; return Ok(if neg { -i32::from(ret) } else { i32::from(ret) }); } let mut i = 0; let mut ret = 0i32; for c in self.remaining { match *c { b'@' => { self.advance(i + 1); return Ok(if neg { ret.wrapping_neg() } else { ret }); } b'A'..=b'P' => { ret = (ret << 4) + i32::from(c - b'A'); i += 1; } _ => { return Err(self.fail("bad number")); } } } Err(self.fail("bad number")) } fn read_unsigned(&mut self) -> Result { let num = self.read_number()?; if num < 0 { return Err(self.fail("expected unsigned")); } Ok(num as u32) } // Read until the next b'@'. fn read_string(&mut self) -> Result<&'a [u8]> { if let Some(pos) = self.remaining.iter().position(|&x| x == b'@') { let ret = &self.remaining[0..pos]; self.advance(pos + 1); Ok(ret) } else { Err(self.fail("read_string: missing b'@'")) } } // First 10 strings can be referenced by special names ?0, ?1, ..., ?9. // Memorize it. fn memorize_name(&mut self, n: &Name<'a>) { // TODO: the contains check does an equality check on the Name enum, which // might do unexpected things in subtle cases. It's not a pure string equality check. if self.memorized_names.len() < 10 && !self.memorized_names.contains(n) { self.memorized_names.push(n.clone()); } } fn memorize_type(&mut self, t: &Type<'a>) { // TODO: the contains check does an equality check on the Type enum, which // might do unexpected things in subtle cases. It's not a pure string equality check. if self.memorized_types.len() < 10 && !self.memorized_types.contains(t) { self.memorized_types.push(t.clone()); } } fn read_template_name(&mut self) -> Result> { // Templates have their own context for backreferences. let saved_memorized_names = mem::take(&mut self.memorized_names); let saved_memorized_types = mem::take(&mut self.memorized_types); let name = self.read_unqualified_name(false)?; // how does wine deal with ??$?DM@std@@YA?AV?$complex@M@0@ABMABV10@@Z let template_params = self.read_params()?; let _ = mem::replace(&mut self.memorized_names, saved_memorized_names); let _ = mem::replace(&mut self.memorized_types, saved_memorized_types); Ok(Name::Template(Box::new(name), template_params)) } fn read_nested_name(&mut self) -> Result> { 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")); } self.memorized_names[i].clone() } else if self.consume(b"?") { match self.peek() { Some(b'?') => Name::ParsedName(Box::new(self.parse()?)), _ => { if self.consume(b"$") { let name = self.read_template_name()?; self.memorize_name(&name); name } else if self.consume(b"A") { 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"@")?; let memorize = id.is_some(); let name = Name::AnonymousNamespace(id); if memorize { self.memorize_name(&name); } name } else if self.consume(b"Q") { let name = self.read_string()?; self.expect(b"@")?; let name = Name::AsInterface(name); self.memorize_name(&name); name } else { let discriminator = self.read_number()?; Name::Discriminator(discriminator) } } } } else { // Non-template functions or classes. let name = self.read_string()?; let name = Name::NonTemplate(name); self.memorize_name(&name); name }; Ok(name) } fn read_unqualified_name(&mut self, function: bool) -> Result> { 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")); } self.memorized_names[i].clone() } else if self.consume(b"?$") { let name = self.read_template_name()?; if !function { self.memorize_name(&name); } name } else if self.consume(b"?") { self.read_special_name()? } else { // Non-template functions or classes. let name = self.read_string()?; let name = Name::NonTemplate(name); self.memorize_name(&name); name }; Ok(name) } fn read_scope(&mut self) -> Result> { let mut names = Vec::new(); while !self.consume(b"@") { let name = self.read_nested_name()?; names.push(name); } Ok(NameSequence { names }) } // Parses a name in the form of A@B@C@@ which represents C::B::A. fn read_name(&mut self, function: bool) -> Result> { let name = self.read_unqualified_name(function)?; let scope = self.read_scope()?; Ok(Symbol { name, scope }) } fn read_func_qualifiers(&mut self) -> Result { let ptr64 = if self.consume(b"E") { StorageClass::PTR64 } else { StorageClass::empty() }; let restrict = if self.consume(b"I") { StorageClass::RESTRICT } else { StorageClass::empty() }; let unaligned = if self.consume(b"F") { StorageClass::UNALIGNED } else { StorageClass::empty() }; let ref_qualifiers = match self.peek() { Some(b'G') => { self.expect(b"G")?; StorageClass::LVALUE_QUAL } Some(b'H') => { self.expect(b"H")?; StorageClass::RVALUE_QUAL } _ => StorageClass::empty(), }; Ok(self.read_qualifier() | ptr64 | restrict | unaligned | ref_qualifiers) } fn read_func_type(&mut self, read_qualifiers: bool) -> Result> { let sc = if read_qualifiers { self.read_func_qualifiers()? } else { StorageClass::empty() }; let calling_conv = self.read_calling_conv()?; // this might have to be conditional on template context. For now // this does not cause issues. For more information see // https://github.com/mstange/msvc-demangler-rust/issues/21 let var_sc = if self.consume(b"?") { self.read_storage_class() } else { StorageClass::empty() }; let return_type = self.read_var_type(var_sc)?; let params = self.read_func_params()?; Ok(Type::NonMemberFunction( calling_conv, params, sc, Box::new(return_type), )) } fn read_special_name(&mut self) -> Result> { Ok(Name::Operator(match self.get()? { b'0' => Operator::Ctor, b'1' => Operator::Dtor, b'2' => Operator::New, b'3' => Operator::Delete, b'4' => Operator::Equal, b'5' => Operator::RShift, b'6' => Operator::LShift, b'7' => Operator::Bang, b'8' => Operator::EqualEqual, b'9' => Operator::BangEqual, b'A' => Operator::Subscript, b'B' => Operator::Conversion, b'C' => Operator::Arrow, b'D' => Operator::Star, b'E' => Operator::PlusPlus, b'F' => Operator::MinusMinus, b'G' => Operator::Minus, b'H' => Operator::Plus, b'I' => Operator::Amp, b'J' => Operator::ArrowStar, b'K' => Operator::Slash, b'L' => Operator::Percent, b'M' => Operator::Less, b'N' => Operator::LessEqual, b'O' => Operator::Greater, b'P' => Operator::GreaterEqual, b'Q' => Operator::Comma, b'R' => Operator::Call, b'S' => Operator::Tilde, b'T' => Operator::Caret, b'U' => Operator::Pipe, b'V' => Operator::AmpAmp, b'W' => Operator::PipePipe, b'X' => Operator::StarEqual, b'Y' => Operator::PlusEqual, b'Z' => Operator::MinusEqual, b'_' => match self.get()? { b'0' => Operator::SlashEqual, b'1' => Operator::PercentEqual, b'2' => Operator::GreaterGreaterEqual, b'3' => Operator::LessLessEqual, b'4' => Operator::AmpEqual, b'5' => Operator::PipeEqual, b'6' => Operator::CaretEqual, b'7' => Operator::VFTable, b'8' => Operator::VBTable, b'9' => Operator::VCall, b'A' => Operator::Typeof, b'B' => Operator::LocalStaticGuard(None), b'C' => Operator::String, b'D' => Operator::VBaseDtor, b'E' => Operator::VectorDeletingDtor, b'F' => Operator::DefaultCtorClosure, b'G' => Operator::ScalarDeletingDtor, b'H' => Operator::VectorCtorIterator, b'I' => Operator::VectorDtorIterator, b'J' => Operator::VectorVBaseCtorIterator, b'K' => Operator::VirtualDisplacementMap, b'L' => Operator::EHVectorCtorIterator, b'M' => Operator::EHVectorDtorIterator, b'N' => Operator::EHVectorVBaseCtorIterator, b'O' => Operator::CopyCtorClosure, b'R' => { let c = self.get()?; match c { b'0' => { self.expect(b"?")?; let storage_class = self.read_storage_class(); let t = self.read_var_type(storage_class)?; Operator::RTTITypeDescriptor(storage_class, Box::new(t)) } b'1' => { let nv_offset = self.read_number()?; let vbptr_offset = self.read_number()?; let vbtable_offset = self.read_number()?; let flags = self.read_number()?; Operator::RTTIBaseClassDescriptor( nv_offset, vbptr_offset, vbtable_offset, flags, ) } b'2' => Operator::RTTIBaseClassArray, b'3' => Operator::RTTIClassHierarchyDescriptor, b'4' => Operator::RTTIClassCompleteObjectLocator, _ => { return Err(self.fail("unknown RTTI Operator name")); } } } b'S' => Operator::LocalVFTable, b'T' => Operator::LocalVFTableCtorClosure, b'U' => Operator::ArrayNew, b'V' => Operator::ArrayDelete, b'X' => Operator::PlacementDeleteClosure, b'Y' => Operator::PlacementArrayDeleteClosure, b'_' => { if self.consume(b"L") { Operator::CoroutineAwait } else if self.consume(b"E") { Operator::DynamicInitializer } else if self.consume(b"F") { Operator::DynamicAtexitDtor } else if self.consume(b"J") { Operator::LocalStaticThreadGuard(None) } else if self.consume(b"K") { Operator::LiteralOperatorName // TODO: read , that's the operator name } else { return Err(self.fail("unknown operator name")); } } _ => { return Err(self.fail("unknown operator name")); } }, _ => { return Err(self.fail("unknown operator name")); } })) } fn read_func_class(&mut self, c: u8) -> Result { // TODO: need to figure out how to wrap up the adjustment. let mut read_thunk = |func_class| -> Result { let _adjustment = self.read_number()?; Ok(func_class | FuncClass::THUNK) }; Ok(match c { b'A' => FuncClass::PRIVATE, b'B' => FuncClass::PRIVATE | FuncClass::FAR, b'C' => FuncClass::PRIVATE | FuncClass::STATIC, b'D' => FuncClass::PRIVATE | FuncClass::STATIC, b'E' => FuncClass::PRIVATE | FuncClass::VIRTUAL, b'F' => FuncClass::PRIVATE | FuncClass::VIRTUAL, // TODO(mitsuhiko): llvm uses adjustor here instead of virtual b'G' => read_thunk(FuncClass::PRIVATE | FuncClass::VIRTUAL)?, // TODO(mitsuhiko): llvm uses adjustor here instead of virtual b'H' => read_thunk(FuncClass::PRIVATE | FuncClass::VIRTUAL | FuncClass::FAR)?, b'I' => FuncClass::PROTECTED, b'J' => FuncClass::PROTECTED | FuncClass::FAR, b'K' => FuncClass::PROTECTED | FuncClass::STATIC, b'L' => FuncClass::PROTECTED | FuncClass::STATIC | FuncClass::FAR, b'M' => FuncClass::PROTECTED | FuncClass::VIRTUAL, b'N' => FuncClass::PROTECTED | FuncClass::VIRTUAL | FuncClass::FAR, // TODO(mitsuhiko): llvm uses adjustor here instead of virtual b'O' => read_thunk(FuncClass::PROTECTED | FuncClass::VIRTUAL)?, // TODO(mitsuhiko): llvm uses adjustor here instead of virtual b'P' => read_thunk(FuncClass::PROTECTED | FuncClass::VIRTUAL | FuncClass::FAR)?, b'Q' => FuncClass::PUBLIC, b'R' => FuncClass::PUBLIC | FuncClass::FAR, b'S' => FuncClass::PUBLIC | FuncClass::STATIC, b'T' => FuncClass::PUBLIC | FuncClass::STATIC | FuncClass::FAR, b'U' => FuncClass::PUBLIC | FuncClass::VIRTUAL, b'V' => FuncClass::PUBLIC | FuncClass::VIRTUAL | FuncClass::FAR, // TODO(mitsuhiko): llvm uses adjustor here instead of virtual b'W' => read_thunk(FuncClass::PUBLIC | FuncClass::VIRTUAL)?, // TODO(mitsuhiko): llvm uses adjustor here instead of virtual b'X' => read_thunk(FuncClass::PUBLIC | FuncClass::VIRTUAL | FuncClass::FAR)?, b'Y' => FuncClass::GLOBAL, b'Z' => FuncClass::GLOBAL | FuncClass::FAR, _ => { return Err(self.fail("unknown func class")); } }) } fn read_qualifier(&mut self) -> StorageClass { let access_class = match self.peek() { Some(b'A') => StorageClass::empty(), Some(b'B') => StorageClass::CONST, Some(b'C') => StorageClass::VOLATILE, Some(b'D') => StorageClass::CONST | StorageClass::VOLATILE, Some(b'Q') => StorageClass::empty(), Some(b'R') => StorageClass::CONST, Some(b'S') => StorageClass::VOLATILE, Some(b'T') => StorageClass::CONST | StorageClass::VOLATILE, _ => return StorageClass::empty(), }; self.advance(1); access_class } fn read_calling_conv(&mut self) -> Result { Ok(match self.get()? { b'A' => CallingConv::Cdecl, b'B' => CallingConv::Cdecl, b'C' => CallingConv::Pascal, b'E' => CallingConv::Thiscall, b'G' => CallingConv::Stdcall, b'I' => CallingConv::Fastcall, _ => { return Err(self.fail("unknown calling conv")); } }) } // ::= // ::= @ # structors (they have no declared return type) fn read_func_return_type(&mut self, storage_class: StorageClass) -> Result> { if self.consume(b"@") { Ok(Type::None) } else { self.read_var_type(storage_class) } } fn read_storage_class(&mut self) -> StorageClass { let storage_class = match self.peek() { Some(b'A') => StorageClass::empty(), Some(b'B') => StorageClass::CONST, Some(b'C') => StorageClass::VOLATILE, Some(b'D') => StorageClass::CONST | StorageClass::VOLATILE, Some(b'E') => StorageClass::FAR, Some(b'F') => StorageClass::CONST | StorageClass::FAR, Some(b'G') => StorageClass::VOLATILE | StorageClass::FAR, Some(b'H') => StorageClass::CONST | StorageClass::VOLATILE | StorageClass::FAR, Some(b'Q') => StorageClass::empty(), Some(b'R') => StorageClass::CONST, Some(b'S') => StorageClass::VOLATILE, Some(b'T') => StorageClass::CONST | StorageClass::VOLATILE, _ => return StorageClass::empty(), }; self.advance(1); storage_class } fn read_storage_class_for_return(&mut self) -> Result { if !self.consume(b"?") { return Ok(StorageClass::empty()); } Ok(match self.get()? { b'A' => StorageClass::empty(), b'B' => StorageClass::CONST, b'C' => StorageClass::VOLATILE, b'D' => StorageClass::CONST | StorageClass::VOLATILE, _ => { return Err(self.fail("unknown storage class")); } }) } fn read_member_function_pointer(&mut self, read_qualifiers: bool) -> Result> { let symbol = self.read_name(true)?; let ptr64 = if self.consume(b"E") { StorageClass::PTR64 } else { StorageClass::empty() }; let (access_class, func_class) = if read_qualifiers { (self.read_qualifier() | ptr64, FuncClass::empty()) } else { let c = self.get()?; (ptr64, self.read_func_class(c)?) }; let calling_conv = self.read_calling_conv()?; let storage_class_for_return = self.read_storage_class_for_return()?; let return_type = self.read_func_return_type(storage_class_for_return)?; let params = self.read_func_params()?; Ok(Type::MemberFunctionPointer( symbol, func_class, calling_conv, params, access_class, Box::new(return_type), )) } // Reads a variable type. fn read_var_type(&mut self, mut sc: StorageClass) -> Result> { if self.consume(b"W4") { let name = self.read_name(false)?; return Ok(Type::Enum(name, sc)); } if self.consume(b"A6") { let func_type = self.read_func_type(false)?; return Ok(Type::Ref(Box::new(func_type), sc)); } if self.consume(b"P6") { let func_type = self.read_func_type(false)?; return Ok(Type::Ptr(Box::new(func_type), sc)); } if self.consume(b"P8") { return self.read_member_function_pointer(true); } if self.consume(b"$") { if self.consume(b"0") { let n = self.read_number()?; return Ok(Type::Constant(n)); } if self.consume(b"D") { let n = self.read_number()?; return Ok(Type::TemplateParameterWithIndex(n)); } if self.consume(b"$BY") { return self.read_array(); } if self.consume(b"$Q") { return Ok(Type::RValueRef(Box::new(self.read_pointee()?), sc)); } if self.consume(b"S") || self.consume(b"$V") || self.consume(b"$Z") || self.consume(b"$$V") { return Ok(Type::EmptyParameterPack); } if self.consume(b"$T") { return Ok(Type::Nullptr); } if self.consume(b"$A6") { return self.read_func_type(false); } if self.consume(b"$A8@@") { return self.read_func_type(true); } if self.consume(b"$Y") { let name = self.read_name(true)?; return Ok(Type::Alias(name, sc)); } // These next cases can fallthrough, so be careful adding new ones! if self.consume(b"$C") { sc = self.read_qualifier(); } else if let Some(x) = self.peek() { match x { // Inheritance specifiers, which we don't need to remember. b'1' | b'H' | b'I' | b'J' => { self.advance(1); self.expect(b"?")?; return self.read_member_function_pointer(false); } _ => {} }; } } if self.consume(b"?") { let n = self.read_number()?; return Ok(Type::TemplateParameterWithIndex(-n)); } 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))); } return Ok(self.memorized_types[n as usize].clone()); } Ok(match self.get()? { b'T' => Type::Union(self.read_name(false)?, sc), b'U' => Type::Struct(self.read_name(false)?, sc), b'V' => Type::Class(self.read_name(false)?, sc), b'A' => Type::Ref(Box::new(self.read_pointee()?), sc), b'B' => Type::Ref(Box::new(self.read_pointee()?), StorageClass::VOLATILE), b'P' => Type::Ptr(Box::new(self.read_pointee()?), sc), b'Q' => Type::Ptr(Box::new(self.read_pointee()?), StorageClass::CONST), b'R' => Type::Ptr(Box::new(self.read_pointee()?), StorageClass::VOLATILE), b'S' => Type::Ptr( Box::new(self.read_pointee()?), StorageClass::CONST | StorageClass::VOLATILE, ), b'Y' => self.read_array()?, b'X' => Type::Void(sc), b'D' => Type::Char(sc), b'C' => Type::Schar(sc), b'E' => Type::Uchar(sc), b'F' => Type::Short(sc), b'G' => Type::Ushort(sc), b'H' => Type::Int(sc), b'I' => Type::Uint(sc), b'J' => Type::Long(sc), b'K' => Type::Ulong(sc), b'M' => Type::Float(sc), b'N' => Type::Double(sc), b'O' => Type::Ldouble(sc), b'_' => match self.get()? { b'N' => Type::Bool(sc), b'J' => Type::Int64(sc), b'K' => Type::Uint64(sc), b'L' => Type::Int128(sc), b'M' => Type::Uint128(sc), b'W' => Type::Wchar(sc), b'Q' => Type::Char8(sc), b'S' => Type::Char16(sc), b'U' => Type::Char32(sc), _ => { return Err(self.fail("unknown primitive type")); } }, _c => { return Err(self.fail("unknown primitive type")); } }) } fn read_pointee(&mut self) -> Result> { let ptr64 = if self.consume(b"E") { StorageClass::PTR64 } else { StorageClass::empty() }; let storage_class = self.read_storage_class(); self.read_var_type(storage_class | ptr64) } fn read_array(&mut self) -> Result> { let dimension = self.read_number()?; if dimension <= 0 { return Err(self.fail_args(format_args!("invalid array dimension: {}", dimension))); } let (array, _) = self.read_nested_array(dimension)?; Ok(array) } fn read_nested_array(&mut self, dimension: i32) -> Result<(Type<'a>, StorageClass)> { if dimension > 0 { let len = self.read_number()?; let (inner_array, storage_class) = self.read_nested_array(dimension - 1)?; Ok(( Type::Array(len, Box::new(inner_array), storage_class), storage_class, )) } else { let storage_class = if self.consume(b"$$C") { if self.consume(b"B") { StorageClass::CONST } else if self.consume(b"C") || self.consume(b"D") { StorageClass::CONST | StorageClass::VOLATILE } else if !self.consume(b"A") { return Err(self.fail("unknown storage class")); } else { StorageClass::empty() } } else { StorageClass::empty() }; Ok((self.read_var_type(StorageClass::empty())?, storage_class)) } } // Reads a function or a template parameters. fn read_params(&mut self) -> Result> { // println!("read_params on {}", str::from_utf8(self.input)?); // Within the same parameter list, you can backreference the first 10 types. // let mut backref: Vec> = Vec::with_capacity(10); let mut params: Vec> = Vec::new(); while !self.remaining.starts_with(b"@") && !self.remaining.starts_with(b"Z") && !self.remaining.is_empty() { 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))); } // println!("reading a type from memorized_types[{}]. full list: {:#?}", n, self.memorized_types); params.push(self.memorized_types[n as usize].clone()); continue; } let len = self.remaining.len(); let param_type = self.read_var_type(StorageClass::empty())?; // Single-letter types are ignored for backreferences because // memorizing them doesn't save anything. if len - self.remaining.len() > 1 { self.memorize_type(¶m_type); } params.push(param_type); } if self.consume(b"Z") { params.push(Type::VarArgs); } else if self.remaining.is_empty() { // this is needed to handle the weird standalone template manglings } else { self.expect(b"@")?; } Ok(Params { types: params }) } // Reads a function parameters. fn read_func_params(&mut self) -> Result> { let params = if self.consume(b"X") { Params { types: vec![Type::Void(StorageClass::empty())], } } else { self.read_params()? }; self.expect(b"Z")?; Ok(params) } } pub fn demangle(input: &str, flags: DemangleFlags) -> Result { serialize(&parse(input)?, flags) } pub fn parse(input: &str) -> Result { let mut state = ParserState { remaining: input.as_bytes(), input, offset: 0, memorized_names: Vec::with_capacity(10), memorized_types: Vec::with_capacity(10), }; state.parse() } pub fn serialize(input: &ParseResult, flags: DemangleFlags) -> Result { let mut s = Vec::new(); { let mut serializer = Serializer { flags, w: &mut s }; serializer.serialize(input)?; } Ok(String::from_utf8(s)?) } // Converts an AST to a string. // // Converting an AST representing a C++ type to a string is tricky due // to the bad grammar of the C++ declaration inherited from C. You have // to construct a string from inside to outside. For example, if a type // X is a pointer to a function returning int, the order you create a // string becomes something like this: // // (1) X is a pointer: *X // (2) (1) is a function returning int: int (*X)() // // So you cannot construct a result just by appending strings to a result. // // To deal with this, we split the function into two. write_pre() writes // the "first half" of type declaration, and write_post() writes the // "second half". For example, write_pre() writes a return type for a // function and write_post() writes an parameter list. struct Serializer<'a> { flags: DemangleFlags, w: &'a mut Vec, } impl<'a> Serializer<'a> { fn serialize(&mut self, parse_result: &ParseResult) -> Result<()> { if !self .flags .intersects(DemangleFlags::NAME_ONLY | DemangleFlags::NO_FUNCTION_RETURNS) { self.write_pre(&parse_result.symbol_type)?; } self.write_name(&parse_result.symbol, Some(&parse_result.symbol_type))?; if !self.flags.contains(DemangleFlags::NAME_ONLY) { self.write_post(&parse_result.symbol_type)?; } Ok(()) } fn write_calling_conv(&mut self, calling_conv: &CallingConv) -> Result<()> { match self.w.last() { Some(b' ') | Some(b'(') => {} _ => write!(self.w, " ")?, } if !self.flags.contains(DemangleFlags::NO_MS_KEYWORDS) { match calling_conv { CallingConv::Cdecl => { write!(self.w, "__cdecl ")?; } CallingConv::Pascal => { write!(self.w, "__pascal ")?; } CallingConv::Thiscall => { write!(self.w, "__thiscall ")?; } CallingConv::Stdcall => { write!(self.w, "__stdcall ")?; } CallingConv::Fastcall => { write!(self.w, "__fastcall ")?; } CallingConv::_Regcall => { write!(self.w, "__regcall ")?; } }; } Ok(()) } // Write the "first half" of a given type. fn write_pre(&mut self, t: &Type) -> Result<()> { let storage_class = match t { Type::None => return Ok(()), Type::MemberFunction(func_class, calling_conv, _, _, ref inner) => { if func_class.contains(FuncClass::THUNK) { write!(self.w, "[thunk]: ")? } if !self.flags.contains(DemangleFlags::NO_ACCESS_SPECIFIERS) { if func_class.contains(FuncClass::PRIVATE) { write!(self.w, "private: ")? } if func_class.contains(FuncClass::PROTECTED) { write!(self.w, "protected: ")? } if func_class.contains(FuncClass::PUBLIC) { write!(self.w, "public: ")? } } if !self.flags.contains(DemangleFlags::NO_MEMBER_TYPE) { if func_class.contains(FuncClass::STATIC) { write!(self.w, "static ")? } if func_class.contains(FuncClass::VIRTUAL) { write!(self.w, "virtual ")?; } } self.write_pre(inner)?; self.write_calling_conv(calling_conv)?; return Ok(()); } Type::MemberFunctionPointer(ref symbol, _, calling_conv, _, _, ref inner) => { self.write_pre(inner)?; self.write_space()?; write!(self.w, "(")?; self.write_calling_conv(calling_conv)?; self.write_space()?; self.write_space()?; self.write_name(symbol, None)?; write!(self.w, "::*")?; return Ok(()); } Type::NonMemberFunction(calling_conv, _, _, ref inner) => { self.write_pre(inner)?; self.write_calling_conv(calling_conv)?; return Ok(()); } Type::VCallThunk(_, calling_conv) => { write!(self.w, "[thunk]: ")?; self.write_calling_conv(calling_conv)?; return Ok(()); } Type::CXXVBTable(_, sc) => sc, Type::CXXVFTable(_, sc) => sc, Type::TemplateParameterWithIndex(n) => { write!(self.w, "`template-parameter{}'", n)?; return Ok(()); } Type::ThreadSafeStaticGuard(num) => { write!(self.w, "TSS{}", num)?; return Ok(()); } Type::Constant(n) => { write!(self.w, "{}", n)?; return Ok(()); } Type::ConstantString(_) => { // We have no idea what the original encoding of the string is, // and undname doesn't even try to display anything. //match str::from_utf8(s).ok() { // Some(ref s) => write!(self.w, "{}", s)?, // None => {}, //} return Ok(()); } Type::VarArgs => { write!(self.w, "...")?; return Ok(()); } Type::Ptr(ref inner, storage_class) | Type::Ref(ref inner, storage_class) | Type::RValueRef(ref inner, storage_class) => { // "[]" and "()" (for function parameters) take precedence over "*", // so "int *x(int)" means "x is a function returning int *". We need // parentheses to supercede the default precedence. (e.g. we want to // emit something like "int (*x)(int)".) match *inner.as_ref() { Type::MemberFunction(_, calling_conv, _, _, ref inner) | Type::NonMemberFunction(calling_conv, _, _, ref inner) => { self.write_pre(inner)?; self.write_space()?; write!(self.w, "(")?; self.write_calling_conv(&calling_conv)?; } Type::Array(_, _, _) => { self.write_pre(inner)?; self.write_space()?; write!(self.w, "(")?; } _ => { self.write_pre(inner)?; } } match t { Type::Ptr(_, _) => { if !self.flags.contains(DemangleFlags::HUG_TYPE) { self.write_space()?; } else if self.flags.contains(DemangleFlags::SPACE_BEFORE_POINTER) { self.write_space_ptr()?; } write!(self.w, "*")? } Type::Ref(_, _) => { if !self.flags.contains(DemangleFlags::HUG_TYPE) { self.write_space()?; } else if self.flags.contains(DemangleFlags::SPACE_BEFORE_POINTER) { self.write_space_ptr()?; } write!(self.w, "&")? } Type::RValueRef(_, _) => { if !self.flags.contains(DemangleFlags::HUG_TYPE) { self.write_space()?; } else if self.flags.contains(DemangleFlags::SPACE_BEFORE_POINTER) { self.write_space_ptr()?; } write!(self.w, "&&")? } _ => {} } storage_class } Type::Array(_len, ref inner, storage_class) => { self.write_pre(inner)?; storage_class } Type::Var(ref inner, kind, sc) => { match kind { VarStorageKind::PrivateStatic => write!(self.w, "private: static ")?, VarStorageKind::ProtectedStatic => write!(self.w, "protected: static ")?, VarStorageKind::PublicStatic => write!(self.w, "public: static ")?, VarStorageKind::Global | VarStorageKind::FunctionLocalStatic => {} } self.write_pre(inner)?; sc } Type::Alias(ref names, sc) => { self.write_name(names, None)?; sc } Type::Struct(ref names, sc) => { self.write_class(names, "struct")?; sc } Type::Union(ref names, sc) => { self.write_class(names, "union")?; sc } Type::Class(ref names, sc) => { self.write_class(names, "class")?; sc } Type::Enum(ref names, sc) => { self.write_class(names, "enum")?; sc } Type::Void(sc) => { write!(self.w, "void")?; sc } Type::Bool(sc) => { write!(self.w, "bool")?; sc } Type::Char(sc) => { write!(self.w, "char")?; sc } Type::Schar(sc) => { write!(self.w, "signed char")?; sc } Type::Uchar(sc) => { write!(self.w, "unsigned char")?; sc } Type::Short(sc) => { write!(self.w, "short")?; sc } Type::Ushort(sc) => { write!(self.w, "unsigned short")?; sc } Type::Int(sc) => { write!(self.w, "int")?; sc } Type::Uint(sc) => { write!(self.w, "unsigned int")?; sc } Type::Long(sc) => { write!(self.w, "long")?; sc } Type::Ulong(sc) => { write!(self.w, "unsigned long")?; sc } Type::Int64(sc) => { if self.flags.contains(DemangleFlags::MS_TYPENAMES) { write!(self.w, "__int64")?; } else { write!(self.w, "int64_t")?; } sc } Type::Uint64(sc) => { if self.flags.contains(DemangleFlags::MS_TYPENAMES) { write!(self.w, "unsigned __int64")?; } else { write!(self.w, "uint64_t")?; } sc } Type::Int128(sc) => { if self.flags.contains(DemangleFlags::MS_TYPENAMES) { write!(self.w, "__int128")?; } else { write!(self.w, "int128_t")?; } sc } Type::Uint128(sc) => { if self.flags.contains(DemangleFlags::MS_TYPENAMES) { write!(self.w, "unsigned __int128")?; } else { write!(self.w, "uint128_t")?; } sc } Type::Wchar(sc) => { write!(self.w, "wchar_t")?; sc } Type::Float(sc) => { write!(self.w, "float")?; sc } Type::Double(sc) => { write!(self.w, "double")?; sc } Type::Ldouble(sc) => { write!(self.w, "long double")?; sc } Type::Char8(sc) => { write!(self.w, "char8_t")?; sc } Type::Char16(sc) => { write!(self.w, "char16_t")?; sc } Type::Char32(sc) => { write!(self.w, "char32_t")?; sc } Type::Nullptr => { write!(self.w, "std::nullptr_t")?; return Ok(()); } Type::EmptyParameterPack => return Ok(()), Type::RTTIType => return Ok(()), }; if storage_class.contains(StorageClass::CONST) { if self.flags.contains(DemangleFlags::SPACE_BEFORE_POINTER) { self.write_space_ptr()?; } else { self.write_space()?; } write!(self.w, "const")?; } if storage_class.contains(StorageClass::VOLATILE) { if self.flags.contains(DemangleFlags::SPACE_BEFORE_POINTER) { self.write_space_ptr()?; } else { self.write_space()?; } write!(self.w, "volatile")?; } Ok(()) } fn write_memfn_qualifiers(&mut self, sc: StorageClass) -> Result<()> { let with_ptr64 = self.flags.contains(DemangleFlags::WITH_PTR64); if self.flags.contains(DemangleFlags::NO_THISTYPE) { // TODO: should probably check for NO_CV_THISTYPE and NO_MS_THISTYPE // separately but I don't know what exactly those affect. return Ok(()); } let mut write_one_qual = |flag, s| -> Result<()> { if sc.contains(flag) { self.write_space()?; self.w.write_all(s)?; } Ok(()) }; write_one_qual(StorageClass::CONST, b"const")?; write_one_qual(StorageClass::VOLATILE, b"volatile")?; if with_ptr64 { write_one_qual(StorageClass::PTR64, b"__ptr64")?; } // __restrict is different than `restrict`, keep the underscores! write_one_qual(StorageClass::RESTRICT, b"__restrict")?; // TODO: undname prints ref-qualifiers tightly to previous qualifiers. write_one_qual(StorageClass::LVALUE_QUAL, b"&")?; write_one_qual(StorageClass::RVALUE_QUAL, b"&&")?; Ok(()) } // Write the "second half" of a given type. fn write_post(&mut self, t: &Type) -> Result<()> { match *t { Type::MemberFunction(_, _, ref params, sc, ref return_type) | Type::NonMemberFunction(_, ref params, sc, ref return_type) => { write!(self.w, "(")?; self.write_types(¶ms.types)?; write!(self.w, ")")?; self.write_memfn_qualifiers(sc)?; self.write_post(return_type)?; } Type::MemberFunctionPointer(_, _, _, ref params, sc, ref return_type) => { write!(self.w, ")(")?; self.write_types(¶ms.types)?; write!(self.w, ")")?; self.write_post(return_type)?; if sc.contains(StorageClass::CONST) { self.write_space()?; write!(self.w, "const")?; } } Type::CXXVBTable(ref names, _sc) => { self.write_scope(names)?; write!(self.w, "\'}}")?; // the rest of the "operator" } Type::Ptr(ref inner, _sc) | Type::Ref(ref inner, _sc) => { match *inner.as_ref() { Type::MemberFunction(_, _, _, _, _) | Type::NonMemberFunction(_, _, _, _) | Type::Array(_, _, _) => { write!(self.w, ")")?; } _ => {} } self.write_post(inner)?; } Type::Array(len, ref inner, _sc) => { write!(self.w, "[{}]", len)?; self.write_post(inner)?; } Type::Var(ref inner, _kind, _sc) => { self.write_post(inner)?; } Type::CXXVFTable(ref names, _) => { if !names.names.is_empty() { write!(self.w, "{{for `")?; self.write_scope(names)?; self.w.write_all(b"'}")?; } } Type::VCallThunk(offset, _) => { write!(self.w, "{{{},", offset)?; if self.flags.contains(DemangleFlags::SPACE_AFTER_COMMA) { write!(self.w, " ")?; } write!(self.w, "{{flat}}}}")?; } _ => {} } Ok(()) } // Write a function or template parameter list. fn write_types(&mut self, types: &[Type]) -> Result<()> { for (idx, param) in types .iter() .filter(|x| **x != Type::EmptyParameterPack) .enumerate() { if idx > 0 { write!(self.w, ",")?; if self.flags.contains(DemangleFlags::SPACE_AFTER_COMMA) { write!(self.w, " ")?; } } self.write_pre(param)?; self.write_post(param)?; } Ok(()) } fn write_class(&mut self, names: &Symbol, s: &str) -> Result<()> { if !self.flags.contains(DemangleFlags::NO_CLASS_TYPE) { write!(self.w, "{}", s)?; write!(self.w, " ")?; } self.write_name(names, None)?; Ok(()) } fn write_space_pre(&mut self) -> Result<()> { if let Some(&c) = self.w.last() { if char::from(c).is_ascii_alphabetic() || c == b'&' || c == b'>' || c == b')' { write!(self.w, " ")?; } } Ok(()) } fn write_space_ptr(&mut self) -> Result<()> { if let Some(&c) = self.w.last() { if char::from(c).is_ascii_alphabetic() || c == b'>' || c == b')' { write!(self.w, " ")?; } } Ok(()) } fn write_space(&mut self) -> Result<()> { if let Some(&c) = self.w.last() { if char::from(c).is_ascii_alphabetic() || c == b'*' || c == b'&' || c == b'>' || c == b')' { write!(self.w, " ")?; } } Ok(()) } fn write_operator_name(&mut self, op: &Operator) -> Result<()> { let s = match *op { Operator::Ctor => "ctor", Operator::Dtor => "dtor", Operator::New => "operator new", Operator::Delete => "operator delete", Operator::Equal => "operator=", Operator::RShift => "operator>>", Operator::LShift => "operator<<", Operator::Bang => "operator!", Operator::EqualEqual => "operator==", Operator::BangEqual => "operator!=", Operator::Subscript => "operator[]", // this is special cased for most situations unless demangling // produced something really wacky Operator::Conversion => "operatorcast", Operator::Arrow => "operator->", Operator::Star => "operator*", Operator::PlusPlus => "operator++", Operator::MinusMinus => "operator--", Operator::Minus => "operator-", Operator::Plus => "operator+", Operator::Amp => "operator&", Operator::ArrowStar => "operator->*", Operator::Slash => "operator/", Operator::Percent => "operator%", Operator::Less => "operator<", Operator::LessEqual => "operator<=", Operator::Greater => "operator>", Operator::GreaterEqual => "operator>=", Operator::Comma => "operator,", Operator::Call => "operator()", Operator::Tilde => "operator~", Operator::Caret => "operator^", Operator::Pipe => "operator|", Operator::AmpAmp => "operator&&", Operator::PipePipe => "operator||", Operator::StarEqual => "operator*=", Operator::PlusEqual => "operator+=", Operator::MinusEqual => "operator-=", Operator::SlashEqual => "operator/=", Operator::PercentEqual => "operator%=", Operator::GreaterGreaterEqual => "operator>>=", Operator::LessLessEqual => "operator<<=", Operator::AmpEqual => "operator&=", Operator::PipeEqual => "operator|=", Operator::CaretEqual => "operator^=", Operator::VFTable => "`vftable'", Operator::VBTable => "`vbtable'", Operator::VCall => "`vcall'", Operator::Typeof => "`typeof'", Operator::LocalStaticGuard(scope) => { write!(self.w, "`local static guard'")?; if let Some(scope) = scope { write!(self.w, "{{{}}}", scope)?; } return Ok(()); } Operator::String => "`string'", Operator::VBaseDtor => "`vbase destructor'", Operator::VectorDeletingDtor => "`vector deleting destructor'", Operator::DefaultCtorClosure => "`default constructor closure'", Operator::ScalarDeletingDtor => "`scalar deleting destructor'", Operator::VectorCtorIterator => "`vector constructor iterator'", Operator::VectorDtorIterator => "`vector destructor iterator'", Operator::VectorVBaseCtorIterator => "`vector vbase constructor iterator'", Operator::VirtualDisplacementMap => "`virtual displacement map'", Operator::EHVectorCtorIterator => "`eh vector constructor iterator'", Operator::EHVectorDtorIterator => "`eh vector destructor iterator'", Operator::EHVectorVBaseCtorIterator => "`eh vector vbase constructor iterator'", Operator::CopyCtorClosure => "`copy constructor closure'", Operator::LocalVFTable => "`local vftable'", Operator::LocalVFTableCtorClosure => "`local vftable constructor closure'", Operator::ArrayNew => "operator new[]", Operator::ArrayDelete => "operator delete[]", Operator::PlacementDeleteClosure => "`placement delete closure'", Operator::PlacementArrayDeleteClosure => "`placement delete[] closure'", Operator::CoroutineAwait => " co_await", Operator::LiteralOperatorName => "operator \"\"", Operator::RTTITypeDescriptor(_, ref inner) => { self.write_pre(inner)?; // XXX(mitsuhiko): llvm uses a space here instead of `::`. No // idea why, seems inconsistent write!(self.w, "::`RTTI Type Descriptor'")?; return Ok(()); } Operator::RTTIBaseClassDescriptor(nv_offset, vbptr_offset, vbtable_offset, flags) => { let sp = if self.flags.contains(DemangleFlags::SPACE_AFTER_COMMA) { " " } else { "" }; write!( self.w, "`RTTI Base Class Descriptor at ({},{}{},{}{},{}{})'", nv_offset, sp, vbptr_offset, sp, vbtable_offset, sp, flags )?; return Ok(()); } Operator::RTTIBaseClassArray => "`RTTI Base Class Array'", Operator::RTTIClassHierarchyDescriptor => "`RTTI Class Hierarchy Descriptor'", Operator::RTTIClassCompleteObjectLocator => "`RTTI Complete Object Locator'", Operator::DynamicInitializer => "`dynamic initializer'", Operator::DynamicAtexitDtor => "`dynamic atexit destructor'", Operator::LocalStaticThreadGuard(scope) => { write!(self.w, "`local static thread guard'")?; if let Some(scope) = scope { write!(self.w, "{{{}}}", scope)?; } return Ok(()); } }; write!(self.w, "{}", s)?; Ok(()) } fn write_one_name(&mut self, name: &Name) -> Result<()> { match *name { Name::Md5(name) => { write!(self.w, "??@")?; self.w.write_all(name)?; write!(self.w, "@")?; } Name::Operator(ref op) => { self.write_space()?; self.write_operator_name(op)?; } Name::NonTemplate(name) => { self.w.write_all(name)?; } Name::AsInterface(name) => { write!(self.w, "[")?; self.w.write_all(name)?; write!(self.w, "]")?; } Name::Template(ref name, ref params) => { self.write_one_name(name)?; self.write_tmpl_params(params)?; } Name::Discriminator(ref val) => { write!(self.w, "`{}'", val)?; } Name::ParsedName(ref val) => { write!(self.w, "`{}'", serialize(val, self.flags)?)?; } Name::AnonymousNamespace(_) => { write!(self.w, "`anonymous namespace'")?; } } Ok(()) } fn write_scope(&mut self, names: &NameSequence) -> Result<()> { // Print out namespaces or outer class names. let mut i = names.names.iter().rev(); if let Some(name) = i.next() { self.write_one_name(name)?; } for name in i { write!(self.w, "::")?; self.write_one_name(name)?; } Ok(()) } // Write a name read by read_name(). fn write_name(&mut self, names: &Symbol, ty: Option<&Type<'_>>) -> Result<()> { if !self.flags.contains(DemangleFlags::SPACE_BEFORE_POINTER) { self.write_space_pre()?; } else { self.write_space_ptr()?; } let mut was_literal_op = false; if let Name::Operator(Operator::LiteralOperatorName) = names.name { self.write_space()?; self.write_operator_name(&Operator::LiteralOperatorName)?; was_literal_op = true; } self.write_scope(&names.scope)?; if !names.scope.names.is_empty() && !was_literal_op { write!(self.w, "::")?; } match names.name { Name::Md5(name) => { write!(self.w, "??@")?; self.w.write_all(name)?; write!(self.w, "@")?; } Name::Operator(ref op) => { match *op { Operator::Ctor => { let prev = names.scope.names.first().ok_or_else(|| { Error::new( "If there's a ctor, there should be another name in this sequence", ) })?; self.write_one_name(prev)?; } Operator::Dtor => { let prev = names.scope.names.first().ok_or_else(|| { Error::new( "If there's a dtor, there should be another name in this sequence", ) })?; write!(self.w, "~")?; self.write_one_name(prev)?; } Operator::VBTable => { write!(self.w, "`vbtable'{{for `")?; // The rest will be written by write_post of the // symbol type. } Operator::Conversion => { if let Some(Type::MemberFunction(_, _, _, _, ref rv)) = ty { write!(self.w, "operator ")?; self.write_pre(rv)?; self.write_post(rv)?; } else { self.write_space()?; self.write_operator_name(op)?; } } Operator::LiteralOperatorName => {} _ => { self.write_space()?; // Print out an overloaded operator. self.write_operator_name(op)?; } } } Name::NonTemplate(name) => { self.w.write_all(name)?; } Name::AsInterface(name) => { write!(self.w, "[")?; self.w.write_all(name)?; write!(self.w, "]")?; } Name::Template(ref name, ref params) => { self.write_one_name(name)?; self.write_tmpl_params(params)?; } Name::Discriminator(ref val) => { write!(self.w, "`{}'", val)?; } Name::ParsedName(ref val) => { write!(self.w, "{}", serialize(val, self.flags)?)?; } Name::AnonymousNamespace(_) => { // this should never happen as they are handled elsewhere debug_assert!(false, "not supposed to be here"); } } Ok(()) } fn write_tmpl_params(&mut self, params: &Params<'_>) -> Result<()> { write!(self.w, "<")?; if !params.types.is_empty() { self.write_types(¶ms.types)?; if let Some(&b'>') = self.w.last() { write!(self.w, " ")?; } } write!(self.w, ">")?; Ok(()) } } // grammar from MicrosoftMangle.cpp: // ::= ? // ::= {[]+ | []}? @ // ::= // ::= // ::= // ::= // ::= ??? // ::= ?B # cast, the target type is encoded as the return type. // ::= @ // // mangleNestedName: calls into mangle, which is responsible for , and into mangleUnqualifiedName // ::= [] // ::= [] // // ::= // ::= // ::= ?$ // ::= // ::= // ::= E? # E designates a 64-bit 'this' // # pointer. in 64-bit mode *all* // # 'this' pointers are 64-bit. // ::= // ::= // // ::= A # private: near // ::= B # private: far // ::= C # private: static near // ::= D # private: static far // ::= E # private: near // ::= F # private: far // ::= I # near // ::= J # far // ::= K # static near // ::= L # static far // ::= M # near // ::= N # far // ::= Q # near // ::= R # far // ::= S # static near // ::= T # static far // ::= U # near // ::= V # far // ::= Y # global near // ::= Z # global far // ::= 0 # private static member // ::= 1 # protected static member // ::= 2 # public static member // ::= 3 # global // ::= 4 # static local msvc-demangler-0.10.1/tests/llvm-cases/ms-back-references.test000064400000000000000000000207701046102023000223620ustar 00000000000000; RUN: llvm-undname < %s | FileCheck %s ; CHECK-NOT: Invalid mangled name ?f1@@YAXPBD0@Z ; CHECK: void __cdecl f1(char const *, char const *) ?f2@@YAXPBDPAD@Z ; CHECK: void __cdecl f2(char const *, char *) ?f3@@YAXHPBD0@Z ; CHECK: void __cdecl f3(int, char const *, char const *) ?f4@@YAPBDPBD0@Z ; CHECK: char const * __cdecl f4(char const *, char const *) ?f5@@YAXPBDIDPBX0I@Z ; CHECK: void __cdecl f5(char const *, unsigned int, char, void const *, char const *, unsigned int) ?f6@@YAX_N0@Z ; CHECK: void __cdecl f6(bool, bool) ?f7@@YAXHPAHH0_N1PA_N@Z ; CHECK: void __cdecl f7(int, int *, int, int *, bool, bool, bool *) ?g1@@YAXUS@@@Z ; CHECK: void __cdecl g1(struct S) ?g2@@YAXUS@@0@Z ; CHECK: void __cdecl g2(struct S, struct S) ?g3@@YAXUS@@0PAU1@1@Z ; CHECK: void __cdecl g3(struct S, struct S, struct S *, struct S *) ?g4@@YAXPBDPAUS@@01@Z ; CHECK: void __cdecl g4(char const *, struct S *, char const *, struct S *) ?mbb@S@@QAEX_N0@Z ; CHECK: void __thiscall S::mbb(bool, bool) ?h1@@YAXPBD0P6AXXZ1@Z ; CHECK: void __cdecl h1(char const *, char const *, void (__cdecl *)(void), void (__cdecl *)(void)) ?h2@@YAXP6AXPAX@Z0@Z ; CHECK: void __cdecl h2(void (__cdecl *)(void *), void *) ?h3@@YAP6APAHPAH0@ZP6APAH00@Z10@Z ; CHECK: int * (__cdecl * __cdecl h3(int * (__cdecl *)(int *, int *), int * (__cdecl *)(int *, int *), int *))(int *, int *) ?foo@0@YAXXZ ; CHECK: void __cdecl foo::foo(void) ??$?HH@S@@QEAAAEAU0@H@Z ; CHECK: struct S & __cdecl S::operator+(int) ?foo_abbb@@YAXV?$A@V?$B@D@@V1@V1@@@@Z ; CHECK: void __cdecl foo_abbb(class A, class B, class B>) ?foo_abb@@YAXV?$A@DV?$B@D@@V1@@@@Z ; CHECK: void __cdecl foo_abb(class A, class B>) ?foo_abc@@YAXV?$A@DV?$B@D@@V?$C@D@@@@@Z ; 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) ?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>) ?foo_abb@@YAXV?$A@DV?$B@D@N@@V12@@N@@@Z ; CHECK: void __cdecl foo_abb(class N::A, class N::B>) ?foo_abc@@YAXV?$A@DV?$B@D@N@@V?$C@D@2@@N@@@Z ; CHECK: void __cdecl foo_abc(class N::A, class N::C>) ?abc_foo@@YA?AV?$A@DV?$B@D@N@@V?$C@D@2@@N@@XZ ; CHECK: class N::A, class N::C> __cdecl abc_foo(void) ?z_foo@@YA?AVZ@N@@V12@@Z ; CHECK: class N::Z __cdecl z_foo(class N::Z) ?b_foo@@YA?AV?$B@D@N@@V12@@Z ; CHECK: class N::B __cdecl b_foo(class N::B) ?d_foo@@YA?AV?$D@DD@N@@V12@@Z ; CHECK: class N::D __cdecl d_foo(class N::D) ?abc_foo_abc@@YA?AV?$A@DV?$B@D@N@@V?$C@D@2@@N@@V12@@Z ; CHECK: class N::A, class N::C> __cdecl abc_foo_abc(class N::A, class N::C>) ?foo5@@YAXV?$Y@V?$Y@V?$Y@V?$Y@VX@NA@@@NB@@@NA@@@NB@@@NA@@@Z ; CHECK: void __cdecl foo5(class NA::Y>>>) ?foo11@@YAXV?$Y@VX@NA@@@NA@@V1NB@@@Z ; CHECK: void __cdecl foo11(class NA::Y, class NB::Y) ?foo112@@YAXV?$Y@VX@NA@@@NA@@V?$Y@VX@NB@@@NB@@@Z ; CHECK: void __cdecl foo112(class NA::Y, class NB::Y) ?foo22@@YAXV?$Y@V?$Y@VX@NA@@@NB@@@NA@@V?$Y@V?$Y@VX@NA@@@NA@@@NB@@@Z ; CHECK: void __cdecl foo22(class NA::Y>, class NB::Y>) ?foo@L@PR13207@@QAEXV?$I@VA@PR13207@@@2@@Z ; CHECK: void __thiscall PR13207::L::foo(class PR13207::I) ?foo@PR13207@@YAXV?$I@VA@PR13207@@@1@@Z ; CHECK: void __cdecl PR13207::foo(class PR13207::I) ?foo2@PR13207@@YAXV?$I@VA@PR13207@@@1@0@Z ; CHECK: void __cdecl PR13207::foo2(class PR13207::I, class PR13207::I) ?bar@PR13207@@YAXV?$J@VA@PR13207@@VB@2@@1@@Z ; CHECK: void __cdecl PR13207::bar(class PR13207::J) ?spam@PR13207@@YAXV?$K@VA@PR13207@@VB@2@VC@2@@1@@Z ; CHECK: void __cdecl PR13207::spam(class PR13207::K) ?baz@PR13207@@YAXV?$K@DV?$F@D@PR13207@@V?$I@D@2@@1@@Z ; CHECK: void __cdecl PR13207::baz(class PR13207::K, class PR13207::I>) ?qux@PR13207@@YAXV?$K@DV?$I@D@PR13207@@V12@@1@@Z ; CHECK: void __cdecl PR13207::qux(class PR13207::K, class PR13207::I>) ?foo@NA@PR13207@@YAXV?$Y@VX@NA@PR13207@@@12@@Z ; CHECK: void __cdecl PR13207::NA::foo(class PR13207::NA::Y) ?foofoo@NA@PR13207@@YAXV?$Y@V?$Y@VX@NA@PR13207@@@NA@PR13207@@@12@@Z ; CHECK: void __cdecl PR13207::NA::foofoo(class PR13207::NA::Y>) ?foo@NB@PR13207@@YAXV?$Y@VX@NA@PR13207@@@12@@Z ; CHECK: void __cdecl PR13207::NB::foo(class PR13207::NB::Y) ?bar@NB@PR13207@@YAXV?$Y@VX@NB@PR13207@@@NA@2@@Z ; CHECK: void __cdecl PR13207::NB::bar(class PR13207::NA::Y) ?spam@NB@PR13207@@YAXV?$Y@VX@NA@PR13207@@@NA@2@@Z ; CHECK: void __cdecl PR13207::NB::spam(class PR13207::NA::Y) ?foobar@NB@PR13207@@YAXV?$Y@V?$Y@VX@NB@PR13207@@@NB@PR13207@@@NA@2@V312@@Z ; CHECK: void __cdecl PR13207::NB::foobar(class PR13207::NA::Y>, class PR13207::NB::Y>) ?foobarspam@NB@PR13207@@YAXV?$Y@VX@NB@PR13207@@@12@V?$Y@V?$Y@VX@NB@PR13207@@@NB@PR13207@@@NA@2@V412@@Z ; CHECK: void __cdecl PR13207::NB::foobarspam(class PR13207::NB::Y, class PR13207::NA::Y>, class PR13207::NB::Y>) ?foobarbaz@NB@PR13207@@YAXV?$Y@VX@NB@PR13207@@@12@V?$Y@V?$Y@VX@NB@PR13207@@@NB@PR13207@@@NA@2@V412@2@Z ; CHECK: void __cdecl PR13207::NB::foobarbaz(class PR13207::NB::Y, class PR13207::NA::Y>, class PR13207::NB::Y>, class PR13207::NB::Y>) ?foobarbazqux@NB@PR13207@@YAXV?$Y@VX@NB@PR13207@@@12@V?$Y@V?$Y@VX@NB@PR13207@@@NB@PR13207@@@NA@2@V412@2V?$Y@V?$Y@V?$Y@VX@NB@PR13207@@@NB@PR13207@@@NB@PR13207@@@52@@Z ; CHECK: void __cdecl PR13207::NB::foobarbazqux(class PR13207::NB::Y, class PR13207::NA::Y>, class PR13207::NB::Y>, class PR13207::NB::Y>, class PR13207::NA::Y>>) ?foo@NC@PR13207@@YAXV?$Y@VX@NB@PR13207@@@12@@Z ; CHECK: void __cdecl PR13207::NC::foo(class PR13207::NC::Y) ?foobar@NC@PR13207@@YAXV?$Y@V?$Y@V?$Y@VX@NA@PR13207@@@NA@PR13207@@@NB@PR13207@@@12@@Z ; CHECK: void __cdecl PR13207::NC::foobar(class PR13207::NC::Y>>) ?fun_normal@fn_space@@YA?AURetVal@1@H@Z ; CHECK: struct fn_space::RetVal __cdecl fn_space::fun_normal(int) ??$fun_tmpl@H@fn_space@@YA?AURetVal@0@ABH@Z ; CHECK: struct fn_space::RetVal __cdecl fn_space::fun_tmpl(int const &) ; 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) ; 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 *) ; 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) msvc-demangler-0.10.1/tests/llvm-cases/ms-basic.test000064400000000000000000000116701046102023000204230ustar 00000000000000; RUN: llvm-undname < %s | FileCheck %s ; CHECK-NOT: Invalid mangled name ?x@@3HA ; CHECK: int x ?x@@3PEAHEA ; CHECK: int *x ?x@@3PEAPEAHEA ; CHECK: int **x ?foo@@3Y123KA ; CHECK: unsigned long foo[3][4] ?x@@3PEAY02HEA ; CHECK: int (*x)[3] ?x@@3PEAY124HEA ; CHECK: int (*x)[3][5] ?x@@3PEAY02$$CBHEA ; CHECK: int const (*x)[3] ?x@@3PEAEEA ; CHECK: unsigned char *x ?y@@3PEAGEA ; CHECK: unsigned short *y ?z@@3PEAKEA ; CHECK: unsigned long *z ?x@@3PEAY1NKM@5HEA ; CHECK: int (*x)[3500][6] ?x@@YAXMH@Z ; CHECK: void __cdecl x(float, int) ?x@@YAXMHZZ ; CHECK: void __cdecl x(float, int, ...) ?x@@YAXZZ ; CHECK: void __cdecl x(...) ?x@@3P6AHMNH@ZEA ; CHECK: int (__cdecl *x)(float, double, int) ?x@@3P6AHP6AHM@ZN@ZEA ; CHECK: int (__cdecl *x)(int (__cdecl *)(float), double) ?x@@3P6AHP6AHM@Z0@ZEA ; CHECK: int (__cdecl *x)(int (__cdecl *)(float), int (__cdecl *)(float)) ?x@ns@@3HA ; CHECK: int ns::x ; Microsoft's undname doesn't handle Q correctly or the multiple occurrences ; of the const modifier. So the results here differ, but ours are correct. ?x@@3PEAHEA ; CHECK: int *x ?x@@3PEBHEB ; CHECK: int const *x ?x@@3QEAHEA ; CHECK: int *const x ?x@@3QEBHEB ; CHECK: int const *const x ?x@@3AEBHEB ; CHECK: int const &x ?x@@3PEAUty@@EA ; CHECK: struct ty *x ?x@@3PEATty@@EA ; CHECK: union ty *x ?x@@3PEAVty@@EA ; CHECK: class ty *x ?x@@3PEAW4ty@@EA ; CHECK: enum ty *x ?x@@3PEAV?$tmpl@H@@EA ; CHECK: class tmpl *x ?x@@3PEAU?$tmpl@H@@EA ; CHECK: struct tmpl *x ?x@@3PEAT?$tmpl@H@@EA ; CHECK: union tmpl *x ?instance@@3Vklass@@A ; CHECK: class klass instance ?instance$initializer$@@3P6AXXZEA ; CHECK: void (__cdecl *instance$initializer$)(void) ??0klass@@QEAA@XZ ; CHECK: __cdecl klass::klass(void) ??1klass@@QEAA@XZ ; CHECK: __cdecl klass::~klass(void) ?x@@YAHPEAVklass@@AEAV1@@Z ; CHECK: int __cdecl x(class klass *, class klass &) ?x@ns@@3PEAV?$klass@HH@1@EA ; CHECK: class ns::klass *ns::x ?fn@?$klass@H@ns@@QEBAIXZ ; CHECK: unsigned int __cdecl ns::klass::fn(void) const ??4klass@@QEAAAEBV0@AEBV0@@Z ; CHECK: class klass const & __cdecl klass::operator=(class klass const &) ??7klass@@QEAA_NXZ ; CHECK: bool __cdecl klass::operator!(void) ??8klass@@QEAA_NAEBV0@@Z ; CHECK: bool __cdecl klass::operator==(class klass const &) ??9klass@@QEAA_NAEBV0@@Z ; CHECK: bool __cdecl klass::operator!=(class klass const &) ??Aklass@@QEAAH_K@Z ; CHECK: int __cdecl klass::operator[](unsigned __int64) ??Cklass@@QEAAHXZ ; CHECK: int __cdecl klass::operator->(void) ??Dklass@@QEAAHXZ ; CHECK: int __cdecl klass::operator*(void) ??Eklass@@QEAAHXZ ; CHECK: int __cdecl klass::operator++(void) ??Eklass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator++(int) ??Fklass@@QEAAHXZ ; CHECK: int __cdecl klass::operator--(void) ??Fklass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator--(int) ??Hklass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator+(int) ??Gklass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator-(int) ??Iklass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator&(int) ??Jklass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator->*(int) ??Kklass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator/(int) ??Mklass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator<(int) ??Nklass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator<=(int) ??Oklass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator>(int) ??Pklass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator>=(int) ??Qklass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator,(int) ??Rklass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator()(int) ??Sklass@@QEAAHXZ ; CHECK: int __cdecl klass::operator~(void) ??Tklass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator^(int) ??Uklass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator|(int) ??Vklass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator&&(int) ??Wklass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator||(int) ??Xklass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator*=(int) ??Yklass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator+=(int) ??Zklass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator-=(int) ??_0klass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator/=(int) ??_1klass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator%=(int) ??_2klass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator>>=(int) ??_3klass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator<<=(int) ??_6klass@@QEAAHH@Z ; CHECK: int __cdecl klass::operator^=(int) ??6@YAAEBVklass@@AEBV0@H@Z ; CHECK: class klass const & __cdecl operator<<(class klass const &, int) ??5@YAAEBVklass@@AEBV0@_K@Z ; CHECK: class klass const & __cdecl operator>>(class klass const &, unsigned __int64) ??2@YAPEAX_KAEAVklass@@@Z ; CHECK: void * __cdecl operator new(unsigned __int64, class klass &) ??_U@YAPEAX_KAEAVklass@@@Z ; CHECK: void * __cdecl operator new[](unsigned __int64, class klass &) ??3@YAXPEAXAEAVklass@@@Z ; CHECK: void __cdecl operator delete(void *, class klass &) ??_V@YAXPEAXAEAVklass@@@Z ; CHECK: void __cdecl operator delete[](void *, class klass &) ?A@?A0x43583946@@3VB@@B ; CHECK: class B const `anonymous namespace'::A msvc-demangler-0.10.1/tests/llvm-cases/ms-cxx11.test000064400000000000000000000146571046102023000203160ustar 00000000000000; These tests are based on clang/test/CodeGenCXX/mangle-ms-cxx11.cpp ; RUN: llvm-undname < %s | FileCheck %s ; CHECK-NOT: Invalid mangled name ?a@FTypeWithQuals@@3U?$S@$$A8@@BAHXZ@1@A ; CHECK: struct FTypeWithQuals::S FTypeWithQuals::a ?b@FTypeWithQuals@@3U?$S@$$A8@@CAHXZ@1@A ; CHECK: struct FTypeWithQuals::S FTypeWithQuals::b ?c@FTypeWithQuals@@3U?$S@$$A8@@IAAHXZ@1@A ; CHECK: struct FTypeWithQuals::S FTypeWithQuals::c ?d@FTypeWithQuals@@3U?$S@$$A8@@GBAHXZ@1@A ; CHECK: struct FTypeWithQuals::S FTypeWithQuals::d ?e@FTypeWithQuals@@3U?$S@$$A8@@GCAHXZ@1@A ; CHECK: struct FTypeWithQuals::S FTypeWithQuals::e ?f@FTypeWithQuals@@3U?$S@$$A8@@IGAAHXZ@1@A ; CHECK: struct FTypeWithQuals::S FTypeWithQuals::f ?g@FTypeWithQuals@@3U?$S@$$A8@@HBAHXZ@1@A ; CHECK: struct FTypeWithQuals::S FTypeWithQuals::g ?h@FTypeWithQuals@@3U?$S@$$A8@@HCAHXZ@1@A ; CHECK: struct FTypeWithQuals::S FTypeWithQuals::h ?i@FTypeWithQuals@@3U?$S@$$A8@@IHAAHXZ@1@A ; CHECK: struct FTypeWithQuals::S FTypeWithQuals::i ?j@FTypeWithQuals@@3U?$S@$$A6AHXZ@1@A ; CHECK: struct FTypeWithQuals::S FTypeWithQuals::j ?k@FTypeWithQuals@@3U?$S@$$A8@@GAAHXZ@1@A ; CHECK: struct FTypeWithQuals::S FTypeWithQuals::k ?l@FTypeWithQuals@@3U?$S@$$A8@@HAAHXZ@1@A ; CHECK: struct FTypeWithQuals::S FTypeWithQuals::l ?Char16Var@@3_SA ; CHECK: char16_t Char16Var ?Char32Var@@3_UA ; CHECK: char32_t Char32Var ?LRef@@YAXAAH@Z ; CHECK: void __cdecl LRef(int &) ?RRef@@YAH$$QAH@Z ; CHECK: int __cdecl RRef(int &&) ?Null@@YAX$$T@Z ; CHECK: void __cdecl Null(std::nullptr_t) ?fun@PR18022@@YA?AU@1@U21@0@Z ; CHECK: struct PR18022:: __cdecl PR18022::fun(struct PR18022::, struct PR18022::) ; First, we have the static local variable of type "" inside of "define_lambda". ; decltype(lambda), where lambda = [] { static int local=42; return 42; }; ?lambda@?1??define_lambda@@YAHXZ@4V@?0??1@YAHXZ@A ; CHECK: class `int __cdecl define_lambda(void)'::`1':: `int __cdecl define_lambda(void)'::`2'::lambda ; Next, we have the "operator()" for "" which is inside of "define_lambda". ??R@?0??define_lambda@@YAHXZ@QBE@XZ ; CHECK: __thiscall `int __cdecl define_lambda(void)'::`1'::::operator()(void) const ; Finally, we have the local which is inside of "" which is inside of "define_lambda". ?local@?2???R@?0??define_lambda@@YAHXZ@QBE@XZ@4HA ; CHECK: __thiscall `int __cdecl define_lambda(void)'::`1'::::operator()(void) const ??$use_lambda_arg@V@?0??call_with_lambda_arg1@@YAXXZ@@@YAXV@?0??call_with_lambda_arg1@@YAXXZ@@Z ; CHECK: void __cdecl use_lambda_arg>(class `void __cdecl call_with_lambda_arg1(void)'::`1'::) ?foo@A@PR19361@@QIGAEXXZ ; CHECK: void __thiscall PR19361::A::foo(void) __restrict & ?foo@A@PR19361@@QIHAEXXZ ; CHECK: void __thiscall PR19361::A::foo(void) __restrict && ??__K_deg@@YAHO@Z ; CHECK: int __cdecl operator ""_deg(long double) ??$templ_fun_with_pack@$S@@YAXXZ ; CHECK: void __cdecl templ_fun_with_pack<>(void) ; $$Z is a parameter pack separator. ??$func@H$$ZH@@YAHAEBU?$Foo@H@@0@Z ; CHECK: int __cdecl func(struct Foo const &, struct Foo const &) ??$templ_fun_with_ty_pack@$$$V@@YAXXZ ; CHECK: void __cdecl templ_fun_with_ty_pack<>(void) ??$templ_fun_with_ty_pack@$$V@@YAXXZ ; CHECK: void __cdecl templ_fun_with_ty_pack<>(void) ??$f@$$YAliasA@PR20047@@@PR20047@@YAXXZ ; CHECK: void __cdecl PR20047::f(void) ?f@UnnamedType@@YAXAAU@A@1@@Z ; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::A:: &) ?f@UnnamedType@@YAXPAW4@?$B@H@1@@Z ; CHECK: void __cdecl UnnamedType::f(enum UnnamedType::B:: *) ??$f@W4@?1??g@PR24651@@YAXXZ@@PR24651@@YAXW4@?1??g@0@YAXXZ@@Z ; CHECK: void __cdecl PR24651::f>(enum `void __cdecl PR24651::g(void)'::`2'::) ??$f@T@PR18204@@@PR18204@@YAHPAT@0@@Z ; CHECK: int __cdecl PR18204::f>(union PR18204:: *) ??R@?0??PR26105@@YAHXZ@QBE@H@Z ; CHECK: public: __thiscall `int __cdecl PR26105(void)'::`1'::::operator()(int) const ??R@?0???R@?0??PR26105@@YAHXZ@QBE@H@Z@QBE@H@Z ; CHECK: public: __thiscall `public: __thiscall `int __cdecl PR26105(void)'::`1'::::operator()(int) const'::`1'::::operator()(int) const ;TODO(mitsuhiko): this test is broken for unknown reasons ;?unaligned_foo1@@YAPFAHXZ ;; CHECK: int __unaligned * __cdecl unaligned_foo1(void) ;TODO(mitsuhiko): this test is broken for unknown reasons ;?unaligned_foo2@@YAPFAPFAHXZ ;; CHECK: int __unaligned *__unaligned * __cdecl unaligned_foo2(void) ;TODO(mitsuhiko): this test is broken for unknown reasons ;?unaligned_foo3@@YAHXZ ;; CHECK: int __cdecl unaligned_foo3(void) ;TODO(mitsuhiko): this test is broken for unknown reasons ;?unaligned_foo4@@YAXPFAH@Z ;; CHECK: void __cdecl unaligned_foo4(int __unaligned *) ;TODO(mitsuhiko): this test is broken for unknown reasons ;?unaligned_foo5@@YAXPIFAH@Z ;; CHECK: void __cdecl unaligned_foo5(int __unaligned *__restrict) ;TODO(mitsuhiko): this test is broken for unknown reasons ;??$unaligned_foo6@PAH@@YAPAHPAH@Z ;; CHECK: int * __cdecl unaligned_foo6(int *) ;TODO(mitsuhiko): this test is broken for unknown reasons ;??$unaligned_foo6@PFAH@@YAPFAHPFAH@Z ;; CHECK: int __unaligned * __cdecl unaligned_foo6(int __unaligned *) ;TODO(mitsuhiko): this test is broken for unknown reasons ;?unaligned_foo8@unaligned_foo8_S@@QFCEXXZ ;; CHECK: void __thiscall unaligned_foo8_S::unaligned_foo8(void) volatile __unaligned ??R@x@A@PR31197@@QBE@XZ ; CHECK: __thiscall PR31197::A::x::::operator()(void) const ?white@?1???R@x@A@PR31197@@QBE@XZ@4HA ; CHECK: int `public: __thiscall PR31197::A::x::::operator()(void) const'::`2'::white ?f@@YAXW4@@@Z ; CHECK: void __cdecl f(enum ) msvc-demangler-0.10.1/tests/llvm-cases/ms-operators.test000064400000000000000000000152361046102023000213620ustar 00000000000000; RUN: llvm-undname < %s | FileCheck %s ; CHECK-NOT: Invalid mangled name ??0Base@@QEAA@XZ ; CHECK: __cdecl Base::Base(void) ??1Base@@UEAA@XZ ; CHECK: virtual __cdecl Base::~Base(void) ??2@YAPEAX_K@Z ; CHECK: void * __cdecl operator new(unsigned __int64) ??3@YAXPEAX_K@Z ; CHECK: void __cdecl operator delete(void *, unsigned __int64) ??4Base@@QEAAHH@Z ; CHECK: int __cdecl Base::operator=(int) ??6Base@@QEAAHH@Z ; CHECK: int __cdecl Base::operator<<(int) ??5Base@@QEAAHH@Z ; CHECK: int __cdecl Base::operator>>(int) ??7Base@@QEAAHXZ ; CHECK: int __cdecl Base::operator!(void) ??8Base@@QEAAHH@Z ; CHECK: int __cdecl Base::operator==(int) ??9Base@@QEAAHH@Z ; CHECK: int __cdecl Base::operator!=(int) ??ABase@@QEAAHH@Z ; CHECK: int __cdecl Base::operator[](int) ??BBase@@QEAAHXZ ; CHECK: __cdecl Base::operator int(void) ??CBase@@QEAAHXZ ; CHECK: int __cdecl Base::operator->(void) ??DBase@@QEAAHXZ ; CHECK: int __cdecl Base::operator*(void) ??EBase@@QEAAHXZ ; CHECK: int __cdecl Base::operator++(void) ??EBase@@QEAAHH@Z ; CHECK: int __cdecl Base::operator++(int) ??FBase@@QEAAHXZ ; CHECK: int __cdecl Base::operator--(void) ??FBase@@QEAAHH@Z ; CHECK: int __cdecl Base::operator--(int) ??GBase@@QEAAHH@Z ; CHECK: int __cdecl Base::operator-(int) ??HBase@@QEAAHH@Z ; CHECK: int __cdecl Base::operator+(int) ??IBase@@QEAAHH@Z ; CHECK: int __cdecl Base::operator&(int) ??JBase@@QEAAHH@Z ; CHECK: int __cdecl Base::operator->*(int) ??KBase@@QEAAHH@Z ; CHECK: int __cdecl Base::operator/(int) ??LBase@@QEAAHH@Z ; CHECK: int __cdecl Base::operator%(int) ??MBase@@QEAAHH@Z ; CHECK: int __cdecl Base::operator<(int) ??NBase@@QEAAHH@Z ; CHECK: int __cdecl Base::operator<=(int) ??OBase@@QEAAHH@Z ; CHECK: int __cdecl Base::operator>(int) ??PBase@@QEAAHH@Z ; CHECK: int __cdecl Base::operator>=(int) ??QBase@@QEAAHH@Z ; CHECK: int __cdecl Base::operator,(int) ??RBase@@QEAAHXZ ; CHECK: int __cdecl Base::operator()(void) ??SBase@@QEAAHXZ ; CHECK: int __cdecl Base::operator~(void) ??TBase@@QEAAHH@Z ; CHECK: int __cdecl Base::operator^(int) ??UBase@@QEAAHH@Z ; CHECK: int __cdecl Base::operator|(int) ??VBase@@QEAAHH@Z ; CHECK: int __cdecl Base::operator&&(int) ??WBase@@QEAAHH@Z ; CHECK: int __cdecl Base::operator||(int) ??XBase@@QEAAHH@Z ; CHECK: int __cdecl Base::operator*=(int) ??YBase@@QEAAHH@Z ; CHECK: int __cdecl Base::operator+=(int) ??ZBase@@QEAAHH@Z ; CHECK: int __cdecl Base::operator-=(int) ??_0Base@@QEAAHH@Z ; CHECK: int __cdecl Base::operator/=(int) ??_1Base@@QEAAHH@Z ; CHECK: int __cdecl Base::operator%=(int) ??_2Base@@QEAAHH@Z ; CHECK: int __cdecl Base::operator>>=(int) ??_3Base@@QEAAHH@Z ; CHECK: int __cdecl Base::operator<<=(int) ??_4Base@@QEAAHH@Z ; CHECK: int __cdecl Base::operator&=(int) ??_5Base@@QEAAHH@Z ; CHECK: int __cdecl Base::operator|=(int) ??_6Base@@QEAAHH@Z ; CHECK: int __cdecl Base::operator^=(int) ??_7Base@@6B@ ; CHECK: const Base::`vftable' ??_7A@B@@6BC@D@@@ ; CHECK: const B::A::`vftable'{for `D::C'} ??_8Middle2@@7B@ ; CHECK: const Middle2::`vbtable' ??_9Base@@$B7AA ; CHECK: [thunk]: __cdecl Base::`vcall'{8, {flat}} ??_B?1??getS@@YAAAUS@@XZ@51 ; CHECK: `struct S & __cdecl getS(void)'::`2'::`local static guard'{2} ; TODO(mitsuhiko): currently broken because no string decoding ;??_C@_02PCEFGMJL@hi?$AA@ ;; CHECK: "hi" ??_DDiamond@@QEAAXXZ ; CHECK: void __cdecl Diamond::`vbase dtor'(void) ??_EBase@@UEAAPEAXI@Z ; CHECK: virtual void * __cdecl Base::`vector deleting dtor'(unsigned int) ; TODO(mitsuhiko): currently broken (virtual vs unimplemented adjustor) ;??_EBase@@G3AEPAXI@Z ;; CHECK: [thunk]: private: void * __thiscall Base::`vector deleting dtor'`adjustor{4}'(unsigned int) ??_F?$SomeTemplate@H@@QAEXXZ ; CHECK: void __thiscall SomeTemplate::`default ctor closure'(void) ??_GBase@@UEAAPEAXI@Z ; CHECK: virtual void * __cdecl Base::`scalar deleting dtor'(unsigned int) ??_H@YAXPEAX_K1P6APEAX0@Z@Z ; CHECK: void __cdecl `vector ctor iterator'(void *, unsigned __int64, unsigned __int64, void * (__cdecl *)(void *)) ??_I@YAXPEAX_K1P6AX0@Z@Z ; CHECK: void __cdecl `vector dtor iterator'(void *, unsigned __int64, unsigned __int64, void (__cdecl *)(void *)) ??_JBase@@UEAAPEAXI@Z ; CHECK: virtual void * __cdecl Base::`vector vbase ctor iterator'(unsigned int) ??_KBase@@UEAAPEAXI@Z ; CHECK: virtual void * __cdecl Base::`virtual displacement map'(unsigned int) ??_LBase@@UEAAPEAXI@Z ; CHECK: virtual void * __cdecl Base::`eh vector ctor iterator'(unsigned int) ??_MBase@@UEAAPEAXI@Z ; CHECK: virtual void * __cdecl Base::`eh vector dtor iterator'(unsigned int) ??_NBase@@UEAAPEAXI@Z ; CHECK: virtual void * __cdecl Base::`eh vector vbase ctor iterator'(unsigned int) ??_O?$SomeTemplate@H@@QAEXXZ ; CHECK: void __thiscall SomeTemplate::`copy ctor closure'(void) ??_SBase@@6B@ ; CHECK: const Base::`local vftable' ??_TDerived@@QEAAXXZ ; CHECK: void __cdecl Derived::`local vftable ctor closure'(void) ??_U@YAPEAX_KAEAVklass@@@Z ; CHECK: void * __cdecl operator new[](unsigned __int64, class klass &) ??_V@YAXPEAXAEAVklass@@@Z ; CHECK: void __cdecl operator delete[](void *, class klass &) ??_R0?AUBase@@@8 ; CHECK: struct Base `RTTI Type Descriptor' ??_R1A@?0A@EA@Base@@8 ; CHECK: Base::`RTTI Base Class Descriptor at (0, -1, 0, 64)' ??_R2Base@@8 ; CHECK: Base::`RTTI Base Class Array' ??_R3Base@@8 ; CHECK: Base::`RTTI Class Hierarchy Descriptor' ??_R4Base@@6B@ ; CHECK: const Base::`RTTI Complete Object Locator' ; Generated for `int Foo = f(4);` at global scope. ??__EFoo@@YAXXZ ; TODO(mitsuhiko): below is the original llvm behavior ;; CHECK: void __cdecl `dynamic initializer for 'Foo''(void) ; CHECK: void __cdecl Foo::`dynamic initializer'(void) ; Generated for ; class C { static int i; }; ; int C::i = f(5); ; TODO(mitsuhiko): This is completely fucked up currently ;??__E?i@C@@0HA@@YAXXZ ;; CHECK: void __cdecl `dynamic initializer for `private: static int C::i''(void) ??__FFoo@@YAXXZ ; TODO(mitsuhiko): Our output does not match llvm here ;; CHECK: void __cdecl `dynamic atexit destructor for 'Foo''(void) ; CHECK: void __cdecl Foo::`dynamic atexit destructor'(void) ??__F_decisionToDFA@XPathLexer@@0V?$vector@VDFA@dfa@antlr4@@V?$allocator@VDFA@dfa@antlr4@@@std@@@std@@A@YAXXZ ; TODO(mitsuhiko): Our output does not match llvm here ;; CHECK: void __cdecl `dynamic atexit destructor for `private: static class std::vector> XPathLexer::_decisionToDFA''(void) ; CHECK: private: static class std::vector > XPathLexer::_decisionToDFA::`dynamic atexit destructor' ??__J?1??f@@YAAAUS@@XZ@51 ; CHECK: `struct S & __cdecl f(void)'::`2'::`local static thread guard'{2} ??__K_deg@@YAHO@Z ; CHECK: int __cdecl operator ""_deg(long double) msvc-demangler-0.10.1/tests/llvm-cases/ms-windows.test000064400000000000000000000006701046102023000210320ustar 00000000000000; See clang/test/CodeGenCXX/mangle-windows.cpp ; These tests are based on clang/test/CodeGenCXX/mangle-ms.cpp ; RUN: llvm-undname < %s | FileCheck %s ; CHECK-NOT: Invalid mangled name ?bar@Foo@@SGXXZ ; CHECK: static void __stdcall Foo::bar(void) ?bar@Foo@@QAGXXZ ; CHECK: void __stdcall Foo::bar(void) ?f2@@YIXXZ ; CHECK: void __fastcall f2(void) ?f1@@YGXXZ ; CHECK: void __stdcall f1(void) ?f5@@YCXXZ ; CHECK: void __pascal f5(void) msvc-demangler-0.10.1/tests/llvm-cases/unused/invalid-manglings.test000064400000000000000000000170021046102023000236260ustar 00000000000000; Run llvm-undname with invalid inputs and make sure it doesn't crash. ; RUN: not llvm-undname < %s 2>&1 | FileCheck %s ?ff@@$$J0YAXAU?$AS_@$0A@PEAU?$AS_@$0A@H@__clang@@@__clang@@@Z ; CHECK: ?ff@@$$J0YAXAU?$AS_@$0A@PEAU?$AS_@$0A@H@__clang@@@__clang@@@Z ; CHECK-NEXT: error: Invalid mangled name ?f0@@YAXPEU?$AS_@$00$$CAD@__clang@@@Z ; CHECK-EMPTY: ; CHECK-NEXT: ?f0@@YAXPEU?$AS_@$00$$CAD@__clang@@@Z ; CHECK-NEXT: error: Invalid mangled name ?@@8 ; CHECK-EMPTY: ; CHECK-NEXT: ?@@8 ; CHECK-NEXT: error: Invalid mangled name ?? ; CHECK-EMPTY: ; CHECK-NEXT: ?? ; CHECK-NEXT: error: Invalid mangled name ??0@ ; CHECK-EMPTY: ; CHECK-NEXT: ??0@ ; CHECK-NEXT: error: Invalid mangled name ? @@ YC@ ; CHECK-EMPTY: ; CHECK-NEXT: ? @@ YC@ ; CHECK-NEXT: error: Invalid mangled name ??B@$$J0 ; CHECK-EMPTY: ; CHECK-NEXT: ??B@$$J0 ; CHECK-NEXT: error: Invalid mangled name ??B@4 ; CHECK-EMPTY: ; CHECK-NEXT: ??B@4 ; CHECK-NEXT: error: Invalid mangled name ?A?@?@???B@4D ; CHECK-EMPTY: ; CHECK-NEXT: ?A?@?@???B@4D ; CHECK-NEXT: error: Invalid mangled name ?A?@?@???B@4DD ; CHECK-EMPTY: ; CHECK-NEXT: ?A?@?@???B@4DD ; CHECK-NEXT: error: Invalid mangled name ??$A@P15@ ; CHECK-EMPTY: ; CHECK-NEXT: ??$A@P15@ ; CHECK-NEXT: error: Invalid mangled name ??$A@P ; CHECK-EMPTY: ; CHECK-NEXT: ??$A@P ; CHECK-NEXT: error: Invalid mangled name ?A@@ ; CHECK-EMPTY: ; CHECK-NEXT: ?A@@ ; CHECK-NEXT: error: Invalid mangled name ?A@@P ; CHECK-EMPTY: ; CHECK-NEXT: ?A@@P ; CHECK-NEXT: error: Invalid mangled name ?A@@4PQA@@ ; CHECK-EMPTY: ; CHECK-NEXT: ?A@@4PQA@@ ; CHECK-NEXT: error: Invalid mangled name ??__E ; CHECK-EMPTY: ; CHECK-NEXT: ??__E ; CHECK-NEXT: error: Invalid mangled name ??__E@@ ; CHECK-EMPTY: ; CHECK-NEXT: ??__E@@ ; CHECK-NEXT: error: Invalid mangled name ??__E?Foo@@0HA@@ ; CHECK-EMPTY: ; CHECK-NEXT: ??__E?Foo@@0HA@@ ; CHECK-NEXT: error: Invalid mangled name ??__E?i@C@@0HA@ ; CHECK-EMPTY: ; CHECK-NEXT: ??__E?i@C@@0HA@ ; CHECK-NEXT: error: Invalid mangled name ??__E?Foo@@YAXXZ ; CHECK-EMPTY: ; CHECK-NEXT: ??__E?Foo@@YAXXZ ; CHECK-NEXT: error: Invalid mangled name ?foo@@YAH0@Z ; CHECK-EMPTY: ; CHECK-NEXT: ?foo@@YAH0@Z ; CHECK-NEXT: error: Invalid mangled name ?foo@@YAHH ; CHECK-EMPTY: ; CHECK-NEXT: ?foo@@YAHH ; CHECK-NEXT: error: Invalid mangled name ??8@8 ; CHECK-EMPTY: ; CHECK-NEXT: ??8@8 ; CHECK-NEXT: error: Invalid mangled name ?B@?$?K$H? ; CHECK-EMPTY: ; CHECK-NEXT: ?B@?$?K$H? ; CHECK-NEXT: error: Invalid mangled name ??C@$ ; CHECK-EMPTY: ; CHECK-NEXT: ??C@$ ; CHECK-NEXT: error: Invalid mangled name ?x@@3PAW ; CHECK-EMPTY: ; CHECK-NEXT: ?x@@3PAW ; CHECK-NEXT: error: Invalid mangled name ??} ; CHECK-EMPTY: ; CHECK-NEXT: ??} ; CHECK-NEXT: error: Invalid mangled name ?foo@?$?_ ; CHECK-EMPTY: ; CHECK-NEXT: ?foo@?$?_ ; CHECK-NEXT: error: Invalid mangled name ??_R4 ; CHECK-EMPTY: ; CHECK-NEXT: ??_R4 ; CHECK-NEXT: error: Invalid mangled name ??_R4foo@@ ; CHECK-EMPTY: ; CHECK-NEXT: ??_R4foo@@ ; CHECK-NEXT: error: Invalid mangled name ?foo@?$?BH@@QAEHXZ ; CHECK-EMPTY: ; CHECK-NEXT: ?foo@?$?BH@@QAEHXZ ; CHECK-NEXT: error: Invalid mangled name ?foo@?$?0H@ ; CHECK-EMPTY: ; CHECK-NEXT: ?foo@?$?0H@ ; CHECK-NEXT: error: Invalid mangled name ??_C@_0A@01234567@a ; CHECK-EMPTY: ; CHECK-NEXT: ??_C@_0A@01234567@a ; CHECK-NEXT: error: Invalid mangled name ??_C@_1A@01234567@a ; CHECK-EMPTY: ; CHECK-NEXT: ??_C@_1A@01234567@a ; CHECK-NEXT: error: Invalid mangled name ??_C@_0301234567@a ; CHECK-EMPTY: ; CHECK-NEXT: ??_C@_0301234567@a ; CHECK-NEXT: error: Invalid mangled name ??_C@_1301234567@a ; CHECK-EMPTY: ; CHECK-NEXT: ??_C@_1301234567@a ; CHECK-NEXT: error: Invalid mangled name ??_C@_0601234567@abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRTSUVWXYZabcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRTSUVWXYZabcdefghijklmnopqrtsuvwxyz ; CHECK-EMPTY: ; CHECK-NEXT: ??_C@_0601234567@abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRTSUVWXYZabcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRTSUVWXYZabcdefghijklmnopqrtsuvwxyz ; CHECK-NEXT: error: Invalid mangled name ??_C@_12@?z ; CHECK-EMPTY: ; CHECK-NEXT: ??_C@_12@?z ; CHECK-NEXT: error: Invalid mangled name ??$foo@$1??_C@_02PCEFGMJL@hi?$AA@@ ; CHECK-EMPTY: ; CHECK-NEXT: ??$foo@$1??_C@_02PCEFGMJL@hi?$AA@@ ; CHECK-NEXT: error: Invalid mangled name ??_C@ ; CHECK-EMPTY: ; CHECK-NEXT: ??_C@ ; CHECK-NEXT: error: Invalid mangled name ??_C@_ ; CHECK-EMPTY: ; CHECK-NEXT: ??_C@_ ; CHECK-NEXT: error: Invalid mangled name ??_C@_3 ; CHECK-EMPTY: ; CHECK-NEXT: ??_C@_3 ; CHECK-NEXT: error: Invalid mangled name ??_C@_01 ; CHECK-EMPTY: ; CHECK-NEXT: ??_C@_01 ; CHECK-NEXT: error: Invalid mangled name ??_C@_0101234567@ ; CHECK-EMPTY: ; CHECK-NEXT: ??_C@_0101234567@ ; CHECK-NEXT: error: Invalid mangled name ??_C@_0101234567@? ; CHECK-EMPTY: ; CHECK-NEXT: ??_C@_0101234567@? ; CHECK-NEXT: error: Invalid mangled name ??_C@_0101234567@?$ ; CHECK-EMPTY: ; CHECK-NEXT: ??_C@_0101234567@?$ ; CHECK-NEXT: error: Invalid mangled name ??_C@_0101234567@?$za ; CHECK-EMPTY: ; CHECK-NEXT: ??_C@_0101234567@?$za ; CHECK-NEXT: error: Invalid mangled name ??_C@_0101234567@?$az ; CHECK-EMPTY: ; CHECK-NEXT: ??_C@_0101234567@?$az ; CHECK-NEXT: error: Invalid mangled name ??_C@_1201234567@a?$az ; CHECK-EMPTY: ; CHECK-NEXT: ??_C@_1201234567@a?$az ; CHECK-NEXT: error: Invalid mangled name ??@foo ; CHECK-EMPTY: ; CHECK-NEXT: ??@foo ; CHECK-NEXT: error: Invalid mangled name ?foo@@3YA@A ; CHECK-EMPTY: ; CHECK-NEXT: ?foo@@3YA@A ; CHECK-NEXT: error: Invalid mangled name ?foo@@3Y~01KA ; CHECK-EMPTY: ; CHECK-NEXT: ?foo@@3Y~01KA ; CHECK-NEXT: error: Invalid mangled name ?foo@@3Y0~1KA ; CHECK-EMPTY: ; CHECK-NEXT: ?foo@@3Y0~1KA ; CHECK-NEXT: error: Invalid mangled name ?x@@3PEAY02$$CRHEA ; CHECK-EMPTY: ; CHECK-NEXT: ?x@@3PEAY02$$CRHEA ; CHECK-NEXT: error: Invalid mangled name ?foo@@3_ ; CHECK-EMPTY: ; CHECK-NEXT: ?foo@@3_ ; CHECK-NEXT: error: Invalid mangled name ?foo@@3_XA ; CHECK-EMPTY: ; CHECK-NEXT: ?foo@@3_XA ; CHECK-NEXT: error: Invalid mangled name ?foo@@3Vbar ; CHECK-EMPTY: ; CHECK-NEXT: ?foo@@3Vbar ; CHECK-NEXT: error: Invalid mangled name ?foo@@3Vbar@ ; CHECK-EMPTY: ; CHECK-NEXT: ?foo@@3Vbar@ ; CHECK-NEXT: error: Invalid mangled name ?foo@?A ; CHECK-EMPTY: ; CHECK-NEXT: ?foo@?A ; CHECK-NEXT: error: Invalid mangled name ?foo@? ; CHECK-EMPTY: ; CHECK-NEXT: ?foo@? ; CHECK-NEXT: error: Invalid mangled name ?foo@?? ; CHECK-EMPTY: ; CHECK-NEXT: ?foo@?? ; CHECK-NEXT: error: Invalid mangled name ?foo@?XX? ; CHECK-EMPTY: ; CHECK-NEXT: ?foo@?XX? ; CHECK-NEXT: error: Invalid mangled name ?foo@?A@? ; CHECK-EMPTY: ; CHECK-NEXT: ?foo@?A@? ; CHECK-NEXT: error: Invalid mangled name ?foo@?Q@? ; CHECK-EMPTY: ; CHECK-NEXT: ?foo@?Q@? ; CHECK-NEXT: error: Invalid mangled name ?foo@?BQ@? ; CHECK-EMPTY: ; CHECK-NEXT: ?foo@?BQ@? ; CHECK-NEXT: error: Invalid mangled name ?foo@?0? ; CHECK-EMPTY: ; CHECK-NEXT: ?foo@?0? ; CHECK-NEXT: error: Invalid mangled name ??_Sfoo@@1Abar@@ ; CHECK-EMPTY: ; CHECK-NEXT: ??_Sfoo@@1Abar@@ ; CHECK-NEXT: error: Invalid mangled name ??_Bfoo@@1 ; CHECK-EMPTY: ; CHECK-NEXT: ??_Bfoo@@1 ; CHECK-NEXT: error: Invalid mangled name ??_R0 ; CHECK-EMPTY: ; CHECK-NEXT: ??_R0 ; CHECK-NEXT: error: Invalid mangled name ??_R0H ; CHECK-EMPTY: ; CHECK-NEXT: ??_R0H ; CHECK-NEXT: error: Invalid mangled name ??_R0H@8foo ; CHECK-EMPTY: ; CHECK-NEXT: ??_R0H@8foo ; CHECK-NEXT: error: Invalid mangled name ??_R1012?3foo@@ ; CHECK-EMPTY: ; CHECK-NEXT: ??_R1012?3foo@@ ; CHECK-NEXT: error: Invalid mangled name ??_R2foo@@1 ; CHECK-EMPTY: ; CHECK-NEXT: ??_R2foo@@1 ; CHECK-NEXT: error: Invalid mangled name ??_A ; CHECK-EMPTY: ; CHECK-NEXT: ??_A ; CHECK-NEXT: error: Invalid mangled name ??_P ; CHECK-EMPTY: ; CHECK-NEXT: ??_P ; CHECK-NEXT: error: Invalid mangled name msvc-demangler-0.10.1/tests/llvm-cases/unused/ms-arg-qualifiers.test000064400000000000000000000242321046102023000235560ustar 00000000000000; These tests are based on clang/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp ; RUN: llvm-undname < %s | FileCheck %s ; CHECK-NOT: Invalid mangled name ?foo@@YAXI@Z ; CHECK: void __cdecl foo(unsigned int) ?foo@@YAXN@Z ; CHECK: void __cdecl foo(double) ?foo_pad@@YAXPAD@Z ; CHECK: void __cdecl foo_pad(char *) ?foo_pad@@YAXPEAD@Z ; CHECK: void __cdecl foo_pad(char *) ?foo_pbd@@YAXPBD@Z ; CHECK: void __cdecl foo_pbd(char const *) ?foo_pbd@@YAXPEBD@Z ; CHECK: void __cdecl foo_pbd(char const *) ?foo_pcd@@YAXPCD@Z ; CHECK: void __cdecl foo_pcd(char volatile *) ?foo_pcd@@YAXPECD@Z ; CHECK: void __cdecl foo_pcd(char volatile *) ?foo_qad@@YAXQAD@Z ; CHECK: void __cdecl foo_qad(char *const) ?foo_qad@@YAXQEAD@Z ; CHECK: void __cdecl foo_qad(char *const) ?foo_rad@@YAXRAD@Z ; CHECK: void __cdecl foo_rad(char *volatile) ?foo_rad@@YAXREAD@Z ; CHECK: void __cdecl foo_rad(char *volatile) ?foo_sad@@YAXSAD@Z ; CHECK: void __cdecl foo_sad(char *const volatile) ?foo_sad@@YAXSEAD@Z ; CHECK: void __cdecl foo_sad(char *const volatile) ?foo_piad@@YAXPIAD@Z ; CHECK: void __cdecl foo_piad(char *__restrict) ?foo_piad@@YAXPEIAD@Z ; CHECK: void __cdecl foo_piad(char *__restrict) ?foo_qiad@@YAXQIAD@Z ; CHECK: void __cdecl foo_qiad(char *const __restrict) ?foo_qiad@@YAXQEIAD@Z ; CHECK: void __cdecl foo_qiad(char *const __restrict) ?foo_riad@@YAXRIAD@Z ; CHECK: void __cdecl foo_riad(char *volatile __restrict) ?foo_riad@@YAXREIAD@Z ; CHECK: void __cdecl foo_riad(char *volatile __restrict) ?foo_siad@@YAXSIAD@Z ; CHECK: void __cdecl foo_siad(char *const volatile __restrict) ?foo_siad@@YAXSEIAD@Z ; CHECK: void __cdecl foo_siad(char *const volatile __restrict) ?foo_papad@@YAXPAPAD@Z ; CHECK: void __cdecl foo_papad(char **) ?foo_papad@@YAXPEAPEAD@Z ; CHECK: void __cdecl foo_papad(char **) ?foo_papbd@@YAXPAPBD@Z ; CHECK: void __cdecl foo_papbd(char const **) ?foo_papbd@@YAXPEAPEBD@Z ; CHECK: void __cdecl foo_papbd(char const **) ?foo_papcd@@YAXPAPCD@Z ; CHECK: void __cdecl foo_papcd(char volatile **) ?foo_papcd@@YAXPEAPECD@Z ; CHECK: void __cdecl foo_papcd(char volatile **) ?foo_pbqad@@YAXPBQAD@Z ; CHECK: void __cdecl foo_pbqad(char *const *) ?foo_pbqad@@YAXPEBQEAD@Z ; CHECK: void __cdecl foo_pbqad(char *const *) ?foo_pcrad@@YAXPCRAD@Z ; CHECK: void __cdecl foo_pcrad(char *volatile *) ?foo_pcrad@@YAXPECREAD@Z ; CHECK: void __cdecl foo_pcrad(char *volatile *) ?foo_qapad@@YAXQAPAD@Z ; CHECK: void __cdecl foo_qapad(char **const) ?foo_qapad@@YAXQEAPEAD@Z ; CHECK: void __cdecl foo_qapad(char **const) ?foo_rapad@@YAXRAPAD@Z ; CHECK: void __cdecl foo_rapad(char **volatile) ?foo_rapad@@YAXREAPEAD@Z ; CHECK: void __cdecl foo_rapad(char **volatile) ?foo_pbqbd@@YAXPBQBD@Z ; CHECK: void __cdecl foo_pbqbd(char const *const *) ?foo_pbqbd@@YAXPEBQEBD@Z ; CHECK: void __cdecl foo_pbqbd(char const *const *) ?foo_pbqcd@@YAXPBQCD@Z ; CHECK: void __cdecl foo_pbqcd(char volatile *const *) ?foo_pbqcd@@YAXPEBQECD@Z ; CHECK: void __cdecl foo_pbqcd(char volatile *const *) ?foo_pcrbd@@YAXPCRBD@Z ; CHECK: void __cdecl foo_pcrbd(char const *volatile *) ?foo_pcrbd@@YAXPECREBD@Z ; CHECK: void __cdecl foo_pcrbd(char const *volatile *) ?foo_pcrcd@@YAXPCRCD@Z ; CHECK: void __cdecl foo_pcrcd(char volatile *volatile *) ?foo_pcrcd@@YAXPECRECD@Z ; CHECK: void __cdecl foo_pcrcd(char volatile *volatile *) ?foo_aad@@YAXAAD@Z ?foo_aad@@YAXAEAD@Z ; CHECK: void __cdecl foo_aad(char &) ?foo_abd@@YAXABD@Z ; CHECK: void __cdecl foo_abd(char const &) ?foo_abd@@YAXAEBD@Z ; CHECK: void __cdecl foo_abd(char const &) ?foo_aapad@@YAXAAPAD@Z ; CHECK: void __cdecl foo_aapad(char *&) ?foo_aapad@@YAXAEAPEAD@Z ; CHECK: void __cdecl foo_aapad(char *&) ?foo_aapbd@@YAXAAPBD@Z ; CHECK: void __cdecl foo_aapbd(char const *&) ?foo_aapbd@@YAXAEAPEBD@Z ; CHECK: void __cdecl foo_aapbd(char const *&) ?foo_abqad@@YAXABQAD@Z ; CHECK: void __cdecl foo_abqad(char *const &) ?foo_abqad@@YAXAEBQEAD@Z ; CHECK: void __cdecl foo_abqad(char *const &) ?foo_abqbd@@YAXABQBD@Z ; CHECK: void __cdecl foo_abqbd(char const *const &) ?foo_abqbd@@YAXAEBQEBD@Z ; CHECK: void __cdecl foo_abqbd(char const *const &) ?foo_aay144h@@YAXAAY144H@Z ; CHECK: void __cdecl foo_aay144h(int (&)[5][5]) ?foo_aay144h@@YAXAEAY144H@Z ; CHECK: void __cdecl foo_aay144h(int (&)[5][5]) ?foo_aay144cbh@@YAXAAY144$$CBH@Z ; CHECK: void __cdecl foo_aay144cbh(int const (&)[5][5]) ?foo_aay144cbh@@YAXAEAY144$$CBH@Z ; CHECK: void __cdecl foo_aay144cbh(int const (&)[5][5]) ?foo_qay144h@@YAX$$QAY144H@Z ; CHECK: void __cdecl foo_qay144h(int (&&)[5][5]) ?foo_qay144h@@YAX$$QEAY144H@Z ; CHECK: void __cdecl foo_qay144h(int (&&)[5][5]) ?foo_qay144cbh@@YAX$$QAY144$$CBH@Z ; CHECK: void __cdecl foo_qay144cbh(int const (&&)[5][5]) ?foo_qay144cbh@@YAX$$QEAY144$$CBH@Z ; CHECK: void __cdecl foo_qay144cbh(int const (&&)[5][5]) ?foo_p6ahxz@@YAXP6AHXZ@Z ; CHECK: void __cdecl foo_p6ahxz(int (__cdecl *)(void)) ?foo_p6ahxz@@YAXP6AHXZ@Z ; CHECK: void __cdecl foo_p6ahxz(int (__cdecl *)(void)) ?foo_a6ahxz@@YAXA6AHXZ@Z ; CHECK: void __cdecl foo_a6ahxz(int (__cdecl &)(void)) ?foo_a6ahxz@@YAXA6AHXZ@Z ; CHECK: void __cdecl foo_a6ahxz(int (__cdecl &)(void)) ?foo_q6ahxz@@YAX$$Q6AHXZ@Z ; CHECK: void __cdecl foo_q6ahxz(int (__cdecl &&)(void)) ?foo_q6ahxz@@YAX$$Q6AHXZ@Z ; CHECK: void __cdecl foo_q6ahxz(int (__cdecl &&)(void)) ?foo_qay04h@@YAXQAY04H@Z ?foo_qay04h@@YAXQEAY04H@Z ; CHECK: void __cdecl foo_qay04h(int (*const)[5]) ?foo_qay04cbh@@YAXQAY04$$CBH@Z ; CHECK: void __cdecl foo_qay04cbh(int const (*const)[5]) ?foo_qay04cbh@@YAXQEAY04$$CBH@Z ; CHECK: void __cdecl foo_qay04cbh(int const (*const)[5]) ?foo@@YAXPAY02N@Z ; CHECK: void __cdecl foo(double (*)[3]) ?foo@@YAXPEAY02N@Z ; CHECK: void __cdecl foo(double (*)[3]) ?foo@@YAXQAN@Z ; CHECK: void __cdecl foo(double *const) ?foo@@YAXQEAN@Z ; CHECK: void __cdecl foo(double *const) ?foo_const@@YAXQBN@Z ; CHECK: void __cdecl foo_const(double const *const) ?foo_const@@YAXQEBN@Z ; CHECK: void __cdecl foo_const(double const *const) ?foo_volatile@@YAXQCN@Z ; CHECK: void __cdecl foo_volatile(double volatile *const) ?foo_volatile@@YAXQECN@Z ; CHECK: void __cdecl foo_volatile(double volatile *const) ?foo@@YAXPAY02NQBNN@Z ; CHECK: void __cdecl foo(double (*)[3], double const *const, double) ?foo@@YAXPEAY02NQEBNN@Z ; CHECK: void __cdecl foo(double (*)[3], double const *const, double) ?foo_fnptrconst@@YAXP6AXQAH@Z@Z ; CHECK: void __cdecl foo_fnptrconst(void (__cdecl *)(int *const)) ?foo_fnptrconst@@YAXP6AXQEAH@Z@Z ; CHECK: void __cdecl foo_fnptrconst(void (__cdecl *)(int *const)) ?foo_fnptrarray@@YAXP6AXQAH@Z@Z ; CHECK: void __cdecl foo_fnptrarray(void (__cdecl *)(int *const)) ?foo_fnptrarray@@YAXP6AXQEAH@Z@Z ; CHECK: void __cdecl foo_fnptrarray(void (__cdecl *)(int *const)) ?foo_fnptrbackref1@@YAXP6AXQAH@Z1@Z ; CHECK: void __cdecl foo_fnptrbackref1(void (__cdecl *)(int *const), void (__cdecl *)(int *const)) ?foo_fnptrbackref1@@YAXP6AXQEAH@Z1@Z ; CHECK: void __cdecl foo_fnptrbackref1(void (__cdecl *)(int *const), void (__cdecl *)(int *const)) ?foo_fnptrbackref2@@YAXP6AXQAH@Z1@Z ; CHECK: void __cdecl foo_fnptrbackref2(void (__cdecl *)(int *const), void (__cdecl *)(int *const)) ?foo_fnptrbackref2@@YAXP6AXQEAH@Z1@Z ; CHECK: void __cdecl foo_fnptrbackref2(void (__cdecl *)(int *const), void (__cdecl *)(int *const)) ?foo_fnptrbackref3@@YAXP6AXQAH@Z1@Z ; CHECK: void __cdecl foo_fnptrbackref3(void (__cdecl *)(int *const), void (__cdecl *)(int *const)) ?foo_fnptrbackref3@@YAXP6AXQEAH@Z1@Z ; CHECK: void __cdecl foo_fnptrbackref3(void (__cdecl *)(int *const), void (__cdecl *)(int *const)) ?foo_fnptrbackref4@@YAXP6AXPAH@Z1@Z ; CHECK: void __cdecl foo_fnptrbackref4(void (__cdecl *)(int *), void (__cdecl *)(int *)) ?foo_fnptrbackref4@@YAXP6AXPEAH@Z1@Z ; CHECK: void __cdecl foo_fnptrbackref4(void (__cdecl *)(int *), void (__cdecl *)(int *)) ?ret_fnptrarray@@YAP6AXQAH@ZXZ ; CHECK: void (__cdecl * __cdecl ret_fnptrarray(void))(int *const) ?ret_fnptrarray@@YAP6AXQEAH@ZXZ ; CHECK: void (__cdecl * __cdecl ret_fnptrarray(void))(int *const) ; The first argument gets mangled as-if it were written int *const ; The second arg should not form a backref because it isn't qualified ?mangle_no_backref0@@YAXQAHPAH@Z ; CHECK: void __cdecl mangle_no_backref0(int *const, int *) ?mangle_no_backref0@@YAXQEAHPEAH@Z ; CHECK: void __cdecl mangle_no_backref0(int *const, int *) ?mangle_no_backref1@@YAXQAHQAH@Z ; CHECK: void __cdecl mangle_no_backref1(int *const, int *const) ?mangle_no_backref1@@YAXQEAHQEAH@Z ; CHECK: void __cdecl mangle_no_backref1(int *const, int *const) ; Pointer to function types don't backref with function types ?mangle_no_backref2@@YAXP6AXXZP6AXXZ@Z ; CHECK: void __cdecl mangle_no_backref2(void (__cdecl *)(void), void (__cdecl *)(void)) ?mangle_no_backref2@@YAXP6AXXZP6AXXZ@Z ; CHECK: void __cdecl mangle_no_backref2(void (__cdecl *)(void), void (__cdecl *)(void)) ?mangle_yes_backref0@@YAXQAH0@Z ; CHECK: void __cdecl mangle_yes_backref0(int *const, int *const) ?mangle_yes_backref0@@YAXQEAH0@Z ; CHECK: void __cdecl mangle_yes_backref0(int *const, int *const) ?mangle_yes_backref1@@YAXQAH0@Z ; CHECK: void __cdecl mangle_yes_backref1(int *const, int *const) ?mangle_yes_backref1@@YAXQEAH0@Z ; CHECK: void __cdecl mangle_yes_backref1(int *const, int *const) ?mangle_yes_backref2@@YAXQBQ6AXXZ0@Z ; CHECK: void __cdecl mangle_yes_backref2(void (__cdecl *const *const)(void), void (__cdecl *const *const)(void)) ?mangle_yes_backref2@@YAXQEBQ6AXXZ0@Z ; CHECK: void __cdecl mangle_yes_backref2(void (__cdecl *const *const)(void), void (__cdecl *const *const)(void)) ?mangle_yes_backref3@@YAXQAP6AXXZ0@Z ; CHECK: void __cdecl mangle_yes_backref3(void (__cdecl **const)(void), void (__cdecl **const)(void)) ?mangle_yes_backref3@@YAXQEAP6AXXZ0@Z ; CHECK: void __cdecl mangle_yes_backref3(void (__cdecl **const)(void), void (__cdecl **const)(void)) ?mangle_yes_backref4@@YAXQIAH0@Z ; CHECK: void __cdecl mangle_yes_backref4(int *const __restrict, int *const __restrict) ?mangle_yes_backref4@@YAXQEIAH0@Z ; CHECK: void __cdecl mangle_yes_backref4(int *const __restrict, int *const __restrict) ?pr23325@@YAXQBUS@@0@Z ; CHECK: void __cdecl pr23325(struct S const *const, struct S const *const) ?pr23325@@YAXQEBUS@@0@Z ; CHECK: void __cdecl pr23325(struct S const *const, struct S const *const) ; ?vla_arg@@YAXHQAY0A@H@Z ; FIXME: void __cdecl vla_arg(int i, int (*const)[0]) ; ?vla_arg@@YAXHQEAY0A@H@Z ; FIXME: void __cdecl vla_arg(int i, int (*const)[0]) msvc-demangler-0.10.1/tests/llvm-cases/unused/ms-conversion-operators.test000064400000000000000000000032661046102023000250500ustar 00000000000000; RUN: llvm-undname < %s | FileCheck %s ; CHECK-NOT: Invalid mangled name ??$?BH@TemplateOps@@QAEHXZ ; CHECK: int __thiscall TemplateOps::operator int(void) ??BOps@@QAEHXZ ; CHECK: int __thiscall Ops::operator int(void) ??BConstOps@@QAE?BHXZ ; CHECK: int const __thiscall ConstOps::operator int const(void) ??BVolatileOps@@QAE?CHXZ ; CHECK: int volatile __thiscall VolatileOps::operator int volatile(void) ??BConstVolatileOps@@QAE?DHXZ ; CHECK: int const volatile __thiscall ConstVolatileOps::operator int const volatile(void) ??$?BN@TemplateOps@@QAENXZ ; CHECK: double __thiscall TemplateOps::operator double(void) ??BOps@@QAENXZ ; CHECK: double __thiscall Ops::operator double(void) ??BConstOps@@QAE?BNXZ ; CHECK: double const __thiscall ConstOps::operator double const(void) ??BVolatileOps@@QAE?CNXZ ; CHECK: double volatile __thiscall VolatileOps::operator double volatile(void) ??BConstVolatileOps@@QAE?DNXZ ; CHECK: double const volatile __thiscall ConstVolatileOps::operator double const volatile(void) ??BCompoundTypeOps@@QAEPAHXZ ; CHECK: nt * __thiscall CompoundTypeOps::operator int *(void) ??BCompoundTypeOps@@QAEPBHXZ ; CHECK: int const * __thiscall CompoundTypeOps::operator int const *(void) ??BCompoundTypeOps@@QAE$$QAHXZ ; CHECK: int && __thiscall CompoundTypeOps::operator int &&(void) ??BCompoundTypeOps@@QAE?AU?$Foo@H@@XZ ; CHECK: struct Foo __thiscall CompoundTypeOps::operator struct Foo(void) ??$?BH@CompoundTypeOps@@QAE?AU?$Bar@U?$Foo@H@@@@XZ ; CHECK: struct Bar> __thiscall CompoundTypeOps::operator struct Bar>(void) ??$?BPAH@TemplateOps@@QAEPAHXZ ; CHECK: int * __thiscall TemplateOps::operator int *(void) msvc-demangler-0.10.1/tests/llvm-cases/unused/ms-cxx14.test000064400000000000000000000032241046102023000216100ustar 00000000000000; These tests are based on clang/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp ; RUN: llvm-undname < %s | FileCheck %s ; CHECK-NOT: Invalid mangled name ??$x@X@@3HA ; CHECK: int x ?FunctionWithLocalType@@YA?A?@@XZ ; CHECK: __cdecl FunctionWithLocalType(void) ?ValueFromFunctionWithLocalType@@3ULocalType@?1??FunctionWithLocalType@@YA?A?@@XZ@A ; CHECK: struct ` __cdecl FunctionWithLocalType(void)'::`2'::LocalType ValueFromFunctionWithLocalType ??R@@QBE?A?@@XZ ; CHECK: __thiscall ::operator()(void) const ?ValueFromLambdaWithLocalType@@3ULocalType@?1???R@@QBE?A?@@XZ@A ; CHECK: struct `public: __thiscall ::operator()(void) const'::`2'::LocalType ValueFromLambdaWithLocalType ?ValueFromTemplateFuncionWithLocalLambda@@3ULocalType@?2???R@?0???$TemplateFuncionWithLocalLambda@H@@YA?A?@@H@Z@QBE?A?3@XZ@A ; CHECK: struct `public: __thiscall ` __cdecl TemplateFuncionWithLocalLambda(int)'::`1'::::operator()(void) const'::`3'::LocalType ValueFromTemplateFuncionWithLocalLambda ??$TemplateFuncionWithLocalLambda@H@@YA?A?@@H@Z ; CHECK: __cdecl TemplateFuncionWithLocalLambda(int) ??R@?0???$TemplateFuncionWithLocalLambda@H@@YA?A?@@H@Z@QBE?A?1@XZ ; CHECK: __thiscall ` __cdecl TemplateFuncionWithLocalLambda(int)'::`1'::::operator()(void) const ??$WithPMD@$GA@A@?0@@3HA ; CHECK: int WithPMD<{0, 0, -1}> ?Zoo@@3U?$Foo@$1??$x@H@@3HA$1?1@3HA@@A ; CHECK: struct Foo<&int x, &int x> Zoo ??$unaligned_x@PFAH@@3PFAHA ; CHECK: int __unaligned *unaligned_x msvc-demangler-0.10.1/tests/llvm-cases/unused/ms-cxx17-noexcept.test000064400000000000000000000012421046102023000234340ustar 00000000000000; RUN: llvm-undname < %s | FileCheck %s ; CHECK-NOT: Invalid mangled name ?nochange@@YAXXZ ; CHECK: void __cdecl nochange(void) ?a@@YAXP6AHXZ@Z ; CHECK: void __cdecl a(int (__cdecl *)(void)) ?a@@YAXP6AHX_E@Z ; CHECK: void __cdecl a(int (__cdecl *)(void) noexcept) ?b@@YAXP6AHXZ@Z ; CHECK: void __cdecl b(int (__cdecl *)(void)) ?c@@YAXP6AHXZ@Z ; CHECK: void __cdecl c(int (__cdecl *)(void)) ?c@@YAXP6AHX_E@Z ; CHECK: void __cdecl c(int (__cdecl *)(void) noexcept) ?ee@?$e@$$A6AXXZ@@EEAAXXZ ; CHECK: private: virtual void __cdecl e::ee(void) ?ee@?$e@$$A6AXX_E@@EEAAXXZ ; CHECK: private: virtual void __cdecl e::ee(void) msvc-demangler-0.10.1/tests/llvm-cases/unused/ms-cxx20.test000064400000000000000000000005221046102023000216030ustar 00000000000000; RUN: llvm-undname < %s | FileCheck %s ; CHECK-NOT: Invalid mangled name ??__LA@@QEAA?AUno_suspend@@XZ ; CHECK: struct no_suspend __cdecl A::operator co_await(void) ??__MS@@QEAA?AVstrong_ordering@std@@AEBU0@@Z' ; CHECK: class std::strong_ordering __cdecl S::operator<=>(struct S const &) ?f@@YAX_Q@Z ; CHECK: void __cdecl f(char8_t) msvc-demangler-0.10.1/tests/llvm-cases/unused/ms-mangle.test000064400000000000000000000264261046102023000221150ustar 00000000000000; These tests are based on clang/test/CodeGenCXX/mangle-ms.cpp ; RUN: llvm-undname < %s | FileCheck %s ; CHECK-NOT: Invalid mangled name ?a@@3HA ; CHECK: int a ?b@N@@3HA ; CHECK: int N::b ?anonymous@?A@N@@3HA ; CHECK: int N::`anonymous namespace'::anonymous ?$RT1@NeedsReferenceTemporary@@3ABHB ; CHECK: int const &NeedsReferenceTemporary::$RT1 ?$RT1@NeedsReferenceTemporary@@3AEBHEB ; CHECK: int const &NeedsReferenceTemporary::$RT1 ?_c@@YAHXZ ; CHECK: int __cdecl _c(void) ?d@foo@@0FB ; CHECK: static short const foo::d ?e@foo@@1JC ; CHECK: static long volatile foo::e ?f@foo@@2DD ; CHECK: static char const volatile foo::f ??0foo@@QAE@XZ ; CHECK: __thiscall foo::foo(void) ??0foo@@QEAA@XZ ; CHECK: __cdecl foo::foo(void) ??1foo@@QAE@XZ ; CHECK: __thiscall foo::~foo(void) ??1foo@@QEAA@XZ ; CHECK: __cdecl foo::~foo(void) ??0foo@@QAE@H@Z ; CHECK: __thiscall foo::foo(int) ??0foo@@QEAA@H@Z ; CHECK: __cdecl foo::foo(int) ??0foo@@QAE@PAD@Z ; CHECK: __thiscall foo::foo(char *) ??0foo@@QEAA@PEAD@Z ; CHECK: __cdecl foo::foo(char *) ?bar@@YA?AVfoo@@XZ ; CHECK: class foo __cdecl bar(void) ?bar@@YA?AVfoo@@XZ ; CHECK: class foo __cdecl bar(void) ??Hfoo@@QAEHH@Z ; CHECK: int __thiscall foo::operator+(int) ??Hfoo@@QEAAHH@Z ; CHECK: int __cdecl foo::operator+(int) ??$?HH@S@@QEAAAEANH@Z ; CHECK: double & __cdecl S::operator+(int) ?static_method@foo@@SAPAV1@XZ ; CHECK: static class foo * __cdecl foo::static_method(void) ?static_method@foo@@SAPEAV1@XZ ; CHECK: static class foo * __cdecl foo::static_method(void) ?g@bar@@2HA ; CHECK: static int bar::g ; undname returns `int *h1`, but it is a bug in their demangler. Their mangler ; correctly mangles `int *h1` as ?h1@3PAHA and `int * const h1` as ?h1@3QAHA ?h1@@3QAHA ; CHECK: int *const h1 ?h2@@3QBHB ; CHECK: int const *const h2 ?h3@@3QIAHIA ; CHECK: int *const __restrict h3 ?h3@@3QEIAHEIA ; CHECK: int *const __restrict h3 ?i@@3PAY0BE@HA ; CHECK: int (*i)[20] ?FunArr@@3PAY0BE@P6AHHH@ZA ; CHECK: int (__cdecl *(*FunArr)[20])(int, int) ?j@@3P6GHCE@ZA ; CHECK: int (__stdcall *j)(signed char, unsigned char) ?funptr@@YAP6AHXZXZ ; CHECK: int (__cdecl * __cdecl funptr(void))(void) ?m@@3PRfoo@@DR1@ ; CHECK: char const foo::*m ?m@@3PERfoo@@DER1@ ; CHECK: char const foo::*m ?k@@3PTfoo@@DT1@ ; CHECK: char const volatile foo::*k ?k@@3PETfoo@@DET1@ ; CHECK: char const volatile foo::*k ?l@@3P8foo@@AEHH@ZQ1@ ; CHECK: int (__thiscall foo::*l)(int) ?g_cInt@@3HB ; CHECK: int const g_cInt ?g_vInt@@3HC ; CHECK: int volatile g_vInt ?g_cvInt@@3HD ; CHECK: int const volatile g_cvInt ?beta@@YI_N_J_W@Z ; CHECK: bool __fastcall beta(__int64, wchar_t) ?beta@@YA_N_J_W@Z ; CHECK: bool __cdecl beta(__int64, wchar_t) ?alpha@@YGXMN@Z ; CHECK: void __stdcall alpha(float, double) ?alpha@@YAXMN@Z ; CHECK: void __cdecl alpha(float, double) ?gamma@@YAXVfoo@@Ubar@@Tbaz@@W4quux@@@Z ; CHECK: void __cdecl gamma(class foo, struct bar, union baz, enum quux) ?gamma@@YAXVfoo@@Ubar@@Tbaz@@W4quux@@@Z ; CHECK: void __cdecl gamma(class foo, struct bar, union baz, enum quux) ?delta@@YAXQAHABJ@Z ; CHECK: void __cdecl delta(int *const, long const &) ?delta@@YAXQEAHAEBJ@Z ; CHECK: void __cdecl delta(int *const, long const &) ?epsilon@@YAXQAY19BE@H@Z ; CHECK: void __cdecl epsilon(int (*const)[10][20]) ?epsilon@@YAXQEAY19BE@H@Z ; CHECK: void __cdecl epsilon(int (*const)[10][20]) ?zeta@@YAXP6AHHH@Z@Z ; CHECK: void __cdecl zeta(int (__cdecl *)(int, int)) ?zeta@@YAXP6AHHH@Z@Z ; CHECK: void __cdecl zeta(int (__cdecl *)(int, int)) ; FIXME: We don't support blocks yet. ; ?eta@@YAXP_EAHHH@Z@Z ; FIXME: void eta(int (^)(int, int)) ; ?theta@@YAXP_EAHHH@Z@Z ; FIXME: void theta(int(int,int)^ block) ??2@YAPAXI@Z ; CHECK: void * __cdecl operator new(unsigned int) ??3@YAXPAX@Z ; CHECK: void __cdecl operator delete(void *) ??_U@YAPAXI@Z ; CHECK: void * __cdecl operator new[](unsigned int) ??_V@YAXPAX@Z ; CHECK: void __cdecl operator delete[](void *) ?color1@@3PANA ; CHECK: double *color1 ?color2@@3QBNB ; CHECK: double const *const color2 ; undname prints `double const (* color3)[3]`, but this is a bug in undname. ?color3@@3QAY02$$CBNA ; CHECK: double const (*const color3)[3] ; undname prints `double const (* color4)[3]`, but this is a bug in undname. ?color4@@3QAY02$$CBNA ; CHECK: double const (*const color4)[3] ?memptr1@@3RESB@@HES1@ ; CHECK: int volatile B::*volatile memptr1 ?memptr2@@3PESB@@HES1@ ; CHECK: int volatile B::*memptr2 ?memptr3@@3REQB@@HEQ1@ ; CHECK: int B::*volatile memptr3 ?funmemptr1@@3RESB@@R6AHXZES1@ ; CHECK: int (__cdecl *volatile B::*volatile funmemptr1)(void) ?funmemptr2@@3PESB@@R6AHXZES1@ ; CHECK: int (__cdecl *volatile B::*funmemptr2)(void) ?funmemptr3@@3REQB@@P6AHXZEQ1@ ; CHECK: int (__cdecl *B::*volatile funmemptr3)(void) ?memptrtofun1@@3R8B@@EAAXXZEQ1@ ; CHECK: void (__cdecl B::*volatile memptrtofun1)(void) ?memptrtofun2@@3P8B@@EAAXXZEQ1@ ; CHECK: void (__cdecl B::*memptrtofun2)(void) ?memptrtofun3@@3P8B@@EAAXXZEQ1@ ; CHECK: void (__cdecl B::*memptrtofun3)(void) ?memptrtofun4@@3R8B@@EAAHXZEQ1@ ; CHECK: int (__cdecl B::*volatile memptrtofun4)(void) ?memptrtofun5@@3P8B@@EAA?CHXZEQ1@ ; CHECK: int volatile (__cdecl B::*memptrtofun5)(void) ?memptrtofun6@@3P8B@@EAA?BHXZEQ1@ ; CHECK: int const (__cdecl B::*memptrtofun6)(void) ?memptrtofun7@@3R8B@@EAAP6AHXZXZEQ1@ ; CHECK: int (__cdecl * (__cdecl B::*volatile memptrtofun7)(void))(void) ?memptrtofun8@@3P8B@@EAAR6AHXZXZEQ1@ ; CHECK: int (__cdecl *volatile (__cdecl B::*memptrtofun8)(void))(void) ?memptrtofun9@@3P8B@@EAAQ6AHXZXZEQ1@ ; CHECK: int (__cdecl *const (__cdecl B::*memptrtofun9)(void))(void) ?fooE@@YA?AW4E@@XZ ; CHECK: enum E __cdecl fooE(void) ?fooE@@YA?AW4E@@XZ ; CHECK: enum E __cdecl fooE(void) ?fooX@@YA?AVX@@XZ ; CHECK: class X __cdecl fooX(void) ?fooX@@YA?AVX@@XZ ; CHECK: class X __cdecl fooX(void) ?s0@PR13182@@3PADA ; CHECK: char *PR13182::s0 ?s1@PR13182@@3PADA ; CHECK: char *PR13182::s1 ?s2@PR13182@@3QBDB ; CHECK: char const *const PR13182::s2 ?s3@PR13182@@3QBDB ; CHECK: char const *const PR13182::s3 ?s4@PR13182@@3RCDC ; CHECK: char volatile *volatile PR13182::s4 ?s5@PR13182@@3SDDD ; CHECK: char const volatile *const volatile PR13182::s5 ; undname adds an extra const in here, but it seems like their bug. ?s6@PR13182@@3PBQBDB ; CHECK: char const *const *PR13182::s6 ?local@?1??extern_c_func@@9@4HA ; CHECK: int `extern "C" extern_c_func'::`2'::local ?local@?1??extern_c_func@@9@4HA ; CHECK: int `extern "C" extern_c_func'::`2'::local ?v@?1??f@@YAHXZ@4U@?1??1@YAHXZ@A ; CHECK: struct `int __cdecl f(void)'::`2':: `int __cdecl f(void)'::`2'::v ?v@?1???$f@H@@YAHXZ@4U@?1???$f@H@@YAHXZ@A ; CHECK: struct `int __cdecl f(void)'::`2':: `int __cdecl f(void)'::`2'::v ??2OverloadedNewDelete@@SAPAXI@Z ; CHECK: static void * __cdecl OverloadedNewDelete::operator new(unsigned int) ??_UOverloadedNewDelete@@SAPAXI@Z ; CHECK: static void * __cdecl OverloadedNewDelete::operator new[](unsigned int) ??3OverloadedNewDelete@@SAXPAX@Z ; CHECK: static void __cdecl OverloadedNewDelete::operator delete(void *) ??_VOverloadedNewDelete@@SAXPAX@Z ; CHECK: static void __cdecl OverloadedNewDelete::operator delete[](void *) ??HOverloadedNewDelete@@QAEHH@Z ; CHECK: int __thiscall OverloadedNewDelete::operator+(int) ??2OverloadedNewDelete@@SAPEAX_K@Z ; CHECK: static void * __cdecl OverloadedNewDelete::operator new(unsigned __int64) ??_UOverloadedNewDelete@@SAPEAX_K@Z ; CHECK: static void * __cdecl OverloadedNewDelete::operator new[](unsigned __int64) ??3OverloadedNewDelete@@SAXPEAX@Z ; CHECK: static void __cdecl OverloadedNewDelete::operator delete(void *) ??_VOverloadedNewDelete@@SAXPEAX@Z ; CHECK: static void __cdecl OverloadedNewDelete::operator delete[](void *) ??HOverloadedNewDelete@@QEAAHH@Z ; CHECK: int __cdecl OverloadedNewDelete::operator+(int) ??2TypedefNewDelete@@SAPAXI@Z ; CHECK: static void * __cdecl TypedefNewDelete::operator new(unsigned int) ??_UTypedefNewDelete@@SAPAXI@Z ; CHECK: static void * __cdecl TypedefNewDelete::operator new[](unsigned int) ??3TypedefNewDelete@@SAXPAX@Z ; CHECK: static void __cdecl TypedefNewDelete::operator delete(void *) ??_VTypedefNewDelete@@SAXPAX@Z ; CHECK: static void __cdecl TypedefNewDelete::operator delete[](void *) ?vector_func@@YQXXZ ; CHECK: void __vectorcall vector_func(void) ??$fn_tmpl@$1?extern_c_func@@YAXXZ@@YAXXZ ; CHECK: void __cdecl fn_tmpl<&void __cdecl extern_c_func(void)>(void) ?overloaded_fn@@$$J0YAXXZ ; CHECK: extern "C" void __cdecl overloaded_fn(void) ?f@UnnamedType@@YAXQAPAU@S@1@@Z ; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S:: **const) ?f@UnnamedType@@YAXUT2@S@1@@Z ; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::T2) ?f@UnnamedType@@YAXPAUT4@S@1@@Z ; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::T4 *) ?f@UnnamedType@@YAXUT4@S@1@@Z ; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::T4) ?f@UnnamedType@@YAXUT5@S@1@@Z ; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::T5) ?f@UnnamedType@@YAXUT2@S@1@@Z ; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::T2) ?f@UnnamedType@@YAXUT4@S@1@@Z ; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::T4) ?f@UnnamedType@@YAXUT5@S@1@@Z ; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::T5) ; ?foo@PassObjectSize@@YAHQAHW4__pass_object_size0@__clang@@@Z ; FIXME: int foo(int *const i __attribute__((pass_object_size(0)))); ; ?bar@PassObjectSize@@YAHQAHW4__pass_object_size1@__clang@@@Z ; FIXME: int bar(int *const i __attribute__((pass_object_size(1)))); ; ?qux@PassObjectSize@@YAHQAHW4__pass_object_size1@__clang@@0W4__pass_object_size0@3@@Z ; FIXME: int qux(int *const i __attribute__((pass_object_size(1))), int *const j __attribute__((pass_object_size(0)))); ; ?zot@PassObjectSize@@YAHQAHW4__pass_object_size1@__clang@@01@Z ; FIXME: int zot(int *const i __attribute__((pass_object_size(1))), int *const j __attribute__((pass_object_size(1)))); ?f@Atomic@@YAXU?$_Atomic@H@__clang@@@Z ; CHECK: void __cdecl Atomic::f(struct __clang::_Atomic) ?f@Complex@@YAXU?$_Complex@H@__clang@@@Z ; CHECK: void __cdecl Complex::f(struct __clang::_Complex) ?f@Float16@@YAXU_Float16@__clang@@@Z ; CHECK: void __cdecl Float16::f(struct __clang::_Float16) ??0?$L@H@NS@@QEAA@XZ ; CHECK: __cdecl NS::L::L(void) ??0Bar@Foo@@QEAA@XZ ; CHECK: __cdecl Foo::Bar::Bar(void) ??0?$L@V?$H@PAH@PR26029@@@PR26029@@QAE@XZ ; CHECK: __thiscall PR26029::L>::L>(void) ??$emplace_back@ABH@?$vector@HV?$allocator@H@std@@@std@@QAE?A?@@ABH@Z ; CHECK: __thiscall std::vector>::emplace_back(int const &) ?pub_foo@S@@QAEXXZ ; CHECK: public: void __thiscall S::pub_foo(void) ?pub_stat_foo@S@@SAXXZ ; CHECK: public: static void __cdecl S::pub_stat_foo(void) ?pub_virt_foo@S@@UAEXXZ ; CHECK: public: virtual void __thiscall S::pub_virt_foo(void) ?prot_foo@S@@IAEXXZ ; CHECK: protected: void __thiscall S::prot_foo(void) ?prot_stat_foo@S@@KAXXZ ; CHECK: protected: static void __cdecl S::prot_stat_foo(void) ?prot_virt_foo@S@@MAEXXZ ; CHECK: protected: virtual void __thiscall S::prot_virt_foo(void) ?priv_foo@S@@AAEXXZ ; CHECK: private: void __thiscall S::priv_foo(void) ?priv_stat_foo@S@@CAXXZ ; CHECK: private: static void __cdecl S::priv_stat_foo(void) ?priv_virt_foo@S@@EAEXXZ ; CHECK: private: virtual void __thiscall S::priv_virt_foo(void) msvc-demangler-0.10.1/tests/llvm-cases/unused/ms-md5.test000064400000000000000000000016041046102023000213260ustar 00000000000000; These tests are based on clang/test/CodeGenCXX/mangle-ms-md5.cpp ; RUN: llvm-undname < %s | FileCheck %s ; CHECK-NOT: Invalid mangled name ; MD5-mangled names start with ??@ and we should output them as is. We have ; two check lines here since the tool echos the input. ??@a6a285da2eea70dba6b578022be61d81@ ; CHECK: ??@a6a285da2eea70dba6b578022be61d81@ ; CHECK-NEXT: ??@a6a285da2eea70dba6b578022be61d81@ ; Don't include trailing garbage: ??@a6a285da2eea70dba6b578022be61d81@asdf ; CHECK: ??@a6a285da2eea70dba6b578022be61d81@asdf ; CHECK-NEXT: ??@a6a285da2eea70dba6b578022be61d81@ ; The complete object locator special case: ; FIXME: This should probably print ; ??@a6a285da2eea70dba6b578022be61d81@::`RTTI Complete Object Locator' instead. ??@a6a285da2eea70dba6b578022be61d81@??_R4@ ; CHECK: ??@a6a285da2eea70dba6b578022be61d81@??_R4@ ; CHECK-NEXT: ??@a6a285da2eea70dba6b578022be61d81@??_R4@ msvc-demangler-0.10.1/tests/llvm-cases/unused/ms-nested-scopes.test000064400000000000000000000144451046102023000234240ustar 00000000000000; RUN: llvm-undname < %s | FileCheck %s ; CHECK-NOT: Invalid mangled name ; Test demangling of function local scope discriminator IDs. ?M@?@??L@@YAHXZ@4HA ; CHECK: int `int __cdecl L(void)'::`0'::M ?M@?0??L@@YAHXZ@4HA ; CHECK: int `int __cdecl L(void)'::`1'::M ?M@?1??L@@YAHXZ@4HA ; CHECK: int `int __cdecl L(void)'::`2'::M ?M@?2??L@@YAHXZ@4HA ; CHECK: int `int __cdecl L(void)'::`3'::M ?M@?3??L@@YAHXZ@4HA ; CHECK: int `int __cdecl L(void)'::`4'::M ?M@?4??L@@YAHXZ@4HA ; CHECK: int `int __cdecl L(void)'::`5'::M ?M@?5??L@@YAHXZ@4HA ; CHECK: int `int __cdecl L(void)'::`6'::M ?M@?6??L@@YAHXZ@4HA ; CHECK: int `int __cdecl L(void)'::`7'::M ?M@?7??L@@YAHXZ@4HA ; CHECK: int `int __cdecl L(void)'::`8'::M ?M@?8??L@@YAHXZ@4HA ; CHECK: int `int __cdecl L(void)'::`9'::M ?M@?9??L@@YAHXZ@4HA ; CHECK: int `int __cdecl L(void)'::`10'::M ?M@?L@??L@@YAHXZ@4HA ; CHECK: int `int __cdecl L(void)'::`11'::M ?M@?M@??L@@YAHXZ@4HA ; CHECK: int `int __cdecl L(void)'::`12'::M ?M@?N@??L@@YAHXZ@4HA ; CHECK: int `int __cdecl L(void)'::`13'::M ?M@?O@??L@@YAHXZ@4HA ; CHECK: int `int __cdecl L(void)'::`14'::M ?M@?P@??L@@YAHXZ@4HA ; CHECK: int `int __cdecl L(void)'::`15'::M ?M@?BA@??L@@YAHXZ@4HA ; CHECK: int `int __cdecl L(void)'::`16'::M ?M@?BB@??L@@YAHXZ@4HA ; CHECK: int `int __cdecl L(void)'::`17'::M ?j@?1??L@@YAHXZ@4UJ@@A ; CHECK: struct J `int __cdecl L(void)'::`2'::j ; Test demangling of name back-references ?NN@0XX@@3HA ; CHECK: int XX::NN::NN ?MM@0NN@XX@@3HA ; CHECK: int XX::NN::MM::MM ?NN@MM@0XX@@3HA ; CHECK: int XX::NN::MM::NN ?OO@0NN@01XX@@3HA ; CHECK: int XX::NN::OO::NN::OO::OO ?NN@OO@010XX@@3HA ; CHECK: int XX::NN::OO::NN::OO::NN ; Test demangling of name back-references combined with function local scopes. ?M@?1??0@YAHXZ@4HA ; CHECK: int `int __cdecl M(void)'::`2'::M ?L@?2??M@0?2??0@YAHXZ@QEAAHXZ@4HA ; CHECK: int `public: int __cdecl `int __cdecl L(void)'::`3'::L::M(void)'::`3'::L ?M@?2??0L@?2??1@YAHXZ@QEAAHXZ@4HA ; CHECK: int `public: int __cdecl `int __cdecl L(void)'::`3'::L::M(void)'::`3'::M ; Function local scopes of template functions ?M@?1???$L@H@@YAHXZ@4HA ; CHECK: int `int __cdecl L(void)'::`2'::M ; And member functions of template classes ?SN@?$NS@H@NS@@QEAAHXZ ; CHECK: int __cdecl NS::NS::SN(void) ?NS@?1??SN@?$NS@H@0@QEAAHXZ@4HA ; CHECK: int `public: int __cdecl NS::NS::SN(void)'::`2'::NS ?SN@?1??0?$NS@H@NS@@QEAAHXZ@4HA ; CHECK: int `public: int __cdecl NS::NS::SN(void)'::`2'::SN ?NS@?1??SN@?$NS@H@10@QEAAHXZ@4HA ; CHECK: int `public: int __cdecl NS::SN::NS::SN(void)'::`2'::NS ?SN@?1??0?$NS@H@0NS@@QEAAHXZ@4HA ; CHECK: int `public: int __cdecl NS::SN::NS::SN(void)'::`2'::SN ; Make sure instantiated templates participate in back-referencing. ; In the next 3 examples there should be 3 back-references: ; 0 = X (right most name) ; 1 = C (second from right) ; 2 = C (third from right) ; Make sure all 3 work as expected by having the 4th component take each value ; from 0-2 and confirming it is the right component. ?X@?$C@H@C@0@2HB ; CHECK: static int const X::C::C::X ?X@?$C@H@C@1@2HB ; CHECK: static int const C::C::C::X ?X@?$C@H@C@2@2HB ; CHECK: static int const C::C::C::X ; Putting everything together. ; namespace A { namespace B { namespace C { namespace B { namespace C { ; template ; struct C { ; int B() { ; static C C; ; static int B = 7; ; static int A = 7; ; return C.B() + B + A; ; } ; }; ; } } } } } ?C@?1??B@?$C@H@0101A@@QEAAHXZ@4U201013@A ; CHECK: struct A::B::C::B::C::C `public: int __cdecl A::B::C::B::C::C::B(void)'::`2'::C ?B@?1??0?$C@H@C@020A@@QEAAHXZ@4HA ; CHECK: int `public: int __cdecl A::B::C::B::C::C::B(void)'::`2'::B ?A@?1??B@?$C@H@C@1310@QEAAHXZ@4HA ; CHECK: int `public: int __cdecl A::B::C::B::C::C::B(void)'::`2'::A ?a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@@3HA ; CHECK: int a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a::a msvc-demangler-0.10.1/tests/llvm-cases/unused/ms-return-qualifiers.test000064400000000000000000000072311046102023000243240ustar 00000000000000; These tests are based on clang/test/CodeGenCXX/mangle-ms-return-qualifiers.cpp ; RUN: llvm-undname < %s | FileCheck %s ; CHECK-NOT: Invalid mangled name ?a1@@YAXXZ ; CHECK: void __cdecl a1(void) ?a2@@YAHXZ ; CHECK: int __cdecl a2(void) ?a3@@YA?BHXZ ; CHECK: int const __cdecl a3(void) ?a4@@YA?CHXZ ; CHECK: int volatile __cdecl a4(void) ?a5@@YA?DHXZ ; CHECK: int const volatile __cdecl a5(void) ?a6@@YAMXZ ; CHECK: float __cdecl a6(void) ?b1@@YAPAHXZ ; CHECK: int * __cdecl b1(void) ?b2@@YAPBDXZ ; CHECK: char const * __cdecl b2(void) ?b3@@YAPAMXZ ; CHECK: float * __cdecl b3(void) ?b4@@YAPBMXZ ; CHECK: float const * __cdecl b4(void) ?b5@@YAPCMXZ ; CHECK: float volatile * __cdecl b5(void) ?b6@@YAPDMXZ ; CHECK: float const volatile * __cdecl b6(void) ?b7@@YAAAMXZ ; CHECK: float & __cdecl b7(void) ?b8@@YAABMXZ ; CHECK: float const & __cdecl b8(void) ?b9@@YAACMXZ ; CHECK: float volatile & __cdecl b9(void) ?b10@@YAADMXZ ; CHECK: float const volatile & __cdecl b10(void) ?b11@@YAPAPBDXZ ; CHECK: char const ** __cdecl b11(void) ?c1@@YA?AVA@@XZ ; CHECK: class A __cdecl c1(void) ?c2@@YA?BVA@@XZ ; CHECK: class A const __cdecl c2(void) ?c3@@YA?CVA@@XZ ; CHECK: class A volatile __cdecl c3(void) ?c4@@YA?DVA@@XZ ; CHECK: class A const volatile __cdecl c4(void) ?c5@@YAPBVA@@XZ ; CHECK: class A const * __cdecl c5(void) ?c6@@YAPCVA@@XZ ; CHECK: class A volatile * __cdecl c6(void) ?c7@@YAPDVA@@XZ ; CHECK: class A const volatile * __cdecl c7(void) ?c8@@YAAAVA@@XZ ; CHECK: class A & __cdecl c8(void) ?c9@@YAABVA@@XZ ; CHECK: class A const & __cdecl c9(void) ?c10@@YAACVA@@XZ ; CHECK: class A volatile & __cdecl c10(void) ?c11@@YAADVA@@XZ ; CHECK: class A const volatile & __cdecl c11(void) ?d1@@YA?AV?$B@H@@XZ ; CHECK: class B __cdecl d1(void) ?d2@@YA?AV?$B@PBD@@XZ ; CHECK: class B __cdecl d2(void) ?d3@@YA?AV?$B@VA@@@@XZ ; CHECK: class B __cdecl d3(void) ?d4@@YAPAV?$B@VA@@@@XZ ; CHECK: class B * __cdecl d4(void) ?d5@@YAPBV?$B@VA@@@@XZ ; CHECK: class B const * __cdecl d5(void) ?d6@@YAPCV?$B@VA@@@@XZ ; CHECK: class B volatile * __cdecl d6(void) ?d7@@YAPDV?$B@VA@@@@XZ ; CHECK: class B const volatile * __cdecl d7(void) ?d8@@YAAAV?$B@VA@@@@XZ ; CHECK: class B & __cdecl d8(void) ?d9@@YAABV?$B@VA@@@@XZ ; CHECK: class B const & __cdecl d9(void) ?d10@@YAACV?$B@VA@@@@XZ ; CHECK: class B volatile & __cdecl d10(void) ?d11@@YAADV?$B@VA@@@@XZ ; CHECK: class B const volatile & __cdecl d11(void) ?e1@@YA?AW4Enum@@XZ ; CHECK: Enum __cdecl e1(void) ?e2@@YA?BW4Enum@@XZ ; CHECK: Enum const __cdecl e2(void) ?e3@@YAPAW4Enum@@XZ ; CHECK: Enum * __cdecl e3(void) ?e4@@YAAAW4Enum@@XZ ; CHECK: Enum & __cdecl e4(void) ?f1@@YA?AUS@@XZ ; CHECK: struct S __cdecl f1(void) ?f2@@YA?BUS@@XZ ; CHECK: struct S const __cdecl f2(void) ?f3@@YAPAUS@@XZ ; CHECK: struct S * __cdecl f3(void) ?f4@@YAPBUS@@XZ ; CHECK: struct S const * __cdecl f4(void) ?f5@@YAPDUS@@XZ ; CHECK: struct S const volatile * __cdecl f5(void) ?f6@@YAAAUS@@XZ ; CHECK: struct S & __cdecl f6(void) ?f7@@YAQAUS@@XZ ; CHECK: struct S *const __cdecl f7(void) ?f8@@YAPQS@@HXZ ; CHECK: int S::* __cdecl f8(void) ?f9@@YAQQS@@HXZ ; CHECK: int S::*const __cdecl f9(void) ?f10@@YAPIQS@@HXZ ; CHECK: int S::*__restrict __cdecl f10(void) ?f11@@YAQIQS@@HXZ ; CHECK: int S::*const __restrict __cdecl f11(void) ?g1@@YAP6AHH@ZXZ ; CHECK: int (__cdecl * __cdecl g1(void))(int) ?g2@@YAQ6AHH@ZXZ ; CHECK: int (__cdecl *const __cdecl g2(void))(int) ?g3@@YAPAP6AHH@ZXZ ; CHECK: int (__cdecl ** __cdecl g3(void))(int) ?g4@@YAPBQ6AHH@ZXZ ; CHECK: int (__cdecl *const * __cdecl g4(void))(int) ?h1@@YAAIAHXZ ; CHECK: int &__restrict __cdecl h1(void) msvc-demangler-0.10.1/tests/llvm-cases/unused/ms-string-literals.test000064400000000000000000000441761046102023000237770ustar 00000000000000; RUN: llvm-undname < %s | FileCheck %s ; CHECK-NOT: Invalid mangled name ??_C@_01CNACBAHC@?$PP?$AA@ ??_C@_01DEBJCBDD@?$PO?$AA@ ??_C@_01BPDEHCPA@?$PN?$AA@ ??_C@_01GCPEDLB@?$PM?$AA@ ??_C@_01EJGONFHG@?$PL?$AA@ ??_C@_01FAHFOEDH@?z?$AA@ ??_C@_01HLFILHPE@?y?$AA@ ??_C@_01GCEDIGLF@?x?$AA@ ??_C@_01OFNLJKHK@?w?$AA@ ??_C@_01PMMAKLDL@?v?$AA@ ??_C@_01NHONPIPI@?u?$AA@ ??_C@_01MOPGMJLJ@?t?$AA@ ??_C@_01IBLHFPHO@?s?$AA@ ??_C@_01JIKMGODP@?r?$AA@ ??_C@_01LDIBDNPM@?q?$AA@ ??_C@_01KKJKAMLN@?p?$AA@ ??_C@_01GHMAACCD@?o?$AA@ ??_C@_01HONLDDGC@?n?$AA@ ??_C@_01FFPGGAKB@?m?$AA@ ??_C@_01EMONFBOA@?l?$AA@ ??_C@_01DKMMHCH@?k?$AA@ ??_C@_01BKLHPGGG@?j?$AA@ ??_C@_01DBJKKFKF@?i?$AA@ ??_C@_01CIIBJEOE@?h?$AA@ ??_C@_01KPBJIICL@?g?$AA@ ??_C@_01LGACLJGK@?f?$AA@ ??_C@_01JNCPOKKJ@?e?$AA@ ??_C@_01IEDENLOI@?d?$AA@ ??_C@_01MLHFENCP@?c?$AA@ ??_C@_01NCGOHMGO@?b?$AA@ ??_C@_01PJEDCPKN@?a?$AA@ ??_C@_01OAFIBOOM@?$OA?$AA@ ??_C@_01LIIGDENA@?$NP?$AA@ ??_C@_01KBJNAFJB@?$NO?$AA@ ??_C@_01IKLAFGFC@?$NN?$AA@ ??_C@_01JDKLGHBD@?$NM?$AA@ ??_C@_01NMOKPBNE@?$NL?$AA@ ??_C@_01MFPBMAJF@?Z?$AA@ ??_C@_01OONMJDFG@?Y?$AA@ ??_C@_01PHMHKCBH@?X?$AA@ ??_C@_01HAFPLONI@?W?$AA@ ??_C@_01GJEEIPJJ@?V?$AA@ ??_C@_01ECGJNMFK@?U?$AA@ ??_C@_01FLHCONBL@?T?$AA@ ??_C@_01BEDDHLNM@?S?$AA@ ??_C@_01NCIEKJN@?R?$AA@ ??_C@_01CGAFBJFO@?Q?$AA@ ??_C@_01DPBOCIBP@?P?$AA@ ??_C@_01PCEECGIB@?O?$AA@ ??_C@_01OLFPBHMA@?N?$AA@ ??_C@_01MAHCEEAD@?M?$AA@ ??_C@_01NJGJHFEC@?L?$AA@ ??_C@_01JGCIODIF@?K?$AA@ ??_C@_01IPDDNCME@?J?$AA@ ??_C@_01KEBOIBAH@?I?$AA@ ??_C@_01LNAFLAEG@?H?$AA@ ??_C@_01DKJNKMIJ@?G?$AA@ ??_C@_01CDIGJNMI@?F?$AA@ ??_C@_01IKLMOAL@?E?$AA@ ??_C@_01BBLAPPEK@?D?$AA@ ??_C@_01FOPBGJIN@?C?$AA@ ??_C@_01EHOKFIMM@?B?$AA@ ??_C@_01GMMHALAP@?A?$AA@ ??_C@_01HFNMDKEO@?$MA?$AA@ ??_C@_01NNHLFPHH@?$LP?$AA@ ??_C@_01MEGAGODG@?$LO?$AA@ ??_C@_01OPENDNPF@?$LN?$AA@ ??_C@_01PGFGAMLE@?$LM?$AA@ ??_C@_01LJBHJKHD@?$LL?$AA@ ??_C@_01KAAMKLDC@?$LK?$AA@ ??_C@_01ILCBPIPB@?$LJ?$AA@ ??_C@_01JCDKMJLA@?$LI?$AA@ ??_C@_01BFKCNFHP@?$LH?$AA@ ??_C@_01MLJOEDO@?$LG?$AA@ ??_C@_01CHJELHPN@?$LF?$AA@ ??_C@_01DOIPIGLM@?$LE?$AA@ ??_C@_01HBMOBAHL@?$LD?$AA@ ??_C@_01GINFCBDK@?$LC?$AA@ ??_C@_01EDPIHCPJ@?$LB?$AA@ ??_C@_01FKODEDLI@?$LA?$AA@ ??_C@_01JHLJENCG@?$KP?$AA@ ??_C@_01IOKCHMGH@?$KO?$AA@ ??_C@_01KFIPCPKE@?$KN?$AA@ ??_C@_01LMJEBOOF@?$KM?$AA@ ??_C@_01PDNFIICC@?$KL?$AA@ ??_C@_01OKMOLJGD@?$KK?$AA@ ??_C@_01MBODOKKA@?$KJ?$AA@ ??_C@_01NIPINLOB@?$KI?$AA@ ??_C@_01FPGAMHCO@?$KH?$AA@ ??_C@_01EGHLPGGP@?$KG?$AA@ ??_C@_01GNFGKFKM@?$KF?$AA@ ??_C@_01HEENJEON@?$KE?$AA@ ??_C@_01DLAMACCK@?$KD?$AA@ ??_C@_01CCBHDDGL@?$KC?$AA@ ??_C@_01JDKGAKI@?$KB?$AA@ ??_C@_01BACBFBOJ@?$KA?$AA@ ??_C@_01EIPPHLNF@?$JP?$AA@ ??_C@_01FBOEEKJE@?$JO?$AA@ ??_C@_01HKMJBJFH@?$JN?$AA@ ??_C@_01GDNCCIBG@?$JM?$AA@ ??_C@_01CMJDLONB@?$JL?$AA@ ??_C@_01DFIIIPJA@?$JK?$AA@ ??_C@_01BOKFNMFD@?$JJ?$AA@ ??_C@_01HLOONBC@?$JI?$AA@ ??_C@_01IACGPBNN@?$JH?$AA@ ??_C@_01JJDNMAJM@?$JG?$AA@ ??_C@_01LCBAJDFP@?$JF?$AA@ ??_C@_01KLALKCBO@?$JE?$AA@ ??_C@_01OEEKDENJ@?$JD?$AA@ ??_C@_01PNFBAFJI@?$JC?$AA@ ??_C@_01NGHMFGFL@?$JB?$AA@ ??_C@_01MPGHGHBK@?$JA?$AA@ ??_C@_01CDNGJIE@?$IP?$AA@ ??_C@_01BLCGFIMF@?$IO?$AA@ ??_C@_01DAALALAG@?$IN?$AA@ ??_C@_01CJBADKEH@?$IM?$AA@ ??_C@_01GGFBKMIA@?$IL?$AA@ ??_C@_01HPEKJNMB@?$IK?$AA@ ??_C@_01FEGHMOAC@?$IJ?$AA@ ??_C@_01ENHMPPED@?$II?$AA@ ??_C@_01MKOEODIM@?$IH?$AA@ ??_C@_01NDPPNCMN@?$IG?$AA@ ??_C@_01PINCIBAO@?$IF?$AA@ ??_C@_01OBMJLAEP@?$IE?$AA@ ??_C@_01KOIICGII@?$ID?$AA@ ??_C@_01LHJDBHMJ@?$IC?$AA@ ??_C@_01JMLOEEAK@?$IB?$AA@ ??_C@_01IFKFHFEL@?$IA?$AA@ ??_C@_01BGIBIIDJ@?$HP?$AA@ ??_C@_01PJKLJHI@?$HO?$AA@ ??_C@_01CELHOKLL@?$HN?$AA@ ??_C@_01DNKMNLPK@?$HM?$AA@ ??_C@_01HCONENDN@?$HL?$AA@ ??_C@_01GLPGHMHM@z?$AA@ ??_C@_01EANLCPLP@y?$AA@ ??_C@_01FJMABOPO@x?$AA@ ??_C@_01NOFIACDB@w?$AA@ ??_C@_01MHEDDDHA@v?$AA@ ??_C@_01OMGOGALD@u?$AA@ ??_C@_01PFHFFBPC@t?$AA@ ??_C@_01LKDEMHDF@s?$AA@ ??_C@_01KDCPPGHE@r?$AA@ ??_C@_01IIACKFLH@q?$AA@ ??_C@_01JBBJJEPG@p?$AA@ ??_C@_01FMEDJKGI@o?$AA@ ??_C@_01EFFIKLCJ@n?$AA@ ??_C@_01GOHFPIOK@m?$AA@ ??_C@_01HHGOMJKL@l?$AA@ ??_C@_01DICPFPGM@k?$AA@ ??_C@_01CBDEGOCN@j?$AA@ ??_C@_01KBJDNOO@i?$AA@ ??_C@_01BDACAMKP@h?$AA@ ??_C@_01JEJKBAGA@g?$AA@ ??_C@_01INIBCBCB@f?$AA@ ??_C@_01KGKMHCOC@e?$AA@ ??_C@_01LPLHEDKD@d?$AA@ ??_C@_01PAPGNFGE@c?$AA@ ??_C@_01OJONOECF@b?$AA@ ??_C@_01MCMALHOG@a?$AA@ ??_C@_01NLNLIGKH@?$GA?$AA@ ??_C@_01IDAFKMJL@_?$AA@ ??_C@_01JKBOJNNK@?$FO?$AA@ ??_C@_01LBDDMOBJ@?$FN?$AA@ ??_C@_01KICIPPFI@?2?$AA@ ??_C@_01OHGJGJJP@?$FL?$AA@ ??_C@_01POHCFINO@Z?$AA@ ??_C@_01NFFPALBN@Y?$AA@ ??_C@_01MMEEDKFM@X?$AA@ ??_C@_01ELNMCGJD@W?$AA@ ??_C@_01FCMHBHNC@V?$AA@ ??_C@_01HJOKEEBB@U?$AA@ ??_C@_01GAPBHFFA@T?$AA@ ??_C@_01CPLAODJH@S?$AA@ ??_C@_01DGKLNCNG@R?$AA@ ??_C@_01BNIGIBBF@Q?$AA@ ??_C@_01EJNLAFE@P?$AA@ ??_C@_01MJMHLOMK@O?$AA@ ??_C@_01NANMIPIL@N?$AA@ ??_C@_01PLPBNMEI@M?$AA@ ??_C@_01OCOKONAJ@L?$AA@ ??_C@_01KNKLHLMO@K?$AA@ ??_C@_01LELAEKIP@J?$AA@ ??_C@_01JPJNBJEM@I?$AA@ ??_C@_01IGIGCIAN@H?$AA@ ??_C@_01BBODEMC@G?$AA@ ??_C@_01BIAFAFID@F?$AA@ ??_C@_01DDCIFGEA@E?$AA@ ??_C@_01CKDDGHAB@D?$AA@ ??_C@_01GFHCPBMG@C?$AA@ ??_C@_01HMGJMAIH@B?$AA@ ??_C@_01FHEEJDEE@A?$AA@ ??_C@_01EOFPKCAF@?$EA?$AA@ ??_C@_01OGPIMHDM@?$DP?$AA@ ??_C@_01PPODPGHN@?$DO?$AA@ ??_C@_01NEMOKFLO@?$DN?$AA@ ??_C@_01MNNFJEPP@?$DM?$AA@ ??_C@_01ICJEACDI@?$DL?$AA@ ??_C@_01JLIPDDHJ@?3?$AA@ ??_C@_01LAKCGALK@9?$AA@ ??_C@_01KJLJFBPL@8?$AA@ ??_C@_01COCBENDE@7?$AA@ ??_C@_01DHDKHMHF@6?$AA@ ??_C@_01BMBHCPLG@5?$AA@ ??_C@_01FAMBOPH@4?$AA@ ??_C@_01EKENIIDA@3?$AA@ ??_C@_01FDFGLJHB@2?$AA@ ??_C@_01HIHLOKLC@1?$AA@ ??_C@_01GBGANLPD@0?$AA@ ??_C@_01KMDKNFGN@?1?$AA@ ??_C@_01LFCBOECM@?4?$AA@ ??_C@_01JOAMLHOP@?9?$AA@ ??_C@_01IHBHIGKO@?0?$AA@ ??_C@_01MIFGBAGJ@?$CL?$AA@ ??_C@_01NBENCBCI@?$CK?$AA@ ??_C@_01PKGAHCOL@?$CJ?$AA@ ??_C@_01ODHLEDKK@?$CI?$AA@ ??_C@_01GEODFPGF@?8?$AA@ ??_C@_01HNPIGOCE@?$CG?$AA@ ??_C@_01FGNFDNOH@?$CF?$AA@ ??_C@_01EPMOAMKG@$?$AA@ ??_C@_01IPJKGB@?$CD?$AA@ ??_C@_01BJJEKLCA@?$CC?$AA@ ??_C@_01DCLJPIOD@?$CB?$AA@ ??_C@_01CLKCMJKC@?5?$AA@ ??_C@_01HDHMODJO@?$BP?$AA@ ??_C@_01GKGHNCNP@?$BO?$AA@ ??_C@_01EBEKIBBM@?$BN?$AA@ ??_C@_01FIFBLAFN@?$BM?$AA@ ??_C@_01BHBACGJK@?$BL?$AA@ ??_C@_01OALBHNL@?$BK?$AA@ ??_C@_01CFCGEEBI@?$BJ?$AA@ ??_C@_01DMDNHFFJ@?$BI?$AA@ ??_C@_01LLKFGJJG@?$BH?$AA@ ??_C@_01KCLOFINH@?$BG?$AA@ ??_C@_01IJJDALBE@?$BF?$AA@ ??_C@_01JAIIDKFF@?$BE?$AA@ ??_C@_01NPMJKMJC@?$BD?$AA@ ??_C@_01MGNCJNND@?$BC?$AA@ ??_C@_01ONPPMOBA@?$BB?$AA@ ??_C@_01PEOEPPFB@?$BA?$AA@ ??_C@_01DJLOPBMP@?$AP?$AA@ ??_C@_01CAKFMAIO@?$AO?$AA@ ??_C@_01LIIJDEN@?$AN?$AA@ ??_C@_01BCJDKCAM@?$AM?$AA@ ??_C@_01FNNCDEML@?$AL?$AA@ ??_C@_01EEMJAFIK@?6?$AA@ ??_C@_01GPOEFGEJ@?7?$AA@ ??_C@_01HGPPGHAI@?$AI?$AA@ ??_C@_01PBGHHLMH@?$AH?$AA@ ??_C@_01OIHMEKIG@?$AG?$AA@ ??_C@_01MDFBBJEF@?$AF?$AA@ ??_C@_01NKEKCIAE@?$AE?$AA@ ??_C@_01JFALLOMD@?$AD?$AA@ ??_C@_01IMBAIPIC@?$AC?$AA@ ??_C@_01KHDNNMEB@?$AB?$AA@ ??_C@_01LOCGONAA@?$AA?$AA@ ; CHECK: "\xFF" ; CHECK: "\xFE" ; CHECK: "\xFD" ; CHECK: "\xFC" ; CHECK: "\xFB" ; CHECK: "\xFA" ; CHECK: "\xF9" ; CHECK: "\xF8" ; CHECK: "\xF7" ; CHECK: "\xF6" ; CHECK: "\xF5" ; CHECK: "\xF4" ; CHECK: "\xF3" ; CHECK: "\xF2" ; CHECK: "\xF1" ; CHECK: "\xF0" ; CHECK: "\xEF" ; CHECK: "\xEE" ; CHECK: "\xED" ; CHECK: "\xEC" ; CHECK: "\xEB" ; CHECK: "\xEA" ; CHECK: "\xE9" ; CHECK: "\xE8" ; CHECK: "\xE7" ; CHECK: "\xE6" ; CHECK: "\xE5" ; CHECK: "\xE4" ; CHECK: "\xE3" ; CHECK: "\xE2" ; CHECK: "\xE1" ; CHECK: "\xE0" ; CHECK: "\xDF" ; CHECK: "\xDE" ; CHECK: "\xDD" ; CHECK: "\xDC" ; CHECK: "\xDB" ; CHECK: "\xDA" ; CHECK: "\xD9" ; CHECK: "\xD8" ; CHECK: "\xD7" ; CHECK: "\xD6" ; CHECK: "\xD5" ; CHECK: "\xD4" ; CHECK: "\xD3" ; CHECK: "\xD2" ; CHECK: "\xD1" ; CHECK: "\xD0" ; CHECK: "\xCF" ; CHECK: "\xCE" ; CHECK: "\xCD" ; CHECK: "\xCC" ; CHECK: "\xCB" ; CHECK: "\xCA" ; CHECK: "\xC9" ; CHECK: "\xC8" ; CHECK: "\xC7" ; CHECK: "\xC6" ; CHECK: "\xC5" ; CHECK: "\xC4" ; CHECK: "\xC3" ; CHECK: "\xC2" ; CHECK: "\xC1" ; CHECK: "\xC0" ; CHECK: "\xBF" ; CHECK: "\xBE" ; CHECK: "\xBD" ; CHECK: "\xBC" ; CHECK: "\xBB" ; CHECK: "\xBA" ; CHECK: "\xB9" ; CHECK: "\xB8" ; CHECK: "\xB7" ; CHECK: "\xB6" ; CHECK: "\xB5" ; CHECK: "\xB4" ; CHECK: "\xB3" ; CHECK: "\xB2" ; CHECK: "\xB1" ; CHECK: "\xB0" ; CHECK: "\xAF" ; CHECK: "\xAE" ; CHECK: "\xAD" ; CHECK: "\xAC" ; CHECK: "\xAB" ; CHECK: "\xAA" ; CHECK: "\xA9" ; CHECK: "\xA8" ; CHECK: "\xA7" ; CHECK: "\xA6" ; CHECK: "\xA5" ; CHECK: "\xA4" ; CHECK: "\xA3" ; CHECK: "\xA2" ; CHECK: "\xA1" ; CHECK: "\xA0" ; CHECK: "\x9F" ; CHECK: "\x9E" ; CHECK: "\x9D" ; CHECK: "\x9C" ; CHECK: "\x9B" ; CHECK: "\x9A" ; CHECK: "\x99" ; CHECK: "\x98" ; CHECK: "\x97" ; CHECK: "\x96" ; CHECK: "\x95" ; CHECK: "\x94" ; CHECK: "\x93" ; CHECK: "\x92" ; CHECK: "\x91" ; CHECK: "\x90" ; CHECK: "\x8F" ; CHECK: "\x8E" ; CHECK: "\x8D" ; CHECK: "\x8C" ; CHECK: "\x8B" ; CHECK: "\x8A" ; CHECK: "\x89" ; CHECK: "\x88" ; CHECK: "\x87" ; CHECK: "\x86" ; CHECK: "\x85" ; CHECK: "\x84" ; CHECK: "\x83" ; CHECK: "\x82" ; CHECK: "\x81" ; CHECK: "\x80" ; CHECK: "\x7F" ; CHECK: "~" ; CHECK: "}" ; CHECK: "|" ; CHECK: "{" ; CHECK: "z" ; CHECK: "y" ; CHECK: "x" ; CHECK: "w" ; CHECK: "v" ; CHECK: "u" ; CHECK: "t" ; CHECK: "s" ; CHECK: "r" ; CHECK: "q" ; CHECK: "p" ; CHECK: "o" ; CHECK: "n" ; CHECK: "m" ; CHECK: "l" ; CHECK: "k" ; CHECK: "j" ; CHECK: "i" ; CHECK: "h" ; CHECK: "g" ; CHECK: "f" ; CHECK: "e" ; CHECK: "d" ; CHECK: "c" ; CHECK: "b" ; CHECK: "a" ; CHECK: "`" ; CHECK: "_" ; CHECK: "^" ; CHECK: "]" ; CHECK: "\\" ; CHECK: "[" ; CHECK: "Z" ; CHECK: "Y" ; CHECK: "X" ; CHECK: "W" ; CHECK: "V" ; CHECK: "U" ; CHECK: "T" ; CHECK: "S" ; CHECK: "R" ; CHECK: "Q" ; CHECK: "P" ; CHECK: "O" ; CHECK: "N" ; CHECK: "M" ; CHECK: "L" ; CHECK: "K" ; CHECK: "J" ; CHECK: "I" ; CHECK: "H" ; CHECK: "G" ; CHECK: "F" ; CHECK: "E" ; CHECK: "D" ; CHECK: "C" ; CHECK: "B" ; CHECK: "A" ; CHECK: "@" ; CHECK: "?" ; CHECK: ">" ; CHECK: "=" ; CHECK: "<" ; CHECK: ";" ; CHECK: ":" ; CHECK: "9" ; CHECK: "8" ; CHECK: "7" ; CHECK: "6" ; CHECK: "5" ; CHECK: "4" ; CHECK: "3" ; CHECK: "2" ; CHECK: "1" ; CHECK: "0" ; CHECK: "/" ; CHECK: "." ; CHECK: "-" ; CHECK: "," ; CHECK: "+" ; CHECK: "*" ; CHECK: ")" ; CHECK: "(" ; CHECK: "\'" ; CHECK: "&" ; CHECK: "%" ; CHECK: "$" ; CHECK: "#" ; CHECK: "\"" ; CHECK: "!" ; CHECK: " " ; CHECK: "\x1F" ; CHECK: "\x1E" ; CHECK: "\x1D" ; CHECK: "\x1C" ; CHECK: "\x1B" ; CHECK: "\x1A" ; CHECK: "\x19" ; CHECK: "\x18" ; CHECK: "\x17" ; CHECK: "\x16" ; CHECK: "\x15" ; CHECK: "\x14" ; CHECK: "\x13" ; CHECK: "\x12" ; CHECK: "\x11" ; CHECK: "\x10" ; CHECK: "\x0F" ; CHECK: "\x0E" ; CHECK: "\r" ; CHECK: "\f" ; CHECK: "\v" ; CHECK: "\n" ; CHECK: "\t" ; CHECK: "\b" ; CHECK: "\a" ; CHECK: "\x06" ; CHECK: "\x05" ; CHECK: "\x04" ; CHECK: "\x03" ; CHECK: "\x02" ; CHECK: "\x01" ; The mangling doesn't distinguish between char and char16 types, so even though ; this was originally written as a char[] with one embedded null, it mangles ; identically to a char16_t[] that is empty. So when demangling, we choose the ; "smartest" one, which happened to be wrong, but it's still a "better" ; demangling. ; CHECK: u"" ??_C@_13KDLDGPGJ@?$AA?7?$AA?$AA@ ??_C@_13LBAGMAIH@?$AA?6?$AA?$AA@ ??_C@_13JLKKHOC@?$AA?$AL?$AA?$AA@ ??_C@_13HOIJIPNN@?$AA?5?$AA?$AA@ ??_C@_13MGDFOILI@?$AA?$CB?$AA?$AA@ ??_C@_13NEIAEHFG@?$AA?$CC?$AA?$AA@ ??_C@_13GMDMCADD@?$AA?$CD?$AA?$AA@ ??_C@_13PBOLBIIK@?$AA$?$AA?$AA@ ??_C@_13EJFHHPOP@?$AA?$CF?$AA?$AA@ ??_C@_13FLOCNAAB@?$AA?$CG?$AA?$AA@ ??_C@_13ODFOLHGE@?$AA?8?$AA?$AA@ ??_C@_13LLDNKHDC@?$AA?$CI?$AA?$AA@ ??_C@_13DIBMAFH@?$AA?$CJ?$AA?$AA@ ??_C@_13BBDEGPLJ@?$AA?$CK?$AA?$AA@ ??_C@_13KJIIAINM@?$AA?$CL?$AA?$AA@ ??_C@_13DEFPDAGF@?$AA?0?$AA?$AA@ ??_C@_13IMODFHAA@?$AA?9?$AA?$AA@ ??_C@_13JOFGPIOO@?$AA?4?$AA?$AA@ ??_C@_13CGOKJPIL@?$AA?1?$AA?$AA@ ??_C@_13COJANIEC@?$AA0?$AA?$AA@ ??_C@_13JGCMLPCH@?$AA1?$AA?$AA@ ??_C@_13IEJJBAMJ@?$AA2?$AA?$AA@ ??_C@_13DMCFHHKM@?$AA3?$AA?$AA@ ??_C@_13KBPCEPBF@?$AA4?$AA?$AA@ ??_C@_13BJEOCIHA@?$AA5?$AA?$AA@ ??_C@_13LPLIHJO@?$AA6?$AA?$AA@ ??_C@_13LDEHOAPL@?$AA7?$AA?$AA@ ??_C@_13OLCEPAKN@?$AA8?$AA?$AA@ ??_C@_13FDJIJHMI@?$AA9?$AA?$AA@ ??_C@_13EBCNDICG@?$AA?3?$AA?$AA@ ??_C@_13PJJBFPED@?$AA?$DL?$AA?$AA@ ??_C@_13GEEGGHPK@?$AA?$DM?$AA?$AA@ ??_C@_13NMPKAAJP@?$AA?$DN?$AA?$AA@ ??_C@_13MOEPKPHB@?$AA?$DO?$AA?$AA@ ??_C@_13HGPDMIBE@?$AA?$DP?$AA?$AA@ ??_C@_13EFKPHINO@?$AA?$EA?$AA?$AA@ ??_C@_13PNBDBPLL@?$AAA?$AA?$AA@ ??_C@_13OPKGLAFF@?$AAB?$AA?$AA@ ??_C@_13FHBKNHDA@?$AAC?$AA?$AA@ ??_C@_13MKMNOPIJ@?$AAD?$AA?$AA@ ??_C@_13HCHBIIOM@?$AAE?$AA?$AA@ ??_C@_13GAMECHAC@?$AAF?$AA?$AA@ ??_C@_13NIHIEAGH@?$AAG?$AA?$AA@ ??_C@_13IABLFADB@?$AAH?$AA?$AA@ ??_C@_13DIKHDHFE@?$AAI?$AA?$AA@ ??_C@_13CKBCJILK@?$AAJ?$AA?$AA@ ??_C@_13JCKOPPNP@?$AAK?$AA?$AA@ ??_C@_13PHJMHGG@?$AAL?$AA?$AA@ ??_C@_13LHMFKAAD@?$AAM?$AA?$AA@ ??_C@_13KFHAAPON@?$AAN?$AA?$AA@ ??_C@_13BNMMGIII@?$AAO?$AA?$AA@ ??_C@_13BFLGCPEB@?$AAP?$AA?$AA@ ??_C@_13KNAKEICE@?$AAQ?$AA?$AA@ ??_C@_13LPLPOHMK@?$AAR?$AA?$AA@ ??_C@_13HADIAKP@?$AAS?$AA?$AA@ ??_C@_13JKNELIBG@?$AAT?$AA?$AA@ ??_C@_13CCGINPHD@?$AAU?$AA?$AA@ ??_C@_13DANNHAJN@?$AAV?$AA?$AA@ ??_C@_13IIGBBHPI@?$AAW?$AA?$AA@ ??_C@_13NAACAHKO@?$AAX?$AA?$AA@ ??_C@_13GILOGAML@?$AAY?$AA?$AA@ ??_C@_13HKALMPCF@?$AAZ?$AA?$AA@ ??_C@_13MCLHKIEA@?$AA?$FL?$AA?$AA@ ??_C@_13FPGAJAPJ@?$AA?2?$AA?$AA@ ??_C@_13OHNMPHJM@?$AA?$FN?$AA?$AA@ ??_C@_13PFGJFIHC@?$AA?$FO?$AA?$AA@ ??_C@_13ENNFDPBH@?$AA_?$AA?$AA@ ??_C@_13OFJNNHOA@?$AA?$GA?$AA?$AA@ ??_C@_13FNCBLAIF@?$AAa?$AA?$AA@ ??_C@_13EPJEBPGL@?$AAb?$AA?$AA@ ??_C@_13PHCIHIAO@?$AAc?$AA?$AA@ ??_C@_13GKPPEALH@?$AAd?$AA?$AA@ ??_C@_13NCEDCHNC@?$AAe?$AA?$AA@ ??_C@_13MAPGIIDM@?$AAf?$AA?$AA@ ??_C@_13HIEKOPFJ@?$AAg?$AA?$AA@ ??_C@_13CACJPPAP@?$AAh?$AA?$AA@ ??_C@_13JIJFJIGK@?$AAi?$AA?$AA@ ??_C@_13IKCADHIE@?$AAj?$AA?$AA@ ??_C@_13DCJMFAOB@?$AAk?$AA?$AA@ ??_C@_13KPELGIFI@?$AAl?$AA?$AA@ ??_C@_13BHPHAPDN@?$AAm?$AA?$AA@ ??_C@_13FECKAND@?$AAn?$AA?$AA@ ??_C@_13LNPOMHLG@?$AAo?$AA?$AA@ ??_C@_13LFIEIAHP@?$AAp?$AA?$AA@ ??_C@_13NDIOHBK@?$AAq?$AA?$AA@ ??_C@_13BPINEIPE@?$AAr?$AA?$AA@ ??_C@_13KHDBCPJB@?$AAs?$AA?$AA@ ??_C@_13DKOGBHCI@?$AAt?$AA?$AA@ ??_C@_13ICFKHAEN@?$AAu?$AA?$AA@ ??_C@_13JAOPNPKD@?$AAv?$AA?$AA@ ??_C@_13CIFDLIMG@?$AAw?$AA?$AA@ ??_C@_13HADAKIJA@?$AAx?$AA?$AA@ ??_C@_13MIIMMPPF@?$AAy?$AA?$AA@ ??_C@_13NKDJGABL@?$AAz?$AA?$AA@ ??_C@_13GCIFAHHO@?$AA?$HL?$AA?$AA@ ??_C@_13PPFCDPMH@?$AA?$HM?$AA?$AA@ ??_C@_13EHOOFIKC@?$AA?$HN?$AA?$AA@ ??_C@_13FFFLPHEM@?$AA?$HO?$AA?$AA@ ; CHECK: L"\t" ; CHECK: L"\n" ; CHECK: L"\v" ; CHECK: L" " ; CHECK: L"!" ; CHECK: L"\"" ; CHECK: L"#" ; CHECK: L"$" ; CHECK: L"%" ; CHECK: L"&" ; CHECK: L"\'" ; CHECK: L"(" ; CHECK: L")" ; CHECK: L"*" ; CHECK: L"+" ; CHECK: L"," ; CHECK: L"-" ; CHECK: L"." ; CHECK: L"/" ; CHECK: L"0" ; CHECK: L"1" ; CHECK: L"2" ; CHECK: L"3" ; CHECK: L"4" ; CHECK: L"5" ; CHECK: L"6" ; CHECK: L"7" ; CHECK: L"8" ; CHECK: L"9" ; CHECK: L":" ; CHECK: L";" ; CHECK: L"<" ; CHECK: L"=" ; CHECK: L">" ; CHECK: L"?" ; CHECK: L"@" ; CHECK: L"A" ; CHECK: L"B" ; CHECK: L"C" ; CHECK: L"D" ; CHECK: L"E" ; CHECK: L"F" ; CHECK: L"G" ; CHECK: L"H" ; CHECK: L"I" ; CHECK: L"J" ; CHECK: L"K" ; CHECK: L"L" ; CHECK: L"M" ; CHECK: L"N" ; CHECK: L"O" ; CHECK: L"P" ; CHECK: L"Q" ; CHECK: L"R" ; CHECK: L"S" ; CHECK: L"T" ; CHECK: L"U" ; CHECK: L"V" ; CHECK: L"W" ; CHECK: L"X" ; CHECK: L"Y" ; CHECK: L"Z" ; CHECK: L"[" ; CHECK: L"\\" ; CHECK: L"]" ; CHECK: L"^" ; CHECK: L"_" ; CHECK: L"`" ; CHECK: L"a" ; CHECK: L"b" ; CHECK: L"c" ; CHECK: L"d" ; CHECK: L"e" ; CHECK: L"f" ; CHECK: L"g" ; CHECK: L"h" ; CHECK: L"i" ; CHECK: L"j" ; CHECK: L"k" ; CHECK: L"l" ; CHECK: L"m" ; CHECK: L"n" ; CHECK: L"o" ; CHECK: L"p" ; CHECK: L"q" ; CHECK: L"r" ; CHECK: L"s" ; CHECK: L"t" ; CHECK: L"u" ; CHECK: L"v" ; CHECK: L"w" ; CHECK: L"x" ; CHECK: L"y" ; CHECK: L"z" ; CHECK: L"{" ; CHECK: L"|" ; CHECK: L"}" ; CHECK: L"~" ??_C@_0CF@LABBIIMO@012345678901234567890123456789AB@ ; CHECK: "012345678901234567890123456789AB"... ??_C@_1EK@KFPEBLPK@?$AA0?$AA1?$AA2?$AA3?$AA4?$AA5?$AA6?$AA7?$AA8?$AA9?$AA0?$AA1?$AA2?$AA3?$AA4?$AA5?$AA6?$AA7?$AA8?$AA9?$AA0?$AA1?$AA2?$AA3?$AA4?$AA5?$AA6?$AA7?$AA8?$AA9?$AAA?$AAB@ ; CHECK: L"012345678901234567890123456789AB"... ??_C@_13IIHIAFKH@?W?$PP?$AA?$AA@ ; CHECK: L"\xD7FF" ??_C@_03IIHIAFKH@?$PP?W?$AA?$AA@ ; CHECK: u"\xD7FF" ??_C@_02PCEFGMJL@hi?$AA@ ; CHECK: "hi" ??_C@_05OMLEGLOC@h?$AAi?$AA?$AA?$AA@ ; CHECK: u"hi" ??_C@_0EK@FEAOBHPP@o?$AA1?$AA2?$AA3?$AA4?$AA5?$AA6?$AA7?$AA8?$AA9?$AA0?$AA1?$AA2?$AA3?$AA4?$AA5?$AA@ ; CHECK: u"o123456789012345"... ??_C@_0M@GFNAJIPG@h?$AA?$AA?$AAi?$AA?$AA?$AA?$AA?$AA?$AA?$AA@ ; CHECK: U"hi" ??_C@_0JE@IMHFEDAA@0?$AA?$AA?$AA1?$AA?$AA?$AA2?$AA?$AA?$AA3?$AA?$AA?$AA4?$AA?$AA?$AA5?$AA?$AA?$AA6?$AA?$AA?$AA7?$AA?$AA?$AA@ ; CHECK: U"01234567"... ; These all have just the right length that the trailing 0 just fits. ??_C@_0CA@NMANGEKF@012345678901234567890123456789A?$AA@ ; CHECK: "012345678901234567890123456789A" ??_C@_1EA@LJAFPILO@?$AA0?$AA1?$AA2?$AA3?$AA4?$AA5?$AA6?$AA7?$AA8?$AA9?$AA0?$AA1?$AA2?$AA3?$AA4?$AA5?$AA6?$AA7?$AA8?$AA9?$AA0?$AA1?$AA2?$AA3?$AA4?$AA5?$AA6?$AA7?$AA8?$AA9?$AAA?$AA?$AA@ ; CHECK: L"012345678901234567890123456789A" ??_C@_0CA@NMANGEKF@012345678901234567890123456789A?$AA@ ; CHECK: "012345678901234567890123456789A" ??_C@_0CA@NFEFHIFO@0?$AA1?$AA2?$AA3?$AA4?$AA5?$AA6?$AA7?$AA8?$AA9?$AA0?$AA1?$AA2?$AA3?$AA4?$AA?$AA?$AA@ ; CHECK: u"012345678901234" ??_C@_0CA@KFPHPCC@0?$AA?$AA?$AA1?$AA?$AA?$AA2?$AA?$AA?$AA3?$AA?$AA?$AA4?$AA?$AA?$AA5?$AA?$AA?$AA6?$AA?$AA?$AA?$AA?$AA?$AA?$AA@ ; CHECK: U"0123456" ; There are too many bytes encoded in this string literal (it should encode a max of 32 bytes) ; but some buggy compilers will incorrectly generate this, so we need to be able to demangle ; both the correct and incorrect versions. ??_C@_0CG@HJGBPLNO@l?$AAo?$AAo?$AAk?$AAA?$AAh?$AAe?$AAa?$AAd?$AAH?$AAa?$AAr?$AAd?$AAB?$AAr?$AAe?$AAa?$AAk?$AA?$AA?$AA@ ; CHECK: u"lookAheadHardBreak" ??_C@_0CG@HJGBPLNO@l?$AAo?$AAo?$AAk?$AAA?$AAh?$AAe?$AAa?$AAd?$AAH?$AAa?$AAr?$AAd?$AAB?$AAr?$AAe?$AA@ ; CHECK: u"lookAheadHardBre"... ; These are u16 strings that the diagnostic would classify as u32 -- except ; that their byte length % 4 is 2, so they can't be u32. ??_C@_05LABPAAN@b?$AA?$AA?$AA?$AA?$AA@ ; CHECK: u"b\0" ??_C@_0CC@MBPKDIAM@a?$AA?$AA?$AAb?$AA?$AA?$AAc?$AA?$AA?$AAd?$AA?$AA?$AAe?$AA?$AA?$AAf?$AA?$AA?$AAg?$AA?$AA?$AAh?$AA?$AA?$AA@ ; CHECK: u"a\0b\0c\0d\0e\0f\0g\0h\0"... ; This is technically not a valid u32 string since the character in it is not ; <= 0x10FFFF like unicode demands. (Also, the crc doesn't match the contents.) ; It's here because this input used to cause a stack overflow in outputHex(). ; Both cl.exe and clang-cl produce it for `const char32_t* s = U"\x11223344";` ??_C@_07LJGFEJEB@D3?$CC?$BB?$AA?$AA?$AA?$AA@) ; CHECK: U"\x11223344" ; This has a string length of 0x6_0000_0000, so it's 0 if treated as a 32-bit ; number. (In practice, 24GiB large string literals should be rare.) ??_C@_0GAAAAAAAA@GPLEPFHO@01234567890123456789012345678901@ ; CHECK: "01234567890123456789012345678901"... msvc-demangler-0.10.1/tests/llvm-cases/unused/ms-template-callback.test000064400000000000000000000034331046102023000242100ustar 00000000000000; These tests are based on clang/test/CodeGenCXX/mangle-ms-template-callback.cpp ; RUN: llvm-undname < %s | FileCheck %s ; CHECK-NOT: Invalid mangled name ?callback_void@@3V?$C@$$A6AXXZ@@A ; CHECK: class C callback_void ?callback_void_volatile@@3V?$C@$$A6AXXZ@@C ; CHECK: class C volatile callback_void_volatile ?callback_int@@3V?$C@$$A6AHXZ@@A ; CHECK: C callback_int ?callback_Type@@3V?$C@$$A6A?AVType@@XZ@@A ; CHECK: C callback_Type ?callback_void_int@@3V?$C@$$A6AXH@Z@@A ; CHECK: C callback_void_int ?callback_int_int@@3V?$C@$$A6AHH@Z@@A ; CHECK: C callback_int_int ?callback_void_Type@@3V?$C@$$A6AXVType@@@Z@@A ; CHECK: C callback_void_Type ?foo@@YAXV?$C@$$A6AXXZ@@@Z ; CHECK: void __cdecl foo(class C) ?function@@YAXV?$C@$$A6AXXZ@@@Z ; CHECK: void __cdecl function(class C) ?function_pointer@@YAXV?$C@P6AXXZ@@@Z ; CHECK: void __cdecl function_pointer(class C) ?member_pointer@@YAXV?$C@P8Z@@AEXXZ@@@Z ; CHECK: void __cdecl member_pointer(class C) ??$bar@P6AHH@Z@@YAXP6AHH@Z@Z ; CHECK: void __cdecl bar(int (__cdecl *)(int)) ??$WrapFnPtr@$1?VoidFn@@YAXXZ@@YAXXZ ; CHECK: void __cdecl WrapFnPtr<&void __cdecl VoidFn(void)>(void) ??$WrapFnRef@$1?VoidFn@@YAXXZ@@YAXXZ ; CHECK: void __cdecl WrapFnRef<&void __cdecl VoidFn(void)>(void) ??$WrapFnPtr@$1?VoidStaticMethod@Thing@@SAXXZ@@YAXXZ ; CHECK: void __cdecl WrapFnPtr<&public: static void __cdecl Thing::VoidStaticMethod(void)>(void) ??$WrapFnRef@$1?VoidStaticMethod@Thing@@SAXXZ@@YAXXZ ; CHECK: void __cdecl WrapFnRef<&public: static void __cdecl Thing::VoidStaticMethod(void)>(void) msvc-demangler-0.10.1/tests/llvm-cases/unused/ms-templates-memptrs-2.test000064400000000000000000000014641046102023000244670ustar 00000000000000; RUN: llvm-undname < %s | FileCheck %s ; CHECK-NOT: Invalid mangled name ?m@@3U?$J@UM@@$0A@@@A ; CHECK: struct J m ?m2@@3U?$K@UM@@$0?0@@A ; CHECK: struct K m2 ?n@@3U?$J@UN@@$HA@@@A ; CHECK: struct J n ?n2@@3U?$K@UN@@$0?0@@A ; CHECK: struct K n2 ?o@@3U?$J@UO@@$IA@A@@@A ; CHECK: struct J o ?o2@@3U?$K@UO@@$FA@?0@@A ; CHECK: struct K o2 ?p@@3U?$J@UP@@$JA@A@?0@@A ; CHECK: struct J p ?p2@@3U?$K@UP@@$GA@A@?0@@A ; CHECK: struct K p2 ??0?$ClassTemplate@$J??_9MostGeneral@@$BA@AEA@M@3@@QAE@XZ ; CHECK: __thiscall ClassTemplate<{[thunk]: __thiscall MostGeneral::`vcall'{0, {flat}}, 0, 12, 4}>::ClassTemplate<{[thunk]: __thiscall MostGeneral::`vcall'{0, {flat}}, 0, 12, 4}>(void)msvc-demangler-0.10.1/tests/llvm-cases/unused/ms-templates-memptrs.test000064400000000000000000000070761046102023000243350ustar 00000000000000; RUN: llvm-undname < %s | FileCheck %s ; CHECK-NOT: Invalid mangled name ??$CallMethod@UC@NegativeNVOffset@@$I??_912@$BA@AEPPPPPPPM@A@@@YAXAAUC@NegativeNVOffset@@@Z ; CHECK: void __cdecl CallMethod(struct NegativeNVOffset::C &) ??$CallMethod@UM@@$0A@@@YAXAAUM@@@Z ; CHECK: void __cdecl CallMethod(struct M &) ??$CallMethod@UM@@$H??_91@$BA@AEA@@@YAXAAUM@@@Z ; CHECK: void __cdecl CallMethod(struct M &) ??$CallMethod@UM@@$H?f@1@QAEXXZA@@@YAXAAUM@@@Z ; CHECK: void __cdecl CallMethod(struct M &) ??$CallMethod@UO@@$H??_91@$BA@AE3@@YAXAAUO@@@Z ; CHECK: void __cdecl CallMethod(struct O &) ??$CallMethod@US@@$0A@@@YAXAAUS@@@Z ; CHECK: void __cdecl CallMethod(struct S &) ??$CallMethod@US@@$1??_91@$BA@AE@@YAXAAUS@@@Z ; CHECK: void __cdecl CallMethod(struct S &) ??$CallMethod@US@@$1?f@1@QAEXXZ@@YAXAAUS@@@Z ; CHECK: void __cdecl CallMethod(struct S &) ??$CallMethod@UU@@$0A@@@YAXAAUU@@@Z ; CHECK: void __cdecl CallMethod(struct U &) ??$CallMethod@UU@@$J??_91@$BA@AEA@A@A@@@YAXAAUU@@@Z ; CHECK: void __cdecl CallMethod(struct U &) ??$CallMethod@UU@@$J?f@1@QAEXXZA@A@A@@@YAXAAUU@@@Z ; CHECK: void __cdecl CallMethod(struct U &) ??$CallMethod@UV@@$0A@@@YAXAAUV@@@Z ; CHECK: void __cdecl CallMethod(struct V &) ??$CallMethod@UV@@$I??_91@$BA@AEA@A@@@YAXAAUV@@@Z ; CHECK: void __cdecl CallMethod(struct V &) ??$CallMethod@UV@@$I?f@1@QAEXXZA@A@@@YAXAAUV@@@Z ; CHECK: void __cdecl CallMethod(struct V &) ??$ReadField@UA@@$0?0@@YAHAAUA@@@Z ; CHECK: int __cdecl ReadField(struct A &) ??$ReadField@UA@@$0A@@@YAHAAUA@@@Z ; CHECK: int __cdecl ReadField(struct A &) ??$ReadField@UI@@$03@@YAHAAUI@@@Z ; CHECK: int __cdecl ReadField(struct I &) ??$ReadField@UI@@$0A@@@YAHAAUI@@@Z ; CHECK: int __cdecl ReadField(struct I &) ??$ReadField@UM@@$0A@@@YAHAAUM@@@Z ; CHECK: int __cdecl ReadField(struct M &) ??$ReadField@UM@@$0BA@@@YAHAAUM@@@Z ; CHECK: int __cdecl ReadField(struct M &) ??$ReadField@UM@@$0M@@@YAHAAUM@@@Z ; CHECK: int __cdecl ReadField(struct M &) ??$ReadField@US@@$03@@YAHAAUS@@@Z ; CHECK: int __cdecl ReadField(struct S &) ??$ReadField@US@@$07@@YAHAAUS@@@Z ; CHECK: int __cdecl ReadField(struct S &) ??$ReadField@US@@$0A@@@YAHAAUS@@@Z ; CHECK: int __cdecl ReadField(struct S &) ??$ReadField@UU@@$0A@@@YAHAAUU@@@Z ; CHECK: int __cdecl ReadField(struct U &) ??$ReadField@UU@@$G3A@A@@@YAHAAUU@@@Z ; CHECK: int __cdecl ReadField(struct U &) ??$ReadField@UU@@$G7A@A@@@YAHAAUU@@@Z ; CHECK: int __cdecl ReadField(struct U &) ??$ReadField@UV@@$0A@@@YAHAAUV@@@Z ; CHECK: int __cdecl ReadField(struct V &) ??$ReadField@UV@@$F7A@@@YAHAAUV@@@Z ; CHECK: int __cdecl ReadField(struct V &) ??$ReadField@UV@@$FM@A@@@YAHAAUV@@@Z ; CHECK: int __cdecl ReadField(struct V &) ?Q@@3$$QEAP8Foo@@EAAXXZEA ; CHECK: void (__cdecl Foo::*&&Q)(void) msvc-demangler-0.10.1/tests/llvm-cases/unused/ms-templates.test000064400000000000000000000210131046102023000226330ustar 00000000000000; These tests are based on clang/test/CodeGenCXX/mangle-ms-cxx11.cpp ; RUN: llvm-undname < %s | FileCheck %s ; CHECK-NOT: Invalid mangled name ?f@@3V?$C@H@@A ; CHECK: class C f ??0?$Class@VTypename@@@@QAE@XZ ; CHECK: __thiscall Class::Class(void) ??0?$Class@VTypename@@@@QEAA@XZ ; CHECK: __cdecl Class::Class(void) ??0?$Class@$$CBVTypename@@@@QAE@XZ ; CHECK: __thiscall Class::Class(void) ??0?$Class@$$CBVTypename@@@@QEAA@XZ ; CHECK: __cdecl Class::Class(void) ??0?$Class@$$CCVTypename@@@@QAE@XZ ; CHECK: __thiscall Class::Class(void) ??0?$Class@$$CCVTypename@@@@QEAA@XZ ; CHECK: __cdecl Class::Class(void) ??0?$Class@$$CDVTypename@@@@QAE@XZ ; CHECK: __thiscall Class::Class(void) ??0?$Class@$$CDVTypename@@@@QEAA@XZ ; CHECK: __cdecl Class::Class(void) ??0?$Class@V?$Nested@VTypename@@@@@@QAE@XZ ; CHECK: __thiscall Class>::Class>(void) ??0?$Class@V?$Nested@VTypename@@@@@@QEAA@XZ ; CHECK: __cdecl Class>::Class>(void) ??0?$Class@QAH@@QAE@XZ ; CHECK: __thiscall Class::Class(void) ??0?$Class@QEAH@@QEAA@XZ ; CHECK: __cdecl Class::Class(void) ??0?$Class@$$A6AHXZ@@QAE@XZ ; CHECK: __thiscall Class::Class(void) ??0?$Class@$$A6AHXZ@@QEAA@XZ ; CHECK: __cdecl Class::Class(void) ??0?$Class@$$BY0A@H@@QAE@XZ ; CHECK: __thiscall Class::Class(void) ??0?$Class@$$BY0A@H@@QEAA@XZ ; CHECK: __cdecl Class::Class(void) ??0?$Class@$$BY04H@@QAE@XZ ; CHECK: __thiscall Class::Class(void) ??0?$Class@$$BY04H@@QEAA@XZ ; CHECK: __cdecl Class::Class(void) ??0?$Class@$$BY04$$CBH@@QAE@XZ ; CHECK: __thiscall Class::Class(void) ??0?$Class@$$BY04$$CBH@@QEAA@XZ ; CHECK: __cdecl Class::Class(void) ??0?$Class@$$BY04QAH@@QAE@XZ ; CHECK: __thiscall Class::Class(void) ??0?$Class@$$BY04QEAH@@QEAA@XZ ; CHECK: __cdecl Class::Class(void) ??0?$BoolTemplate@$0A@@@QAE@XZ ; CHECK: __thiscall BoolTemplate<0>::BoolTemplate<0>(void) ??0?$BoolTemplate@$0A@@@QEAA@XZ ; CHECK: __cdecl BoolTemplate<0>::BoolTemplate<0>(void) ??0?$BoolTemplate@$00@@QAE@XZ ; CHECK: __thiscall BoolTemplate<1>::BoolTemplate<1>(void) ??0?$BoolTemplate@$00@@QEAA@XZ ; CHECK: __cdecl BoolTemplate<1>::BoolTemplate<1>(void) ??$Foo@H@?$BoolTemplate@$00@@QAEXH@Z ; CHECK: void __thiscall BoolTemplate<1>::Foo(int) ??$Foo@H@?$BoolTemplate@$00@@QEAAXH@Z ; CHECK: void __cdecl BoolTemplate<1>::Foo(int) ??0?$IntTemplate@$0A@@@QAE@XZ ; CHECK: __thiscall IntTemplate<0>::IntTemplate<0>(void) ??0?$IntTemplate@$0A@@@QEAA@XZ ; CHECK: __cdecl IntTemplate<0>::IntTemplate<0>(void) ??0?$IntTemplate@$04@@QAE@XZ ; CHECK: __thiscall IntTemplate<5>::IntTemplate<5>(void) ??0?$IntTemplate@$04@@QEAA@XZ ; CHECK: __cdecl IntTemplate<5>::IntTemplate<5>(void) ??0?$IntTemplate@$0L@@@QAE@XZ ; CHECK: __thiscall IntTemplate<11>::IntTemplate<11>(void) ??0?$IntTemplate@$0L@@@QEAA@XZ ; CHECK: __cdecl IntTemplate<11>::IntTemplate<11>(void) ??0?$IntTemplate@$0BAA@@@QAE@XZ ; CHECK: __thiscall IntTemplate<256>::IntTemplate<256>(void) ??0?$IntTemplate@$0BAA@@@QEAA@XZ ; CHECK: __cdecl IntTemplate<256>::IntTemplate<256>(void) ??0?$IntTemplate@$0CAB@@@QAE@XZ ; CHECK: __thiscall IntTemplate<513>::IntTemplate<513>(void) ??0?$IntTemplate@$0CAB@@@QEAA@XZ ; CHECK: __cdecl IntTemplate<513>::IntTemplate<513>(void) ??0?$IntTemplate@$0EAC@@@QAE@XZ ; CHECK: __thiscall IntTemplate<1026>::IntTemplate<1026>(void) ??0?$IntTemplate@$0EAC@@@QEAA@XZ ; CHECK: __cdecl IntTemplate<1026>::IntTemplate<1026>(void) ??0?$IntTemplate@$0PPPP@@@QAE@XZ ; CHECK: __thiscall IntTemplate<65535>::IntTemplate<65535>(void) ??0?$IntTemplate@$0PPPP@@@QEAA@XZ ; CHECK: __cdecl IntTemplate<65535>::IntTemplate<65535>(void) ??0?$IntTemplate@$0?0@@QAE@XZ ; CHECK: __thiscall IntTemplate<-1>::IntTemplate<-1>(void) ??0?$IntTemplate@$0?0@@QEAA@XZ ; CHECK: __cdecl IntTemplate<-1>::IntTemplate<-1>(void) ??0?$IntTemplate@$0?8@@QAE@XZ ; CHECK: __thiscall IntTemplate<-9>::IntTemplate<-9>(void) ??0?$IntTemplate@$0?8@@QEAA@XZ ; CHECK: __cdecl IntTemplate<-9>::IntTemplate<-9>(void) ??0?$IntTemplate@$0?9@@QAE@XZ ; CHECK: __thiscall IntTemplate<-10>::IntTemplate<-10>(void) ??0?$IntTemplate@$0?9@@QEAA@XZ ; CHECK: __cdecl IntTemplate<-10>::IntTemplate<-10>(void) ??0?$IntTemplate@$0?L@@@QAE@XZ ; CHECK: __thiscall IntTemplate<-11>::IntTemplate<-11>(void) ??0?$IntTemplate@$0?L@@@QEAA@XZ ; CHECK: __cdecl IntTemplate<-11>::IntTemplate<-11>(void) ??0?$UnsignedIntTemplate@$0PPPPPPPP@@@QAE@XZ ; CHECK: __thiscall UnsignedIntTemplate<4294967295>::UnsignedIntTemplate<4294967295>(void) ??0?$UnsignedIntTemplate@$0PPPPPPPP@@@QEAA@XZ ; CHECK: __cdecl UnsignedIntTemplate<4294967295>::UnsignedIntTemplate<4294967295>(void) ??0?$LongLongTemplate@$0?IAAAAAAAAAAAAAAA@@@QAE@XZ ; CHECK: __thiscall LongLongTemplate<-9223372036854775808>::LongLongTemplate<-9223372036854775808>(void) ??0?$LongLongTemplate@$0?IAAAAAAAAAAAAAAA@@@QEAA@XZ ; CHECK: __cdecl LongLongTemplate<-9223372036854775808>::LongLongTemplate<-9223372036854775808>(void) ??0?$LongLongTemplate@$0HPPPPPPPPPPPPPPP@@@QAE@XZ ; CHECK: __thiscall LongLongTemplate<9223372036854775807>::LongLongTemplate<9223372036854775807>(void) ??0?$LongLongTemplate@$0HPPPPPPPPPPPPPPP@@@QEAA@XZ ; CHECK: __cdecl LongLongTemplate<9223372036854775807>::LongLongTemplate<9223372036854775807>(void) ; -1 is indistinguishable from uint64_max in this encoding. ??0?$UnsignedLongLongTemplate@$0?0@@QAE@XZ ; CHECK: __thiscall UnsignedLongLongTemplate<-1>::UnsignedLongLongTemplate<-1>(void) ??0?$UnsignedLongLongTemplate@$0?0@@QEAA@XZ ; CHECK: __cdecl UnsignedLongLongTemplate<-1>::UnsignedLongLongTemplate<-1>(void) ??$foo@H@space@@YAABHABH@Z ; CHECK: int const & __cdecl space::foo(int const &) ??$foo@H@space@@YAAEBHAEBH@Z ; CHECK: int const & __cdecl space::foo(int const &) ??$FunctionPointerTemplate@$1?spam@@YAXXZ@@YAXXZ ; CHECK: void __cdecl FunctionPointerTemplate<&void __cdecl spam(void)>(void) ??$variadic_fn_template@HHHH@@YAXABH000@Z ; CHECK: void __cdecl variadic_fn_template(int const &, int const &, int const &, int const &) ??$variadic_fn_template@HHD$$BY01D@@YAXABH0ABDAAY01$$CBD@Z ; CHECK: void __cdecl variadic_fn_template(int const &, int const &, char const &, char const (&)[2] ??0?$VariadicClass@HD_N@@QAE@XZ ; CHECK: __thiscall VariadicClass::VariadicClass(void) ??0?$VariadicClass@_NDH@@QAE@XZ ; CHECK: __thiscall VariadicClass::VariadicClass(void) ?template_template_fun@@YAXU?$Type@U?$Thing@USecond@@$00@@USecond@@@@@Z ; CHECK: void __cdecl template_template_fun(struct Type, struct Second>) ??$template_template_specialization@$$A6AXU?$Type@U?$Thing@USecond@@$00@@USecond@@@@@Z@@YAXXZ ; CHECK: void __cdecl template_template_specialization, struct Second>)>(void) ?f@@YAXU?$S1@$0A@@@@Z ; CHECK: void __cdecl f(struct S1<0>) ?recref@@YAXU?$type1@$E?inst@@3Urecord@@B@@@Z ; CHECK: void __cdecl recref(struct type1) ?fun@@YAXU?$UUIDType1@Uuuid@@$1?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@@Z ; CHECK: void __cdecl fun(struct UUIDType1) ?fun@@YAXU?$UUIDType2@Uuuid@@$E?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@@Z ; CHECK: void __cdecl fun(struct UUIDType2) ?FunctionDefinedWithInjectedName@@YAXU?$TypeWithFriendDefinition@H@@@Z ; CHECK: void __cdecl FunctionDefinedWithInjectedName(struct TypeWithFriendDefinition) ?bar@?$UUIDType4@$1?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@QAEXXZ ; CHECK: void __thiscall UUIDType4<&struct __s_GUID const _GUID_12345678_1234_1234_1234_1234567890ab>::bar(void) ??$f@US@@$1?g@1@QEAAXXZ@@YAXXZ ; CHECK: void __cdecl f(void) ??$?0N@?$Foo@H@@QEAA@N@Z ; CHECK: __cdecl Foo::Foo(double) msvc-demangler-0.10.1/tests/llvm-cases/unused/ms-thunks.test000064400000000000000000000007771046102023000221670ustar 00000000000000; RUN: llvm-undname < %s | FileCheck %s ; CHECK-NOT: Invalid mangled name ?f@C@@WBA@EAAHXZ ; CHECK: [thunk]: public: virtual int __cdecl C::f`adjustor{16}'(void) ??_EDerived@@$4PPPPPPPM@A@EAAPEAXI@Z ; CHECK: [thunk]: public: virtual void * __cdecl Derived::`vector deleting dtor'`vtordisp{-4, 0}'(unsigned int) ?f@A@simple@@$R477PPPPPPPM@7AEXXZ ; CHECK: [thunk]: public: virtual void __thiscall simple::A::f`vtordispex{8, 8, -4, 8}'(void) ??_9Base@@$B7AA ; CHECK: [thunk]: __cdecl Base::`vcall'{8, {flat}} msvc-demangler-0.10.1/tests/test_basics.rs000064400000000000000000001156221046102023000166310ustar 00000000000000extern crate msvc_demangler; use msvc_demangler::{demangle, DemangleFlags}; fn expect_with_flags(input: &str, reference: &str, flags: u32) { let demangled = demangle(input, ::DemangleFlags::from_bits(flags).unwrap()); let reference = reference.to_owned(); if let Ok(demangled) = demangled { assert_eq!(demangled, reference); } else { panic!("{:?} != {:?}", demangled, Ok::<_, ()>(reference)); } } // For cases where undname demangles differently/better than we do. fn expect_failure(input: &str, reference: &str) { let demangled = demangle(input, ::DemangleFlags::COMPLETE).unwrap(); let reference = reference.to_owned(); assert_ne!(demangled, reference); } // std::basic_filebuf >::basic_filebuf > // std::basic_filebuf >::"operator ctor" // "operator ctor" = ?0 #[test] fn other_tests() { let expect = |input, reference| { expect_with_flags(input, reference, 0x0); }; expect("?f@@YAHQBH@Z", "int __cdecl f(int const * const)"); expect("?f@@YA_WQB_W@Z", "wchar_t __cdecl f(wchar_t const * const)"); expect( "?f@@YA_UQB_U@Z", "char32_t __cdecl f(char32_t const * const)", ); expect( "?f@@YA_SQB_S@Z", "char16_t __cdecl f(char16_t const * const)", ); expect( "?g@@YAHQAY0EA@$$CBH@Z", "int __cdecl g(int const (* const)[64])", ); expect( "??0Klass@std@@AEAA@AEBV01@@Z", "private: __cdecl std::Klass::Klass(class std::Klass const &)", ); expect("??0?$Klass@V?$Mass@_N@@@std@@QEAA@AEBV01@@Z", "public: __cdecl std::Klass >::Klass >(class std::Klass > const &)"); expect( "??$load@M@UnsharedOps@js@@SAMV?$SharedMem@PAM@@@Z", "public: static float __cdecl js::UnsharedOps::load(class SharedMem)", ); expect("?cached@?1??GetLong@BinaryPath@mozilla@@SA?AW4nsresult@@QA_W@Z@4_NA", "bool `public: static enum nsresult __cdecl mozilla::BinaryPath::GetLong(wchar_t * const)\'::`2\'::cached"); expect( "??0?$A@_K@B@@QAE@$$QAV01@@Z", "public: __thiscall B::A::A(class B::A &&)", ); expect("??_7nsI@@6B@", "const nsI::`vftable\'"); expect("??_7W@?A@@6B@", "const `anonymous namespace'::W::`vftable'"); expect( "??_7?$RunnableMethodImpl@PEAVLazyIdleThread@mozilla@@P812@EAAXXZ$0A@$0A@$$V@detail@mozilla@@6BnsIRunnable@@@", "const mozilla::detail::RunnableMethodImpl::`vftable\'{for `nsIRunnable\'}", ); expect_failure( "??_7?$RunnableMethodImpl@PEAVLazyIdleThread@mozilla@@P812@EAAXXZ$0A@$0A@$$V@detail@mozilla@@6BnsIRunnable@@@", "const mozilla::detail::RunnableMethodImpl::`vftable\'{for `nsIRunnable\'}", ); expect( "??1?$ns@$$CBVtxXP@@@@QAE@XZ", "public: __thiscall ns::~ns(void)", ); /* XXX: undname prints void (__thiscall*)(void *) for the parameter type. */ expect( "??_I@YGXPAXIIP6EX0@Z@Z", "void __stdcall `vector destructor iterator'(void *,unsigned int,unsigned int,void (__thiscall *)(void *))", ); expect( "??_GnsWindowsShellService@@EAEPAXI@Z", "private: virtual void * __thiscall nsWindowsShellService::`scalar deleting destructor'(unsigned int)", ); expect( "??1?$nsAutoPtr@$$CBVtxXPathNode@@@@QAE@XZ", "public: __thiscall nsAutoPtr::~nsAutoPtr(void)", ); expect( "??_EPrintfTarget@mozilla@@MAEPAXI@Z", "protected: virtual void * __thiscall mozilla::PrintfTarget::`vector deleting destructor'(unsigned int)", ); expect( "??_GDynamicFrameEventFilter@?A0xcdaa5fa8@@AAEPAXI@Z", "private: void * __thiscall `anonymous namespace'::DynamicFrameEventFilter::`scalar deleting destructor\'(unsigned int)", ); /* XXX: undname tacks on `adjustor{16}` to the name. */ expect( "?Release@ContentSignatureVerifier@@WBA@AGKXZ", "[thunk]: public: virtual unsigned long __stdcall ContentSignatureVerifier::Release(void)", ); expect( "??$new_@VWatchpointMap@js@@$$V@?$MallocProvider@UZone@JS@@@js@@QAEPAVWatchpointMap@1@XZ", "public: class js::WatchpointMap * __thiscall js::MallocProvider::new_(void)", ); expect( "??$templ_fun_with_ty_pack@$$V@@YAXXZ", "void __cdecl templ_fun_with_ty_pack<>(void)", ); expect( "??4?$RefPtr@VnsRange@@@@QAEAAV0@$$T@Z", "public: class RefPtr & __thiscall RefPtr::operator=(std::nullptr_t)", ); expect( "??1?$function@$$A6AXXZ@std@@QAE@XZ", "public: __thiscall std::function::~function(void)", ); expect_failure( "??1?$function@$$A6AXXZ@std@@QAE@XZ", "public: __thiscall std::function::~function(void)", ); expect( "??B?$function@$$A6AXXZ@std@@QBE_NXZ", "public: bool __thiscall std::function::operator bool(void) const", ); expect_failure( "??B?$function@$$A6AXXZ@std@@QBE_NXZ", "public: __thiscall std::function::operator bool(void) const", ); expect( "??$?RA6AXXZ$$V@SkOnce@@QAEXA6AXXZ@Z", "public: void __thiscall SkOnce::operator()(void (__cdecl &)(void))", ); expect_failure( "??$?RA6AXXZ$$V@SkOnce@@QAEXA6AXXZ@Z", "public: void __thiscall SkOnce::operator()(void (__cdecl&)(void))", ); expect( "?foo@A@PR19361@@QIHAEXXZ", "public: void __thiscall PR19361::A::foo(void) __restrict &&", ); expect_failure( "?foo@A@PR19361@@QIHAEXXZ", "public: void __thiscall PR19361::A::foo(void) __restrict&& ", ); expect( "??$GenericCreateConstructor@$1?construct@SetObject@js@@CA_NPEAUJSContext@@IPEATValue@JS@@@Z$0A@$0A@$0A@@js@@YAPEAVJSObject@@PEAUJSContext@@W4JSProtoKey@@@Z", "class JSObject * __cdecl js::GenericCreateConstructor(struct JSContext *,enum JSProtoKey)", ); expect_failure( "??$GenericCreateConstructor@$1?construct@SetObject@js@@CA_NPEAUJSContext@@IPEATValue@JS@@@Z$0A@$0A@$0A@@js@@YAPEAVJSObject@@PEAUJSContext@@W4JSProtoKey@@@Z", "class JSObject * __ptr64 __cdecl js::GenericCreateConstructor<&private: static bool (__cdecl js::SetObject::construct::*)(struct JSContext * __ptr64,unsigned int,union JS::Value * __ptr64),0,0,0>(struct JSContext * __ptr64,enum JSProtoKey)", ); expect( "??$emplace_hint@AEBUpiecewise_construct_t@std@@V?$tuple@AEBH@2@V?$tuple@$$V@2@@?$_Tree@V?$_Tmap_traits@HUPayload@RtpUtility@webrtc@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUPayload@RtpUtility@webrtc@@@std@@@5@$0A@@std@@@std@@QEAA?AV?$_Tree_iterator@V?$_Tree_val@U?$_Tree_simple_types@U?$pair@$$CBHUPayload@RtpUtility@webrtc@@@std@@@std@@@std@@@1@V?$_Tree_const_iterator@V?$_Tree_val@U?$_Tree_simple_types@U?$pair@$$CBHUPayload@RtpUtility@webrtc@@@std@@@std@@@std@@@1@AEBUpiecewise_construct_t@1@$$QEAV?$tuple@AEBH@1@$$QEAV?$tuple@$$V@1@@Z", "public: class std::_Tree_iterator > > > __cdecl std::_Tree,class std::allocator >,0> >::emplace_hint,class std::tuple<> >(class std::_Tree_const_iterator > > >,struct std::piecewise_construct_t const &,class std::tuple &&,class std::tuple<> &&)", ); expect( "?_OptionsStorage@?1??__local_stdio_scanf_options@@9@9", "`__local_stdio_scanf_options'::`2'::_OptionsStorage", ); expect( "??_9nsDocument@@$BDMI@AE", "[thunk]: __thiscall nsDocument::`vcall'{968,{flat}}", ); expect( "??_R0?AUCollationCacheEntry@icu_61@@@8", "struct icu_61::CollationCacheEntry::`RTTI Type Descriptor\'", ); expect( "??_R0?AV?$KxTree@V?$KxSpe@DI@@I@@@8", "class KxTree,unsigned int>::`RTTI Type Descriptor'", ); expect("??_R2A@@8", "A::`RTTI Base Class Array'"); expect("??_R3UO@i@@8", "i::UO::`RTTI Class Hierarchy Descriptor'"); expect( "??_R1A@?0A@EA@U@i@@8", "i::U::`RTTI Base Class Descriptor at (0,-1,0,64)'", ); expect( "?getFactory@SkImageShader@@UBEP6A?AV?$sk_sp@VSkFlattenable@@@@AAVSkReadBuffer@@@ZXZ", "public: virtual class sk_sp (__cdecl * __thiscall SkImageShader::getFactory(void) const)(class SkReadBuffer &)" ); expect( "?Present1@?QIDXGISwapChain4@@CDXGISwapChain@@UAGJIIPBUDXGI_PRESENT_PARAMETERS@@@Z", "public: virtual long __stdcall CDXGISwapChain::[IDXGISwapChain4]::Present1(unsigned int,unsigned int,struct DXGI_PRESENT_PARAMETERS const *)"); // An MD5 mangled name is "valid" but output as-is expect( "??@8ba8d245c9eca390356129098dbe9f73@", "??@8ba8d245c9eca390356129098dbe9f73@", ); } #[test] fn test_strings() { let expect = |input, reference| { expect_with_flags(input, reference, 0x0); }; // Test symbols extracted from clang's test/CodeGenCXX/mangle-ms-string-literals.cpp. // Even though we don't print the encoded strings, these tests // exhaustively cover all the cases we'll run into. // Single-byte characters. expect("??_C@_01CNACBAHC@?$PP?$AA@", "`string'"); expect("??_C@_01DEBJCBDD@?$PO?$AA@", "`string'"); expect("??_C@_01BPDEHCPA@?$PN?$AA@", "`string'"); expect("??_C@_01GCPEDLB@?$PM?$AA@", "`string'"); expect("??_C@_01EJGONFHG@?$PL?$AA@", "`string'"); expect("??_C@_01FAHFOEDH@?z?$AA@", "`string'"); expect("??_C@_01HLFILHPE@?y?$AA@", "`string'"); expect("??_C@_01GCEDIGLF@?x?$AA@", "`string'"); expect("??_C@_01OFNLJKHK@?w?$AA@", "`string'"); expect("??_C@_01PMMAKLDL@?v?$AA@", "`string'"); expect("??_C@_01NHONPIPI@?u?$AA@", "`string'"); expect("??_C@_01MOPGMJLJ@?t?$AA@", "`string'"); expect("??_C@_01IBLHFPHO@?s?$AA@", "`string'"); expect("??_C@_01JIKMGODP@?r?$AA@", "`string'"); expect("??_C@_01LDIBDNPM@?q?$AA@", "`string'"); expect("??_C@_01KKJKAMLN@?p?$AA@", "`string'"); expect("??_C@_01GHMAACCD@?o?$AA@", "`string'"); expect("??_C@_01HONLDDGC@?n?$AA@", "`string'"); expect("??_C@_01FFPGGAKB@?m?$AA@", "`string'"); expect("??_C@_01EMONFBOA@?l?$AA@", "`string'"); expect("??_C@_01DKMMHCH@?k?$AA@", "`string'"); expect("??_C@_01BKLHPGGG@?j?$AA@", "`string'"); expect("??_C@_01DBJKKFKF@?i?$AA@", "`string'"); expect("??_C@_01CIIBJEOE@?h?$AA@", "`string'"); expect("??_C@_01KPBJIICL@?g?$AA@", "`string'"); expect("??_C@_01LGACLJGK@?f?$AA@", "`string'"); expect("??_C@_01JNCPOKKJ@?e?$AA@", "`string'"); expect("??_C@_01IEDENLOI@?d?$AA@", "`string'"); expect("??_C@_01MLHFENCP@?c?$AA@", "`string'"); expect("??_C@_01NCGOHMGO@?b?$AA@", "`string'"); expect("??_C@_01PJEDCPKN@?a?$AA@", "`string'"); expect("??_C@_01OAFIBOOM@?$OA?$AA@", "`string'"); expect("??_C@_01LIIGDENA@?$NP?$AA@", "`string'"); expect("??_C@_01KBJNAFJB@?$NO?$AA@", "`string'"); expect("??_C@_01IKLAFGFC@?$NN?$AA@", "`string'"); expect("??_C@_01JDKLGHBD@?$NM?$AA@", "`string'"); expect("??_C@_01NMOKPBNE@?$NL?$AA@", "`string'"); expect("??_C@_01MFPBMAJF@?Z?$AA@", "`string'"); expect("??_C@_01OONMJDFG@?Y?$AA@", "`string'"); expect("??_C@_01PHMHKCBH@?X?$AA@", "`string'"); expect("??_C@_01HAFPLONI@?W?$AA@", "`string'"); expect("??_C@_01GJEEIPJJ@?V?$AA@", "`string'"); expect("??_C@_01ECGJNMFK@?U?$AA@", "`string'"); expect("??_C@_01FLHCONBL@?T?$AA@", "`string'"); expect("??_C@_01BEDDHLNM@?S?$AA@", "`string'"); expect("??_C@_01NCIEKJN@?R?$AA@", "`string'"); expect("??_C@_01CGAFBJFO@?Q?$AA@", "`string'"); expect("??_C@_01DPBOCIBP@?P?$AA@", "`string'"); expect("??_C@_01PCEECGIB@?O?$AA@", "`string'"); expect("??_C@_01OLFPBHMA@?N?$AA@", "`string'"); expect("??_C@_01MAHCEEAD@?M?$AA@", "`string'"); expect("??_C@_01NJGJHFEC@?L?$AA@", "`string'"); expect("??_C@_01JGCIODIF@?K?$AA@", "`string'"); expect("??_C@_01IPDDNCME@?J?$AA@", "`string'"); expect("??_C@_01KEBOIBAH@?I?$AA@", "`string'"); expect("??_C@_01LNAFLAEG@?H?$AA@", "`string'"); expect("??_C@_01DKJNKMIJ@?G?$AA@", "`string'"); expect("??_C@_01CDIGJNMI@?F?$AA@", "`string'"); expect("??_C@_01IKLMOAL@?E?$AA@", "`string'"); expect("??_C@_01BBLAPPEK@?D?$AA@", "`string'"); expect("??_C@_01FOPBGJIN@?C?$AA@", "`string'"); expect("??_C@_01EHOKFIMM@?B?$AA@", "`string'"); expect("??_C@_01GMMHALAP@?A?$AA@", "`string'"); expect("??_C@_01HFNMDKEO@?$MA?$AA@", "`string'"); expect("??_C@_01NNHLFPHH@?$LP?$AA@", "`string'"); expect("??_C@_01MEGAGODG@?$LO?$AA@", "`string'"); expect("??_C@_01OPENDNPF@?$LN?$AA@", "`string'"); expect("??_C@_01PGFGAMLE@?$LM?$AA@", "`string'"); expect("??_C@_01LJBHJKHD@?$LL?$AA@", "`string'"); expect("??_C@_01KAAMKLDC@?$LK?$AA@", "`string'"); expect("??_C@_01ILCBPIPB@?$LJ?$AA@", "`string'"); expect("??_C@_01JCDKMJLA@?$LI?$AA@", "`string'"); expect("??_C@_01BFKCNFHP@?$LH?$AA@", "`string'"); expect("??_C@_01MLJOEDO@?$LG?$AA@", "`string'"); expect("??_C@_01CHJELHPN@?$LF?$AA@", "`string'"); expect("??_C@_01DOIPIGLM@?$LE?$AA@", "`string'"); expect("??_C@_01HBMOBAHL@?$LD?$AA@", "`string'"); expect("??_C@_01GINFCBDK@?$LC?$AA@", "`string'"); expect("??_C@_01EDPIHCPJ@?$LB?$AA@", "`string'"); expect("??_C@_01FKODEDLI@?$LA?$AA@", "`string'"); expect("??_C@_01JHLJENCG@?$KP?$AA@", "`string'"); expect("??_C@_01IOKCHMGH@?$KO?$AA@", "`string'"); expect("??_C@_01KFIPCPKE@?$KN?$AA@", "`string'"); expect("??_C@_01LMJEBOOF@?$KM?$AA@", "`string'"); expect("??_C@_01PDNFIICC@?$KL?$AA@", "`string'"); expect("??_C@_01OKMOLJGD@?$KK?$AA@", "`string'"); expect("??_C@_01MBODOKKA@?$KJ?$AA@", "`string'"); expect("??_C@_01NIPINLOB@?$KI?$AA@", "`string'"); expect("??_C@_01FPGAMHCO@?$KH?$AA@", "`string'"); expect("??_C@_01EGHLPGGP@?$KG?$AA@", "`string'"); expect("??_C@_01GNFGKFKM@?$KF?$AA@", "`string'"); expect("??_C@_01HEENJEON@?$KE?$AA@", "`string'"); expect("??_C@_01DLAMACCK@?$KD?$AA@", "`string'"); expect("??_C@_01CCBHDDGL@?$KC?$AA@", "`string'"); expect("??_C@_01JDKGAKI@?$KB?$AA@", "`string'"); expect("??_C@_01BACBFBOJ@?$KA?$AA@", "`string'"); expect("??_C@_01EIPPHLNF@?$JP?$AA@", "`string'"); expect("??_C@_01FBOEEKJE@?$JO?$AA@", "`string'"); expect("??_C@_01HKMJBJFH@?$JN?$AA@", "`string'"); expect("??_C@_01GDNCCIBG@?$JM?$AA@", "`string'"); expect("??_C@_01CMJDLONB@?$JL?$AA@", "`string'"); expect("??_C@_01DFIIIPJA@?$JK?$AA@", "`string'"); expect("??_C@_01BOKFNMFD@?$JJ?$AA@", "`string'"); expect("??_C@_01HLOONBC@?$JI?$AA@", "`string'"); expect("??_C@_01IACGPBNN@?$JH?$AA@", "`string'"); expect("??_C@_01JJDNMAJM@?$JG?$AA@", "`string'"); expect("??_C@_01LCBAJDFP@?$JF?$AA@", "`string'"); expect("??_C@_01KLALKCBO@?$JE?$AA@", "`string'"); expect("??_C@_01OEEKDENJ@?$JD?$AA@", "`string'"); expect("??_C@_01PNFBAFJI@?$JC?$AA@", "`string'"); expect("??_C@_01NGHMFGFL@?$JB?$AA@", "`string'"); expect("??_C@_01MPGHGHBK@?$JA?$AA@", "`string'"); expect("??_C@_01CDNGJIE@?$IP?$AA@", "`string'"); expect("??_C@_01BLCGFIMF@?$IO?$AA@", "`string'"); expect("??_C@_01DAALALAG@?$IN?$AA@", "`string'"); expect("??_C@_01CJBADKEH@?$IM?$AA@", "`string'"); expect("??_C@_01GGFBKMIA@?$IL?$AA@", "`string'"); expect("??_C@_01HPEKJNMB@?$IK?$AA@", "`string'"); expect("??_C@_01FEGHMOAC@?$IJ?$AA@", "`string'"); expect("??_C@_01ENHMPPED@?$II?$AA@", "`string'"); expect("??_C@_01MKOEODIM@?$IH?$AA@", "`string'"); expect("??_C@_01NDPPNCMN@?$IG?$AA@", "`string'"); expect("??_C@_01PINCIBAO@?$IF?$AA@", "`string'"); expect("??_C@_01OBMJLAEP@?$IE?$AA@", "`string'"); expect("??_C@_01KOIICGII@?$ID?$AA@", "`string'"); expect("??_C@_01LHJDBHMJ@?$IC?$AA@", "`string'"); expect("??_C@_01JMLOEEAK@?$IB?$AA@", "`string'"); expect("??_C@_01IFKFHFEL@?$IA?$AA@", "`string'"); expect("??_C@_01BGIBIIDJ@?$HP?$AA@", "`string'"); expect("??_C@_01PJKLJHI@?$HO?$AA@", "`string'"); expect("??_C@_01CELHOKLL@?$HN?$AA@", "`string'"); expect("??_C@_01DNKMNLPK@?$HM?$AA@", "`string'"); expect("??_C@_01HCONENDN@?$HL?$AA@", "`string'"); expect("??_C@_01GLPGHMHM@z?$AA@", "`string'"); expect("??_C@_01EANLCPLP@y?$AA@", "`string'"); expect("??_C@_01FJMABOPO@x?$AA@", "`string'"); expect("??_C@_01NOFIACDB@w?$AA@", "`string'"); expect("??_C@_01MHEDDDHA@v?$AA@", "`string'"); expect("??_C@_01OMGOGALD@u?$AA@", "`string'"); expect("??_C@_01PFHFFBPC@t?$AA@", "`string'"); expect("??_C@_01LKDEMHDF@s?$AA@", "`string'"); expect("??_C@_01KDCPPGHE@r?$AA@", "`string'"); expect("??_C@_01IIACKFLH@q?$AA@", "`string'"); expect("??_C@_01JBBJJEPG@p?$AA@", "`string'"); expect("??_C@_01FMEDJKGI@o?$AA@", "`string'"); expect("??_C@_01EFFIKLCJ@n?$AA@", "`string'"); expect("??_C@_01GOHFPIOK@m?$AA@", "`string'"); expect("??_C@_01HHGOMJKL@l?$AA@", "`string'"); expect("??_C@_01DICPFPGM@k?$AA@", "`string'"); expect("??_C@_01CBDEGOCN@j?$AA@", "`string'"); expect("??_C@_01KBJDNOO@i?$AA@", "`string'"); expect("??_C@_01BDACAMKP@h?$AA@", "`string'"); expect("??_C@_01JEJKBAGA@g?$AA@", "`string'"); expect("??_C@_01INIBCBCB@f?$AA@", "`string'"); expect("??_C@_01KGKMHCOC@e?$AA@", "`string'"); expect("??_C@_01LPLHEDKD@d?$AA@", "`string'"); expect("??_C@_01PAPGNFGE@c?$AA@", "`string'"); expect("??_C@_01OJONOECF@b?$AA@", "`string'"); expect("??_C@_01MCMALHOG@a?$AA@", "`string'"); expect("??_C@_01NLNLIGKH@?$GA?$AA@", "`string'"); expect("??_C@_01IDAFKMJL@_?$AA@", "`string'"); expect("??_C@_01JKBOJNNK@?$FO?$AA@", "`string'"); expect("??_C@_01LBDDMOBJ@?$FN?$AA@", "`string'"); expect("??_C@_01KICIPPFI@?2?$AA@", "`string'"); expect("??_C@_01OHGJGJJP@?$FL?$AA@", "`string'"); expect("??_C@_01POHCFINO@Z?$AA@", "`string'"); expect("??_C@_01NFFPALBN@Y?$AA@", "`string'"); expect("??_C@_01MMEEDKFM@X?$AA@", "`string'"); expect("??_C@_01ELNMCGJD@W?$AA@", "`string'"); expect("??_C@_01FCMHBHNC@V?$AA@", "`string'"); expect("??_C@_01HJOKEEBB@U?$AA@", "`string'"); expect("??_C@_01GAPBHFFA@T?$AA@", "`string'"); expect("??_C@_01CPLAODJH@S?$AA@", "`string'"); expect("??_C@_01DGKLNCNG@R?$AA@", "`string'"); expect("??_C@_01BNIGIBBF@Q?$AA@", "`string'"); expect("??_C@_01EJNLAFE@P?$AA@", "`string'"); expect("??_C@_01MJMHLOMK@O?$AA@", "`string'"); expect("??_C@_01NANMIPIL@N?$AA@", "`string'"); expect("??_C@_01PLPBNMEI@M?$AA@", "`string'"); expect("??_C@_01OCOKONAJ@L?$AA@", "`string'"); expect("??_C@_01KNKLHLMO@K?$AA@", "`string'"); expect("??_C@_01LELAEKIP@J?$AA@", "`string'"); expect("??_C@_01JPJNBJEM@I?$AA@", "`string'"); expect("??_C@_01IGIGCIAN@H?$AA@", "`string'"); expect("??_C@_01BBODEMC@G?$AA@", "`string'"); expect("??_C@_01BIAFAFID@F?$AA@", "`string'"); expect("??_C@_01DDCIFGEA@E?$AA@", "`string'"); expect("??_C@_01CKDDGHAB@D?$AA@", "`string'"); expect("??_C@_01GFHCPBMG@C?$AA@", "`string'"); expect("??_C@_01HMGJMAIH@B?$AA@", "`string'"); expect("??_C@_01FHEEJDEE@A?$AA@", "`string'"); expect("??_C@_01EOFPKCAF@?$EA?$AA@", "`string'"); expect("??_C@_01OGPIMHDM@?$DP?$AA@", "`string'"); expect("??_C@_01PPODPGHN@?$DO?$AA@", "`string'"); expect("??_C@_01NEMOKFLO@?$DN?$AA@", "`string'"); expect("??_C@_01MNNFJEPP@?$DM?$AA@", "`string'"); expect("??_C@_01ICJEACDI@?$DL?$AA@", "`string'"); expect("??_C@_01JLIPDDHJ@?3?$AA@", "`string'"); expect("??_C@_01LAKCGALK@9?$AA@", "`string'"); expect("??_C@_01KJLJFBPL@8?$AA@", "`string'"); expect("??_C@_01COCBENDE@7?$AA@", "`string'"); expect("??_C@_01DHDKHMHF@6?$AA@", "`string'"); expect("??_C@_01BMBHCPLG@5?$AA@", "`string'"); expect("??_C@_01FAMBOPH@4?$AA@", "`string'"); expect("??_C@_01EKENIIDA@3?$AA@", "`string'"); expect("??_C@_01FDFGLJHB@2?$AA@", "`string'"); expect("??_C@_01HIHLOKLC@1?$AA@", "`string'"); expect("??_C@_01GBGANLPD@0?$AA@", "`string'"); expect("??_C@_01KMDKNFGN@?1?$AA@", "`string'"); expect("??_C@_01LFCBOECM@?4?$AA@", "`string'"); expect("??_C@_01JOAMLHOP@?9?$AA@", "`string'"); expect("??_C@_01IHBHIGKO@?0?$AA@", "`string'"); expect("??_C@_01MIFGBAGJ@?$CL?$AA@", "`string'"); expect("??_C@_01NBENCBCI@?$CK?$AA@", "`string'"); expect("??_C@_01PKGAHCOL@?$CJ?$AA@", "`string'"); expect("??_C@_01ODHLEDKK@?$CI?$AA@", "`string'"); expect("??_C@_01GEODFPGF@?8?$AA@", "`string'"); expect("??_C@_01HNPIGOCE@?$CG?$AA@", "`string'"); expect("??_C@_01FGNFDNOH@?$CF?$AA@", "`string'"); expect("??_C@_01EPMOAMKG@$?$AA@", "`string'"); expect("??_C@_01IPJKGB@?$CD?$AA@", "`string'"); expect("??_C@_01BJJEKLCA@?$CC?$AA@", "`string'"); expect("??_C@_01DCLJPIOD@?$CB?$AA@", "`string'"); expect("??_C@_01CLKCMJKC@?5?$AA@", "`string'"); expect("??_C@_01HDHMODJO@?$BP?$AA@", "`string'"); expect("??_C@_01GKGHNCNP@?$BO?$AA@", "`string'"); expect("??_C@_01EBEKIBBM@?$BN?$AA@", "`string'"); expect("??_C@_01FIFBLAFN@?$BM?$AA@", "`string'"); expect("??_C@_01BHBACGJK@?$BL?$AA@", "`string'"); expect("??_C@_01OALBHNL@?$BK?$AA@", "`string'"); expect("??_C@_01CFCGEEBI@?$BJ?$AA@", "`string'"); expect("??_C@_01DMDNHFFJ@?$BI?$AA@", "`string'"); expect("??_C@_01LLKFGJJG@?$BH?$AA@", "`string'"); expect("??_C@_01KCLOFINH@?$BG?$AA@", "`string'"); expect("??_C@_01IJJDALBE@?$BF?$AA@", "`string'"); expect("??_C@_01JAIIDKFF@?$BE?$AA@", "`string'"); expect("??_C@_01NPMJKMJC@?$BD?$AA@", "`string'"); expect("??_C@_01MGNCJNND@?$BC?$AA@", "`string'"); expect("??_C@_01ONPPMOBA@?$BB?$AA@", "`string'"); expect("??_C@_01PEOEPPFB@?$BA?$AA@", "`string'"); expect("??_C@_01DJLOPBMP@?$AP?$AA@", "`string'"); expect("??_C@_01CAKFMAIO@?$AO?$AA@", "`string'"); expect("??_C@_01LIIJDEN@?$AN?$AA@", "`string'"); expect("??_C@_01BCJDKCAM@?$AM?$AA@", "`string'"); expect("??_C@_01FNNCDEML@?$AL?$AA@", "`string'"); expect("??_C@_01EEMJAFIK@?6?$AA@", "`string'"); expect("??_C@_01GPOEFGEJ@?7?$AA@", "`string'"); expect("??_C@_01HGPPGHAI@?$AI?$AA@", "`string'"); expect("??_C@_01PBGHHLMH@?$AH?$AA@", "`string'"); expect("??_C@_01OIHMEKIG@?$AG?$AA@", "`string'"); expect("??_C@_01MDFBBJEF@?$AF?$AA@", "`string'"); expect("??_C@_01NKEKCIAE@?$AE?$AA@", "`string'"); expect("??_C@_01JFALLOMD@?$AD?$AA@", "`string'"); expect("??_C@_01IMBAIPIC@?$AC?$AA@", "`string'"); expect("??_C@_01KHDNNMEB@?$AB?$AA@", "`string'"); expect("??_C@_01LOCGONAA@?$AA?$AA@", "`string'"); // Wide characters. expect("??_C@_13KDLDGPGJ@?$AA?7?$AA?$AA@", "`string'"); expect("??_C@_13LBAGMAIH@?$AA?6?$AA?$AA@", "`string'"); expect("??_C@_13JLKKHOC@?$AA?$AL?$AA?$AA@", "`string'"); expect("??_C@_13HOIJIPNN@?$AA?5?$AA?$AA@", "`string'"); expect("??_C@_13MGDFOILI@?$AA?$CB?$AA?$AA@", "`string'"); expect("??_C@_13NEIAEHFG@?$AA?$CC?$AA?$AA@", "`string'"); expect("??_C@_13GMDMCADD@?$AA?$CD?$AA?$AA@", "`string'"); expect("??_C@_13PBOLBIIK@?$AA$?$AA?$AA@", "`string'"); expect("??_C@_13EJFHHPOP@?$AA?$CF?$AA?$AA@", "`string'"); expect("??_C@_13FLOCNAAB@?$AA?$CG?$AA?$AA@", "`string'"); expect("??_C@_13ODFOLHGE@?$AA?8?$AA?$AA@", "`string'"); expect("??_C@_13LLDNKHDC@?$AA?$CI?$AA?$AA@", "`string'"); expect("??_C@_13DIBMAFH@?$AA?$CJ?$AA?$AA@", "`string'"); expect("??_C@_13BBDEGPLJ@?$AA?$CK?$AA?$AA@", "`string'"); expect("??_C@_13KJIIAINM@?$AA?$CL?$AA?$AA@", "`string'"); expect("??_C@_13DEFPDAGF@?$AA?0?$AA?$AA@", "`string'"); expect("??_C@_13IMODFHAA@?$AA?9?$AA?$AA@", "`string'"); expect("??_C@_13JOFGPIOO@?$AA?4?$AA?$AA@", "`string'"); expect("??_C@_13CGOKJPIL@?$AA?1?$AA?$AA@", "`string'"); expect("??_C@_13COJANIEC@?$AA0?$AA?$AA@", "`string'"); expect("??_C@_13JGCMLPCH@?$AA1?$AA?$AA@", "`string'"); expect("??_C@_13IEJJBAMJ@?$AA2?$AA?$AA@", "`string'"); expect("??_C@_13DMCFHHKM@?$AA3?$AA?$AA@", "`string'"); expect("??_C@_13KBPCEPBF@?$AA4?$AA?$AA@", "`string'"); expect("??_C@_13BJEOCIHA@?$AA5?$AA?$AA@", "`string'"); expect("??_C@_13LPLIHJO@?$AA6?$AA?$AA@", "`string'"); expect("??_C@_13LDEHOAPL@?$AA7?$AA?$AA@", "`string'"); expect("??_C@_13OLCEPAKN@?$AA8?$AA?$AA@", "`string'"); expect("??_C@_13FDJIJHMI@?$AA9?$AA?$AA@", "`string'"); expect("??_C@_13EBCNDICG@?$AA?3?$AA?$AA@", "`string'"); expect("??_C@_13PJJBFPED@?$AA?$DL?$AA?$AA@", "`string'"); expect("??_C@_13GEEGGHPK@?$AA?$DM?$AA?$AA@", "`string'"); expect("??_C@_13NMPKAAJP@?$AA?$DN?$AA?$AA@", "`string'"); expect("??_C@_13MOEPKPHB@?$AA?$DO?$AA?$AA@", "`string'"); expect("??_C@_13HGPDMIBE@?$AA?$DP?$AA?$AA@", "`string'"); expect("??_C@_13EFKPHINO@?$AA?$EA?$AA?$AA@", "`string'"); expect("??_C@_13PNBDBPLL@?$AAA?$AA?$AA@", "`string'"); expect("??_C@_13OPKGLAFF@?$AAB?$AA?$AA@", "`string'"); expect("??_C@_13FHBKNHDA@?$AAC?$AA?$AA@", "`string'"); expect("??_C@_13MKMNOPIJ@?$AAD?$AA?$AA@", "`string'"); expect("??_C@_13HCHBIIOM@?$AAE?$AA?$AA@", "`string'"); expect("??_C@_13GAMECHAC@?$AAF?$AA?$AA@", "`string'"); expect("??_C@_13NIHIEAGH@?$AAG?$AA?$AA@", "`string'"); expect("??_C@_13IABLFADB@?$AAH?$AA?$AA@", "`string'"); expect("??_C@_13DIKHDHFE@?$AAI?$AA?$AA@", "`string'"); expect("??_C@_13CKBCJILK@?$AAJ?$AA?$AA@", "`string'"); expect("??_C@_13JCKOPPNP@?$AAK?$AA?$AA@", "`string'"); expect("??_C@_13PHJMHGG@?$AAL?$AA?$AA@", "`string'"); expect("??_C@_13LHMFKAAD@?$AAM?$AA?$AA@", "`string'"); expect("??_C@_13KFHAAPON@?$AAN?$AA?$AA@", "`string'"); expect("??_C@_13BNMMGIII@?$AAO?$AA?$AA@", "`string'"); expect("??_C@_13BFLGCPEB@?$AAP?$AA?$AA@", "`string'"); expect("??_C@_13KNAKEICE@?$AAQ?$AA?$AA@", "`string'"); expect("??_C@_13LPLPOHMK@?$AAR?$AA?$AA@", "`string'"); expect("??_C@_13HADIAKP@?$AAS?$AA?$AA@", "`string'"); expect("??_C@_13JKNELIBG@?$AAT?$AA?$AA@", "`string'"); expect("??_C@_13CCGINPHD@?$AAU?$AA?$AA@", "`string'"); expect("??_C@_13DANNHAJN@?$AAV?$AA?$AA@", "`string'"); expect("??_C@_13IIGBBHPI@?$AAW?$AA?$AA@", "`string'"); expect("??_C@_13NAACAHKO@?$AAX?$AA?$AA@", "`string'"); expect("??_C@_13GILOGAML@?$AAY?$AA?$AA@", "`string'"); expect("??_C@_13HKALMPCF@?$AAZ?$AA?$AA@", "`string'"); expect("??_C@_13MCLHKIEA@?$AA?$FL?$AA?$AA@", "`string'"); expect("??_C@_13FPGAJAPJ@?$AA?2?$AA?$AA@", "`string'"); expect("??_C@_13OHNMPHJM@?$AA?$FN?$AA?$AA@", "`string'"); expect("??_C@_13PFGJFIHC@?$AA?$FO?$AA?$AA@", "`string'"); expect("??_C@_13ENNFDPBH@?$AA_?$AA?$AA@", "`string'"); expect("??_C@_13OFJNNHOA@?$AA?$GA?$AA?$AA@", "`string'"); expect("??_C@_13FNCBLAIF@?$AAa?$AA?$AA@", "`string'"); expect("??_C@_13EPJEBPGL@?$AAb?$AA?$AA@", "`string'"); expect("??_C@_13PHCIHIAO@?$AAc?$AA?$AA@", "`string'"); expect("??_C@_13GKPPEALH@?$AAd?$AA?$AA@", "`string'"); expect("??_C@_13NCEDCHNC@?$AAe?$AA?$AA@", "`string'"); expect("??_C@_13MAPGIIDM@?$AAf?$AA?$AA@", "`string'"); expect("??_C@_13HIEKOPFJ@?$AAg?$AA?$AA@", "`string'"); expect("??_C@_13CACJPPAP@?$AAh?$AA?$AA@", "`string'"); expect("??_C@_13JIJFJIGK@?$AAi?$AA?$AA@", "`string'"); expect("??_C@_13IKCADHIE@?$AAj?$AA?$AA@", "`string'"); expect("??_C@_13DCJMFAOB@?$AAk?$AA?$AA@", "`string'"); expect("??_C@_13KPELGIFI@?$AAl?$AA?$AA@", "`string'"); expect("??_C@_13BHPHAPDN@?$AAm?$AA?$AA@", "`string'"); expect("??_C@_13FECKAND@?$AAn?$AA?$AA@", "`string'"); expect("??_C@_13LNPOMHLG@?$AAo?$AA?$AA@", "`string'"); expect("??_C@_13LFIEIAHP@?$AAp?$AA?$AA@", "`string'"); expect("??_C@_13NDIOHBK@?$AAq?$AA?$AA@", "`string'"); expect("??_C@_13BPINEIPE@?$AAr?$AA?$AA@", "`string'"); expect("??_C@_13KHDBCPJB@?$AAs?$AA?$AA@", "`string'"); expect("??_C@_13DKOGBHCI@?$AAt?$AA?$AA@", "`string'"); expect("??_C@_13ICFKHAEN@?$AAu?$AA?$AA@", "`string'"); expect("??_C@_13JAOPNPKD@?$AAv?$AA?$AA@", "`string'"); expect("??_C@_13CIFDLIMG@?$AAw?$AA?$AA@", "`string'"); expect("??_C@_13HADAKIJA@?$AAx?$AA?$AA@", "`string'"); expect("??_C@_13MIIMMPPF@?$AAy?$AA?$AA@", "`string'"); expect("??_C@_13NKDJGABL@?$AAz?$AA?$AA@", "`string'"); expect("??_C@_13GCIFAHHO@?$AA?$HL?$AA?$AA@", "`string'"); expect("??_C@_13PPFCDPMH@?$AA?$HM?$AA?$AA@", "`string'"); expect("??_C@_13EHOOFIKC@?$AA?$HN?$AA?$AA@", "`string'"); expect("??_C@_13FFFLPHEM@?$AA?$HO?$AA?$AA@", "`string'"); // Tests for maximum string length expect( "??_C@_0CF@LABBIIMO@012345678901234567890123456789AB@", "`string'", ); expect("??_C@_1EK@KFPEBLPK@?$AA0?$AA1?$AA2?$AA3?$AA4?$AA5?$AA6?$AA7?$AA8?$AA9?$AA0?$AA1?$AA2?$AA3?$AA4?$AA5?$AA6?$AA7?$AA8?$AA9?$AA0?$AA1?$AA2?$AA3?$AA4?$AA5?$AA6?$AA7?$AA8?$AA9?$AAA?$AAB@", "`string'"); // Unicode character. expect("??_C@_13IIHIAFKH@?W?$PP?$AA?$AA@", "`string'"); // u8/u/U literal strings. expect("??_C@_02PCEFGMJL@hi?$AA@", "`string'"); expect("??_C@_05OMLEGLOC@h?$AAi?$AA?$AA?$AA@", "`string'"); expect( "??_C@_0M@GFNAJIPG@h?$AA?$AA?$AAi?$AA?$AA?$AA?$AA?$AA?$AA?$AA@", "`string'", ); } #[test] fn upstream_tests() { let expect = |input, reference| { expect_with_flags(input, reference, 0x0); }; expect("?x@@3HA", "int x"); expect("?x@@3PEAHEA", "int *x"); expect("?x@@3PEAPEAHEA", "int * *x"); expect("?x@@3PEAY02HEA", "int (*x)[3]"); expect("?x@@3PEAY124HEA", "int (*x)[3][5]"); expect("?x@@3PEAY02$$CBHEA", "int const (*x)[3]"); expect("?x@@3PEAEEA", "unsigned char *x"); expect("?x@@3PEAY1NKM@5HEA", "int (*x)[3500][6]"); expect("?x@@YAXMH@Z", "void __cdecl x(float,int)"); expect("?x@@YAXMH@Z", "void __cdecl x(float,int)"); expect("?x@@3P6AHMNH@ZEA", "int (__cdecl *x)(float,double,int)"); expect( "?x@@3P6AHP6AHM@ZN@ZEA", "int (__cdecl *x)(int (__cdecl *)(float),double)", ); expect( "?x@@3P6AHP6AHM@Z0@ZEA", "int (__cdecl *x)(int (__cdecl *)(float),int (__cdecl *)(float))", ); expect("?x@ns@@3HA", "int ns::x"); // Microsoft's undname returns "int const * const x" for this symbol. // I believe it's their bug. expect("?x@@3PEBHEB", "int const *x"); expect("?x@@3QEAHEB", "int * const x"); expect("?x@@3QEBHEB", "int const * const x"); expect("?x@@3AEBHEB", "int const & x"); expect("?x@@3PEAUty@@EA", "struct ty *x"); expect("?x@@3PEATty@@EA", "union ty *x"); expect("?x@@3PEAUty@@EA", "struct ty *x"); expect("?x@@3PEAW4ty@@EA", "enum ty *x"); expect("?x@@3PEAVty@@EA", "class ty *x"); expect("?x@@3PEAV?$tmpl@H@@EA", "class tmpl *x"); expect("?x@@3PEAU?$tmpl@H@@EA", "struct tmpl *x"); expect("?x@@3PEAT?$tmpl@H@@EA", "union tmpl *x"); expect("?instance@@3Vklass@@A", "class klass instance"); expect( "?instance$initializer$@@3P6AXXZEA", "void (__cdecl *instance$initializer$)(void)", ); expect("??0klass@@QEAA@XZ", "public: __cdecl klass::klass(void)"); expect("??1klass@@QEAA@XZ", "public: __cdecl klass::~klass(void)"); expect( "?x@@YAHPEAVklass@@AEAV1@@Z", "int __cdecl x(class klass *,class klass &)", ); expect( "?x@ns@@3PEAV?$klass@HH@1@EA", "class ns::klass *ns::x", ); expect( "?fn@?$klass@H@ns@@QEBAIXZ", "public: unsigned int __cdecl ns::klass::fn(void) const", ); expect( "??4klass@@QEAAAEBV0@AEBV0@@Z", "public: class klass const & __cdecl klass::operator=(class klass const &)", ); expect( "??7klass@@QEAA_NXZ", "public: bool __cdecl klass::operator!(void)", ); expect( "??8klass@@QEAA_NAEBV0@@Z", "public: bool __cdecl klass::operator==(class klass const &)", ); expect( "??9klass@@QEAA_NAEBV0@@Z", "public: bool __cdecl klass::operator!=(class klass const &)", ); expect( "??Aklass@@QEAAH_K@Z", "public: int __cdecl klass::operator[](uint64_t)", ); expect( "??Cklass@@QEAAHXZ", "public: int __cdecl klass::operator->(void)", ); expect( "??Dklass@@QEAAHXZ", "public: int __cdecl klass::operator*(void)", ); expect( "??Eklass@@QEAAHXZ", "public: int __cdecl klass::operator++(void)", ); expect( "??Eklass@@QEAAHH@Z", "public: int __cdecl klass::operator++(int)", ); expect( "??Fklass@@QEAAHXZ", "public: int __cdecl klass::operator--(void)", ); expect( "??Fklass@@QEAAHH@Z", "public: int __cdecl klass::operator--(int)", ); expect( "??Hklass@@QEAAHH@Z", "public: int __cdecl klass::operator+(int)", ); expect( "??Gklass@@QEAAHH@Z", "public: int __cdecl klass::operator-(int)", ); expect( "??Iklass@@QEAAHH@Z", "public: int __cdecl klass::operator&(int)", ); expect( "??Jklass@@QEAAHH@Z", "public: int __cdecl klass::operator->*(int)", ); expect( "??Kklass@@QEAAHH@Z", "public: int __cdecl klass::operator/(int)", ); expect( "??Mklass@@QEAAHH@Z", "public: int __cdecl klass::operator<(int)", ); expect( "??Nklass@@QEAAHH@Z", "public: int __cdecl klass::operator<=(int)", ); expect( "??Oklass@@QEAAHH@Z", "public: int __cdecl klass::operator>(int)", ); expect( "??Pklass@@QEAAHH@Z", "public: int __cdecl klass::operator>=(int)", ); expect( "??Qklass@@QEAAHH@Z", "public: int __cdecl klass::operator,(int)", ); expect( "??Rklass@@QEAAHH@Z", "public: int __cdecl klass::operator()(int)", ); expect( "??Sklass@@QEAAHXZ", "public: int __cdecl klass::operator~(void)", ); expect( "??Tklass@@QEAAHH@Z", "public: int __cdecl klass::operator^(int)", ); expect( "??Uklass@@QEAAHH@Z", "public: int __cdecl klass::operator|(int)", ); expect( "??Vklass@@QEAAHH@Z", "public: int __cdecl klass::operator&&(int)", ); expect( "??Wklass@@QEAAHH@Z", "public: int __cdecl klass::operator||(int)", ); expect( "??Xklass@@QEAAHH@Z", "public: int __cdecl klass::operator*=(int)", ); expect( "??Yklass@@QEAAHH@Z", "public: int __cdecl klass::operator+=(int)", ); expect( "??Zklass@@QEAAHH@Z", "public: int __cdecl klass::operator-=(int)", ); expect( "??_0klass@@QEAAHH@Z", "public: int __cdecl klass::operator/=(int)", ); expect( "??_1klass@@QEAAHH@Z", "public: int __cdecl klass::operator%=(int)", ); expect( "??_2klass@@QEAAHH@Z", "public: int __cdecl klass::operator>>=(int)", ); expect( "??_3klass@@QEAAHH@Z", "public: int __cdecl klass::operator<<=(int)", ); expect( "??_6klass@@QEAAHH@Z", "public: int __cdecl klass::operator^=(int)", ); expect( "??6@YAAEBVklass@@AEBV0@H@Z", "class klass const & __cdecl operator<<(class klass const &,int)", ); expect( "??5@YAAEBVklass@@AEBV0@_K@Z", "class klass const & __cdecl operator>>(class klass const &,uint64_t)", ); expect( "??2@YAPEAX_KAEAVklass@@@Z", "void * __cdecl operator new(uint64_t,class klass &)", ); expect( "??_U@YAPEAX_KAEAVklass@@@Z", "void * __cdecl operator new[](uint64_t,class klass &)", ); expect( "??3@YAXPEAXAEAVklass@@@Z", "void __cdecl operator delete(void *,class klass &)", ); expect( "??_V@YAXPEAXAEAVklass@@@Z", "void __cdecl operator delete[](void *,class klass &)", ); expect( "?DispatchToCallback@?$I@U?$Y@$S@y@x@@$$V@y@x@@QEAAXV?$C@$$A6AXXZ@base@@@Z", "public: void __cdecl x::y::I >::DispatchToCallback(class base::C)", ); expect( "?DispatchToCallback@?$I@U?$Y@$$Z@y@x@@$$V@y@x@@QEAAXV?$C@$$A6AXXZ@base@@@Z", "public: void __cdecl x::y::I >::DispatchToCallback(class base::C)", ); expect( "??$func@H$$ZH@@YAHAEBU?$Foo@H@@0@Z", "int __cdecl func(struct Foo const &,struct Foo const &)", ); expect( "??$func@HH$$Z@@YAHAEBU?$Foo@H@@0@Z", "int __cdecl func(struct Foo const &,struct Foo const &)", ); expect( "??$templ_fun_with_pack@$S@@YAXXZ", "void __cdecl templ_fun_with_pack<>(void)", ); expect( "??$templ_fun_with_ty_pack@$$$V@@YAXXZ", "void __cdecl templ_fun_with_ty_pack<>(void)", ); expect( "??$templ_fun_with_ty_pack@$$V@@YAXXZ", "void __cdecl templ_fun_with_ty_pack<>(void)", ); expect( "??__FFLASH_TEMP_FILENAME@sandboxing@mozilla@@YAXXZ", "void __cdecl mozilla::sandboxing::FLASH_TEMP_FILENAME::`dynamic atexit destructor'(void)", ); expect( "??__J?1??f@@YAAAUS@@XZ@5BB@", "`struct S & __cdecl f(void)'::`2'::`local static thread guard'{17}", ); expect( "??__J?@??f@@YAAAUS@@XZ@5BB@", "`struct S & __cdecl f(void)'::`0'::`local static thread guard'{17}", ); expect( "??__J?A@??f@@YAAAUS@@XZ@5BB@", "`struct S & __cdecl f(void)'::`anonymous namespace'::`local static thread guard'{17}", ); expect( "??__J?B@??f@@YAAAUS@@XZ@5BB@", "`struct S & __cdecl f(void)'::`1'::`local static thread guard'{17}", ); expect( "??__J?@??f@@YAAAUS@@XZ@5BB@", "`struct S & __cdecl f(void)'::`0'::`local static thread guard'{17}", ); } #[test] fn gh_issues() { let expect = |input, reference| { expect_with_flags(input, reference, 0x0); }; // panic: attempt to negate with overflow in `msvc_demangler::ParserState::read_number`: // . expect( "??$TypedThrowBadVariantAccess@AEBV?$IdType@VGpuDiskCacheDawnWebGPU@gpu@@H$0?IAAAAAAA@$00$S@base@@@variant_internal@absl@@YAAEBV?$IdType@VGpuDiskCacheDawnWebGPU@gpu@@H$0?IAAAAAAA@$00$S@base@@XZ", "class base::IdType const & __cdecl absl::variant_internal::TypedThrowBadVariantAccess const &>(void)" ); } msvc-demangler-0.10.1/tests/test_llvm.rs000064400000000000000000000075441046102023000163420ustar 00000000000000extern crate msvc_demangler; use msvc_demangler::{parse, serialize, DemangleFlags}; use std::iter; #[derive(Debug)] pub struct TestCase<'a> { mangled: &'a str, demangled_ref: &'a str, not_invalid: bool, } #[derive(Debug)] enum LineRule<'a> { Input(&'a str), Check(&'a str), CheckNotInvalid, } fn parse_cases<'a, I: Iterator>(i: I) -> impl Iterator> { let mut rule_iter = i.filter_map(|item| { let item = item.trim(); if item.is_empty() { None } else if item.starts_with("; RUN: ") { assert!(item.contains("llvm-undname")); None } else if item == "; CHECK-NOT: Invalid mangled name" { Some(LineRule::CheckNotInvalid) } else if item.starts_with("; CHECK-NOT: ") { panic!("unsupported rule: {}", &item[2..]); } else if let Some(item) = item.strip_prefix("; CHECK: ") { Some(LineRule::Check(item)) } else if item.starts_with(';') { None } else { Some(LineRule::Input(item)) } }); let mut not_invalid = false; iter::from_fn(move || loop { match rule_iter.next() { None => return None, Some(LineRule::CheckNotInvalid) => { not_invalid = true; } Some(LineRule::Input(input)) => { if let Some(next) = rule_iter.next() { match next { LineRule::CheckNotInvalid => { panic!("not invalid at unexpected position"); } LineRule::Check(check) => { return Some(TestCase { mangled: input, demangled_ref: check, not_invalid, }); } LineRule::Input(_) => { panic!("multi line input unsupported"); } } } } Some(LineRule::Check(check)) => { panic!("unexpected check: {}", check); } } }) } macro_rules! llvm_test { ($filename:expr) => {{ let rules = include_str!($filename); for case in parse_cases(rules.lines()) { if case.not_invalid { let parsed = dbg!(parse(case.mangled).unwrap()); let demangled = serialize(&parsed, DemangleFlags::llvm()).unwrap(); println!(" mangled: {}", case.mangled); println!("demangled ref: {}", case.demangled_ref); println!(" demangled: {}", &demangled); // llvm is inconsistent with ctor vs constructor in a few cases let demangled_fuzzy = demangled .replace("constructor", "ctor") .replace("destructor", "dtor") .replace("::`RTTI", " `RTTI") .replace("> > > >", ">>>>") .replace("> > >", ">>>") .replace("> >", ">>"); assert!( demangled_fuzzy.contains(case.demangled_ref) || demangled.contains(case.demangled_ref) ); } else { panic!("not implemented"); } println!(); } }}; } #[test] fn test_llvm_ms_basic() { llvm_test!("llvm-cases/ms-basic.test"); } #[test] 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"); } #[test] fn test_llvm_cxx11() { llvm_test!("llvm-cases/ms-cxx11.test"); }