diff --git a/src/ast.rs b/src/ast.rs index 5392213..3551786 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -4146,14 +4146,71 @@ impl<'a> GetLeafName<'a> for QualifiedBuiltin { } } +/// The `` production. +/// +/// ::= Do # non-throwing exception-specification (e.g., noexcept, throw()) +/// ::= DO E # computed (instantiation-dependent) noexcept +/// ::= Dw + E # dynamic exception specification with instantiation-dependent types +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum ExceptionSpec { + /// noexcept + NoExcept, + /// noexcept(expression) + Computed(Expression), + // Dynamic exception specification is deprecated, lets see if we can get away with + // not implementing it. +} + +impl Parse for ExceptionSpec { + fn parse<'a, 'b>( + ctx: &'a ParseContext, + subs: &'a mut SubstitutionTable, + input: IndexStr<'b>, + ) -> Result<(ExceptionSpec, IndexStr<'b>)> { + try_begin_parse!("ExceptionSpec", ctx, input); + + if let Ok(tail) = consume(b"Do", input) { + return Ok((ExceptionSpec::NoExcept, tail)); + } + + let tail = consume(b"DO", input)?; + let (expr, tail) = Expression::parse(ctx, subs, tail)?; + let tail = consume(b"E", tail)?; + Ok((ExceptionSpec::Computed(expr), tail)) + } +} + +impl<'subs, W> Demangle<'subs, W> for ExceptionSpec +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 { + ExceptionSpec::NoExcept => write!(ctx, "noexcept"), + ExceptionSpec::Computed(ref expr) => { + write!(ctx, "noexcept(")?; + expr.demangle(ctx, scope)?; + write!(ctx, ")") + } + } + } +} + /// The `` production. /// /// ```text -/// ::= [] [Dx] F [Y] [] E +/// ::= [] [exception-spec] [Dx] F [Y] [] E /// ``` #[derive(Clone, Debug, PartialEq, Eq)] pub struct FunctionType { cv_qualifiers: CvQualifiers, + exception_spec: Option, transaction_safe: bool, extern_c: bool, bare: BareFunctionType, @@ -4175,6 +4232,13 @@ impl Parse for FunctionType { (Default::default(), input) }; + let (exception_spec, tail) = + if let Ok((exception_spec, tail)) = ExceptionSpec::parse(ctx, subs, tail) { + (Some(exception_spec), tail) + } else { + (None, tail) + }; + let (transaction_safe, tail) = if let Ok(tail) = consume(b"Dx", tail) { (true, tail) } else { @@ -4202,6 +4266,7 @@ impl Parse for FunctionType { let func_ty = FunctionType { cv_qualifiers: cv_qualifiers, + exception_spec: exception_spec, transaction_safe: transaction_safe, extern_c: extern_c, bare: bare, @@ -4227,6 +4292,11 @@ where if ctx.pop_inner_if(self) { self.demangle_as_inner(ctx, scope)?; } + if let Some(ref es) = self.exception_spec { + // Print out a space before printing "noexcept" + ctx.ensure_space()?; + es.demangle(ctx, scope)?; + } Ok(()) } } @@ -7792,12 +7862,12 @@ mod tests { use super::{ ArrayType, BareFunctionType, BaseUnresolvedName, BuiltinType, CallOffset, ClassEnumType, ClosureTypeName, CtorDtorName, CvQualifiers, DataMemberPrefix, Decltype, DestructorName, - Discriminator, Encoding, ExprPrimary, Expression, FunctionParam, FunctionType, - GlobalCtorDtor, Identifier, Initializer, LambdaSig, LocalName, MangledName, MemberName, - Name, NestedName, NonSubstitution, Number, NvOffset, OperatorName, Parse, ParseContext, - PointerToMemberType, Prefix, PrefixHandle, RefQualifier, ResourceName, SeqId, SimpleId, - SimpleOperatorName, SourceName, SpecialName, StandardBuiltinType, Substitution, TaggedName, - TemplateArg, TemplateArgs, TemplateParam, TemplateTemplateParam, + Discriminator, Encoding, ExceptionSpec, ExprPrimary, Expression, FunctionParam, + FunctionType, GlobalCtorDtor, Identifier, Initializer, LambdaSig, LocalName, MangledName, + MemberName, Name, NestedName, NonSubstitution, Number, NvOffset, OperatorName, Parse, + ParseContext, PointerToMemberType, Prefix, PrefixHandle, RefQualifier, ResourceName, SeqId, + SimpleId, SimpleOperatorName, SourceName, SpecialName, StandardBuiltinType, Substitution, + TaggedName, TemplateArg, TemplateArgs, TemplateParam, TemplateTemplateParam, TemplateTemplateParamHandle, Type, TypeHandle, UnnamedTypeName, UnqualifiedName, UnresolvedName, UnresolvedQualifierLevel, UnresolvedType, UnresolvedTypeHandle, UnscopedName, UnscopedTemplateName, UnscopedTemplateNameHandle, VOffset, VectorType, @@ -8649,6 +8719,7 @@ mod tests { volatile: false, const_: false, }, + exception_spec: None, transaction_safe: false, extern_c: false, bare: BareFunctionType(vec![TypeHandle::BackReference(0)]), @@ -8819,6 +8890,28 @@ mod tests { }); } + #[test] + fn parse_exception_spec() { + assert_parse!(ExceptionSpec { + Ok => { + b"Do..." => { + ExceptionSpec::NoExcept, + b"..." + } + b"DOtrE..." => { + ExceptionSpec::Computed(Expression::Rethrow), + b"..." + } + } + Err => { + b"DOtre" => Error::UnexpectedText, + b"DOE" => Error::UnexpectedText, + b"D" => Error::UnexpectedEnd, + b"" => Error::UnexpectedEnd, + } + }); + } + #[test] fn parse_function_type() { assert_parse!(FunctionType { @@ -8835,6 +8928,7 @@ mod tests { volatile: false, const_: true, }, + exception_spec: None, transaction_safe: true, extern_c: true, bare: BareFunctionType(vec![TypeHandle::BackReference(0)]), @@ -8850,6 +8944,7 @@ mod tests { volatile: false, const_: false, }, + exception_spec: None, transaction_safe: true, extern_c: true, bare: BareFunctionType(vec![TypeHandle::BackReference(0)]), @@ -8865,6 +8960,7 @@ mod tests { volatile: false, const_: false, }, + exception_spec: None, transaction_safe: false, extern_c: true, bare: BareFunctionType(vec![TypeHandle::BackReference(0)]), @@ -8880,6 +8976,7 @@ mod tests { volatile: false, const_: false, }, + exception_spec: None, transaction_safe: false, extern_c: false, bare: BareFunctionType(vec![TypeHandle::BackReference(0)]), @@ -8895,6 +8992,7 @@ mod tests { volatile: false, const_: false, }, + exception_spec: None, transaction_safe: false, extern_c: false, bare: BareFunctionType(vec![TypeHandle::BackReference(0)]), diff --git a/tests/tests.rs b/tests/tests.rs index 8e908e1..ebe18ab 100755 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -600,3 +600,8 @@ demangles!( _ZN4glslL7combineIhLi2EEEDvmlT0_Li4E_T_DvT0__S1_S3_S3_S3_, "unsigned char __vector((2)*(4)) glsl::combine(unsigned char __vector(2), unsigned char __vector(2), unsigned char __vector(2), unsigned char __vector(2))" ); + +demangles!( + _Z14WasmMemoryCopyIPhPDoFPvS1_PKvmEjEiP9JSContextT_mT1_S9_S9_T0_, + "int WasmMemoryCopy(JSContext*, unsigned char*, unsigned long, unsigned int, unsigned int, unsigned int, void* (*)(void*, void const*, unsigned long) noexcept)" +);