Skip to content

Commit faa220f

Browse files
committed
Add _BitInt to substitution table for compatibility with clang
1 parent 6fc3a53 commit faa220f

File tree

2 files changed

+43
-3
lines changed

2 files changed

+43
-3
lines changed

src/ast.rs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3619,6 +3619,11 @@ pub enum Type {
36193619

36203620
/// A pack expansion.
36213621
PackExpansion(TypeHandle),
3622+
3623+
/// Builtin type eligible for substitutions, e.g. vendor extended type or _BitInt(N).
3624+
/// Note: most builtin types are excluded from substitutions, and we store them directly
3625+
/// in TypeHandle without creating a Type.
3626+
Builtin(BuiltinType),
36223627
}
36233628

36243629
define_handle! {
@@ -3665,6 +3670,30 @@ impl Parse for TypeHandle {
36653670
if let Ok((builtin, tail)) = try_recurse!(BuiltinType::parse(ctx, subs, input)) {
36663671
// Builtin types are one of two exceptions that do not end up in the
36673672
// substitutions table.
3673+
3674+
// But there are exceptions to the exception:
3675+
// * "vendor extended type" builtin types do go in the substitution table.
3676+
// * Quirk: clang treats `_BitInt` types (`DB<n>_`, `DU<n>_`) as substitutable,
3677+
// even though they're <builtin-type>. This contradicts the current Itanium ABI spec.
3678+
// This behavior is consistent between clang's mangler and demangler.
3679+
// It seems more likely that the ABI spec will be changed to match clang, rather than
3680+
// the other way around. So we do what clang does and put _BitInt-s into the substitution table.
3681+
let substitutable = match &builtin {
3682+
BuiltinType::Parametric(p) => match p {
3683+
ParametricBuiltinType::SignedBitInt(_) |
3684+
ParametricBuiltinType::UnsignedBitInt(_) |
3685+
ParametricBuiltinType::SignedBitIntExpression(_) |
3686+
ParametricBuiltinType::UnsignedBitIntExpression(_) => true,
3687+
_ => false,
3688+
}
3689+
BuiltinType::Extension(_) => true,
3690+
_ => false,
3691+
};
3692+
if substitutable {
3693+
let ty = Type::Builtin(builtin);
3694+
return insert_and_return_handle(ty, subs, tail);
3695+
}
3696+
36683697
let handle = TypeHandle::Builtin(builtin);
36693698
return Ok((handle, tail));
36703699
}
@@ -3908,6 +3937,7 @@ where
39083937
}
39093938
Ok(())
39103939
}
3940+
Type::Builtin(ref builtin) => builtin.demangle(ctx, scope),
39113941
}
39123942
}
39133943
}
@@ -4309,6 +4339,7 @@ impl Parse for ParametricBuiltinType {
43094339
Ok((t, input))
43104340
} else if allow_expression {
43114341
let (expr, input) = Expression::parse(ctx, subs, input)?;
4342+
let input = consume(b"_", input)?;
43124343
let expr = Box::new(expr);
43134344
let t = match ch {
43144345
b'B' => ParametricBuiltinType::SignedBitIntExpression(expr),
@@ -4336,10 +4367,10 @@ where
43364367
match *self {
43374368
Self::FloatN(n) => write!(ctx, "_Float{}", n),
43384369
Self::FloatNx(n) => write!(ctx, "_Float{}x", n),
4339-
Self::SignedBitInt(n) => write!(ctx, "signed _BitInt({})", n),
4370+
Self::SignedBitInt(n) => write!(ctx, "_BitInt({})", n),
43404371
Self::UnsignedBitInt(n) => write!(ctx, "unsigned _BitInt({})", n),
43414372
Self::SignedBitIntExpression(ref expr) => {
4342-
write!(ctx, "signed _BitInt(")?;
4373+
write!(ctx, "_BitInt(")?;
43434374
expr.demangle(ctx, scope)?;
43444375
write!(ctx, ")")
43454376
}
@@ -11615,7 +11646,7 @@ mod tests {
1161511646
BuiltinType::Parametric(ParametricBuiltinType::SignedBitInt(8)),
1161611647
b"..."
1161711648
}
11618-
b"DUsZT_" => {
11649+
b"DUsZT__" => {
1161911650
BuiltinType::Parametric(ParametricBuiltinType::UnsignedBitIntExpression(Box::new(Expression::SizeofTemplatePack(TemplateParam(0))))),
1162011651
b""
1162111652
}

tests/tests.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,15 @@ demangles!(
682682
"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"
683683
);
684684

685+
// _BitInt(N) is substitutable, but _FloatN is not.
686+
demangles!(_Z1fDB8_S_, "f(_BitInt(8), _BitInt(8))");
687+
demangles!(_Z1fDU8_S_, "f(unsigned _BitInt(8), unsigned _BitInt(8))");
688+
demangles!(_Z1fILi8EEvDBT__S0_, "void f<8>(_BitInt(8), _BitInt(8))");
689+
demangles!(_Z1fDF32_2xxS_, "f(_Float32, xx, xx)");
690+
691+
// Vendor extended builtin type is substitutable.
692+
demangles!(_Z1fu2xxS_, "f(xx, xx)");
693+
685694
// This symbol previously ran into some mutual recursion and unbounded growth of the substitution table.
686695
// See <https://github.com/gimli-rs/cpp_demangle/issues/277> and <https://github.com/getsentry/symbolic/issues/477>
687696
#[test]

0 commit comments

Comments
 (0)