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::CastSizedExact, 32 invariant::{Aligned, Initialized, Safe}, 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_safe`]. 522 /// 523 /// [`is_safe`]: TryFromBytes::is_safe 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 src = mem::ManuallyDrop::new(ReadOnly::new(src)); 533 let mut ptr = 534 Ptr::from_ref(&*src).transmute_with::<ReadOnly<Dst>, Initialized, CastSizedExact, _>(); 535 if Dst::is_safe(ptr.reborrow_shared()) { 536 // SAFETY: `read_unaligned` requires that `ptr` be valid for reads and 537 // point to a properly initialized `ReadOnly<Dst>` [1]. `ptr` was 538 // derived from a live reference to `src`; `CastSizedExact` preserves 539 // that reference's address, provenance, and exact byte extent. Thus, 540 // the entire range remains live and valid for reads. The reference is 541 // non-null even when `ReadOnly<Dst>` is zero-sized, and the cast 542 // preserves that address, satisfying [1]'s explicit ZST requirement. 543 // 544 // `Src: IntoBytes` and the `ReadOnly<Src>` bridge let `transmute_with` 545 // establish that every byte in that exact range is initialized. 546 // `Dst::is_safe` then established that the same bytes are bit-valid for 547 // `Dst`, and thus for `ReadOnly<Dst>`. The candidate was a shared 548 // `ReadOnly` pointer, so it could not mutate the bytes; no operation 549 // occurs between validation and this read which could do so. Alignment 550 // is not an additional precondition because [1] expressly permits 551 // unaligned pointers. 552 // 553 // `read_unaligned` leaves the source memory unchanged and makes a 554 // bitwise copy [1]. The source is wrapped in `ManuallyDrop`, which 555 // inhibits its destructor [2]. After this read, neither `src` nor 556 // `ptr` is used to access the inner value, and the wrapper's eventual 557 // drop does not drop it. Thus, only the returned `Dst` is subsequently 558 // used or dropped; there is no duplicate ownership use. 559 // 560 // [1] Per https://doc.rust-lang.org/1.56.0/std/ptr/fn.read_unaligned.html: 561 // 562 // Reads the value from `src` without moving it. This leaves the 563 // memory in `src` unchanged. 564 // 565 // Unlike `read`, `read_unaligned` works with unaligned pointers. 566 // 567 // Behavior is undefined if any of the following conditions are 568 // violated: 569 // 570 // * `src` must be valid for reads. 571 // 572 // * `src` must point to a properly initialized value of type `T`. 573 // 574 // Like `read`, `read_unaligned` creates a bitwise copy of `T`, 575 // regardless of whether `T` is `Copy`. If `T` is not `Copy`, using 576 // both the returned value and the value at `*src` can violate 577 // memory safety. 578 // 579 // Note that even if `T` has size `0`, the pointer must be non-null. 580 // 581 // [2] Per https://doc.rust-lang.org/1.56.0/std/mem/struct.ManuallyDrop.html: 582 // 583 // A wrapper to inhibit compiler from automatically calling `T`'s 584 // destructor. 585 let dst = unsafe { core::ptr::read_unaligned(ptr.as_inner().as_ptr()) }; 586 Ok(ReadOnly::into_inner(dst)) 587 } else { 588 let src = ReadOnly::into_inner(mem::ManuallyDrop::into_inner(src)); 589 Err(ValidityError::new(src)) 590 } 591 } 592 593 /// See `try_transmute_ref!` documentation. 594 pub trait TryTransmuteRefDst<'a> { 595 type Dst: ?Sized; 596 597 /// See `try_transmute_ref!` documentation. 598 fn try_transmute_ref(self) -> Result<&'a Self::Dst, ValidityError<&'a Self::Src, Self::Dst>> 599 where 600 Self: TryTransmuteRefSrc<'a>, 601 Self::Src: IntoBytes + Immutable + KnownLayout, 602 Self::Dst: TryFromBytes + Immutable + KnownLayout; 603 } 604 605 pub trait TryTransmuteRefSrc<'a> { 606 type Src: ?Sized; 607 } 608 609 impl<'a, Src, Dst> TryTransmuteRefSrc<'a> for Wrap<&'a Src, &'a Dst> 610 where 611 Src: ?Sized, 612 Dst: ?Sized, 613 { 614 type Src = Src; 615 } 616 617 impl<'a, Src, Dst> TryTransmuteRefDst<'a> for Wrap<&'a Src, &'a Dst> 618 where 619 Src: IntoBytes + Immutable + KnownLayout + ?Sized, 620 Dst: TryFromBytes + Immutable + KnownLayout + ?Sized, 621 { 622 type Dst = Dst; 623 624 #[inline(always)] 625 fn try_transmute_ref( 626 self, 627 ) -> Result< 628 &'a Dst, 629 ValidityError<&'a <Wrap<&'a Src, &'a Dst> as TryTransmuteRefSrc<'a>>::Src, Dst>, 630 > { 631 let ptr = Ptr::from_ref(self.0); 632 #[rustfmt::skip] 633 let res = ptr.try_with(#[inline(always)] |ptr| { 634 let ptr = ptr.recall_validity::<Initialized, _>(); 635 let ptr = ptr.cast::<_, crate::layout::CastFrom<Dst>, _>(); 636 ptr.try_into_safe() 637 }); 638 match res { 639 Ok(ptr) => { 640 static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => { 641 Src::LAYOUT.align.get() >= Dst::LAYOUT.align.get() 642 }, "cannot transmute reference when destination type has higher alignment than source type"); 643 // SAFETY: We have checked that `Dst` does not have a stricter 644 // alignment requirement than `Src`. 645 let ptr = unsafe { ptr.assume_alignment::<Aligned>() }; 646 Ok(ptr.as_ref()) 647 } 648 Err(err) => Err(err.map_src(Ptr::as_ref)), 649 } 650 } 651 } 652 653 pub trait TryTransmuteMutDst<'a> { 654 type Dst: ?Sized; 655 656 /// See `try_transmute_mut!` documentation. 657 fn try_transmute_mut( 658 self, 659 ) -> Result<&'a mut Self::Dst, ValidityError<&'a mut Self::Src, Self::Dst>> 660 where 661 Self: TryTransmuteMutSrc<'a>, 662 Self::Src: IntoBytes, 663 Self::Dst: TryFromBytes; 664 } 665 666 pub trait TryTransmuteMutSrc<'a> { 667 type Src: ?Sized; 668 } 669 670 impl<'a, Src, Dst> TryTransmuteMutSrc<'a> for Wrap<&'a mut Src, &'a mut Dst> 671 where 672 Src: ?Sized, 673 Dst: ?Sized, 674 { 675 type Src = Src; 676 } 677 678 impl<'a, Src, Dst> TryTransmuteMutDst<'a> for Wrap<&'a mut Src, &'a mut Dst> 679 where 680 Src: FromBytes + IntoBytes + KnownLayout + ?Sized, 681 Dst: TryFromBytes + IntoBytes + KnownLayout + ?Sized, 682 { 683 type Dst = Dst; 684 685 #[inline(always)] 686 fn try_transmute_mut( 687 self, 688 ) -> Result< 689 &'a mut Dst, 690 ValidityError<&'a mut <Wrap<&'a mut Src, &'a mut Dst> as TryTransmuteMutSrc<'a>>::Src, Dst>, 691 > { 692 let ptr = Ptr::from_mut(self.0); 693 // SAFETY: The provided closure returns the only copy of `ptr`. 694 #[rustfmt::skip] 695 let res = unsafe { 696 ptr.try_with_unchecked(#[inline(always)] |ptr| { 697 let ptr = ptr.recall_validity::<Initialized, (_, (_, _))>(); 698 let ptr = ptr.cast::<_, crate::layout::CastFrom<Dst>, _>(); 699 ptr.try_into_safe() 700 }) 701 }; 702 match res { 703 Ok(ptr) => { 704 static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => { 705 Src::LAYOUT.align.get() >= Dst::LAYOUT.align.get() 706 }, "cannot transmute reference when destination type has higher alignment than source type"); 707 // SAFETY: We have checked that `Dst` does not have a stricter 708 // alignment requirement than `Src`. 709 let ptr = unsafe { ptr.assume_alignment::<Aligned>() }; 710 Ok(ptr.as_mut()) 711 } 712 Err(err) => Err(err.map_src(Ptr::as_mut)), 713 } 714 } 715 } 716 717 // Used in `transmute_ref!` and friends. 718 // 719 // This permits us to use the autoref specialization trick to dispatch to 720 // associated functions for `transmute_ref` and `transmute_mut` when both `Src` 721 // and `Dst` are `Sized`, and to trait methods otherwise. The associated 722 // functions, unlike the trait methods, do not require a `KnownLayout` bound. 723 // This permits us to add support for transmuting references to unsized types 724 // without breaking backwards-compatibility (on v0.8.x) with the old 725 // implementation, which did not require a `KnownLayout` bound to transmute 726 // sized types. 727 #[derive(Copy, Clone)] 728 pub struct Wrap<Src, Dst>(pub Src, pub PhantomData<Dst>); 729 730 impl<Src, Dst> Wrap<Src, Dst> { 731 #[inline(always)] 732 pub const fn new(src: Src) -> Self { 733 Wrap(src, PhantomData) 734 } 735 } 736 737 impl<'a, Src, Dst> Wrap<&'a Src, &'a Dst> 738 where 739 Src: ?Sized, 740 Dst: ?Sized, 741 { 742 #[allow(clippy::must_use_candidate, clippy::missing_inline_in_public_items, clippy::empty_loop)] 743 pub const fn transmute_ref_inference_helper(self) -> &'a Dst { 744 loop {} 745 } 746 } 747 748 impl<'a, Src, Dst> Wrap<&'a Src, &'a Dst> { 749 /// # Safety 750 /// The caller must guarantee that: 751 /// - `Src: IntoBytes + Immutable` 752 /// - `Dst: FromBytes + Immutable` 753 /// 754 /// # PME 755 /// 756 /// Instantiating this method PMEs unless both: 757 /// - `mem::size_of::<Dst>() == mem::size_of::<Src>()` 758 /// - `mem::align_of::<Dst>() <= mem::align_of::<Src>()` 759 #[inline(always)] 760 #[must_use] 761 pub const unsafe fn transmute_ref(self) -> &'a Dst { 762 static_assert!(Src, Dst => mem::size_of::<Dst>() == mem::size_of::<Src>()); 763 static_assert!(Src, Dst => mem::align_of::<Dst>() <= mem::align_of::<Src>()); 764 765 let src: *const Src = self.0; 766 let dst = src.cast::<Dst>(); 767 // SAFETY: 768 // - We know that it is sound to view the target type of the input 769 // reference (`Src`) as the target type of the output reference 770 // (`Dst`) because the caller has guaranteed that `Src: IntoBytes`, 771 // `Dst: FromBytes`, and `size_of::<Src>() == size_of::<Dst>()`. 772 // - We know that there are no `UnsafeCell`s, and thus we don't have to 773 // worry about `UnsafeCell` overlap, because `Src: Immutable` and 774 // `Dst: Immutable`. 775 // - The caller has guaranteed that alignment is not increased. 776 // - We know that the returned lifetime will not outlive the input 777 // lifetime thanks to the lifetime bounds on this function. 778 // 779 // FIXME(#67): Once our MSRV is 1.58, replace this `transmute` with 780 // `&*dst`. 781 #[allow(clippy::transmute_ptr_to_ref)] 782 unsafe { 783 mem::transmute(dst) 784 } 785 } 786 787 #[inline(always)] 788 pub fn try_transmute_ref(self) -> Result<&'a Dst, ValidityError<&'a Src, Dst>> 789 where 790 Src: IntoBytes + Immutable, 791 Dst: TryFromBytes + Immutable, 792 { 793 static_assert!(Src => mem::align_of::<Src>() == mem::align_of::<Wrapping<Src>>()); 794 static_assert!(Dst => mem::align_of::<Dst>() == mem::align_of::<Wrapping<Dst>>()); 795 796 // SAFETY: By the preceding assert, `Src` and `Wrapping<Src>` have the 797 // same alignment. 798 let src: &Wrapping<Src> = 799 unsafe { crate::util::transmute_ref::<_, _, BecauseImmutable>(self.0) }; 800 let src = Wrap::new(src); 801 <Wrap<&'a Wrapping<Src>, &'a Wrapping<Dst>> as TryTransmuteRefDst<'a>>::try_transmute_ref( 802 src, 803 ) 804 .map( 805 // SAFETY: By the preceding assert, `Dst` and `Wrapping<Dst>` have 806 // the same alignment. 807 #[inline(always)] 808 |dst| unsafe { crate::util::transmute_ref::<_, _, BecauseImmutable>(dst) }, 809 ) 810 .map_err( 811 #[inline(always)] 812 |err| { 813 // SAFETY: By the preceding assert, `Src` and `Wrapping<Src>` have the 814 // same alignment. 815 ValidityError::new(unsafe { 816 crate::util::transmute_ref::<_, _, BecauseImmutable>(err.into_src()) 817 }) 818 }, 819 ) 820 } 821 } 822 823 impl<'a, Src, Dst> Wrap<&'a mut Src, &'a mut Dst> 824 where 825 Src: ?Sized, 826 Dst: ?Sized, 827 { 828 #[allow(clippy::must_use_candidate, clippy::missing_inline_in_public_items, clippy::empty_loop)] 829 pub fn transmute_mut_inference_helper(self) -> &'a mut Dst { 830 loop {} 831 } 832 } 833 834 impl<'a, Src, Dst> Wrap<&'a mut Src, &'a mut Dst> { 835 /// Transmutes a mutable reference of one type to a mutable reference of 836 /// another type. 837 /// 838 /// # PME 839 /// 840 /// Instantiating this method PMEs unless both: 841 /// - `mem::size_of::<Dst>() == mem::size_of::<Src>()` 842 /// - `mem::align_of::<Dst>() <= mem::align_of::<Src>()` 843 #[inline(always)] 844 #[must_use] 845 pub fn transmute_mut(self) -> &'a mut Dst 846 where 847 Src: FromBytes + IntoBytes, 848 Dst: FromBytes + IntoBytes, 849 { 850 static_assert!(Src, Dst => mem::size_of::<Dst>() == mem::size_of::<Src>()); 851 static_assert!(Src, Dst => mem::align_of::<Dst>() <= mem::align_of::<Src>()); 852 853 let src: *mut Src = self.0; 854 let dst = src.cast::<Dst>(); 855 // SAFETY: 856 // - We know that it is sound to view the target type of the input 857 // reference (`Src`) as the target type of the output reference 858 // (`Dst`) and vice-versa because `Src: FromBytes + IntoBytes`, `Dst: 859 // FromBytes + IntoBytes`, and (as asserted above) `size_of::<Src>() 860 // == size_of::<Dst>()`. 861 // - We asserted above that alignment will not increase. 862 // - We know that the returned lifetime will not outlive the input 863 // lifetime thanks to the lifetime bounds on this function. 864 unsafe { &mut *dst } 865 } 866 867 #[inline(always)] 868 pub fn try_transmute_mut(self) -> Result<&'a mut Dst, ValidityError<&'a mut Src, Dst>> 869 where 870 Src: FromBytes + IntoBytes, 871 Dst: TryFromBytes + IntoBytes, 872 { 873 static_assert!(Src => mem::align_of::<Src>() == mem::align_of::<Wrapping<Src>>()); 874 static_assert!(Dst => mem::align_of::<Dst>() == mem::align_of::<Wrapping<Dst>>()); 875 876 // SAFETY: By the preceding assert, `Src` and `Wrapping<Src>` have the 877 // same alignment. 878 let src: &mut Wrapping<Src> = 879 unsafe { crate::util::transmute_mut::<_, _, (_, (_, _))>(self.0) }; 880 let src = Wrap::new(src); 881 <Wrap<&'a mut Wrapping<Src>, &'a mut Wrapping<Dst>> as TryTransmuteMutDst<'a>> 882 ::try_transmute_mut(src) 883 // SAFETY: By the preceding assert, `Dst` and `Wrapping<Dst>` have the 884 // same alignment. 885 .map(|dst| unsafe { crate::util::transmute_mut::<_, _, (_, (_, _))>(dst) }) 886 .map_err(|err| { 887 // SAFETY: By the preceding assert, `Src` and `Wrapping<Src>` have the 888 // same alignment. 889 ValidityError::new(unsafe { 890 crate::util::transmute_mut::<_, _, (_, (_, _))>(err.into_src()) 891 }) 892 }) 893 } 894 } 895 896 pub trait TransmuteRefDst<'a> { 897 type Dst: ?Sized; 898 899 #[must_use] 900 fn transmute_ref(self) -> &'a Self::Dst; 901 } 902 903 impl<'a, Src: ?Sized, Dst: ?Sized> TransmuteRefDst<'a> for Wrap<&'a Src, &'a Dst> 904 where 905 Src: KnownLayout + IntoBytes + Immutable, 906 Dst: KnownLayout<PointerMetadata = usize> + FromBytes + Immutable, 907 { 908 type Dst = Dst; 909 910 #[inline(always)] 911 fn transmute_ref(self) -> &'a Dst { 912 let ptr = Ptr::from_ref(self.0) 913 .recall_validity::<Initialized, _>() 914 .transmute_with::<Dst, Initialized, crate::layout::CastFrom<Dst>, (crate::pointer::BecauseMutationCompatible, _)>() 915 .recall_validity::<Safe, _>(); 916 917 static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => { 918 Src::LAYOUT.align.get() >= Dst::LAYOUT.align.get() 919 }, "cannot transmute reference when destination type has higher alignment than source type"); 920 921 // SAFETY: The preceding `static_assert!` ensures that 922 // `Src::LAYOUT.align >= Dst::LAYOUT.align`. Since `self` is 923 // validly-aligned for `Src`, it is also validly-aligned for `Dst`. 924 let ptr = unsafe { ptr.assume_alignment() }; 925 926 ptr.as_ref() 927 } 928 } 929 930 pub trait TransmuteMutDst<'a> { 931 type Dst: ?Sized; 932 #[must_use] 933 fn transmute_mut(self) -> &'a mut Self::Dst; 934 } 935 936 impl<'a, Src: ?Sized, Dst: ?Sized> TransmuteMutDst<'a> for Wrap<&'a mut Src, &'a mut Dst> 937 where 938 Src: KnownLayout + FromBytes + IntoBytes, 939 Dst: KnownLayout<PointerMetadata = usize> + FromBytes + IntoBytes, 940 { 941 type Dst = Dst; 942 943 #[inline(always)] 944 fn transmute_mut(self) -> &'a mut Dst { 945 let ptr = Ptr::from_mut(self.0) 946 .recall_validity::<Initialized, (_, (_, _))>() 947 .transmute_with::<Dst, Initialized, crate::layout::CastFrom<Dst>, _>() 948 .recall_validity::<Safe, (_, (_, _))>(); 949 950 static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => { 951 Src::LAYOUT.align.get() >= Dst::LAYOUT.align.get() 952 }, "cannot transmute reference when destination type has higher alignment than source type"); 953 954 // SAFETY: The preceding `static_assert!` ensures that 955 // `Src::LAYOUT.align >= Dst::LAYOUT.align`. Since `self` is 956 // validly-aligned for `Src`, it is also validly-aligned for `Dst`. 957 let ptr = unsafe { ptr.assume_alignment() }; 958 959 ptr.as_mut() 960 } 961 } 962 963 /// A function which emits a warning if its return value is not used. 964 #[must_use] 965 #[inline(always)] 966 pub const fn must_use<T>(t: T) -> T { 967 t 968 } 969 970 // NOTE: We can't change this to a `pub use core as core_reexport` until [1] is 971 // fixed or we update to a semver-breaking version (as of this writing, 0.8.0) 972 // on the `main` branch. 973 // 974 // [1] https://github.com/obi1kenobi/cargo-semver-checks/issues/573 975 pub mod core_reexport { 976 pub use core::*; 977 978 pub mod mem { 979 pub use core::mem::*; 980 } 981 } 982 983 /// Projects `Self` to itself. 984 /// 985 /// This is used by macros to have the compiler verify that two syntactically 986 /// similar types actually resolve to the same type. The blanket implementation 987 /// ensures that no other implementation can project a type to anything other 988 /// than itself. 989 #[doc(hidden)] 990 pub trait Identity { 991 /// `Self`. 992 type Type: ?Sized; 993 } 994 995 impl<T: ?Sized> Identity for T { 996 type Type = T; 997 } 998 999 #[cfg(test)] 1000 mod tests { 1001 use core::num::NonZeroUsize; 1002 1003 use crate::util::testutil::*; 1004 1005 #[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)] 1006 mod nightly { 1007 use super::super::*; 1008 use crate::util::testutil::*; 1009 1010 // FIXME(#29), FIXME(https://github.com/rust-lang/rust/issues/69835): 1011 // Remove this `cfg` when `size_of_val_raw` is stabilized. 1012 #[allow(clippy::decimal_literal_representation)] 1013 #[test] 1014 fn test_trailing_field_offset() { 1015 assert_eq!(mem::align_of::<Aligned64kAllocation>(), _64K); 1016 1017 macro_rules! test { 1018 (#[$cfg:meta] ($($ts:ty),* ; $trailing_field_ty:ty) => $expect:expr) => {{ 1019 #[$cfg] 1020 struct Test($(#[allow(dead_code)] $ts,)* #[allow(dead_code)] $trailing_field_ty); 1021 assert_eq!(test!(@offset $($ts),* ; $trailing_field_ty), $expect); 1022 }}; 1023 (#[$cfg:meta] $(#[$cfgs:meta])* ($($ts:ty),* ; $trailing_field_ty:ty) => $expect:expr) => { 1024 test!(#[$cfg] ($($ts),* ; $trailing_field_ty) => $expect); 1025 test!($(#[$cfgs])* ($($ts),* ; $trailing_field_ty) => $expect); 1026 }; 1027 (@offset ; $_trailing:ty) => { trailing_field_offset!(Test, 0) }; 1028 (@offset $_t:ty ; $_trailing:ty) => { trailing_field_offset!(Test, 1) }; 1029 } 1030 1031 test!(#[repr(C)] #[repr(transparent)] #[repr(packed)](; u8) => Some(0)); 1032 test!(#[repr(C)] #[repr(transparent)] #[repr(packed)](; [u8]) => Some(0)); 1033 test!(#[repr(C)] #[repr(C, packed)] (u8; u8) => Some(1)); 1034 test!(#[repr(C)] (; AU64) => Some(0)); 1035 test!(#[repr(C)] (; [AU64]) => Some(0)); 1036 test!(#[repr(C)] (u8; AU64) => Some(8)); 1037 test!(#[repr(C)] (u8; [AU64]) => Some(8)); 1038 1039 #[derive( 1040 Immutable, FromBytes, Eq, PartialEq, Ord, PartialOrd, Default, Debug, Copy, Clone, 1041 )] 1042 #[repr(C)] 1043 pub(crate) struct Nested<T, U: ?Sized> { 1044 _t: T, 1045 _u: U, 1046 } 1047 1048 test!(#[repr(C)] (; Nested<u8, AU64>) => Some(0)); 1049 test!(#[repr(C)] (; Nested<u8, [AU64]>) => Some(0)); 1050 test!(#[repr(C)] (u8; Nested<u8, AU64>) => Some(8)); 1051 test!(#[repr(C)] (u8; Nested<u8, [AU64]>) => Some(8)); 1052 1053 // Test that `packed(N)` limits the offset of the trailing field. 1054 test!(#[repr(C, packed( 1))] (u8; elain::Align< 2>) => Some( 1)); 1055 test!(#[repr(C, packed( 2))] (u8; elain::Align< 4>) => Some( 2)); 1056 test!(#[repr(C, packed( 4))] (u8; elain::Align< 8>) => Some( 4)); 1057 test!(#[repr(C, packed( 8))] (u8; elain::Align< 16>) => Some( 8)); 1058 test!(#[repr(C, packed( 16))] (u8; elain::Align< 32>) => Some( 16)); 1059 test!(#[repr(C, packed( 32))] (u8; elain::Align< 64>) => Some( 32)); 1060 test!(#[repr(C, packed( 64))] (u8; elain::Align< 128>) => Some( 64)); 1061 test!(#[repr(C, packed( 128))] (u8; elain::Align< 256>) => Some( 128)); 1062 test!(#[repr(C, packed( 256))] (u8; elain::Align< 512>) => Some( 256)); 1063 test!(#[repr(C, packed( 512))] (u8; elain::Align< 1024>) => Some( 512)); 1064 test!(#[repr(C, packed( 1024))] (u8; elain::Align< 2048>) => Some( 1024)); 1065 test!(#[repr(C, packed( 2048))] (u8; elain::Align< 4096>) => Some( 2048)); 1066 test!(#[repr(C, packed( 4096))] (u8; elain::Align< 8192>) => Some( 4096)); 1067 test!(#[repr(C, packed( 8192))] (u8; elain::Align< 16384>) => Some( 8192)); 1068 test!(#[repr(C, packed( 16384))] (u8; elain::Align< 32768>) => Some( 16384)); 1069 test!(#[repr(C, packed( 32768))] (u8; elain::Align< 65536>) => Some( 32768)); 1070 test!(#[repr(C, packed( 65536))] (u8; elain::Align< 131072>) => Some( 65536)); 1071 /* Alignments above 65536 are not yet supported. 1072 test!(#[repr(C, packed( 131072))] (u8; elain::Align< 262144>) => Some( 131072)); 1073 test!(#[repr(C, packed( 262144))] (u8; elain::Align< 524288>) => Some( 262144)); 1074 test!(#[repr(C, packed( 524288))] (u8; elain::Align< 1048576>) => Some( 524288)); 1075 test!(#[repr(C, packed( 1048576))] (u8; elain::Align< 2097152>) => Some( 1048576)); 1076 test!(#[repr(C, packed( 2097152))] (u8; elain::Align< 4194304>) => Some( 2097152)); 1077 test!(#[repr(C, packed( 4194304))] (u8; elain::Align< 8388608>) => Some( 4194304)); 1078 test!(#[repr(C, packed( 8388608))] (u8; elain::Align< 16777216>) => Some( 8388608)); 1079 test!(#[repr(C, packed( 16777216))] (u8; elain::Align< 33554432>) => Some( 16777216)); 1080 test!(#[repr(C, packed( 33554432))] (u8; elain::Align< 67108864>) => Some( 33554432)); 1081 test!(#[repr(C, packed( 67108864))] (u8; elain::Align< 33554432>) => Some( 67108864)); 1082 test!(#[repr(C, packed( 33554432))] (u8; elain::Align<134217728>) => Some( 33554432)); 1083 test!(#[repr(C, packed(134217728))] (u8; elain::Align<268435456>) => Some(134217728)); 1084 test!(#[repr(C, packed(268435456))] (u8; elain::Align<268435456>) => Some(268435456)); 1085 */ 1086 1087 // Test that `align(N)` does not limit the offset of the trailing field. 1088 test!(#[repr(C, align( 1))] (u8; elain::Align< 2>) => Some( 2)); 1089 test!(#[repr(C, align( 2))] (u8; elain::Align< 4>) => Some( 4)); 1090 test!(#[repr(C, align( 4))] (u8; elain::Align< 8>) => Some( 8)); 1091 test!(#[repr(C, align( 8))] (u8; elain::Align< 16>) => Some( 16)); 1092 test!(#[repr(C, align( 16))] (u8; elain::Align< 32>) => Some( 32)); 1093 test!(#[repr(C, align( 32))] (u8; elain::Align< 64>) => Some( 64)); 1094 test!(#[repr(C, align( 64))] (u8; elain::Align< 128>) => Some( 128)); 1095 test!(#[repr(C, align( 128))] (u8; elain::Align< 256>) => Some( 256)); 1096 test!(#[repr(C, align( 256))] (u8; elain::Align< 512>) => Some( 512)); 1097 test!(#[repr(C, align( 512))] (u8; elain::Align< 1024>) => Some( 1024)); 1098 test!(#[repr(C, align( 1024))] (u8; elain::Align< 2048>) => Some( 2048)); 1099 test!(#[repr(C, align( 2048))] (u8; elain::Align< 4096>) => Some( 4096)); 1100 test!(#[repr(C, align( 4096))] (u8; elain::Align< 8192>) => Some( 8192)); 1101 test!(#[repr(C, align( 8192))] (u8; elain::Align< 16384>) => Some( 16384)); 1102 test!(#[repr(C, align( 16384))] (u8; elain::Align< 32768>) => Some( 32768)); 1103 test!(#[repr(C, align( 32768))] (u8; elain::Align< 65536>) => Some( 65536)); 1104 /* Alignments above 65536 are not yet supported. 1105 test!(#[repr(C, align( 65536))] (u8; elain::Align< 131072>) => Some( 131072)); 1106 test!(#[repr(C, align( 131072))] (u8; elain::Align< 262144>) => Some( 262144)); 1107 test!(#[repr(C, align( 262144))] (u8; elain::Align< 524288>) => Some( 524288)); 1108 test!(#[repr(C, align( 524288))] (u8; elain::Align< 1048576>) => Some( 1048576)); 1109 test!(#[repr(C, align( 1048576))] (u8; elain::Align< 2097152>) => Some( 2097152)); 1110 test!(#[repr(C, align( 2097152))] (u8; elain::Align< 4194304>) => Some( 4194304)); 1111 test!(#[repr(C, align( 4194304))] (u8; elain::Align< 8388608>) => Some( 8388608)); 1112 test!(#[repr(C, align( 8388608))] (u8; elain::Align< 16777216>) => Some( 16777216)); 1113 test!(#[repr(C, align( 16777216))] (u8; elain::Align< 33554432>) => Some( 33554432)); 1114 test!(#[repr(C, align( 33554432))] (u8; elain::Align< 67108864>) => Some( 67108864)); 1115 test!(#[repr(C, align( 67108864))] (u8; elain::Align< 33554432>) => Some( 33554432)); 1116 test!(#[repr(C, align( 33554432))] (u8; elain::Align<134217728>) => Some(134217728)); 1117 test!(#[repr(C, align(134217728))] (u8; elain::Align<268435456>) => Some(268435456)); 1118 */ 1119 } 1120 1121 // FIXME(#29), FIXME(https://github.com/rust-lang/rust/issues/69835): 1122 // Remove this `cfg` when `size_of_val_raw` is stabilized. 1123 #[allow(clippy::decimal_literal_representation)] 1124 #[test] 1125 fn test_align_of_dst() { 1126 // Test that `align_of!` correctly computes the alignment of DSTs. 1127 assert_eq!(align_of!([elain::Align<1>]), Some(1)); 1128 assert_eq!(align_of!([elain::Align<2>]), Some(2)); 1129 assert_eq!(align_of!([elain::Align<4>]), Some(4)); 1130 assert_eq!(align_of!([elain::Align<8>]), Some(8)); 1131 assert_eq!(align_of!([elain::Align<16>]), Some(16)); 1132 assert_eq!(align_of!([elain::Align<32>]), Some(32)); 1133 assert_eq!(align_of!([elain::Align<64>]), Some(64)); 1134 assert_eq!(align_of!([elain::Align<128>]), Some(128)); 1135 assert_eq!(align_of!([elain::Align<256>]), Some(256)); 1136 assert_eq!(align_of!([elain::Align<512>]), Some(512)); 1137 assert_eq!(align_of!([elain::Align<1024>]), Some(1024)); 1138 assert_eq!(align_of!([elain::Align<2048>]), Some(2048)); 1139 assert_eq!(align_of!([elain::Align<4096>]), Some(4096)); 1140 assert_eq!(align_of!([elain::Align<8192>]), Some(8192)); 1141 assert_eq!(align_of!([elain::Align<16384>]), Some(16384)); 1142 assert_eq!(align_of!([elain::Align<32768>]), Some(32768)); 1143 assert_eq!(align_of!([elain::Align<65536>]), Some(65536)); 1144 /* Alignments above 65536 are not yet supported. 1145 assert_eq!(align_of!([elain::Align<131072>]), Some(131072)); 1146 assert_eq!(align_of!([elain::Align<262144>]), Some(262144)); 1147 assert_eq!(align_of!([elain::Align<524288>]), Some(524288)); 1148 assert_eq!(align_of!([elain::Align<1048576>]), Some(1048576)); 1149 assert_eq!(align_of!([elain::Align<2097152>]), Some(2097152)); 1150 assert_eq!(align_of!([elain::Align<4194304>]), Some(4194304)); 1151 assert_eq!(align_of!([elain::Align<8388608>]), Some(8388608)); 1152 assert_eq!(align_of!([elain::Align<16777216>]), Some(16777216)); 1153 assert_eq!(align_of!([elain::Align<33554432>]), Some(33554432)); 1154 assert_eq!(align_of!([elain::Align<67108864>]), Some(67108864)); 1155 assert_eq!(align_of!([elain::Align<33554432>]), Some(33554432)); 1156 assert_eq!(align_of!([elain::Align<134217728>]), Some(134217728)); 1157 assert_eq!(align_of!([elain::Align<268435456>]), Some(268435456)); 1158 */ 1159 } 1160 } 1161 1162 #[test] 1163 fn test_enum_casts() { 1164 // Test that casting the variants of enums with signed integer reprs to 1165 // unsigned integers obeys expected signed -> unsigned casting rules. 1166 1167 #[repr(i8)] 1168 enum ReprI8 { 1169 MinusOne = -1, 1170 Zero = 0, 1171 Min = i8::MIN, 1172 Max = i8::MAX, 1173 } 1174 1175 #[allow(clippy::as_conversions)] 1176 let x = ReprI8::MinusOne as u8; 1177 assert_eq!(x, u8::MAX); 1178 1179 #[allow(clippy::as_conversions)] 1180 let x = ReprI8::Zero as u8; 1181 assert_eq!(x, 0); 1182 1183 #[allow(clippy::as_conversions)] 1184 let x = ReprI8::Min as u8; 1185 assert_eq!(x, 128); 1186 1187 #[allow(clippy::as_conversions)] 1188 let x = ReprI8::Max as u8; 1189 assert_eq!(x, 127); 1190 } 1191 1192 #[test] 1193 fn test_struct_padding() { 1194 // Test that, for each provided repr, `struct_padding!` reports the 1195 // expected value. 1196 macro_rules! test { 1197 (#[$cfg:meta] ($($ts:ty),*) => $expect:expr) => {{ 1198 #[$cfg] 1199 #[allow(dead_code)] 1200 struct Test($($ts),*); 1201 assert_eq!(struct_padding!(Test, None::<NonZeroUsize>, None::<NonZeroUsize>, [$($ts),*]), $expect); 1202 }}; 1203 (#[$cfg:meta] $(#[$cfgs:meta])* ($($ts:ty),*) => $expect:expr) => { 1204 test!(#[$cfg] ($($ts),*) => $expect); 1205 test!($(#[$cfgs])* ($($ts),*) => $expect); 1206 }; 1207 } 1208 1209 test!(#[repr(C)] #[repr(transparent)] #[repr(packed)] () => 0); 1210 test!(#[repr(C)] #[repr(transparent)] #[repr(packed)] (u8) => 0); 1211 test!(#[repr(C)] #[repr(transparent)] #[repr(packed)] (u8, ()) => 0); 1212 test!(#[repr(C)] #[repr(packed)] (u8, u8) => 0); 1213 1214 test!(#[repr(C)] (u8, AU64) => 7); 1215 // Rust won't let you put `#[repr(packed)]` on a type which contains a 1216 // `#[repr(align(n > 1))]` type (`AU64`), so we have to use `u64` here. 1217 // It's not ideal, but it definitely has align > 1 on /some/ of our CI 1218 // targets, and this isn't a particularly complex macro we're testing 1219 // anyway. 1220 test!(#[repr(packed)] (u8, u64) => 0); 1221 } 1222 1223 #[test] 1224 fn test_repr_c_struct_padding() { 1225 // Test that, for each provided repr, `repr_c_struct_padding!` reports 1226 // the expected value. 1227 macro_rules! test { 1228 (($($ts:tt),*) => $expect:expr) => {{ 1229 #[repr(C)] 1230 #[allow(dead_code)] 1231 struct Test($($ts),*); 1232 assert_eq!(repr_c_struct_has_padding!(Test, None::<NonZeroUsize>, None::<NonZeroUsize>, [$($ts),*]), $expect); 1233 }}; 1234 } 1235 1236 // Test static padding 1237 test!(() => false); 1238 test!(([u8]) => false); 1239 test!((u8) => false); 1240 test!((u8, [u8]) => false); 1241 test!((u8, ()) => false); 1242 test!((u8, (), [u8]) => false); 1243 test!((u8, u8) => false); 1244 test!((u8, u8, [u8]) => false); 1245 1246 test!((u8, AU64) => true); 1247 test!((u8, AU64, [u8]) => true); 1248 1249 // Test dynamic padding 1250 test!((AU64, [AU64]) => false); 1251 test!((u8, [AU64]) => true); 1252 1253 #[repr(align(4))] 1254 struct AU32(#[allow(unused)] u32); 1255 test!((AU64, [AU64]) => false); 1256 test!((AU64, [AU32]) => true); 1257 } 1258 1259 #[test] 1260 fn test_union_padding() { 1261 // Test that, for each provided repr, `union_padding!` reports the 1262 // expected value. 1263 macro_rules! test { 1264 (#[$cfg:meta] {$($fs:ident: $ts:ty),*} => $expect:expr) => {{ 1265 #[$cfg] 1266 #[allow(unused)] // fields are never read 1267 union Test{ $($fs: $ts),* } 1268 assert_eq!(union_padding!(Test, None::<NonZeroUsize>, None::<usize>, [$($ts),*]), $expect); 1269 }}; 1270 (#[$cfg:meta] $(#[$cfgs:meta])* {$($fs:ident: $ts:ty),*} => $expect:expr) => { 1271 test!(#[$cfg] {$($fs: $ts),*} => $expect); 1272 test!($(#[$cfgs])* {$($fs: $ts),*} => $expect); 1273 }; 1274 } 1275 1276 test!(#[repr(C)] #[repr(packed)] {a: u8} => 0); 1277 test!(#[repr(C)] #[repr(packed)] {a: u8, b: u8} => 0); 1278 1279 // Rust won't let you put `#[repr(packed)]` on a type which contains a 1280 // `#[repr(align(n > 1))]` type (`AU64`), so we have to use `u64` here. 1281 // It's not ideal, but it definitely has align > 1 on /some/ of our CI 1282 // targets, and this isn't a particularly complex macro we're testing 1283 // anyway. 1284 test!(#[repr(C)] #[repr(packed)] {a: u8, b: u64} => 7); 1285 } 1286 1287 #[test] 1288 fn test_enum_padding() { 1289 // Test that, for each provided repr, `enum_has_padding!` reports the 1290 // expected value. 1291 macro_rules! test { 1292 (#[repr($disc:ident $(, $c:ident)?)] { $($vs:ident ($($ts:ty),*),)* } => $expect:expr) => { 1293 test!(@case #[repr($disc $(, $c)?)] { $($vs ($($ts),*),)* } => $expect); 1294 }; 1295 (#[repr($disc:ident $(, $c:ident)?)] #[$cfg:meta] $(#[$cfgs:meta])* { $($vs:ident ($($ts:ty),*),)* } => $expect:expr) => { 1296 test!(@case #[repr($disc $(, $c)?)] #[$cfg] { $($vs ($($ts),*),)* } => $expect); 1297 test!(#[repr($disc $(, $c)?)] $(#[$cfgs])* { $($vs ($($ts),*),)* } => $expect); 1298 }; 1299 (@case #[repr($disc:ident $(, $c:ident)?)] $(#[$cfg:meta])? { $($vs:ident ($($ts:ty),*),)* } => $expect:expr) => {{ 1300 #[repr($disc $(, $c)?)] 1301 $(#[$cfg])? 1302 #[allow(unused)] // variants and fields are never used 1303 enum Test { 1304 $($vs ($($ts),*),)* 1305 } 1306 assert_eq!( 1307 enum_padding!(Test, None::<NonZeroUsize>, None::<NonZeroUsize>, $disc, $([$($ts),*]),*), 1308 $expect 1309 ); 1310 }}; 1311 } 1312 1313 #[allow(unused)] 1314 #[repr(align(2))] 1315 struct U16(u16); 1316 1317 #[allow(unused)] 1318 #[repr(align(4))] 1319 struct U32(u32); 1320 1321 test!(#[repr(u8)] #[repr(C)] { 1322 A(u8), 1323 } => 0); 1324 test!(#[repr(u16)] #[repr(C)] { 1325 A(u8, u8), 1326 B(U16), 1327 } => 0); 1328 test!(#[repr(u32)] #[repr(C)] { 1329 A(u8, u8, u8, u8), 1330 B(U16, u8, u8), 1331 C(u8, u8, U16), 1332 D(U16, U16), 1333 E(U32), 1334 } => 0); 1335 1336 // `repr(int)` can pack the discriminant more efficiently 1337 test!(#[repr(u8)] { 1338 A(u8, U16), 1339 } => 0); 1340 test!(#[repr(u8)] { 1341 A(u8, U16, U32), 1342 } => 0); 1343 1344 // `repr(C)` cannot 1345 test!(#[repr(u8, C)] { 1346 A(u8, U16), 1347 } => 2); 1348 test!(#[repr(u8, C)] { 1349 A(u8, u8, u8, U32), 1350 } => 4); 1351 1352 // And field ordering can always cause problems 1353 test!(#[repr(u8)] #[repr(C)] { 1354 A(U16, u8), 1355 } => 2); 1356 test!(#[repr(u8)] #[repr(C)] { 1357 A(U32, u8, u8, u8), 1358 } => 4); 1359 } 1360 } 1361