//! Abstract syntax tree types for mangled symbols. use super::{DemangleNodeType, DemangleOptions, DemangleWrite, ParseOptions}; use crate::error::{self, Result}; use crate::index_str::IndexStr; use crate::subs::{Substitutable, SubstitutionTable}; use alloc::boxed::Box; use alloc::string::String; use alloc::vec::Vec; use core::cell::Cell; #[cfg(feature = "logging")] use core::cell::RefCell; use core::fmt::{self, Write}; use core::hash::{Hash, Hasher}; use core::mem; use core::ops; use core::ptr; use core::str; macro_rules! r#try_recurse { ($expr:expr $(,)?) => { match $expr { Result::Err(error::Error::TooMuchRecursion) => { return Result::Err(error::Error::TooMuchRecursion); } val => val, } }; } struct AutoLogParse; #[cfg(feature = "logging")] thread_local! { static LOG_DEPTH: RefCell = RefCell::new(0); } impl AutoLogParse { #[cfg(feature = "logging")] fn new(production: &'static str, input: IndexStr<'_>) -> AutoLogParse { LOG_DEPTH.with(|depth| { if *depth.borrow() == 0 { println!(); } let indent: String = (0..*depth.borrow() * 4).map(|_| ' ').collect(); log!( "{}({} \"{}\" {}", indent, production, String::from_utf8_lossy(input.as_ref()), input.len(), ); *depth.borrow_mut() += 1; }); AutoLogParse } #[cfg(not(feature = "logging"))] #[inline(always)] fn new(_: &'static str, _: IndexStr) -> AutoLogParse { AutoLogParse } } #[cfg(feature = "logging")] impl Drop for AutoLogParse { fn drop(&mut self) { LOG_DEPTH.with(|depth| { *depth.borrow_mut() -= 1; let indent: String = (0..*depth.borrow() * 4).map(|_| ' ').collect(); log!("{})", indent); }); } } /// Performs the two operations that begin every parse: /// /// 1. Keeps track of recursion levels and early returns with an error if there /// is too much recursion. /// /// 2. Automatically log start and end parsing in an s-expression format, when the /// `logging` feature is enabled. macro_rules! try_begin_parse { ( $production:expr , $ctx:expr , $input:expr ) => { let _log = AutoLogParse::new($production, $input); let _auto_check_recursion = AutoParseRecursion::new($ctx)?; }; } struct AutoLogDemangle; impl AutoLogDemangle { #[cfg(feature = "logging")] fn new( production: &P, ctx: &DemangleContext, scope: Option, is_inner: bool, ) -> AutoLogDemangle where P: ?Sized + fmt::Debug, W: DemangleWrite, { LOG_DEPTH.with(|depth| { if *depth.borrow() == 0 { println!(); } let indent: String = (0..*depth.borrow() * 4).map(|_| ' ').collect(); log!("{}(", indent); log!( "{} {}{:?}", indent, if is_inner { "as_inner: " } else { "" }, production ); log!("{} inner = {:?}", indent, ctx.inner); log!("{} scope = {:?}", indent, scope); *depth.borrow_mut() += 1; }); AutoLogDemangle } #[cfg(not(feature = "logging"))] #[inline(always)] fn new( _: &P, _: &DemangleContext, _: Option, _: bool, ) -> AutoLogDemangle where P: ?Sized + fmt::Debug, W: DemangleWrite, { AutoLogDemangle } } #[cfg(feature = "logging")] impl Drop for AutoLogDemangle { fn drop(&mut self) { LOG_DEPTH.with(|depth| { *depth.borrow_mut() -= 1; let indent: String = (0..*depth.borrow() * 4).map(|_| ' ').collect(); log!("{})", indent); }); } } /// Automatically log start and end demangling in an s-expression format, when /// the `logging` feature is enabled. macro_rules! try_begin_demangle { ( $production:expr, $ctx:expr, $scope:expr ) => {{ let _log = AutoLogDemangle::new($production, $ctx, $scope, false); &mut AutoParseDemangle::new($ctx)? }}; } /// Automatically log start and end demangling in an s-expression format, when /// the `logging` feature is enabled. macro_rules! try_begin_demangle_as_inner { ( $production:expr, $ctx:expr, $scope:expr ) => {{ let _log = AutoLogDemangle::new($production, $ctx, $scope, true); &mut AutoParseDemangle::new($ctx)? }}; } #[derive(Debug, Default, Clone, Copy)] struct ParseContextState { // The current recursion level. Should always be less than or equal to the // maximum. recursion_level: u32, // Whether or not we are currently parsing a conversion operator. in_conversion: bool, } /// Common context needed when parsing. #[derive(Debug, Clone)] pub struct ParseContext { // Maximum amount of recursive parsing calls we will allow. If this is too // large, we can blow the stack. max_recursion: u32, // Mutable state within the `ParseContext`. state: Cell, } impl ParseContext { /// Construct a new `ParseContext`. pub fn new(options: ParseOptions) -> ParseContext { ParseContext { max_recursion: options.recursion_limit.map(|v| v.get()).unwrap_or(96), state: Cell::new(ParseContextState::default()), } } /// Get the current recursion level for this context. pub fn recursion_level(&self) -> u32 { self.state.get().recursion_level } #[inline] fn enter_recursion(&self) -> error::Result<()> { let mut state = self.state.get(); let new_recursion_level = state.recursion_level + 1; if new_recursion_level >= self.max_recursion { log!("Hit too much recursion at level {}", self.max_recursion); Err(error::Error::TooMuchRecursion) } else { state.recursion_level = new_recursion_level; self.state.set(state); Ok(()) } } #[inline] fn exit_recursion(&self) { let mut state = self.state.get(); debug_assert!(state.recursion_level >= 1); state.recursion_level -= 1; self.state.set(state); } #[inline] fn in_conversion(&self) -> bool { self.state.get().in_conversion } fn set_in_conversion(&self, in_conversion: bool) -> bool { let mut state = self.state.get(); let previously_in_conversion = state.in_conversion; state.in_conversion = in_conversion; self.state.set(state); previously_in_conversion } } /// An RAII type to automatically check the recursion level against the /// maximum. If the maximum has been crossed, return an error. Otherwise, /// increment the level upon construction, and decrement it upon destruction. struct AutoParseRecursion<'a>(&'a ParseContext); impl<'a> AutoParseRecursion<'a> { #[inline] fn new(ctx: &'a ParseContext) -> error::Result> { ctx.enter_recursion()?; Ok(AutoParseRecursion(ctx)) } } impl<'a> Drop for AutoParseRecursion<'a> { #[inline] fn drop(&mut self) { self.0.exit_recursion(); } } /// A trait for anything that can be parsed from an `IndexStr` and return a /// `Result` of the parsed `Self` value and the rest of the `IndexStr` input /// that has not been consumed in parsing the `Self` value. /// /// For AST types representing productions which have `` as a /// possible right hand side, do not implement this trait directly. Instead, /// make a newtype over `usize`, parse either the `` back /// reference or "real" value, insert the "real" value into the substitution /// table if needed, and *always* return the newtype index into the substitution /// table. #[doc(hidden)] pub trait Parse: Sized { /// Parse the `Self` value from `input` and return it, updating the /// substitution table as needed. fn parse<'a, 'b>( ctx: &'a ParseContext, subs: &'a mut SubstitutionTable, input: IndexStr<'b>, ) -> Result<(Self, IndexStr<'b>)>; } /// Determine whether this AST node is an instantiated[*] template function, and /// get its concrete template arguments. /// /// [*] Note that we will never see an abstract, un-instantiated template /// function, since they don't end up in object files and don't get mangled /// names. trait GetTemplateArgs { /// Returns `Some` if this is a template function, `None` otherwise. fn get_template_args<'a>(&'a self, subs: &'a SubstitutionTable) -> Option<&'a TemplateArgs>; } /// A leaf name is the part the name that describes some type or class without /// any leading namespace qualifiers. /// /// This is used when figuring out how to format constructors and destructors, /// which are formatted as `gooble::dodo::Thing::~Thing()` but we don't have /// direct access to `Thing` in the `CtorDtorName` AST. #[derive(Debug)] pub(crate) enum LeafName<'a> { SourceName(&'a SourceName), WellKnownComponent(&'a WellKnownComponent), Closure(&'a ClosureTypeName), UnnamedType(&'a UnnamedTypeName), } impl<'subs, W> DemangleAsLeaf<'subs, W> for LeafName<'subs> where W: 'subs + DemangleWrite, { fn demangle_as_leaf<'me, 'ctx>( &'me self, ctx: &'ctx mut DemangleContext<'subs, W>, ) -> fmt::Result { match *self { LeafName::SourceName(sn) => sn.demangle(ctx, None), LeafName::Closure(c) => c.demangle(ctx, None), LeafName::WellKnownComponent(wkc) => wkc.demangle_as_leaf(ctx), LeafName::UnnamedType(utn) => utn.demangle_as_leaf(ctx), } } } /// Determine whether this AST node is some kind (potentially namespaced) name /// and if so get its leaf name. pub(crate) trait GetLeafName<'a> { fn get_leaf_name(&'a self, subs: &'a SubstitutionTable) -> Option>; } /// Determine whether this AST node is a constructor, destructor, or conversion /// function. pub(crate) trait IsCtorDtorConversion { fn is_ctor_dtor_conversion(&self, subs: &SubstitutionTable) -> bool; } /// When formatting a mangled symbol's parsed AST as a demangled symbol, we need /// to resolve indirect references to template and function arguments with /// direct `TemplateArg` and `Type` references respectively. /// /// Note that which set of arguments are implicitly referenced change as we /// enter and leave different functions' scope. One might usually use de Brujin /// indices to keep arguments within scopes separated from each other, but the /// Itanium C++ ABI does not allow us the luxury. AFAIK, when the ABI was first /// drafted, C++ did not have lambdas, and the issue did not come up at all /// since a function simply couldn't refer to the types of closed over /// variables. /// /// This trait is implemented by anything that can potentially resolve arguments /// for us. trait ArgScope<'me, 'ctx>: fmt::Debug { /// Get the current scope's leaf name. fn leaf_name(&'me self) -> Result>; /// Get the current scope's `index`th template argument. fn get_template_arg(&'me self, index: usize) -> Result<(&'ctx TemplateArg, &'ctx TemplateArgs)>; #[allow(unused)] /// Get the current scope's `index`th function argument's type. fn get_function_arg(&'me self, index: usize) -> Result<&'ctx Type>; } /// An `ArgScopeStack` represents the current function and template demangling /// scope we are within. As we enter new demangling scopes, we construct new /// `ArgScopeStack`s whose `prev` references point back to the old ones. These /// `ArgScopeStack`s are kept on the native stack, and as functions return, they /// go out of scope and we use the previous `ArgScopeStack`s again. #[derive(Copy, Clone, Debug)] pub struct ArgScopeStack<'prev, 'subs> where 'subs: 'prev, { item: &'subs dyn ArgScope<'subs, 'subs>, in_arg: Option<(usize, &'subs TemplateArgs)>, prev: Option<&'prev ArgScopeStack<'prev, 'subs>>, } /// When we first begin demangling, we haven't entered any function or template /// demangling scope and we don't have any useful `ArgScopeStack`. Therefore, we /// are never actually dealing with `ArgScopeStack` directly in practice, but /// always an `Option` instead. Nevertheless, we want to define /// useful methods on `Option`. /// /// A custom "extension" trait with exactly one implementor: Rust's principled /// monkey patching! trait ArgScopeStackExt<'prev, 'subs>: Copy { /// Push a new `ArgScope` onto this `ArgScopeStack` and return the new /// `ArgScopeStack` with the pushed resolver on top. fn push( &'prev self, item: &'subs dyn ArgScope<'subs, 'subs>, ) -> Option>; } impl<'prev, 'subs> ArgScopeStackExt<'prev, 'subs> for Option> { fn push( &'prev self, item: &'subs dyn ArgScope<'subs, 'subs>, ) -> Option> { log!("ArgScopeStack::push: {:?}", item); Some(ArgScopeStack { prev: self.as_ref(), in_arg: None, item: item, }) } } /// A stack of `ArgScope`s is itself an `ArgScope`! impl<'prev, 'subs> ArgScope<'prev, 'subs> for Option> { fn leaf_name(&'prev self) -> Result> { let mut scope = self.as_ref(); while let Some(s) = scope { if let Ok(c) = s.item.leaf_name() { return Ok(c); } scope = s.prev; } Err(error::Error::BadLeafNameReference) } fn get_template_arg( &'prev self, idx: usize, ) -> Result<(&'subs TemplateArg, &'subs TemplateArgs)> { let mut scope = self.as_ref(); while let Some(s) = scope { if let Ok((arg, args)) = s.item.get_template_arg(idx) { if let Some((in_idx, in_args)) = s.in_arg { if args as *const TemplateArgs == in_args as *const TemplateArgs && in_idx <= idx { return Err(error::Error::ForwardTemplateArgReference); } } return Ok((arg, args)); } scope = s.prev; } Err(error::Error::BadTemplateArgReference) } fn get_function_arg(&'prev self, idx: usize) -> Result<&'subs Type> { let mut scope = self.as_ref(); while let Some(s) = scope { if let Ok(arg) = s.item.get_function_arg(idx) { return Ok(arg); } scope = s.prev; } Err(error::Error::BadFunctionArgReference) } } #[derive(Debug, Copy, Clone)] struct DemangleState { /// How deep in the demangling are we? pub recursion_level: u32, } /// An RAII type to automatically check the recursion level against the /// maximum. If the maximum has been crossed, return an error. Otherwise, /// increment the level upon construction, and decrement it upon destruction. struct AutoParseDemangle<'a, 'b, W: 'a + DemangleWrite>(&'b mut DemangleContext<'a, W>); impl<'a, 'b, W: 'a + DemangleWrite> AutoParseDemangle<'a, 'b, W> { #[inline] fn new(ctx: &'b mut DemangleContext<'a, W>) -> core::result::Result { ctx.enter_recursion()?; Ok(AutoParseDemangle(ctx)) } } impl<'a, 'b, W: 'a + DemangleWrite> ops::Deref for AutoParseDemangle<'a, 'b, W> { type Target = DemangleContext<'a, W>; fn deref(&self) -> &Self::Target { self.0 } } impl<'a, 'b, W: 'a + DemangleWrite> ops::DerefMut for AutoParseDemangle<'a, 'b, W> { fn deref_mut(&mut self) -> &mut Self::Target { self.0 } } impl<'a, 'b, W: 'a + DemangleWrite> Drop for AutoParseDemangle<'a, 'b, W> { #[inline] fn drop(&mut self) { self.0.exit_recursion(); } } /// Common state that is required when demangling a mangled symbol's parsed AST. #[doc(hidden)] #[derive(Debug)] pub struct DemangleContext<'a, W> where W: 'a + DemangleWrite, { // The substitution table built up when parsing the mangled symbol into an // AST. subs: &'a SubstitutionTable, // The maximum recursion max_recursion: u32, // Sometimes an AST node needs to insert itself as an inner item within one // of its children when demangling that child. For example, the AST // // (array 10 int) // // is demangled as `int[10]`, but if we were to demangle the AST // // (lvalue-ref (array 10 int)) // // then we would want this demangled form: `int (&) [10]`, which requires // the parent lvalue-ref to be passed into the child array's demangling // method. This kind of thing also pops up with function pointers. // // The `inner` stack enables such behavior by allowing us to pass AST // parents down to their children as inner items. inner: Vec<&'a dyn DemangleAsInner<'a, W>>, // The original input string. input: &'a [u8], // `Identifier`s will be placed here, so `UnnamedTypeName` can utilize and print // out the Constructor/Destructor used. source_name: Option<&'a str>, // What the demangled name is being written to. out: &'a mut W, // The total number of bytes written to `out`. This is maintained by the // `Write` implementation for `DemangleContext`. bytes_written: usize, // The last char written to `out`, if any. last_char_written: Option, // We are currently demangling a lambda argument, so template substitution // should be suppressed to match libiberty. is_lambda_arg: bool, // We are currently demangling a template-prefix. is_template_prefix: bool, // We are currently demangling a template-prefix in a nested-name. is_template_prefix_in_nested_name: bool, // `PackExpansion`'s should only print '...', only when there is no template // argument pack. is_template_argument_pack: bool, // Whether to show function parameters. // This must be set to true before calling `demangle` on `Encoding` // unless that call is via the toplevel call to `MangledName::demangle`. show_params: bool, // Whether to show function return types. // This must be set to true before calling `demangle` on `Encoding` // unless that call is via the toplevel call to `MangledName::demangle`. show_return_type: bool, // Whether to show types of expression literals. show_expression_literal_types: bool, // recursion protection. state: Cell, } impl<'a, W> fmt::Write for DemangleContext<'a, W> where W: 'a + DemangleWrite, { fn write_str(&mut self, s: &str) -> fmt::Result { if s.is_empty() { return Ok(()); } log!("DemangleContext::write: '{}'", s); self.out.write_string(s).map(|_| { self.last_char_written = s.chars().last(); self.bytes_written += s.len(); }) } } impl<'a, W> DemangleContext<'a, W> where W: 'a + DemangleWrite, { /// Construct a new `DemangleContext`. pub fn new( subs: &'a SubstitutionTable, input: &'a [u8], options: DemangleOptions, out: &'a mut W, ) -> DemangleContext<'a, W> { DemangleContext { subs: subs, max_recursion: options.recursion_limit.map(|v| v.get()).unwrap_or(128), inner: vec![], input: input, source_name: None, out: out, bytes_written: 0, last_char_written: None, is_lambda_arg: false, is_template_prefix: false, is_template_prefix_in_nested_name: false, is_template_argument_pack: false, show_params: !options.no_params, show_return_type: !options.no_return_type, show_expression_literal_types: !options.hide_expression_literal_types, state: Cell::new(DemangleState { recursion_level: 0 }), } } /// Get the current recursion level for this context. pub fn recursion_level(&self) -> u32 { self.state.get().recursion_level } #[inline] fn enter_recursion(&self) -> fmt::Result { let mut state = self.state.get(); let new_recursion_level = state.recursion_level + 1; if new_recursion_level >= self.max_recursion { log!("Hit too much recursion at level {}", self.max_recursion); Err(Default::default()) } else { state.recursion_level = new_recursion_level; self.state.set(state); Ok(()) } } #[inline] fn exit_recursion(&self) { let mut state = self.state.get(); debug_assert!(state.recursion_level >= 1); state.recursion_level -= 1; self.state.set(state); } #[inline] fn ensure(&mut self, ch: char) -> fmt::Result { if self.last_char_written == Some(ch) { Ok(()) } else { write!(self, "{}", ch)?; Ok(()) } } #[inline] fn ensure_space(&mut self) -> fmt::Result { self.ensure(' ') } #[inline] fn push_inner(&mut self, item: &'a dyn DemangleAsInner<'a, W>) { log!("DemangleContext::push_inner: {:?}", item); self.inner.push(item); } #[inline] fn pop_inner(&mut self) -> Option<&'a dyn DemangleAsInner<'a, W>> { let popped = self.inner.pop(); log!("DemangleContext::pop_inner: {:?}", popped); popped } #[inline] fn pop_inner_if(&mut self, inner: &'a dyn DemangleAsInner<'a, W>) -> bool { let last = match self.inner.last() { None => return false, Some(last) => *last, }; if ptr::eq(last, inner) { self.inner.pop(); true } else { false } } fn demangle_inner_prefixes<'prev>( &mut self, scope: Option>, ) -> fmt::Result { log!("DemangleContext::demangle_inner_prefixes"); let mut new_inner = vec![]; while let Some(inner) = self.pop_inner() { if inner .downcast_to_function_type() .map_or(false, |f| !f.cv_qualifiers.is_empty()) { log!( "DemangleContext::demangle_inner_prefixes: not a prefix, saving: {:?}", inner ); new_inner.push(inner); } else { log!( "DemangleContext::demangle_inner_prefixes: demangling prefix: {:?}", inner ); inner.demangle_as_inner(self, scope)?; } } new_inner.reverse(); self.inner = new_inner; Ok(()) } fn demangle_inners<'prev>(&mut self, scope: Option>) -> fmt::Result { while let Some(inner) = self.pop_inner() { inner.demangle_as_inner(self, scope)?; } Ok(()) } fn set_source_name(&mut self, start: usize, end: usize) { let ident = &self.input[start..end]; self.source_name = str::from_utf8(ident).ok(); } fn push_demangle_node(&mut self, t: DemangleNodeType) { self.out.push_demangle_node(t); } /// This should not be called on error paths. /// pop_inner_if already doesn't balance if there are errors. fn pop_demangle_node(&mut self) { self.out.pop_demangle_node(); } } #[doc(hidden)] #[derive(Debug)] pub struct AutoDemangleContextInnerBarrier<'ctx, 'a, W> where W: 'a + DemangleWrite, 'a: 'ctx, { ctx: &'ctx mut DemangleContext<'a, W>, saved_inner: Vec<&'a dyn DemangleAsInner<'a, W>>, } impl<'ctx, 'a, W> AutoDemangleContextInnerBarrier<'ctx, 'a, W> where W: 'a + DemangleWrite, 'a: 'ctx, { /// Set aside the current inner stack on the demangle context. pub fn new(ctx: &'ctx mut DemangleContext<'a, W>) -> Self { let mut saved_inner = vec![]; mem::swap(&mut saved_inner, &mut ctx.inner); AutoDemangleContextInnerBarrier { ctx: ctx, saved_inner: saved_inner, } } } impl<'ctx, 'a, W> ops::Deref for AutoDemangleContextInnerBarrier<'ctx, 'a, W> where W: 'a + DemangleWrite, 'a: 'ctx, { type Target = DemangleContext<'a, W>; fn deref(&self) -> &Self::Target { self.ctx } } impl<'ctx, 'a, W> ops::DerefMut for AutoDemangleContextInnerBarrier<'ctx, 'a, W> where W: 'a + DemangleWrite, 'a: 'ctx, { fn deref_mut(&mut self) -> &mut Self::Target { self.ctx } } impl<'ctx, 'a, W> Drop for AutoDemangleContextInnerBarrier<'ctx, 'a, W> where W: 'a + DemangleWrite, 'a: 'ctx, { fn drop(&mut self) { // NB: We cannot assert that the context's inner is empty here, // because if demangling failed we'll unwind the stack without // using everything that put on the inner. if !self.ctx.inner.is_empty() { log!("Context inner was not emptied, did demangling fail?"); } mem::swap(&mut self.saved_inner, &mut self.ctx.inner); } } /// The inner stack allows passing AST nodes down deeper into the tree so that /// nodes that logically precede something (e.g. PointerRef) can show up after /// that thing in the demangled output. What's on the stack may not always be /// intended for the first node that looks at the stack to grab, though. /// /// Consider a function with template arguments and parameters, f(a). /// The function parameters logically precede the template arguments in the AST, /// but they must be reversed in the output. The parameters end up on the inner /// stack before processing the template argument nodes. If we're not careful, /// a node inside the template arguments might pick the function parameters /// off of the inner stack! /// /// To solve this, certain nodes act as "inner barriers". By using this macro, /// they set the existing inner stack aside and replace it with an empty stack /// while visiting their children. This allows these barrier nodes to have /// completely self-contained children. macro_rules! inner_barrier { ( $ctx:ident ) => { let mut _ctx = AutoDemangleContextInnerBarrier::new($ctx); let $ctx = &mut _ctx; }; } /// Any AST node that can be printed in a demangled form. #[doc(hidden)] pub trait Demangle<'subs, W>: fmt::Debug where W: 'subs + DemangleWrite, { /// Write the demangled form of this AST node to the given context. fn demangle<'prev, 'ctx>( &'subs self, ctx: &'ctx mut DemangleContext<'subs, W>, scope: Option>, ) -> fmt::Result; } /// Any AST node that can be printed as an inner type. /// /// See the comments surrounding `DemangleContext::inner` for details. #[doc(hidden)] pub trait DemangleAsInner<'subs, W>: Demangle<'subs, W> where W: 'subs + DemangleWrite, { /// Write the inner demangling form of this AST node to the given context. fn demangle_as_inner<'prev, 'ctx>( &'subs self, ctx: &'ctx mut DemangleContext<'subs, W>, scope: Option>, ) -> fmt::Result { self.demangle(ctx, scope) } /// Cast this `DemangleAsInner` to a `Type`. fn downcast_to_type(&self) -> Option<&Type> { None } /// Cast this `DemangleAsInner` to a `FunctionType`. fn downcast_to_function_type(&self) -> Option<&FunctionType> { None } /// Cast this `DemangleAsInner` to an `ArrayType`. fn downcast_to_array_type(&self) -> Option<&ArrayType> { None } /// Cast this `DemangleAsInner` to a `PointerToMember`. fn downcast_to_pointer_to_member(&self) -> Option<&PointerToMemberType> { None } fn is_qualified(&self) -> bool { false } } /// Demangle this thing in the leaf name position. /// /// For most things this should be the same as its `Demangle` /// implementation. For `WellKnownComponent`s we need to strip the embedded /// `std::` namespace prefix. pub(crate) trait DemangleAsLeaf<'subs, W> where W: 'subs + DemangleWrite, { fn demangle_as_leaf<'me, 'ctx>( &'me self, ctx: &'ctx mut DemangleContext<'subs, W>, ) -> fmt::Result; } macro_rules! reference_newtype { ( $newtype_name:ident , $oldtype:ty ) => { #[derive(Debug)] struct $newtype_name($oldtype); impl $newtype_name { #[allow(clippy::ptr_arg)] #[allow(unsafe_code)] fn new(types: &$oldtype) -> &$newtype_name { unsafe { // This is safe because we only create an immutable // reference. We are not breaking unique mutable aliasing // requirements. An immutable reference does not allow // dropping the referent, so no worries about double-free // (additionally, see the assertion inside `Drop` below). &*(types as *const $oldtype as *const $newtype_name) } } } impl Drop for $newtype_name { fn drop(&mut self) { unreachable!( "Dropping implies we dereferenced and took ownership, which \ is not safe for this newtype" ); } } impl ops::Deref for $newtype_name { type Target = $oldtype; fn deref(&self) -> &Self::Target { &self.0 } } }; } // We can't implement `DemangleAsInner` for newtypes of `[TypeHandle]` like we // want to because it is unsized and we need to make trait objects out of // `DemangleAsInner` for pushing onto the context's inner stack. Therefore, we // have this inelegant newtyping of `Vec`. // A set of function arguments. reference_newtype!(FunctionArgList, Vec); // A set of function arguments prefixed by a return type (which we want to // ignore). reference_newtype!(FunctionArgListAndReturnType, Vec); // A newtype around a slice of type handles that we format as function // arguments. reference_newtype!(FunctionArgSlice, [TypeHandle]); // Demangle a slice of TypeHandle as a function argument list. impl<'subs, W> Demangle<'subs, W> for FunctionArgSlice where W: 'subs + DemangleWrite, { fn demangle<'prev, 'ctx>( &'subs self, ctx: &'ctx mut DemangleContext<'subs, W>, scope: Option>, ) -> fmt::Result { let ctx = try_begin_demangle!(self, ctx, scope); let mut saw_needs_paren = false; let (needs_space, needs_paren) = ctx .inner .iter() .rev() .map(|inner| { if inner.downcast_to_pointer_to_member().is_some() { (true, true) } else { match inner.downcast_to_type() { Some(&Type::Qualified(..)) | Some(&Type::Complex(_)) | Some(&Type::Imaginary(_)) | Some(&Type::PointerToMember(_)) => (true, true), Some(&Type::PointerTo(_)) | Some(&Type::LvalueRef(_)) | Some(&Type::RvalueRef(_)) => (false, true), _ => (false, false), } } }) .take_while(|&(_, needs_paren)| { if saw_needs_paren { false } else { saw_needs_paren |= needs_paren; true } }) .fold( (false, false), |(space, paren), (next_space, next_paren)| { (space || next_space, paren || next_paren) }, ); if needs_paren { let needs_space = needs_space || match ctx.last_char_written { Some('(') | Some('*') => false, _ => true, }; if needs_space { ctx.ensure_space()?; } write!(ctx, "(")?; } ctx.demangle_inner_prefixes(scope)?; if needs_paren { write!(ctx, ")")?; } write!(ctx, "(")?; // To maintain compatibility with libiberty, print `()` instead of // `(void)` for functions that take no arguments. if self.len() == 1 && self[0].is_void() { write!(ctx, ")")?; return Ok(()); } let mut need_comma = false; for arg in self.iter() { if need_comma { write!(ctx, ", ")?; } arg.demangle(ctx, scope)?; need_comma = true; } write!(ctx, ")")?; ctx.demangle_inners(scope) } } impl<'subs, W> Demangle<'subs, W> for FunctionArgList where W: 'subs + DemangleWrite, { fn demangle<'prev, 'ctx>( &'subs self, ctx: &'ctx mut DemangleContext<'subs, W>, scope: Option>, ) -> fmt::Result { FunctionArgSlice::new(&self.0[..]).demangle(ctx, scope) } } impl<'subs, W> DemangleAsInner<'subs, W> for FunctionArgList where W: 'subs + DemangleWrite {} impl<'subs, W> Demangle<'subs, W> for FunctionArgListAndReturnType where W: 'subs + DemangleWrite, { fn demangle<'prev, 'ctx>( &'subs self, ctx: &'ctx mut DemangleContext<'subs, W>, scope: Option>, ) -> fmt::Result { FunctionArgSlice::new(&self.0[1..]).demangle(ctx, scope) } } impl<'subs, W> DemangleAsInner<'subs, W> for FunctionArgListAndReturnType where W: 'subs + DemangleWrite { } /// Define a handle to a AST type that lives inside the substitution table. A /// handle is always either an index into the substitution table, or it is a /// reference to a "well-known" component. /// /// This declares: /// /// - The enum of either a back reference into the substitution table or a /// reference to a "well-known" component /// - a `Demangle` impl that proxies to the appropriate `Substitutable` in the /// `SubstitutionTable` macro_rules! define_handle { ( $(#[$attr:meta])* pub enum $typename:ident ) => { define_handle! { $(#[$attr])* pub enum $typename {} } }; ( $(#[$attr:meta])* pub enum $typename:ident { $( $( #[$extra_attr:meta] )* extra $extra_variant:ident ( $extra_variant_ty:ty ), )* } ) => { $(#[$attr])* #[derive(Clone, Debug, PartialEq, Eq)] pub enum $typename { /// A reference to a "well-known" component. WellKnown(WellKnownComponent), /// A back-reference into the substitution table to a component we /// have already parsed. BackReference(usize), $( $( #[$extra_attr] )* $extra_variant( $extra_variant_ty ), )* } impl $typename { /// If this is a `BackReference`, get its index. pub fn back_reference(&self) -> Option { match *self { $typename::BackReference(n) => Some(n), _ => None, } } } impl<'subs, W> Demangle<'subs, W> for $typename where W: 'subs + DemangleWrite { #[inline] fn demangle<'prev, 'ctx>(&'subs self, ctx: &'ctx mut DemangleContext<'subs, W>, scope: Option>) -> fmt::Result { match *self { $typename::WellKnown(ref comp) => comp.demangle(ctx, scope), $typename::BackReference(idx) => ctx.subs[idx].demangle(ctx, scope), $( $typename::$extra_variant(ref extra) => extra.demangle(ctx, scope), )* } } } impl<'a> GetLeafName<'a> for $typename { fn get_leaf_name(&'a self, subs: &'a SubstitutionTable) -> Option> { match *self { $typename::WellKnown(ref wk) => wk.get_leaf_name(subs), $typename::BackReference(idx) => { subs.get(idx).and_then(|s| s.get_leaf_name(subs)) } $( $typename::$extra_variant(ref e) => e.get_leaf_name(subs), )* } } } }; } /// A handle to a component that is usually substitutable, and lives in the /// substitutions table, but in this particular case does not qualify for /// substitutions. #[derive(Clone, Debug, PartialEq, Eq)] pub struct NonSubstitution(usize); impl<'subs, W> Demangle<'subs, W> for NonSubstitution where W: 'subs + DemangleWrite, { fn demangle<'prev, 'ctx>( &'subs self, ctx: &'ctx mut DemangleContext<'subs, W>, scope: Option>, ) -> fmt::Result { ctx.subs.non_substitution(self.0).demangle(ctx, scope) } } impl<'a> GetLeafName<'a> for NonSubstitution { fn get_leaf_name(&'a self, subs: &'a SubstitutionTable) -> Option> { subs.get_non_substitution(self.0) .and_then(|ns| ns.get_leaf_name(subs)) } } /// Define a "vocabulary" nonterminal, something like `OperatorName` or /// `CtorDtorName` that's basically a big list of constant strings. /// /// This declares: /// /// - the enum itself /// - a `Parse` impl /// - a `Demangle` impl /// /// See the definition of `CTorDtorName` for an example of its use. /// /// Optionally, a piece of user data can be attached to the definitions /// and be returned by a generated accessor. See `SimpleOperatorName` for /// an example. macro_rules! define_vocabulary { ( $(#[$attr:meta])* pub enum $typename:ident { $($variant:ident ( $mangled:expr, $printable:expr )),* } ) => { $(#[$attr])* pub enum $typename { $( #[doc=$printable] $variant ),* } impl Parse for $typename { fn parse<'a, 'b>(ctx: &'a ParseContext, _subs: &'a mut SubstitutionTable, input: IndexStr<'b>) -> Result<($typename, IndexStr<'b>)> { try_begin_parse!(stringify!($typename), ctx, input); let mut found_prefix = false; $( if let Some((head, tail)) = input.try_split_at($mangled.len()) { if head.as_ref() == $mangled { return Ok(($typename::$variant, tail)); } } else { found_prefix |= 0 < input.len() && input.len() < $mangled.len() && input.as_ref() == &$mangled[..input.len()]; } )* if input.is_empty() || found_prefix { Err(error::Error::UnexpectedEnd) } else { Err(error::Error::UnexpectedText) } } } impl<'subs, W> Demangle<'subs, W> for $typename where W: 'subs + DemangleWrite, { fn demangle<'prev, 'ctx>( &'subs self, ctx: &'ctx mut DemangleContext<'subs, W>, scope: Option> ) -> fmt::Result { let ctx = try_begin_demangle!(self, ctx, scope); write!(ctx, "{}", match *self { $( $typename::$variant => $printable ),* }) } } impl $typename { #[allow(dead_code)] #[inline] fn starts_with(byte: u8) -> bool { $( if $mangled[0] == byte { return true; } )* false } } }; ( $(#[$attr:meta])* pub enum $typename:ident { $($variant:ident ( $mangled:expr, $printable:expr, $userdata:expr)),* } impl $typename2:ident { fn $fn_name:ident(&self) -> $userdata_ty:ty; } ) => { define_vocabulary! { $(#[$attr])* pub enum $typename { $( $variant ( $mangled, $printable ) ),* } } impl $typename2 { fn $fn_name(&self) -> $userdata_ty { match *self { $( $typename2::$variant => $userdata, )* } } } }; } /// The root AST node, and starting production. /// /// ```text /// ::= _Z []* /// ::= ___Z /// ::= /// /// ::= _block_invoke /// ::= _block_invoke+ /// ::= _block_invoke_+ /// ``` #[derive(Clone, Debug, PartialEq, Eq)] pub enum MangledName { /// The encoding of the mangled symbol name. Encoding(Encoding, Vec), /// The encoding of the mangled symbol name. BlockInvoke(Encoding, Option), /// A top-level type. Technically not allowed by the standard, however in /// practice this can happen, and is tested for by libiberty. Type(TypeHandle), /// A global constructor or destructor. This is another de facto standard /// extension (I think originally from `g++`?) that is not actually part of /// the standard proper. GlobalCtorDtor(GlobalCtorDtor), } impl Parse for MangledName { fn parse<'a, 'b>( ctx: &'a ParseContext, subs: &'a mut SubstitutionTable, input: IndexStr<'b>, ) -> Result<(MangledName, IndexStr<'b>)> { try_begin_parse!("MangledName", ctx, input); if let Ok(tail) = consume(b"_Z", input).or_else(|_| consume(b"__Z", input)) { let (encoding, tail) = Encoding::parse(ctx, subs, tail)?; let (clone_suffixes, tail) = zero_or_more(ctx, subs, tail)?; return Ok((MangledName::Encoding(encoding, clone_suffixes), tail)); } if let Ok(tail) = consume(b"___Z", input).or_else(|_| consume(b"____Z", input)) { let (encoding, tail) = Encoding::parse(ctx, subs, tail)?; let tail = consume(b"_block_invoke", tail)?; let tail_opt = match consume(b"_", tail).or_else(|_| consume(b".", tail)) { Ok(tail) => Some(parse_number(10, false, tail)?), Err(_) => parse_number(10, false, tail).ok(), }; let (digits, tail) = match tail_opt { Some((digits, tail)) => (Some(digits), tail), None => (None, tail), }; return Ok((MangledName::BlockInvoke(encoding, digits), tail)); } if let Ok(tail) = consume(b"_GLOBAL_", input) { let (global_ctor_dtor, tail) = GlobalCtorDtor::parse(ctx, subs, tail)?; return Ok((MangledName::GlobalCtorDtor(global_ctor_dtor), tail)); } // The libiberty tests also specify that a type can be top level, // and they are not prefixed with "_Z". let (ty, tail) = TypeHandle::parse(ctx, subs, input)?; Ok((MangledName::Type(ty), tail)) } } impl<'subs, W> Demangle<'subs, W> for MangledName where W: 'subs + DemangleWrite, { fn demangle<'prev, 'ctx>( &'subs self, ctx: &'ctx mut DemangleContext<'subs, W>, scope: Option>, ) -> fmt::Result { let ctx = try_begin_demangle!(self, ctx, scope); match *self { MangledName::Encoding(ref enc, ref cs) => { enc.demangle(ctx, scope)?; if !cs.is_empty() && ctx.show_params { for clone_suffix in cs { clone_suffix.demangle(ctx, scope)?; } } Ok(()) } MangledName::BlockInvoke(ref enc, _) => { write!(ctx, "invocation function for block in ")?; enc.demangle(ctx, scope)?; Ok(()) } MangledName::Type(ref ty) => ty.demangle(ctx, scope), MangledName::GlobalCtorDtor(ref gcd) => gcd.demangle(ctx, scope), } } } /// The `` production. /// /// ```text /// ::= /// ::= /// ::= /// ``` #[derive(Clone, Debug, PartialEq, Eq)] pub enum Encoding { /// An encoded function. Function(Name, BareFunctionType), /// An encoded static variable. Data(Name), /// A special encoding. Special(SpecialName), } impl Parse for Encoding { fn parse<'a, 'b>( ctx: &'a ParseContext, subs: &'a mut SubstitutionTable, input: IndexStr<'b>, ) -> Result<(Encoding, IndexStr<'b>)> { try_begin_parse!("Encoding", ctx, input); if let Ok((name, tail)) = try_recurse!(Name::parse(ctx, subs, input)) { if let Ok((ty, tail)) = try_recurse!(BareFunctionType::parse(ctx, subs, tail)) { return Ok((Encoding::Function(name, ty), tail)); } else { return Ok((Encoding::Data(name), tail)); } } let (name, tail) = SpecialName::parse(ctx, subs, input)?; Ok((Encoding::Special(name), tail)) } } impl<'subs, W> Demangle<'subs, W> for Encoding where W: 'subs + DemangleWrite, { fn demangle<'prev, 'ctx>( &'subs self, ctx: &'ctx mut DemangleContext<'subs, W>, scope: Option>, ) -> fmt::Result { let ctx = try_begin_demangle!(self, ctx, scope); inner_barrier!(ctx); match *self { Encoding::Function(ref name, ref fun_ty) => { // Even if this function takes no args and doesn't have a return // value (see below), it will have the void parameter. debug_assert!(!fun_ty.0.is_empty()); let scope = if let Some(leaf) = name.get_leaf_name(ctx.subs) { match leaf { LeafName::SourceName(leaf) => scope.push(leaf), LeafName::WellKnownComponent(leaf) => scope.push(leaf), LeafName::Closure(leaf) => scope.push(leaf), LeafName::UnnamedType(leaf) => scope.push(leaf), } } else { scope }; // Whether the first type in the BareFunctionType is a return // type or parameter depends on the context in which it // appears. // // * Templates and functions in a type or parameter position // have return types, unless they are constructors, destructors, // or conversion operator functions. // // * Non-template functions that are not in a type or parameter // position do not have a return type. // // We know we are not printing a type, so we only need to check // whether this is a template. // // For the details, see // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.function-type let scope = if let Some(template_args) = name.get_template_args(ctx.subs) { let scope = scope.push(template_args); if ctx.show_return_type && !name.is_ctor_dtor_conversion(ctx.subs) { fun_ty.0[0].demangle(ctx, scope)?; write!(ctx, " ")?; } scope } else { scope }; if ctx.show_params { ctx.push_inner(self); name.demangle(ctx, scope)?; if ctx.pop_inner_if(self) { self.demangle_as_inner(ctx, scope)?; } } else { name.demangle(ctx, scope)?; } Ok(()) } Encoding::Data(ref name) => name.demangle(ctx, scope), Encoding::Special(ref name) => name.demangle(ctx, scope), } } } impl<'subs, W> DemangleAsInner<'subs, W> for Encoding where W: 'subs + DemangleWrite, { fn demangle_as_inner<'prev, 'ctx>( &'subs self, ctx: &'ctx mut DemangleContext<'subs, W>, scope: Option>, ) -> fmt::Result { if let Encoding::Function(ref name, ref fun_ty) = *self { let (scope, function_args) = if let Some(template_args) = name.get_template_args(ctx.subs) { let scope = scope.push(template_args); let function_args = FunctionArgListAndReturnType::new(&fun_ty.0); (scope, function_args as &dyn DemangleAsInner) } else { let function_args = FunctionArgList::new(&fun_ty.0); (scope, function_args as &dyn DemangleAsInner) }; function_args.demangle_as_inner(ctx, scope) } else { unreachable!("we only push Encoding::Function onto the inner stack"); } } } /// ::= [ . ] [ . ]* #[derive(Clone, Debug, PartialEq, Eq)] pub struct CloneSuffix(CloneTypeIdentifier, Vec); impl Parse for CloneSuffix { fn parse<'a, 'b>( ctx: &'a ParseContext, subs: &'a mut SubstitutionTable, input: IndexStr<'b>, ) -> Result<(CloneSuffix, IndexStr<'b>)> { try_begin_parse!("CloneSuffix", ctx, input); let tail = consume(b".", input)?; let (identifier, mut tail) = CloneTypeIdentifier::parse(ctx, subs, tail)?; let mut numbers = Vec::with_capacity(1); while let Ok((n, t)) = consume(b".", tail).and_then(|t| parse_number(10, false, t)) { numbers.push(n); tail = t; } let clone_suffix = CloneSuffix(identifier, numbers); Ok((clone_suffix, tail)) } } impl<'subs, W> Demangle<'subs, W> for CloneSuffix where W: 'subs + DemangleWrite, { fn demangle<'prev, 'ctx>( &'subs self, ctx: &'ctx mut DemangleContext<'subs, W>, scope: Option>, ) -> fmt::Result { let ctx = try_begin_demangle!(self, ctx, scope); write!(ctx, " [clone")?; self.0.demangle(ctx, scope)?; for nonnegative in &self.1 { write!(ctx, ".{}", nonnegative)?; } write!(ctx, "]")?; Ok(()) } } /// A global constructor or destructor. #[derive(Clone, Debug, PartialEq, Eq)] pub enum GlobalCtorDtor { /// A global constructor. Ctor(Box), /// A global destructor. Dtor(Box), } impl Parse for GlobalCtorDtor { fn parse<'a, 'b>( ctx: &'a ParseContext, subs: &'a mut SubstitutionTable, input: IndexStr<'b>, ) -> Result<(GlobalCtorDtor, IndexStr<'b>)> { try_begin_parse!("GlobalCtorDtor", ctx, input); let tail = match input.next_or(error::Error::UnexpectedEnd)? { (b'_', t) | (b'.', t) | (b'$', t) => t, _ => return Err(error::Error::UnexpectedText), }; match tail.next_or(error::Error::UnexpectedEnd)? { (b'I', tail) => { let tail = consume(b"_", tail)?; let (name, tail) = MangledName::parse(ctx, subs, tail)?; Ok((GlobalCtorDtor::Ctor(Box::new(name)), tail)) } (b'D', tail) => { let tail = consume(b"_", tail)?; let (name, tail) = MangledName::parse(ctx, subs, tail)?; Ok((GlobalCtorDtor::Dtor(Box::new(name)), tail)) } _ => Err(error::Error::UnexpectedText), } } } impl<'subs, W> Demangle<'subs, W> for GlobalCtorDtor where W: 'subs + DemangleWrite, { fn demangle<'prev, 'ctx>( &'subs self, ctx: &'ctx mut DemangleContext<'subs, W>, scope: Option>, ) -> fmt::Result { let ctx = try_begin_demangle!(self, ctx, scope); inner_barrier!(ctx); let saved_show_params = ctx.show_params; ctx.show_params = true; let ret = match *self { GlobalCtorDtor::Ctor(ref name) => { write!(ctx, "global constructors keyed to ")?; name.demangle(ctx, scope) } GlobalCtorDtor::Dtor(ref name) => { write!(ctx, "global destructors keyed to ")?; name.demangle(ctx, scope) } }; ctx.show_params = saved_show_params; ret } } /// The `` production. /// /// ```text /// ::= /// ::= /// ::= /// ::= /// ``` #[derive(Clone, Debug, PartialEq, Eq)] pub enum Name { /// A nested name Nested(NestedName), /// An unscoped name. Unscoped(UnscopedName), /// An unscoped template. UnscopedTemplate(UnscopedTemplateNameHandle, TemplateArgs), /// A local name. Local(LocalName), } impl Parse for Name { fn parse<'a, 'b>( ctx: &'a ParseContext, subs: &'a mut SubstitutionTable, input: IndexStr<'b>, ) -> Result<(Name, IndexStr<'b>)> { try_begin_parse!("Name", ctx, input); if let Ok((name, tail)) = try_recurse!(NestedName::parse(ctx, subs, input)) { return Ok((Name::Nested(name), tail)); } if let Ok((name, tail)) = try_recurse!(UnscopedName::parse(ctx, subs, input)) { if tail.peek() == Some(b'I') { let name = UnscopedTemplateName(name); let idx = subs.insert(Substitutable::UnscopedTemplateName(name)); let handle = UnscopedTemplateNameHandle::BackReference(idx); let (args, tail) = TemplateArgs::parse(ctx, subs, tail)?; return Ok((Name::UnscopedTemplate(handle, args), tail)); } else { return Ok((Name::Unscoped(name), tail)); } } if let Ok((name, tail)) = try_recurse!(UnscopedTemplateNameHandle::parse(ctx, subs, input)) { let (args, tail) = TemplateArgs::parse(ctx, subs, tail)?; return Ok((Name::UnscopedTemplate(name, args), tail)); } let (name, tail) = LocalName::parse(ctx, subs, input)?; Ok((Name::Local(name), tail)) } } impl<'subs, W> Demangle<'subs, W> for Name where W: 'subs + DemangleWrite, { fn demangle<'prev, 'ctx>( &'subs self, ctx: &'ctx mut DemangleContext<'subs, W>, scope: Option>, ) -> fmt::Result { let ctx = try_begin_demangle!(self, ctx, scope); match *self { Name::Nested(ref nested) => nested.demangle(ctx, scope), Name::Unscoped(ref unscoped) => unscoped.demangle(ctx, scope), Name::UnscopedTemplate(ref template, ref args) => { template.demangle(ctx, scope.push(args))?; args.demangle(ctx, scope) } Name::Local(ref local) => local.demangle(ctx, scope), } } } impl GetTemplateArgs for Name { fn get_template_args<'a>(&'a self, subs: &'a SubstitutionTable) -> Option<&'a TemplateArgs> { match *self { Name::UnscopedTemplate(_, ref args) => Some(args), Name::Nested(ref nested) => nested.get_template_args(subs), Name::Local(ref local) => local.get_template_args(subs), Name::Unscoped(_) => None, } } } impl<'a> GetLeafName<'a> for Name { fn get_leaf_name(&'a self, subs: &'a SubstitutionTable) -> Option> { match *self { Name::UnscopedTemplate(ref templ, _) => templ.get_leaf_name(subs), Name::Nested(ref nested) => nested.get_leaf_name(subs), Name::Unscoped(ref unscoped) => unscoped.get_leaf_name(subs), Name::Local(ref local) => local.get_leaf_name(subs), } } } impl IsCtorDtorConversion for Name { fn is_ctor_dtor_conversion(&self, subs: &SubstitutionTable) -> bool { match *self { Name::Unscoped(ref unscoped) => unscoped.is_ctor_dtor_conversion(subs), Name::Nested(ref nested) => nested.is_ctor_dtor_conversion(subs), Name::Local(_) | Name::UnscopedTemplate(..) => false, } } } /// The `` production. /// /// ```text /// ::= /// ::= St # ::std:: /// ``` #[derive(Clone, Debug, PartialEq, Eq)] pub enum UnscopedName { /// An unqualified name. Unqualified(UnqualifiedName), /// A name within the `std::` namespace. Std(UnqualifiedName), } impl Parse for UnscopedName { fn parse<'a, 'b>( ctx: &'a ParseContext, subs: &'a mut SubstitutionTable, input: IndexStr<'b>, ) -> Result<(UnscopedName, IndexStr<'b>)> { try_begin_parse!("UnscopedName", ctx, input); if let Ok(tail) = consume(b"St", input) { let (name, tail) = UnqualifiedName::parse(ctx, subs, tail)?; return Ok((UnscopedName::Std(name), tail)); } let (name, tail) = UnqualifiedName::parse(ctx, subs, input)?; Ok((UnscopedName::Unqualified(name), tail)) } } impl<'subs, W> Demangle<'subs, W> for UnscopedName where W: 'subs + DemangleWrite, { fn demangle<'prev, 'ctx>( &'subs self, ctx: &'ctx mut DemangleContext<'subs, W>, scope: Option>, ) -> fmt::Result { let ctx = try_begin_demangle!(self, ctx, scope); match *self { UnscopedName::Unqualified(ref unqualified) => unqualified.demangle(ctx, scope), UnscopedName::Std(ref std) => { write!(ctx, "std::")?; std.demangle(ctx, scope) } } } } impl<'a> GetLeafName<'a> for UnscopedName { fn get_leaf_name(&'a self, subs: &'a SubstitutionTable) -> Option> { match *self { UnscopedName::Unqualified(ref name) | UnscopedName::Std(ref name) => { name.get_leaf_name(subs) } } } } impl IsCtorDtorConversion for UnscopedName { fn is_ctor_dtor_conversion(&self, subs: &SubstitutionTable) -> bool { match *self { UnscopedName::Unqualified(ref name) | UnscopedName::Std(ref name) => { name.is_ctor_dtor_conversion(subs) } } } } /// The `` production. /// /// ```text /// ::= /// ::= /// ``` #[derive(Clone, Debug, PartialEq, Eq)] pub struct UnscopedTemplateName(UnscopedName); define_handle! { /// A handle to an `UnscopedTemplateName`. pub enum UnscopedTemplateNameHandle { /// A handle to some `` component that isn't by itself /// substitutable. extra NonSubstitution(NonSubstitution), } } impl Parse for UnscopedTemplateNameHandle { fn parse<'a, 'b>( ctx: &'a ParseContext, subs: &'a mut SubstitutionTable, input: IndexStr<'b>, ) -> Result<(UnscopedTemplateNameHandle, IndexStr<'b>)> { try_begin_parse!("UnscopedTemplateNameHandle", ctx, input); if let Ok((name, tail)) = try_recurse!(UnscopedName::parse(ctx, subs, input)) { let name = UnscopedTemplateName(name); let idx = subs.insert(Substitutable::UnscopedTemplateName(name)); let handle = UnscopedTemplateNameHandle::BackReference(idx); return Ok((handle, tail)); } let (sub, tail) = Substitution::parse(ctx, subs, input)?; match sub { Substitution::WellKnown(component) => { Ok((UnscopedTemplateNameHandle::WellKnown(component), tail)) } Substitution::BackReference(idx) => { // TODO: should this check/assert that subs[idx] is an // UnscopedTemplateName? Ok((UnscopedTemplateNameHandle::BackReference(idx), tail)) } } } } impl<'subs, W> Demangle<'subs, W> for UnscopedTemplateName where W: 'subs + DemangleWrite, { fn demangle<'prev, 'ctx>( &'subs self, ctx: &'ctx mut DemangleContext<'subs, W>, scope: Option>, ) -> fmt::Result { let ctx = try_begin_demangle!(self, ctx, scope); self.0.demangle(ctx, scope) } } impl<'a> GetLeafName<'a> for UnscopedTemplateName { fn get_leaf_name(&'a self, subs: &'a SubstitutionTable) -> Option> { self.0.get_leaf_name(subs) } } /// The `` production. /// /// ```text /// ::= N [] [] E /// ::= N [] [] E /// ``` #[derive(Clone, Debug, PartialEq, Eq)] pub enum NestedName { /// A nested name. Unqualified( CvQualifiers, Option, PrefixHandle, UnqualifiedName, ), /// A nested template name. The `` are part of the `PrefixHandle`. Template(CvQualifiers, Option, PrefixHandle), } impl Parse for NestedName { fn parse<'a, 'b>( ctx: &'a ParseContext, subs: &'a mut SubstitutionTable, input: IndexStr<'b>, ) -> Result<(NestedName, IndexStr<'b>)> { try_begin_parse!("NestedName", ctx, input); let tail = consume(b"N", input)?; let (cv_qualifiers, tail) = if let Ok((q, tail)) = try_recurse!(CvQualifiers::parse(ctx, subs, tail)) { (q, tail) } else { (Default::default(), tail) }; let (ref_qualifier, tail) = if let Ok((r, tail)) = try_recurse!(RefQualifier::parse(ctx, subs, tail)) { (Some(r), tail) } else { (None, tail) }; let (prefix, tail) = PrefixHandle::parse(ctx, subs, tail)?; let tail = consume(b"E", tail)?; let substitutable = match prefix { PrefixHandle::BackReference(idx) => subs.get(idx), PrefixHandle::NonSubstitution(NonSubstitution(idx)) => subs.get_non_substitution(idx), PrefixHandle::WellKnown(_) => None, }; match substitutable { Some(&Substitutable::Prefix(Prefix::Nested(ref prefix, ref name))) => Ok(( NestedName::Unqualified(cv_qualifiers, ref_qualifier, prefix.clone(), name.clone()), tail, )), Some(&Substitutable::Prefix(Prefix::Template(..))) => Ok(( NestedName::Template(cv_qualifiers, ref_qualifier, prefix), tail, )), _ => Err(error::Error::UnexpectedText), } } } impl NestedName { /// Get the CV-qualifiers for this name. pub fn cv_qualifiers(&self) -> &CvQualifiers { match *self { NestedName::Unqualified(ref q, ..) | NestedName::Template(ref q, ..) => q, } } /// Get the ref-qualifier for this name, if one exists. pub fn ref_qualifier(&self) -> Option<&RefQualifier> { match *self { NestedName::Unqualified(_, Some(ref r), ..) | NestedName::Template(_, Some(ref r), ..) => Some(r), _ => None, } } // Not public because the prefix means different things for different // variants, and for `::Template` it actually contains part of what // conceptually belongs to ``. fn prefix(&self) -> &PrefixHandle { match *self { NestedName::Unqualified(_, _, ref p, _) | NestedName::Template(_, _, ref p) => p, } } } impl<'subs, W> Demangle<'subs, W> for NestedName where W: 'subs + DemangleWrite, { fn demangle<'prev, 'ctx>( &'subs self, ctx: &'ctx mut DemangleContext<'subs, W>, scope: Option>, ) -> fmt::Result { let ctx = try_begin_demangle!(self, ctx, scope); match *self { NestedName::Unqualified(_, _, ref p, ref name) => { ctx.push_demangle_node(DemangleNodeType::NestedName); p.demangle(ctx, scope)?; if name.accepts_double_colon() { ctx.write_str("::")?; } name.demangle(ctx, scope)?; ctx.pop_demangle_node(); } NestedName::Template(_, _, ref p) => { ctx.is_template_prefix_in_nested_name = true; p.demangle(ctx, scope)?; ctx.is_template_prefix_in_nested_name = false; } } if let Some(inner) = ctx.pop_inner() { inner.demangle_as_inner(ctx, scope)?; } if self.cv_qualifiers() != &CvQualifiers::default() && ctx.show_params { self.cv_qualifiers().demangle(ctx, scope)?; } if let Some(ref refs) = self.ref_qualifier() { ctx.ensure_space()?; refs.demangle(ctx, scope)?; } Ok(()) } } impl GetTemplateArgs for NestedName { fn get_template_args<'a>(&'a self, subs: &'a SubstitutionTable) -> Option<&'a TemplateArgs> { match *self { NestedName::Template(_, _, ref prefix) => prefix.get_template_args(subs), _ => None, } } } impl<'a> GetLeafName<'a> for NestedName { fn get_leaf_name(&'a self, subs: &'a SubstitutionTable) -> Option> { match *self { NestedName::Unqualified(_, _, ref prefix, ref name) => name .get_leaf_name(subs) .or_else(|| prefix.get_leaf_name(subs)), NestedName::Template(_, _, ref prefix) => prefix.get_leaf_name(subs), } } } impl IsCtorDtorConversion for NestedName { fn is_ctor_dtor_conversion(&self, subs: &SubstitutionTable) -> bool { self.prefix().is_ctor_dtor_conversion(subs) } } /// The `` production. /// /// ```text /// ::= /// ::= /// ::= /// ::= /// ::= /// ::= /// ::= /// /// ::=