@@ -18,3 +18,78 @@ pub type uint16_t = u16;
1818pub type uint32_t = u32 ;
1919#[ deprecated( since = "0.2.55" , note = "Use u64 instead." ) ]
2020pub type uint64_t = u64 ;
21+
22+ cfg_if ! {
23+ if #[ cfg( all( libc_int128, target_arch = "aarch64" , not( target_os = "windows" ) ) ) ] {
24+ // This introduces partial support for FFI with __int128 and
25+ // equivalent types on platforms where Rust's definition is validated
26+ // to match the standard C ABI of that platform.
27+ //
28+ // Rust does not guarantee u128/i128 are sound for FFI, and its
29+ // definitions are in fact known to be incompatible. [0]
30+ //
31+ // However these problems aren't fundamental, and are just platform
32+ // inconsistencies. Specifically at the time of this writing:
33+ //
34+ // * For x64 SysV ABIs (everything but Windows), the types are underaligned.
35+ // * For all Windows ABIs, Microsoft doesn't actually officially define __int128,
36+ // and as a result different implementations don't actually agree on its ABI.
37+ //
38+ // But on the other major aarch64 platforms (android, linux, ios, macos) we have
39+ // validated that rustc has the right ABI for these types. This is important because
40+ // aarch64 uses these types in some fundamental OS types like user_fpsimd_struct,
41+ // which represents saved simd registers.
42+ //
43+ // Any API which uses these types will need to `#[ignore(improper_ctypes)]`
44+ // until the upstream rust issue is resolved, but this at least lets us make
45+ // progress on platforms where this type is important.
46+ //
47+ // The supported architectures and OSes is intentionally very restricted,
48+ // as careful work needs to be done to verify that a particular platform
49+ // has a conformant ABI.
50+ //
51+ // [0]: https://github.com/rust-lang/rust/issues/54341
52+
53+ /// C `__int128` (a GCC extension that's part of many ABIs)
54+ pub type __int128 = i128 ;
55+ /// C `unsigned __int128` (a GCC extension that's part of many ABIs)
56+ pub type __uint128 = u128 ;
57+ /// C __int128_t (alternate name for [__int128][])
58+ pub type __int128_t = i128 ;
59+ /// C __uint128_t (alternate name for [__uint128][])
60+ pub type __uint128_t = u128 ;
61+
62+ cfg_if! {
63+ if #[ cfg( libc_const_assert) ] {
64+ // NOTE: if you add more platforms to here, you may need to cfg
65+ // these consts. They should always match the platform's values
66+ // for `sizeof(__int128)` and `_Alignof(__int128)`.
67+ const _SIZE_128: usize = 16 ;
68+ const _ALIGN_128: usize = 16 ;
69+
70+ /// Since Rust doesn't officially guarantee that these types
71+ /// have compatible ABIs, we const assert that these values have the
72+ /// known size/align of the target platform's libc. If rustc ever
73+ /// tries to regress things, it will cause a compilation error.
74+ ///
75+ /// This isn't a bullet-proof solution because e.g. it doesn't
76+ /// catch the fact that llvm and gcc disagree on how x64 __int128
77+ /// is actually *passed* on the stack (clang underaligns it for
78+ /// the same reason that rustc *never* properly aligns it).
79+ const _ASSERT_128_COMPAT: ( ) = {
80+ assert!( core:: mem:: size_of:: <__int128>( ) == _SIZE_128) ;
81+ assert!( core:: mem:: align_of:: <__int128>( ) == _ALIGN_128) ;
82+
83+ assert!( core:: mem:: size_of:: <__uint128>( ) == _SIZE_128) ;
84+ assert!( core:: mem:: align_of:: <__uint128>( ) == _ALIGN_128) ;
85+
86+ assert!( core:: mem:: size_of:: <__int128_t>( ) == _SIZE_128) ;
87+ assert!( core:: mem:: align_of:: <__int128_t>( ) == _ALIGN_128) ;
88+
89+ assert!( core:: mem:: size_of:: <__uint128_t>( ) == _SIZE_128) ;
90+ assert!( core:: mem:: align_of:: <__uint128_t>( ) == _ALIGN_128) ;
91+ } ;
92+ }
93+ }
94+ }
95+ }
0 commit comments