Skip to content

Commit

Permalink
Support noexcept/noexcept(expression).
Browse files Browse the repository at this point in the history
Issue #273
  • Loading branch information
khuey committed Oct 20, 2022
1 parent 8dfae16 commit 39ffd11
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 7 deletions.
112 changes: 105 additions & 7 deletions src/ast.rs
Expand Up @@ -4146,14 +4146,71 @@ impl<'a> GetLeafName<'a> for QualifiedBuiltin {
}
}

/// The `<exception-spec>` production.
///
/// <exception-spec> ::= Do # non-throwing exception-specification (e.g., noexcept, throw())
/// ::= DO <expression> E # computed (instantiation-dependent) noexcept
/// ::= Dw <type>+ 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<ArgScopeStack<'prev, 'subs>>,
) -> 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 `<function-type>` production.
///
/// ```text
/// <function-type> ::= [<CV-qualifiers>] [Dx] F [Y] <bare-function-type> [<ref-qualifier>] E
/// <function-type> ::= [<CV-qualifiers>] [exception-spec] [Dx] F [Y] <bare-function-type> [<ref-qualifier>] E
/// ```
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FunctionType {
cv_qualifiers: CvQualifiers,
exception_spec: Option<ExceptionSpec>,
transaction_safe: bool,
extern_c: bool,
bare: BareFunctionType,
Expand All @@ -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 {
Expand Down Expand Up @@ -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,
Expand All @@ -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(())
}
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)]),
Expand Down Expand Up @@ -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 {
Expand All @@ -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)]),
Expand All @@ -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)]),
Expand All @@ -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)]),
Expand All @@ -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)]),
Expand All @@ -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)]),
Expand Down
5 changes: 5 additions & 0 deletions tests/tests.rs
Expand Up @@ -600,3 +600,8 @@ demangles!(
_ZN4glslL7combineIhLi2EEEDvmlT0_Li4E_T_DvT0__S1_S3_S3_S3_,
"unsigned char __vector((2)*(4)) glsl::combine<unsigned char, 2>(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<unsigned char*, void* (*)(void*, void const*, unsigned long) noexcept, unsigned int>(JSContext*, unsigned char*, unsigned long, unsigned int, unsigned int, unsigned int, void* (*)(void*, void const*, unsigned long) noexcept)"
);

0 comments on commit 39ffd11

Please sign in to comment.