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