1 // Copyright 2022 The Fuchsia Authors 2 // 3 // Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0 4 // <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT 5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option. 6 // This file may not be copied, modified, or distributed except according to 7 // those terms. 8 9 //! Utilities used by macros and by `zerocopy-derive`. 10 //! 11 //! These are defined here `zerocopy` rather than in code generated by macros or 12 //! by `zerocopy-derive` so that they can be compiled once rather than 13 //! recompiled for every invocation (e.g., if they were defined in generated 14 //! code, then deriving `IntoBytes` and `FromBytes` on three different types 15 //! would result in the code in question being emitted and compiled six 16 //! different times). 17 18 #![allow(missing_debug_implementations)] 19 20 // FIXME(#29), FIXME(https://github.com/rust-lang/rust/issues/69835): Remove 21 // this `cfg` when `size_of_val_raw` is stabilized. 22 #[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)] 23 #[cfg(not(target_pointer_width = "16"))] 24 use core::ptr::{self, NonNull}; 25 use core::{marker::PhantomData, mem, num::Wrapping}; 26 27 use crate::{ 28 pointer::{ 29 cast::CastSized, 30 invariant::{Aligned, Initialized, Valid}, 31 BecauseImmutable, 32 }, 33 FromBytes, Immutable, IntoBytes, KnownLayout, Ptr, ReadOnly, TryFromBytes, ValidityError, 34 }; 35 36 /// Projects the type of the field at `Index` in `Self` without regard for field 37 /// privacy. 38 /// 39 /// The `Index` parameter is any sort of handle that identifies the field; its 40 /// definition is the obligation of the implementer. 41 /// 42 /// # Safety 43 /// 44 /// Unsafe code may assume that this accurately reflects the definition of 45 /// `Self`. 46 pub unsafe trait Field<Index> { 47 /// The type of the field at `Index`. 48 type Type: ?Sized; 49 } 50 51 #[cfg_attr( 52 not(no_zerocopy_diagnostic_on_unimplemented_1_78_0), 53 diagnostic::on_unimplemented( 54 message = "`{T}` has {PADDING_BYTES} total byte(s) of padding", 55 label = "types with padding cannot implement `IntoBytes`", 56 note = "consider using `zerocopy::Unalign` to lower the alignment of individual fields", 57 note = "consider adding explicit fields where padding would be", 58 note = "consider using `#[repr(packed)]` to remove padding" 59 ) 60 )] 61 pub trait PaddingFree<T: ?Sized, const PADDING_BYTES: usize> {} 62 impl<T: ?Sized> PaddingFree<T, 0> for () {} 63 64 // FIXME(#1112): In the slice DST case, we should delegate to *both* 65 // `PaddingFree` *and* `DynamicPaddingFree` (and probably rename `PaddingFree` 66 // to `StaticPaddingFree` or something - or introduce a third trait with that 67 // name) so that we can have more clear error messages. 68 69 #[cfg_attr( 70 not(no_zerocopy_diagnostic_on_unimplemented_1_78_0), 71 diagnostic::on_unimplemented( 72 message = "`{T}` has one or more padding bytes", 73 label = "types with padding cannot implement `IntoBytes`", 74 note = "consider using `zerocopy::Unalign` to lower the alignment of individual fields", 75 note = "consider adding explicit fields where padding would be", 76 note = "consider using `#[repr(packed)]` to remove padding" 77 ) 78 )] 79 pub trait DynamicPaddingFree<T: ?Sized, const HAS_PADDING: bool> {} 80 impl<T: ?Sized> DynamicPaddingFree<T, false> for () {} 81 82 #[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)] 83 #[cfg(not(target_pointer_width = "16"))] 84 const _64K: usize = 1 << 16; 85 86 // FIXME(#29), FIXME(https://github.com/rust-lang/rust/issues/69835): Remove 87 // this `cfg` when `size_of_val_raw` is stabilized. 88 #[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)] 89 #[cfg(not(target_pointer_width = "16"))] 90 #[repr(C, align(65536))] 91 struct Aligned64kAllocation([u8; _64K]); 92 93 /// A pointer to an aligned allocation of size 2^16. 94 /// 95 /// # Safety 96 /// 97 /// `ALIGNED_64K_ALLOCATION` is guaranteed to point to the entirety of an 98 /// allocation with size and alignment 2^16, and to have valid provenance. 99 // FIXME(#29), FIXME(https://github.com/rust-lang/rust/issues/69835): Remove 100 // this `cfg` when `size_of_val_raw` is stabilized. 101 #[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)] 102 #[cfg(not(target_pointer_width = "16"))] 103 pub const ALIGNED_64K_ALLOCATION: NonNull<[u8]> = { 104 const REF: &Aligned64kAllocation = &Aligned64kAllocation([0; _64K]); 105 let ptr: *const Aligned64kAllocation = REF; 106 let ptr: *const [u8] = ptr::slice_from_raw_parts(ptr.cast(), _64K); 107 // SAFETY: 108 // - `ptr` is derived from a Rust reference, which is guaranteed to be 109 // non-null. 110 // - `ptr` is derived from an `&Aligned64kAllocation`, which has size and 111 // alignment `_64K` as promised. Its length is initialized to `_64K`, 112 // which means that it refers to the entire allocation. 113 // - `ptr` is derived from a Rust reference, which is guaranteed to have 114 // valid provenance. 115 // 116 // FIXME(#429): Once `NonNull::new_unchecked` docs document that it 117 // preserves provenance, cite those docs. 118 // FIXME: Replace this `as` with `ptr.cast_mut()` once our MSRV >= 1.65 119 #[allow(clippy::as_conversions)] 120 unsafe { 121 NonNull::new_unchecked(ptr as *mut _) 122 } 123 }; 124 125 /// Computes the offset of the base of the field `$trailing_field_name` within 126 /// the type `$ty`. 127 /// 128 /// `trailing_field_offset!` produces code which is valid in a `const` context. 129 // FIXME(#29), FIXME(https://github.com/rust-lang/rust/issues/69835): Remove 130 // this `cfg` when `size_of_val_raw` is stabilized. 131 #[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)] 132 #[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`. 133 #[macro_export] 134 macro_rules! trailing_field_offset { 135 ($ty:ty, $trailing_field_name:tt) => {{ 136 let min_size = { 137 let zero_elems: *const [()] = 138 $crate::util::macro_util::core_reexport::ptr::slice_from_raw_parts( 139 $crate::util::macro_util::core_reexport::ptr::NonNull::<()>::dangling() 140 .as_ptr() 141 .cast_const(), 142 0, 143 ); 144 // SAFETY: 145 // - If `$ty` is `Sized`, `size_of_val_raw` is always safe to call. 146 // - Otherwise: 147 // - If `$ty` is not a slice DST, this pointer conversion will 148 // fail due to "mismatched vtable kinds", and compilation will 149 // fail. 150 // - If `$ty` is a slice DST, we have constructed `zero_elems` to 151 // have zero trailing slice elements. Per the `size_of_val_raw` 152 // docs, "For the special case where the dynamic tail length is 153 // 0, this function is safe to call." [1] 154 // 155 // [1] https://doc.rust-lang.org/nightly/std/mem/fn.size_of_val_raw.html 156 unsafe { 157 #[allow(clippy::as_conversions)] 158 $crate::util::macro_util::core_reexport::mem::size_of_val_raw( 159 zero_elems as *const $ty, 160 ) 161 } 162 }; 163 164 assert!(min_size <= _64K); 165 166 #[allow(clippy::as_conversions)] 167 let ptr = ALIGNED_64K_ALLOCATION.as_ptr() as *const $ty; 168 169 // SAFETY: 170 // - Thanks to the preceding `assert!`, we know that the value with zero 171 // elements fits in `_64K` bytes, and thus in the allocation addressed 172 // by `ALIGNED_64K_ALLOCATION`. The offset of the trailing field is 173 // guaranteed to be no larger than this size, so this field projection 174 // is guaranteed to remain in-bounds of its allocation. 175 // - Because the minimum size is no larger than `_64K` bytes, and 176 // because an object's size must always be a multiple of its alignment 177 // [1], we know that `$ty`'s alignment is no larger than `_64K`. The 178 // allocation addressed by `ALIGNED_64K_ALLOCATION` is guaranteed to 179 // be aligned to `_64K`, so `ptr` is guaranteed to satisfy `$ty`'s 180 // alignment. 181 // - As required by `addr_of!`, we do not write through `field`. 182 // 183 // Note that, as of [2], this requirement is technically unnecessary 184 // for Rust versions >= 1.75.0, but no harm in guaranteeing it anyway 185 // until we bump our MSRV. 186 // 187 // [1] Per https://doc.rust-lang.org/reference/type-layout.html: 188 // 189 // The size of a value is always a multiple of its alignment. 190 // 191 // [2] https://github.com/rust-lang/reference/pull/1387 192 let field = unsafe { 193 $crate::util::macro_util::core_reexport::ptr::addr_of!((*ptr).$trailing_field_name) 194 }; 195 // SAFETY: 196 // - Both `ptr` and `field` are derived from the same allocated object. 197 // - By the preceding safety comment, `field` is in bounds of that 198 // allocated object. 199 // - The distance, in bytes, between `ptr` and `field` is required to be 200 // a multiple of the size of `u8`, which is trivially true because 201 // `u8`'s size is 1. 202 // - The distance, in bytes, cannot overflow `isize`. This is guaranteed 203 // because no allocated object can have a size larger than can fit in 204 // `isize`. [1] 205 // - The distance being in-bounds cannot rely on wrapping around the 206 // address space. This is guaranteed because the same is guaranteed of 207 // allocated objects. [1] 208 // 209 // [1] FIXME(#429), FIXME(https://github.com/rust-lang/rust/pull/116675): 210 // Once these are guaranteed in the Reference, cite it. 211 let offset = unsafe { field.cast::<u8>().offset_from(ptr.cast::<u8>()) }; 212 // Guaranteed not to be lossy: `field` comes after `ptr`, so the offset 213 // from `ptr` to `field` is guaranteed to be positive. 214 assert!(offset >= 0); 215 Some( 216 #[allow(clippy::as_conversions)] 217 { 218 offset as usize 219 }, 220 ) 221 }}; 222 } 223 224 /// Computes alignment of `$ty: ?Sized`. 225 /// 226 /// `align_of!` produces code which is valid in a `const` context. 227 // FIXME(#29), FIXME(https://github.com/rust-lang/rust/issues/69835): Remove 228 // this `cfg` when `size_of_val_raw` is stabilized. 229 #[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)] 230 #[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`. 231 #[macro_export] 232 macro_rules! align_of { 233 ($ty:ty) => {{ 234 // SAFETY: `OffsetOfTrailingIsAlignment` is `repr(C)`, and its layout is 235 // guaranteed [1] to begin with the single-byte layout for `_byte`, 236 // followed by the padding needed to align `_trailing`, then the layout 237 // for `_trailing`, and finally any trailing padding bytes needed to 238 // correctly-align the entire struct. 239 // 240 // This macro computes the alignment of `$ty` by counting the number of 241 // bytes preceding `_trailing`. For instance, if the alignment of `$ty` 242 // is `1`, then no padding is required align `_trailing` and it will be 243 // located immediately after `_byte` at offset 1. If the alignment of 244 // `$ty` is 2, then a single padding byte is required before 245 // `_trailing`, and `_trailing` will be located at offset 2. 246 247 // This correspondence between offset and alignment holds for all valid 248 // Rust alignments, and we confirm this exhaustively (or, at least up to 249 // the maximum alignment supported by `trailing_field_offset!`) in 250 // `test_align_of_dst`. 251 // 252 // [1]: https://doc.rust-lang.org/nomicon/other-reprs.html#reprc 253 254 #[repr(C)] 255 struct OffsetOfTrailingIsAlignment { 256 _byte: u8, 257 _trailing: $ty, 258 } 259 260 trailing_field_offset!(OffsetOfTrailingIsAlignment, _trailing) 261 }}; 262 } 263 264 mod size_to_tag { 265 pub trait SizeToTag<const SIZE: usize> { 266 type Tag; 267 } 268 269 impl SizeToTag<1> for () { 270 type Tag = u8; 271 } 272 impl SizeToTag<2> for () { 273 type Tag = u16; 274 } 275 impl SizeToTag<4> for () { 276 type Tag = u32; 277 } 278 impl SizeToTag<8> for () { 279 type Tag = u64; 280 } 281 impl SizeToTag<16> for () { 282 type Tag = u128; 283 } 284 } 285 286 /// An alias for the unsigned integer of the given size in bytes. 287 #[doc(hidden)] 288 pub type SizeToTag<const SIZE: usize> = <() as size_to_tag::SizeToTag<SIZE>>::Tag; 289 290 // We put `Sized` in its own module so it can have the same name as the standard 291 // library `Sized` without shadowing it in the parent module. 292 #[cfg(not(no_zerocopy_diagnostic_on_unimplemented_1_78_0))] 293 mod __size_of { 294 #[diagnostic::on_unimplemented( 295 message = "`{Self}` is unsized", 296 label = "`IntoBytes` needs all field types to be `Sized` in order to determine whether there is padding", 297 note = "consider using `#[repr(packed)]` to remove padding", 298 note = "`IntoBytes` does not require the fields of `#[repr(packed)]` types to be `Sized`" 299 )] 300 pub trait Sized: core::marker::Sized {} 301 impl<T: core::marker::Sized> Sized for T {} 302 303 #[inline(always)] 304 #[must_use] 305 #[allow(clippy::needless_maybe_sized)] 306 pub const fn size_of<T: Sized + ?core::marker::Sized>() -> usize { 307 core::mem::size_of::<T>() 308 } 309 } 310 311 #[cfg(no_zerocopy_diagnostic_on_unimplemented_1_78_0)] 312 pub use core::mem::size_of; 313 314 #[cfg(not(no_zerocopy_diagnostic_on_unimplemented_1_78_0))] 315 pub use __size_of::size_of; 316 317 /// How many padding bytes does the struct type `$t` have? 318 /// 319 /// `$ts` is the list of the type of every field in `$t`. `$t` must be a struct 320 /// type, or else `struct_padding!`'s result may be meaningless. 321 /// 322 /// Note that `struct_padding!`'s results are independent of `repcr` since they 323 /// only consider the size of the type and the sizes of the fields. Whatever the 324 /// repr, the size of the type already takes into account any padding that the 325 /// compiler has decided to add. Structs with well-defined representations (such 326 /// as `repr(C)`) can use this macro to check for padding. Note that while this 327 /// may yield some consistent value for some `repr(Rust)` structs, it is not 328 /// guaranteed across platforms or compilations. 329 #[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`. 330 #[macro_export] 331 macro_rules! struct_padding { 332 ($t:ty, $_align:expr, $_packed:expr, [$($ts:ty),*]) => {{ 333 // The `align` and `packed` directives can be ignored here. Regardless 334 // of if and how they are set, comparing the size of `$t` to the sum of 335 // its field sizes is a reliable indicator of the presence of padding. 336 $crate::util::macro_util::size_of::<$t>() - (0 $(+ $crate::util::macro_util::size_of::<$ts>())*) 337 }}; 338 } 339 340 /// Does the `repr(C)` struct type `$t` have padding? 341 /// 342 /// `$ts` is the list of the type of every field in `$t`. `$t` must be a 343 /// `repr(C)` struct type, or else `struct_has_padding!`'s result may be 344 /// meaningless. 345 #[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`. 346 #[macro_export] 347 macro_rules! repr_c_struct_has_padding { 348 ($t:ty, $align:expr, $packed:expr, [$($ts:tt),*]) => {{ 349 let layout = $crate::DstLayout::for_repr_c_struct( 350 $align, 351 $packed, 352 &[$($crate::repr_c_struct_has_padding!(@field $ts),)*] 353 ); 354 layout.requires_static_padding() || layout.requires_dynamic_padding() 355 }}; 356 (@field ([$t:ty])) => { 357 <[$t] as $crate::KnownLayout>::LAYOUT 358 }; 359 (@field ($t:ty)) => { 360 $crate::DstLayout::for_unpadded_type::<$t>() 361 }; 362 (@field [$t:ty]) => { 363 <[$t] as $crate::KnownLayout>::LAYOUT 364 }; 365 (@field $t:ty) => { 366 $crate::DstLayout::for_unpadded_type::<$t>() 367 }; 368 } 369 370 /// Does the union type `$t` have padding? 371 /// 372 /// `$ts` is the list of the type of every field in `$t`. `$t` must be a union 373 /// type, or else `union_padding!`'s result may be meaningless. 374 /// 375 /// Note that `union_padding!`'s results are independent of `repr` since they 376 /// only consider the size of the type and the sizes of the fields. Whatever the 377 /// repr, the size of the type already takes into account any padding that the 378 /// compiler has decided to add. Unions with well-defined representations (such 379 /// as `repr(C)`) can use this macro to check for padding. Note that while this 380 /// may yield some consistent value for some `repr(Rust)` unions, it is not 381 /// guaranteed across platforms or compilations. 382 #[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`. 383 #[macro_export] 384 macro_rules! union_padding { 385 ($t:ty, $_align:expr, $_packed:expr, [$($ts:ty),*]) => {{ 386 // The `align` and `packed` directives can be ignored here. Regardless 387 // of if and how they are set, comparing the size of `$t` to each of its 388 // field sizes is a reliable indicator of the presence of padding. 389 let mut max = 0; 390 $({ 391 let padding = $crate::util::macro_util::size_of::<$t>() - $crate::util::macro_util::size_of::<$ts>(); 392 if padding > max { 393 max = padding; 394 } 395 })* 396 max 397 }}; 398 } 399 400 /// How many padding bytes does the enum type `$t` have? 401 /// 402 /// `$disc` is the type of the enum tag, and `$ts` is a list of fields in each 403 /// square-bracket-delimited variant. `$t` must be an enum, or else 404 /// `enum_padding!`'s result may be meaningless. An enum has padding if any of 405 /// its variant structs [1][2] contain padding, and so all of the variants of an 406 /// enum must be "full" in order for the enum to not have padding. 407 /// 408 /// The results of `enum_padding!` require that the enum is not `repr(Rust)`, as 409 /// `repr(Rust)` enums may niche the enum's tag and reduce the total number of 410 /// bytes required to represent the enum as a result. As long as the enum is 411 /// `repr(C)`, `repr(int)`, or `repr(C, int)`, this will consistently return 412 /// whether the enum contains any padding bytes. 413 /// 414 /// [1]: https://doc.rust-lang.org/1.81.0/reference/type-layout.html#reprc-enums-with-fields 415 /// [2]: https://doc.rust-lang.org/1.81.0/reference/type-layout.html#primitive-representation-of-enums-with-fields 416 #[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`. 417 #[macro_export] 418 macro_rules! enum_padding { 419 ($t:ty, $_align:expr, $packed:expr, $disc:ty, $([$($ts:ty),*]),*) => {{ 420 // The `align` and `packed` directives are irrelevant. `$align` can be 421 // ignored because regardless of if and how it is set, comparing the 422 // size of `$t` to each of its field sizes is a reliable indicator of 423 // the presence of padding. `$packed` is irrelevant because it is 424 // forbidden on enums. 425 #[allow(clippy::as_conversions)] 426 const _: [(); 1] = [(); $packed.is_none() as usize]; 427 let mut max = 0; 428 $({ 429 let padding = $crate::util::macro_util::size_of::<$t>() 430 - ( 431 $crate::util::macro_util::size_of::<$disc>() 432 $(+ $crate::util::macro_util::size_of::<$ts>())* 433 ); 434 if padding > max { 435 max = padding; 436 } 437 })* 438 max 439 }}; 440 } 441 442 /// Unwraps an infallible `Result`. 443 #[doc(hidden)] 444 #[macro_export] 445 macro_rules! into_inner { 446 ($e:expr) => { 447 match $e { 448 $crate::util::macro_util::core_reexport::result::Result::Ok(e) => e, 449 $crate::util::macro_util::core_reexport::result::Result::Err(i) => match i {}, 450 } 451 }; 452 } 453 454 /// Translates an identifier or tuple index into a numeric identifier. 455 #[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`. 456 #[macro_export] 457 macro_rules! ident_id { 458 ($field:ident) => { 459 $crate::util::macro_util::hash_name(stringify!($field)) 460 }; 461 ($field:literal) => { 462 $field 463 }; 464 } 465 466 /// Computes the hash of a string. 467 /// 468 /// NOTE(#2749) on hash collisions: This function's output only needs to be 469 /// deterministic within a particular compilation. Thus, if a user ever reports 470 /// a hash collision (very unlikely given the <= 16-byte special case), we can 471 /// strengthen the hash function at that point and publish a new version. Since 472 /// this is computed at compile time on small strings, we can easily use more 473 /// expensive and higher-quality hash functions if need be. 474 #[inline(always)] 475 #[must_use] 476 #[allow(clippy::as_conversions, clippy::indexing_slicing, clippy::arithmetic_side_effects)] 477 pub const fn hash_name(name: &str) -> i128 { 478 let name = name.as_bytes(); 479 480 // We guarantee freedom from hash collisions between any two strings of 481 // length 16 or less by having the hashes of such strings be equal to 482 // their value. There is still a possibility that such strings will have 483 // the same value as the hash of a string of length > 16. 484 if name.len() <= size_of::<u128>() { 485 let mut bytes = [0u8; 16]; 486 487 let mut i = 0; 488 while i < name.len() { 489 bytes[i] = name[i]; 490 i += 1; 491 } 492 493 return i128::from_ne_bytes(bytes); 494 }; 495 496 // An implementation of FxHasher, although returning a u128. Probably 497 // not as strong as it could be, but probably more collision resistant 498 // than normal 64-bit FxHasher. 499 let mut hash = 0u128; 500 let mut i = 0; 501 while i < name.len() { 502 // This is just FxHasher's `0x517cc1b727220a95` constant 503 // concatenated back-to-back. 504 const K: u128 = 0x517cc1b727220a95517cc1b727220a95; 505 hash = (hash.rotate_left(5) ^ (name[i] as u128)).wrapping_mul(K); 506 i += 1; 507 } 508 i128::from_ne_bytes(hash.to_ne_bytes()) 509 } 510 511 /// Attempts to transmute `Src` into `Dst`. 512 /// 513 /// A helper for `try_transmute!`. 514 /// 515 /// # Panics 516 /// 517 /// `try_transmute` may either produce a post-monomorphization error or a panic 518 /// if `Dst` is bigger than `Src`. Otherwise, `try_transmute` panics under the 519 /// same circumstances as [`is_bit_valid`]. 520 /// 521 /// [`is_bit_valid`]: TryFromBytes::is_bit_valid 522 #[inline(always)] 523 pub fn try_transmute<Src, Dst>(src: Src) -> Result<Dst, ValidityError<Src, Dst>> 524 where 525 Src: IntoBytes, 526 Dst: TryFromBytes, 527 { 528 static_assert!(Src, Dst => mem::size_of::<Dst>() == mem::size_of::<Src>()); 529 530 let mu_src = mem::MaybeUninit::new(src); 531 // SAFETY: `MaybeUninit` has no validity requirements. 532 let mu_dst: mem::MaybeUninit<ReadOnly<Dst>> = 533 unsafe { crate::util::transmute_unchecked(mu_src) }; 534 535 let ptr = Ptr::from_ref(&mu_dst); 536 537 // SAFETY: Since `Src: IntoBytes`, and since `size_of::<Src>() == 538 // size_of::<Dst>()` by the preceding assertion, all of `mu_dst`'s bytes are 539 // initialized. `MaybeUninit` has no validity requirements, so even if 540 // `ptr` is used to mutate its referent (which it actually can't be - it's 541 // a shared `ReadOnly` pointer), that won't violate its referent's validity. 542 let ptr = unsafe { ptr.assume_validity::<Initialized>() }; 543 if Dst::is_bit_valid(ptr.cast::<_, CastSized, _>()) { 544 // SAFETY: Since `Dst::is_bit_valid`, we know that `ptr`'s referent is 545 // bit-valid for `Dst`. `ptr` points to `mu_dst`, and no intervening 546 // operations have mutated it, so it is a bit-valid `Dst`. 547 Ok(ReadOnly::into_inner(unsafe { mu_dst.assume_init() })) 548 } else { 549 // SAFETY: `MaybeUninit` has no validity requirements. 550 let mu_src: mem::MaybeUninit<Src> = unsafe { crate::util::transmute_unchecked(mu_dst) }; 551 // SAFETY: `mu_dst`/`mu_src` was constructed from `src` and never 552 // modified, so it is still bit-valid. 553 Err(ValidityError::new(unsafe { mu_src.assume_init() })) 554 } 555 } 556 557 /// See `try_transmute_ref!` documentation. 558 pub trait TryTransmuteRefDst<'a> { 559 type Dst: ?Sized; 560 561 /// See `try_transmute_ref!` documentation. 562 fn try_transmute_ref(self) -> Result<&'a Self::Dst, ValidityError<&'a Self::Src, Self::Dst>> 563 where 564 Self: TryTransmuteRefSrc<'a>, 565 Self::Src: IntoBytes + Immutable + KnownLayout, 566 Self::Dst: TryFromBytes + Immutable + KnownLayout; 567 } 568 569 pub trait TryTransmuteRefSrc<'a> { 570 type Src: ?Sized; 571 } 572 573 impl<'a, Src, Dst> TryTransmuteRefSrc<'a> for Wrap<&'a Src, &'a Dst> 574 where 575 Src: ?Sized, 576 Dst: ?Sized, 577 { 578 type Src = Src; 579 } 580 581 impl<'a, Src, Dst> TryTransmuteRefDst<'a> for Wrap<&'a Src, &'a Dst> 582 where 583 Src: IntoBytes + Immutable + KnownLayout + ?Sized, 584 Dst: TryFromBytes + Immutable + KnownLayout + ?Sized, 585 { 586 type Dst = Dst; 587 588 #[inline(always)] 589 fn try_transmute_ref( 590 self, 591 ) -> Result< 592 &'a Dst, 593 ValidityError<&'a <Wrap<&'a Src, &'a Dst> as TryTransmuteRefSrc<'a>>::Src, Dst>, 594 > { 595 let ptr = Ptr::from_ref(self.0); 596 #[rustfmt::skip] 597 let res = ptr.try_with(#[inline(always)] |ptr| { 598 let ptr = ptr.recall_validity::<Initialized, _>(); 599 let ptr = ptr.cast::<_, crate::layout::CastFrom<Dst>, _>(); 600 ptr.try_into_valid() 601 }); 602 match res { 603 Ok(ptr) => { 604 static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => { 605 Src::LAYOUT.align.get() >= Dst::LAYOUT.align.get() 606 }, "cannot transmute reference when destination type has higher alignment than source type"); 607 // SAFETY: We have checked that `Dst` does not have a stricter 608 // alignment requirement than `Src`. 609 let ptr = unsafe { ptr.assume_alignment::<Aligned>() }; 610 Ok(ptr.as_ref()) 611 } 612 Err(err) => Err(err.map_src(Ptr::as_ref)), 613 } 614 } 615 } 616 617 pub trait TryTransmuteMutDst<'a> { 618 type Dst: ?Sized; 619 620 /// See `try_transmute_mut!` documentation. 621 fn try_transmute_mut( 622 self, 623 ) -> Result<&'a mut Self::Dst, ValidityError<&'a mut Self::Src, Self::Dst>> 624 where 625 Self: TryTransmuteMutSrc<'a>, 626 Self::Src: IntoBytes, 627 Self::Dst: TryFromBytes; 628 } 629 630 pub trait TryTransmuteMutSrc<'a> { 631 type Src: ?Sized; 632 } 633 634 impl<'a, Src, Dst> TryTransmuteMutSrc<'a> for Wrap<&'a mut Src, &'a mut Dst> 635 where 636 Src: ?Sized, 637 Dst: ?Sized, 638 { 639 type Src = Src; 640 } 641 642 impl<'a, Src, Dst> TryTransmuteMutDst<'a> for Wrap<&'a mut Src, &'a mut Dst> 643 where 644 Src: FromBytes + IntoBytes + KnownLayout + ?Sized, 645 Dst: TryFromBytes + IntoBytes + KnownLayout + ?Sized, 646 { 647 type Dst = Dst; 648 649 #[inline(always)] 650 fn try_transmute_mut( 651 self, 652 ) -> Result< 653 &'a mut Dst, 654 ValidityError<&'a mut <Wrap<&'a mut Src, &'a mut Dst> as TryTransmuteMutSrc<'a>>::Src, Dst>, 655 > { 656 let ptr = Ptr::from_mut(self.0); 657 // SAFETY: The provided closure returns the only copy of `ptr`. 658 #[rustfmt::skip] 659 let res = unsafe { 660 ptr.try_with_unchecked(#[inline(always)] |ptr| { 661 let ptr = ptr.recall_validity::<Initialized, (_, (_, _))>(); 662 let ptr = ptr.cast::<_, crate::layout::CastFrom<Dst>, _>(); 663 ptr.try_into_valid() 664 }) 665 }; 666 match res { 667 Ok(ptr) => { 668 static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => { 669 Src::LAYOUT.align.get() >= Dst::LAYOUT.align.get() 670 }, "cannot transmute reference when destination type has higher alignment than source type"); 671 // SAFETY: We have checked that `Dst` does not have a stricter 672 // alignment requirement than `Src`. 673 let ptr = unsafe { ptr.assume_alignment::<Aligned>() }; 674 Ok(ptr.as_mut()) 675 } 676 Err(err) => Err(err.map_src(Ptr::as_mut)), 677 } 678 } 679 } 680 681 // Used in `transmute_ref!` and friends. 682 // 683 // This permits us to use the autoref specialization trick to dispatch to 684 // associated functions for `transmute_ref` and `transmute_mut` when both `Src` 685 // and `Dst` are `Sized`, and to trait methods otherwise. The associated 686 // functions, unlike the trait methods, do not require a `KnownLayout` bound. 687 // This permits us to add support for transmuting references to unsized types 688 // without breaking backwards-compatibility (on v0.8.x) with the old 689 // implementation, which did not require a `KnownLayout` bound to transmute 690 // sized types. 691 #[derive(Copy, Clone)] 692 pub struct Wrap<Src, Dst>(pub Src, pub PhantomData<Dst>); 693 694 impl<Src, Dst> Wrap<Src, Dst> { 695 #[inline(always)] 696 pub const fn new(src: Src) -> Self { 697 Wrap(src, PhantomData) 698 } 699 } 700 701 impl<'a, Src, Dst> Wrap<&'a Src, &'a Dst> 702 where 703 Src: ?Sized, 704 Dst: ?Sized, 705 { 706 #[allow(clippy::must_use_candidate, clippy::missing_inline_in_public_items, clippy::empty_loop)] 707 pub const fn transmute_ref_inference_helper(self) -> &'a Dst { 708 loop {} 709 } 710 } 711 712 impl<'a, Src, Dst> Wrap<&'a Src, &'a Dst> { 713 /// # Safety 714 /// The caller must guarantee that: 715 /// - `Src: IntoBytes + Immutable` 716 /// - `Dst: FromBytes + Immutable` 717 /// 718 /// # PME 719 /// 720 /// Instantiating this method PMEs unless both: 721 /// - `mem::size_of::<Dst>() == mem::size_of::<Src>()` 722 /// - `mem::align_of::<Dst>() <= mem::align_of::<Src>()` 723 #[inline(always)] 724 #[must_use] 725 pub const unsafe fn transmute_ref(self) -> &'a Dst { 726 static_assert!(Src, Dst => mem::size_of::<Dst>() == mem::size_of::<Src>()); 727 static_assert!(Src, Dst => mem::align_of::<Dst>() <= mem::align_of::<Src>()); 728 729 let src: *const Src = self.0; 730 let dst = src.cast::<Dst>(); 731 // SAFETY: 732 // - We know that it is sound to view the target type of the input 733 // reference (`Src`) as the target type of the output reference 734 // (`Dst`) because the caller has guaranteed that `Src: IntoBytes`, 735 // `Dst: FromBytes`, and `size_of::<Src>() == size_of::<Dst>()`. 736 // - We know that there are no `UnsafeCell`s, and thus we don't have to 737 // worry about `UnsafeCell` overlap, because `Src: Immutable` and 738 // `Dst: Immutable`. 739 // - The caller has guaranteed that alignment is not increased. 740 // - We know that the returned lifetime will not outlive the input 741 // lifetime thanks to the lifetime bounds on this function. 742 // 743 // FIXME(#67): Once our MSRV is 1.58, replace this `transmute` with 744 // `&*dst`. 745 #[allow(clippy::transmute_ptr_to_ref)] 746 unsafe { 747 mem::transmute(dst) 748 } 749 } 750 751 #[inline(always)] 752 pub fn try_transmute_ref(self) -> Result<&'a Dst, ValidityError<&'a Src, Dst>> 753 where 754 Src: IntoBytes + Immutable, 755 Dst: TryFromBytes + Immutable, 756 { 757 static_assert!(Src => mem::align_of::<Src>() == mem::align_of::<Wrapping<Src>>()); 758 static_assert!(Dst => mem::align_of::<Dst>() == mem::align_of::<Wrapping<Dst>>()); 759 760 // SAFETY: By the preceding assert, `Src` and `Wrapping<Src>` have the 761 // same alignment. 762 let src: &Wrapping<Src> = 763 unsafe { crate::util::transmute_ref::<_, _, BecauseImmutable>(self.0) }; 764 let src = Wrap::new(src); 765 <Wrap<&'a Wrapping<Src>, &'a Wrapping<Dst>> as TryTransmuteRefDst<'a>>::try_transmute_ref( 766 src, 767 ) 768 .map( 769 // SAFETY: By the preceding assert, `Dst` and `Wrapping<Dst>` have 770 // the same alignment. 771 #[inline(always)] 772 |dst| unsafe { crate::util::transmute_ref::<_, _, BecauseImmutable>(dst) }, 773 ) 774 .map_err( 775 #[inline(always)] 776 |err| { 777 // SAFETY: By the preceding assert, `Src` and `Wrapping<Src>` have the 778 // same alignment. 779 ValidityError::new(unsafe { 780 crate::util::transmute_ref::<_, _, BecauseImmutable>(err.into_src()) 781 }) 782 }, 783 ) 784 } 785 } 786 787 impl<'a, Src, Dst> Wrap<&'a mut Src, &'a mut Dst> 788 where 789 Src: ?Sized, 790 Dst: ?Sized, 791 { 792 #[allow(clippy::must_use_candidate, clippy::missing_inline_in_public_items, clippy::empty_loop)] 793 pub fn transmute_mut_inference_helper(self) -> &'a mut Dst { 794 loop {} 795 } 796 } 797 798 impl<'a, Src, Dst> Wrap<&'a mut Src, &'a mut Dst> { 799 /// Transmutes a mutable reference of one type to a mutable reference of 800 /// another type. 801 /// 802 /// # PME 803 /// 804 /// Instantiating this method PMEs unless both: 805 /// - `mem::size_of::<Dst>() == mem::size_of::<Src>()` 806 /// - `mem::align_of::<Dst>() <= mem::align_of::<Src>()` 807 #[inline(always)] 808 #[must_use] 809 pub fn transmute_mut(self) -> &'a mut Dst 810 where 811 Src: FromBytes + IntoBytes, 812 Dst: FromBytes + IntoBytes, 813 { 814 static_assert!(Src, Dst => mem::size_of::<Dst>() == mem::size_of::<Src>()); 815 static_assert!(Src, Dst => mem::align_of::<Dst>() <= mem::align_of::<Src>()); 816 817 let src: *mut Src = self.0; 818 let dst = src.cast::<Dst>(); 819 // SAFETY: 820 // - We know that it is sound to view the target type of the input 821 // reference (`Src`) as the target type of the output reference 822 // (`Dst`) and vice-versa because `Src: FromBytes + IntoBytes`, `Dst: 823 // FromBytes + IntoBytes`, and (as asserted above) `size_of::<Src>() 824 // == size_of::<Dst>()`. 825 // - We asserted above that alignment will not increase. 826 // - We know that the returned lifetime will not outlive the input 827 // lifetime thanks to the lifetime bounds on this function. 828 unsafe { &mut *dst } 829 } 830 831 #[inline(always)] 832 pub fn try_transmute_mut(self) -> Result<&'a mut Dst, ValidityError<&'a mut Src, Dst>> 833 where 834 Src: FromBytes + IntoBytes, 835 Dst: TryFromBytes + IntoBytes, 836 { 837 static_assert!(Src => mem::align_of::<Src>() == mem::align_of::<Wrapping<Src>>()); 838 static_assert!(Dst => mem::align_of::<Dst>() == mem::align_of::<Wrapping<Dst>>()); 839 840 // SAFETY: By the preceding assert, `Src` and `Wrapping<Src>` have the 841 // same alignment. 842 let src: &mut Wrapping<Src> = 843 unsafe { crate::util::transmute_mut::<_, _, (_, (_, _))>(self.0) }; 844 let src = Wrap::new(src); 845 <Wrap<&'a mut Wrapping<Src>, &'a mut Wrapping<Dst>> as TryTransmuteMutDst<'a>> 846 ::try_transmute_mut(src) 847 // SAFETY: By the preceding assert, `Dst` and `Wrapping<Dst>` have the 848 // same alignment. 849 .map(|dst| unsafe { crate::util::transmute_mut::<_, _, (_, (_, _))>(dst) }) 850 .map_err(|err| { 851 // SAFETY: By the preceding assert, `Src` and `Wrapping<Src>` have the 852 // same alignment. 853 ValidityError::new(unsafe { 854 crate::util::transmute_mut::<_, _, (_, (_, _))>(err.into_src()) 855 }) 856 }) 857 } 858 } 859 860 pub trait TransmuteRefDst<'a> { 861 type Dst: ?Sized; 862 863 #[must_use] 864 fn transmute_ref(self) -> &'a Self::Dst; 865 } 866 867 impl<'a, Src: ?Sized, Dst: ?Sized> TransmuteRefDst<'a> for Wrap<&'a Src, &'a Dst> 868 where 869 Src: KnownLayout + IntoBytes + Immutable, 870 Dst: KnownLayout<PointerMetadata = usize> + FromBytes + Immutable, 871 { 872 type Dst = Dst; 873 874 #[inline(always)] 875 fn transmute_ref(self) -> &'a Dst { 876 let ptr = Ptr::from_ref(self.0) 877 .recall_validity::<Initialized, _>() 878 .transmute_with::<Dst, Initialized, crate::layout::CastFrom<Dst>, (crate::pointer::BecauseMutationCompatible, _)>() 879 .recall_validity::<Valid, _>(); 880 881 static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => { 882 Src::LAYOUT.align.get() >= Dst::LAYOUT.align.get() 883 }, "cannot transmute reference when destination type has higher alignment than source type"); 884 885 // SAFETY: The preceding `static_assert!` ensures that 886 // `Src::LAYOUT.align >= Dst::LAYOUT.align`. Since `self` is 887 // validly-aligned for `Src`, it is also validly-aligned for `Dst`. 888 let ptr = unsafe { ptr.assume_alignment() }; 889 890 ptr.as_ref() 891 } 892 } 893 894 pub trait TransmuteMutDst<'a> { 895 type Dst: ?Sized; 896 #[must_use] 897 fn transmute_mut(self) -> &'a mut Self::Dst; 898 } 899 900 impl<'a, Src: ?Sized, Dst: ?Sized> TransmuteMutDst<'a> for Wrap<&'a mut Src, &'a mut Dst> 901 where 902 Src: KnownLayout + FromBytes + IntoBytes, 903 Dst: KnownLayout<PointerMetadata = usize> + FromBytes + IntoBytes, 904 { 905 type Dst = Dst; 906 907 #[inline(always)] 908 fn transmute_mut(self) -> &'a mut Dst { 909 let ptr = Ptr::from_mut(self.0) 910 .recall_validity::<Initialized, (_, (_, _))>() 911 .transmute_with::<Dst, Initialized, crate::layout::CastFrom<Dst>, _>() 912 .recall_validity::<Valid, (_, (_, _))>(); 913 914 static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => { 915 Src::LAYOUT.align.get() >= Dst::LAYOUT.align.get() 916 }, "cannot transmute reference when destination type has higher alignment than source type"); 917 918 // SAFETY: The preceding `static_assert!` ensures that 919 // `Src::LAYOUT.align >= Dst::LAYOUT.align`. Since `self` is 920 // validly-aligned for `Src`, it is also validly-aligned for `Dst`. 921 let ptr = unsafe { ptr.assume_alignment() }; 922 923 ptr.as_mut() 924 } 925 } 926 927 /// A function which emits a warning if its return value is not used. 928 #[must_use] 929 #[inline(always)] 930 pub const fn must_use<T>(t: T) -> T { 931 t 932 } 933 934 // NOTE: We can't change this to a `pub use core as core_reexport` until [1] is 935 // fixed or we update to a semver-breaking version (as of this writing, 0.8.0) 936 // on the `main` branch. 937 // 938 // [1] https://github.com/obi1kenobi/cargo-semver-checks/issues/573 939 pub mod core_reexport { 940 pub use core::*; 941 942 pub mod mem { 943 pub use core::mem::*; 944 } 945 } 946 947 #[cfg(test)] 948 mod tests { 949 use core::num::NonZeroUsize; 950 951 use crate::util::testutil::*; 952 953 #[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)] 954 mod nightly { 955 use super::super::*; 956 use crate::util::testutil::*; 957 958 // FIXME(#29), FIXME(https://github.com/rust-lang/rust/issues/69835): 959 // Remove this `cfg` when `size_of_val_raw` is stabilized. 960 #[allow(clippy::decimal_literal_representation)] 961 #[test] 962 fn test_trailing_field_offset() { 963 assert_eq!(mem::align_of::<Aligned64kAllocation>(), _64K); 964 965 macro_rules! test { 966 (#[$cfg:meta] ($($ts:ty),* ; $trailing_field_ty:ty) => $expect:expr) => {{ 967 #[$cfg] 968 struct Test($(#[allow(dead_code)] $ts,)* #[allow(dead_code)] $trailing_field_ty); 969 assert_eq!(test!(@offset $($ts),* ; $trailing_field_ty), $expect); 970 }}; 971 (#[$cfg:meta] $(#[$cfgs:meta])* ($($ts:ty),* ; $trailing_field_ty:ty) => $expect:expr) => { 972 test!(#[$cfg] ($($ts),* ; $trailing_field_ty) => $expect); 973 test!($(#[$cfgs])* ($($ts),* ; $trailing_field_ty) => $expect); 974 }; 975 (@offset ; $_trailing:ty) => { trailing_field_offset!(Test, 0) }; 976 (@offset $_t:ty ; $_trailing:ty) => { trailing_field_offset!(Test, 1) }; 977 } 978 979 test!(#[repr(C)] #[repr(transparent)] #[repr(packed)](; u8) => Some(0)); 980 test!(#[repr(C)] #[repr(transparent)] #[repr(packed)](; [u8]) => Some(0)); 981 test!(#[repr(C)] #[repr(C, packed)] (u8; u8) => Some(1)); 982 test!(#[repr(C)] (; AU64) => Some(0)); 983 test!(#[repr(C)] (; [AU64]) => Some(0)); 984 test!(#[repr(C)] (u8; AU64) => Some(8)); 985 test!(#[repr(C)] (u8; [AU64]) => Some(8)); 986 987 #[derive( 988 Immutable, FromBytes, Eq, PartialEq, Ord, PartialOrd, Default, Debug, Copy, Clone, 989 )] 990 #[repr(C)] 991 pub(crate) struct Nested<T, U: ?Sized> { 992 _t: T, 993 _u: U, 994 } 995 996 test!(#[repr(C)] (; Nested<u8, AU64>) => Some(0)); 997 test!(#[repr(C)] (; Nested<u8, [AU64]>) => Some(0)); 998 test!(#[repr(C)] (u8; Nested<u8, AU64>) => Some(8)); 999 test!(#[repr(C)] (u8; Nested<u8, [AU64]>) => Some(8)); 1000 1001 // Test that `packed(N)` limits the offset of the trailing field. 1002 test!(#[repr(C, packed( 1))] (u8; elain::Align< 2>) => Some( 1)); 1003 test!(#[repr(C, packed( 2))] (u8; elain::Align< 4>) => Some( 2)); 1004 test!(#[repr(C, packed( 4))] (u8; elain::Align< 8>) => Some( 4)); 1005 test!(#[repr(C, packed( 8))] (u8; elain::Align< 16>) => Some( 8)); 1006 test!(#[repr(C, packed( 16))] (u8; elain::Align< 32>) => Some( 16)); 1007 test!(#[repr(C, packed( 32))] (u8; elain::Align< 64>) => Some( 32)); 1008 test!(#[repr(C, packed( 64))] (u8; elain::Align< 128>) => Some( 64)); 1009 test!(#[repr(C, packed( 128))] (u8; elain::Align< 256>) => Some( 128)); 1010 test!(#[repr(C, packed( 256))] (u8; elain::Align< 512>) => Some( 256)); 1011 test!(#[repr(C, packed( 512))] (u8; elain::Align< 1024>) => Some( 512)); 1012 test!(#[repr(C, packed( 1024))] (u8; elain::Align< 2048>) => Some( 1024)); 1013 test!(#[repr(C, packed( 2048))] (u8; elain::Align< 4096>) => Some( 2048)); 1014 test!(#[repr(C, packed( 4096))] (u8; elain::Align< 8192>) => Some( 4096)); 1015 test!(#[repr(C, packed( 8192))] (u8; elain::Align< 16384>) => Some( 8192)); 1016 test!(#[repr(C, packed( 16384))] (u8; elain::Align< 32768>) => Some( 16384)); 1017 test!(#[repr(C, packed( 32768))] (u8; elain::Align< 65536>) => Some( 32768)); 1018 test!(#[repr(C, packed( 65536))] (u8; elain::Align< 131072>) => Some( 65536)); 1019 /* Alignments above 65536 are not yet supported. 1020 test!(#[repr(C, packed( 131072))] (u8; elain::Align< 262144>) => Some( 131072)); 1021 test!(#[repr(C, packed( 262144))] (u8; elain::Align< 524288>) => Some( 262144)); 1022 test!(#[repr(C, packed( 524288))] (u8; elain::Align< 1048576>) => Some( 524288)); 1023 test!(#[repr(C, packed( 1048576))] (u8; elain::Align< 2097152>) => Some( 1048576)); 1024 test!(#[repr(C, packed( 2097152))] (u8; elain::Align< 4194304>) => Some( 2097152)); 1025 test!(#[repr(C, packed( 4194304))] (u8; elain::Align< 8388608>) => Some( 4194304)); 1026 test!(#[repr(C, packed( 8388608))] (u8; elain::Align< 16777216>) => Some( 8388608)); 1027 test!(#[repr(C, packed( 16777216))] (u8; elain::Align< 33554432>) => Some( 16777216)); 1028 test!(#[repr(C, packed( 33554432))] (u8; elain::Align< 67108864>) => Some( 33554432)); 1029 test!(#[repr(C, packed( 67108864))] (u8; elain::Align< 33554432>) => Some( 67108864)); 1030 test!(#[repr(C, packed( 33554432))] (u8; elain::Align<134217728>) => Some( 33554432)); 1031 test!(#[repr(C, packed(134217728))] (u8; elain::Align<268435456>) => Some(134217728)); 1032 test!(#[repr(C, packed(268435456))] (u8; elain::Align<268435456>) => Some(268435456)); 1033 */ 1034 1035 // Test that `align(N)` does not limit the offset of the trailing field. 1036 test!(#[repr(C, align( 1))] (u8; elain::Align< 2>) => Some( 2)); 1037 test!(#[repr(C, align( 2))] (u8; elain::Align< 4>) => Some( 4)); 1038 test!(#[repr(C, align( 4))] (u8; elain::Align< 8>) => Some( 8)); 1039 test!(#[repr(C, align( 8))] (u8; elain::Align< 16>) => Some( 16)); 1040 test!(#[repr(C, align( 16))] (u8; elain::Align< 32>) => Some( 32)); 1041 test!(#[repr(C, align( 32))] (u8; elain::Align< 64>) => Some( 64)); 1042 test!(#[repr(C, align( 64))] (u8; elain::Align< 128>) => Some( 128)); 1043 test!(#[repr(C, align( 128))] (u8; elain::Align< 256>) => Some( 256)); 1044 test!(#[repr(C, align( 256))] (u8; elain::Align< 512>) => Some( 512)); 1045 test!(#[repr(C, align( 512))] (u8; elain::Align< 1024>) => Some( 1024)); 1046 test!(#[repr(C, align( 1024))] (u8; elain::Align< 2048>) => Some( 2048)); 1047 test!(#[repr(C, align( 2048))] (u8; elain::Align< 4096>) => Some( 4096)); 1048 test!(#[repr(C, align( 4096))] (u8; elain::Align< 8192>) => Some( 8192)); 1049 test!(#[repr(C, align( 8192))] (u8; elain::Align< 16384>) => Some( 16384)); 1050 test!(#[repr(C, align( 16384))] (u8; elain::Align< 32768>) => Some( 32768)); 1051 test!(#[repr(C, align( 32768))] (u8; elain::Align< 65536>) => Some( 65536)); 1052 /* Alignments above 65536 are not yet supported. 1053 test!(#[repr(C, align( 65536))] (u8; elain::Align< 131072>) => Some( 131072)); 1054 test!(#[repr(C, align( 131072))] (u8; elain::Align< 262144>) => Some( 262144)); 1055 test!(#[repr(C, align( 262144))] (u8; elain::Align< 524288>) => Some( 524288)); 1056 test!(#[repr(C, align( 524288))] (u8; elain::Align< 1048576>) => Some( 1048576)); 1057 test!(#[repr(C, align( 1048576))] (u8; elain::Align< 2097152>) => Some( 2097152)); 1058 test!(#[repr(C, align( 2097152))] (u8; elain::Align< 4194304>) => Some( 4194304)); 1059 test!(#[repr(C, align( 4194304))] (u8; elain::Align< 8388608>) => Some( 8388608)); 1060 test!(#[repr(C, align( 8388608))] (u8; elain::Align< 16777216>) => Some( 16777216)); 1061 test!(#[repr(C, align( 16777216))] (u8; elain::Align< 33554432>) => Some( 33554432)); 1062 test!(#[repr(C, align( 33554432))] (u8; elain::Align< 67108864>) => Some( 67108864)); 1063 test!(#[repr(C, align( 67108864))] (u8; elain::Align< 33554432>) => Some( 33554432)); 1064 test!(#[repr(C, align( 33554432))] (u8; elain::Align<134217728>) => Some(134217728)); 1065 test!(#[repr(C, align(134217728))] (u8; elain::Align<268435456>) => Some(268435456)); 1066 */ 1067 } 1068 1069 // FIXME(#29), FIXME(https://github.com/rust-lang/rust/issues/69835): 1070 // Remove this `cfg` when `size_of_val_raw` is stabilized. 1071 #[allow(clippy::decimal_literal_representation)] 1072 #[test] 1073 fn test_align_of_dst() { 1074 // Test that `align_of!` correctly computes the alignment of DSTs. 1075 assert_eq!(align_of!([elain::Align<1>]), Some(1)); 1076 assert_eq!(align_of!([elain::Align<2>]), Some(2)); 1077 assert_eq!(align_of!([elain::Align<4>]), Some(4)); 1078 assert_eq!(align_of!([elain::Align<8>]), Some(8)); 1079 assert_eq!(align_of!([elain::Align<16>]), Some(16)); 1080 assert_eq!(align_of!([elain::Align<32>]), Some(32)); 1081 assert_eq!(align_of!([elain::Align<64>]), Some(64)); 1082 assert_eq!(align_of!([elain::Align<128>]), Some(128)); 1083 assert_eq!(align_of!([elain::Align<256>]), Some(256)); 1084 assert_eq!(align_of!([elain::Align<512>]), Some(512)); 1085 assert_eq!(align_of!([elain::Align<1024>]), Some(1024)); 1086 assert_eq!(align_of!([elain::Align<2048>]), Some(2048)); 1087 assert_eq!(align_of!([elain::Align<4096>]), Some(4096)); 1088 assert_eq!(align_of!([elain::Align<8192>]), Some(8192)); 1089 assert_eq!(align_of!([elain::Align<16384>]), Some(16384)); 1090 assert_eq!(align_of!([elain::Align<32768>]), Some(32768)); 1091 assert_eq!(align_of!([elain::Align<65536>]), Some(65536)); 1092 /* Alignments above 65536 are not yet supported. 1093 assert_eq!(align_of!([elain::Align<131072>]), Some(131072)); 1094 assert_eq!(align_of!([elain::Align<262144>]), Some(262144)); 1095 assert_eq!(align_of!([elain::Align<524288>]), Some(524288)); 1096 assert_eq!(align_of!([elain::Align<1048576>]), Some(1048576)); 1097 assert_eq!(align_of!([elain::Align<2097152>]), Some(2097152)); 1098 assert_eq!(align_of!([elain::Align<4194304>]), Some(4194304)); 1099 assert_eq!(align_of!([elain::Align<8388608>]), Some(8388608)); 1100 assert_eq!(align_of!([elain::Align<16777216>]), Some(16777216)); 1101 assert_eq!(align_of!([elain::Align<33554432>]), Some(33554432)); 1102 assert_eq!(align_of!([elain::Align<67108864>]), Some(67108864)); 1103 assert_eq!(align_of!([elain::Align<33554432>]), Some(33554432)); 1104 assert_eq!(align_of!([elain::Align<134217728>]), Some(134217728)); 1105 assert_eq!(align_of!([elain::Align<268435456>]), Some(268435456)); 1106 */ 1107 } 1108 } 1109 1110 #[test] 1111 fn test_enum_casts() { 1112 // Test that casting the variants of enums with signed integer reprs to 1113 // unsigned integers obeys expected signed -> unsigned casting rules. 1114 1115 #[repr(i8)] 1116 enum ReprI8 { 1117 MinusOne = -1, 1118 Zero = 0, 1119 Min = i8::MIN, 1120 Max = i8::MAX, 1121 } 1122 1123 #[allow(clippy::as_conversions)] 1124 let x = ReprI8::MinusOne as u8; 1125 assert_eq!(x, u8::MAX); 1126 1127 #[allow(clippy::as_conversions)] 1128 let x = ReprI8::Zero as u8; 1129 assert_eq!(x, 0); 1130 1131 #[allow(clippy::as_conversions)] 1132 let x = ReprI8::Min as u8; 1133 assert_eq!(x, 128); 1134 1135 #[allow(clippy::as_conversions)] 1136 let x = ReprI8::Max as u8; 1137 assert_eq!(x, 127); 1138 } 1139 1140 #[test] 1141 fn test_struct_padding() { 1142 // Test that, for each provided repr, `struct_padding!` reports the 1143 // expected value. 1144 macro_rules! test { 1145 (#[$cfg:meta] ($($ts:ty),*) => $expect:expr) => {{ 1146 #[$cfg] 1147 #[allow(dead_code)] 1148 struct Test($($ts),*); 1149 assert_eq!(struct_padding!(Test, None::<NonZeroUsize>, None::<NonZeroUsize>, [$($ts),*]), $expect); 1150 }}; 1151 (#[$cfg:meta] $(#[$cfgs:meta])* ($($ts:ty),*) => $expect:expr) => { 1152 test!(#[$cfg] ($($ts),*) => $expect); 1153 test!($(#[$cfgs])* ($($ts),*) => $expect); 1154 }; 1155 } 1156 1157 test!(#[repr(C)] #[repr(transparent)] #[repr(packed)] () => 0); 1158 test!(#[repr(C)] #[repr(transparent)] #[repr(packed)] (u8) => 0); 1159 test!(#[repr(C)] #[repr(transparent)] #[repr(packed)] (u8, ()) => 0); 1160 test!(#[repr(C)] #[repr(packed)] (u8, u8) => 0); 1161 1162 test!(#[repr(C)] (u8, AU64) => 7); 1163 // Rust won't let you put `#[repr(packed)]` on a type which contains a 1164 // `#[repr(align(n > 1))]` type (`AU64`), so we have to use `u64` here. 1165 // It's not ideal, but it definitely has align > 1 on /some/ of our CI 1166 // targets, and this isn't a particularly complex macro we're testing 1167 // anyway. 1168 test!(#[repr(packed)] (u8, u64) => 0); 1169 } 1170 1171 #[test] 1172 fn test_repr_c_struct_padding() { 1173 // Test that, for each provided repr, `repr_c_struct_padding!` reports 1174 // the expected value. 1175 macro_rules! test { 1176 (($($ts:tt),*) => $expect:expr) => {{ 1177 #[repr(C)] 1178 #[allow(dead_code)] 1179 struct Test($($ts),*); 1180 assert_eq!(repr_c_struct_has_padding!(Test, None::<NonZeroUsize>, None::<NonZeroUsize>, [$($ts),*]), $expect); 1181 }}; 1182 } 1183 1184 // Test static padding 1185 test!(() => false); 1186 test!(([u8]) => false); 1187 test!((u8) => false); 1188 test!((u8, [u8]) => false); 1189 test!((u8, ()) => false); 1190 test!((u8, (), [u8]) => false); 1191 test!((u8, u8) => false); 1192 test!((u8, u8, [u8]) => false); 1193 1194 test!((u8, AU64) => true); 1195 test!((u8, AU64, [u8]) => true); 1196 1197 // Test dynamic padding 1198 test!((AU64, [AU64]) => false); 1199 test!((u8, [AU64]) => true); 1200 1201 #[repr(align(4))] 1202 struct AU32(#[allow(unused)] u32); 1203 test!((AU64, [AU64]) => false); 1204 test!((AU64, [AU32]) => true); 1205 } 1206 1207 #[test] 1208 fn test_union_padding() { 1209 // Test that, for each provided repr, `union_padding!` reports the 1210 // expected value. 1211 macro_rules! test { 1212 (#[$cfg:meta] {$($fs:ident: $ts:ty),*} => $expect:expr) => {{ 1213 #[$cfg] 1214 #[allow(unused)] // fields are never read 1215 union Test{ $($fs: $ts),* } 1216 assert_eq!(union_padding!(Test, None::<NonZeroUsize>, None::<usize>, [$($ts),*]), $expect); 1217 }}; 1218 (#[$cfg:meta] $(#[$cfgs:meta])* {$($fs:ident: $ts:ty),*} => $expect:expr) => { 1219 test!(#[$cfg] {$($fs: $ts),*} => $expect); 1220 test!($(#[$cfgs])* {$($fs: $ts),*} => $expect); 1221 }; 1222 } 1223 1224 test!(#[repr(C)] #[repr(packed)] {a: u8} => 0); 1225 test!(#[repr(C)] #[repr(packed)] {a: u8, b: u8} => 0); 1226 1227 // Rust won't let you put `#[repr(packed)]` on a type which contains a 1228 // `#[repr(align(n > 1))]` type (`AU64`), so we have to use `u64` here. 1229 // It's not ideal, but it definitely has align > 1 on /some/ of our CI 1230 // targets, and this isn't a particularly complex macro we're testing 1231 // anyway. 1232 test!(#[repr(C)] #[repr(packed)] {a: u8, b: u64} => 7); 1233 } 1234 1235 #[test] 1236 fn test_enum_padding() { 1237 // Test that, for each provided repr, `enum_has_padding!` reports the 1238 // expected value. 1239 macro_rules! test { 1240 (#[repr($disc:ident $(, $c:ident)?)] { $($vs:ident ($($ts:ty),*),)* } => $expect:expr) => { 1241 test!(@case #[repr($disc $(, $c)?)] { $($vs ($($ts),*),)* } => $expect); 1242 }; 1243 (#[repr($disc:ident $(, $c:ident)?)] #[$cfg:meta] $(#[$cfgs:meta])* { $($vs:ident ($($ts:ty),*),)* } => $expect:expr) => { 1244 test!(@case #[repr($disc $(, $c)?)] #[$cfg] { $($vs ($($ts),*),)* } => $expect); 1245 test!(#[repr($disc $(, $c)?)] $(#[$cfgs])* { $($vs ($($ts),*),)* } => $expect); 1246 }; 1247 (@case #[repr($disc:ident $(, $c:ident)?)] $(#[$cfg:meta])? { $($vs:ident ($($ts:ty),*),)* } => $expect:expr) => {{ 1248 #[repr($disc $(, $c)?)] 1249 $(#[$cfg])? 1250 #[allow(unused)] // variants and fields are never used 1251 enum Test { 1252 $($vs ($($ts),*),)* 1253 } 1254 assert_eq!( 1255 enum_padding!(Test, None::<NonZeroUsize>, None::<NonZeroUsize>, $disc, $([$($ts),*]),*), 1256 $expect 1257 ); 1258 }}; 1259 } 1260 1261 #[allow(unused)] 1262 #[repr(align(2))] 1263 struct U16(u16); 1264 1265 #[allow(unused)] 1266 #[repr(align(4))] 1267 struct U32(u32); 1268 1269 test!(#[repr(u8)] #[repr(C)] { 1270 A(u8), 1271 } => 0); 1272 test!(#[repr(u16)] #[repr(C)] { 1273 A(u8, u8), 1274 B(U16), 1275 } => 0); 1276 test!(#[repr(u32)] #[repr(C)] { 1277 A(u8, u8, u8, u8), 1278 B(U16, u8, u8), 1279 C(u8, u8, U16), 1280 D(U16, U16), 1281 E(U32), 1282 } => 0); 1283 1284 // `repr(int)` can pack the discriminant more efficiently 1285 test!(#[repr(u8)] { 1286 A(u8, U16), 1287 } => 0); 1288 test!(#[repr(u8)] { 1289 A(u8, U16, U32), 1290 } => 0); 1291 1292 // `repr(C)` cannot 1293 test!(#[repr(u8, C)] { 1294 A(u8, U16), 1295 } => 2); 1296 test!(#[repr(u8, C)] { 1297 A(u8, u8, u8, U32), 1298 } => 4); 1299 1300 // And field ordering can always cause problems 1301 test!(#[repr(u8)] #[repr(C)] { 1302 A(U16, u8), 1303 } => 2); 1304 test!(#[repr(u8)] #[repr(C)] { 1305 A(U32, u8, u8, u8), 1306 } => 4); 1307 } 1308 } 1309