Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 34 additions & 3 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3619,6 +3619,11 @@ pub enum Type {

/// A pack expansion.
PackExpansion(TypeHandle),

/// Builtin type eligible for substitutions, e.g. vendor extended type or _BitInt(N).
/// Note: most builtin types are excluded from substitutions, and we store them directly
/// in TypeHandle without creating a Type.
Builtin(BuiltinType),
}

define_handle! {
Expand Down Expand Up @@ -3665,6 +3670,30 @@ impl Parse for TypeHandle {
if let Ok((builtin, tail)) = try_recurse!(BuiltinType::parse(ctx, subs, input)) {
// Builtin types are one of two exceptions that do not end up in the
// substitutions table.

// But there are exceptions to the exception:
// * "vendor extended type" builtin types do go in the substitution table.
// * Quirk: clang treats `_BitInt` types (`DB<n>_`, `DU<n>_`) as substitutable,
// even though they're <builtin-type>. This contradicts the current Itanium ABI spec.
// This behavior is consistent between clang's mangler and demangler.
// It seems more likely that the ABI spec will be changed to match clang, rather than
// the other way around. So we do what clang does and put _BitInt-s into the substitution table.
let substitutable = match &builtin {
BuiltinType::Parametric(p) => match p {
ParametricBuiltinType::SignedBitInt(_)
| ParametricBuiltinType::UnsignedBitInt(_)
| ParametricBuiltinType::SignedBitIntExpression(_)
| ParametricBuiltinType::UnsignedBitIntExpression(_) => true,
_ => false,
},
BuiltinType::Extension(_) => true,
_ => false,
};
if substitutable {
let ty = Type::Builtin(builtin);
return insert_and_return_handle(ty, subs, tail);
}

let handle = TypeHandle::Builtin(builtin);
return Ok((handle, tail));
}
Expand Down Expand Up @@ -3908,6 +3937,7 @@ where
}
Ok(())
}
Type::Builtin(ref builtin) => builtin.demangle(ctx, scope),
}
}
}
Expand Down Expand Up @@ -4309,6 +4339,7 @@ impl Parse for ParametricBuiltinType {
Ok((t, input))
} else if allow_expression {
let (expr, input) = Expression::parse(ctx, subs, input)?;
let input = consume(b"_", input)?;
let expr = Box::new(expr);
let t = match ch {
b'B' => ParametricBuiltinType::SignedBitIntExpression(expr),
Expand Down Expand Up @@ -4336,10 +4367,10 @@ where
match *self {
Self::FloatN(n) => write!(ctx, "_Float{}", n),
Self::FloatNx(n) => write!(ctx, "_Float{}x", n),
Self::SignedBitInt(n) => write!(ctx, "signed _BitInt({})", n),
Self::SignedBitInt(n) => write!(ctx, "_BitInt({})", n),
Self::UnsignedBitInt(n) => write!(ctx, "unsigned _BitInt({})", n),
Self::SignedBitIntExpression(ref expr) => {
write!(ctx, "signed _BitInt(")?;
write!(ctx, "_BitInt(")?;
expr.demangle(ctx, scope)?;
write!(ctx, ")")
}
Expand Down Expand Up @@ -11615,7 +11646,7 @@ mod tests {
BuiltinType::Parametric(ParametricBuiltinType::SignedBitInt(8)),
b"..."
}
b"DUsZT_" => {
b"DUsZT__" => {
BuiltinType::Parametric(ParametricBuiltinType::UnsignedBitIntExpression(Box::new(Expression::SizeofTemplatePack(TemplateParam(0))))),
b""
}
Expand Down
9 changes: 9 additions & 0 deletions tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,15 @@ demangles!(
"decltype ((((declval<nlohmann::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> > > const&>)()).(get_impl<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >))((nlohmann::detail::priority_tag<(unsigned int)4>)({}))) nlohmann::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> > >::get<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >() const"
);

// _BitInt(N) is substitutable, but _FloatN is not.
demangles!(_Z1fDB8_S_, "f(_BitInt(8), _BitInt(8))");
demangles!(_Z1fDU8_S_, "f(unsigned _BitInt(8), unsigned _BitInt(8))");
demangles!(_Z1fILi8EEvDBT__S0_, "void f<8>(_BitInt(8), _BitInt(8))");
demangles!(_Z1fDF32_2xxS_, "f(_Float32, xx, xx)");

// Vendor extended builtin type is substitutable.
demangles!(_Z1fu2xxS_, "f(xx, xx)");

// This symbol previously ran into some mutual recursion and unbounded growth of the substitution table.
// See <https://github.com/gimli-rs/cpp_demangle/issues/277> and <https://github.com/getsentry/symbolic/issues/477>
#[test]
Expand Down