From 5b5d5a6f1a1778923c2e727498ed0fc5eea92d81 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Sat, 12 Oct 2024 07:06:07 -0700 Subject: [PATCH 01/96] [ci] Don't run on push (#1882) We already have the merge queue; running on push is redundant. --- .github/workflows/ci.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b86152cbf6..6101661938 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,10 +10,6 @@ name: Build & Tests on: pull_request: - push: - branches: - - main - - v0.6.x merge_group: permissions: read-all From e7217b5f43d522ab6fbd4919c1583cf51e414ba4 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Sat, 12 Oct 2024 07:23:54 -0700 Subject: [PATCH 02/96] Release 0.9.0-alpha.0 (#1881) Upgrade our MSRV to 1.65 and remove version detection logic prior to that version. --- .github/workflows/ci.yml | 64 ---------- Cargo.toml | 25 +--- src/byteorder.rs | 58 +++++---- src/impls.rs | 18 ++- src/layout.rs | 47 ++++---- src/lib.rs | 10 -- src/pointer/ptr.rs | 2 +- src/util/macros.rs | 112 +----------------- src/util/mod.rs | 19 ++- src/wrappers.rs | 2 +- ...agnostic-not-implemented-from-bytes.stderr | 10 ++ ...agnostic-not-implemented-from-zeros.stderr | 10 ++ ...iagnostic-not-implemented-immutable.stderr | 10 ++ ...agnostic-not-implemented-into-bytes.stderr | 10 ++ ...agnostic-not-implemented-issue-1296.stderr | 36 +++++- ...nostic-not-implemented-known-layout.stderr | 10 ++ ...stic-not-implemented-try-from-bytes.stderr | 10 ++ ...iagnostic-not-implemented-unaligned.stderr | 10 ++ .../include_value_not_from_bytes.stderr | 21 +++- tests/ui-msrv/include_value_wrong_size.stderr | 2 +- .../invalid-impls/invalid-impls.stderr | 45 +++---- .../transmute-dst-not-frombytes.stderr | 19 ++- .../transmute-mut-alignment-increase.stderr | 28 +---- tests/ui-msrv/transmute-mut-const.stderr | 5 +- .../ui-msrv/transmute-mut-dst-generic.stderr | 4 +- .../transmute-mut-dst-not-a-reference.stderr | 10 +- .../transmute-mut-dst-not-frombytes.stderr | 19 ++- .../transmute-mut-dst-not-intobytes.stderr | 19 ++- .../ui-msrv/transmute-mut-dst-unsized.stderr | 40 +++---- .../transmute-mut-size-decrease.stderr | 28 +---- .../transmute-mut-size-increase.stderr | 28 +---- .../transmute-mut-src-dst-generic.stderr | 4 +- .../transmute-mut-src-dst-unsized.stderr | 110 +++++++++-------- .../ui-msrv/transmute-mut-src-generic.stderr | 4 +- .../transmute-mut-src-not-frombytes.stderr | 29 ++++- .../transmute-mut-src-not-intobytes.stderr | 29 ++++- .../ui-msrv/transmute-mut-src-unsized.stderr | 92 ++++++-------- tests/ui-msrv/transmute-ptr-to-usize.stderr | 29 ++++- .../transmute-ref-alignment-increase.stderr | 2 +- .../ui-msrv/transmute-ref-dst-generic.stderr | 4 +- .../ui-msrv/transmute-ref-dst-mutable.stderr | 10 +- .../transmute-ref-dst-not-a-reference.stderr | 10 +- .../transmute-ref-dst-not-frombytes.stderr | 19 ++- .../transmute-ref-dst-not-nocell.stderr | 19 ++- .../ui-msrv/transmute-ref-dst-unsized.stderr | 40 +++---- .../transmute-ref-size-decrease.stderr | 2 +- .../transmute-ref-size-increase.stderr | 2 +- .../transmute-ref-src-dst-generic.stderr | 4 +- ...ransmute-ref-src-dst-not-references.stderr | 10 +- .../transmute-ref-src-dst-unsized.stderr | 110 +++++++++-------- .../ui-msrv/transmute-ref-src-generic.stderr | 4 +- .../transmute-ref-src-not-intobytes.stderr | 29 ++++- .../transmute-ref-src-not-nocell.stderr | 29 ++++- .../ui-msrv/transmute-ref-src-unsized.stderr | 92 ++++++-------- .../transmute-src-not-intobytes.stderr | 29 ++++- .../try_transmute-dst-not-tryfrombytes.stderr | 30 +++++ .../try_transmute-size-decrease.stderr | 8 -- .../try_transmute-size-increase.stderr | 8 -- .../try_transmute-src-not-intobytes.stderr | 15 ++- ...ry_transmute_mut-alignment-increase.stderr | 10 +- ..._transmute_mut-dst-not-tryfrombytes.stderr | 30 +++++ .../try_transmute_mut-size-decrease.stderr | 10 +- .../try_transmute_mut-size-increase.stderr | 10 +- ...try_transmute_mut-src-not-intobytes.stderr | 15 ++- ...ry_transmute_ref-alignment-increase.stderr | 10 +- .../try_transmute_ref-dst-mutable.stderr | 20 +++- ..._ref-dst-not-immutable-tryfrombytes.stderr | 40 +++++++ .../try_transmute_ref-size-decrease.stderr | 10 +- .../try_transmute_ref-size-increase.stderr | 10 +- ...ute_ref-src-not-immutable-intobytes.stderr | 30 ++++- zerocopy-derive/Cargo.toml | 2 +- zerocopy-derive/tests/include.rs | 2 +- .../tests/struct_try_from_bytes.rs | 6 +- .../tests/ui-msrv/derive_transparent.stderr | 110 ++++++++++++----- zerocopy-derive/tests/ui-msrv/enum.stderr | 73 ++++++++++-- .../tests/ui-msrv/late_compile_pass.stderr | 100 ++++++++++++++++ .../tests/ui-msrv/mid_compile_pass.stderr | 20 ++-- .../tests/ui-msrv/msrv_specific.stderr | 16 ++- zerocopy-derive/tests/ui-msrv/struct.stderr | 60 +++++++++- zerocopy-derive/tests/ui-msrv/union.stderr | 15 ++- .../union_into_bytes_cfg.stderr | 2 +- 81 files changed, 1266 insertions(+), 839 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6101661938..6fb9264c21 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,10 +52,6 @@ jobs: # which a particular feature is supported. "zerocopy-core-error", "zerocopy-diagnostic-on-unimplemented", - "zerocopy-generic-bounds-in-const-fn", - "zerocopy-target-has-atomics", - "zerocopy-aarch64-simd", - "zerocopy-panic-in-const-and-vec-try-reserve" ] target: [ "i686-unknown-linux-gnu", @@ -89,14 +85,6 @@ jobs: features: "--all-features" - toolchain: "zerocopy-diagnostic-on-unimplemented" features: "--all-features" - - toolchain: "zerocopy-generic-bounds-in-const-fn" - features: "--all-features" - - toolchain: "zerocopy-target-has-atomics" - features: "--all-features" - - toolchain: "zerocopy-aarch64-simd" - features: "--all-features" - - toolchain: "zerocopy-panic-in-const-and-vec-try-reserve" - features: "--all-features" # Exclude any combination for the zerocopy-derive crate which # uses zerocopy features. - crate: "zerocopy-derive" @@ -113,36 +101,6 @@ jobs: toolchain: "zerocopy-core-error" - crate: "zerocopy-derive" toolchain: "zerocopy-diagnostic-on-unimplemented" - - crate: "zerocopy-derive" - toolchain: "zerocopy-generic-bounds-in-const-fn" - - crate: "zerocopy-derive" - toolchain: "zerocopy-target-has-atomics" - - crate: "zerocopy-derive" - toolchain: "zerocopy-aarch64-simd" - - crate: "zerocopy-derive" - toolchain: "zerocopy-panic-in-const-and-vec-try-reserve" - # Exclude non-aarch64 targets from the `zerocopy-aarch64-simd` - # toolchain. - - toolchain: "zerocopy-aarch64-simd" - target: "i686-unknown-linux-gnu" - - toolchain: "zerocopy-aarch64-simd" - target: "x86_64-unknown-linux-gnu" - - toolchain: "zerocopy-aarch64-simd" - target: "arm-unknown-linux-gnueabi" - - toolchain: "zerocopy-aarch64-simd" - target: "powerpc-unknown-linux-gnu" - - toolchain: "zerocopy-aarch64-simd" - target: "powerpc64-unknown-linux-gnu" - - toolchain: "zerocopy-aarch64-simd" - target: "riscv64gc-unknown-linux-gnu" - - toolchain: "zerocopy-aarch64-simd" - target: "s390x-unknown-linux-gnu" - - toolchain: "zerocopy-aarch64-simd" - target: "x86_64-pc-windows-msvc" - - toolchain: "zerocopy-aarch64-simd" - target: "thumbv6m-none-eabi" - - toolchain: "zerocopy-aarch64-simd" - target: "wasm32-wasi" # Exclude most targets targets from the `zerocopy-core-error` # toolchain since the `zerocopy-core-error` feature is unrelated to # compilation target. This only leaves i686 and x86_64 targets. @@ -186,28 +144,6 @@ jobs: target: "thumbv6m-none-eabi" - toolchain: "zerocopy-diagnostic-on-unimplemented" target: "wasm32-wasi" - # Exclude most targets targets from the - # `zerocopy-generic-bounds-in-const-fn` toolchain since the - # `zerocopy-generic-bounds-in-const-fn` feature is unrelated to - # compilation target. This only leaves i686 and x86_64 targets. - - toolchain: "zerocopy-generic-bounds-in-const-fn" - target: "arm-unknown-linux-gnueabi" - - toolchain: "zerocopy-generic-bounds-in-const-fn" - target: "aarch64-unknown-linux-gnu" - - toolchain: "zerocopy-generic-bounds-in-const-fn" - target: "powerpc-unknown-linux-gnu" - - toolchain: "zerocopy-generic-bounds-in-const-fn" - target: "powerpc64-unknown-linux-gnu" - - toolchain: "zerocopy-generic-bounds-in-const-fn" - target: "riscv64gc-unknown-linux-gnu" - - toolchain: "zerocopy-generic-bounds-in-const-fn" - target: "s390x-unknown-linux-gnu" - - toolchain: "zerocopy-generic-bounds-in-const-fn" - target: "x86_64-pc-windows-msvc" - - toolchain: "zerocopy-generic-bounds-in-const-fn" - target: "thumbv6m-none-eabi" - - toolchain: "zerocopy-generic-bounds-in-const-fn" - target: "wasm32-wasi" # Exclude `thumbv6m-none-eabi` combined with any feature that implies # the `std` feature since `thumbv6m-none-eabi` does not include a # pre-compiled std. diff --git a/Cargo.toml b/Cargo.toml index efc21f3e69..aa0ca6aa77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,14 +15,14 @@ [package] edition = "2021" name = "zerocopy" -version = "0.8.5" +version = "0.9.0-alpha.0" authors = ["Joshua Liebow-Feeser "] description = "Zerocopy makes zero-cost memory manipulation effortless. We write \"unsafe\" so you don't have to." categories = ["embedded", "encoding", "no-std::no-alloc", "parsing", "rust-patterns"] keywords = ["cast", "convert", "transmute", "transmutation", "type-punning"] license = "BSD-2-Clause OR Apache-2.0 OR MIT" repository = "https://github.com/google/zerocopy" -rust-version = "1.56.0" +rust-version = "1.65.0" exclude = [".*"] @@ -38,21 +38,6 @@ zerocopy-core-error = "1.81.0" # From 1.78.0, Rust supports the `#[diagnostic::on_unimplemented]` attribute. zerocopy-diagnostic-on-unimplemented = "1.78.0" -# From 1.61.0, Rust supports generic types with trait bounds in `const fn`. -zerocopy-generic-bounds-in-const-fn = "1.61.0" - -# From 1.60.0, Rust supports `cfg(target_has_atomics)`, which allows us to -# detect whether a target supports particular sets of atomics. -zerocopy-target-has-atomics = "1.60.0" - -# When the "simd" feature is enabled, include SIMD types from the -# `core::arch::aarch64` module, which was stabilized in 1.59.0. On earlier Rust -# versions, these types require the "simd-nightly" feature. -zerocopy-aarch64-simd = "1.59.0" - -# Permit panicking in `const fn`s and calling `Vec::try_reserve`. -zerocopy-panic-in-const-and-vec-try-reserve = "1.57.0" - [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.81.0" @@ -77,13 +62,13 @@ std = ["alloc"] __internal_use_only_features_that_work_on_stable = ["alloc", "derive", "simd", "std"] [dependencies] -zerocopy-derive = { version = "=0.8.5", path = "zerocopy-derive", optional = true } +zerocopy-derive = { version = "=0.9.0-alpha.0", path = "zerocopy-derive", optional = true } # The "associated proc macro pattern" ensures that the versions of zerocopy and # zerocopy-derive remain equal, even if the 'derive' feature isn't used. # See: https://github.com/matklad/macro-dep-test [target.'cfg(any())'.dependencies] -zerocopy-derive = { version = "=0.8.5", path = "zerocopy-derive" } +zerocopy-derive = { version = "=0.9.0-alpha.0", path = "zerocopy-derive" } [dev-dependencies] itertools = "0.11" @@ -97,6 +82,6 @@ testutil = { path = "testutil" } # CI test failures. trybuild = { version = "=1.0.89", features = ["diff"] } # In tests, unlike in production, zerocopy-derive is not optional -zerocopy-derive = { version = "=0.8.5", path = "zerocopy-derive" } +zerocopy-derive = { version = "=0.9.0-alpha.0", path = "zerocopy-derive" } # TODO(#381) Remove this dependency once we have our own layout gadgets. elain = "0.3.0" diff --git a/src/byteorder.rs b/src/byteorder.rs index b6b4687c0f..836790f9e5 100644 --- a/src/byteorder.rs +++ b/src/byteorder.rs @@ -539,33 +539,29 @@ example of how it can be used for parsing UDP packets. } impl $name { - maybe_const_trait_bounded_fn! { - /// Constructs a new value, possibly performing an endianness - /// swap to guarantee that the returned value has endianness - /// `O`. - #[must_use = "has no side effects"] - #[inline(always)] - pub const fn new(n: $native) -> $name { - let bytes = match O::ORDER { - Order::BigEndian => $to_be_fn(n), - Order::LittleEndian => $to_le_fn(n), - }; + /// Constructs a new value, possibly performing an endianness + /// swap to guarantee that the returned value has endianness + /// `O`. + #[must_use = "has no side effects"] + #[inline(always)] + pub const fn new(n: $native) -> $name { + let bytes = match O::ORDER { + Order::BigEndian => $to_be_fn(n), + Order::LittleEndian => $to_le_fn(n), + }; - $name(bytes, PhantomData) - } + $name(bytes, PhantomData) } - maybe_const_trait_bounded_fn! { - /// Returns the value as a primitive type, possibly performing - /// an endianness swap to guarantee that the return value has - /// the endianness of the native platform. - #[must_use = "has no side effects"] - #[inline(always)] - pub const fn get(self) -> $native { - match O::ORDER { - Order::BigEndian => $from_be_fn(self.0), - Order::LittleEndian => $from_le_fn(self.0), - } + /// Returns the value as a primitive type, possibly performing + /// an endianness swap to guarantee that the return value has + /// the endianness of the native platform. + #[must_use = "has no side effects"] + #[inline(always)] + pub const fn get(self) -> $native { + match O::ORDER { + Order::BigEndian => $from_be_fn(self.0), + Order::LittleEndian => $from_le_fn(self.0), } } @@ -1057,8 +1053,8 @@ mod tests { /// themselves. This method is like `assert_eq!`, but it treats NaN /// values as equal. fn assert_eq_or_nan(self, other: Self) { - let slf = (!self.is_nan()).then(|| self); - let other = (!other.is_nan()).then(|| other); + let slf = (!self.is_nan()).then_some(self); + let other = (!other.is_nan()).then_some(other); assert_eq!(slf, other); } } @@ -1088,8 +1084,8 @@ mod tests { /// themselves. This method is like `assert_eq!`, but it treats NaN /// values as equal. fn assert_eq_or_nan(self, other: Self) { - let slf = (!self.get().is_nan()).then(|| self); - let other = (!other.get().is_nan()).then(|| other); + let slf = (!self.get().is_nan()).then_some(self); + let other = (!other.get().is_nan()).then_some(other); assert_eq!(slf, other); } } @@ -1396,11 +1392,11 @@ mod tests { // For `f32` and `f64`, NaN values are not considered equal to // themselves. We store `Option`/`Option` and store // NaN as `None` so they can still be compared. - let val_or_none = |t: T| (!T::Native::is_nan(t.get())).then(|| t.get()); + let val_or_none = |t: T| (!T::Native::is_nan(t.get())).then_some(t.get()); let t_t_res = val_or_none(t_t_res); let t_n_res = val_or_none(t_n_res); let n_t_res = val_or_none(n_t_res); - let n_n_res = (!T::Native::is_nan(n_n_res)).then(|| n_n_res); + let n_n_res = (!T::Native::is_nan(n_n_res)).then_some(n_n_res); assert_eq!(t_t_res, n_n_res); assert_eq!(t_n_res, n_n_res); assert_eq!(n_t_res, n_n_res); @@ -1418,7 +1414,7 @@ mod tests { // NaN as `None` so they can still be compared. let t_t_res = val_or_none(t_t_res); let t_n_res = val_or_none(t_n_res); - let n_t_res = (!T::Native::is_nan(n_t_res)).then(|| n_t_res); + let n_t_res = (!T::Native::is_nan(n_t_res)).then_some(n_t_res); assert_eq!(t_t_res, n_n_res); assert_eq!(t_n_res, n_n_res); assert_eq!(n_t_res, n_n_res); diff --git a/src/impls.rs b/src/impls.rs index 678f8fb2e6..b4712d8932 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -441,15 +441,12 @@ safety_comment! { unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_extern_c_fn!(...)); } -#[cfg(all( - zerocopy_target_has_atomics, - any( - target_has_atomic = "8", - target_has_atomic = "16", - target_has_atomic = "32", - target_has_atomic = "64", - target_has_atomic = "ptr" - ) +#[cfg(any( + target_has_atomic = "8", + target_has_atomic = "16", + target_has_atomic = "32", + target_has_atomic = "64", + target_has_atomic = "ptr" ))] mod atomics { use super::*; @@ -933,7 +930,6 @@ mod simd { #[cfg(all(feature = "simd-nightly", target_arch = "powerpc64"))] powerpc64, powerpc64, vector_bool_long, vector_double, vector_signed_long, vector_unsigned_long ); - #[cfg(zerocopy_aarch64_simd)] simd_arch_mod!( // NOTE(https://github.com/rust-lang/stdarch/issues/1484): NEON intrinsics are currently // broken on big-endian platforms. @@ -1882,7 +1878,7 @@ mod tests { vector_signed_long, vector_unsigned_long ); - #[cfg(all(target_arch = "aarch64", zerocopy_aarch64_simd))] + #[cfg(target_arch = "aarch64")] #[rustfmt::skip] test_simd_arch_mod!( aarch64, float32x2_t, float32x4_t, float64x1_t, float64x2_t, int8x8_t, int8x8x2_t, diff --git a/src/layout.rs b/src/layout.rs index 24d8fb6ef3..d2f4cd2900 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -96,7 +96,7 @@ impl DstLayout { /// The minimum possible alignment of a type. const MIN_ALIGN: NonZeroUsize = match NonZeroUsize::new(1) { Some(min_align) => min_align, - None => const_unreachable!(), + None => unreachable!(), }; /// The maximum theoretic possible alignment of a type. @@ -107,7 +107,7 @@ impl DstLayout { pub(crate) const THEORETICAL_MAX_ALIGN: NonZeroUsize = match NonZeroUsize::new(1 << (POINTER_WIDTH_BITS - 1)) { Some(max_align) => max_align, - None => const_unreachable!(), + None => unreachable!(), }; /// The current, documented max alignment of a type \[1\]. @@ -119,7 +119,7 @@ impl DstLayout { #[cfg(not(kani))] pub(crate) const CURRENT_MAX_ALIGN: NonZeroUsize = match NonZeroUsize::new(1 << 28) { Some(max_align) => max_align, - None => const_unreachable!(), + None => unreachable!(), }; /// Constructs a `DstLayout` for a zero-sized type with `repr_align` @@ -142,7 +142,7 @@ impl DstLayout { None => Self::MIN_ALIGN, }; - const_assert!(align.get().is_power_of_two()); + assert!(align.get().is_power_of_two()); DstLayout { align, size_info: SizeInfo::Sized { size: 0 } } } @@ -162,7 +162,7 @@ impl DstLayout { DstLayout { align: match NonZeroUsize::new(mem::align_of::()) { Some(align) => align, - None => const_unreachable!(), + None => unreachable!(), }, size_info: SizeInfo::Sized { size: mem::size_of::() }, } @@ -185,7 +185,7 @@ impl DstLayout { DstLayout { align: match NonZeroUsize::new(mem::align_of::()) { Some(align) => align, - None => const_unreachable!(), + None => unreachable!(), }, size_info: SizeInfo::SliceDst(TrailingSliceLayout { offset: 0, @@ -232,17 +232,17 @@ impl DstLayout { None => Self::THEORETICAL_MAX_ALIGN, }; - const_assert!(max_align.get().is_power_of_two()); + assert!(max_align.get().is_power_of_two()); // We use Kani to prove that this method is robust to future increases // in Rust's maximum allowed alignment. However, if such a change ever // actually occurs, we'd like to be notified via assertion failures. #[cfg(not(kani))] { - const_debug_assert!(self.align.get() <= DstLayout::CURRENT_MAX_ALIGN.get()); - const_debug_assert!(field.align.get() <= DstLayout::CURRENT_MAX_ALIGN.get()); + debug_assert!(self.align.get() <= DstLayout::CURRENT_MAX_ALIGN.get()); + debug_assert!(field.align.get() <= DstLayout::CURRENT_MAX_ALIGN.get()); if let Some(repr_packed) = repr_packed { - const_debug_assert!(repr_packed.get() <= DstLayout::CURRENT_MAX_ALIGN.get()); + debug_assert!(repr_packed.get() <= DstLayout::CURRENT_MAX_ALIGN.get()); } } @@ -263,7 +263,7 @@ impl DstLayout { let size_info = match self.size_info { // If the layout is already a DST, we panic; DSTs cannot be extended // with additional fields. - SizeInfo::SliceDst(..) => const_panic!("Cannot extend a DST with additional fields."), + SizeInfo::SliceDst(..) => panic!("Cannot extend a DST with additional fields."), SizeInfo::Sized { size: preceding_size } => { // Compute the minimum amount of inter-field padding needed to @@ -284,7 +284,7 @@ impl DstLayout { // exceeding `isize::MAX`). let offset = match preceding_size.checked_add(padding) { Some(offset) => offset, - None => const_panic!("Adding padding to `self`'s size overflows `usize`."), + None => panic!("Adding padding to `self`'s size overflows `usize`."), }; match field.size_info { @@ -302,7 +302,7 @@ impl DstLayout { // `usize::MAX`). let size = match offset.checked_add(field_size) { Some(size) => size, - None => const_panic!("`field` cannot be appended without the total size overflowing `usize`"), + None => panic!("`field` cannot be appended without the total size overflowing `usize`"), }; SizeInfo::Sized { size } } @@ -324,7 +324,7 @@ impl DstLayout { // `usize::MAX`). let offset = match offset.checked_add(trailing_offset) { Some(offset) => offset, - None => const_panic!("`field` cannot be appended without the total size overflowing `usize`"), + None => panic!("`field` cannot be appended without the total size overflowing `usize`"), }; SizeInfo::SliceDst(TrailingSliceLayout { offset, elem_size }) } @@ -372,7 +372,7 @@ impl DstLayout { let padding = padding_needed_for(unpadded_size, self.align); let size = match unpadded_size.checked_add(padding) { Some(size) => size, - None => const_panic!("Adding padding caused size to overflow `usize`."), + None => panic!("Adding padding caused size to overflow `usize`."), }; SizeInfo::Sized { size } } @@ -458,9 +458,9 @@ impl DstLayout { cast_type: CastType, ) -> Result<(usize, usize), MetadataCastError> { // `debug_assert!`, but with `#[allow(clippy::arithmetic_side_effects)]`. - macro_rules! __const_debug_assert { + macro_rules! __debug_assert { ($e:expr $(, $msg:expr)?) => { - const_debug_assert!({ + debug_assert!({ #[allow(clippy::arithmetic_side_effects)] let e = $e; e @@ -479,14 +479,11 @@ impl DstLayout { // https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#let-else-statements let size_info = match self.size_info.try_to_nonzero_elem_size() { Some(size_info) => size_info, - None => const_panic!("attempted to cast to slice type with zero-sized element"), + None => panic!("attempted to cast to slice type with zero-sized element"), }; // Precondition - __const_debug_assert!( - addr.checked_add(bytes_len).is_some(), - "`addr` + `bytes_len` > usize::MAX" - ); + __debug_assert!(addr.checked_add(bytes_len).is_some(), "`addr` + `bytes_len` > usize::MAX"); // Alignment checks go in their own block to avoid introducing variables // into the top-level scope. @@ -582,7 +579,7 @@ impl DstLayout { } }; - __const_debug_assert!(self_bytes <= bytes_len); + __debug_assert!(self_bytes <= bytes_len); let split_at = match cast_type { CastType::Prefix => self_bytes, @@ -842,7 +839,7 @@ mod tests { /// call to `validate_cast_and_convert_metadata` panics with the given /// panic message or, if the current Rust toolchain version is too /// early to support panicking in `const fn`s, panics with *some* - /// message. In the latter case, the `const_panic!` macro is used, + /// message. In the latter case, the `panic!` macro is used, /// which emits code which causes a non-panicking error at const eval /// time, but which does panic when invoked at runtime. Thus, it is /// merely difficult to predict the *value* of this panic. We deem @@ -880,7 +877,7 @@ mod tests { layout(size_info, align).validate_cast_and_convert_metadata(addr, bytes_len, cast_type) }).map_err(|d| { let msg = d.downcast::<&'static str>().ok().map(|s| *s.as_ref()); - assert!(msg.is_some() || cfg!(not(zerocopy_panic_in_const_and_vec_try_reserve)), "non-string panic messages are not permitted when `--cfg zerocopy_panic_in_const_and_vec_try_reserve` is set"); + assert!(msg.is_some(), "non-string panic messages are not permitted"); msg }); std::panic::set_hook(previous_hook); diff --git a/src/lib.rs b/src/lib.rs index 296836425a..cbd8c4f4e2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3141,7 +3141,6 @@ pub unsafe trait FromZeros: TryFromBytes { /// Extends a `Vec` by pushing `additional` new items onto the end of /// the vector. The new items are initialized with zeros. - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] #[cfg(feature = "alloc")] #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] #[inline(always)] @@ -3160,7 +3159,6 @@ pub unsafe trait FromZeros: TryFromBytes { /// # Panics /// /// Panics if `position > v.len()`. - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] #[cfg(feature = "alloc")] #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] #[inline] @@ -5362,13 +5360,11 @@ pub unsafe trait Unaligned { #[cfg(feature = "alloc")] #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] -#[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] mod alloc_support { use super::*; /// Extends a `Vec` by pushing `additional` new items onto the end of the /// vector. The new items are initialized with zeros. - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] #[doc(hidden)] #[deprecated(since = "0.8.0", note = "moved to `FromZeros`")] #[inline(always)] @@ -5385,7 +5381,6 @@ mod alloc_support { /// # Panics /// /// Panics if `position > v.len()`. - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] #[doc(hidden)] #[deprecated(since = "0.8.0", note = "moved to `FromZeros`")] #[inline(always)] @@ -5399,7 +5394,6 @@ mod alloc_support { } #[cfg(feature = "alloc")] -#[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] #[doc(hidden)] pub use alloc_support::*; @@ -6262,7 +6256,6 @@ mod tests { mod alloc { use super::*; - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] #[test] fn test_extend_vec_zeroed() { // Test extending when there is an existing allocation. @@ -6280,7 +6273,6 @@ mod tests { drop(v); } - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] #[test] fn test_extend_vec_zeroed_zst() { // Test extending when there is an existing (fake) allocation. @@ -6297,7 +6289,6 @@ mod tests { drop(v); } - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] #[test] fn test_insert_vec_zeroed() { // Insert at start (no existing allocation). @@ -6329,7 +6320,6 @@ mod tests { drop(v); } - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] #[test] fn test_insert_vec_zeroed_zst() { // Insert at start (no existing fake allocation). diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index affdd921f9..100b0ded12 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -675,7 +675,7 @@ mod _transitions { const IS_EXCLUSIVE: bool = { let is_exclusive = strs_are_equal(::NAME, ::NAME); - const_assert!(is_exclusive); + assert!(is_exclusive); true }; } diff --git a/src/util/macros.rs b/src/util/macros.rs index af751e7523..cbeffdaee2 100644 --- a/src/util/macros.rs +++ b/src/util/macros.rs @@ -615,109 +615,9 @@ macro_rules! assert_unaligned { }; } -/// Emits a function definition as either `const fn` or `fn` depending on -/// whether the current toolchain version supports `const fn` with generic trait -/// bounds. -macro_rules! maybe_const_trait_bounded_fn { - // This case handles both `self` methods (where `self` is by value) and - // non-method functions. Each `$args` may optionally be followed by `: - // $arg_tys:ty`, which can be omitted for `self`. - ($(#[$attr:meta])* $vis:vis const fn $name:ident($($args:ident $(: $arg_tys:ty)?),* $(,)?) $(-> $ret_ty:ty)? $body:block) => { - #[cfg(zerocopy_generic_bounds_in_const_fn)] - $(#[$attr])* $vis const fn $name($($args $(: $arg_tys)?),*) $(-> $ret_ty)? $body - - #[cfg(not(zerocopy_generic_bounds_in_const_fn))] - $(#[$attr])* $vis fn $name($($args $(: $arg_tys)?),*) $(-> $ret_ty)? $body - }; -} - -/// Either panic (if the current Rust toolchain supports panicking in `const -/// fn`) or evaluate a constant that will cause an array indexing error whose -/// error message will include the format string. -/// -/// The type that this expression evaluates to must be `Copy`, or else the -/// non-panicking desugaring will fail to compile. -macro_rules! const_panic { - (@non_panic $($_arg:tt)+) => {{ - // This will type check to whatever type is expected based on the call - // site. - let panic: [_; 0] = []; - // This will always fail (since we're indexing into an array of size 0. - #[allow(unconditional_panic)] - panic[0] - }}; - ($($arg:tt)+) => {{ - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] - panic!($($arg)+); - #[cfg(not(zerocopy_panic_in_const_and_vec_try_reserve))] - const_panic!(@non_panic $($arg)+) - }}; -} - -/// Either assert (if the current Rust toolchain supports panicking in `const -/// fn`) or evaluate the expression and, if it evaluates to `false`, call -/// `const_panic!`. This is used in place of `assert!` in const contexts to -/// accommodate old toolchains. -macro_rules! const_assert { - ($e:expr) => {{ - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] - assert!($e); - #[cfg(not(zerocopy_panic_in_const_and_vec_try_reserve))] - { - let e = $e; - if !e { - let _: () = const_panic!(@non_panic concat!("assertion failed: ", stringify!($e))); - } - } - }}; - ($e:expr, $($args:tt)+) => {{ - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] - assert!($e, $($args)+); - #[cfg(not(zerocopy_panic_in_const_and_vec_try_reserve))] - { - let e = $e; - if !e { - let _: () = const_panic!(@non_panic concat!("assertion failed: ", stringify!($e), ": ", stringify!($arg)), $($args)*); - } - } - }}; -} - -/// Like `const_assert!`, but relative to `debug_assert!`. -macro_rules! const_debug_assert { - ($e:expr $(, $msg:expr)?) => {{ - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] - debug_assert!($e $(, $msg)?); - #[cfg(not(zerocopy_panic_in_const_and_vec_try_reserve))] - { - // Use this (rather than `#[cfg(debug_assertions)]`) to ensure that - // `$e` is always compiled even if it will never be evaluated at - // runtime. - if cfg!(debug_assertions) { - let e = $e; - if !e { - let _: () = const_panic!(@non_panic concat!("assertion failed: ", stringify!($e) $(, ": ", $msg)?)); - } - } - } - }} -} - -/// Either invoke `unreachable!()` or `loop {}` depending on whether the Rust -/// toolchain supports panicking in `const fn`. -macro_rules! const_unreachable { - () => {{ - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] - unreachable!(); - - #[cfg(not(zerocopy_panic_in_const_and_vec_try_reserve))] - loop {} - }}; -} - /// Asserts at compile time that `$condition` is true for `Self` or the given -/// `$tyvar`s. Unlike `const_assert`, this is *strictly* a compile-time check; -/// it cannot be evaluated in a runtime context. The condition is checked after +/// `$tyvar`s. Unlike `assert!`, this is *strictly* a compile-time check; it +/// cannot be evaluated in a runtime context. The condition is checked after /// monomorphization and, upon failure, emits a compile error. macro_rules! static_assert { (Self $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )? => $condition:expr $(, $args:tt)*) => {{ @@ -727,12 +627,12 @@ macro_rules! static_assert { impl StaticAssert for T { const ASSERT: bool = { - const_assert!($condition $(, $args)*); + assert!($condition $(, $args)*); $condition }; } - const_assert!(::ASSERT); + assert!(::ASSERT); }}; ($($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),* => $condition:expr $(, $args:tt)*) => {{ trait StaticAssert { @@ -741,12 +641,12 @@ macro_rules! static_assert { impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?,)*> StaticAssert for ($($tyvar,)*) { const ASSERT: bool = { - const_assert!($condition $(, $args)*); + assert!($condition $(, $args)*); $condition }; } - const_assert!(<($($tyvar,)*) as StaticAssert>::ASSERT); + assert!(<($($tyvar,)*) as StaticAssert>::ASSERT); }}; } diff --git a/src/util/mod.rs b/src/util/mod.rs index a05700cf02..04d8b8f546 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -373,15 +373,12 @@ unsafe impl TransparentWrapper for Unalign { /// /// The caller promises that `$atomic` is an atomic type whose natie equivalent /// is `$native`. -#[cfg(all( - zerocopy_target_has_atomics, - any( - target_has_atomic = "8", - target_has_atomic = "16", - target_has_atomic = "32", - target_has_atomic = "64", - target_has_atomic = "ptr" - ) +#[cfg(any( + target_has_atomic = "8", + target_has_atomic = "16", + target_has_atomic = "32", + target_has_atomic = "64", + target_has_atomic = "ptr" ))] macro_rules! unsafe_impl_transparent_wrapper_for_atomic { ($(#[$attr:meta])* $(,)?) => {}; @@ -635,7 +632,6 @@ pub(crate) const fn round_down_to_next_multiple_of_alignment( align: NonZeroUsize, ) -> usize { let align = align.get(); - #[cfg(zerocopy_panic_in_const_and_vec_try_reserve)] debug_assert!(align.is_power_of_two()); // Subtraction can't underflow because `align.get() >= 1`. @@ -869,10 +865,9 @@ mod tests { } } - #[rustversion::since(1.57.0)] #[test] #[should_panic] - fn test_round_down_to_next_multiple_of_alignment_zerocopy_panic_in_const_and_vec_try_reserve() { + fn test_round_down_to_next_multiple_of_alignment_panics() { round_down_to_next_multiple_of_alignment(0, NonZeroUsize::new(3).unwrap()); } } diff --git a/src/wrappers.rs b/src/wrappers.rs index 0637d76025..4b52622573 100644 --- a/src/wrappers.rs +++ b/src/wrappers.rs @@ -525,7 +525,7 @@ mod tests { let au64 = unsafe { x.t.deref_unchecked() }; match au64 { AU64(123) => {} - _ => const_unreachable!(), + _ => unreachable!(), } }; } diff --git a/tests/ui-msrv/diagnostic-not-implemented-from-bytes.stderr b/tests/ui-msrv/diagnostic-not-implemented-from-bytes.stderr index 8c7294f7fd..239c69f696 100644 --- a/tests/ui-msrv/diagnostic-not-implemented-from-bytes.stderr +++ b/tests/ui-msrv/diagnostic-not-implemented-from-bytes.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfie 18 | takes_from_bytes::(); | ^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::FromBytes`: + () + AU16 + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others note: required by a bound in `takes_from_bytes` --> tests/ui-msrv/diagnostic-not-implemented-from-bytes.rs:21:24 | diff --git a/tests/ui-msrv/diagnostic-not-implemented-from-zeros.stderr b/tests/ui-msrv/diagnostic-not-implemented-from-zeros.stderr index 894701e17e..03afed0604 100644 --- a/tests/ui-msrv/diagnostic-not-implemented-from-zeros.stderr +++ b/tests/ui-msrv/diagnostic-not-implemented-from-zeros.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `NotZerocopy: FromZeros` is not satisfied 18 | takes_from_zeros::(); | ^^^^^^^^^^^ the trait `FromZeros` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `FromZeros`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `takes_from_zeros` --> tests/ui-msrv/diagnostic-not-implemented-from-zeros.rs:21:24 | diff --git a/tests/ui-msrv/diagnostic-not-implemented-immutable.stderr b/tests/ui-msrv/diagnostic-not-implemented-immutable.stderr index d0093ad8a1..4b64f94ffb 100644 --- a/tests/ui-msrv/diagnostic-not-implemented-immutable.stderr +++ b/tests/ui-msrv/diagnostic-not-implemented-immutable.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::Immutable` is not satisfie 18 | takes_immutable::(); | ^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::Immutable`: + &T + &mut T + () + *const T + *mut T + AU16 + Box + F32 + and $N others note: required by a bound in `takes_immutable` --> tests/ui-msrv/diagnostic-not-implemented-immutable.rs:21:23 | diff --git a/tests/ui-msrv/diagnostic-not-implemented-into-bytes.stderr b/tests/ui-msrv/diagnostic-not-implemented-into-bytes.stderr index c2959ef8b8..961d77fbad 100644 --- a/tests/ui-msrv/diagnostic-not-implemented-into-bytes.stderr +++ b/tests/ui-msrv/diagnostic-not-implemented-into-bytes.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfie 18 | takes_into_bytes::(); | ^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others note: required by a bound in `takes_into_bytes` --> tests/ui-msrv/diagnostic-not-implemented-into-bytes.rs:21:24 | diff --git a/tests/ui-msrv/diagnostic-not-implemented-issue-1296.stderr b/tests/ui-msrv/diagnostic-not-implemented-issue-1296.stderr index 0475a6499e..966dc9fe85 100644 --- a/tests/ui-msrv/diagnostic-not-implemented-issue-1296.stderr +++ b/tests/ui-msrv/diagnostic-not-implemented-issue-1296.stderr @@ -2,10 +2,42 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::Immutable` is not satisfie --> tests/ui-msrv/diagnostic-not-implemented-issue-1296.rs:52:19 | 52 | Foo.write_obj(NotZerocopy(())); - | ^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `NotZerocopy` + | --------- ^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `NotZerocopy` + | | + | required by a bound introduced by this call + | +note: required by a bound in `Foo::write_obj` + --> tests/ui-msrv/diagnostic-not-implemented-issue-1296.rs:58:21 + | +58 | fn write_obj(&mut self, _val: T) {} + | ^^^^^^^^^ required by this bound in `Foo::write_obj` +help: consider borrowing here + | +52 | Foo.write_obj(&NotZerocopy(())); + | + +52 | Foo.write_obj(&mut NotZerocopy(())); + | ++++ error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied --> tests/ui-msrv/diagnostic-not-implemented-issue-1296.rs:52:19 | 52 | Foo.write_obj(NotZerocopy(())); - | ^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | --------- ^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | | + | required by a bound introduced by this call + | + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others +note: required by a bound in `Foo::write_obj` + --> tests/ui-msrv/diagnostic-not-implemented-issue-1296.rs:58:33 + | +58 | fn write_obj(&mut self, _val: T) {} + | ^^^^^^^^^ required by this bound in `Foo::write_obj` diff --git a/tests/ui-msrv/diagnostic-not-implemented-known-layout.stderr b/tests/ui-msrv/diagnostic-not-implemented-known-layout.stderr index d3cfd29c6c..4fc50b9f2e 100644 --- a/tests/ui-msrv/diagnostic-not-implemented-known-layout.stderr +++ b/tests/ui-msrv/diagnostic-not-implemented-known-layout.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::KnownLayout` is not satisf 18 | takes_known_layout::(); | ^^^^^^^^^^^ the trait `zerocopy::KnownLayout` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::KnownLayout`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `takes_known_layout` --> tests/ui-msrv/diagnostic-not-implemented-known-layout.rs:21:26 | diff --git a/tests/ui-msrv/diagnostic-not-implemented-try-from-bytes.stderr b/tests/ui-msrv/diagnostic-not-implemented-try-from-bytes.stderr index 8e27c9c8cb..09bb2f7399 100644 --- a/tests/ui-msrv/diagnostic-not-implemented-try-from-bytes.stderr +++ b/tests/ui-msrv/diagnostic-not-implemented-try-from-bytes.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 18 | takes_try_from_bytes::(); | ^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `takes_try_from_bytes` --> tests/ui-msrv/diagnostic-not-implemented-try-from-bytes.rs:21:28 | diff --git a/tests/ui-msrv/diagnostic-not-implemented-unaligned.stderr b/tests/ui-msrv/diagnostic-not-implemented-unaligned.stderr index bde813f691..a7607ce872 100644 --- a/tests/ui-msrv/diagnostic-not-implemented-unaligned.stderr +++ b/tests/ui-msrv/diagnostic-not-implemented-unaligned.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `NotZerocopy: Unaligned` is not satisfied 18 | takes_unaligned::(); | ^^^^^^^^^^^ the trait `Unaligned` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `Unaligned`: + () + AtomicBool + AtomicI8 + AtomicU8 + F32 + F64 + I128 + I16 + and $N others note: required by a bound in `takes_unaligned` --> tests/ui-msrv/diagnostic-not-implemented-unaligned.rs:21:23 | diff --git a/tests/ui-msrv/include_value_not_from_bytes.stderr b/tests/ui-msrv/include_value_not_from_bytes.stderr index 14dd22a71a..9e42493e43 100644 --- a/tests/ui-msrv/include_value_not_from_bytes.stderr +++ b/tests/ui-msrv/include_value_not_from_bytes.stderr @@ -2,11 +2,24 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not sat --> tests/ui-msrv/include_value_not_from_bytes.rs:19:42 | 19 | const NOT_FROM_BYTES: NotZerocopy = include_value!("../../testdata/include_value/data"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` + | required by a bound introduced by this call | -note: required by `AssertIsFromBytes` + = help: the following other types implement trait `zerocopy::FromBytes`: + () + AU16 + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others +note: required by a bound in `AssertIsFromBytes` --> tests/ui-msrv/include_value_not_from_bytes.rs:19:42 | 19 | const NOT_FROM_BYTES: NotZerocopy = include_value!("../../testdata/include_value/data"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::transmute` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes` + = note: this error originates in the macro `$crate::transmute` which comes from the expansion of the macro `include_value` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/include_value_wrong_size.stderr b/tests/ui-msrv/include_value_wrong_size.stderr index b4531c7fa5..d564e20f91 100644 --- a/tests/ui-msrv/include_value_wrong_size.stderr +++ b/tests/ui-msrv/include_value_wrong_size.stderr @@ -6,4 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `[u8; 4]` (32 bits) = note: target type: `u64` (64 bits) - = note: this error originates in the macro `$crate::transmute` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::transmute` which comes from the expansion of the macro `include_value` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/invalid-impls/invalid-impls.stderr b/tests/ui-msrv/invalid-impls/invalid-impls.stderr index 7e9765e6be..29e98d64ce 100644 --- a/tests/ui-msrv/invalid-impls/invalid-impls.stderr +++ b/tests/ui-msrv/invalid-impls/invalid-impls.stderr @@ -7,9 +7,9 @@ error[E0277]: the trait bound `T: zerocopy::TryFromBytes` is not satisfied ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:26:1 | 26 | impl_or_verify!(T => TryFromBytes for Foo); - | ---------------------------------------------- in this macro invocation + | --------------------------------------------- in this macro invocation | -note: required because of the requirements on the impl of `zerocopy::TryFromBytes` for `Foo` +note: required for `Foo` to implement `zerocopy::TryFromBytes` --> tests/ui-msrv/invalid-impls/invalid-impls.rs:22:10 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] @@ -23,11 +23,12 @@ note: required by a bound in `_::Subtrait` ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:26:1 | 26 | impl_or_verify!(T => TryFromBytes for Foo); - | ---------------------------------------------- in this macro invocation + | --------------------------------------------- in this macro invocation = note: this error originates in the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` + --> |$DIR/tests/ui-msrv/invalid-impls/invalid-impls.rs | -26 | impl_or_verify!(T: zerocopy::TryFromBytes => TryFromBytes for Foo); + | impl_or_verify!(T: zerocopy::TryFromBytes => TryFromBytes for Foo); | ++++++++++++++++++++++++ error[E0277]: the trait bound `T: zerocopy::FromZeros` is not satisfied @@ -39,9 +40,9 @@ error[E0277]: the trait bound `T: zerocopy::FromZeros` is not satisfied ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:27:1 | 27 | impl_or_verify!(T => FromZeros for Foo); - | ------------------------------------------- in this macro invocation + | ------------------------------------------ in this macro invocation | -note: required because of the requirements on the impl of `zerocopy::FromZeros` for `Foo` +note: required for `Foo` to implement `zerocopy::FromZeros` --> tests/ui-msrv/invalid-impls/invalid-impls.rs:22:10 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] @@ -55,11 +56,12 @@ note: required by a bound in `_::Subtrait` ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:27:1 | 27 | impl_or_verify!(T => FromZeros for Foo); - | ------------------------------------------- in this macro invocation + | ------------------------------------------ in this macro invocation = note: this error originates in the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` + --> |$DIR/tests/ui-msrv/invalid-impls/invalid-impls.rs | -27 | impl_or_verify!(T: zerocopy::FromZeros => FromZeros for Foo); + | impl_or_verify!(T: zerocopy::FromZeros => FromZeros for Foo); | +++++++++++++++++++++ error[E0277]: the trait bound `T: zerocopy::FromBytes` is not satisfied @@ -71,9 +73,9 @@ error[E0277]: the trait bound `T: zerocopy::FromBytes` is not satisfied ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:28:1 | 28 | impl_or_verify!(T => FromBytes for Foo); - | ------------------------------------------- in this macro invocation + | ------------------------------------------ in this macro invocation | -note: required because of the requirements on the impl of `zerocopy::FromBytes` for `Foo` +note: required for `Foo` to implement `zerocopy::FromBytes` --> tests/ui-msrv/invalid-impls/invalid-impls.rs:22:10 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] @@ -87,11 +89,12 @@ note: required by a bound in `_::Subtrait` ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:28:1 | 28 | impl_or_verify!(T => FromBytes for Foo); - | ------------------------------------------- in this macro invocation + | ------------------------------------------ in this macro invocation = note: this error originates in the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` + --> |$DIR/tests/ui-msrv/invalid-impls/invalid-impls.rs | -28 | impl_or_verify!(T: zerocopy::FromBytes => FromBytes for Foo); + | impl_or_verify!(T: zerocopy::FromBytes => FromBytes for Foo); | +++++++++++++++++++++ error[E0277]: the trait bound `T: zerocopy::IntoBytes` is not satisfied @@ -103,9 +106,9 @@ error[E0277]: the trait bound `T: zerocopy::IntoBytes` is not satisfied ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:29:1 | 29 | impl_or_verify!(T => IntoBytes for Foo); - | ------------------------------------------- in this macro invocation + | ------------------------------------------ in this macro invocation | -note: required because of the requirements on the impl of `zerocopy::IntoBytes` for `Foo` +note: required for `Foo` to implement `zerocopy::IntoBytes` --> tests/ui-msrv/invalid-impls/invalid-impls.rs:22:21 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] @@ -119,11 +122,12 @@ note: required by a bound in `_::Subtrait` ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:29:1 | 29 | impl_or_verify!(T => IntoBytes for Foo); - | ------------------------------------------- in this macro invocation + | ------------------------------------------ in this macro invocation = note: this error originates in the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` + --> |$DIR/tests/ui-msrv/invalid-impls/invalid-impls.rs | -29 | impl_or_verify!(T: zerocopy::IntoBytes => IntoBytes for Foo); + | impl_or_verify!(T: zerocopy::IntoBytes => IntoBytes for Foo); | +++++++++++++++++++++ error[E0277]: the trait bound `T: zerocopy::Unaligned` is not satisfied @@ -135,9 +139,9 @@ error[E0277]: the trait bound `T: zerocopy::Unaligned` is not satisfied ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:30:1 | 30 | impl_or_verify!(T => Unaligned for Foo); - | ------------------------------------------- in this macro invocation + | ------------------------------------------ in this macro invocation | -note: required because of the requirements on the impl of `zerocopy::Unaligned` for `Foo` +note: required for `Foo` to implement `zerocopy::Unaligned` --> tests/ui-msrv/invalid-impls/invalid-impls.rs:22:32 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] @@ -151,9 +155,10 @@ note: required by a bound in `_::Subtrait` ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:30:1 | 30 | impl_or_verify!(T => Unaligned for Foo); - | ------------------------------------------- in this macro invocation + | ------------------------------------------ in this macro invocation = note: this error originates in the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` + --> |$DIR/tests/ui-msrv/invalid-impls/invalid-impls.rs | -30 | impl_or_verify!(T: zerocopy::Unaligned => Unaligned for Foo); + | impl_or_verify!(T: zerocopy::Unaligned => Unaligned for Foo); | +++++++++++++++++++++ diff --git a/tests/ui-msrv/transmute-dst-not-frombytes.stderr b/tests/ui-msrv/transmute-dst-not-frombytes.stderr index 744cb48da0..bc351bf725 100644 --- a/tests/ui-msrv/transmute-dst-not-frombytes.stderr +++ b/tests/ui-msrv/transmute-dst-not-frombytes.stderr @@ -2,11 +2,24 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfie --> tests/ui-msrv/transmute-dst-not-frombytes.rs:19:41 | 19 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0)); - | ^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` + | ^^^^^^^^^^^^^^^^^^^ + | | + | the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` + | required by a bound introduced by this call | -note: required by `AssertIsFromBytes` + = help: the following other types implement trait `zerocopy::FromBytes`: + () + AU16 + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others +note: required by a bound in `AssertIsFromBytes` --> tests/ui-msrv/transmute-dst-not-frombytes.rs:19:41 | 19 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0)); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes` = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-mut-alignment-increase.stderr b/tests/ui-msrv/transmute-mut-alignment-increase.stderr index 7b771b8521..15561e68b2 100644 --- a/tests/ui-msrv/transmute-mut-alignment-increase.stderr +++ b/tests/ui-msrv/transmute-mut-alignment-increase.stderr @@ -6,30 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AlignOf<[u8; 2]>` (8 bits) = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0658]: mutable references are not allowed in constants - --> tests/ui-msrv/transmute-mut-alignment-increase.rs:20:54 - | -20 | const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]); - | ^^^^^^^^^^^^^ - | - = note: see issue #57349 for more information - -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants - --> tests/ui-msrv/transmute-mut-alignment-increase.rs:20:39 - | -20 | const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0716]: temporary value dropped while borrowed - --> tests/ui-msrv/transmute-mut-alignment-increase.rs:20:59 - | -20 | const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]); - | --------------------^^^^^^^^- - | | | - | | creates a temporary which is freed while still in use - | temporary value is freed at the end of this statement - | using this value as a constant requires that borrow lasts for `'static` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-mut-const.stderr b/tests/ui-msrv/transmute-mut-const.stderr index 8578fa1932..91c88fb337 100644 --- a/tests/ui-msrv/transmute-mut-const.stderr +++ b/tests/ui-msrv/transmute-mut-const.stderr @@ -11,7 +11,7 @@ note: `const` item defined here --> tests/ui-msrv/transmute-mut-const.rs:17:1 | 17 | const ARRAY_OF_U8S: [u8; 2] = [0u8; 2]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0658]: mutable references are not allowed in constants --> tests/ui-msrv/transmute-mut-const.rs:20:52 @@ -21,12 +21,13 @@ error[E0658]: mutable references are not allowed in constants | = note: see issue #57349 for more information -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `transmute_mut::<[u8; 2], [u8; 2]>` in constants --> tests/ui-msrv/transmute-mut-const.rs:20:37 | 20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0716]: temporary value dropped while borrowed diff --git a/tests/ui-msrv/transmute-mut-dst-generic.stderr b/tests/ui-msrv/transmute-mut-dst-generic.stderr index f6b54ce1c2..28edcf15eb 100644 --- a/tests/ui-msrv/transmute-mut-dst-generic.stderr +++ b/tests/ui-msrv/transmute-mut-dst-generic.stderr @@ -6,7 +6,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `u8` (8 bits) = note: target type: `T` (this type does not have a fixed size) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/transmute-mut-dst-generic.rs:17:5 @@ -16,4 +16,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AlignOf` (8 bits) = note: target type: `MaxAlignsOf` (size can vary because of T) - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-mut-dst-not-a-reference.stderr b/tests/ui-msrv/transmute-mut-dst-not-a-reference.stderr index eaff00fd27..97a3f4a8d7 100644 --- a/tests/ui-msrv/transmute-mut-dst-not-a-reference.stderr +++ b/tests/ui-msrv/transmute-mut-dst-not-a-reference.stderr @@ -42,8 +42,16 @@ error[E0308]: mismatched types --> tests/ui-msrv/transmute-mut-dst-not-a-reference.rs:17:36 | 17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8); - | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected `usize`, found `&mut _` + | arguments to this function are incorrect | = note: expected type `usize` found mutable reference `&mut _` +note: function defined here + --> src/util/macro_util.rs + | + | pub const fn must_use(t: T) -> T { + | ^^^^^^^^ = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-mut-dst-not-frombytes.stderr b/tests/ui-msrv/transmute-mut-dst-not-frombytes.stderr index 3f92e0d4e4..7d6b7a086e 100644 --- a/tests/ui-msrv/transmute-mut-dst-not-frombytes.stderr +++ b/tests/ui-msrv/transmute-mut-dst-not-frombytes.stderr @@ -2,11 +2,24 @@ error[E0277]: the trait bound `Dst: FromBytes` is not satisfied --> tests/ui-msrv/transmute-mut-dst-not-frombytes.rs:24:38 | 24 | const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Dst` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Dst` + | required by a bound introduced by this call | -note: required by `AssertDstIsFromBytes` + = help: the following other types implement trait `FromBytes`: + () + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + AtomicU32 + and $N others +note: required by a bound in `AssertDstIsFromBytes` --> tests/ui-msrv/transmute-mut-dst-not-frombytes.rs:24:38 | 24 | const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-mut-dst-not-intobytes.stderr b/tests/ui-msrv/transmute-mut-dst-not-intobytes.stderr index 4ceffcd010..a4d1cf86f9 100644 --- a/tests/ui-msrv/transmute-mut-dst-not-intobytes.stderr +++ b/tests/ui-msrv/transmute-mut-dst-not-intobytes.stderr @@ -2,11 +2,24 @@ error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied --> tests/ui-msrv/transmute-mut-dst-not-intobytes.rs:24:36 | 24 | const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Dst` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `Dst` + | required by a bound introduced by this call | -note: required by `AssertDstIsIntoBytes` + = help: the following other types implement trait `IntoBytes`: + () + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others +note: required by a bound in `AssertDstIsIntoBytes` --> tests/ui-msrv/transmute-mut-dst-not-intobytes.rs:24:36 | 24 | const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsIntoBytes` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-mut-dst-unsized.stderr b/tests/ui-msrv/transmute-mut-dst-unsized.stderr index e54fac982c..de5a4f2363 100644 --- a/tests/ui-msrv/transmute-mut-dst-unsized.stderr +++ b/tests/ui-msrv/transmute-mut-dst-unsized.stderr @@ -2,14 +2,17 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32 | 17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by `AssertDstIsSized` +note: required by a bound in `AssertDstIsSized` --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32 | 17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsSized` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -35,7 +38,7 @@ note: required by a bound in `MaxAlignsOf` | | pub union MaxAlignsOf { | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32 @@ -49,35 +52,24 @@ note: required by a bound in `transmute` | | pub fn transmute(e: T) -> U; | ^ required by this bound in `transmute` - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32 - | -17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` -note: required by `MaxAlignsOf::::new` - --> src/util/macro_util.rs - | - | pub fn new(_t: T, _u: U) -> MaxAlignsOf { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32 | 17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `MaxAlignsOf` +note: required by a bound in `MaxAlignsOf::::new` --> src/util/macro_util.rs | - | pub union MaxAlignsOf { - | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32 diff --git a/tests/ui-msrv/transmute-mut-size-decrease.stderr b/tests/ui-msrv/transmute-mut-size-decrease.stderr index ee3261ed28..6a2dbdab53 100644 --- a/tests/ui-msrv/transmute-mut-size-decrease.stderr +++ b/tests/ui-msrv/transmute-mut-size-decrease.stderr @@ -6,30 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `[u8; 2]` (16 bits) = note: target type: `u8` (8 bits) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0658]: mutable references are not allowed in constants - --> tests/ui-msrv/transmute-mut-size-decrease.rs:17:47 - | -17 | const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]); - | ^^^^^^^^^^^^^ - | - = note: see issue #57349 for more information - -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants - --> tests/ui-msrv/transmute-mut-size-decrease.rs:17:32 - | -17 | const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0716]: temporary value dropped while borrowed - --> tests/ui-msrv/transmute-mut-size-decrease.rs:17:52 - | -17 | const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]); - | --------------------^^^^^^^^- - | | | - | | creates a temporary which is freed while still in use - | temporary value is freed at the end of this statement - | using this value as a constant requires that borrow lasts for `'static` + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-mut-size-increase.stderr b/tests/ui-msrv/transmute-mut-size-increase.stderr index 242493ff0a..06ec48d72a 100644 --- a/tests/ui-msrv/transmute-mut-size-increase.stderr +++ b/tests/ui-msrv/transmute-mut-size-increase.stderr @@ -6,30 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `u8` (8 bits) = note: target type: `[u8; 2]` (16 bits) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0658]: mutable references are not allowed in constants - --> tests/ui-msrv/transmute-mut-size-increase.rs:17:52 - | -17 | const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8); - | ^^^^^^^^ - | - = note: see issue #57349 for more information - -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants - --> tests/ui-msrv/transmute-mut-size-increase.rs:17:37 - | -17 | const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0716]: temporary value dropped while borrowed - --> tests/ui-msrv/transmute-mut-size-increase.rs:17:57 - | -17 | const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8); - | --------------------^^^- - | | | - | | creates a temporary which is freed while still in use - | temporary value is freed at the end of this statement - | using this value as a constant requires that borrow lasts for `'static` + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-mut-src-dst-generic.stderr b/tests/ui-msrv/transmute-mut-src-dst-generic.stderr index f41be15ad3..f96b268786 100644 --- a/tests/ui-msrv/transmute-mut-src-dst-generic.stderr +++ b/tests/ui-msrv/transmute-mut-src-dst-generic.stderr @@ -6,7 +6,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `T` (this type does not have a fixed size) = note: target type: `U` (this type does not have a fixed size) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/transmute-mut-src-dst-generic.rs:20:5 @@ -16,4 +16,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AlignOf` (size can vary because of T) = note: target type: `MaxAlignsOf` (size can vary because of T) - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-mut-src-dst-unsized.stderr b/tests/ui-msrv/transmute-mut-src-dst-unsized.stderr index ff2d7d198d..c1ca231f44 100644 --- a/tests/ui-msrv/transmute-mut-src-dst-unsized.stderr +++ b/tests/ui-msrv/transmute-mut-src-dst-unsized.stderr @@ -2,14 +2,17 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by `AssertSrcIsSized` +note: required by a bound in `AssertSrcIsSized` --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsSized` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -30,14 +33,17 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by `AssertDstIsSized` +note: required by a bound in `AssertDstIsSized` --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsSized` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -55,7 +61,10 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `transmute` @@ -63,16 +72,24 @@ note: required by a bound in `transmute` | | pub fn transmute(e: T) -> U; | ^ required by this bound in `transmute` - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) +note: required by a bound in `AlignOf::::into_t` + --> src/util/macro_util.rs + | + | impl AlignOf { + | ^ required by this bound in `AlignOf::::into_t` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 @@ -82,7 +99,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation | = help: the trait `Sized` is not implemented for `[u8]` = note: the left-hand-side of an assignment must have a statically known size - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 @@ -96,35 +113,24 @@ note: required by a bound in `AlignOf` | | pub struct AlignOf { | ^ required by this bound in `AlignOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` -note: required by `MaxAlignsOf::::new` - --> src/util/macro_util.rs - | - | pub fn new(_t: T, _u: U) -> MaxAlignsOf { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 - | -17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `MaxAlignsOf` +note: required by a bound in `MaxAlignsOf::::new` --> src/util/macro_util.rs | - | pub union MaxAlignsOf { - | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 @@ -138,7 +144,7 @@ note: required by a bound in `MaxAlignsOf` | | pub union MaxAlignsOf { | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 @@ -152,21 +158,7 @@ note: required by a bound in `AlignOf` | | pub struct AlignOf { | ^ required by this bound in `AlignOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 - | -17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `MaxAlignsOf` - --> src/util/macro_util.rs - | - | pub union MaxAlignsOf { - | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 @@ -191,13 +183,33 @@ note: required by a bound in `transmute` | | pub fn transmute(e: T) -> U; | ^ required by this bound in `transmute` - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf::::new` + --> src/util/macro_util.rs + | + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36 + | +17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `transmute_mut` diff --git a/tests/ui-msrv/transmute-mut-src-generic.stderr b/tests/ui-msrv/transmute-mut-src-generic.stderr index 319fc27a8b..b230f68eaa 100644 --- a/tests/ui-msrv/transmute-mut-src-generic.stderr +++ b/tests/ui-msrv/transmute-mut-src-generic.stderr @@ -6,7 +6,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `T` (this type does not have a fixed size) = note: target type: `u8` (8 bits) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/transmute-mut-src-generic.rs:17:5 @@ -16,4 +16,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AlignOf` (size can vary because of T) = note: target type: `MaxAlignsOf` (size can vary because of T) - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-mut-src-not-frombytes.stderr b/tests/ui-msrv/transmute-mut-src-not-frombytes.stderr index ebb8e0bafe..19fd0ce496 100644 --- a/tests/ui-msrv/transmute-mut-src-not-frombytes.stderr +++ b/tests/ui-msrv/transmute-mut-src-not-frombytes.stderr @@ -2,13 +2,26 @@ error[E0277]: the trait bound `Src: FromBytes` is not satisfied --> tests/ui-msrv/transmute-mut-src-not-frombytes.rs:24:38 | 24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Src` + | required by a bound introduced by this call | -note: required by `AssertSrcIsFromBytes` + = help: the following other types implement trait `FromBytes`: + () + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + AtomicU32 + and $N others +note: required by a bound in `AssertSrcIsFromBytes` --> tests/ui-msrv/transmute-mut-src-not-frombytes.rs:24:38 | 24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Src: FromBytes` is not satisfied @@ -17,6 +30,16 @@ error[E0277]: the trait bound `Src: FromBytes` is not satisfied 24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src` | + = help: the following other types implement trait `FromBytes`: + () + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + AtomicU32 + and $N others note: required by a bound in `AssertSrcIsFromBytes` --> tests/ui-msrv/transmute-mut-src-not-frombytes.rs:24:38 | diff --git a/tests/ui-msrv/transmute-mut-src-not-intobytes.stderr b/tests/ui-msrv/transmute-mut-src-not-intobytes.stderr index 7522b32a69..0691557aa1 100644 --- a/tests/ui-msrv/transmute-mut-src-not-intobytes.stderr +++ b/tests/ui-msrv/transmute-mut-src-not-intobytes.stderr @@ -2,13 +2,26 @@ error[E0277]: the trait bound `Src: IntoBytes` is not satisfied --> tests/ui-msrv/transmute-mut-src-not-intobytes.rs:24:36 | 24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Src` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `Src` + | required by a bound introduced by this call | -note: required by `AssertSrcIsIntoBytes` + = help: the following other types implement trait `IntoBytes`: + () + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others +note: required by a bound in `AssertSrcIsIntoBytes` --> tests/ui-msrv/transmute-mut-src-not-intobytes.rs:24:36 | 24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsIntoBytes` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Src: IntoBytes` is not satisfied @@ -17,6 +30,16 @@ error[E0277]: the trait bound `Src: IntoBytes` is not satisfied 24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Src` | + = help: the following other types implement trait `IntoBytes`: + () + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others note: required by a bound in `AssertSrcIsIntoBytes` --> tests/ui-msrv/transmute-mut-src-not-intobytes.rs:24:36 | diff --git a/tests/ui-msrv/transmute-mut-src-unsized.stderr b/tests/ui-msrv/transmute-mut-src-unsized.stderr index df471dc458..e71157fe11 100644 --- a/tests/ui-msrv/transmute-mut-src-unsized.stderr +++ b/tests/ui-msrv/transmute-mut-src-unsized.stderr @@ -2,14 +2,17 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 | 16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by `AssertSrcIsSized` +note: required by a bound in `AssertSrcIsSized` --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 | 16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsSized` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -41,7 +44,10 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 | 16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `transmute` @@ -49,16 +55,24 @@ note: required by a bound in `transmute` | | pub fn transmute(e: T) -> U; | ^ required by this bound in `transmute` - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 | 16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) +note: required by a bound in `AlignOf::::into_t` + --> src/util/macro_util.rs + | + | impl AlignOf { + | ^ required by this bound in `AlignOf::::into_t` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 @@ -68,7 +82,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation | = help: the trait `Sized` is not implemented for `[u8]` = note: the left-hand-side of an assignment must have a statically known size - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 @@ -82,21 +96,24 @@ note: required by a bound in `AlignOf` | | pub struct AlignOf { | ^ required by this bound in `AlignOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 | 16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by `MaxAlignsOf::::new` +note: required by a bound in `MaxAlignsOf::::new` --> src/util/macro_util.rs | - | pub fn new(_t: T, _u: U) -> MaxAlignsOf { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 @@ -110,21 +127,7 @@ note: required by a bound in `MaxAlignsOf` | | pub union MaxAlignsOf { | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 - | -16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `MaxAlignsOf` - --> src/util/macro_util.rs - | - | pub union MaxAlignsOf { - | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 @@ -138,27 +141,16 @@ note: required by a bound in `AlignOf` | | pub struct AlignOf { | ^ required by this bound in `AlignOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 - | -16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `MaxAlignsOf` - --> src/util/macro_util.rs - | - | pub union MaxAlignsOf { - | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 | 16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `transmute_mut` @@ -167,13 +159,3 @@ note: required by a bound in `transmute_mut` | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( | ^^^ required by this bound in `transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35 - | -16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` - = note: all function arguments must have a statically known size - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ptr-to-usize.stderr b/tests/ui-msrv/transmute-ptr-to-usize.stderr index 81d60c71a1..603e06914e 100644 --- a/tests/ui-msrv/transmute-ptr-to-usize.stderr +++ b/tests/ui-msrv/transmute-ptr-to-usize.stderr @@ -2,13 +2,26 @@ error[E0277]: the trait bound `*const usize: IntoBytes` is not satisfied --> tests/ui-msrv/transmute-ptr-to-usize.rs:20:30 | 20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `*const usize` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `*const usize` + | required by a bound introduced by this call | -note: required by `AssertIsIntoBytes` + = help: the following other types implement trait `IntoBytes`: + f32 + f64 + i128 + i16 + i32 + i64 + i8 + isize + and $N others +note: required by a bound in `AssertIsIntoBytes` --> tests/ui-msrv/transmute-ptr-to-usize.rs:20:30 | 20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsIntoBytes` = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `*const usize: IntoBytes` is not satisfied @@ -17,6 +30,16 @@ error[E0277]: the trait bound `*const usize: IntoBytes` is not satisfied 20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `*const usize` | + = help: the following other types implement trait `IntoBytes`: + f32 + f64 + i128 + i16 + i32 + i64 + i8 + isize + and $N others note: required by a bound in `AssertIsIntoBytes` --> tests/ui-msrv/transmute-ptr-to-usize.rs:20:30 | diff --git a/tests/ui-msrv/transmute-ref-alignment-increase.stderr b/tests/ui-msrv/transmute-ref-alignment-increase.stderr index bbf5058287..1db5b9c6e7 100644 --- a/tests/ui-msrv/transmute-ref-alignment-increase.stderr +++ b/tests/ui-msrv/transmute-ref-alignment-increase.stderr @@ -6,4 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AlignOf<[u8; 2]>` (8 bits) = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ref-dst-generic.stderr b/tests/ui-msrv/transmute-ref-dst-generic.stderr index ec7ec74894..efaf33de60 100644 --- a/tests/ui-msrv/transmute-ref-dst-generic.stderr +++ b/tests/ui-msrv/transmute-ref-dst-generic.stderr @@ -6,7 +6,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `u8` (8 bits) = note: target type: `T` (this type does not have a fixed size) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/transmute-ref-dst-generic.rs:17:5 @@ -16,4 +16,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AlignOf` (8 bits) = note: target type: `MaxAlignsOf` (size can vary because of T) - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ref-dst-mutable.stderr b/tests/ui-msrv/transmute-ref-dst-mutable.stderr index 3189cd0d4b..ef50d79678 100644 --- a/tests/ui-msrv/transmute-ref-dst-mutable.stderr +++ b/tests/ui-msrv/transmute-ref-dst-mutable.stderr @@ -42,8 +42,16 @@ error[E0308]: mismatched types --> tests/ui-msrv/transmute-ref-dst-mutable.rs:18:22 | 18 | let _: &mut u8 = transmute_ref!(&0u8); - | ^^^^^^^^^^^^^^^^^^^^ types differ in mutability + | ^^^^^^^^^^^^^^^^^^^^ + | | + | types differ in mutability + | arguments to this function are incorrect | = note: expected mutable reference `&mut u8` found reference `&_` +note: function defined here + --> src/util/macro_util.rs + | + | pub const fn must_use(t: T) -> T { + | ^^^^^^^^ = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ref-dst-not-a-reference.stderr b/tests/ui-msrv/transmute-ref-dst-not-a-reference.stderr index 60a79caeba..614c30600c 100644 --- a/tests/ui-msrv/transmute-ref-dst-not-a-reference.stderr +++ b/tests/ui-msrv/transmute-ref-dst-not-a-reference.stderr @@ -42,8 +42,16 @@ error[E0308]: mismatched types --> tests/ui-msrv/transmute-ref-dst-not-a-reference.rs:17:36 | 17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); - | ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference + | ^^^^^^^^^^^^^^^^^^^^ + | | + | expected `usize`, found reference + | arguments to this function are incorrect | = note: expected type `usize` found reference `&_` +note: function defined here + --> src/util/macro_util.rs + | + | pub const fn must_use(t: T) -> T { + | ^^^^^^^^ = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ref-dst-not-frombytes.stderr b/tests/ui-msrv/transmute-ref-dst-not-frombytes.stderr index 9cdc03ef84..8a2239af9a 100644 --- a/tests/ui-msrv/transmute-ref-dst-not-frombytes.stderr +++ b/tests/ui-msrv/transmute-ref-dst-not-frombytes.stderr @@ -2,11 +2,24 @@ error[E0277]: the trait bound `Dst: zerocopy::FromBytes` is not satisfied --> tests/ui-msrv/transmute-ref-dst-not-frombytes.rs:23:34 | 23 | const DST_NOT_FROM_BYTES: &Dst = transmute_ref!(&AU16(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `Dst` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `zerocopy::FromBytes` is not implemented for `Dst` + | required by a bound introduced by this call | -note: required by `AssertDstIsFromBytes` + = help: the following other types implement trait `zerocopy::FromBytes`: + () + AU16 + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others +note: required by a bound in `AssertDstIsFromBytes` --> tests/ui-msrv/transmute-ref-dst-not-frombytes.rs:23:34 | 23 | const DST_NOT_FROM_BYTES: &Dst = transmute_ref!(&AU16(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ref-dst-not-nocell.stderr b/tests/ui-msrv/transmute-ref-dst-not-nocell.stderr index 899805b05c..d9df2fbb00 100644 --- a/tests/ui-msrv/transmute-ref-dst-not-nocell.stderr +++ b/tests/ui-msrv/transmute-ref-dst-not-nocell.stderr @@ -2,11 +2,24 @@ error[E0277]: the trait bound `Dst: zerocopy::Immutable` is not satisfied --> tests/ui-msrv/transmute-ref-dst-not-nocell.rs:23:33 | 23 | const DST_NOT_IMMUTABLE: &Dst = transmute_ref!(&AU16(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `Dst` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `zerocopy::Immutable` is not implemented for `Dst` + | required by a bound introduced by this call | -note: required by `AssertDstIsImmutable` + = help: the following other types implement trait `zerocopy::Immutable`: + &T + &mut T + () + *const T + *mut T + AU16 + Box + F32 + and $N others +note: required by a bound in `AssertDstIsImmutable` --> tests/ui-msrv/transmute-ref-dst-not-nocell.rs:23:33 | 23 | const DST_NOT_IMMUTABLE: &Dst = transmute_ref!(&AU16(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsImmutable` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ref-dst-unsized.stderr b/tests/ui-msrv/transmute-ref-dst-unsized.stderr index 5967222fb0..19f18bbcd7 100644 --- a/tests/ui-msrv/transmute-ref-dst-unsized.stderr +++ b/tests/ui-msrv/transmute-ref-dst-unsized.stderr @@ -2,14 +2,17 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28 | 17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by `AssertDstIsSized` +note: required by a bound in `AssertDstIsSized` --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28 | 17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsSized` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -35,7 +38,7 @@ note: required by a bound in `MaxAlignsOf` | | pub union MaxAlignsOf { | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28 @@ -49,35 +52,24 @@ note: required by a bound in `transmute` | | pub fn transmute(e: T) -> U; | ^ required by this bound in `transmute` - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28 - | -17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` -note: required by `MaxAlignsOf::::new` - --> src/util/macro_util.rs - | - | pub fn new(_t: T, _u: U) -> MaxAlignsOf { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28 | 17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `MaxAlignsOf` +note: required by a bound in `MaxAlignsOf::::new` --> src/util/macro_util.rs | - | pub union MaxAlignsOf { - | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28 diff --git a/tests/ui-msrv/transmute-ref-size-decrease.stderr b/tests/ui-msrv/transmute-ref-size-decrease.stderr index 95669f9063..d85a005c0a 100644 --- a/tests/ui-msrv/transmute-ref-size-decrease.stderr +++ b/tests/ui-msrv/transmute-ref-size-decrease.stderr @@ -6,4 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `[u8; 2]` (16 bits) = note: target type: `u8` (8 bits) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ref-size-increase.stderr b/tests/ui-msrv/transmute-ref-size-increase.stderr index 10f0e1038c..07d0188e44 100644 --- a/tests/ui-msrv/transmute-ref-size-increase.stderr +++ b/tests/ui-msrv/transmute-ref-size-increase.stderr @@ -6,4 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `u8` (8 bits) = note: target type: `[u8; 2]` (16 bits) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ref-src-dst-generic.stderr b/tests/ui-msrv/transmute-ref-src-dst-generic.stderr index eb3268fa8f..272d11f416 100644 --- a/tests/ui-msrv/transmute-ref-src-dst-generic.stderr +++ b/tests/ui-msrv/transmute-ref-src-dst-generic.stderr @@ -6,7 +6,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `T` (this type does not have a fixed size) = note: target type: `U` (this type does not have a fixed size) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/transmute-ref-src-dst-generic.rs:18:5 @@ -16,4 +16,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AlignOf` (size can vary because of T) = note: target type: `MaxAlignsOf` (size can vary because of T) - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ref-src-dst-not-references.stderr b/tests/ui-msrv/transmute-ref-src-dst-not-references.stderr index 1826e28a52..eeef5ff67c 100644 --- a/tests/ui-msrv/transmute-ref-src-dst-not-references.stderr +++ b/tests/ui-msrv/transmute-ref-src-dst-not-references.stderr @@ -55,8 +55,16 @@ error[E0308]: mismatched types --> tests/ui-msrv/transmute-ref-src-dst-not-references.rs:17:39 | 17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); - | ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference + | ^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected `usize`, found reference + | arguments to this function are incorrect | = note: expected type `usize` found reference `&_` +note: function defined here + --> src/util/macro_util.rs + | + | pub const fn must_use(t: T) -> T { + | ^^^^^^^^ = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ref-src-dst-unsized.stderr b/tests/ui-msrv/transmute-ref-src-dst-unsized.stderr index af59584992..9054ad74de 100644 --- a/tests/ui-msrv/transmute-ref-src-dst-unsized.stderr +++ b/tests/ui-msrv/transmute-ref-src-dst-unsized.stderr @@ -2,14 +2,17 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by `AssertSrcIsSized` +note: required by a bound in `AssertSrcIsSized` --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsSized` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -30,14 +33,17 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by `AssertDstIsSized` +note: required by a bound in `AssertDstIsSized` --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsSized` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -55,7 +61,10 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `transmute` @@ -63,16 +72,24 @@ note: required by a bound in `transmute` | | pub fn transmute(e: T) -> U; | ^ required by this bound in `transmute` - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) +note: required by a bound in `AlignOf::::into_t` + --> src/util/macro_util.rs + | + | impl AlignOf { + | ^ required by this bound in `AlignOf::::into_t` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 @@ -82,7 +99,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation | = help: the trait `Sized` is not implemented for `[u8]` = note: the left-hand-side of an assignment must have a statically known size - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 @@ -96,35 +113,24 @@ note: required by a bound in `AlignOf` | | pub struct AlignOf { | ^ required by this bound in `AlignOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` -note: required by `MaxAlignsOf::::new` - --> src/util/macro_util.rs - | - | pub fn new(_t: T, _u: U) -> MaxAlignsOf { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 - | -17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `MaxAlignsOf` +note: required by a bound in `MaxAlignsOf::::new` --> src/util/macro_util.rs | - | pub union MaxAlignsOf { - | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 @@ -138,7 +144,7 @@ note: required by a bound in `MaxAlignsOf` | | pub union MaxAlignsOf { | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 @@ -152,21 +158,7 @@ note: required by a bound in `AlignOf` | | pub struct AlignOf { | ^ required by this bound in `AlignOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 - | -17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `MaxAlignsOf` - --> src/util/macro_util.rs - | - | pub union MaxAlignsOf { - | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 @@ -191,13 +183,33 @@ note: required by a bound in `transmute` | | pub fn transmute(e: T) -> U; | ^ required by this bound in `transmute` - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `MaxAlignsOf::::new` + --> src/util/macro_util.rs + | + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32 + | +17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `transmute_ref` diff --git a/tests/ui-msrv/transmute-ref-src-generic.stderr b/tests/ui-msrv/transmute-ref-src-generic.stderr index 4cb3e51bc7..dd9df98eb9 100644 --- a/tests/ui-msrv/transmute-ref-src-generic.stderr +++ b/tests/ui-msrv/transmute-ref-src-generic.stderr @@ -6,7 +6,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `T` (this type does not have a fixed size) = note: target type: `u8` (8 bits) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/transmute-ref-src-generic.rs:17:5 @@ -16,4 +16,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AlignOf` (size can vary because of T) = note: target type: `MaxAlignsOf` (size can vary because of T) - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-ref-src-not-intobytes.stderr b/tests/ui-msrv/transmute-ref-src-not-intobytes.stderr index 84036b70ba..a4317d985b 100644 --- a/tests/ui-msrv/transmute-ref-src-not-intobytes.stderr +++ b/tests/ui-msrv/transmute-ref-src-not-intobytes.stderr @@ -2,13 +2,26 @@ error[E0277]: the trait bound `Src: zerocopy::IntoBytes` is not satisfied --> tests/ui-msrv/transmute-ref-src-not-intobytes.rs:23:33 | 23 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&Src(AU16(0))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `Src` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `zerocopy::IntoBytes` is not implemented for `Src` + | required by a bound introduced by this call | -note: required by `AssertSrcIsIntoBytes` + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others +note: required by a bound in `AssertSrcIsIntoBytes` --> tests/ui-msrv/transmute-ref-src-not-intobytes.rs:23:33 | 23 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&Src(AU16(0))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsIntoBytes` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Src: zerocopy::IntoBytes` is not satisfied @@ -17,6 +30,16 @@ error[E0277]: the trait bound `Src: zerocopy::IntoBytes` is not satisfied 23 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `Src` | + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others note: required by a bound in `AssertSrcIsIntoBytes` --> tests/ui-msrv/transmute-ref-src-not-intobytes.rs:23:33 | diff --git a/tests/ui-msrv/transmute-ref-src-not-nocell.stderr b/tests/ui-msrv/transmute-ref-src-not-nocell.stderr index 2e94e8064a..e1d50b0f07 100644 --- a/tests/ui-msrv/transmute-ref-src-not-nocell.stderr +++ b/tests/ui-msrv/transmute-ref-src-not-nocell.stderr @@ -2,13 +2,26 @@ error[E0277]: the trait bound `Src: zerocopy::Immutable` is not satisfied --> tests/ui-msrv/transmute-ref-src-not-nocell.rs:23:34 | 23 | const SRC_NOT_IMMUTABLE: &AU16 = transmute_ref!(&Src(AU16(0))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `zerocopy::Immutable` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `zerocopy::Immutable` is not implemented for `Src` + | required by a bound introduced by this call | -note: required by `AssertSrcIsImmutable` + = help: the following other types implement trait `zerocopy::Immutable`: + &T + &mut T + () + *const T + *mut T + AU16 + Box + F32 + and $N others +note: required by a bound in `AssertSrcIsImmutable` --> tests/ui-msrv/transmute-ref-src-not-nocell.rs:23:34 | 23 | const SRC_NOT_IMMUTABLE: &AU16 = transmute_ref!(&Src(AU16(0))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsImmutable` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Src: zerocopy::Immutable` is not satisfied @@ -17,6 +30,16 @@ error[E0277]: the trait bound `Src: zerocopy::Immutable` is not satisfied 23 | const SRC_NOT_IMMUTABLE: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `Src` | + = help: the following other types implement trait `zerocopy::Immutable`: + &T + &mut T + () + *const T + *mut T + AU16 + Box + F32 + and $N others note: required by a bound in `AssertSrcIsImmutable` --> tests/ui-msrv/transmute-ref-src-not-nocell.rs:23:34 | diff --git a/tests/ui-msrv/transmute-ref-src-unsized.stderr b/tests/ui-msrv/transmute-ref-src-unsized.stderr index b3705bca36..81b3e3870f 100644 --- a/tests/ui-msrv/transmute-ref-src-unsized.stderr +++ b/tests/ui-msrv/transmute-ref-src-unsized.stderr @@ -2,14 +2,17 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 | 16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by `AssertSrcIsSized` +note: required by a bound in `AssertSrcIsSized` --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 | 16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsSized` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -41,7 +44,10 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 | 16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `transmute` @@ -49,16 +55,24 @@ note: required by a bound in `transmute` | | pub fn transmute(e: T) -> U; | ^ required by this bound in `transmute` - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 | 16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) +note: required by a bound in `AlignOf::::into_t` + --> src/util/macro_util.rs + | + | impl AlignOf { + | ^ required by this bound in `AlignOf::::into_t` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 @@ -68,7 +82,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation | = help: the trait `Sized` is not implemented for `[u8]` = note: the left-hand-side of an assignment must have a statically known size - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 @@ -82,21 +96,24 @@ note: required by a bound in `AlignOf` | | pub struct AlignOf { | ^ required by this bound in `AlignOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 | 16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by `MaxAlignsOf::::new` +note: required by a bound in `MaxAlignsOf::::new` --> src/util/macro_util.rs | - | pub fn new(_t: T, _u: U) -> MaxAlignsOf { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + | impl MaxAlignsOf { + | ^ required by this bound in `MaxAlignsOf::::new` + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 @@ -110,21 +127,7 @@ note: required by a bound in `MaxAlignsOf` | | pub union MaxAlignsOf { | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 - | -16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `MaxAlignsOf` - --> src/util/macro_util.rs - | - | pub union MaxAlignsOf { - | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 @@ -138,27 +141,16 @@ note: required by a bound in `AlignOf` | | pub struct AlignOf { | ^ required by this bound in `AlignOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 - | -16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `MaxAlignsOf` - --> src/util/macro_util.rs - | - | pub union MaxAlignsOf { - | ^ required by this bound in `MaxAlignsOf` - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 | 16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `transmute_ref` @@ -167,13 +159,3 @@ note: required by a bound in `transmute_ref` | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( | ^^^ required by this bound in `transmute_ref` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 - | -16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` - = note: all function arguments must have a statically known size - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/transmute-src-not-intobytes.stderr b/tests/ui-msrv/transmute-src-not-intobytes.stderr index 6382be909c..38b76d0067 100644 --- a/tests/ui-msrv/transmute-src-not-intobytes.stderr +++ b/tests/ui-msrv/transmute-src-not-intobytes.stderr @@ -2,13 +2,26 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not sa --> tests/ui-msrv/transmute-src-not-intobytes.rs:19:32 | 19 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | required by a bound introduced by this call | -note: required by `AssertIsIntoBytes` + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others +note: required by a bound in `AssertIsIntoBytes` --> tests/ui-msrv/transmute-src-not-intobytes.rs:19:32 | 19 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsIntoBytes` = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied @@ -17,6 +30,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not sa 19 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others note: required by a bound in `AssertIsIntoBytes` --> tests/ui-msrv/transmute-src-not-intobytes.rs:19:32 | diff --git a/tests/ui-msrv/try_transmute-dst-not-tryfrombytes.stderr b/tests/ui-msrv/try_transmute-dst-not-tryfrombytes.stderr index 5536f61216..fe3ccbde22 100644 --- a/tests/ui-msrv/try_transmute-dst-not-tryfrombytes.stderr +++ b/tests/ui-msrv/try_transmute-dst-not-tryfrombytes.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 17 | let dst_not_try_from_bytes: Result = try_transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `try_transmute` --> src/util/macro_util.rs | @@ -17,6 +27,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 17 | let dst_not_try_from_bytes: Result = try_transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `ValidityError` --> src/error.rs | @@ -29,6 +49,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 17 | let dst_not_try_from_bytes: Result = try_transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `ValidityError` --> src/error.rs | diff --git a/tests/ui-msrv/try_transmute-size-decrease.stderr b/tests/ui-msrv/try_transmute-size-decrease.stderr index 6817bc92cc..f8ee5d663a 100644 --- a/tests/ui-msrv/try_transmute-size-decrease.stderr +++ b/tests/ui-msrv/try_transmute-size-decrease.stderr @@ -1,11 +1,3 @@ -warning: unused variable: `decrease_size` - --> tests/ui-msrv/try_transmute-size-decrease.rs:19:9 - | -19 | let decrease_size: Result = try_transmute!(AU16(0)); - | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_decrease_size` - | - = note: `#[warn(unused_variables)]` on by default - error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute-size-decrease.rs:19:40 | diff --git a/tests/ui-msrv/try_transmute-size-increase.stderr b/tests/ui-msrv/try_transmute-size-increase.stderr index c66289ff9d..e8bd2019b8 100644 --- a/tests/ui-msrv/try_transmute-size-increase.stderr +++ b/tests/ui-msrv/try_transmute-size-increase.stderr @@ -1,11 +1,3 @@ -warning: unused variable: `increase_size` - --> tests/ui-msrv/try_transmute-size-increase.rs:19:9 - | -19 | let increase_size: Result = try_transmute!(0u8); - | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_increase_size` - | - = note: `#[warn(unused_variables)]` on by default - error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute-size-increase.rs:19:42 | diff --git a/tests/ui-msrv/try_transmute-src-not-intobytes.stderr b/tests/ui-msrv/try_transmute-src-not-intobytes.stderr index 589f8931d7..3b79ffbeeb 100644 --- a/tests/ui-msrv/try_transmute-src-not-intobytes.stderr +++ b/tests/ui-msrv/try_transmute-src-not-intobytes.stderr @@ -2,8 +2,21 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not sa --> tests/ui-msrv/try_transmute-src-not-intobytes.rs:18:47 | 18 | let src_not_into_bytes: Result = try_transmute!(NotZerocopy(AU16(0))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | required by a bound introduced by this call | + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others note: required by a bound in `try_transmute` --> src/util/macro_util.rs | diff --git a/tests/ui-msrv/try_transmute_mut-alignment-increase.stderr b/tests/ui-msrv/try_transmute_mut-alignment-increase.stderr index aa67d03d7e..a5b5b224fc 100644 --- a/tests/ui-msrv/try_transmute_mut-alignment-increase.stderr +++ b/tests/ui-msrv/try_transmute_mut-alignment-increase.stderr @@ -1,11 +1,3 @@ -warning: unused variable: `increase_size` - --> tests/ui-msrv/try_transmute_mut-alignment-increase.rs:20:9 - | -20 | let increase_size: Result<&mut AU16, _> = try_transmute_mut!(src); - | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_increase_size` - | - = note: `#[warn(unused_variables)]` on by default - error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute_mut-alignment-increase.rs:20:47 | @@ -14,4 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AlignOf<[u8; 2]>` (8 bits) = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/try_transmute_mut-dst-not-tryfrombytes.stderr b/tests/ui-msrv/try_transmute_mut-dst-not-tryfrombytes.stderr index a722fb99b5..a682314f09 100644 --- a/tests/ui-msrv/try_transmute_mut-dst-not-tryfrombytes.stderr +++ b/tests/ui-msrv/try_transmute_mut-dst-not-tryfrombytes.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `try_transmute_mut` --> src/util/macro_util.rs | @@ -17,6 +27,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `ValidityError` --> src/error.rs | @@ -29,6 +49,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `ValidityError` --> src/error.rs | diff --git a/tests/ui-msrv/try_transmute_mut-size-decrease.stderr b/tests/ui-msrv/try_transmute_mut-size-decrease.stderr index 6a5c78050a..24d3ce4cd8 100644 --- a/tests/ui-msrv/try_transmute_mut-size-decrease.stderr +++ b/tests/ui-msrv/try_transmute_mut-size-decrease.stderr @@ -1,11 +1,3 @@ -warning: unused variable: `decrease_size` - --> tests/ui-msrv/try_transmute_mut-size-decrease.rs:20:9 - | -20 | let decrease_size: Result<&mut u8, _> = try_transmute_mut!(src); - | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_decrease_size` - | - = note: `#[warn(unused_variables)]` on by default - error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute_mut-size-decrease.rs:20:45 | @@ -14,4 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AU16` (16 bits) = note: target type: `u8` (8 bits) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/try_transmute_mut-size-increase.stderr b/tests/ui-msrv/try_transmute_mut-size-increase.stderr index b363475e5c..415d2f3278 100644 --- a/tests/ui-msrv/try_transmute_mut-size-increase.stderr +++ b/tests/ui-msrv/try_transmute_mut-size-increase.stderr @@ -6,14 +6,6 @@ warning: unused import: `util::AU16` | = note: `#[warn(unused_imports)]` on by default -warning: unused variable: `increase_size` - --> tests/ui-msrv/try_transmute_mut-size-increase.rs:20:9 - | -20 | let increase_size: Result<&mut [u8; 2], _> = try_transmute_mut!(src); - | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_increase_size` - | - = note: `#[warn(unused_variables)]` on by default - error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute_mut-size-increase.rs:20:50 | @@ -22,4 +14,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `u8` (8 bits) = note: target type: `[u8; 2]` (16 bits) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/try_transmute_mut-src-not-intobytes.stderr b/tests/ui-msrv/try_transmute_mut-src-not-intobytes.stderr index 170c63f9d2..ff726ab6d9 100644 --- a/tests/ui-msrv/try_transmute_mut-src-not-intobytes.stderr +++ b/tests/ui-msrv/try_transmute_mut-src-not-intobytes.stderr @@ -2,8 +2,21 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not sa --> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:19:52 | 19 | let src_not_into_bytes: Result<&mut AU16, _> = try_transmute_mut!(src); - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | ^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | required by a bound introduced by this call | + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others note: required by a bound in `try_transmute_mut` --> src/util/macro_util.rs | diff --git a/tests/ui-msrv/try_transmute_ref-alignment-increase.stderr b/tests/ui-msrv/try_transmute_ref-alignment-increase.stderr index 0ff43d87d4..5c9559b160 100644 --- a/tests/ui-msrv/try_transmute_ref-alignment-increase.stderr +++ b/tests/ui-msrv/try_transmute_ref-alignment-increase.stderr @@ -1,11 +1,3 @@ -warning: unused variable: `increase_size` - --> tests/ui-msrv/try_transmute_ref-alignment-increase.rs:19:9 - | -19 | let increase_size: Result<&AU16, _> = try_transmute_ref!(&[0u8; 2]); - | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_increase_size` - | - = note: `#[warn(unused_variables)]` on by default - error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute_ref-alignment-increase.rs:19:43 | @@ -14,4 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AlignOf<[u8; 2]>` (8 bits) = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/try_transmute_ref-dst-mutable.stderr b/tests/ui-msrv/try_transmute_ref-dst-mutable.stderr index 2c4ca40c00..c9c0ee358a 100644 --- a/tests/ui-msrv/try_transmute_ref-dst-mutable.stderr +++ b/tests/ui-msrv/try_transmute_ref-dst-mutable.stderr @@ -2,21 +2,31 @@ error[E0308]: mismatched types --> tests/ui-msrv/try_transmute_ref-dst-mutable.rs:18:33 | 18 | let _: Result<&mut u8, _> = try_transmute_ref!(&0u8); - | ^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | types differ in mutability + | arguments to this enum variant are incorrect | = note: expected mutable reference `&mut u8` found reference `&_` +note: tuple variant defined here + --> $RUST/core/src/result.rs + | + | Ok(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^ = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> tests/ui-msrv/try_transmute_ref-dst-mutable.rs:18:33 | 18 | let _: Result<&mut u8, _> = try_transmute_ref!(&0u8); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | types differ in mutability - | help: try using a variant of the expected enum: `Err($crate::util::macro_util::try_transmute_ref::<_, _>(e))` + | ^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability | = note: expected enum `Result<&mut u8, _>` found enum `Result<&_, ValidityError<&u8, _>>` = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) +help: try wrapping the expression in `Err` + --> src/macros.rs + | + | Err($crate::util::macro_util::try_transmute_ref::<_, _>(e)) + | ++++ + diff --git a/tests/ui-msrv/try_transmute_ref-dst-not-immutable-tryfrombytes.stderr b/tests/ui-msrv/try_transmute_ref-dst-not-immutable-tryfrombytes.stderr index fb6e75f23e..46e7083a27 100644 --- a/tests/ui-msrv/try_transmute_ref-dst-not-immutable-tryfrombytes.stderr +++ b/tests/ui-msrv/try_transmute_ref-dst-not-immutable-tryfrombytes.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 19 | let dst_not_try_from_bytes: Result<&NotZerocopy, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `try_transmute_ref` --> src/util/macro_util.rs | @@ -17,6 +27,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::Immutable` is not satisfie 19 | let dst_not_try_from_bytes: Result<&NotZerocopy, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::Immutable`: + &T + &mut T + () + *const T + *mut T + AU16 + Box + F32 + and $N others note: required by a bound in `try_transmute_ref` --> src/util/macro_util.rs | @@ -30,6 +50,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 19 | let dst_not_try_from_bytes: Result<&NotZerocopy, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `ValidityError` --> src/error.rs | @@ -42,6 +72,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 19 | let dst_not_try_from_bytes: Result<&NotZerocopy, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others note: required by a bound in `ValidityError` --> src/error.rs | diff --git a/tests/ui-msrv/try_transmute_ref-size-decrease.stderr b/tests/ui-msrv/try_transmute_ref-size-decrease.stderr index a2d527d858..c302a98976 100644 --- a/tests/ui-msrv/try_transmute_ref-size-decrease.stderr +++ b/tests/ui-msrv/try_transmute_ref-size-decrease.stderr @@ -1,11 +1,3 @@ -warning: unused variable: `decrease_size` - --> tests/ui-msrv/try_transmute_ref-size-decrease.rs:19:9 - | -19 | let decrease_size: Result<&u8, _> = try_transmute_ref!(&AU16(0)); - | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_decrease_size` - | - = note: `#[warn(unused_variables)]` on by default - error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute_ref-size-decrease.rs:19:41 | @@ -14,4 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AU16` (16 bits) = note: target type: `u8` (8 bits) - = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/try_transmute_ref-size-increase.stderr b/tests/ui-msrv/try_transmute_ref-size-increase.stderr index 44e02b42be..239d3c18de 100644 --- a/tests/ui-msrv/try_transmute_ref-size-increase.stderr +++ b/tests/ui-msrv/try_transmute_ref-size-increase.stderr @@ -1,11 +1,3 @@ -warning: unused variable: `increase_size` - --> tests/ui-msrv/try_transmute_ref-size-increase.rs:19:9 - | -19 | let increase_size: Result<&AU16, _> = try_transmute_ref!(&[0u8; 2]); - | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_increase_size` - | - = note: `#[warn(unused_variables)]` on by default - error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute_ref-size-increase.rs:19:43 | @@ -14,4 +6,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- | = note: source type: `AlignOf<[u8; 2]>` (8 bits) = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) - = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/try_transmute_ref-src-not-immutable-intobytes.stderr b/tests/ui-msrv/try_transmute_ref-src-not-immutable-intobytes.stderr index ca5a0daf99..25ab032501 100644 --- a/tests/ui-msrv/try_transmute_ref-src-not-immutable-intobytes.stderr +++ b/tests/ui-msrv/try_transmute_ref-src-not-immutable-intobytes.stderr @@ -2,8 +2,21 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not sa --> tests/ui-msrv/try_transmute_ref-src-not-immutable-intobytes.rs:19:48 | 19 | let src_not_into_bytes: Result<&AU16, _> = try_transmute_ref!(&NotZerocopy(AU16(0))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | required by a bound introduced by this call | + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others note: required by a bound in `try_transmute_ref` --> src/util/macro_util.rs | @@ -15,8 +28,21 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::Immutable` is not sa --> tests/ui-msrv/try_transmute_ref-src-not-immutable-intobytes.rs:19:48 | 19 | let src_not_into_bytes: Result<&AU16, _> = try_transmute_ref!(&NotZerocopy(AU16(0))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `zerocopy::Immutable` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `zerocopy::Immutable` is not implemented for `NotZerocopy` + | required by a bound introduced by this call | + = help: the following other types implement trait `zerocopy::Immutable`: + &T + &mut T + () + *const T + *mut T + AU16 + Box + F32 + and $N others note: required by a bound in `try_transmute_ref` --> src/util/macro_util.rs | diff --git a/zerocopy-derive/Cargo.toml b/zerocopy-derive/Cargo.toml index 71d4b55dbb..75f345aaa1 100644 --- a/zerocopy-derive/Cargo.toml +++ b/zerocopy-derive/Cargo.toml @@ -9,7 +9,7 @@ [package] edition = "2021" name = "zerocopy-derive" -version = "0.8.5" +version = "0.9.0-alpha.0" authors = ["Joshua Liebow-Feeser "] description = "Custom derive for traits from the zerocopy crate" license = "BSD-2-Clause OR Apache-2.0 OR MIT" diff --git a/zerocopy-derive/tests/include.rs b/zerocopy-derive/tests/include.rs index 6c236a3cf9..7a4bf32890 100644 --- a/zerocopy-derive/tests/include.rs +++ b/zerocopy-derive/tests/include.rs @@ -26,7 +26,7 @@ mod imp { #[allow(unused)] pub use { ::core::{ - assert_eq, + self, assert_eq, cell::UnsafeCell, convert::TryFrom, marker::PhantomData, diff --git a/zerocopy-derive/tests/struct_try_from_bytes.rs b/zerocopy-derive/tests/struct_try_from_bytes.rs index d212187cfa..5aa9d70695 100644 --- a/zerocopy-derive/tests/struct_try_from_bytes.rs +++ b/zerocopy-derive/tests/struct_try_from_bytes.rs @@ -171,7 +171,7 @@ fn test_maybe_from_bytes() { imp::assert!(!is_bit_valid); } -#[derive(Debug, PartialEq, Eq, imp::TryFromBytes, imp::Immutable, imp::KnownLayout)] +#[derive(imp::TryFromBytes, imp::Immutable, imp::KnownLayout)] #[repr(C, packed)] struct CPacked { a: u8, @@ -189,7 +189,9 @@ struct CPacked { fn c_packed() { let candidate = &[42u8, 0xFF, 0xFF, 0xFF, 0xFF]; let converted = ::try_ref_from_bytes(candidate); - imp::assert_eq!(converted, imp::Ok(&CPacked { a: 42, b: u32::MAX })); + // Can't derive `Debug` or `PartialEq` on a `#[repr(packed)]` type, so we + // can't use `assert_eq!` or `assert!(converted == ...)`. + imp::assert!(imp::core::matches!(converted, imp::Ok(&CPacked { a: 42, b: u32::MAX }))); } #[derive(imp::TryFromBytes, imp::KnownLayout, imp::Immutable)] diff --git a/zerocopy-derive/tests/ui-msrv/derive_transparent.stderr b/zerocopy-derive/tests/ui-msrv/derive_transparent.stderr index 20ebd03a16..6a4461aed4 100644 --- a/zerocopy-derive/tests/ui-msrv/derive_transparent.stderr +++ b/zerocopy-derive/tests/ui-msrv/derive_transparent.stderr @@ -1,10 +1,20 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied - --> tests/ui-msrv/derive_transparent.rs:34:1 + --> tests/ui-msrv/derive_transparent.rs:34:23 | 34 | util_assert_impl_all!(TransparentStruct: TryFromBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` - | -note: required because of the requirements on the impl of `zerocopy::TryFromBytes` for `TransparentStruct` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others +note: required for `TransparentStruct` to implement `zerocopy::TryFromBytes` --> tests/ui-msrv/derive_transparent.rs:24:21 | 24 | #[derive(IntoBytes, FromBytes, Unaligned)] @@ -13,16 +23,26 @@ note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` --> tests/ui-msrv/derive_transparent.rs:34:1 | 34 | util_assert_impl_all!(TransparentStruct: TryFromBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` - = note: this error originates in the macro `::static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` + = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `util_assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: FromZeros` is not satisfied - --> tests/ui-msrv/derive_transparent.rs:35:1 + --> tests/ui-msrv/derive_transparent.rs:35:23 | 35 | util_assert_impl_all!(TransparentStruct: FromZeros); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromZeros` is not implemented for `NotZerocopy` - | -note: required because of the requirements on the impl of `FromZeros` for `TransparentStruct` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromZeros` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `FromZeros`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others +note: required for `TransparentStruct` to implement `FromZeros` --> tests/ui-msrv/derive_transparent.rs:24:21 | 24 | #[derive(IntoBytes, FromBytes, Unaligned)] @@ -31,16 +51,26 @@ note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` --> tests/ui-msrv/derive_transparent.rs:35:1 | 35 | util_assert_impl_all!(TransparentStruct: FromZeros); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` - = note: this error originates in the macro `::static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` + = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `util_assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfied - --> tests/ui-msrv/derive_transparent.rs:36:1 + --> tests/ui-msrv/derive_transparent.rs:36:23 | 36 | util_assert_impl_all!(TransparentStruct: FromBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` - | -note: required because of the requirements on the impl of `zerocopy::FromBytes` for `TransparentStruct` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `zerocopy::FromBytes`: + () + AU16 + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others +note: required for `TransparentStruct` to implement `zerocopy::FromBytes` --> tests/ui-msrv/derive_transparent.rs:24:21 | 24 | #[derive(IntoBytes, FromBytes, Unaligned)] @@ -49,16 +79,26 @@ note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` --> tests/ui-msrv/derive_transparent.rs:36:1 | 36 | util_assert_impl_all!(TransparentStruct: FromBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` - = note: this error originates in the macro `::static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` + = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `util_assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied - --> tests/ui-msrv/derive_transparent.rs:37:1 + --> tests/ui-msrv/derive_transparent.rs:37:23 | 37 | util_assert_impl_all!(TransparentStruct: IntoBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` - | -note: required because of the requirements on the impl of `zerocopy::IntoBytes` for `TransparentStruct` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others +note: required for `TransparentStruct` to implement `zerocopy::IntoBytes` --> tests/ui-msrv/derive_transparent.rs:24:10 | 24 | #[derive(IntoBytes, FromBytes, Unaligned)] @@ -67,16 +107,26 @@ note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` --> tests/ui-msrv/derive_transparent.rs:37:1 | 37 | util_assert_impl_all!(TransparentStruct: IntoBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` - = note: this error originates in the macro `::static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` + = note: this error originates in the derive macro `IntoBytes` which comes from the expansion of the macro `util_assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: Unaligned` is not satisfied - --> tests/ui-msrv/derive_transparent.rs:38:1 + --> tests/ui-msrv/derive_transparent.rs:38:23 | 38 | util_assert_impl_all!(TransparentStruct: Unaligned); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `NotZerocopy` - | -note: required because of the requirements on the impl of `Unaligned` for `TransparentStruct` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `Unaligned`: + () + AtomicBool + AtomicI8 + AtomicU8 + F32 + F64 + I128 + I16 + and $N others +note: required for `TransparentStruct` to implement `Unaligned` --> tests/ui-msrv/derive_transparent.rs:24:32 | 24 | #[derive(IntoBytes, FromBytes, Unaligned)] @@ -85,5 +135,5 @@ note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` --> tests/ui-msrv/derive_transparent.rs:38:1 | 38 | util_assert_impl_all!(TransparentStruct: Unaligned); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` - = note: this error originates in the macro `::static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all` + = note: this error originates in the derive macro `Unaligned` which comes from the expansion of the macro `util_assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/zerocopy-derive/tests/ui-msrv/enum.stderr b/zerocopy-derive/tests/ui-msrv/enum.stderr index 938c8384e3..038682724f 100644 --- a/zerocopy-derive/tests/ui-msrv/enum.stderr +++ b/zerocopy-derive/tests/ui-msrv/enum.stderr @@ -83,7 +83,7 @@ error: FromZeros only supported on enums with a variant that has a discriminant | |_^ error: FromZeros only supported on enums with a variant that has a discriminant of `0` -help: This enum has discriminants which are not literal integers. One of those may define or imply which variant has a discriminant of zero. Use a literal integer to define or imply the variant with a discriminant of zero. + help: This enum has discriminants which are not literal integers. One of those may define or imply which variant has a discriminant of zero. Use a literal integer to define or imply the variant with a discriminant of zero. --> tests/ui-msrv/enum.rs:119:1 | 119 | / #[repr(i8)] @@ -294,6 +294,8 @@ error[E0552]: unrecognized representation hint | 25 | #[repr(foo)] | ^^^ + | + = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` error[E0566]: conflicting representation hints --> tests/ui-msrv/enum.rs:37:8 @@ -311,6 +313,16 @@ error[E0277]: the trait bound `UnsafeCell<()>: Immutable` is not satisfied 51 | #[derive(Immutable)] | ^^^^^^^^^ the trait `Immutable` is not implemented for `UnsafeCell<()>` | + = help: the following other types implement trait `Immutable`: + &T + &mut T + () + *const T + *mut T + F32 + F64 + I128 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `Immutable` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -320,6 +332,16 @@ error[E0277]: the trait bound `UnsafeCell: Immutable` is not satisfied 59 | #[derive(Immutable)] | ^^^^^^^^^ the trait `Immutable` is not implemented for `UnsafeCell` | + = help: the following other types implement trait `Immutable`: + &T + &mut T + () + *const T + *mut T + F32 + F64 + I128 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `Immutable` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -329,6 +351,16 @@ error[E0277]: the trait bound `NotTryFromBytes: TryFromBytes` is not satisfied 82 | #[derive(TryFromBytes)] | ^^^^^^^^^^^^ the trait `TryFromBytes` is not implemented for `NotTryFromBytes` | + = help: the following other types implement trait `TryFromBytes`: + () + *const T + *mut T + ::is_bit_valid::___ZerocopyVariantStruct_A + ::is_bit_valid::___ZerocopyVariantStruct_A + AtomicBool + AtomicI16 + AtomicI32 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `TryFromBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -338,6 +370,16 @@ error[E0277]: the trait bound `NotFromZeros: TryFromBytes` is not satisfied 127 | #[derive(FromZeros)] | ^^^^^^^^^ the trait `TryFromBytes` is not implemented for `NotFromZeros` | + = help: the following other types implement trait `TryFromBytes`: + () + *const T + *mut T + ::is_bit_valid::___ZerocopyVariantStruct_A + ::is_bit_valid::___ZerocopyVariantStruct_A + AtomicBool + AtomicI16 + AtomicI32 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `FromZeros` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -347,6 +389,16 @@ error[E0277]: the trait bound `NotFromZeros: FromZeros` is not satisfied 127 | #[derive(FromZeros)] | ^^^^^^^^^ the trait `FromZeros` is not implemented for `NotFromZeros` | + = help: the following other types implement trait `FromZeros`: + () + *const T + *mut T + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `FromZeros` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -356,6 +408,16 @@ error[E0277]: the trait bound `bool: FromBytes` is not satisfied 191 | #[derive(FromBytes)] | ^^^^^^^^^ the trait `FromBytes` is not implemented for `bool` | + = help: the following other types implement trait `FromBytes`: + () + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + AtomicU32 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -365,8 +427,7 @@ error[E0277]: the trait bound `(): PaddingFree` is not satisfi 538 | #[derive(IntoBytes)] | ^^^^^^^^^ the trait `PaddingFree` is not implemented for `()` | - = help: the following implementations were found: - <() as PaddingFree> + = help: the trait `PaddingFree` is implemented for `()` = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -376,8 +437,7 @@ error[E0277]: the trait bound `(): PaddingFree` is not satisfi 549 | #[derive(IntoBytes)] | ^^^^^^^^^ the trait `PaddingFree` is not implemented for `()` | - = help: the following implementations were found: - <() as PaddingFree> + = help: the trait `PaddingFree` is implemented for `()` = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -387,8 +447,7 @@ error[E0277]: the trait bound `(): PaddingFree` is not satisfi 555 | #[derive(IntoBytes)] | ^^^^^^^^^ the trait `PaddingFree` is not implemented for `()` | - = help: the following implementations were found: - <() as PaddingFree> + = help: the trait `PaddingFree` is implemented for `()` = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/zerocopy-derive/tests/ui-msrv/late_compile_pass.stderr b/zerocopy-derive/tests/ui-msrv/late_compile_pass.stderr index 0b57efc7d1..c52e355591 100644 --- a/zerocopy-derive/tests/ui-msrv/late_compile_pass.stderr +++ b/zerocopy-derive/tests/ui-msrv/late_compile_pass.stderr @@ -12,6 +12,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 28 | #[derive(TryFromBytes)] | ^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `TryFromBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -21,6 +31,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 37 | #[derive(FromZeros)] | ^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `FromZeros` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -30,6 +50,16 @@ error[E0277]: the trait bound `NotZerocopy: FromZeros` is not satisfied 37 | #[derive(FromZeros)] | ^^^^^^^^^ the trait `FromZeros` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `FromZeros`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `FromZeros` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -39,6 +69,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis 46 | #[derive(FromBytes)] | ^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::TryFromBytes`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -48,6 +88,16 @@ error[E0277]: the trait bound `NotZerocopy: FromZeros` is not satisfied 46 | #[derive(FromBytes)] | ^^^^^^^^^ the trait `FromZeros` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `FromZeros`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -57,6 +107,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfie 46 | #[derive(FromBytes)] | ^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::FromBytes`: + () + AU16 + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -66,6 +126,16 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfie 55 | #[derive(IntoBytes)] | ^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -75,6 +145,16 @@ error[E0277]: the trait bound `AU16: Unaligned` is not satisfied 65 | #[derive(Unaligned)] | ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` | + = help: the following other types implement trait `Unaligned`: + () + AtomicBool + AtomicI8 + AtomicU8 + F32 + F64 + I128 + I16 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -84,6 +164,16 @@ error[E0277]: the trait bound `AU16: Unaligned` is not satisfied 73 | #[derive(Unaligned)] | ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` | + = help: the following other types implement trait `Unaligned`: + () + AtomicBool + AtomicI8 + AtomicU8 + F32 + F64 + I128 + I16 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -93,5 +183,15 @@ error[E0277]: the trait bound `AU16: Unaligned` is not satisfied 80 | #[derive(Unaligned)] | ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` | + = help: the following other types implement trait `Unaligned`: + () + AtomicBool + AtomicI8 + AtomicU8 + F32 + F64 + I128 + I16 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/zerocopy-derive/tests/ui-msrv/mid_compile_pass.stderr b/zerocopy-derive/tests/ui-msrv/mid_compile_pass.stderr index 1d6d22df3f..2538c9deb4 100644 --- a/zerocopy-derive/tests/ui-msrv/mid_compile_pass.stderr +++ b/zerocopy-derive/tests/ui-msrv/mid_compile_pass.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `T: KnownLayout` is not satisfied 59 | fn test_kl13(t: T) -> impl KnownLayout { | ^^^^^^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `T` | -note: required because of the requirements on the impl of `KnownLayout` for `KL13` +note: required for `KL13` to implement `KnownLayout` --> tests/ui-msrv/mid_compile_pass.rs:55:10 | 55 | #[derive(KnownLayout)] @@ -21,14 +21,16 @@ error[E0277]: the size for values of type `T` cannot be known at compilation tim 30 | fn test_kl04(kl: &KL04) { | - this type parameter needs to be `std::marker::Sized` 31 | assert_kl(kl); - | ^^ doesn't have a size known at compile-time + | --------- ^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | note: required because it appears within the type `KL04` --> tests/ui-msrv/mid_compile_pass.rs:28:8 | 28 | struct KL04(u8, T); | ^^^^ -note: required because of the requirements on the impl of `KnownLayout` for `KL04` +note: required for `KL04` to implement `KnownLayout` --> tests/ui-msrv/mid_compile_pass.rs:27:10 | 27 | #[derive(KnownLayout)] @@ -51,14 +53,16 @@ error[E0277]: the size for values of type `T` cannot be known at compilation tim 39 | fn test_kl06(kl: &KL06) { | - this type parameter needs to be `std::marker::Sized` 40 | assert_kl(kl); - | ^^ doesn't have a size known at compile-time + | --------- ^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | note: required because it appears within the type `KL06` --> tests/ui-msrv/mid_compile_pass.rs:37:8 | 37 | struct KL06(u8, T); | ^^^^ -note: required because of the requirements on the impl of `KnownLayout` for `KL06` +note: required for `KL06` to implement `KnownLayout` --> tests/ui-msrv/mid_compile_pass.rs:36:10 | 36 | #[derive(KnownLayout)] @@ -79,9 +83,11 @@ error[E0277]: the trait bound `T: KnownLayout` is not satisfied --> tests/ui-msrv/mid_compile_pass.rs:50:15 | 50 | assert_kl(kl) - | ^^ the trait `KnownLayout` is not implemented for `T` + | --------- ^^ the trait `KnownLayout` is not implemented for `T` + | | + | required by a bound introduced by this call | -note: required because of the requirements on the impl of `KnownLayout` for `KL12` +note: required for `KL12` to implement `KnownLayout` --> tests/ui-msrv/mid_compile_pass.rs:45:10 | 45 | #[derive(KnownLayout)] diff --git a/zerocopy-derive/tests/ui-msrv/msrv_specific.stderr b/zerocopy-derive/tests/ui-msrv/msrv_specific.stderr index 027fd48507..82b8f08a2d 100644 --- a/zerocopy-derive/tests/ui-msrv/msrv_specific.stderr +++ b/zerocopy-derive/tests/ui-msrv/msrv_specific.stderr @@ -7,12 +7,22 @@ warning: unused `#[macro_use]` import = note: `#[warn(unused_imports)]` on by default error[E0277]: the trait bound `AU16: Unaligned` is not satisfied - --> tests/ui-msrv/msrv_specific.rs:35:9 + --> tests/ui-msrv/msrv_specific.rs:35:27 | 35 | is_into_bytes_1::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` + | ^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` | -note: required because of the requirements on the impl of `zerocopy::IntoBytes` for `IntoBytes1` + = help: the following other types implement trait `Unaligned`: + () + AtomicBool + AtomicI8 + AtomicU8 + F32 + F64 + I128 + I16 + and $N others +note: required for `IntoBytes1` to implement `zerocopy::IntoBytes` --> tests/ui-msrv/msrv_specific.rs:24:10 | 24 | #[derive(IntoBytes)] diff --git a/zerocopy-derive/tests/ui-msrv/struct.stderr b/zerocopy-derive/tests/ui-msrv/struct.stderr index 4fc4a581ff..ed72562beb 100644 --- a/zerocopy-derive/tests/ui-msrv/struct.stderr +++ b/zerocopy-derive/tests/ui-msrv/struct.stderr @@ -122,6 +122,16 @@ error[E0277]: the trait bound `NotKnownLayoutDst: zerocopy::KnownLayout` is not 41 | #[derive(KnownLayout)] | ^^^^^^^^^^^ the trait `zerocopy::KnownLayout` is not implemented for `NotKnownLayoutDst` | + = help: the following other types implement trait `zerocopy::KnownLayout`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -131,6 +141,16 @@ error[E0277]: the trait bound `NotKnownLayout: zerocopy::KnownLayout` is not sat 47 | #[derive(KnownLayout)] | ^^^^^^^^^^^ the trait `zerocopy::KnownLayout` is not implemented for `NotKnownLayout` | + = help: the following other types implement trait `zerocopy::KnownLayout`: + () + *const T + *mut T + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -140,6 +160,16 @@ error[E0277]: the trait bound `UnsafeCell<()>: zerocopy::Immutable` is not satis 55 | #[derive(Immutable)] | ^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `UnsafeCell<()>` | + = help: the following other types implement trait `zerocopy::Immutable`: + &T + &mut T + () + *const T + *mut T + AU16 + F32 + F64 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `Immutable` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -149,7 +179,17 @@ error[E0277]: the trait bound `UnsafeCell: zerocopy::Immutable` is not satis 60 | #[derive(Immutable)] | ^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `UnsafeCell` | - = note: required because of the requirements on the impl of `zerocopy::Immutable` for `[UnsafeCell; 0]` + = help: the following other types implement trait `zerocopy::Immutable`: + &T + &mut T + () + *const T + *mut T + AU16 + F32 + F64 + and $N others + = note: required for `[UnsafeCell; 0]` to implement `zerocopy::Immutable` = help: see issue #48214 = note: this error originates in the derive macro `Immutable` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -159,6 +199,16 @@ error[E0277]: the trait bound `AU16: Unaligned` is not satisfied 100 | #[derive(IntoBytes)] | ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` | + = help: the following other types implement trait `Unaligned`: + () + AtomicBool + AtomicI8 + AtomicU8 + F32 + F64 + I128 + I16 + and $N others = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -168,8 +218,7 @@ error[E0277]: the trait bound `(): PaddingFree` is not satisfi 107 | #[derive(IntoBytes)] | ^^^^^^^^^ the trait `PaddingFree` is not implemented for `()` | - = help: the following implementations were found: - <() as PaddingFree> + = help: the trait `PaddingFree` is implemented for `()` = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -179,8 +228,7 @@ error[E0277]: the trait bound `(): PaddingFree` is not satisfi 114 | #[derive(IntoBytes)] | ^^^^^^^^^ the trait `PaddingFree` is not implemented for `()` | - = help: the following implementations were found: - <() as PaddingFree> + = help: the trait `PaddingFree` is implemented for `()` = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -201,7 +249,7 @@ note: required by a bound in `std::mem::size_of` | | pub const fn size_of() -> usize { | ^ required by this bound in `std::mem::size_of` - = note: this error originates in the macro `::zerocopy::struct_has_padding` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/struct.rs:129:8 diff --git a/zerocopy-derive/tests/ui-msrv/union.stderr b/zerocopy-derive/tests/ui-msrv/union.stderr index 88251941af..af55c57d29 100644 --- a/zerocopy-derive/tests/ui-msrv/union.stderr +++ b/zerocopy-derive/tests/ui-msrv/union.stderr @@ -68,7 +68,17 @@ error[E0277]: the trait bound `UnsafeCell<()>: zerocopy::Immutable` is not satis 24 | #[derive(Immutable)] | ^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `UnsafeCell<()>` | - = note: required because of the requirements on the impl of `zerocopy::Immutable` for `ManuallyDrop>` + = help: the following other types implement trait `zerocopy::Immutable`: + &T + &mut T + () + *const T + *mut T + AU16 + F32 + F64 + and $N others + = note: required for `ManuallyDrop>` to implement `zerocopy::Immutable` = help: see issue #48214 = note: this error originates in the derive macro `Immutable` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -78,7 +88,6 @@ error[E0277]: the trait bound `(): PaddingFree` is not satisfi 39 | #[derive(IntoBytes)] | ^^^^^^^^^ the trait `PaddingFree` is not implemented for `()` | - = help: the following implementations were found: - <() as PaddingFree> + = help: the trait `PaddingFree` is implemented for `()` = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/zerocopy-derive/tests/ui-msrv/union_into_bytes_cfg/union_into_bytes_cfg.stderr b/zerocopy-derive/tests/ui-msrv/union_into_bytes_cfg/union_into_bytes_cfg.stderr index d25c238f6e..13d68fce49 100644 --- a/zerocopy-derive/tests/ui-msrv/union_into_bytes_cfg/union_into_bytes_cfg.stderr +++ b/zerocopy-derive/tests/ui-msrv/union_into_bytes_cfg/union_into_bytes_cfg.stderr @@ -1,5 +1,5 @@ error: requires --cfg zerocopy_derive_union_into_bytes; -please let us know you use this feature: https://github.com/google/zerocopy/discussions/1802 + please let us know you use this feature: https://github.com/google/zerocopy/discussions/1802 --> tests/ui-msrv/union_into_bytes_cfg/union_into_bytes_cfg.rs:20:10 | 20 | #[derive(IntoBytes)] From 2b56c078165f09194b6eb80816360eef8d27f6d5 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Sat, 12 Oct 2024 07:53:35 -0700 Subject: [PATCH 03/96] Enable clippy::missing_const_for_fn (#1883) * Release 0.9.0-alpha.0 Upgrade our MSRV to 1.65 and remove version detection logic prior to that version. * Enable clippy::missing_const_for_fn While we're here, remove defensive programming against bug in `Layout::from_size_align` which is no longer needed on our new MSRV. --- src/byteorder.rs | 1 + src/error.rs | 7 ++++--- src/lib.rs | 19 ++++++------------- src/pointer/ptr.rs | 29 +++++++++++++++-------------- src/ref.rs | 2 +- src/util/macros.rs | 4 ++-- src/util/mod.rs | 2 ++ src/wrappers.rs | 3 +-- 8 files changed, 32 insertions(+), 35 deletions(-) diff --git a/src/byteorder.rs b/src/byteorder.rs index 836790f9e5..a65cb167d7 100644 --- a/src/byteorder.rs +++ b/src/byteorder.rs @@ -967,6 +967,7 @@ module!(network_endian, NetworkEndian, "network-endian"); module!(native_endian, NativeEndian, "native-endian"); #[cfg(any(test, kani))] +#[allow(clippy::missing_const_for_fn)] mod tests { use super::*; diff --git a/src/error.rs b/src/error.rs index e30b6895ce..729102727d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -302,7 +302,7 @@ impl AlignmentError { AlignmentError { src: f(self.src), dst: SendSyncPhantomData::default() } } - pub(crate) fn into(self) -> ConvertError { + pub(crate) const fn into(self) -> ConvertError { ConvertError::Alignment(self) } @@ -463,7 +463,7 @@ impl SizeError { } /// Converts the error into a general [`ConvertError`]. - pub(crate) fn into(self) -> ConvertError { + pub(crate) const fn into(self) -> ConvertError { ConvertError::Size(self) } @@ -595,7 +595,7 @@ impl ValidityError { } /// Converts the error into a general [`ConvertError`]. - pub(crate) fn into(self) -> ConvertError { + pub(crate) const fn into(self) -> ConvertError { ConvertError::Validity(self) } @@ -957,6 +957,7 @@ pub type AlignedTryCastError = pub struct AllocError; #[cfg(test)] +#[allow(clippy::missing_const_for_fn)] mod tests { use super::*; diff --git a/src/lib.rs b/src/lib.rs index cbd8c4f4e2..c12e09d075 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -248,6 +248,7 @@ clippy::double_must_use, clippy::get_unwrap, clippy::indexing_slicing, + clippy::missing_const_for_fn, clippy::missing_inline_in_public_items, clippy::missing_safety_doc, clippy::must_use_candidate, @@ -3030,17 +3031,6 @@ pub unsafe trait FromZeros: TryFromBytes { }; let align = Self::LAYOUT.align.get(); - // On stable Rust versions <= 1.64.0, `Layout::from_size_align` has a - // bug in which sufficiently-large allocations (those which, when - // rounded up to the alignment, overflow `isize`) are not rejected, - // which can cause undefined behavior. See #64 for details. - // - // TODO(#67): Once our MSRV is > 1.64.0, remove this assertion. - #[allow(clippy::as_conversions)] - let max_alloc = (isize::MAX as usize).saturating_sub(align); - if size > max_alloc { - return Err(AllocError); - } // TODO(https://github.com/rust-lang/rust/issues/55724): Use // `Layout::repeat` once it's stabilized. @@ -3055,7 +3045,6 @@ pub unsafe trait FromZeros: TryFromBytes { None => return Err(AllocError), } } else { - let align = Self::LAYOUT.align.get(); // We use `transmute` instead of an `as` cast since Miri (with // strict provenance enabled) notices and complains that an `as` // cast creates a pointer with no provenance. Miri isn't smart @@ -5398,7 +5387,11 @@ mod alloc_support { pub use alloc_support::*; #[cfg(test)] -#[allow(clippy::assertions_on_result_states, clippy::unreadable_literal)] +#[allow( + clippy::assertions_on_result_states, + clippy::unreadable_literal, + clippy::missing_const_for_fn +)] mod tests { use static_assertions::assert_impl_all; diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index 100b0ded12..e46179c800 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -103,7 +103,7 @@ mod def { /// [`I::Alignment`](invariant::Alignment). /// 8. `ptr` conforms to the validity invariant of /// [`I::Validity`](invariant::Validity). - pub(super) unsafe fn new(ptr: NonNull) -> Ptr<'a, T, I> { + pub(super) const unsafe fn new(ptr: NonNull) -> Ptr<'a, T, I> { // SAFETY: The caller has promised to satisfy all safety invariants // of `Ptr`. Self { ptr, _invariants: PhantomData } @@ -114,7 +114,7 @@ mod def { /// Note that this method does not consume `self`. The caller should /// watch out for `unsafe` code which uses the returned `NonNull` in a /// way that violates the safety invariants of `self`. - pub(crate) fn as_non_null(&self) -> NonNull { + pub(crate) const fn as_non_null(&self) -> NonNull { self.ptr } } @@ -717,7 +717,7 @@ mod _transitions { /// # Safety /// /// The caller promises that `self` satisfies the invariants `H`. - unsafe fn assume_invariants(self) -> Ptr<'a, T, H> { + const unsafe fn assume_invariants(self) -> Ptr<'a, T, H> { // SAFETY: The caller has promised to satisfy all parameterized // invariants of `Ptr`. `Ptr`'s other invariants are satisfied // by-contract by the source `Ptr`. @@ -726,7 +726,7 @@ mod _transitions { /// Helps the type system unify two distinct invariant types which are /// actually the same. - pub(crate) fn unify_invariants< + pub(crate) const fn unify_invariants< H: Invariants, >( self, @@ -743,7 +743,7 @@ mod _transitions { /// The caller promises that `self` satisfies the aliasing requirement /// of `A`. #[inline] - pub(crate) unsafe fn assume_aliasing( + pub(crate) const unsafe fn assume_aliasing( self, ) -> Ptr<'a, T, (A, I::Alignment, I::Validity)> { // SAFETY: The caller promises that `self` satisfies the aliasing @@ -760,7 +760,7 @@ mod _transitions { /// /// [`Exclusive`]: invariant::Exclusive #[inline] - pub(crate) unsafe fn assume_exclusive( + pub(crate) const unsafe fn assume_exclusive( self, ) -> Ptr<'a, T, (Exclusive, I::Alignment, I::Validity)> { // SAFETY: The caller promises that `self` satisfies the aliasing @@ -776,7 +776,7 @@ mod _transitions { /// The caller promises that `self`'s referent conforms to the alignment /// invariant of `T` if required by `A`. #[inline] - pub(crate) unsafe fn assume_alignment( + pub(crate) const unsafe fn assume_alignment( self, ) -> Ptr<'a, T, (I::Aliasing, A, I::Validity)> { // SAFETY: The caller promises that `self`'s referent is @@ -804,7 +804,7 @@ mod _transitions { #[inline] // TODO(#859): Reconsider the name of this method before making it // public. - pub(crate) fn bikeshed_recall_aligned( + pub(crate) const fn bikeshed_recall_aligned( self, ) -> Ptr<'a, T, (I::Aliasing, Aligned, I::Validity)> where @@ -825,7 +825,7 @@ mod _transitions { #[doc(hidden)] #[must_use] #[inline] - pub unsafe fn assume_validity( + pub const unsafe fn assume_validity( self, ) -> Ptr<'a, T, (I::Aliasing, I::Alignment, V)> { // SAFETY: The caller promises that `self`'s referent conforms to @@ -842,7 +842,7 @@ mod _transitions { #[doc(hidden)] #[must_use] #[inline] - pub unsafe fn assume_initialized( + pub const unsafe fn assume_initialized( self, ) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Initialized)> { // SAFETY: The caller has promised to uphold the safety @@ -859,7 +859,7 @@ mod _transitions { #[doc(hidden)] #[must_use] #[inline] - pub unsafe fn assume_valid(self) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Valid)> { + pub const unsafe fn assume_valid(self) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Valid)> { // SAFETY: The caller has promised to uphold the safety // preconditions. unsafe { self.assume_validity::() } @@ -871,7 +871,7 @@ mod _transitions { #[inline] // TODO(#859): Reconsider the name of this method before making it // public. - pub fn bikeshed_recall_valid(self) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Valid)> + pub const fn bikeshed_recall_valid(self) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Valid)> where T: crate::FromBytes, I: Invariants, @@ -921,7 +921,7 @@ mod _transitions { #[doc(hidden)] #[must_use] #[inline] - pub fn forget_exclusive(self) -> Ptr<'a, T, (Shared, I::Alignment, I::Validity)> + pub const fn forget_exclusive(self) -> Ptr<'a, T, (Shared, I::Alignment, I::Validity)> where I::Aliasing: AtLeast, { @@ -933,7 +933,7 @@ mod _transitions { #[doc(hidden)] #[must_use] #[inline] - pub fn forget_aligned(self) -> Ptr<'a, T, (I::Aliasing, Any, I::Validity)> { + pub const fn forget_aligned(self) -> Ptr<'a, T, (I::Aliasing, Any, I::Validity)> { // SAFETY: `Any` is less restrictive than `Aligned`. unsafe { self.assume_invariants() } } @@ -1641,6 +1641,7 @@ mod _project { } #[cfg(test)] +#[allow(clippy::missing_const_for_fn)] mod tests { use core::mem::{self, MaybeUninit}; diff --git a/src/ref.rs b/src/ref.rs index 0f4ce00214..5a01b01442 100644 --- a/src/ref.rs +++ b/src/ref.rs @@ -75,7 +75,7 @@ mod def { /// [`deref`]: core::ops::Deref::deref /// [`deref_mut`]: core::ops::DerefMut::deref_mut /// [`into`]: core::convert::Into::into - pub(crate) unsafe fn new_unchecked(bytes: B) -> Ref { + pub(crate) const unsafe fn new_unchecked(bytes: B) -> Ref { // INVARIANTS: The caller has promised that `bytes`'s referent is // validly-aligned and has a valid size. Ref(bytes, PhantomData) diff --git a/src/util/macros.rs b/src/util/macros.rs index cbeffdaee2..4626e0d3c4 100644 --- a/src/util/macros.rs +++ b/src/util/macros.rs @@ -255,7 +255,7 @@ macro_rules! impl_for_transparent_wrapper { impl_for_transparent_wrapper!(@define_is_transparent_wrapper $trait); #[cfg_attr(coverage_nightly, coverage(off))] - fn f() { + const fn f() { is_transparent_wrapper::(); } } @@ -327,7 +327,7 @@ macro_rules! impl_for_transparent_wrapper { }; (@define_is_transparent_wrapper $trait:ident, $variance:ident) => { #[cfg_attr(coverage_nightly, coverage(off))] - fn is_transparent_wrapper + ?Sized>() + const fn is_transparent_wrapper + ?Sized>() where W::Inner: $trait, {} diff --git a/src/util/mod.rs b/src/util/mod.rs index 04d8b8f546..8df0b26590 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -756,6 +756,7 @@ pub(crate) mod polyfills { } #[cfg(test)] +#[allow(clippy::missing_const_for_fn)] pub(crate) mod testutil { use crate::*; @@ -845,6 +846,7 @@ pub(crate) mod testutil { } #[cfg(test)] +#[allow(clippy::missing_const_for_fn)] mod tests { use super::*; diff --git a/src/wrappers.rs b/src/wrappers.rs index 4b52622573..f176abf467 100644 --- a/src/wrappers.rs +++ b/src/wrappers.rs @@ -393,9 +393,8 @@ impl Unalign { impl Unalign { /// Gets a copy of the inner `T`. - // TODO(https://github.com/rust-lang/rust/issues/57349): Make this `const`. #[inline(always)] - pub fn get(&self) -> T { + pub const fn get(&self) -> T { let Unalign(val) = *self; val } From 1788f441343248d308fd6e032c47087f6adec3f7 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Sat, 12 Oct 2024 08:28:48 -0700 Subject: [PATCH 04/96] Upgrade some code for MSRV 1.65 (#1885) Now that our MSRV is 1.65, we can clean up some code. Makes progress on #67 --- src/layout.rs | 21 ++++----------------- src/pointer/ptr.rs | 3 --- src/util/macro_util.rs | 7 +------ src/util/mod.rs | 2 +- zerocopy-derive/src/lib.rs | 22 ---------------------- 5 files changed, 6 insertions(+), 49 deletions(-) diff --git a/src/layout.rs b/src/layout.rs index d2f4cd2900..5aaf102f8a 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -474,12 +474,8 @@ impl DstLayout { // invalid type) instead of allowing this panic to be hidden if the cast // would have failed anyway for runtime reasons (such as a too-small // memory region). - // - // TODO(#67): Once our MSRV is 1.65, use let-else: - // https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#let-else-statements - let size_info = match self.size_info.try_to_nonzero_elem_size() { - Some(size_info) => size_info, - None => panic!("attempted to cast to slice type with zero-sized element"), + let Some(size_info) = self.size_info.try_to_nonzero_elem_size() else { + panic!("attempted to cast to slice type with zero-sized element"); }; // Precondition @@ -531,13 +527,9 @@ impl DstLayout { util::round_down_to_next_multiple_of_alignment(bytes_len, self.align); // Calculate the maximum number of bytes that could be consumed // by the trailing slice. - // - // TODO(#67): Once our MSRV is 1.65, use let-else: - // https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#let-else-statements - let max_slice_and_padding_bytes = match max_total_bytes.checked_sub(offset) { - Some(max) => max, + let Some(max_slice_and_padding_bytes) = max_total_bytes.checked_sub(offset) else { // `bytes_len` too small even for 0 trailing slice elements. - None => return Err(MetadataCastError::Size), + return Err(MetadataCastError::Size); }; // Calculate the number of elements that fit in @@ -596,11 +588,6 @@ impl DstLayout { } } -// TODO(#67): For some reason, on our MSRV toolchain, this `allow` isn't -// enforced despite having `#![allow(unknown_lints)]` at the crate root, but -// putting it here works. Once our MSRV is high enough that this bug has been -// fixed, remove this `allow`. -#[allow(unknown_lints)] #[cfg(test)] mod tests { use super::*; diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index e46179c800..a1ea6ba98f 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -1296,9 +1296,6 @@ mod _casts { U: 'a + ?Sized + KnownLayout + AliasingSafe<[u8], I::Aliasing, R>, R: AliasingSafeReason, { - // TODO(#67): Remove this allow. See NonNulSlicelExt for more - // details. - #[allow(unstable_name_collisions)] match self.try_cast_into(CastType::Prefix, meta) { Ok((slf, remainder)) => { if remainder.len() == 0 { diff --git a/src/util/macro_util.rs b/src/util/macro_util.rs index f7e66056d2..734ff50759 100644 --- a/src/util/macro_util.rs +++ b/src/util/macro_util.rs @@ -469,12 +469,7 @@ pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( // - The caller has guaranteed that alignment is not increased. // - We know that the returned lifetime will not outlive the input lifetime // thanks to the lifetime bounds on this function. - // - // TODO(#67): Once our MSRV is 1.58, replace this `transmute` with `&*dst`. - #[allow(clippy::transmute_ptr_to_ref)] - unsafe { - mem::transmute(dst) - } + unsafe { &*dst } } /// Transmutes a mutable reference of one type to a mutable reference of another diff --git a/src/util/mod.rs b/src/util/mod.rs index 8df0b26590..b00437cd7c 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -725,7 +725,7 @@ pub(crate) mod polyfills { // toolchain versions, `ptr.slice_from_raw_parts()` resolves to the inherent // method rather than to this trait, and so this trait is considered unused. // - // TODO(#67): Once our MSRV is high enough, remove this. + // TODO(#67): Once our MSRV is >= 1.79, remove this. #[allow(unused)] pub(crate) trait NumExt { /// Subtract without checking for underflow. diff --git a/zerocopy-derive/src/lib.rs b/zerocopy-derive/src/lib.rs index 65414b51fa..e2318c53b4 100644 --- a/zerocopy-derive/src/lib.rs +++ b/zerocopy-derive/src/lib.rs @@ -1349,25 +1349,3 @@ fn impl_block( } } } - -// A polyfill for `Option::then_some`, which was added after our MSRV. -// -// The `#[allow(unused)]` is necessary because, on sufficiently recent toolchain -// versions, `b.then_some(...)` resolves to the inherent method rather than to -// this trait, and so this trait is considered unused. -// -// TODO(#67): Remove this once our MSRV is >= 1.62. -#[allow(unused)] -trait BoolExt { - fn then_some(self, t: T) -> Option; -} - -impl BoolExt for bool { - fn then_some(self, t: T) -> Option { - if self { - Some(t) - } else { - None - } - } -} From 7349fe0c745ecb89cba8dfaf70764e57378b5c88 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Sat, 12 Oct 2024 08:53:37 -0700 Subject: [PATCH 05/96] Clean up some code for new MSRV (#1888) Also clean up some code for 0.9. --- src/lib.rs | 21 --------------------- src/pointer/ptr.rs | 1 - src/wrappers.rs | 6 +----- 3 files changed, 1 insertion(+), 27 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c12e09d075..7c87b7ddca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -395,27 +395,6 @@ const _: () = { _WARNING }; -// These exist so that code which was written against the old names will get -// less confusing error messages when they upgrade to a more recent version of -// zerocopy. On our MSRV toolchain, the error messages read, for example: -// -// error[E0603]: trait `FromZeroes` is private -// --> examples/deprecated.rs:1:15 -// | -// 1 | use zerocopy::FromZeroes; -// | ^^^^^^^^^^ private trait -// | -// note: the trait `FromZeroes` is defined here -// --> /Users/josh/workspace/zerocopy/src/lib.rs:1845:5 -// | -// 1845 | use FromZeros as FromZeroes; -// | ^^^^^^^^^^^^^^^^^^^^^^^ -// -// The "note" provides enough context to make it easy to figure out how to fix -// the error. -#[allow(unused)] -use {FromZeros as FromZeroes, IntoBytes as AsBytes, Ref as LayoutVerified}; - /// Implements [`KnownLayout`]. /// /// This derive analyzes various aspects of a type's layout that are needed for diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index a1ea6ba98f..6147ea7fc5 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -120,7 +120,6 @@ mod def { } } -#[allow(unreachable_pub)] // This is a false positive on our MSRV toolchain. pub use def::Ptr; /// Used to define the system of [invariants][invariant] of `Ptr`. diff --git a/src/wrappers.rs b/src/wrappers.rs index f176abf467..ac2442486e 100644 --- a/src/wrappers.rs +++ b/src/wrappers.rs @@ -239,11 +239,7 @@ impl Unalign { // but the caller has promised that `self` is properly aligned, so we // know that it is sound to create a reference to `T` at this memory // location. - // - // We use `mem::transmute` instead of `&*self.get_ptr()` because - // dereferencing pointers is not stable in `const` on our current MSRV - // (1.56 as of this writing). - unsafe { mem::transmute(self) } + unsafe { &*self.get_ptr() } } /// Returns a mutable reference to the wrapped `T` without checking From 19ab41ccba56dc1bc084bcb99c838168d42f9e97 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Sat, 12 Oct 2024 09:04:03 -0700 Subject: [PATCH 06/96] Upgrade versions of some dependencies (#1886) * Upgrade some code for MSRV 1.65 Now that our MSRV is 1.65, we can clean up some code. Makes progress on #67 * Upgrade versions of some dependencies Now that our MSRV is 1.65, it unlocks upgrading some dependencies' versions. --- .github/workflows/ci.yml | 4 ++-- Cargo.toml | 8 ++++---- zerocopy-derive/Cargo.toml | 16 +++++----------- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6fb9264c21..75b09963ec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -191,7 +191,7 @@ jobs: set -eo pipefail # Override the exising `syn` dependency with one which requires an exact # version. - cargo add -p zerocopy-derive 'syn@=2.0.46' + cargo add -p zerocopy-derive 'syn@=2.0.79' - name: Configure environment variables run: | @@ -613,7 +613,7 @@ jobs: # # TODO(#1595): Debug why this step is still necessary after #1564 and # maybe remove it. - cargo add -p zerocopy-derive 'syn@=2.0.46' &> /dev/null + cargo add -p zerocopy-derive 'syn@=2.0.79' &> /dev/null cargo check --workspace --tests &> /dev/null & cargo metadata &> /dev/null & diff --git a/Cargo.toml b/Cargo.toml index aa0ca6aa77..9d917d4c3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,16 +71,16 @@ zerocopy-derive = { version = "=0.9.0-alpha.0", path = "zerocopy-derive", option zerocopy-derive = { version = "=0.9.0-alpha.0", path = "zerocopy-derive" } [dev-dependencies] -itertools = "0.11" +itertools = "0.13.0" rand = { version = "0.8.5", default-features = false, features = ["small_rng"] } -rustversion = "1.0" -static_assertions = "1.1" +rustversion = "1.0.17" +static_assertions = "1.1.0" testutil = { path = "testutil" } # Pinned to a specific version so that the version used for local development # and the version used in CI are guaranteed to be the same. Future versions # sometimes change the output format slightly, so a version mismatch can cause # CI test failures. -trybuild = { version = "=1.0.89", features = ["diff"] } +trybuild = { version = "=1.0.90", features = ["diff"] } # In tests, unlike in production, zerocopy-derive is not optional zerocopy-derive = { version = "=0.9.0-alpha.0", path = "zerocopy-derive" } # TODO(#381) Remove this dependency once we have our own layout gadgets. diff --git a/zerocopy-derive/Cargo.toml b/zerocopy-derive/Cargo.toml index 75f345aaa1..d348ef482e 100644 --- a/zerocopy-derive/Cargo.toml +++ b/zerocopy-derive/Cargo.toml @@ -32,23 +32,17 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.1" quote = "1.0.10" -syn = { version = "2.0.46", features = ["full"] } +syn = { version = "2.0.79", features = ["full"] } [dev-dependencies] dissimilar = "1.0.9" -# We don't use this directly, but trybuild does. On the MSRV toolchain, the -# version resolver fails to select any version for once_cell unless we -# depend on it directly. -once_cell = "=1.9" -# This is the latest version which is compatible with `syn` 2.0.46, which we pin -# to in CI for MSRV compatibility reasons. -prettyplease = "=0.2.17" -rustversion = "1.0" -static_assertions = "1.1" +prettyplease = "0.2.22" +rustversion = "1.0.17" +static_assertions = "1.1.0" testutil = { path = "../testutil" } # Pinned to a specific version so that the version used for local development # and the version used in CI are guaranteed to be the same. Future versions # sometimes change the output format slightly, so a version mismatch can cause # CI test failures. -trybuild = { version = "=1.0.89", features = ["diff"] } +trybuild = { version = "=1.0.90", features = ["diff"] } zerocopy = { path = "../", features = ["derive"] } From 5452c3d787486603e57bd191571ad05525c181b0 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Sat, 12 Oct 2024 09:17:45 -0700 Subject: [PATCH 07/96] Roll pinned toolchains on v0.8.x branch (#1887) --- .github/workflows/roll-pinned-toolchain-versions.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/roll-pinned-toolchain-versions.yml b/.github/workflows/roll-pinned-toolchain-versions.yml index 90de5927d1..7592de8179 100644 --- a/.github/workflows/roll-pinned-toolchain-versions.yml +++ b/.github/workflows/roll-pinned-toolchain-versions.yml @@ -35,7 +35,7 @@ jobs: fail-fast: false matrix: toolchain: ["stable", "nightly"] - branch: ["main"] + branch: ["main", "v0.8.x"] name: Roll pinned toolchain ${{ matrix.toolchain }} version on ${{ matrix.branch }} steps: - name: Checkout code From 2e819ac05d5a0840adfea34940b2b54bbfb512b7 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Sun, 13 Oct 2024 06:43:46 -0700 Subject: [PATCH 08/96] [ci] Roll pinned nightly toolchain (#1900) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 9d917d4c3b..cbcbf5bafa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.81.0" -pinned-nightly = "nightly-2024-10-11" +pinned-nightly = "nightly-2024-10-12" [package.metadata.docs.rs] all-features = true From ccf477d03c8ba45ef0837221131128391b17e79f Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Mon, 14 Oct 2024 06:33:59 -0700 Subject: [PATCH 09/96] [ci] Roll pinned nightly toolchain (#1902) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cbcbf5bafa..17edaf4ef0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.81.0" -pinned-nightly = "nightly-2024-10-12" +pinned-nightly = "nightly-2024-10-13" [package.metadata.docs.rs] all-features = true From c128ed2f8ff81c2fb2f57e434819377357101a59 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 13:39:10 +0000 Subject: [PATCH 10/96] [CI] Bump github/codeql-action from 3.26.12 to 3.26.13 (#1903) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.26.12 to 3.26.13. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/c36620d31ac7c881962c3d9dd939c40ec9434f2b...f779452ac5af1c261dce0346a8f964149f49322b) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index b8fc853a0f..eaaad9f67f 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -66,6 +66,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 + uses: github/codeql-action/upload-sarif@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13 with: sarif_file: results.sarif From 1c8cbc7414fbd275fcf864ed6e02e250321f27a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 13:39:58 +0000 Subject: [PATCH 11/96] [CI] Bump Swatinem/rust-cache from 2.7.3 to 2.7.5 (#1904) Bumps [Swatinem/rust-cache](https://github.com/swatinem/rust-cache) from 2.7.3 to 2.7.5. - [Release notes](https://github.com/swatinem/rust-cache/releases) - [Changelog](https://github.com/Swatinem/rust-cache/blob/master/CHANGELOG.md) - [Commits](https://github.com/swatinem/rust-cache/compare/23bce251a8cd2ffc3c1075eaa2367cf899916d84...82a92a6e8fbeee089604da2575dc567ae9ddeaab) --- updated-dependencies: - dependency-name: Swatinem/rust-cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 75b09963ec..a9cfc928c1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -253,7 +253,7 @@ jobs: components: clippy, rust-src ${{ matrix.toolchain == 'nightly' && ', miri' || '' }} - name: Rust Cache - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2.7.5 with: key: "${{ matrix.target }}" @@ -526,7 +526,7 @@ jobs: echo "RUSTFLAGS=$RUSTFLAGS" >> $GITHUB_ENV echo "ZC_TOOLCHAIN=$ZC_TOOLCHAIN" >> $GITHUB_ENV - name: Rust Cache - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2.7.5 with: key: aarch64_be-unknown-linux-gnu - name: Install stable Rust for use in 'cargo.sh' From d9e48e36bb5031b5aad814f94656710d38ac8ec0 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Mon, 14 Oct 2024 07:45:42 -0700 Subject: [PATCH 12/96] [pointer] Clarify semantics of aliasing invariants (#1889) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, we supported the `AtLeast` bound, which was used to describe a subset relationship in which `I: AtLeast` implied that `I` as at least as restrictive as `J`. However, as described in #1866, this incorrectly models invariants as monotonic. In reality, invariants both provide guarantees but also *require* guarantees. This commit takes a step in the direction of resolving #1866 by removing `AtLeast`. Uses of `AtLeast` are replaced by a new `Reference` trait, which is implemented for `Shared` and `Exclusive`. This serves two purposes: First, it makes it explicit what this bound means. Previously, `AtLeast` had an ambiguous meaning, while `Reference` means precisely that an invariant is either `Shared` or `Exclusive` and nothing else. Second, it paves the way for #1183, in which we may add new aliasing invariants which convey ownership. In that case, it will be important for existing methods to add `Reference` bounds when those methods would not be sound in the face of ownership semantics. We also inline the items in the `invariant` module, which were previously generated by macro. The addition of the `Reference` trait did not play nicely with that macro, and we will likely need to go further from the macro in order to fix #1839 – this fix will likely require making aliasing invariants meaningfully different than other invariants, for example by adding an associated type. Makes progress on #1866 --- src/impls.rs | 16 +- src/lib.rs | 4 +- src/pointer/mod.rs | 17 +- src/pointer/ptr.rs | 414 +++++++++++----------------- src/util/macro_util.rs | 4 +- src/util/macros.rs | 8 +- zerocopy-derive/src/enum.rs | 3 +- zerocopy-derive/src/lib.rs | 12 +- zerocopy-derive/src/output_tests.rs | 45 +-- 9 files changed, 212 insertions(+), 311 deletions(-) diff --git a/src/impls.rs b/src/impls.rs index b4712d8932..b082c30b21 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -657,9 +657,7 @@ unsafe impl TryFromBytes for UnsafeCell { } #[inline] - fn is_bit_valid>( - candidate: Maybe<'_, Self, A>, - ) -> bool { + fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool { // The only way to implement this function is using an exclusive-aliased // pointer. `UnsafeCell`s cannot be read via shared-aliased pointers // (other than by using `unsafe` code, which we can't use since we can't @@ -1134,10 +1132,7 @@ mod tests { pub(super) trait TestIsBitValidShared { #[allow(clippy::needless_lifetimes)] - fn test_is_bit_valid_shared< - 'ptr, - A: invariant::Aliasing + invariant::AtLeast, - >( + fn test_is_bit_valid_shared<'ptr, A: invariant::Reference>( &self, candidate: Maybe<'ptr, T, A>, ) -> Option; @@ -1145,10 +1140,7 @@ mod tests { impl TestIsBitValidShared for AutorefWrapper { #[allow(clippy::needless_lifetimes)] - fn test_is_bit_valid_shared< - 'ptr, - A: invariant::Aliasing + invariant::AtLeast, - >( + fn test_is_bit_valid_shared<'ptr, A: invariant::Reference>( &self, candidate: Maybe<'ptr, T, A>, ) -> Option { @@ -1238,7 +1230,7 @@ mod tests { #[allow(unused, non_local_definitions)] impl AutorefWrapper<$ty> { #[allow(clippy::needless_lifetimes)] - fn test_is_bit_valid_shared<'ptr, A: invariant::Aliasing + invariant::AtLeast>( + fn test_is_bit_valid_shared<'ptr, A: invariant::Reference>( &mut self, candidate: Maybe<'ptr, $ty, A>, ) -> Option { diff --git a/src/lib.rs b/src/lib.rs index 7c87b7ddca..3b79c8c900 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1321,9 +1321,7 @@ pub unsafe trait TryFromBytes { /// [`UnsafeCell`]: core::cell::UnsafeCell /// [`Shared`]: invariant::Shared #[doc(hidden)] - fn is_bit_valid>( - candidate: Maybe<'_, Self, A>, - ) -> bool; + fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool; /// Attempts to interpret the given `source` as a `&Self`. /// diff --git a/src/pointer/mod.rs b/src/pointer/mod.rs index 1533eb9efd..0e13e59f65 100644 --- a/src/pointer/mod.rs +++ b/src/pointer/mod.rs @@ -35,7 +35,7 @@ pub type MaybeAligned<'a, T, Aliasing = invariant::Shared, Alignment = invariant impl<'a, T, Aliasing, Alignment> MaybeAligned<'a, T, Aliasing, Alignment> where T: 'a + ?Sized, - Aliasing: invariant::Aliasing + invariant::AtLeast, + Aliasing: invariant::Reference, Alignment: invariant::Alignment, { /// Reads the value from `MaybeAligned`. @@ -47,11 +47,20 @@ where { let raw = self.as_non_null().as_ptr(); // SAFETY: By invariant on `MaybeAligned`, `raw` contains - // validly-initialized data for `T`. The value is safe to read and - // return, because `T` is copy. + // validly-initialized data for `T`. By `Aliasing: Reference`, + // `Aliasing` is either `Shared` or `Exclusive`, both of which ensure + // that it is sound to perform this read. By `T: Copy`, the value is + // safe to return. unsafe { core::ptr::read_unaligned(raw) } } +} +impl<'a, T, Aliasing, Alignment> MaybeAligned<'a, T, Aliasing, Alignment> +where + T: 'a + ?Sized, + Aliasing: invariant::Reference, + Alignment: invariant::Alignment, +{ /// Views the value as an aligned reference. /// /// This is only available if `T` is [`Unaligned`]. @@ -70,7 +79,7 @@ pub(crate) fn is_zeroed(ptr: Ptr<'_, T, I>) -> bool where T: crate::Immutable + crate::KnownLayout, I: invariant::Invariants, - I::Aliasing: invariant::AtLeast, + I::Aliasing: invariant::Reference, { ptr.as_bytes::().as_ref().iter().all(|&byte| byte == 0) } diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index 6147ea7fc5..8ca250ace0 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -122,182 +122,143 @@ mod def { pub use def::Ptr; -/// Used to define the system of [invariants][invariant] of `Ptr`. -macro_rules! define_system { - ($(#[$system_attr:meta])* $system:ident { - $($(#[$set_attr:meta])* $set:ident { - $( $(#[$elem_attr:meta])* $elem:ident $(< $($stronger_elem:ident)|*)?,)* - })* - }) => { - /// No requirement - any invariant is allowed. - #[allow(missing_copy_implementations, missing_debug_implementations)] - pub enum Any {} - - /// `Self` imposes a requirement at least as strict as `I`. - pub trait AtLeast {} - - mod sealed { - pub trait Sealed {} - - impl<$($set,)*> Sealed for ($($set,)*) - where - $($set: super::$set,)* - {} - - impl Sealed for super::Any {} - - $($( - impl Sealed for super::$elem {} - )*)* - } +/// The parameterized invariants of a [`Ptr`]. +/// +/// Invariants are encoded as ([`Aliasing`], [`Alignment`], [`Validity`]) +/// triples implementing the [`Invariants`] trait. +#[doc(hidden)] +#[allow(missing_copy_implementations, missing_debug_implementations)] +pub mod invariant { + /// The invariants of a [`Ptr`][super::Ptr]. + pub trait Invariants: Sealed { + type Aliasing: Aliasing; + type Alignment: Alignment; + type Validity: Validity; + } - $(#[$system_attr])* - /// - #[doc = concat!( - stringify!($system), - " are encoded as tuples of (", - )] - $(#[doc = concat!( - "[`", - stringify!($set), - "`]," - )])* - #[doc = concat!( - ").", - )] - /// This trait is implemented for such tuples, and can be used to - /// project out the components of these tuples via its associated types. - pub trait $system: sealed::Sealed { - $( - $(#[$set_attr])* - type $set: $set; - )* - } + impl Invariants for (A, AA, V) { + type Aliasing = A; + type Alignment = AA; + type Validity = V; + } - impl<$($set,)*> $system for ($($set,)*) - where - $($set: self::$set,)* - { - $(type $set = $set;)* - } + /// The aliasing invariant of a [`Ptr`][super::Ptr]. + pub trait Aliasing: Sealed { + /// Is `Self` [`Exclusive`]? + #[doc(hidden)] + const IS_EXCLUSIVE: bool; + } - $( - $(#[$set_attr])* - pub trait $set: 'static + sealed::Sealed { - // This only exists for use in - // `into_exclusive_or_post_monomorphization_error`. - #[doc(hidden)] - const NAME: &'static str; - } + /// The alignment invariant of a [`Ptr`][super::Ptr]. + pub trait Alignment: Sealed {} - impl $set for Any { - const NAME: &'static str = stringify!(Any); - } + /// The validity invariant of a [`Ptr`][super::Ptr]. + pub trait Validity: Sealed {} - $( - $(#[$elem_attr])* - #[allow(missing_copy_implementations, missing_debug_implementations)] - pub enum $elem {} + /// An [`Aliasing`] invariant which is either [`Shared`] or [`Exclusive`]. + /// + /// # Safety + /// + /// Given `A: Reference`, callers may assume that either `A = Shared` or `A + /// = Exclusive`. + pub trait Reference: Aliasing + Sealed {} + + /// No requirement - any invariant is allowed. + pub enum Any {} + impl Aliasing for Any { + const IS_EXCLUSIVE: bool = false; + } + impl Alignment for Any {} + impl Validity for Any {} - $(#[$elem_attr])* - impl $set for $elem { - const NAME: &'static str = stringify!($elem); - } - )* - )* + /// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a T`. + /// + /// The referent of a shared-aliased `Ptr` may be concurrently referenced by + /// any number of shared-aliased `Ptr` or `&T` references, and may not be + /// concurrently referenced by any exclusively-aliased `Ptr`s or `&mut T` + /// references. The referent must not be mutated, except via + /// [`UnsafeCell`]s. + /// + /// [`UnsafeCell`]: core::cell::UnsafeCell + pub enum Shared {} + impl Aliasing for Shared { + const IS_EXCLUSIVE: bool = false; + } + impl Reference for Shared {} - $($( - impl AtLeast for $elem {} - impl AtLeast<$elem> for $elem {} + /// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a mut T`. + /// + /// The referent of an exclusively-aliased `Ptr` may not be concurrently + /// referenced by any other `Ptr`s or references, and may not be accessed + /// (read or written) other than via this `Ptr`. + pub enum Exclusive {} + impl Aliasing for Exclusive { + const IS_EXCLUSIVE: bool = true; + } + impl Reference for Exclusive {} - $($(impl AtLeast<$elem> for $stronger_elem {})*)? - )*)* - }; -} + /// The referent is aligned: for `Ptr`, the referent's address is a + /// multiple of the `T`'s alignment. + pub enum Aligned {} + impl Alignment for Aligned {} -/// The parameterized invariants of a [`Ptr`]. -/// -/// Invariants are encoded as ([`Aliasing`], [`Alignment`], [`Validity`]) -/// triples implementing the [`Invariants`] trait. -#[doc(hidden)] -pub mod invariant { - define_system! { - /// The invariants of a [`Ptr`][super::Ptr]. - Invariants { - /// The aliasing invariant of a [`Ptr`][super::Ptr]. - Aliasing { - /// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a T`. - /// - /// The referent of a shared-aliased `Ptr` may be concurrently - /// referenced by any number of shared-aliased `Ptr` or `&T` - /// references, and may not be concurrently referenced by any - /// exclusively-aliased `Ptr`s or `&mut T` references. The - /// referent must not be mutated, except via [`UnsafeCell`]s. - /// - /// [`UnsafeCell`]: core::cell::UnsafeCell - Shared < Exclusive, - - /// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a mut - /// T`. - /// - /// The referent of an exclusively-aliased `Ptr` may not be - /// concurrently referenced by any other `Ptr`s or references, - /// and may not be accessed (read or written) other than via - /// this `Ptr`. - Exclusive, - } + /// The byte ranges initialized in `T` are also initialized in the referent. + /// + /// Formally: uninitialized bytes may only be present in `Ptr`'s referent + /// where they are guaranteed to be present in `T`. This is a dynamic + /// property: if, at a particular byte offset, a valid enum discriminant is + /// set, the subsequent bytes may only have uninitialized bytes as + /// specificed by the corresponding enum. + /// + /// Formally, given `len = size_of_val_raw(ptr)`, at every byte offset, `b`, + /// in the range `[0, len)`: + /// - If, in any instance `t: T` of length `len`, the byte at offset `b` in + /// `t` is initialized, then the byte at offset `b` within `*ptr` must be + /// initialized. + /// - Let `c` be the contents of the byte range `[0, b)` in `*ptr`. Let `S` + /// be the subset of valid instances of `T` of length `len` which contain + /// `c` in the offset range `[0, b)`. If, in any instance of `t: T` in + /// `S`, the byte at offset `b` in `t` is initialized, then the byte at + /// offset `b` in `*ptr` must be initialized. + /// + /// Pragmatically, this means that if `*ptr` is guaranteed to contain an + /// enum type at a particular offset, and the enum discriminant stored in + /// `*ptr` corresponds to a valid variant of that enum type, then it is + /// guaranteed that the appropriate bytes of `*ptr` are initialized as + /// defined by that variant's bit validity (although note that the variant + /// may contain another enum type, in which case the same rules apply + /// depending on the state of its discriminant, and so on recursively). + pub enum AsInitialized {} + impl Validity for AsInitialized {} + + /// The byte ranges in the referent are fully initialized. In other words, + /// if the referent is `N` bytes long, then it contains a bit-valid `[u8; + /// N]`. + pub enum Initialized {} + impl Validity for Initialized {} + + /// The referent is bit-valid for `T`. + pub enum Valid {} + impl Validity for Valid {} + + use sealed::Sealed; + mod sealed { + use super::*; - /// The alignment invariant of a [`Ptr`][super::Ptr]. - Alignment { - /// The referent is aligned: for `Ptr`, the referent's - /// address is a multiple of the `T`'s alignment. - Aligned, - } + pub trait Sealed {} - /// The validity invariant of a [`Ptr`][super::Ptr]. - Validity { - /// The byte ranges initialized in `T` are also initialized in - /// the referent. - /// - /// Formally: uninitialized bytes may only be present in - /// `Ptr`'s referent where they are guaranteed to be present - /// in `T`. This is a dynamic property: if, at a particular byte - /// offset, a valid enum discriminant is set, the subsequent - /// bytes may only have uninitialized bytes as specificed by the - /// corresponding enum. - /// - /// Formally, given `len = size_of_val_raw(ptr)`, at every byte - /// offset, `b`, in the range `[0, len)`: - /// - If, in any instance `t: T` of length `len`, the byte at - /// offset `b` in `t` is initialized, then the byte at offset - /// `b` within `*ptr` must be initialized. - /// - Let `c` be the contents of the byte range `[0, b)` in - /// `*ptr`. Let `S` be the subset of valid instances of `T` of - /// length `len` which contain `c` in the offset range `[0, - /// b)`. If, in any instance of `t: T` in `S`, the byte at - /// offset `b` in `t` is initialized, then the byte at offset - /// `b` in `*ptr` must be initialized. - /// - /// Pragmatically, this means that if `*ptr` is guaranteed to - /// contain an enum type at a particular offset, and the enum - /// discriminant stored in `*ptr` corresponds to a valid - /// variant of that enum type, then it is guaranteed that the - /// appropriate bytes of `*ptr` are initialized as defined by - /// that variant's bit validity (although note that the - /// variant may contain another enum type, in which case the - /// same rules apply depending on the state of its - /// discriminant, and so on recursively). - AsInitialized < Initialized | Valid, - - /// The byte ranges in the referent are fully initialized. In - /// other words, if the referent is `N` bytes long, then it - /// contains a bit-valid `[u8; N]`. - Initialized, - - /// The referent is bit-valid for `T`. - Valid, - } - } + impl Sealed for Any {} + + impl Sealed for Shared {} + impl Sealed for Exclusive {} + + impl Sealed for Aligned {} + + impl Sealed for AsInitialized {} + impl Sealed for Initialized {} + impl Sealed for Valid {} + + impl Sealed for (A, AA, V) {} } } @@ -308,27 +269,23 @@ mod _external { use super::*; use core::fmt::{Debug, Formatter}; - /// SAFETY: Shared pointers are safely `Copy`. We do not implement `Copy` - /// for exclusive pointers, since at most one may exist at a time. `Ptr`'s - /// other invariants are unaffected by the number of references that exist + /// SAFETY: Shared pointers are safely `Copy`. `Ptr`'s other invariants + /// (besides aliasing) are unaffected by the number of references that exist /// to `Ptr`'s referent. impl<'a, T, I> Copy for Ptr<'a, T, I> where T: 'a + ?Sized, - I: Invariants, - Shared: AtLeast, + I: Invariants, { } - /// SAFETY: Shared pointers are safely `Clone`. We do not implement `Clone` - /// for exclusive pointers, since at most one may exist at a time. `Ptr`'s - /// other invariants are unaffected by the number of references that exist + /// SAFETY: Shared pointers are safely `Clone`. `Ptr`'s other invariants + /// (besides aliasing) are unaffected by the number of references that exist /// to `Ptr`'s referent. impl<'a, T, I> Clone for Ptr<'a, T, I> where T: 'a + ?Sized, - I: Invariants, - Shared: AtLeast, + I: Invariants, { #[inline] fn clone(&self) -> Self { @@ -428,7 +385,7 @@ mod _conversions { where T: 'a + ?Sized, I: Invariants, - I::Aliasing: AtLeast, + I::Aliasing: Reference, { /// Converts `self` to a shared reference. // This consumes `self`, not `&self`, because `self` is, logically, a @@ -459,10 +416,10 @@ mod _conversions { // `Valid`. // // 4. You must enforce Rust’s aliasing rules. This is ensured by - // contract on `Ptr`, because the `I::Aliasing` is - // `AtLeast`. Either it is `Shared` or `Exclusive`. If it - // is `Shared`, other references may not mutate the referent - // outside of `UnsafeCell`s. + // contract on `Ptr`, because the `I::Aliasing: Reference`. + // Either it is `Shared` or `Exclusive`. If it is `Shared`, other + // references may not mutate the referent outside of + // `UnsafeCell`s. // // [1]: https://doc.rust-lang.org/std/ptr/struct.NonNull.html#method.as_ref // [2]: https://doc.rust-lang.org/std/ptr/index.html#safety @@ -474,7 +431,7 @@ mod _conversions { where T: 'a + ?Sized, I: Invariants, - I::Aliasing: AtLeast, + I::Aliasing: Reference, { /// Reborrows `self`, producing another `Ptr`. /// @@ -507,7 +464,7 @@ mod _conversions { // 8. `ptr` conforms to the validity invariant of // [`I::Validity`](invariant::Validity). // - // For aliasing (6 above), since `I::Aliasing: AtLeast`, + // For aliasing (6 above), since `I::Aliasing: Reference`, // there are two cases for `I::Aliasing`: // - For `invariant::Shared`: `'a` outlives `'b`, and so the // returned `Ptr` does not permit accessing the referent any @@ -666,48 +623,29 @@ mod _transitions { pub(crate) fn into_exclusive_or_post_monomorphization_error( self, ) -> Ptr<'a, T, (Exclusive, I::Alignment, I::Validity)> { + // NOTE(https://github.com/rust-lang/rust/issues/131625): We do this + // rather than just having `Aliasing::IS_EXCLUSIVE` have the panic + // behavior because doing it that way causes rustdoc to fail while + // attempting to document hidden items (since it evaluates the + // constant - and thus panics). trait AliasingExt: Aliasing { - const IS_EXCLUSIVE: bool; + const IS_EXCL: bool; } impl AliasingExt for A { - const IS_EXCLUSIVE: bool = { - let is_exclusive = - strs_are_equal(::NAME, ::NAME); - assert!(is_exclusive); + const IS_EXCL: bool = { + assert!(Self::IS_EXCLUSIVE); true }; } - const fn strs_are_equal(s: &str, t: &str) -> bool { - if s.len() != t.len() { - return false; - } - - let s = s.as_bytes(); - let t = t.as_bytes(); - - let mut i = 0; - #[allow(clippy::arithmetic_side_effects)] - while i < s.len() { - #[allow(clippy::indexing_slicing)] - if s[i] != t[i] { - return false; - } - - i += 1; - } - - true - } - - assert!(I::Aliasing::IS_EXCLUSIVE); + assert!(I::Aliasing::IS_EXCL); // SAFETY: We've confirmed that `self` already has the aliasing // `Exclusive`. If it didn't, either the preceding assert would fail - // or evaluating `I::Aliasing::IS_EXCLUSIVE` would fail. We're - // *pretty* sure that it's guaranteed to fail const eval, but the - // `assert!` provides a backstop in case that doesn't work. + // or evaluating `I::Aliasing::IS_EXCL` would fail. We're *pretty* + // sure that it's guaranteed to fail const eval, but the `assert!` + // provides a backstop in case that doesn't work. unsafe { self.assume_exclusive() } } @@ -900,7 +838,7 @@ mod _transitions { ) -> Result, ValidityError> where T: TryFromBytes, - I::Aliasing: AtLeast, + I::Aliasing: Reference, I: Invariants, { // This call may panic. If that happens, it doesn't cause any soundness @@ -915,19 +853,6 @@ mod _transitions { } } - /// Forgets that `self`'s referent exclusively references `T`, - /// downgrading to a shared reference. - #[doc(hidden)] - #[must_use] - #[inline] - pub const fn forget_exclusive(self) -> Ptr<'a, T, (Shared, I::Alignment, I::Validity)> - where - I::Aliasing: AtLeast, - { - // SAFETY: `I::Aliasing` is at least as restrictive as `Shared`. - unsafe { self.assume_invariants() } - } - /// Forgets that `self`'s referent is validly-aligned for `T`. #[doc(hidden)] #[must_use] @@ -1174,6 +1099,7 @@ mod _casts { > where R: AliasingSafeReason, + I::Aliasing: Reference, U: 'a + ?Sized + KnownLayout + AliasingSafe<[u8], I::Aliasing, R>, { let layout = match meta { @@ -1292,6 +1218,7 @@ mod _casts { meta: Option, ) -> Result, CastError> where + I::Aliasing: Reference, U: 'a + ?Sized + KnownLayout + AliasingSafe<[u8], I::Aliasing, R>, R: AliasingSafeReason, { @@ -1444,7 +1371,14 @@ mod _project { pub(crate) fn len(&self) -> usize { self.trailing_slice_len() } + } + impl<'a, T, I> Ptr<'a, [T], I> + where + T: 'a, + I: Invariants, + I::Aliasing: Reference, + { /// Creates a pointer which addresses the given `range` of self. /// /// # Safety @@ -1518,8 +1452,13 @@ mod _project { /// /// The caller promises that `l_len <= self.len()`. pub(crate) unsafe fn split_at(self, l_len: usize) -> (Self, Self) { - // SAFETY: `Any` imposes no invariants, and so this is always sound. - let slf = unsafe { self.assume_aliasing::() }; + // SAFETY: TODO(#1890): This is explicitly unsound! It's sound + // *given how `slice_unchecked` is implemented*, and it's sound + // *given what we do with `slf` in this method body*, but it's + // unsound in the general case. We do it temporarily as part of + // broader `Ptr` changes, but it must be fixed before releasing a + // stable zerocopy version. + let slf = unsafe { self.assume_aliasing::() }; // SAFETY: The caller promises that `l_len <= self.len()`. // Trivially, `0 <= l_len`. @@ -1641,8 +1580,6 @@ mod _project { mod tests { use core::mem::{self, MaybeUninit}; - use static_assertions::{assert_impl_all, assert_not_impl_any}; - use super::*; use crate::{pointer::BecauseImmutable, util::testutil::AU64, FromBytes, Immutable}; @@ -1834,21 +1771,6 @@ mod tests { test!(f32, f64); } - #[test] - fn test_invariants() { - // Test that the correct invariant relationships hold. - use super::invariant::*; - - assert_not_impl_any!(Any: AtLeast); - assert_impl_all!(Shared: AtLeast); - assert_impl_all!(Exclusive: AtLeast); - - assert_not_impl_any!(Any: AtLeast); - assert_impl_all!(AsInitialized: AtLeast); - assert_impl_all!(Initialized: AtLeast); - assert_impl_all!(Valid: AtLeast); - } - #[test] fn test_try_cast_into_explicit_count() { macro_rules! test { diff --git a/src/util/macro_util.rs b/src/util/macro_util.rs index 734ff50759..b94e82c573 100644 --- a/src/util/macro_util.rs +++ b/src/util/macro_util.rs @@ -26,7 +26,7 @@ use core::ptr::{self, NonNull}; use crate::{ pointer::{ - invariant::{self, AtLeast, Invariants}, + invariant::{self, Invariants}, AliasingSafe, AliasingSafeReason, BecauseExclusive, BecauseImmutable, }, Immutable, IntoBytes, Ptr, TryFromBytes, Unalign, ValidityError, @@ -530,7 +530,7 @@ where Src: IntoBytes, Dst: TryFromBytes + AliasingSafe, I: Invariants, - I::Aliasing: AtLeast, + I::Aliasing: invariant::Reference, R: AliasingSafeReason, { static_assert!(Src, Dst => mem::size_of::() == mem::size_of::()); diff --git a/src/util/macros.rs b/src/util/macros.rs index 4626e0d3c4..32fd7dd69a 100644 --- a/src/util/macros.rs +++ b/src/util/macros.rs @@ -141,7 +141,7 @@ macro_rules! unsafe_impl { fn only_derive_is_allowed_to_implement_this_trait() {} #[inline] - fn is_bit_valid>(candidate: Maybe<'_, Self, AA>) -> bool { + fn is_bit_valid(candidate: Maybe<'_, Self, AA>) -> bool { // SAFETY: // - The cast preserves address. The caller has promised that the // cast results in an object of equal or lesser size, and so the @@ -165,7 +165,7 @@ macro_rules! unsafe_impl { fn only_derive_is_allowed_to_implement_this_trait() {} #[inline] - fn is_bit_valid>(candidate: Maybe<'_, Self, AA>) -> bool { + fn is_bit_valid(candidate: Maybe<'_, Self, AA>) -> bool { // SAFETY: // - The cast preserves address. The caller has promised that the // cast results in an object of equal or lesser size, and so the @@ -189,7 +189,7 @@ macro_rules! unsafe_impl { #[allow(clippy::missing_inline_in_public_items)] #[cfg_attr(coverage_nightly, coverage(off))] fn only_derive_is_allowed_to_implement_this_trait() {} - #[inline(always)] fn is_bit_valid>(_: Maybe<'_, Self, A>) -> bool { true } + #[inline(always)] fn is_bit_valid(_: Maybe<'_, Self, AA>) -> bool { true } }; (@method $trait:ident) => { #[allow(clippy::missing_inline_in_public_items)] @@ -341,7 +341,7 @@ macro_rules! impl_for_transparent_wrapper { // TryFromBytes)` macro arm for an explanation of why this is a sound // implementation of `is_bit_valid`. #[inline] - fn is_bit_valid>(candidate: Maybe<'_, Self, A>) -> bool { + fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool { TryFromBytes::is_bit_valid(candidate.transparent_wrapper_into_inner()) } }; diff --git a/zerocopy-derive/src/enum.rs b/zerocopy-derive/src/enum.rs index df531ea00d..9ac24d9432 100644 --- a/zerocopy-derive/src/enum.rs +++ b/zerocopy-derive/src/enum.rs @@ -286,8 +286,7 @@ pub(crate) fn derive_is_bit_valid( mut candidate: ::zerocopy::Maybe<'_, Self, ___ZerocopyAliasing>, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { use ::zerocopy::util::macro_util::core_reexport; diff --git a/zerocopy-derive/src/lib.rs b/zerocopy-derive/src/lib.rs index e2318c53b4..959f7bbf5b 100644 --- a/zerocopy-derive/src/lib.rs +++ b/zerocopy-derive/src/lib.rs @@ -422,8 +422,7 @@ fn derive_try_from_bytes_struct( mut candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { true #(&& { // SAFETY: @@ -480,8 +479,7 @@ fn derive_try_from_bytes_union( mut candidate: ::zerocopy::Maybe<'_, Self, ___ZerocopyAliasing> ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { false #(|| { // SAFETY: @@ -574,8 +572,7 @@ fn try_gen_trivial_is_bit_valid( _candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { if false { fn assert_is_from_bytes() @@ -618,8 +615,7 @@ unsafe fn gen_trivial_is_bit_valid_unchecked() -> proc_macro2::TokenStream { _candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { true } diff --git a/zerocopy-derive/src/output_tests.rs b/zerocopy-derive/src/output_tests.rs index 32377e5ea3..ebeab2fdc7 100644 --- a/zerocopy-derive/src/output_tests.rs +++ b/zerocopy-derive/src/output_tests.rs @@ -155,8 +155,7 @@ fn test_try_from_bytes() { mut candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { true } @@ -179,8 +178,7 @@ fn test_from_zeros() { mut candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { true } @@ -208,8 +206,7 @@ fn test_from_bytes_struct() { _candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { if false { fn assert_is_from_bytes() @@ -256,8 +253,7 @@ fn test_from_bytes_union() { _candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { if false { fn assert_is_from_bytes() @@ -377,8 +373,7 @@ fn test_try_from_bytes_enum() { mut candidate: ::zerocopy::Maybe<'_, Self, ___ZerocopyAliasing>, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { use ::zerocopy::util::macro_util::core_reexport; #[repr(u8)] @@ -434,8 +429,7 @@ fn test_try_from_bytes_enum() { mut candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { true && { let field_candidate = unsafe { @@ -528,8 +522,7 @@ fn test_try_from_bytes_enum() { mut candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { true && { let field_candidate = unsafe { @@ -671,8 +664,7 @@ fn test_try_from_bytes_enum() { mut candidate: ::zerocopy::Maybe<'_, Self, ___ZerocopyAliasing>, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { use ::zerocopy::util::macro_util::core_reexport; #[repr(u32)] @@ -728,8 +720,7 @@ fn test_try_from_bytes_enum() { mut candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { true && { let field_candidate = unsafe { @@ -822,8 +813,7 @@ fn test_try_from_bytes_enum() { mut candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { true && { let field_candidate = unsafe { @@ -965,8 +955,7 @@ fn test_try_from_bytes_enum() { mut candidate: ::zerocopy::Maybe<'_, Self, ___ZerocopyAliasing>, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { use ::zerocopy::util::macro_util::core_reexport; #[repr(C)] @@ -1022,8 +1011,7 @@ fn test_try_from_bytes_enum() { mut candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { true && { let field_candidate = unsafe { @@ -1116,8 +1104,7 @@ fn test_try_from_bytes_enum() { mut candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { true && { let field_candidate = unsafe { @@ -1503,8 +1490,7 @@ fn test_from_bytes_enum() { _candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { if false { fn assert_is_from_bytes() @@ -1808,8 +1794,7 @@ fn test_try_from_bytes_trivial_is_bit_valid_enum() { _candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Aliasing - + ::zerocopy::pointer::invariant::AtLeast<::zerocopy::pointer::invariant::Shared>, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { true } From 967b3a09c5998884c25ed121f88d0373d3d2ead4 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Mon, 14 Oct 2024 07:48:02 -0700 Subject: [PATCH 13/96] [derive] Document trivial_is_bit_valid (#1905) Explain why we only support concrete types so that future authors won't spuriously add support for them. --- zerocopy-derive/src/lib.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/zerocopy-derive/src/lib.rs b/zerocopy-derive/src/lib.rs index 959f7bbf5b..45c2de5d67 100644 --- a/zerocopy-derive/src/lib.rs +++ b/zerocopy-derive/src/lib.rs @@ -551,6 +551,22 @@ fn derive_try_from_bytes_enum( /// Attempts to generate a `TryFromBytes::is_bit_valid` instance that /// unconditionally returns true. /// +/// This is possible when the `top_level` trait is `FromBytes` and there are no +/// generic type parameters. In this case, we know that compilation will succeed +/// only if the type is unconditionally `FromBytes`. Type parameters are not +/// supported because a type with type parameters could be `TryFromBytes` but +/// not `FromBytes` depending on its type parameters, and so deriving a trivial +/// `is_bit_valid` would be either unsound or, assuming we add a defensive +/// `Self: FromBytes` bound (as we currently do), overly restrictive. Consider, +/// for example, that `Foo` ought to be `TryFromBytes` but not `FromBytes` +/// in this example: +/// +/// ```rust,ignore +/// #[derive(FromBytes)] +/// #[repr(transparent)] +/// struct Foo(T); +/// ``` +/// /// This should be used where possible. Using this impl is faster to codegen, /// faster to compile, and is friendlier on the optimizer. fn try_gen_trivial_is_bit_valid( From b43c5103e4e88e4d9264b2ac56ca0adb78f20100 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Mon, 14 Oct 2024 10:18:23 -0700 Subject: [PATCH 14/96] [pointer] Add separate PtrInner (#1891) `PtrInner` carries all invariants which are not controlled by type parameters. Since `PtrInner` does not promise to uphold aliasing, alignment, or validity, we can move some utility methods to `PtrInner` which previously were responsible for maintaining invariants orthogonal to their purpose. Makes progress on #1892 (still needs to be fixed on v0.8.x) Closes #1890 --- src/impls.rs | 26 +- src/lib.rs | 4 +- src/pointer/inner.rs | 541 +++++++++++++++++++++++++ src/pointer/mod.rs | 16 +- src/pointer/ptr.rs | 606 ++++++---------------------- zerocopy-derive/src/enum.rs | 2 +- zerocopy-derive/src/output_tests.rs | 6 +- 7 files changed, 698 insertions(+), 503 deletions(-) create mode 100644 src/pointer/inner.rs diff --git a/src/impls.rs b/src/impls.rs index b082c30b21..0c84a115f1 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -180,7 +180,7 @@ safety_comment! { /// /// [4] TODO(#429): Justify this claim. unsafe_impl!(char: TryFromBytes; |candidate: MaybeAligned| { - let candidate = candidate.read_unaligned(); + let candidate = candidate.read_unaligned::(); char::from_u32(candidate).is_some() }); } @@ -310,18 +310,18 @@ safety_comment! { /// /// [2] `NonZeroXxx` self-evidently does not contain `UnsafeCell`s. This is /// not a proof, but we are accepting this as a known risk per #1358. - unsafe_impl!(NonZeroU8: TryFromBytes; |n: MaybeAligned| NonZeroU8::new(n.read_unaligned()).is_some()); - unsafe_impl!(NonZeroI8: TryFromBytes; |n: MaybeAligned| NonZeroI8::new(n.read_unaligned()).is_some()); - unsafe_impl!(NonZeroU16: TryFromBytes; |n: MaybeAligned| NonZeroU16::new(n.read_unaligned()).is_some()); - unsafe_impl!(NonZeroI16: TryFromBytes; |n: MaybeAligned| NonZeroI16::new(n.read_unaligned()).is_some()); - unsafe_impl!(NonZeroU32: TryFromBytes; |n: MaybeAligned| NonZeroU32::new(n.read_unaligned()).is_some()); - unsafe_impl!(NonZeroI32: TryFromBytes; |n: MaybeAligned| NonZeroI32::new(n.read_unaligned()).is_some()); - unsafe_impl!(NonZeroU64: TryFromBytes; |n: MaybeAligned| NonZeroU64::new(n.read_unaligned()).is_some()); - unsafe_impl!(NonZeroI64: TryFromBytes; |n: MaybeAligned| NonZeroI64::new(n.read_unaligned()).is_some()); - unsafe_impl!(NonZeroU128: TryFromBytes; |n: MaybeAligned| NonZeroU128::new(n.read_unaligned()).is_some()); - unsafe_impl!(NonZeroI128: TryFromBytes; |n: MaybeAligned| NonZeroI128::new(n.read_unaligned()).is_some()); - unsafe_impl!(NonZeroUsize: TryFromBytes; |n: MaybeAligned| NonZeroUsize::new(n.read_unaligned()).is_some()); - unsafe_impl!(NonZeroIsize: TryFromBytes; |n: MaybeAligned| NonZeroIsize::new(n.read_unaligned()).is_some()); + unsafe_impl!(NonZeroU8: TryFromBytes; |n: MaybeAligned| NonZeroU8::new(n.read_unaligned::()).is_some()); + unsafe_impl!(NonZeroI8: TryFromBytes; |n: MaybeAligned| NonZeroI8::new(n.read_unaligned::()).is_some()); + unsafe_impl!(NonZeroU16: TryFromBytes; |n: MaybeAligned| NonZeroU16::new(n.read_unaligned::()).is_some()); + unsafe_impl!(NonZeroI16: TryFromBytes; |n: MaybeAligned| NonZeroI16::new(n.read_unaligned::()).is_some()); + unsafe_impl!(NonZeroU32: TryFromBytes; |n: MaybeAligned| NonZeroU32::new(n.read_unaligned::()).is_some()); + unsafe_impl!(NonZeroI32: TryFromBytes; |n: MaybeAligned| NonZeroI32::new(n.read_unaligned::()).is_some()); + unsafe_impl!(NonZeroU64: TryFromBytes; |n: MaybeAligned| NonZeroU64::new(n.read_unaligned::()).is_some()); + unsafe_impl!(NonZeroI64: TryFromBytes; |n: MaybeAligned| NonZeroI64::new(n.read_unaligned::()).is_some()); + unsafe_impl!(NonZeroU128: TryFromBytes; |n: MaybeAligned| NonZeroU128::new(n.read_unaligned::()).is_some()); + unsafe_impl!(NonZeroI128: TryFromBytes; |n: MaybeAligned| NonZeroI128::new(n.read_unaligned::()).is_some()); + unsafe_impl!(NonZeroUsize: TryFromBytes; |n: MaybeAligned| NonZeroUsize::new(n.read_unaligned::()).is_some()); + unsafe_impl!(NonZeroIsize: TryFromBytes; |n: MaybeAligned| NonZeroIsize::new(n.read_unaligned::()).is_some()); } safety_comment! { /// SAFETY: diff --git a/src/lib.rs b/src/lib.rs index 3b79c8c900..c939c1db6a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -360,7 +360,7 @@ use core::{ slice, }; -use crate::pointer::{invariant, BecauseExclusive, BecauseImmutable}; +use crate::pointer::{invariant, BecauseExclusive}; #[cfg(any(feature = "alloc", test))] extern crate alloc; @@ -372,7 +372,7 @@ use core::alloc::Layout; // Used by `TryFromBytes::is_bit_valid`. #[doc(hidden)] -pub use crate::pointer::{Maybe, MaybeAligned, Ptr}; +pub use crate::pointer::{BecauseImmutable, Maybe, MaybeAligned, Ptr}; // Used by `KnownLayout`. #[doc(hidden)] pub use crate::layout::*; diff --git a/src/pointer/inner.rs b/src/pointer/inner.rs new file mode 100644 index 0000000000..48d4e8f113 --- /dev/null +++ b/src/pointer/inner.rs @@ -0,0 +1,541 @@ +// Copyright 2024 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +use core::{marker::PhantomData, ops::Range, ptr::NonNull}; + +#[allow(unused_imports)] +use crate::util::polyfills::NumExt as _; +use crate::{ + layout::{CastType, DstLayout, MetadataCastError}, + util::AsAddress, + AlignmentError, CastError, KnownLayout, PointerMetadata, SizeError, +}; + +pub(crate) use _def::PtrInner; + +mod _def { + use super::*; + /// The inner pointer stored inside a [`Ptr`][crate::Ptr]. + /// + /// `Ptr<'a, T>` is [covariant] in `'a` and `T`. + /// + /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html + pub(crate) struct PtrInner<'a, T> + where + T: ?Sized, + { + /// # Invariants + /// + /// 0. If `ptr`'s referent is not zero sized, then `ptr` is derived from + /// some valid Rust allocation, `A`. + /// 1. If `ptr`'s referent is not zero sized, then `ptr` has valid + /// provenance for `A`. + /// 2. If `ptr`'s referent is not zero sized, then `ptr` addresses a + /// byte range which is entirely contained in `A`. + /// 3. `ptr` addresses a byte range whose length fits in an `isize`. + /// 4. `ptr` addresses a byte range which does not wrap around the + /// address space. + /// 5. If `ptr`'s referent is not zero sized,`A` is guaranteed to live + /// for at least `'a`. + // SAFETY: `NonNull` is covariant over `T` [1]. + // + // [1]: https://doc.rust-lang.org/std/ptr/struct.NonNull.html + ptr: NonNull, + // SAFETY: `&'a T` is covariant over `'a` [1]. + // + // [1] https://doc.rust-lang.org/1.81.0/reference/subtyping.html#variance + _marker: PhantomData<&'a T>, + } + + impl<'a, T: 'a + ?Sized> Copy for PtrInner<'a, T> {} + impl<'a, T: 'a + ?Sized> Clone for PtrInner<'a, T> { + fn clone(&self) -> PtrInner<'a, T> { + // SAFETY: None of the invariants on `ptr` are affected by having + // multiple copies of a `PtrInner`. + *self + } + } + + impl<'a, T: 'a + ?Sized> PtrInner<'a, T> { + /// Constructs a `Ptr` from a [`NonNull`]. + /// + /// # Safety + /// + /// The caller promises that: + /// + /// 0. If `ptr`'s referent is not zero sized, then `ptr` is derived from + /// some valid Rust allocation, `A`. + /// 1. If `ptr`'s referent is not zero sized, then `ptr` has valid + /// provenance for `A`. + /// 2. If `ptr`'s referent is not zero sized, then `ptr` addresses a + /// byte range which is entirely contained in `A`. + /// 3. `ptr` addresses a byte range whose length fits in an `isize`. + /// 4. `ptr` addresses a byte range which does not wrap around the + /// address space. + /// 5. If `ptr`'s referent is not zero sized, then `A` is guaranteed to + /// live for at least `'a`. + pub(crate) const unsafe fn new(ptr: NonNull) -> PtrInner<'a, T> { + // SAFETY: The caller has promised to satisfy all safety invariants + // of `PtrInner`. + Self { ptr, _marker: PhantomData } + } + + /// Converts this `PtrInner` to a [`NonNull`]. + /// + /// Note that this method does not consume `self`. The caller should + /// watch out for `unsafe` code which uses the returned `NonNull` in a + /// way that violates the safety invariants of `self`. + pub(crate) const fn as_non_null(&self) -> NonNull { + self.ptr + } + } +} + +impl<'a, T: ?Sized> PtrInner<'a, T> { + /// Constructs a `PtrInner` from a reference. + #[inline] + pub(crate) fn from_ref(ptr: &'a T) -> Self { + let ptr = NonNull::from(ptr); + // SAFETY: + // 0. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on + // `&'a T`, is derived from some valid Rust allocation, `A`. + // 1. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on + // `&'a T`, has valid provenance for `A`. + // 2. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on + // `&'a T`, addresses a byte range which is entirely contained in + // `A`. + // 3. `ptr`, by invariant on `&'a T`, addresses a byte range whose + // length fits in an `isize`. + // 4. `ptr`, by invariant on `&'a T`, addresses a byte range which does + // not wrap around the address space. + // 5. If `ptr`'s referent is not zero sized, then `A`, by invariant on + // `&'a T`, is guaranteed to live for at least `'a`. + unsafe { Self::new(ptr) } + } + + /// Constructs a `PtrInner` from a mutable reference. + #[inline] + pub(crate) fn from_mut(ptr: &'a mut T) -> Self { + let ptr = NonNull::from(ptr); + // SAFETY: + // 0. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on + // `&'a mut T`, is derived from some valid Rust allocation, `A`. + // 1. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on + // `&'a mut T`, has valid provenance for `A`. + // 2. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on + // `&'a mut T`, addresses a byte range which is entirely contained in + // `A`. + // 3. `ptr`, by invariant on `&'a mut T`, addresses a byte range whose + // length fits in an `isize`. + // 4. `ptr`, by invariant on `&'a mut T`, addresses a byte range which + // does not wrap around the address space. + // 5. If `ptr`'s referent is not zero sized, then `A`, by invariant on + // `&'a mut T`, is guaranteed to live for at least `'a`. + unsafe { Self::new(ptr) } + } +} + +#[allow(clippy::needless_lifetimes)] +impl<'a, T> PtrInner<'a, [T]> { + /// Creates a pointer which addresses the given `range` of self. + /// + /// # Safety + /// + /// `range` is a valid range (`start <= end`) and `end <= self.len()`. + pub(crate) unsafe fn slice_unchecked(self, range: Range) -> Self { + let base = self.as_non_null().cast::().as_ptr(); + + // SAFETY: The caller promises that `start <= end <= self.len()`. By + // invariant, if `self`'s referent is not zero-sized, then `self` refers + // to a byte range which is contained within a single allocation, which + // is no more than `isize::MAX` bytes long, and which does not wrap + // around the address space. Thus, this pointer arithmetic remains + // in-bounds of the same allocation, and does not wrap around the + // address space. The offset (in bytes) does not overflow `isize`. + // + // If `self`'s referent is zero-sized, then these conditions are + // trivially satisfied. + let base = unsafe { base.add(range.start) }; + + // SAFETY: The caller promises that `start <= end`, and so this will not + // underflow. + #[allow(unstable_name_collisions, clippy::incompatible_msrv)] + let len = unsafe { range.end.unchecked_sub(range.start) }; + + let ptr = core::ptr::slice_from_raw_parts_mut(base, len); + + // SAFETY: By invariant, `self`'s address is non-null and its range does + // not wrap around the address space. Since, by the preceding lemma, + // `ptr` addresses a range within that addressed by `self`, `ptr` is + // non-null. + let ptr = unsafe { NonNull::new_unchecked(ptr) }; + + // SAFETY: + // + // Lemma 0: `ptr` addresses a subset of the bytes addressed by `self`, + // and has the same provenance. Proof: The caller guarantees + // that `start <= end <= self.len()`. Thus, `base` is in-bounds of + // `self`, and `base + (end - start)` is also in-bounds of self. + // Finally, `ptr` is constructed using provenance-preserving + // operations. + // + // 0. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not + // zero sized, then `ptr` is derived from some valid Rust allocation, + // `A`. + // 1. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not + // zero sized, then `ptr` has valid provenance for `A`. + // 2. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not + // zero sized, then `ptr` addresses a byte range which is entirely + // contained in `A`. + // 3. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte + // range whose length fits in an `isize`. + // 4. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte + // range which does not wrap around the address space. + // 5. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not + // zero sized, then `A` is guaranteed to live for at least `'a`. + unsafe { PtrInner::new(ptr) } + } + + /// Splits the slice in two. + /// + /// # Safety + /// + /// The caller promises that `l_len <= self.len()`. + /// + /// Given `let (left, right) = ptr.split_at(l_len)`, it is guaranteed + /// that `left` and `right` are contiguous and non-overlapping. + pub(crate) unsafe fn split_at(self, l_len: usize) -> (Self, Self) { + // SAFETY: The caller promises that `l_len <= self.len()`. + // Trivially, `0 <= l_len`. + let left = unsafe { self.slice_unchecked(0..l_len) }; + + // SAFETY: The caller promises that `l_len <= self.len() = + // slf.len()`. Trivially, `slf.len() <= slf.len()`. + let right = unsafe { self.slice_unchecked(l_len..self.len()) }; + + // SAFETY: `left` and `right` are non-overlapping. Proof: `left` is + // constructed from `slf` with `l_len` as its (exclusive) upper + // bound, while `right` is constructed from `slf` with `l_len` as + // its (inclusive) lower bound. Thus, no index is a member of both + // ranges. + (left, right) + } + + /// Iteratively projects the elements `PtrInner` from `PtrInner<[T]>`. + pub(crate) fn iter(&self) -> impl Iterator> { + // TODO(#429): Once `NonNull::cast` documents that it preserves + // provenance, cite those docs. + let base = self.as_non_null().cast::().as_ptr(); + (0..self.len()).map(move |i| { + // TODO(https://github.com/rust-lang/rust/issues/74265): Use + // `NonNull::get_unchecked_mut`. + + // SAFETY: If the following conditions are not satisfied + // `pointer::cast` may induce Undefined Behavior [1]: + // + // > - The computed offset, `count * size_of::()` bytes, must not + // > overflow `isize``. + // > - If the computed offset is non-zero, then `self` must be + // > derived from a pointer to some allocated object, and the + // > entire memory range between `self` and the result must be in + // > bounds of that allocated object. In particular, this range + // > must not “wrap around” the edge of the address space. + // + // [1] https://doc.rust-lang.org/std/primitive.pointer.html#method.add + // + // We satisfy both of these conditions here: + // - By invariant on `Ptr`, `self` addresses a byte range whose + // length fits in an `isize`. Since `elem` is contained in `self`, + // the computed offset of `elem` must fit within `isize.` + // - If the computed offset is non-zero, then this means that the + // referent is not zero-sized. In this case, `base` points to an + // allocated object (by invariant on `self`). Thus: + // - By contract, `self.len()` accurately reflects the number of + // elements in the slice. `i` is in bounds of `c.len()` by + // construction, and so the result of this addition cannot + // overflow past the end of the allocation referred to by `c`. + // - By invariant on `Ptr`, `self` addresses a byte range which + // does not wrap around the address space. Since `elem` is + // contained in `self`, the computed offset of `elem` must wrap + // around the address space. + // + // TODO(#429): Once `pointer::add` documents that it preserves + // provenance, cite those docs. + let elem = unsafe { base.add(i) }; + + // SAFETY: + // - `elem` must not be null. `base` is constructed from a + // `NonNull` pointer, and the addition that produces `elem` must + // not overflow or wrap around, so `elem >= base > 0`. + // + // TODO(#429): Once `NonNull::new_unchecked` documents that it + // preserves provenance, cite those docs. + let elem = unsafe { NonNull::new_unchecked(elem) }; + + // SAFETY: The safety invariants of `Ptr::new` (see definition) are + // satisfied: + // 0. If `elem`'s referent is not zero sized, then `elem` is derived + // from a valid Rust allocation, because `self` is derived from a + // valid Rust allocation, by invariant on `Ptr`. + // 1. If `elem`'s referent is not zero sized, then `elem` has valid + // provenance for `self`, because it derived from `self` using a + // series of provenance-preserving operations. + // 2. If `elem`'s referent is not zero sized, then `elem` is + // entirely contained in the allocation of `self` (see above). + // 3. `elem` addresses a byte range whose length fits in an `isize` + // (see above). + // 4. `elem` addresses a byte range which does not wrap around the + // address space (see above). + // 5. If `elem`'s referent is not zero sized, then the allocation of + // `elem` is guaranteed to live for at least `'a`, because `elem` + // is entirely contained in `self`, which lives for at least `'a` + // by invariant on `Ptr`. + unsafe { PtrInner::new(elem) } + }) + } + + /// The number of slice elements in the object referenced by `self`. + /// + /// # Safety + /// + /// Unsafe code my rely on `len` satisfying the above contract. + pub(crate) fn len(&self) -> usize { + self.trailing_slice_len() + } +} + +#[allow(clippy::needless_lifetimes)] +impl<'a, T> PtrInner<'a, T> +where + T: ?Sized + KnownLayout, +{ + /// The number of trailing slice elements in the object referenced by + /// `self`. + /// + /// # Safety + /// + /// Unsafe code my rely on `trailing_slice_len` satisfying the above + /// contract. + pub(super) fn trailing_slice_len(&self) -> usize { + T::pointer_to_metadata(self.as_non_null().as_ptr()) + } +} + +impl<'a, T, const N: usize> PtrInner<'a, [T; N]> { + /// Casts this pointer-to-array into a slice. + /// + /// # Safety + /// + /// Callers may assume that the returned `PtrInner` references the same + /// address and length as `self`. + #[allow(clippy::wrong_self_convention)] + pub(crate) fn as_slice(self) -> PtrInner<'a, [T]> { + let start = self.as_non_null().cast::().as_ptr(); + let slice = core::ptr::slice_from_raw_parts_mut(start, N); + // SAFETY: `slice` is not null, because it is derived from `start` + // which is non-null. + let slice = unsafe { NonNull::new_unchecked(slice) }; + // SAFETY: Lemma: In the following safety arguments, note that `slice` + // is derived from `self` in two steps: first, by casting `self: [T; N]` + // to `start: T`, then by constructing a pointer to a slice starting at + // `start` of length `N`. As a result, `slice` references exactly the + // same allocation as `self`, if any. + // + // 0. By the above lemma, if `slice`'s referent is not zero sized, then + // `slice` is derived from the same allocation as `self`, which, by + // invariant on `Ptr`, is valid. + // 1. By the above lemma, if `slice`'s referent is not zero sized, then + // , `slice` has valid provenance for `A`, since it is derived from + // the pointer `self`, which, by invariant on `Ptr`, has valid + // provenance for `A`. + // 2. By the above lemma, if `slice`'s referent is not zero sized, then + // `slice` addresses a byte range which is entirely contained in `A`, + // because it references exactly the same byte range as `self`, + // which, by invariant on `Ptr`, is entirely contained in `A`. + // 3. By the above lemma, `slice` addresses a byte range whose length + // fits in an `isize`, since it addresses exactly the same byte range + // as `self`, which, by invariant on `Ptr`, has a length that fits in + // an `isize`. + // 4. By the above lemma, `slice` addresses a byte range which does not + // wrap around the address space, since it addresses exactly the same + // byte range as `self`, which, by invariant on `Ptr`, does not wrap + // around the address space. + // 5. By the above lemma, if `slice`'s referent is not zero sized, then + // `A` is guaranteed to live for at least `'a`, because it is derived + // from the same allocation as `self`, which, by invariant on `Ptr`, + // lives for at least `'a`. + unsafe { PtrInner::new(slice) } + } +} + +impl<'a> PtrInner<'a, [u8]> { + /// Attempts to cast `self` to a `U` using the given cast type. + /// + /// If `U` is a slice DST and pointer metadata (`meta`) is provided, then + /// the cast will only succeed if it would produce an object with the given + /// metadata. + /// + /// Returns `None` if the resulting `U` would be invalidly-aligned, if no + /// `U` can fit in `self`, or if the provided pointer metadata describes an + /// invalid instance of `U`. On success, returns a pointer to the + /// largest-possible `U` which fits in `self`. + /// + /// # Safety + /// + /// The caller may assume that this implementation is correct, and may rely + /// on that assumption for the soundness of their code. In particular, the + /// caller may assume that, if `try_cast_into` returns `Some((ptr, + /// remainder))`, then `ptr` and `remainder` refer to non-overlapping byte + /// ranges within `self`, and that `ptr` and `remainder` entirely cover + /// `self`. Finally: + /// - If this is a prefix cast, `ptr` has the same address as `self`. + /// - If this is a suffix cast, `remainder` has the same address as `self`. + pub(crate) fn try_cast_into( + self, + cast_type: CastType, + meta: Option, + ) -> Result<(PtrInner<'a, U>, PtrInner<'a, [u8]>), CastError> + where + U: 'a + ?Sized + KnownLayout, + { + let layout = match meta { + None => U::LAYOUT, + // This can return `None` if the metadata describes an object + // which can't fit in an `isize`. + Some(meta) => { + let size = match meta.size_for_metadata(U::LAYOUT) { + Some(size) => size, + None => return Err(CastError::Size(SizeError::new(self))), + }; + DstLayout { align: U::LAYOUT.align, size_info: crate::SizeInfo::Sized { size } } + } + }; + // PANICS: By invariant, the byte range addressed by + // `self.as_non_null()` does not wrap around the address space. This + // implies that the sum of the address (represented as a `usize`) and + // length do not overflow `usize`, as required by + // `validate_cast_and_convert_metadata`. Thus, this call to + // `validate_cast_and_convert_metadata` will only panic if `U` is a DST + // whose trailing slice element is zero-sized. + let maybe_metadata = layout.validate_cast_and_convert_metadata( + AsAddress::addr(self.as_non_null().as_ptr()), + self.len(), + cast_type, + ); + + let (elems, split_at) = match maybe_metadata { + Ok((elems, split_at)) => (elems, split_at), + Err(MetadataCastError::Alignment) => { + // SAFETY: Since `validate_cast_and_convert_metadata` returned + // an alignment error, `U` must have an alignment requirement + // greater than one. + let err = unsafe { AlignmentError::<_, U>::new_unchecked(self) }; + return Err(CastError::Alignment(err)); + } + Err(MetadataCastError::Size) => return Err(CastError::Size(SizeError::new(self))), + }; + + // SAFETY: `validate_cast_and_convert_metadata` promises to return + // `split_at <= self.len()`. + let (l_slice, r_slice) = unsafe { self.split_at(split_at) }; + + let (target, remainder) = match cast_type { + CastType::Prefix => (l_slice, r_slice), + CastType::Suffix => (r_slice, l_slice), + }; + + let base = target.as_non_null().cast::(); + + let elems = ::PointerMetadata::from_elem_count(elems); + // For a slice DST type, if `meta` is `Some(elems)`, then we synthesize + // `layout` to describe a sized type whose size is equal to the size of + // the instance that we are asked to cast. For sized types, + // `validate_cast_and_convert_metadata` returns `elems == 0`. Thus, in + // this case, we need to use the `elems` passed by the caller, not the + // one returned by `validate_cast_and_convert_metadata`. + let elems = meta.unwrap_or(elems); + + let ptr = U::raw_from_ptr_len(base, elems); + + // SAFETY: + // 0. By invariant, if `target`'s referent is not zero sized, then + // `target` is derived from some valid Rust allocation, `A`. By + // contract on `cast`, `ptr` is derived from `self`, and thus from + // the same valid Rust allocation, `A`. + // 1. By invariant, if `target`'s referent is not zero sized, then + // `target` has provenance valid for some Rust allocation, `A`. + // Because `ptr` is derived from `target` via provenance-preserving + // operations, `ptr` will also have provenance valid for `A`. + // - `validate_cast_and_convert_metadata` promises that the object + // described by `elems` and `split_at` lives at a byte range which is + // a subset of the input byte range. Thus: + // 2. Since, by invariant, if `target`'s referent is not zero sized, + // then `target` addresses a byte range which is entirely + // contained in `A`, so does `ptr`. + // 3. Since, by invariant, `target` addresses a byte range whose + // length fits in an `isize`, so does `ptr`. + // 4. Since, by invariant, `target` addresses a byte range which does + // not wrap around the address space, so does `ptr`. + // 5. Since, by invariant, if `target`'s referent is not zero sized, + // then `target` refers to an allocation which is guaranteed to + // live for at least `'a`, so does `ptr`. + Ok((unsafe { PtrInner::new(ptr) }, remainder)) + } +} + +#[allow(clippy::needless_lifetimes)] +impl<'a, T> PtrInner<'a, T> { + /// Performs an unaligned read of `self`'s referent. + /// + /// # Safety + /// + /// `self` must point to a properly initialized value of type `T`, and + /// reading a copy of `T` must not violate `T`'s safety invariants. + /// + /// `self`'s referent must not be concurrently modified during this call. + pub(crate) unsafe fn read_unaligned(self) -> T { + let raw = self.as_non_null().as_ptr(); + // SAFETY: The caller promises that `self` points to a bit-valid `T` and + // that reading a copy of it won't violate `T`'s safety invariants. The + // caller promises that `self`'s referent won't be concurrently modified + // during this operation. + // + // `raw` is valid for reads: + // - `self.as_non_null()` returns a `NonNull`, which is guaranteed to be + // non-null. + // - By invariant on `PtrInner`, `raw` is is either zero-sized or: + // - ...is within bounds of a single allocated object which lives for + // at least `'a`. + // - ...has valid provenance for that object. + unsafe { core::ptr::read_unaligned(raw) } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_split_at() { + const N: usize = 16; + let arr = [1; N]; + let ptr = PtrInner::from_ref(&arr).as_slice(); + for i in 0..=N { + assert_eq!(ptr.len(), N); + // SAFETY: `i` is in bounds by construction. + let (l, r) = unsafe { ptr.split_at(i) }; + // SAFETY: Points to a valid value by construction. + let l_sum: usize = l.iter().map(|ptr| unsafe { ptr.read_unaligned() }).sum(); + // SAFETY: Points to a valid value by construction. + let r_sum: usize = r.iter().map(|ptr| unsafe { ptr.read_unaligned() }).sum(); + assert_eq!(l_sum, i); + assert_eq!(r_sum, N - i); + assert_eq!(l_sum + r_sum, N); + } + } +} diff --git a/src/pointer/mod.rs b/src/pointer/mod.rs index 0e13e59f65..dd7b162d7e 100644 --- a/src/pointer/mod.rs +++ b/src/pointer/mod.rs @@ -9,6 +9,7 @@ //! Abstractions over raw pointers. mod aliasing_safety; +mod inner; mod ptr; pub use aliasing_safety::{AliasingSafe, AliasingSafeReason, BecauseExclusive, BecauseImmutable}; @@ -35,23 +36,22 @@ pub type MaybeAligned<'a, T, Aliasing = invariant::Shared, Alignment = invariant impl<'a, T, Aliasing, Alignment> MaybeAligned<'a, T, Aliasing, Alignment> where T: 'a + ?Sized, - Aliasing: invariant::Reference, + Aliasing: invariant::Aliasing, Alignment: invariant::Alignment, { /// Reads the value from `MaybeAligned`. #[must_use] #[inline] - pub fn read_unaligned(self) -> T + pub fn read_unaligned(self) -> T where T: Copy, + R: AliasingSafeReason, + T: AliasingSafe, { - let raw = self.as_non_null().as_ptr(); // SAFETY: By invariant on `MaybeAligned`, `raw` contains - // validly-initialized data for `T`. By `Aliasing: Reference`, - // `Aliasing` is either `Shared` or `Exclusive`, both of which ensure - // that it is sound to perform this read. By `T: Copy`, the value is - // safe to return. - unsafe { core::ptr::read_unaligned(raw) } + // validly-initialized data for `T`. By `T: AliasingSafe`, we are + // permitted to perform a read of `self`'s referent. + unsafe { self.as_inner().read_unaligned() } } } diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index 8ca250ace0..ad5d91f2e4 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -6,16 +6,17 @@ // This file may not be copied, modified, or distributed except according to // those terms. -use core::ptr::NonNull; +use core::{marker::PhantomData, ptr::NonNull}; -use crate::{util::AsAddress, CastType, KnownLayout}; +use super::inner::PtrInner; +use crate::{CastType, KnownLayout}; /// Module used to gate access to [`Ptr`]'s fields. mod def { + use super::*; + #[cfg(doc)] use super::invariant; - use super::Invariants; - use core::{marker::PhantomData, ptr::NonNull}; /// A raw pointer with more restrictions. /// @@ -42,37 +43,20 @@ mod def { /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html pub struct Ptr<'a, T, I> where - T: 'a + ?Sized, + T: ?Sized, I: Invariants, { /// # Invariants /// - /// 0. If `ptr`'s referent is not zero sized, then `ptr` is derived from - /// some valid Rust allocation, `A`. - /// 1. If `ptr`'s referent is not zero sized, then `ptr` has valid - /// provenance for `A`. - /// 2. If `ptr`'s referent is not zero sized, then `ptr` addresses a - /// byte range which is entirely contained in `A`. - /// 3. `ptr` addresses a byte range whose length fits in an `isize`. - /// 4. `ptr` addresses a byte range which does not wrap around the - /// address space. - /// 5. If `ptr`'s referent is not zero sized,`A` is guaranteed to live - /// for at least `'a`. - /// 6. `T: 'a`. - /// 7. `ptr` conforms to the aliasing invariant of + /// 0. `ptr` conforms to the aliasing invariant of /// [`I::Aliasing`](invariant::Aliasing). - /// 8. `ptr` conforms to the alignment invariant of + /// 1. `ptr` conforms to the alignment invariant of /// [`I::Alignment`](invariant::Alignment). - /// 9. `ptr` conforms to the validity invariant of + /// 2. `ptr` conforms to the validity invariant of /// [`I::Validity`](invariant::Validity). - // SAFETY: `NonNull` is covariant over `T` [1]. - // - // [1]: https://doc.rust-lang.org/std/ptr/struct.NonNull.html - ptr: NonNull, - // SAFETY: `&'a ()` is covariant over `'a` [1]. - // - // [1]: https://doc.rust-lang.org/reference/subtyping.html#variance - _invariants: PhantomData<&'a I>, + // SAFETY: `PtrInner<'a, T>` is covariant over `'a` and `T`. + ptr: PtrInner<'a, T>, + _invariants: PhantomData, } impl<'a, T, I> Ptr<'a, T, I> @@ -104,17 +88,38 @@ mod def { /// 8. `ptr` conforms to the validity invariant of /// [`I::Validity`](invariant::Validity). pub(super) const unsafe fn new(ptr: NonNull) -> Ptr<'a, T, I> { + // SAFETY: The caller has promised (in 0 - 5) to satisfy all safety + // invariants of `PtrInner::new`. + let ptr = unsafe { PtrInner::new(ptr) }; + // SAFETY: The caller has promised (in 6 - 8) to satisfy all safety + // invariants of `Ptr`. + Self { ptr, _invariants: PhantomData } + } + + /// Constructs a new `Ptr` from a [`PtrInner`]. + /// + /// # Safety + /// + /// The caller promises that: + /// + /// 0. `ptr` conforms to the aliasing invariant of + /// [`I::Aliasing`](invariant::Aliasing). + /// 1. `ptr` conforms to the alignment invariant of + /// [`I::Alignment`](invariant::Alignment). + /// 2. `ptr` conforms to the validity invariant of + /// [`I::Validity`](invariant::Validity). + pub(super) const unsafe fn from_inner(ptr: PtrInner<'a, T>) -> Ptr<'a, T, I> { // SAFETY: The caller has promised to satisfy all safety invariants // of `Ptr`. Self { ptr, _invariants: PhantomData } } - /// Converts this `Ptr` to a [`NonNull`]. + /// Converts this `Ptr` to a [`PtrInner`]. /// /// Note that this method does not consume `self`. The caller should - /// watch out for `unsafe` code which uses the returned `NonNull` in a - /// way that violates the safety invariants of `self`. - pub(crate) const fn as_non_null(&self) -> NonNull { + /// watch out for `unsafe` code which uses the returned value in a way + /// that violates the safety invariants of `self`. + pub(crate) const fn as_inner(&self) -> PtrInner<'a, T> { self.ptr } } @@ -300,7 +305,7 @@ mod _external { { #[inline] fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - self.as_non_null().fmt(f) + self.as_inner().as_non_null().fmt(f) } } } @@ -319,30 +324,15 @@ mod _conversions { #[doc(hidden)] #[inline] pub fn from_ref(ptr: &'a T) -> Self { - let ptr = NonNull::from(ptr); + let inner = PtrInner::from_ref(ptr); // SAFETY: - // 0. If `ptr`'s referent is not zero sized, then `ptr`, by - // invariant on `&'a T`, is derived from some valid Rust - // allocation, `A`. - // 1. If `ptr`'s referent is not zero sized, then `ptr`, by - // invariant on `&'a T`, has valid provenance for `A`. - // 2. If `ptr`'s referent is not zero sized, then `ptr`, by - // invariant on `&'a T`, addresses a byte range which is entirely - // contained in `A`. - // 3. `ptr`, by invariant on `&'a T`, addresses a byte range whose - // length fits in an `isize`. - // 4. `ptr`, by invariant on `&'a T`, addresses a byte range which - // does not wrap around the address space. - // 5. If `ptr`'s referent is not zero sized, then `A`, by invariant - // on `&'a T`, is guaranteed to live for at least `'a`. - // 6. `T: 'a`. - // 7. `ptr`, by invariant on `&'a T`, conforms to the aliasing + // 0. `ptr`, by invariant on `&'a T`, conforms to the aliasing // invariant of `Shared`. - // 8. `ptr`, by invariant on `&'a T`, conforms to the alignment + // 1. `ptr`, by invariant on `&'a T`, conforms to the alignment // invariant of `Aligned`. - // 9. `ptr`, by invariant on `&'a T`, conforms to the validity + // 2. `ptr`, by invariant on `&'a T`, conforms to the validity // invariant of `Valid`. - unsafe { Self::new(ptr) } + unsafe { Self::from_inner(inner) } } } @@ -354,29 +344,15 @@ mod _conversions { /// Constructs a `Ptr` from an exclusive reference. #[inline] pub(crate) fn from_mut(ptr: &'a mut T) -> Self { - let ptr = NonNull::from(ptr); + let inner = PtrInner::from_mut(ptr); // SAFETY: - // 0. If `ptr`'s referent is not zero sized, then `ptr`, by - // invariant on `&'a mut T`, is derived from some valid Rust - // allocation, `A`. - // 1. If `ptr`'s referent is not zero sized, then `ptr`, by - // invariant on `&'a mut T`, has valid provenance for `A`. - // 2. If `ptr`'s referent is not zero sized, then `ptr`, by - // invariant on `&'a mut T`, addresses a byte range which is - // entirely contained in `A`. - // 3. `ptr`, by invariant on `&'a mut T`, addresses a byte range - // whose length fits in an `isize`. - // 4. `ptr`, by invariant on `&'a mut T`, addresses a byte range - // which does not wrap around the address space. - // 5. If `ptr`'s referent is not zero sized, then `A`, by invariant - // on `&'a mut T`, is guaranteed to live for at least `'a`. - // 6. `ptr`, by invariant on `&'a mut T`, conforms to the aliasing + // 0. `ptr`, by invariant on `&'a mut T`, conforms to the aliasing // invariant of `Exclusive`. - // 7. `ptr`, by invariant on `&'a mut T`, conforms to the alignment + // 1. `ptr`, by invariant on `&'a mut T`, conforms to the alignment // invariant of `Aligned`. - // 8. `ptr`, by invariant on `&'a mut T`, conforms to the validity + // 2. `ptr`, by invariant on `&'a mut T`, conforms to the validity // invariant of `Valid`. - unsafe { Self::new(ptr) } + unsafe { Self::from_inner(inner) } } } @@ -394,7 +370,7 @@ mod _conversions { // calling `as_ref`. #[allow(clippy::wrong_self_convention)] pub(crate) fn as_ref(self) -> &'a T { - let raw = self.as_non_null(); + let raw = self.as_inner().as_non_null(); // SAFETY: This invocation of `NonNull::as_ref` satisfies its // documented safety preconditions: // @@ -409,15 +385,15 @@ mod _conversions { // > must all be within the bounds of a single allocated object. // > [2] // - // This is ensured by contract on all `Ptr`s. + // This is ensured by contract on all `PtrInner`s. // // 3. The pointer must point to an initialized instance of `T`. This // is ensured by-contract on `Ptr`, because the `I::Validity` is // `Valid`. // // 4. You must enforce Rust’s aliasing rules. This is ensured by - // contract on `Ptr`, because the `I::Aliasing: Reference`. - // Either it is `Shared` or `Exclusive`. If it is `Shared`, other + // contract on `Ptr`, because `I::Aliasing: Reference`. Either it + // is `Shared` or `Exclusive`. If it is `Shared`, other // references may not mutate the referent outside of // `UnsafeCell`s. // @@ -446,22 +422,11 @@ mod _conversions { 'a: 'b, { // SAFETY: The following all hold by invariant on `self`, and thus - // hold of `ptr = self.as_non_null()`: - // 0. If `ptr`'s referent is not zero sized, then `ptr` is derived - // from some valid Rust allocation, `A`. - // 1. If `ptr`'s referent is not zero sized, then `ptr` has valid - // provenance for `A`. - // 2. If `ptr`'s referent is not zero sized, then `ptr` addresses a - // byte range which is entirely contained in `A`. - // 3. `ptr` addresses a byte range whose length fits in an `isize`. - // 4. `ptr` addresses a byte range which does not wrap around the - // address space. - // 5. If `ptr`'s referent is not zero sized, then `A` is guaranteed - // to live for at least `'a`. - // 6. SEE BELOW. - // 7. `ptr` conforms to the alignment invariant of + // hold of `ptr = self.as_inner()`: + // 0. SEE BELOW. + // 1. `ptr` conforms to the alignment invariant of // [`I::Alignment`](invariant::Alignment). - // 8. `ptr` conforms to the validity invariant of + // 2. `ptr` conforms to the validity invariant of // [`I::Validity`](invariant::Validity). // // For aliasing (6 above), since `I::Aliasing: Reference`, @@ -481,7 +446,7 @@ mod _conversions { // while `self` is live. Thus, as long as the returned `Ptr` // exists, no other references or `Ptr`s which refer to the same // memory may be live. - unsafe { Ptr::new(self.as_non_null()) } + unsafe { Ptr::from_inner(self.as_inner()) } } } @@ -493,7 +458,7 @@ mod _conversions { /// Converts `self` to a mutable reference. #[allow(clippy::wrong_self_convention)] pub(crate) fn as_mut(self) -> &'a mut T { - let mut raw = self.as_non_null(); + let mut raw = self.as_inner().as_non_null(); // SAFETY: This invocation of `NonNull::as_mut` satisfies its // documented safety preconditions: // @@ -508,11 +473,11 @@ mod _conversions { // > must all be within the bounds of a single allocated object. // > [2] // - // This is ensured by contract on all `Ptr`s. + // This is ensured by contract on all `PtrInner`s. // // 3. The pointer must point to an initialized instance of `T`. This - // is ensured by-contract on `Ptr`, because the - // `VALIDITY_INVARIANT` is `Valid`. + // is ensured by-contract on `Ptr`, because the validity + // invariant is `Valid`. // // 4. You must enforce Rust’s aliasing rules. This is ensured by // contract on `Ptr`, because the `ALIASING_INVARIANT` is @@ -658,7 +623,7 @@ mod _transitions { // SAFETY: The caller has promised to satisfy all parameterized // invariants of `Ptr`. `Ptr`'s other invariants are satisfied // by-contract by the source `Ptr`. - unsafe { Ptr::new(self.as_non_null()) } + unsafe { Ptr::from_inner(self.as_inner()) } } /// Helps the type system unify two distinct invariant types which are @@ -729,7 +694,9 @@ mod _transitions { where T: Sized, { - if let Err(err) = crate::util::validate_aligned_to::<_, T>(self.as_non_null()) { + if let Err(err) = + crate::util::validate_aligned_to::<_, T>(self.as_inner().as_non_null()) + { return Err(err.with_src(self)); } @@ -867,11 +834,7 @@ mod _transitions { /// Casts of the referent type. mod _casts { use super::*; - use crate::{ - layout::{DstLayout, MetadataCastError}, - pointer::aliasing_safety::*, - AlignmentError, CastError, PointerMetadata, SizeError, - }; + use crate::{pointer::aliasing_safety::*, CastError, SizeError}; impl<'a, T, I> Ptr<'a, T, I> where @@ -895,10 +858,10 @@ mod _casts { self, cast: F, ) -> Ptr<'a, U, (I::Aliasing, Any, Any)> { - let ptr = cast(self.as_non_null().as_ptr()); + let ptr = cast(self.as_inner().as_non_null().as_ptr()); // SAFETY: Caller promises that `cast` returns a pointer whose - // address is in the range of `self.as_non_null()`'s referent. By + // address is in the range of `self.as_inner().as_non_null()`'s referent. By // invariant, none of these addresses are null. let ptr = unsafe { NonNull::new_unchecked(ptr) }; @@ -906,7 +869,7 @@ mod _casts { // // Lemma 1: `ptr` has the same provenance as `self`. The caller // promises that `cast` preserves provenance, and we call it with - // `self.as_non_null()`. + // `self.as_inner().as_non_null()`. // // 0. By invariant, if `self`'s referent is not zero sized, then // `self` is derived from some valid Rust allocation, `A`. By @@ -967,7 +930,7 @@ mod _casts { [u8]: AliasingSafe, R: AliasingSafeReason, { - let bytes = match T::size_of_val_raw(self.as_non_null()) { + let bytes = match T::size_of_val_raw(self.as_inner().as_non_null()) { Some(bytes) => bytes, // SAFETY: `KnownLayout::size_of_val_raw` promises to always // return `Some` so long as the resulting size fits in a @@ -1012,51 +975,17 @@ mod _casts { /// Casts this pointer-to-array into a slice. #[allow(clippy::wrong_self_convention)] pub(crate) fn as_slice(self) -> Ptr<'a, [T], I> { - let start = self.as_non_null().cast::().as_ptr(); - let slice = core::ptr::slice_from_raw_parts_mut(start, N); - // SAFETY: `slice` is not null, because it is derived from `start` - // which is non-null. - let slice = unsafe { NonNull::new_unchecked(slice) }; - // SAFETY: Lemma: In the following safety arguments, note that - // `slice` is derived from `self` in two steps: first, by casting - // `self: [T; N]` to `start: T`, then by constructing a pointer to a - // slice starting at `start` of length `N`. As a result, `slice` - // references exactly the same allocation as `self`, if any. + let slice = self.as_inner().as_slice(); + // SAFETY: Note that, by post-condition on `PtrInner::as_slice`, + // `slice` refers to the same byte range as `self.as_inner()`. // - // 0. By the above lemma, if `slice`'s referent is not zero sized, - // then `slice` is derived from the same allocation as `self`, - // which, by invariant on `Ptr`, is valid. - // 1. By the above lemma, if `slice`'s referent is not zero sized, - // then , `slice` has valid provenance for `A`, since it is - // derived from the pointer `self`, which, by invariant on `Ptr`, - // has valid provenance for `A`. - // 2. By the above lemma, if `slice`'s referent is not zero sized, - // then `slice` addresses a byte range which is entirely - // contained in `A`, because it references exactly the same byte - // range as `self`, which, by invariant on `Ptr`, is entirely - // contained in `A`. - // 3. By the above lemma, `slice` addresses a byte range whose - // length fits in an `isize`, since it addresses exactly the same - // byte range as `self`, which, by invariant on `Ptr`, has a - // length that fits in an `isize`. - // 4. By the above lemma, `slice` addresses a byte range which does - // not wrap around the address space, since it addresses exactly - // the same byte range as `self`, which, by invariant on `Ptr`, - // does not wrap around the address space. - // 5. By the above lemma, if `slice`'s referent is not zero sized, - // then `A` is guaranteed to live for at least `'a`, because it - // is derived from the same allocation as `self`, which, by - // invariant on `Ptr`, lives for at least `'a`. - // 6. By the above lemma, `slice` conforms to the aliasing invariant - // of `I::Aliasing`, because the operations that produced `slice` - // from `self` do not impact aliasing. + // 6. Thus, `slice` conforms to the aliasing invariant of + // `I::Aliasing` because `self` does. // 7. By the above lemma, `slice` conforms to the alignment - // invariant of `I::Alignment`, because the operations that - // produced `slice` from `self` do not impact alignment. + // invariant of `I::Alignment` because `self` does. // 8. By the above lemma, `slice` conforms to the validity invariant - // of `I::Validity`, because the operations that produced `slice` - // from `self` do not impact validity. - unsafe { Ptr::new(slice) } + // of `I::Validity` because `self` does. + unsafe { Ptr::from_inner(slice) } } } @@ -1102,103 +1031,43 @@ mod _casts { I::Aliasing: Reference, U: 'a + ?Sized + KnownLayout + AliasingSafe<[u8], I::Aliasing, R>, { - let layout = match meta { - None => U::LAYOUT, - // This can return `None` if the metadata describes an object - // which can't fit in an `isize`. - Some(meta) => { - let size = match meta.size_for_metadata(U::LAYOUT) { - Some(size) => size, - None => return Err(CastError::Size(SizeError::new(self))), - }; - DstLayout { align: U::LAYOUT.align, size_info: crate::SizeInfo::Sized { size } } - } - }; - // PANICS: By invariant, the byte range addressed by `self.ptr` does - // not wrap around the address space. This implies that the sum of - // the address (represented as a `usize`) and length do not overflow - // `usize`, as required by `validate_cast_and_convert_metadata`. - // Thus, this call to `validate_cast_and_convert_metadata` will only - // panic if `U` is a DST whose trailing slice element is zero-sized. - let maybe_metadata = layout.validate_cast_and_convert_metadata( - AsAddress::addr(self.as_non_null().as_ptr()), - self.len(), - cast_type, - ); - - let (elems, split_at) = match maybe_metadata { - Ok((elems, split_at)) => (elems, split_at), - Err(MetadataCastError::Alignment) => { - // SAFETY: Since `validate_cast_and_convert_metadata` - // returned an alignment error, `U` must have an alignment - // requirement greater than one. - let err = unsafe { AlignmentError::<_, U>::new_unchecked(self) }; - return Err(CastError::Alignment(err)); - } - Err(MetadataCastError::Size) => return Err(CastError::Size(SizeError::new(self))), - }; - - // SAFETY: `validate_cast_and_convert_metadata` promises to return - // `split_at <= self.len()`. - let (l_slice, r_slice) = unsafe { self.split_at(split_at) }; - - let (target, remainder) = match cast_type { - CastType::Prefix => (l_slice, r_slice), - CastType::Suffix => (r_slice, l_slice), - }; - - let base = target.as_non_null().cast::(); - - let elems = ::PointerMetadata::from_elem_count(elems); - // For a slice DST type, if `meta` is `Some(elems)`, then we - // synthesize `layout` to describe a sized type whose size is equal - // to the size of the instance that we are asked to cast. For sized - // types, `validate_cast_and_convert_metadata` returns `elems == 0`. - // Thus, in this case, we need to use the `elems` passed by the - // caller, not the one returned by - // `validate_cast_and_convert_metadata`. - let elems = meta.unwrap_or(elems); - - let ptr = U::raw_from_ptr_len(base, elems); + let (inner, remainder) = + self.as_inner().try_cast_into(cast_type, meta).map_err(|err| { + err.map_src(|inner| + // SAFETY: `PtrInner::try_cast_into` promises to return its + // original argument on error, which was originally produced + // by `self.as_inner()`, which is guaranteed to satisfy + // `Ptr`'s invariants. + unsafe { Ptr::from_inner(inner) }) + })?; // SAFETY: - // 0. By invariant, if `target`'s referent is not zero sized, then - // `target` is derived from some valid Rust allocation, `A`. By - // contract on `cast`, `ptr` is derived from `self`, and thus - // from the same valid Rust allocation, `A`. - // 1. By invariant, if `target`'s referent is not zero sized, then - // `target` has provenance valid for some Rust allocation, `A`. - // Because `ptr` is derived from `target` via - // provenance-preserving operations, `ptr` will also have - // provenance valid for `A`. - // - `validate_cast_and_convert_metadata` promises that the object - // described by `elems` and `split_at` lives at a byte range - // which is a subset of the input byte range. Thus: - // 2. Since, by invariant, if `target`'s referent is not zero - // sized, then `target` addresses a byte range which is - // entirely contained in `A`, so does `ptr`. - // 3. Since, by invariant, `target` addresses a byte range whose - // length fits in an `isize`, so does `ptr`. - // 4. Since, by invariant, `target` addresses a byte range which - // does not wrap around the address space, so does `ptr`. - // 5. Since, by invariant, if `target`'s referent is not zero - // sized, then `target` refers to an allocation which is - // guaranteed to live for at least `'a`, so does `ptr`. - // 6. Since `U: AliasingSafe<[u8], I::Aliasing, _>`, either: - // - `I::Aliasing` is `Exclusive`, in which case both `src` - // and `ptr` conform to `Exclusive` - // - `I::Aliasing` is `Shared` or `Any` and both `U` and - // `[u8]` are `Immutable`. In this case, neither pointer - // permits mutation, and so `Shared` aliasing is satisfied. - // 7. `ptr` conforms to the alignment invariant of `Aligned` because - // it is derived from `validate_cast_and_convert_metadata`, which - // promises that the object described by `target` is validly - // aligned for `U`. - // 8. By trait bound, `self` - and thus `target` - is a bit-valid + // 0. Since `U: AliasingSafe<[u8], I::Aliasing, _>`, either: + // - `I::Aliasing` is `Exclusive`, in which case both `src` and + // `ptr` conform to `Exclusive` + // - `I::Aliasing` is `Shared` or `Any` and both `U` and `[u8]` + // are `Immutable`. In this case, neither pointer permits + // mutation, and so `Shared` aliasing is satisfied. + // 1. `ptr` conforms to the alignment invariant of `Aligned` because + // it is derived from `try_cast_into`, which promises that the + // object described by `target` is validly aligned for `U`. + // 2. By trait bound, `self` - and thus `target` - is a bit-valid // `[u8]`. All bit-valid `[u8]`s have all of their bytes // initialized, so `ptr` conforms to the validity invariant of // `Initialized`. - Ok((unsafe { Ptr::new(ptr) }, remainder)) + let res = unsafe { Ptr::from_inner(inner) }; + + // SAFETY: + // 0. `self` and `remainder` both have the type `[u8]`. Thus, they + // have `UnsafeCell`s at the same locations. Type casting does + // not affect aliasing. + // 1. `[u8]` has no alignment requirement. + // 2. `self` has validity `Valid` and has type `[u8]`. Since + // `remainder` references a subset of `self`'s referent, it is + // also bit-valid. + let remainder = unsafe { Ptr::from_inner(remainder) }; + + Ok((res, remainder)) } /// Attempts to cast `self` into a `U`, failing if all of the bytes of @@ -1303,11 +1172,6 @@ mod _casts { /// Projections through the referent. mod _project { - use core::ops::Range; - - #[allow(unused_imports)] - use crate::util::polyfills::NumExt as _; - use super::*; impl<'a, T, I> Ptr<'a, T, I> @@ -1341,23 +1205,6 @@ mod _project { } } - impl<'a, T, I> Ptr<'a, T, I> - where - T: 'a + KnownLayout + ?Sized, - I: Invariants, - { - /// The number of trailing slice elements in the object referenced by - /// `self`. - /// - /// # Safety - /// - /// Unsafe code my rely on `trailing_slice_len` satisfying the above - /// contract. - pub(super) fn trailing_slice_len(&self) -> usize { - T::pointer_to_metadata(self.as_non_null().as_ptr()) - } - } - impl<'a, T, I> Ptr<'a, [T], I> where T: 'a, @@ -1369,7 +1216,7 @@ mod _project { /// /// Unsafe code my rely on `len` satisfying the above contract. pub(crate) fn len(&self) -> usize { - self.trailing_slice_len() + self.as_inner().len() } } @@ -1379,198 +1226,18 @@ mod _project { I: Invariants, I::Aliasing: Reference, { - /// Creates a pointer which addresses the given `range` of self. - /// - /// # Safety - /// - /// `range` is a valid range (`start <= end`) and `end <= self.len()`. - pub(crate) unsafe fn slice_unchecked(self, range: Range) -> Self { - let base = self.as_non_null().cast::().as_ptr(); - - // SAFETY: The caller promises that `start <= end <= self.len()`. By - // invariant, if `self`'s referent is not zero-sized, then `self` - // refers to a byte range which is contained within a single - // allocation, which is no more than `isize::MAX` bytes long, and - // which does not wrap around the address space. Thus, this pointer - // arithmetic remains in-bounds of the same allocation, and does not - // wrap around the address space. The offset (in bytes) does not - // overflow `isize`. - // - // If `self`'s referent is zero-sized, then these conditions are - // trivially satisfied. - let base = unsafe { base.add(range.start) }; - - // SAFETY: The caller promises that `start <= end`, and so this will - // not underflow. - #[allow(unstable_name_collisions, clippy::incompatible_msrv)] - let len = unsafe { range.end.unchecked_sub(range.start) }; - - let ptr = core::ptr::slice_from_raw_parts_mut(base, len); - - // SAFETY: By invariant, `self`'s address is non-null and its range - // does not wrap around the address space. Since, by the preceding - // lemma, `ptr` addresses a range within that addressed by `self`, - // `ptr` is non-null. - let ptr = unsafe { NonNull::new_unchecked(ptr) }; - - // SAFETY: - // - // Lemma 0: `ptr` addresses a subset of the bytes addressed by - // `self`, and has the same provenance. - // Proof: The caller guarantees that `start <= end <= self.len()`. - // Thus, `base` is in-bounds of `self`, and `base + (end - - // start)` is also in-bounds of self. Finally, `ptr` is - // constructed using provenance-preserving operations. - // - // 0. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is - // not zero sized, then `ptr` is derived from some valid Rust - // allocation, `A`. - // 1. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is - // not zero sized, then `ptr` has valid provenance for `A`. - // 2. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is - // not zero sized, then `ptr` addresses a byte range which is - // entirely contained in `A`. - // 3. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte - // range whose length fits in an `isize`. - // 4. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte - // range which does not wrap around the address space. - // 5. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is - // not zero sized, then `A` is guaranteed to live for at least - // `'a`. - // 6. Per Lemma 0 and by invariant on `self`, `ptr` conforms to the - // aliasing invariant of [`I::Aliasing`](invariant::Aliasing). - // 7. Per Lemma 0 and by invariant on `self`, `ptr` conforms to the - // alignment invariant of [`I::Alignment`](invariant::Alignment). - // 8. Per Lemma 0 and by invariant on `self`, `ptr` conforms to the - // validity invariant of [`I::Validity`](invariant::Validity). - unsafe { Ptr::new(ptr) } - } - - /// Splits the slice in two. - /// - /// # Safety - /// - /// The caller promises that `l_len <= self.len()`. - pub(crate) unsafe fn split_at(self, l_len: usize) -> (Self, Self) { - // SAFETY: TODO(#1890): This is explicitly unsound! It's sound - // *given how `slice_unchecked` is implemented*, and it's sound - // *given what we do with `slf` in this method body*, but it's - // unsound in the general case. We do it temporarily as part of - // broader `Ptr` changes, but it must be fixed before releasing a - // stable zerocopy version. - let slf = unsafe { self.assume_aliasing::() }; - - // SAFETY: The caller promises that `l_len <= self.len()`. - // Trivially, `0 <= l_len`. - let left = unsafe { slf.slice_unchecked(0..l_len) }; - - // SAFETY: The caller promises that `l_len <= self.len() = - // slf.len()`. Trivially, `slf.len() <= slf.len()`. - let right = unsafe { slf.slice_unchecked(l_len..slf.len()) }; - - // LEMMA: `left` and `right` are non-overlapping. Proof: `left` is - // constructed from `slf` with `l_len` as its (exclusive) upper - // bound, while `right` is constructed from `slf` with `l_len` as - // its (inclusive) lower bound. Thus, no index is a member of both - // ranges. - - // SAFETY: By the preceding lemma, `left` and `right` do not alias. - // We do not construct any other `Ptr`s or references which alias - // `left` or `right`. Thus, the only `Ptr`s or references which - // alias `left` or `right` are outside of this method. By invariant, - // `self` obeys the aliasing invariant `I::Aliasing` with respect to - // those other `Ptr`s or references, and so `left` and `right` do as - // well. - let (left, right) = unsafe { - (left.assume_aliasing::(), right.assume_aliasing::()) - }; - (left.unify_invariants(), right.unify_invariants()) - } - /// Iteratively projects the elements `Ptr` from `Ptr<[T]>`. pub(crate) fn iter(&self) -> impl Iterator> { - // TODO(#429): Once `NonNull::cast` documents that it preserves - // provenance, cite those docs. - let base = self.as_non_null().cast::().as_ptr(); - (0..self.len()).map(move |i| { - // TODO(https://github.com/rust-lang/rust/issues/74265): Use - // `NonNull::get_unchecked_mut`. - - // SAFETY: If the following conditions are not satisfied - // `pointer::cast` may induce Undefined Behavior [1]: - // - // > - The computed offset, `count * size_of::()` bytes, must - // > not overflow `isize``. - // > - If the computed offset is non-zero, then `self` must be - // > derived from a pointer to some allocated object, and the - // > entire memory range between `self` and the result must be - // > in bounds of that allocated object. In particular, this - // > range must not “wrap around” the edge of the address - // > space. - // - // [1] https://doc.rust-lang.org/std/primitive.pointer.html#method.add - // - // We satisfy both of these conditions here: - // - By invariant on `Ptr`, `self` addresses a byte range whose - // length fits in an `isize`. Since `elem` is contained in - // `self`, the computed offset of `elem` must fit within - // `isize.` - // - If the computed offset is non-zero, then this means that - // the referent is not zero-sized. In this case, `base` points - // to an allocated object (by invariant on `self`). Thus: - // - By contract, `self.len()` accurately reflects the number - // of elements in the slice. `i` is in bounds of `c.len()` - // by construction, and so the result of this addition - // cannot overflow past the end of the allocation referred - // to by `c`. - // - By invariant on `Ptr`, `self` addresses a byte range - // which does not wrap around the address space. Since - // `elem` is contained in `self`, the computed offset of - // `elem` must wrap around the address space. - // - // TODO(#429): Once `pointer::add` documents that it preserves - // provenance, cite those docs. - let elem = unsafe { base.add(i) }; - - // SAFETY: - // - `elem` must not be null. `base` is constructed from a - // `NonNull` pointer, and the addition that produces `elem` - // must not overflow or wrap around, so `elem >= base > 0`. - // - // TODO(#429): Once `NonNull::new_unchecked` documents that it - // preserves provenance, cite those docs. - let elem = unsafe { NonNull::new_unchecked(elem) }; - - // SAFETY: The safety invariants of `Ptr::new` (see definition) - // are satisfied: - // 0. If `elem`'s referent is not zero sized, then `elem` is - // derived from a valid Rust allocation, because `self` is - // derived from a valid Rust allocation, by invariant on - // `Ptr`. - // 1. If `elem`'s referent is not zero sized, then `elem` has - // valid provenance for `self`, because it derived from - // `self` using a series of provenance-preserving operations. - // 2. If `elem`'s referent is not zero sized, then `elem` is - // entirely contained in the allocation of `self` (see - // above). - // 3. `elem` addresses a byte range whose length fits in an - // `isize` (see above). - // 4. `elem` addresses a byte range which does not wrap around - // the address space (see above). - // 5. If `elem`'s referent is not zero sized, then the - // allocation of `elem` is guaranteed to live for at least - // `'a`, because `elem` is entirely contained in `self`, - // which lives for at least `'a` by invariant on `Ptr`. - // 6. `elem` conforms to the aliasing invariant of `I::Aliasing` - // because projection does not impact the aliasing invariant. - // 7. `elem`, conditionally, conforms to the validity invariant - // of `I::Alignment`. If `elem` is projected from data - // well-aligned for `[T]`, `elem` will be valid for `T`. - // 8. `elem`, conditionally, conforms to the validity invariant - // of `I::Validity`. If `elem` is projected from data valid - // for `[T]`, `elem` will be valid for `T`. - unsafe { Ptr::new(elem) } - }) + // SAFETY: + // 0. `elem` conforms to the aliasing invariant of `I::Aliasing` + // because projection does not impact the aliasing invariant. + // 1. `elem`, conditionally, conforms to the validity invariant of + // `I::Alignment`. If `elem` is projected from data well-aligned + // for `[T]`, `elem` will be valid for `T`. + // 2. `elem`, conditionally, conforms to the validity invariant of + // `I::Validity`. If `elem` is projected from data valid for + // `[T]`, `elem` will be valid for `T`. + self.as_inner().iter().map(|elem| unsafe { Ptr::from_inner(elem) }) } } } @@ -1581,25 +1248,10 @@ mod tests { use core::mem::{self, MaybeUninit}; use super::*; + #[allow(unused)] // Needed on our MSRV, but considered unused on later toolchains. + use crate::util::AsAddress; use crate::{pointer::BecauseImmutable, util::testutil::AU64, FromBytes, Immutable}; - #[test] - fn test_split_at() { - const N: usize = 16; - let mut arr = [1; N]; - let mut ptr = Ptr::from_mut(&mut arr).as_slice(); - for i in 0..=N { - assert_eq!(ptr.len(), N); - // SAFETY: `i` is in bounds by construction. - let (l, r) = unsafe { ptr.reborrow().split_at(i) }; - let l_sum: usize = l.iter().map(Ptr::read_unaligned).sum(); - let r_sum: usize = r.iter().map(Ptr::read_unaligned).sum(); - assert_eq!(l_sum, i); - assert_eq!(r_sum, N - i); - assert_eq!(l_sum + r_sum, N); - } - } - mod test_ptr_try_cast_into_soundness { use super::*; @@ -1685,7 +1337,8 @@ mod tests { #[allow(unstable_name_collisions)] let bytes_addr = bytes.as_ptr().addr(); #[allow(unstable_name_collisions)] - let remaining_addr = remaining.as_non_null().as_ptr().addr(); + let remaining_addr = + remaining.as_inner().as_non_null().as_ptr().addr(); match cast_type { CastType::Prefix => { assert_eq!(remaining_addr, bytes_addr + len) @@ -1695,7 +1348,7 @@ mod tests { if let Some(want) = meta { let got = KnownLayout::pointer_to_metadata( - slf.as_non_null().as_ptr(), + slf.as_inner().as_non_null().as_ptr(), ); assert_eq!(got, want); } @@ -1711,8 +1364,9 @@ mod tests { assert_eq!(len, bytes.len()); if let Some(want) = meta { - let got = - KnownLayout::pointer_to_metadata(slf.as_non_null().as_ptr()); + let got = KnownLayout::pointer_to_metadata( + slf.as_inner().as_non_null().as_ptr(), + ); assert_eq!(got, want); } } @@ -1782,7 +1436,7 @@ mod tests { if let Some(expect) = $expect { let (ptr, _) = res.unwrap(); assert_eq!( - KnownLayout::pointer_to_metadata(ptr.as_non_null().as_ptr()), + KnownLayout::pointer_to_metadata(ptr.as_inner().as_non_null().as_ptr()), expect ); } else { diff --git a/zerocopy-derive/src/enum.rs b/zerocopy-derive/src/enum.rs index 9ac24d9432..7836117231 100644 --- a/zerocopy-derive/src/enum.rs +++ b/zerocopy-derive/src/enum.rs @@ -329,7 +329,7 @@ pub(crate) fn derive_is_bit_valid( // is `Initialized`. Since we have not written uninitialized // bytes into the referent, `tag_ptr` is also `Initialized`. let tag_ptr = unsafe { tag_ptr.assume_initialized() }; - tag_ptr.bikeshed_recall_valid().read_unaligned() + tag_ptr.bikeshed_recall_valid().read_unaligned::<::zerocopy::BecauseImmutable>() }; // SAFETY: diff --git a/zerocopy-derive/src/output_tests.rs b/zerocopy-derive/src/output_tests.rs index ebeab2fdc7..8bf8e5bb13 100644 --- a/zerocopy-derive/src/output_tests.rs +++ b/zerocopy-derive/src/output_tests.rs @@ -592,7 +592,7 @@ fn test_try_from_bytes_enum() { candidate.reborrow().cast_unsized(|p: *mut Self| { p as *mut ___ZerocopyTagPrimitive }) }; let tag_ptr = unsafe { tag_ptr.assume_initialized() }; - tag_ptr.bikeshed_recall_valid().read_unaligned() + tag_ptr.bikeshed_recall_valid().read_unaligned::<::zerocopy::BecauseImmutable>() }; let raw_enum = unsafe { candidate.cast_unsized(|p: *mut Self| { p as *mut ___ZerocopyRawEnum<'a, N, X, Y> }) @@ -883,7 +883,7 @@ fn test_try_from_bytes_enum() { candidate.reborrow().cast_unsized(|p: *mut Self| { p as *mut ___ZerocopyTagPrimitive }) }; let tag_ptr = unsafe { tag_ptr.assume_initialized() }; - tag_ptr.bikeshed_recall_valid().read_unaligned() + tag_ptr.bikeshed_recall_valid().read_unaligned::<::zerocopy::BecauseImmutable>() }; let raw_enum = unsafe { candidate.cast_unsized(|p: *mut Self| { p as *mut ___ZerocopyRawEnum<'a, N, X, Y> }) @@ -1174,7 +1174,7 @@ fn test_try_from_bytes_enum() { candidate.reborrow().cast_unsized(|p: *mut Self| { p as *mut ___ZerocopyTagPrimitive }) }; let tag_ptr = unsafe { tag_ptr.assume_initialized() }; - tag_ptr.bikeshed_recall_valid().read_unaligned() + tag_ptr.bikeshed_recall_valid().read_unaligned::<::zerocopy::BecauseImmutable>() }; let raw_enum = unsafe { candidate.cast_unsized(|p: *mut Self| { p as *mut ___ZerocopyRawEnum<'a, N, X, Y> }) From ca9243fc00709a92dc69f7dfbafa014b3f3dbc41 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Mon, 14 Oct 2024 11:02:14 -0700 Subject: [PATCH 15/96] [pointer][invariant] Move to separate file (#1906) This prepares us for future changes which will significantly increase the amount of code in the `invariant` module. Also merge `aliasing_safety` into this new file. --- src/pointer/aliasing_safety.rs | 89 ------------- src/pointer/invariant.rs | 221 +++++++++++++++++++++++++++++++++ src/pointer/mod.rs | 11 +- src/pointer/ptr.rs | 152 +---------------------- 4 files changed, 234 insertions(+), 239 deletions(-) delete mode 100644 src/pointer/aliasing_safety.rs create mode 100644 src/pointer/invariant.rs diff --git a/src/pointer/aliasing_safety.rs b/src/pointer/aliasing_safety.rs deleted file mode 100644 index 7308cf5529..0000000000 --- a/src/pointer/aliasing_safety.rs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2024 The Fuchsia Authors -// -// Licensed under a BSD-style license , Apache License, Version 2.0 -// , or the MIT -// license , at your option. -// This file may not be copied, modified, or distributed except according to -// those terms. - -//! Machinery for statically proving the "aliasing-safety" of a `Ptr`. - -use crate::{invariant, Immutable}; - -/// Pointer conversions which do not violate aliasing. -/// -/// `U: AliasingSafe` implies that a pointer conversion from `T` to `U` -/// does not violate the aliasing invariant, `A`. This can be because `A` is -/// [`Exclusive`] or because neither `T` nor `U` permit interior mutability. -/// -/// # Safety -/// -/// `U: AliasingSafe` if either of the following conditions holds: -/// - `A` is [`Exclusive`] -/// - `T` and `U` both implement [`Immutable`] -/// -/// [`Exclusive`]: crate::pointer::invariant::Exclusive -#[doc(hidden)] -pub unsafe trait AliasingSafe {} - -/// Used to prevent user implementations of `AliasingSafeReason`. -mod sealed { - pub trait Sealed {} - - impl Sealed for super::BecauseExclusive {} - impl Sealed for super::BecauseImmutable {} - impl Sealed for (S,) {} -} - -#[doc(hidden)] -pub trait AliasingSafeReason: sealed::Sealed {} -impl AliasingSafeReason for (R,) {} - -/// The conversion is safe because only one live `Ptr` or reference may exist to -/// the referent bytes at a time. -#[derive(Copy, Clone, Debug)] -#[doc(hidden)] -pub enum BecauseExclusive {} -impl AliasingSafeReason for BecauseExclusive {} - -/// The conversion is safe because no live `Ptr`s or references permit mutation. -#[derive(Copy, Clone, Debug)] -#[doc(hidden)] -pub enum BecauseImmutable {} -impl AliasingSafeReason for BecauseImmutable {} - -/// SAFETY: `T: AliasingSafe` because for all -/// `Ptr<'a, T, I>` such that `I::Aliasing = Exclusive`, there cannot exist -/// other live references to the memory referenced by `Ptr`. -unsafe impl AliasingSafe for U {} - -/// SAFETY: `U: AliasingSafe` because for all `Ptr<'a, T, -/// I>` and `Ptr<'a, U, I>` such that `I::Aliasing = A`, all live references and -/// live `Ptr`s agree, by invariant on `Immutable`, that the referenced bytes -/// contain no `UnsafeCell`s, and thus do not permit mutation except via -/// exclusive aliasing. -unsafe impl AliasingSafe for U -where - A: invariant::Aliasing, - T: Immutable, - U: Immutable, -{ -} - -/// This ensures that `U: AliasingSafe` implies `T: AliasingSafe` in -/// a manner legible to rustc, which in turn means we can write simpler bounds in -/// some places. -/// -/// SAFETY: Per `U: AliasingSafe`, either: -/// - `A` is `Exclusive` -/// - `T` and `U` both implement `Immutable` -/// -/// Neither property depends on which of `T` and `U` are in the `Self` position -/// vs the first type parameter position. -unsafe impl AliasingSafe for T -where - A: invariant::Aliasing, - R: AliasingSafeReason, - U: AliasingSafe, -{ -} diff --git a/src/pointer/invariant.rs b/src/pointer/invariant.rs new file mode 100644 index 0000000000..abd019a391 --- /dev/null +++ b/src/pointer/invariant.rs @@ -0,0 +1,221 @@ +// Copyright 2024 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#![allow(missing_copy_implementations, missing_debug_implementations)] + +//! The parameterized invariants of a [`Ptr`][super::Ptr]. +//! +//! Invariants are encoded as ([`Aliasing`], [`Alignment`], [`Validity`]) +//! triples implementing the [`Invariants`] trait. + +/// The invariants of a [`Ptr`][super::Ptr]. +pub trait Invariants: Sealed { + type Aliasing: Aliasing; + type Alignment: Alignment; + type Validity: Validity; +} + +impl Invariants for (A, AA, V) { + type Aliasing = A; + type Alignment = AA; + type Validity = V; +} + +/// The aliasing invariant of a [`Ptr`][super::Ptr]. +pub trait Aliasing: Sealed { + /// Is `Self` [`Exclusive`]? + #[doc(hidden)] + const IS_EXCLUSIVE: bool; +} + +/// The alignment invariant of a [`Ptr`][super::Ptr]. +pub trait Alignment: Sealed {} + +/// The validity invariant of a [`Ptr`][super::Ptr]. +pub trait Validity: Sealed {} + +/// An [`Aliasing`] invariant which is either [`Shared`] or [`Exclusive`]. +/// +/// # Safety +/// +/// Given `A: Reference`, callers may assume that either `A = Shared` or `A = +/// Exclusive`. +pub trait Reference: Aliasing + Sealed {} + +/// No requirement - any invariant is allowed. +pub enum Any {} +impl Aliasing for Any { + const IS_EXCLUSIVE: bool = false; +} +impl Alignment for Any {} +impl Validity for Any {} + +/// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a T`. +/// +/// The referent of a shared-aliased `Ptr` may be concurrently referenced by any +/// number of shared-aliased `Ptr` or `&T` references, and may not be +/// concurrently referenced by any exclusively-aliased `Ptr`s or `&mut T` +/// references. The referent must not be mutated, except via [`UnsafeCell`]s. +/// +/// [`UnsafeCell`]: core::cell::UnsafeCell +pub enum Shared {} +impl Aliasing for Shared { + const IS_EXCLUSIVE: bool = false; +} +impl Reference for Shared {} + +/// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a mut T`. +/// +/// The referent of an exclusively-aliased `Ptr` may not be concurrently +/// referenced by any other `Ptr`s or references, and may not be accessed (read +/// or written) other than via this `Ptr`. +pub enum Exclusive {} +impl Aliasing for Exclusive { + const IS_EXCLUSIVE: bool = true; +} +impl Reference for Exclusive {} + +/// The referent is aligned: for `Ptr`, the referent's address is a multiple +/// of the `T`'s alignment. +pub enum Aligned {} +impl Alignment for Aligned {} + +/// The byte ranges initialized in `T` are also initialized in the referent. +/// +/// Formally: uninitialized bytes may only be present in `Ptr`'s referent +/// where they are guaranteed to be present in `T`. This is a dynamic property: +/// if, at a particular byte offset, a valid enum discriminant is set, the +/// subsequent bytes may only have uninitialized bytes as specificed by the +/// corresponding enum. +/// +/// Formally, given `len = size_of_val_raw(ptr)`, at every byte offset, `b`, in +/// the range `[0, len)`: +/// - If, in any instance `t: T` of length `len`, the byte at offset `b` in `t` +/// is initialized, then the byte at offset `b` within `*ptr` must be +/// initialized. +/// - Let `c` be the contents of the byte range `[0, b)` in `*ptr`. Let `S` be +/// the subset of valid instances of `T` of length `len` which contain `c` in +/// the offset range `[0, b)`. If, in any instance of `t: T` in `S`, the byte +/// at offset `b` in `t` is initialized, then the byte at offset `b` in `*ptr` +/// must be initialized. +/// +/// Pragmatically, this means that if `*ptr` is guaranteed to contain an enum +/// type at a particular offset, and the enum discriminant stored in `*ptr` +/// corresponds to a valid variant of that enum type, then it is guaranteed +/// that the appropriate bytes of `*ptr` are initialized as defined by that +/// variant's bit validity (although note that the variant may contain another +/// enum type, in which case the same rules apply depending on the state of +/// its discriminant, and so on recursively). +pub enum AsInitialized {} +impl Validity for AsInitialized {} + +/// The byte ranges in the referent are fully initialized. In other words, if +/// the referent is `N` bytes long, then it contains a bit-valid `[u8; N]`. +pub enum Initialized {} +impl Validity for Initialized {} + +/// The referent is bit-valid for `T`. +pub enum Valid {} +impl Validity for Valid {} + +pub mod aliasing_safety { + use super::*; + use crate::Immutable; + + /// Pointer conversions which do not violate aliasing. + /// + /// `U: AliasingSafe` implies that a pointer conversion from `T` to + /// `U` does not violate the aliasing invariant, `A`. This can be because + /// `A` is [`Exclusive`] or because neither `T` nor `U` permit interior + /// mutability. + /// + /// # Safety + /// + /// `U: AliasingSafe` if either of the following conditions holds: + /// - `A` is [`Exclusive`] + /// - `T` and `U` both implement [`Immutable`] + #[doc(hidden)] + pub unsafe trait AliasingSafe {} + + #[doc(hidden)] + pub trait AliasingSafeReason: sealed::Sealed {} + impl AliasingSafeReason for (R,) {} + + /// The conversion is safe because only one live `Ptr` or reference may exist to + /// the referent bytes at a time. + #[derive(Copy, Clone, Debug)] + #[doc(hidden)] + pub enum BecauseExclusive {} + impl AliasingSafeReason for BecauseExclusive {} + + /// The conversion is safe because no live `Ptr`s or references permit mutation. + #[derive(Copy, Clone, Debug)] + #[doc(hidden)] + pub enum BecauseImmutable {} + impl AliasingSafeReason for BecauseImmutable {} + + /// SAFETY: `T: AliasingSafe` because for all + /// `Ptr<'a, T, I>` such that `I::Aliasing = Exclusive`, there cannot exist + /// other live references to the memory referenced by `Ptr`. + unsafe impl AliasingSafe for U {} + + /// SAFETY: `U: AliasingSafe` because for all `Ptr<'a, T, + /// I>` and `Ptr<'a, U, I>` such that `I::Aliasing = A`, all live references and + /// live `Ptr`s agree, by invariant on `Immutable`, that the referenced bytes + /// contain no `UnsafeCell`s, and thus do not permit mutation except via + /// exclusive aliasing. + unsafe impl AliasingSafe for U + where + A: Aliasing, + T: Immutable, + U: Immutable, + { + } + + /// This ensures that `U: AliasingSafe` implies `T: AliasingSafe` in + /// a manner legible to rustc, which in turn means we can write simpler bounds in + /// some places. + /// + /// SAFETY: Per `U: AliasingSafe`, either: + /// - `A` is `Exclusive` + /// - `T` and `U` both implement `Immutable` + /// + /// Neither property depends on which of `T` and `U` are in the `Self` position + /// vs the first type parameter position. + unsafe impl AliasingSafe for T + where + A: Aliasing, + R: AliasingSafeReason, + U: AliasingSafe, + { + } +} + +use sealed::Sealed; +mod sealed { + use super::*; + + pub trait Sealed {} + + impl Sealed for Any {} + + impl Sealed for Shared {} + impl Sealed for Exclusive {} + + impl Sealed for Aligned {} + + impl Sealed for AsInitialized {} + impl Sealed for Initialized {} + impl Sealed for Valid {} + + impl Sealed for (A, AA, V) {} + + impl Sealed for super::aliasing_safety::BecauseExclusive {} + impl Sealed for super::aliasing_safety::BecauseImmutable {} + impl Sealed for (S,) {} +} diff --git a/src/pointer/mod.rs b/src/pointer/mod.rs index dd7b162d7e..9329f157c9 100644 --- a/src/pointer/mod.rs +++ b/src/pointer/mod.rs @@ -8,12 +8,17 @@ //! Abstractions over raw pointers. -mod aliasing_safety; mod inner; +#[doc(hidden)] +pub mod invariant; mod ptr; -pub use aliasing_safety::{AliasingSafe, AliasingSafeReason, BecauseExclusive, BecauseImmutable}; -pub use ptr::{invariant, Ptr}; +#[doc(hidden)] +pub use invariant::aliasing_safety::{ + AliasingSafe, AliasingSafeReason, BecauseExclusive, BecauseImmutable, +}; +#[doc(hidden)] +pub use ptr::Ptr; use crate::Unaligned; diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index ad5d91f2e4..1352c6a48d 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -8,7 +8,7 @@ use core::{marker::PhantomData, ptr::NonNull}; -use super::inner::PtrInner; +use super::{inner::PtrInner, invariant::*}; use crate::{CastType, KnownLayout}; /// Module used to gate access to [`Ptr`]'s fields. @@ -16,7 +16,7 @@ mod def { use super::*; #[cfg(doc)] - use super::invariant; + use super::super::invariant; /// A raw pointer with more restrictions. /// @@ -127,148 +127,6 @@ mod def { pub use def::Ptr; -/// The parameterized invariants of a [`Ptr`]. -/// -/// Invariants are encoded as ([`Aliasing`], [`Alignment`], [`Validity`]) -/// triples implementing the [`Invariants`] trait. -#[doc(hidden)] -#[allow(missing_copy_implementations, missing_debug_implementations)] -pub mod invariant { - /// The invariants of a [`Ptr`][super::Ptr]. - pub trait Invariants: Sealed { - type Aliasing: Aliasing; - type Alignment: Alignment; - type Validity: Validity; - } - - impl Invariants for (A, AA, V) { - type Aliasing = A; - type Alignment = AA; - type Validity = V; - } - - /// The aliasing invariant of a [`Ptr`][super::Ptr]. - pub trait Aliasing: Sealed { - /// Is `Self` [`Exclusive`]? - #[doc(hidden)] - const IS_EXCLUSIVE: bool; - } - - /// The alignment invariant of a [`Ptr`][super::Ptr]. - pub trait Alignment: Sealed {} - - /// The validity invariant of a [`Ptr`][super::Ptr]. - pub trait Validity: Sealed {} - - /// An [`Aliasing`] invariant which is either [`Shared`] or [`Exclusive`]. - /// - /// # Safety - /// - /// Given `A: Reference`, callers may assume that either `A = Shared` or `A - /// = Exclusive`. - pub trait Reference: Aliasing + Sealed {} - - /// No requirement - any invariant is allowed. - pub enum Any {} - impl Aliasing for Any { - const IS_EXCLUSIVE: bool = false; - } - impl Alignment for Any {} - impl Validity for Any {} - - /// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a T`. - /// - /// The referent of a shared-aliased `Ptr` may be concurrently referenced by - /// any number of shared-aliased `Ptr` or `&T` references, and may not be - /// concurrently referenced by any exclusively-aliased `Ptr`s or `&mut T` - /// references. The referent must not be mutated, except via - /// [`UnsafeCell`]s. - /// - /// [`UnsafeCell`]: core::cell::UnsafeCell - pub enum Shared {} - impl Aliasing for Shared { - const IS_EXCLUSIVE: bool = false; - } - impl Reference for Shared {} - - /// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a mut T`. - /// - /// The referent of an exclusively-aliased `Ptr` may not be concurrently - /// referenced by any other `Ptr`s or references, and may not be accessed - /// (read or written) other than via this `Ptr`. - pub enum Exclusive {} - impl Aliasing for Exclusive { - const IS_EXCLUSIVE: bool = true; - } - impl Reference for Exclusive {} - - /// The referent is aligned: for `Ptr`, the referent's address is a - /// multiple of the `T`'s alignment. - pub enum Aligned {} - impl Alignment for Aligned {} - - /// The byte ranges initialized in `T` are also initialized in the referent. - /// - /// Formally: uninitialized bytes may only be present in `Ptr`'s referent - /// where they are guaranteed to be present in `T`. This is a dynamic - /// property: if, at a particular byte offset, a valid enum discriminant is - /// set, the subsequent bytes may only have uninitialized bytes as - /// specificed by the corresponding enum. - /// - /// Formally, given `len = size_of_val_raw(ptr)`, at every byte offset, `b`, - /// in the range `[0, len)`: - /// - If, in any instance `t: T` of length `len`, the byte at offset `b` in - /// `t` is initialized, then the byte at offset `b` within `*ptr` must be - /// initialized. - /// - Let `c` be the contents of the byte range `[0, b)` in `*ptr`. Let `S` - /// be the subset of valid instances of `T` of length `len` which contain - /// `c` in the offset range `[0, b)`. If, in any instance of `t: T` in - /// `S`, the byte at offset `b` in `t` is initialized, then the byte at - /// offset `b` in `*ptr` must be initialized. - /// - /// Pragmatically, this means that if `*ptr` is guaranteed to contain an - /// enum type at a particular offset, and the enum discriminant stored in - /// `*ptr` corresponds to a valid variant of that enum type, then it is - /// guaranteed that the appropriate bytes of `*ptr` are initialized as - /// defined by that variant's bit validity (although note that the variant - /// may contain another enum type, in which case the same rules apply - /// depending on the state of its discriminant, and so on recursively). - pub enum AsInitialized {} - impl Validity for AsInitialized {} - - /// The byte ranges in the referent are fully initialized. In other words, - /// if the referent is `N` bytes long, then it contains a bit-valid `[u8; - /// N]`. - pub enum Initialized {} - impl Validity for Initialized {} - - /// The referent is bit-valid for `T`. - pub enum Valid {} - impl Validity for Valid {} - - use sealed::Sealed; - mod sealed { - use super::*; - - pub trait Sealed {} - - impl Sealed for Any {} - - impl Sealed for Shared {} - impl Sealed for Exclusive {} - - impl Sealed for Aligned {} - - impl Sealed for AsInitialized {} - impl Sealed for Initialized {} - impl Sealed for Valid {} - - impl Sealed for (A, AA, V) {} - } -} - -pub(crate) use invariant::*; - /// External trait implementations on [`Ptr`]. mod _external { use super::*; @@ -583,7 +441,7 @@ mod _transitions { /// This allows code which is generic over aliasing to down-cast to a /// concrete aliasing. /// - /// [`Exclusive`]: invariant::Exclusive + /// [`Exclusive`]: crate::pointer::invariant::Exclusive #[inline] pub(crate) fn into_exclusive_or_post_monomorphization_error( self, @@ -660,7 +518,7 @@ mod _transitions { /// The caller promises that `self` satisfies the aliasing requirement /// of `Exclusive`. /// - /// [`Exclusive`]: invariant::Exclusive + /// [`Exclusive`]: crate::pointer::invariant::Exclusive #[inline] pub(crate) const unsafe fn assume_exclusive( self, @@ -834,7 +692,7 @@ mod _transitions { /// Casts of the referent type. mod _casts { use super::*; - use crate::{pointer::aliasing_safety::*, CastError, SizeError}; + use crate::{pointer::invariant::aliasing_safety::*, CastError, SizeError}; impl<'a, T, I> Ptr<'a, T, I> where From 51475bd245d49ed7615234434f6ccf851a3ec18d Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Mon, 14 Oct 2024 11:34:54 -0700 Subject: [PATCH 16/96] [pointer] Match variance of references (#1894) When the aliasing mode is `Any`, `Ptr<'a, T>` is invariant in `'a` and `T`. When the aliasing mode is `Shared` or `Exclusive`, `Ptr` has the same variance as `&'a T` and `&'a mut T` respectively. Makes progress on #1839 --- src/pointer/invariant.rs | 19 +++++++++++++++++++ src/pointer/ptr.rs | 5 +++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/pointer/invariant.rs b/src/pointer/invariant.rs index abd019a391..cec4bbfc0d 100644 --- a/src/pointer/invariant.rs +++ b/src/pointer/invariant.rs @@ -31,6 +31,12 @@ pub trait Aliasing: Sealed { /// Is `Self` [`Exclusive`]? #[doc(hidden)] const IS_EXCLUSIVE: bool; + + /// A type which has the correct variance over `'a` and `T` for this + /// aliasing invariant. `Ptr` stores a `::Variance<'a, T>` to inherit this variance. + #[doc(hidden)] + type Variance<'a, T: 'a + ?Sized>; } /// The alignment invariant of a [`Ptr`][super::Ptr]. @@ -51,6 +57,17 @@ pub trait Reference: Aliasing + Sealed {} pub enum Any {} impl Aliasing for Any { const IS_EXCLUSIVE: bool = false; + + // SAFETY: Since we don't know what aliasing model this is, we have to be + // conservative. Invariance is strictly more restrictive than any other + // variance model, so this can never cause soundness issues. + // + // `fn() -> T` and `fn(T) -> ()` are covariant and contravariant in `T`, + // respectively. [1] Thus, `fn(T) -> T` is invariant in `T`. Thus, `fn(&'a + // T) -> &'a T` is invariant in `'a` and `T`. + // + // [1] https://doc.rust-lang.org/1.81.0/reference/subtyping.html#variance + type Variance<'a, T: 'a + ?Sized> = fn(&'a T) -> &'a T; } impl Alignment for Any {} impl Validity for Any {} @@ -66,6 +83,7 @@ impl Validity for Any {} pub enum Shared {} impl Aliasing for Shared { const IS_EXCLUSIVE: bool = false; + type Variance<'a, T: 'a + ?Sized> = &'a T; } impl Reference for Shared {} @@ -77,6 +95,7 @@ impl Reference for Shared {} pub enum Exclusive {} impl Aliasing for Exclusive { const IS_EXCLUSIVE: bool = true; + type Variance<'a, T: 'a + ?Sized> = &'a mut T; } impl Reference for Exclusive {} diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index 1352c6a48d..f9d96b1566 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -56,6 +56,7 @@ mod def { /// [`I::Validity`](invariant::Validity). // SAFETY: `PtrInner<'a, T>` is covariant over `'a` and `T`. ptr: PtrInner<'a, T>, + _variance: PhantomData<::Variance<'a, T>>, _invariants: PhantomData, } @@ -93,7 +94,7 @@ mod def { let ptr = unsafe { PtrInner::new(ptr) }; // SAFETY: The caller has promised (in 6 - 8) to satisfy all safety // invariants of `Ptr`. - Self { ptr, _invariants: PhantomData } + Self { ptr, _variance: PhantomData, _invariants: PhantomData } } /// Constructs a new `Ptr` from a [`PtrInner`]. @@ -111,7 +112,7 @@ mod def { pub(super) const unsafe fn from_inner(ptr: PtrInner<'a, T>) -> Ptr<'a, T, I> { // SAFETY: The caller has promised to satisfy all safety invariants // of `Ptr`. - Self { ptr, _invariants: PhantomData } + Self { ptr, _variance: PhantomData, _invariants: PhantomData } } /// Converts this `Ptr` to a [`PtrInner`]. From f80a65d0cfe2a78b1ce9d8c71c84b5b230abef59 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Mon, 14 Oct 2024 12:11:09 -0700 Subject: [PATCH 17/96] [pointer] Make invariants opaque, more ergonomic (#1895) Closes #1876 --- src/pointer/invariant.rs | 68 ++++++++++++++++++++++++++++------------ src/pointer/ptr.rs | 38 +++++++++------------- 2 files changed, 63 insertions(+), 43 deletions(-) diff --git a/src/pointer/invariant.rs b/src/pointer/invariant.rs index cec4bbfc0d..f85b1271a3 100644 --- a/src/pointer/invariant.rs +++ b/src/pointer/invariant.rs @@ -18,12 +18,40 @@ pub trait Invariants: Sealed { type Aliasing: Aliasing; type Alignment: Alignment; type Validity: Validity; + + /// Invariants identical to `Self` except with a different aliasing + /// invariant. + type WithAliasing: Invariants< + Aliasing = A, + Alignment = Self::Alignment, + Validity = Self::Validity, + >; + + /// Invariants identical to `Self` except with a different alignment + /// invariant. + type WithAlignment: Invariants< + Aliasing = Self::Aliasing, + Alignment = A, + Validity = Self::Validity, + >; + + /// Invariants identical to `Self` except with a different validity + /// invariant. + type WithValidity: Invariants< + Aliasing = Self::Aliasing, + Alignment = Self::Alignment, + Validity = V, + >; } impl Invariants for (A, AA, V) { type Aliasing = A; type Alignment = AA; type Validity = V; + + type WithAliasing = (AB, AA, V); + type WithAlignment = (A, AB, V); + type WithValidity = (A, AA, VB); } /// The aliasing invariant of a [`Ptr`][super::Ptr]. @@ -107,29 +135,29 @@ impl Alignment for Aligned {} /// The byte ranges initialized in `T` are also initialized in the referent. /// /// Formally: uninitialized bytes may only be present in `Ptr`'s referent -/// where they are guaranteed to be present in `T`. This is a dynamic property: -/// if, at a particular byte offset, a valid enum discriminant is set, the -/// subsequent bytes may only have uninitialized bytes as specificed by the -/// corresponding enum. +/// where they are guaranteed to be present in `T`. This is a dynamic +/// property: if, at a particular byte offset, a valid enum discriminant is +/// set, the subsequent bytes may only have uninitialized bytes as +/// specificed by the corresponding enum. /// -/// Formally, given `len = size_of_val_raw(ptr)`, at every byte offset, `b`, in -/// the range `[0, len)`: -/// - If, in any instance `t: T` of length `len`, the byte at offset `b` in `t` -/// is initialized, then the byte at offset `b` within `*ptr` must be +/// Formally, given `len = size_of_val_raw(ptr)`, at every byte offset, `b`, +/// in the range `[0, len)`: +/// - If, in any instance `t: T` of length `len`, the byte at offset `b` in +/// `t` is initialized, then the byte at offset `b` within `*ptr` must be /// initialized. -/// - Let `c` be the contents of the byte range `[0, b)` in `*ptr`. Let `S` be -/// the subset of valid instances of `T` of length `len` which contain `c` in -/// the offset range `[0, b)`. If, in any instance of `t: T` in `S`, the byte -/// at offset `b` in `t` is initialized, then the byte at offset `b` in `*ptr` -/// must be initialized. +/// - Let `c` be the contents of the byte range `[0, b)` in `*ptr`. Let `S` +/// be the subset of valid instances of `T` of length `len` which contain +/// `c` in the offset range `[0, b)`. If, in any instance of `t: T` in +/// `S`, the byte at offset `b` in `t` is initialized, then the byte at +/// offset `b` in `*ptr` must be initialized. /// -/// Pragmatically, this means that if `*ptr` is guaranteed to contain an enum -/// type at a particular offset, and the enum discriminant stored in `*ptr` -/// corresponds to a valid variant of that enum type, then it is guaranteed -/// that the appropriate bytes of `*ptr` are initialized as defined by that -/// variant's bit validity (although note that the variant may contain another -/// enum type, in which case the same rules apply depending on the state of -/// its discriminant, and so on recursively). +/// Pragmatically, this means that if `*ptr` is guaranteed to contain an +/// enum type at a particular offset, and the enum discriminant stored in +/// `*ptr` corresponds to a valid variant of that enum type, then it is +/// guaranteed that the appropriate bytes of `*ptr` are initialized as +/// defined by that variant's bit validity (although note that the variant +/// may contain another enum type, in which case the same rules apply +/// depending on the state of its discriminant, and so on recursively). pub enum AsInitialized {} impl Validity for AsInitialized {} diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index f9d96b1566..d828e284ea 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -401,9 +401,7 @@ mod _conversions { { /// Converts a `Ptr` an unaligned `T` into a `Ptr` to an aligned /// `Unalign`. - pub(crate) fn into_unalign( - self, - ) -> Ptr<'a, crate::Unalign, (I::Aliasing, Aligned, I::Validity)> { + pub(crate) fn into_unalign(self) -> Ptr<'a, crate::Unalign, I::WithAlignment> { // SAFETY: // - This cast preserves provenance. // - This cast preserves address. `Unalign` promises to have the @@ -421,7 +419,7 @@ mod _conversions { // SAFETY: `Unalign` promises to have alignment 1, and so it is // trivially aligned. let ptr = unsafe { ptr.assume_alignment::() }; - ptr + ptr.unify_invariants() } } } @@ -446,7 +444,7 @@ mod _transitions { #[inline] pub(crate) fn into_exclusive_or_post_monomorphization_error( self, - ) -> Ptr<'a, T, (Exclusive, I::Alignment, I::Validity)> { + ) -> Ptr<'a, T, I::WithAliasing> { // NOTE(https://github.com/rust-lang/rust/issues/131625): We do this // rather than just having `Aliasing::IS_EXCLUSIVE` have the panic // behavior because doing it that way causes rustdoc to fail while @@ -506,7 +504,7 @@ mod _transitions { #[inline] pub(crate) const unsafe fn assume_aliasing( self, - ) -> Ptr<'a, T, (A, I::Alignment, I::Validity)> { + ) -> Ptr<'a, T, I::WithAliasing> { // SAFETY: The caller promises that `self` satisfies the aliasing // requirements of `A`. unsafe { self.assume_invariants() } @@ -523,7 +521,7 @@ mod _transitions { #[inline] pub(crate) const unsafe fn assume_exclusive( self, - ) -> Ptr<'a, T, (Exclusive, I::Alignment, I::Validity)> { + ) -> Ptr<'a, T, I::WithAliasing> { // SAFETY: The caller promises that `self` satisfies the aliasing // requirements of `Exclusive`. unsafe { self.assume_aliasing::() } @@ -539,7 +537,7 @@ mod _transitions { #[inline] pub(crate) const unsafe fn assume_alignment( self, - ) -> Ptr<'a, T, (I::Aliasing, A, I::Validity)> { + ) -> Ptr<'a, T, I::WithAlignment> { // SAFETY: The caller promises that `self`'s referent is // well-aligned for `T` if required by `A` . unsafe { self.assume_invariants() } @@ -549,7 +547,7 @@ mod _transitions { /// on success. pub(crate) fn bikeshed_try_into_aligned( self, - ) -> Result, AlignmentError> + ) -> Result>, AlignmentError> where T: Sized, { @@ -567,9 +565,7 @@ mod _transitions { #[inline] // TODO(#859): Reconsider the name of this method before making it // public. - pub(crate) const fn bikeshed_recall_aligned( - self, - ) -> Ptr<'a, T, (I::Aliasing, Aligned, I::Validity)> + pub(crate) const fn bikeshed_recall_aligned(self) -> Ptr<'a, T, I::WithAlignment> where T: crate::Unaligned, { @@ -588,9 +584,7 @@ mod _transitions { #[doc(hidden)] #[must_use] #[inline] - pub const unsafe fn assume_validity( - self, - ) -> Ptr<'a, T, (I::Aliasing, I::Alignment, V)> { + pub const unsafe fn assume_validity(self) -> Ptr<'a, T, I::WithValidity> { // SAFETY: The caller promises that `self`'s referent conforms to // the validity requirement of `V`. unsafe { self.assume_invariants() } @@ -605,9 +599,7 @@ mod _transitions { #[doc(hidden)] #[must_use] #[inline] - pub const unsafe fn assume_initialized( - self, - ) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Initialized)> { + pub const unsafe fn assume_initialized(self) -> Ptr<'a, T, I::WithValidity> { // SAFETY: The caller has promised to uphold the safety // preconditions. unsafe { self.assume_validity::() } @@ -622,7 +614,7 @@ mod _transitions { #[doc(hidden)] #[must_use] #[inline] - pub const unsafe fn assume_valid(self) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Valid)> { + pub const unsafe fn assume_valid(self) -> Ptr<'a, T, I::WithValidity> { // SAFETY: The caller has promised to uphold the safety // preconditions. unsafe { self.assume_validity::() } @@ -634,7 +626,7 @@ mod _transitions { #[inline] // TODO(#859): Reconsider the name of this method before making it // public. - pub const fn bikeshed_recall_valid(self) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Valid)> + pub const fn bikeshed_recall_valid(self) -> Ptr<'a, T, I::WithValidity> where T: crate::FromBytes, I: Invariants, @@ -661,7 +653,7 @@ mod _transitions { #[inline] pub(crate) fn try_into_valid( mut self, - ) -> Result, ValidityError> + ) -> Result>, ValidityError> where T: TryFromBytes, I::Aliasing: Reference, @@ -670,7 +662,7 @@ mod _transitions { // This call may panic. If that happens, it doesn't cause any soundness // issues, as we have not generated any invalid state which we need to // fix before returning. - if T::is_bit_valid(self.reborrow().forget_aligned()) { + if T::is_bit_valid(self.reborrow().forget_aligned().unify_invariants()) { // SAFETY: If `T::is_bit_valid`, code may assume that `self` // contains a bit-valid instance of `Self`. Ok(unsafe { self.assume_valid() }) @@ -683,7 +675,7 @@ mod _transitions { #[doc(hidden)] #[must_use] #[inline] - pub const fn forget_aligned(self) -> Ptr<'a, T, (I::Aliasing, Any, I::Validity)> { + pub const fn forget_aligned(self) -> Ptr<'a, T, I::WithAlignment> { // SAFETY: `Any` is less restrictive than `Aligned`. unsafe { self.assume_invariants() } } From 85a12e2f5a81b8e3eadb3869b3e4811c26820961 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Mon, 14 Oct 2024 13:00:54 -0700 Subject: [PATCH 18/96] [pointer] Simplify AliasingSafe, rename to Read (#1908) `AliasingSafe` is really about whether a pointer permits unsynchronized reads - either because the referent contains no `UnsafeCell`s or because the aliasing mode is `Exclusive`. Previously, `AliasingSafe` was not named consistent with this meaning, and was a function of a *pair* of types rather than of a single type. This commit fixes both oversights. While we're here, we also add `Read` bounds in some places, allowing us to simplify many safety comments. --- src/impls.rs | 1 + src/lib.rs | 4 +- src/pointer/invariant.rs | 112 ++++++------------ src/pointer/mod.rs | 10 +- src/pointer/ptr.rs | 88 +++++++++----- src/util/macro_util.rs | 19 +-- src/util/macros.rs | 4 +- zerocopy-derive/src/enum.rs | 17 +-- zerocopy-derive/src/lib.rs | 2 +- zerocopy-derive/src/output_tests.rs | 24 ++-- zerocopy-derive/tests/include.rs | 2 +- .../tests/struct_try_from_bytes.rs | 6 +- zerocopy-derive/tests/union_try_from_bytes.rs | 6 +- 13 files changed, 138 insertions(+), 157 deletions(-) diff --git a/src/impls.rs b/src/impls.rs index 0c84a115f1..53df018ae9 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -950,6 +950,7 @@ mod simd { #[cfg(test)] mod tests { use super::*; + use crate::pointer::invariant; #[test] fn test_impls() { diff --git a/src/lib.rs b/src/lib.rs index c939c1db6a..2db7816c0e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -360,7 +360,7 @@ use core::{ slice, }; -use crate::pointer::{invariant, BecauseExclusive}; +use crate::pointer::invariant::{self, BecauseExclusive}; #[cfg(any(feature = "alloc", test))] extern crate alloc; @@ -372,7 +372,7 @@ use core::alloc::Layout; // Used by `TryFromBytes::is_bit_valid`. #[doc(hidden)] -pub use crate::pointer::{BecauseImmutable, Maybe, MaybeAligned, Ptr}; +pub use crate::pointer::{invariant::BecauseImmutable, Maybe, MaybeAligned, Ptr}; // Used by `KnownLayout`. #[doc(hidden)] pub use crate::layout::*; diff --git a/src/pointer/invariant.rs b/src/pointer/invariant.rs index f85b1271a3..c48e0a196c 100644 --- a/src/pointer/invariant.rs +++ b/src/pointer/invariant.rs @@ -170,78 +170,41 @@ impl Validity for Initialized {} pub enum Valid {} impl Validity for Valid {} -pub mod aliasing_safety { - use super::*; - use crate::Immutable; - - /// Pointer conversions which do not violate aliasing. - /// - /// `U: AliasingSafe` implies that a pointer conversion from `T` to - /// `U` does not violate the aliasing invariant, `A`. This can be because - /// `A` is [`Exclusive`] or because neither `T` nor `U` permit interior - /// mutability. - /// - /// # Safety - /// - /// `U: AliasingSafe` if either of the following conditions holds: - /// - `A` is [`Exclusive`] - /// - `T` and `U` both implement [`Immutable`] - #[doc(hidden)] - pub unsafe trait AliasingSafe {} - - #[doc(hidden)] - pub trait AliasingSafeReason: sealed::Sealed {} - impl AliasingSafeReason for (R,) {} - - /// The conversion is safe because only one live `Ptr` or reference may exist to - /// the referent bytes at a time. - #[derive(Copy, Clone, Debug)] - #[doc(hidden)] - pub enum BecauseExclusive {} - impl AliasingSafeReason for BecauseExclusive {} - - /// The conversion is safe because no live `Ptr`s or references permit mutation. - #[derive(Copy, Clone, Debug)] - #[doc(hidden)] - pub enum BecauseImmutable {} - impl AliasingSafeReason for BecauseImmutable {} - - /// SAFETY: `T: AliasingSafe` because for all - /// `Ptr<'a, T, I>` such that `I::Aliasing = Exclusive`, there cannot exist - /// other live references to the memory referenced by `Ptr`. - unsafe impl AliasingSafe for U {} - - /// SAFETY: `U: AliasingSafe` because for all `Ptr<'a, T, - /// I>` and `Ptr<'a, U, I>` such that `I::Aliasing = A`, all live references and - /// live `Ptr`s agree, by invariant on `Immutable`, that the referenced bytes - /// contain no `UnsafeCell`s, and thus do not permit mutation except via - /// exclusive aliasing. - unsafe impl AliasingSafe for U - where - A: Aliasing, - T: Immutable, - U: Immutable, - { - } - - /// This ensures that `U: AliasingSafe` implies `T: AliasingSafe` in - /// a manner legible to rustc, which in turn means we can write simpler bounds in - /// some places. - /// - /// SAFETY: Per `U: AliasingSafe`, either: - /// - `A` is `Exclusive` - /// - `T` and `U` both implement `Immutable` - /// - /// Neither property depends on which of `T` and `U` are in the `Self` position - /// vs the first type parameter position. - unsafe impl AliasingSafe for T - where - A: Aliasing, - R: AliasingSafeReason, - U: AliasingSafe, - { - } -} +/// [`Ptr`](crate::Ptr) referents that permit unsynchronized read operations. +/// +/// `T: Read` implies that a pointer to `T` with aliasing `A` permits +/// unsynchronized read oeprations. This can be because `A` is [`Exclusive`] or +/// because `T` does not permit interior mutation. +/// +/// # Safety +/// +/// `T: Read` if either of the following conditions holds: +/// - `A` is [`Exclusive`] +/// - `T` implements [`Immutable`](crate::Immutable) +/// +/// As a consequence, if `T: Read`, then any `Ptr` is +/// permitted to perform unsynchronized reads from its referent. +pub trait Read {} + +impl Read for T {} +impl Read for T {} + +/// Used to disambiguate [`Read`] impls. +pub trait ReadReason: Sealed {} + +/// Unsynchronized reads are permitted because only one live [`Ptr`](crate::Ptr) +/// or reference may exist to the referent bytes at a time. +#[derive(Copy, Clone, Debug)] +#[doc(hidden)] +pub enum BecauseExclusive {} +impl ReadReason for BecauseExclusive {} + +/// Unsynchronized reads are permitted because no live [`Ptr`](crate::Ptr)s or +/// references permit interior mutation. +#[derive(Copy, Clone, Debug)] +#[doc(hidden)] +pub enum BecauseImmutable {} +impl ReadReason for BecauseImmutable {} use sealed::Sealed; mod sealed { @@ -262,7 +225,6 @@ mod sealed { impl Sealed for (A, AA, V) {} - impl Sealed for super::aliasing_safety::BecauseExclusive {} - impl Sealed for super::aliasing_safety::BecauseImmutable {} - impl Sealed for (S,) {} + impl Sealed for BecauseImmutable {} + impl Sealed for BecauseExclusive {} } diff --git a/src/pointer/mod.rs b/src/pointer/mod.rs index 9329f157c9..ceda0c6bd0 100644 --- a/src/pointer/mod.rs +++ b/src/pointer/mod.rs @@ -14,9 +14,7 @@ pub mod invariant; mod ptr; #[doc(hidden)] -pub use invariant::aliasing_safety::{ - AliasingSafe, AliasingSafeReason, BecauseExclusive, BecauseImmutable, -}; +pub use invariant::{BecauseExclusive, BecauseImmutable, Read, ReadReason}; #[doc(hidden)] pub use ptr::Ptr; @@ -50,11 +48,11 @@ where pub fn read_unaligned(self) -> T where T: Copy, - R: AliasingSafeReason, - T: AliasingSafe, + R: invariant::ReadReason, + T: invariant::Read, { // SAFETY: By invariant on `MaybeAligned`, `raw` contains - // validly-initialized data for `T`. By `T: AliasingSafe`, we are + // validly-initialized data for `T`. By `T: Read`, we are // permitted to perform a read of `self`'s referent. unsafe { self.as_inner().read_unaligned() } } diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index d828e284ea..78bf23d1b3 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -377,7 +377,7 @@ mod _conversions { // byte ranges. Since `p` and the returned pointer address the // same byte range, they refer to `UnsafeCell`s at the same byte // ranges. - let c = unsafe { self.cast_unsized(|p| T::cast_into_inner(p)) }; + let c = unsafe { self.cast_unsized_unchecked(|p| T::cast_into_inner(p)) }; // SAFETY: By invariant on `TransparentWrapper`, since `self` // satisfies the alignment invariant `I::Alignment`, `c` (of type // `T::Inner`) satisfies the given "applied" alignment invariant. @@ -411,7 +411,7 @@ mod _conversions { // `UnsafeCell`s at the same locations as `p`. let ptr = unsafe { #[allow(clippy::as_conversions)] - self.cast_unsized(|p: *mut T| p as *mut crate::Unalign) + self.cast_unsized_unchecked(|p: *mut T| p as *mut crate::Unalign) }; // SAFETY: `Unalign` promises to have the same bit validity as // `T`. @@ -651,13 +651,14 @@ mod _transitions { /// On error, unsafe code may rely on this method's returned /// `ValidityError` containing `self`. #[inline] - pub(crate) fn try_into_valid( + pub(crate) fn try_into_valid( mut self, ) -> Result>, ValidityError> where - T: TryFromBytes, + T: TryFromBytes + Read, I::Aliasing: Reference, I: Invariants, + R: crate::pointer::ReadReason, { // This call may panic. If that happens, it doesn't cause any soundness // issues, as we have not generated any invalid state which we need to @@ -685,14 +686,19 @@ mod _transitions { /// Casts of the referent type. mod _casts { use super::*; - use crate::{pointer::invariant::aliasing_safety::*, CastError, SizeError}; + use crate::{CastError, SizeError}; impl<'a, T, I> Ptr<'a, T, I> where T: 'a + ?Sized, I: Invariants, { - /// Casts to a different (unsized) target type. + /// Casts to a different (unsized) target type without checking interior + /// mutability. + /// + /// Callers should prefer [`cast_unsized`] where possible. + /// + /// [`cast_unsized`]: Ptr::cast_unsized /// /// # Safety /// @@ -705,7 +711,7 @@ mod _casts { /// exist in `*p` #[doc(hidden)] #[inline] - pub unsafe fn cast_unsized *mut U>( + pub unsafe fn cast_unsized_unchecked *mut U>( self, cast: F, ) -> Ptr<'a, U, (I::Aliasing, Any, Any)> { @@ -767,6 +773,34 @@ mod _casts { // 8. `ptr`, trivially, conforms to the validity invariant of `Any`. unsafe { Ptr::new(ptr) } } + + /// Casts to a different (unsized) target type. + /// + /// # Safety + /// + /// The caller promises that `u = cast(p)` is a pointer cast with the + /// following properties: + /// - `u` addresses a subset of the bytes addressed by `p` + /// - `u` has the same provenance as `p` + #[doc(hidden)] + #[inline] + pub unsafe fn cast_unsized(self, cast: F) -> Ptr<'a, U, (I::Aliasing, Any, Any)> + where + T: Read, + U: 'a + ?Sized + Read, + R: ReadReason, + S: ReadReason, + F: FnOnce(*mut T) -> *mut U, + { + // SAFETY: Because `T` and `U` both implement `Read`, + // either: + // - `I::Aliasing` is `Exclusive` + // - `T` and `U` are both `Immutable`, in which case they trivially + // contain `UnsafeCell`s at identical locations + // + // The caller promises all other safety preconditions. + unsafe { self.cast_unsized_unchecked(cast) } + } } impl<'a, T, I> Ptr<'a, T, I> @@ -778,8 +812,9 @@ mod _casts { #[allow(clippy::wrong_self_convention)] pub(crate) fn as_bytes(self) -> Ptr<'a, [u8], (I::Aliasing, Aligned, Valid)> where - [u8]: AliasingSafe, - R: AliasingSafeReason, + R: ReadReason, + T: Read, + I::Aliasing: Reference, { let bytes = match T::size_of_val_raw(self.as_inner().as_non_null()) { Some(bytes) => bytes, @@ -796,10 +831,6 @@ mod _casts { // pointer's address, and `bytes` is the length of `p`, so the // returned pointer addresses the same bytes as `p` // - `slice_from_raw_parts_mut` and `.cast` both preserve provenance - // - Because `[u8]: AliasingSafe`, either: - // - `I::Aliasing` is `Exclusive` - // - `T` and `[u8]` are both `Immutable`, in which case they - // trivially contain `UnsafeCell`s at identical locations let ptr: Ptr<'a, [u8], _> = unsafe { self.cast_unsized(|p: *mut T| { #[allow(clippy::as_conversions)] @@ -878,9 +909,9 @@ mod _casts { CastError, > where - R: AliasingSafeReason, + R: ReadReason, I::Aliasing: Reference, - U: 'a + ?Sized + KnownLayout + AliasingSafe<[u8], I::Aliasing, R>, + U: 'a + ?Sized + KnownLayout + Read, { let (inner, remainder) = self.as_inner().try_cast_into(cast_type, meta).map_err(|err| { @@ -893,12 +924,13 @@ mod _casts { })?; // SAFETY: - // 0. Since `U: AliasingSafe<[u8], I::Aliasing, _>`, either: + // 0. Since `U: Read`, either: // - `I::Aliasing` is `Exclusive`, in which case both `src` and // `ptr` conform to `Exclusive` - // - `I::Aliasing` is `Shared` or `Any` and both `U` and `[u8]` - // are `Immutable`. In this case, neither pointer permits - // mutation, and so `Shared` aliasing is satisfied. + // - `I::Aliasing` is `Shared` or `Any` and `U` is `Immutable` + // (we already know that `[u8]: Immutable`). In this case, + // neither `U` nor `[u8]` permit mutation, and so `Shared` + // aliasing is satisfied. // 1. `ptr` conforms to the alignment invariant of `Aligned` because // it is derived from `try_cast_into`, which promises that the // object described by `target` is validly aligned for `U`. @@ -939,8 +971,8 @@ mod _casts { ) -> Result, CastError> where I::Aliasing: Reference, - U: 'a + ?Sized + KnownLayout + AliasingSafe<[u8], I::Aliasing, R>, - R: AliasingSafeReason, + U: 'a + ?Sized + KnownLayout + Read, + R: ReadReason, { match self.try_cast_into(CastType::Prefix, meta) { Ok((slf, remainder)) => { @@ -984,11 +1016,8 @@ mod _casts { #[must_use] #[inline(always)] pub fn get_mut(self) -> Ptr<'a, T, I> { - // SAFETY: - // - The closure uses an `as` cast, which preserves address range - // and provenance. - // - We require `I: Invariants`, so we are not - // required to uphold `UnsafeCell` equality. + // SAFETY: The closure uses an `as` cast, which preserves address + // range and provenance. #[allow(clippy::as_conversions)] let ptr = unsafe { self.cast_unsized(|p| p as *mut T) }; @@ -1034,7 +1063,8 @@ mod _project { /// /// # Safety /// - /// `project` has the same safety preconditions as `cast_unsized`. + /// `project` has the same safety preconditions as + /// `cast_unsized_unchecked`. #[doc(hidden)] #[inline] pub unsafe fn project( @@ -1046,8 +1076,8 @@ mod _project { // `Initialized` pointer, we could remove this method entirely. // SAFETY: This method has the same safety preconditions as - // `cast_unsized`. - let ptr = unsafe { self.cast_unsized(projector) }; + // `cast_unsized_unchecked`. + let ptr = unsafe { self.cast_unsized_unchecked(projector) }; // SAFETY: If all of the bytes of `self` are initialized (as // promised by `I: Invariants`), then any diff --git a/src/util/macro_util.rs b/src/util/macro_util.rs index b94e82c573..1064a5b76b 100644 --- a/src/util/macro_util.rs +++ b/src/util/macro_util.rs @@ -25,10 +25,7 @@ use core::mem::{self, ManuallyDrop}; use core::ptr::{self, NonNull}; use crate::{ - pointer::{ - invariant::{self, Invariants}, - AliasingSafe, AliasingSafeReason, BecauseExclusive, BecauseImmutable, - }, + pointer::invariant::{self, BecauseExclusive, BecauseImmutable, Invariants, ReadReason}, Immutable, IntoBytes, Ptr, TryFromBytes, Unalign, ValidityError, }; @@ -527,11 +524,11 @@ fn try_cast_or_pme( ValidityError, Dst>, > where - Src: IntoBytes, - Dst: TryFromBytes + AliasingSafe, + Src: IntoBytes + invariant::Read, + Dst: TryFromBytes + invariant::Read, I: Invariants, I::Aliasing: invariant::Reference, - R: AliasingSafeReason, + R: ReadReason, { static_assert!(Src, Dst => mem::size_of::() == mem::size_of::()); @@ -540,10 +537,6 @@ where // because we assert above that the size of `Dst` equal to the size of // `Src`. // - `p as *mut Dst` is a provenance-preserving cast - // - Because `Dst: AliasingSafe`, either: - // - `I::Aliasing` is `Exclusive` - // - `Src` and `Dst` are both `Immutable`, in which case they - // trivially contain `UnsafeCell`s at identical locations #[allow(clippy::as_conversions)] let c_ptr = unsafe { src.cast_unsized(|p| p as *mut Dst) }; @@ -563,10 +556,6 @@ where // `ptr`, because we assert above that the size of `Dst` is equal // to the size of `Src`. // - `p as *mut Src` is a provenance-preserving cast - // - Because `Dst: AliasingSafe`, either: - // - `I::Aliasing` is `Exclusive` - // - `Src` and `Dst` are both `Immutable`, in which case they - // trivially contain `UnsafeCell`s at identical locations #[allow(clippy::as_conversions)] let ptr = unsafe { ptr.cast_unsized(|p| p as *mut Src) }; // SAFETY: `ptr` is `src`, and has the same alignment invariant. diff --git a/src/util/macros.rs b/src/util/macros.rs index 32fd7dd69a..3e6fbed8a1 100644 --- a/src/util/macros.rs +++ b/src/util/macros.rs @@ -151,7 +151,7 @@ macro_rules! unsafe_impl { // - The caller has promised that the destination type has // `UnsafeCell`s at the same byte ranges as the source type. #[allow(clippy::as_conversions)] - let candidate = unsafe { candidate.cast_unsized::<$repr, _>(|p| p as *mut _) }; + let candidate = unsafe { candidate.cast_unsized_unchecked::<$repr, _>(|p| p as *mut _) }; // SAFETY: The caller has promised that the referenced memory region // will contain a valid `$repr`. @@ -175,7 +175,7 @@ macro_rules! unsafe_impl { // - The caller has promised that the destination type has // `UnsafeCell`s at the same byte ranges as the source type. #[allow(clippy::as_conversions)] - let $candidate = unsafe { candidate.cast_unsized::<$repr, _>(|p| p as *mut _) }; + let $candidate = unsafe { candidate.cast_unsized_unchecked::<$repr, _>(|p| p as *mut _) }; // Restore the invariant that the referent bytes are initialized. // SAFETY: The above cast does not uninitialize any referent bytes; diff --git a/zerocopy-derive/src/enum.rs b/zerocopy-derive/src/enum.rs index 7836117231..2bc9e033a7 100644 --- a/zerocopy-derive/src/enum.rs +++ b/zerocopy-derive/src/enum.rs @@ -259,15 +259,15 @@ pub(crate) fn derive_is_bit_valid( // `UnsafeCell`s will have the same location as in the // original type. let variant = unsafe { - variants.cast_unsized( + variants.cast_unsized_unchecked( |p: *mut ___ZerocopyVariants #ty_generics| { p as *mut #variant_struct_ident #ty_generics } ) }; - // SAFETY: `cast_unsized` removes the initialization - // invariant from `p`, so we re-assert that all of the bytes - // are initialized. + // SAFETY: `cast_unsized_unchecked` removes the + // initialization invariant from `p`, so we re-assert that + // all of the bytes are initialized. let variant = unsafe { variant.assume_initialized() }; < #variant_struct_ident #ty_generics as #trait_path @@ -321,7 +321,7 @@ pub(crate) fn derive_is_bit_valid( // - There are no `UnsafeCell`s in the tag because it is a // primitive integer. let tag_ptr = unsafe { - candidate.reborrow().cast_unsized(|p: *mut Self| { + candidate.reborrow().cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyTagPrimitive }) }; @@ -343,12 +343,13 @@ pub(crate) fn derive_is_bit_valid( // original enum, and so preserves the locations of any // `UnsafeCell`s. let raw_enum = unsafe { - candidate.cast_unsized(|p: *mut Self| { + candidate.cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyRawEnum #ty_generics }) }; - // SAFETY: `cast_unsized` removes the initialization invariant from - // `p`, so we re-assert that all of the bytes are initialized. + // SAFETY: `cast_unsized_unchecked` removes the initialization + // invariant from `p`, so we re-assert that all of the bytes are + // initialized. let raw_enum = unsafe { raw_enum.assume_initialized() }; // SAFETY: // - This projection returns a subfield of `this` using diff --git a/zerocopy-derive/src/lib.rs b/zerocopy-derive/src/lib.rs index 45c2de5d67..5d2f3ef43f 100644 --- a/zerocopy-derive/src/lib.rs +++ b/zerocopy-derive/src/lib.rs @@ -476,7 +476,7 @@ fn derive_try_from_bytes_union( // is guaranteed to be no more strict than this definition. See #696 // for a more in-depth discussion. fn is_bit_valid<___ZerocopyAliasing>( - mut candidate: ::zerocopy::Maybe<'_, Self, ___ZerocopyAliasing> + mut candidate: ::zerocopy::Maybe<'_, Self,___ZerocopyAliasing> ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, diff --git a/zerocopy-derive/src/output_tests.rs b/zerocopy-derive/src/output_tests.rs index 8bf8e5bb13..2ad4eb72d8 100644 --- a/zerocopy-derive/src/output_tests.rs +++ b/zerocopy-derive/src/output_tests.rs @@ -589,13 +589,13 @@ fn test_try_from_bytes_enum() { } let tag = { let tag_ptr = unsafe { - candidate.reborrow().cast_unsized(|p: *mut Self| { p as *mut ___ZerocopyTagPrimitive }) + candidate.reborrow().cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyTagPrimitive }) }; let tag_ptr = unsafe { tag_ptr.assume_initialized() }; tag_ptr.bikeshed_recall_valid().read_unaligned::<::zerocopy::BecauseImmutable>() }; let raw_enum = unsafe { - candidate.cast_unsized(|p: *mut Self| { p as *mut ___ZerocopyRawEnum<'a, N, X, Y> }) + candidate.cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyRawEnum<'a, N, X, Y> }) }; let raw_enum = unsafe { raw_enum.assume_initialized() }; let variants = unsafe { @@ -608,7 +608,7 @@ fn test_try_from_bytes_enum() { ___ZEROCOPY_TAG_UnitLike => true, ___ZEROCOPY_TAG_StructLike => { let variant = unsafe { - variants.cast_unsized(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { + variants.cast_unsized_unchecked(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { p as *mut ___ZerocopyVariantStruct_StructLike<'a, N, X, Y> }) }; @@ -618,7 +618,7 @@ fn test_try_from_bytes_enum() { } ___ZEROCOPY_TAG_TupleLike => { let variant = unsafe { - variants.cast_unsized(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { + variants.cast_unsized_unchecked(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { p as *mut ___ZerocopyVariantStruct_TupleLike<'a, N, X, Y> }) }; @@ -880,13 +880,13 @@ fn test_try_from_bytes_enum() { } let tag = { let tag_ptr = unsafe { - candidate.reborrow().cast_unsized(|p: *mut Self| { p as *mut ___ZerocopyTagPrimitive }) + candidate.reborrow().cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyTagPrimitive }) }; let tag_ptr = unsafe { tag_ptr.assume_initialized() }; tag_ptr.bikeshed_recall_valid().read_unaligned::<::zerocopy::BecauseImmutable>() }; let raw_enum = unsafe { - candidate.cast_unsized(|p: *mut Self| { p as *mut ___ZerocopyRawEnum<'a, N, X, Y> }) + candidate.cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyRawEnum<'a, N, X, Y> }) }; let raw_enum = unsafe { raw_enum.assume_initialized() }; let variants = unsafe { @@ -899,7 +899,7 @@ fn test_try_from_bytes_enum() { ___ZEROCOPY_TAG_UnitLike => true, ___ZEROCOPY_TAG_StructLike => { let variant = unsafe { - variants.cast_unsized(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { + variants.cast_unsized_unchecked(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { p as *mut ___ZerocopyVariantStruct_StructLike<'a, N, X, Y> }) }; @@ -909,7 +909,7 @@ fn test_try_from_bytes_enum() { } ___ZEROCOPY_TAG_TupleLike => { let variant = unsafe { - variants.cast_unsized(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { + variants.cast_unsized_unchecked(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { p as *mut ___ZerocopyVariantStruct_TupleLike<'a, N, X, Y> }) }; @@ -1171,13 +1171,13 @@ fn test_try_from_bytes_enum() { } let tag = { let tag_ptr = unsafe { - candidate.reborrow().cast_unsized(|p: *mut Self| { p as *mut ___ZerocopyTagPrimitive }) + candidate.reborrow().cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyTagPrimitive }) }; let tag_ptr = unsafe { tag_ptr.assume_initialized() }; tag_ptr.bikeshed_recall_valid().read_unaligned::<::zerocopy::BecauseImmutable>() }; let raw_enum = unsafe { - candidate.cast_unsized(|p: *mut Self| { p as *mut ___ZerocopyRawEnum<'a, N, X, Y> }) + candidate.cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyRawEnum<'a, N, X, Y> }) }; let raw_enum = unsafe { raw_enum.assume_initialized() }; let variants = unsafe { @@ -1190,7 +1190,7 @@ fn test_try_from_bytes_enum() { ___ZEROCOPY_TAG_UnitLike => true, ___ZEROCOPY_TAG_StructLike => { let variant = unsafe { - variants.cast_unsized(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { + variants.cast_unsized_unchecked(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { p as *mut ___ZerocopyVariantStruct_StructLike<'a, N, X, Y> }) }; @@ -1200,7 +1200,7 @@ fn test_try_from_bytes_enum() { } ___ZEROCOPY_TAG_TupleLike => { let variant = unsafe { - variants.cast_unsized(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { + variants.cast_unsized_unchecked(|p: *mut ___ZerocopyVariants<'a, N, X, Y>| { p as *mut ___ZerocopyVariantStruct_TupleLike<'a, N, X, Y> }) }; diff --git a/zerocopy-derive/tests/include.rs b/zerocopy-derive/tests/include.rs index 7a4bf32890..964ff17fb9 100644 --- a/zerocopy-derive/tests/include.rs +++ b/zerocopy-derive/tests/include.rs @@ -119,7 +119,7 @@ pub mod util { let ptr = super::imp::Ptr::from_ref(&buf); // SAFETY: `T` and `MaybeUninit` have the same layout, so this is a // size-preserving cast. It is also a provenance-preserving cast. - let ptr = unsafe { ptr.cast_unsized(|p| p as *mut T) }; + let ptr = unsafe { ptr.cast_unsized_unchecked(|p| p as *mut T) }; // SAFETY: This is intentionally unsound; see the preceding comment. let ptr = unsafe { ptr.assume_initialized() }; assert!(::is_bit_valid(ptr)); diff --git a/zerocopy-derive/tests/struct_try_from_bytes.rs b/zerocopy-derive/tests/struct_try_from_bytes.rs index 5aa9d70695..8a4c70536c 100644 --- a/zerocopy-derive/tests/struct_try_from_bytes.rs +++ b/zerocopy-derive/tests/struct_try_from_bytes.rs @@ -78,7 +78,7 @@ fn two_bad() { // the same bytes as `c`. // - The cast preserves provenance. // - Neither the input nor output types contain any `UnsafeCell`s. - let candidate = unsafe { candidate.cast_unsized(|p| p as *mut Two) }; + let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut Two) }; // SAFETY: `candidate`'s referent is as-initialized as `Two`. let candidate = unsafe { candidate.assume_initialized() }; @@ -108,7 +108,7 @@ fn un_sized() { // the same bytes as `c`. // - The cast preserves provenance. // - Neither the input nor output types contain any `UnsafeCell`s. - let candidate = unsafe { candidate.cast_unsized(|p| p as *mut Unsized) }; + let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut Unsized) }; // SAFETY: `candidate`'s referent is as-initialized as `Two`. let candidate = unsafe { candidate.assume_initialized() }; @@ -163,7 +163,7 @@ fn test_maybe_from_bytes() { // the same bytes as `c`. // - The cast preserves provenance. // - Neither the input nor output types contain any `UnsafeCell`s. - let candidate = unsafe { candidate.cast_unsized(|p| p as *mut MaybeFromBytes) }; + let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut MaybeFromBytes) }; // SAFETY: `[u8]` consists entirely of initialized bytes. let candidate = unsafe { candidate.assume_initialized() }; diff --git a/zerocopy-derive/tests/union_try_from_bytes.rs b/zerocopy-derive/tests/union_try_from_bytes.rs index 8c3183e5d8..f2bd84ee4e 100644 --- a/zerocopy-derive/tests/union_try_from_bytes.rs +++ b/zerocopy-derive/tests/union_try_from_bytes.rs @@ -73,7 +73,7 @@ fn two_bad() { // the same bytes as `c`. // - The cast preserves provenance. // - Neither the input nor output types contain any `UnsafeCell`s. - let candidate = unsafe { candidate.cast_unsized(|p| p as *mut Two) }; + let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut Two) }; // SAFETY: `candidate`'s referent is as-initialized as `Two`. let candidate = unsafe { candidate.assume_initialized() }; @@ -102,7 +102,7 @@ fn bool_and_zst() { // the same bytes as `c`. // - The cast preserves provenance. // - Neither the input nor output types contain any `UnsafeCell`s. - let candidate = unsafe { candidate.cast_unsized(|p| p as *mut BoolAndZst) }; + let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut BoolAndZst) }; // SAFETY: `candidate`'s referent is fully initialized. let candidate = unsafe { candidate.assume_initialized() }; @@ -130,7 +130,7 @@ fn test_maybe_from_bytes() { // the same bytes as `c`. // - The cast preserves provenance. // - Neither the input nor output types contain any `UnsafeCell`s. - let candidate = unsafe { candidate.cast_unsized(|p| p as *mut MaybeFromBytes) }; + let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut MaybeFromBytes) }; // SAFETY: `[u8]` consists entirely of initialized bytes. let candidate = unsafe { candidate.assume_initialized() }; From ae43fce851eec5d23c71855831abf2dc0c19f6b3 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Mon, 14 Oct 2024 14:02:18 -0700 Subject: [PATCH 19/96] [pointer] Rename Any -> Unknown/Inaccessible (#1909) For aliasing, use `Inaccessible`. For alignment and validity, use `Unknown`. --- src/pointer/invariant.rs | 31 +++++++++++++++++-------------- src/pointer/mod.rs | 4 ++-- src/pointer/ptr.rs | 33 +++++++++++++++++++-------------- src/util/macro_util.rs | 2 +- src/util/mod.rs | 4 ++-- 5 files changed, 41 insertions(+), 33 deletions(-) diff --git a/src/pointer/invariant.rs b/src/pointer/invariant.rs index c48e0a196c..4d963398c7 100644 --- a/src/pointer/invariant.rs +++ b/src/pointer/invariant.rs @@ -81,24 +81,26 @@ pub trait Validity: Sealed {} /// Exclusive`. pub trait Reference: Aliasing + Sealed {} -/// No requirement - any invariant is allowed. -pub enum Any {} -impl Aliasing for Any { +/// It is unknown whether any invariant holds. +pub enum Unknown {} + +impl Alignment for Unknown {} +impl Validity for Unknown {} + +/// The `Ptr<'a, T>` does not permit any reads or writes from or to its referent. +pub enum Inaccessible {} + +impl Aliasing for Inaccessible { const IS_EXCLUSIVE: bool = false; - // SAFETY: Since we don't know what aliasing model this is, we have to be - // conservative. Invariance is strictly more restrictive than any other - // variance model, so this can never cause soundness issues. - // - // `fn() -> T` and `fn(T) -> ()` are covariant and contravariant in `T`, - // respectively. [1] Thus, `fn(T) -> T` is invariant in `T`. Thus, `fn(&'a - // T) -> &'a T` is invariant in `'a` and `T`. + // SAFETY: Inaccessible `Ptr`s permit neither reads nor writes, and so it + // doesn't matter how long the referent actually lives. Thus, covariance is + // fine (and is chosen because it is maximally permissive). Shared + // references are covariant [1]. // // [1] https://doc.rust-lang.org/1.81.0/reference/subtyping.html#variance - type Variance<'a, T: 'a + ?Sized> = fn(&'a T) -> &'a T; + type Variance<'a, T: 'a + ?Sized> = &'a T; } -impl Alignment for Any {} -impl Validity for Any {} /// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a T`. /// @@ -212,8 +214,9 @@ mod sealed { pub trait Sealed {} - impl Sealed for Any {} + impl Sealed for Unknown {} + impl Sealed for Inaccessible {} impl Sealed for Shared {} impl Sealed for Exclusive {} diff --git a/src/pointer/mod.rs b/src/pointer/mod.rs index ceda0c6bd0..e7b8c0e802 100644 --- a/src/pointer/mod.rs +++ b/src/pointer/mod.rs @@ -24,14 +24,14 @@ use crate::Unaligned; /// to [`TryFromBytes::is_bit_valid`]. /// /// [`TryFromBytes::is_bit_valid`]: crate::TryFromBytes::is_bit_valid -pub type Maybe<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Any> = +pub type Maybe<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Unknown> = Ptr<'a, T, (Aliasing, Alignment, invariant::Initialized)>; /// A semi-user-facing wrapper type representing a maybe-aligned reference, for /// use in [`TryFromBytes::is_bit_valid`]. /// /// [`TryFromBytes::is_bit_valid`]: crate::TryFromBytes::is_bit_valid -pub type MaybeAligned<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Any> = +pub type MaybeAligned<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Unknown> = Ptr<'a, T, (Aliasing, Alignment, invariant::Valid)>; // These methods are defined on the type alias, `MaybeAligned`, so as to bring diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index 78bf23d1b3..b8ecc4afb0 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -676,8 +676,8 @@ mod _transitions { #[doc(hidden)] #[must_use] #[inline] - pub const fn forget_aligned(self) -> Ptr<'a, T, I::WithAlignment> { - // SAFETY: `Any` is less restrictive than `Aligned`. + pub const fn forget_aligned(self) -> Ptr<'a, T, I::WithAlignment> { + // SAFETY: `Unknown` is less restrictive than `Aligned`. unsafe { self.assume_invariants() } } } @@ -706,15 +706,14 @@ mod _casts { /// following properties: /// - `u` addresses a subset of the bytes addressed by `p` /// - `u` has the same provenance as `p` - /// - If `I::Aliasing` is [`Any`] or [`Shared`], `UnsafeCell`s in `*u` - /// must exist at ranges identical to those at which `UnsafeCell`s - /// exist in `*p` + /// - If `I::Aliasing` is [`Shared`], `UnsafeCell`s in `*u` must exist + /// at ranges identical to those at which `UnsafeCell`s exist in `*p` #[doc(hidden)] #[inline] pub unsafe fn cast_unsized_unchecked *mut U>( self, cast: F, - ) -> Ptr<'a, U, (I::Aliasing, Any, Any)> { + ) -> Ptr<'a, U, (I::Aliasing, Unknown, Unknown)> { let ptr = cast(self.as_inner().as_non_null().as_ptr()); // SAFETY: Caller promises that `cast` returns a pointer whose @@ -768,9 +767,11 @@ mod _casts { // pointer will permit mutation of this byte during `'a`, by // invariant on `self`, no other code assumes that this will // not happen. + // - `Inaccessible`: There are no restrictions we need to uphold. // 7. `ptr`, trivially, conforms to the alignment invariant of - // `Any`. - // 8. `ptr`, trivially, conforms to the validity invariant of `Any`. + // `Unknown`. + // 8. `ptr`, trivially, conforms to the validity invariant of + // `Unknown`. unsafe { Ptr::new(ptr) } } @@ -784,7 +785,10 @@ mod _casts { /// - `u` has the same provenance as `p` #[doc(hidden)] #[inline] - pub unsafe fn cast_unsized(self, cast: F) -> Ptr<'a, U, (I::Aliasing, Any, Any)> + pub unsafe fn cast_unsized( + self, + cast: F, + ) -> Ptr<'a, U, (I::Aliasing, Unknown, Unknown)> where T: Read, U: 'a + ?Sized + Read, @@ -927,10 +931,11 @@ mod _casts { // 0. Since `U: Read`, either: // - `I::Aliasing` is `Exclusive`, in which case both `src` and // `ptr` conform to `Exclusive` - // - `I::Aliasing` is `Shared` or `Any` and `U` is `Immutable` - // (we already know that `[u8]: Immutable`). In this case, - // neither `U` nor `[u8]` permit mutation, and so `Shared` - // aliasing is satisfied. + // - `I::Aliasing` is `Shared` or `Inaccessible` and `U` is + // `Immutable` (we already know that `[u8]: Immutable`). In + // this case, neither `U` nor `[u8]` permit mutation, and so + // `Shared` aliasing is satisfied. `Inaccessible` is trivially + // satisfied since it imposes no requirements. // 1. `ptr` conforms to the alignment invariant of `Aligned` because // it is derived from `try_cast_into`, which promises that the // object described by `target` is validly aligned for `U`. @@ -1070,7 +1075,7 @@ mod _project { pub unsafe fn project( self, projector: impl FnOnce(*mut T) -> *mut U, - ) -> Ptr<'a, U, (I::Aliasing, Any, Initialized)> { + ) -> Ptr<'a, U, (I::Aliasing, Unknown, Initialized)> { // TODO(#1122): If `cast_unsized` were able to reason that, when // casting from an `Initialized` pointer, the result is another // `Initialized` pointer, we could remove this method entirely. diff --git a/src/util/macro_util.rs b/src/util/macro_util.rs index 1064a5b76b..7a904438ee 100644 --- a/src/util/macro_util.rs +++ b/src/util/macro_util.rs @@ -520,7 +520,7 @@ pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( fn try_cast_or_pme( src: Ptr<'_, Src, I>, ) -> Result< - Ptr<'_, Dst, (I::Aliasing, invariant::Any, invariant::Valid)>, + Ptr<'_, Dst, (I::Aliasing, invariant::Unknown, invariant::Valid)>, ValidityError, Dst>, > where diff --git a/src/util/mod.rs b/src/util/mod.rs index b00437cd7c..dd2e5bdd61 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -99,11 +99,11 @@ impl ValidityVariance for Covariant { pub enum Invariant {} impl AlignmentVariance for Invariant { - type Applied = invariant::Any; + type Applied = invariant::Unknown; } impl ValidityVariance for Invariant { - type Applied = invariant::Any; + type Applied = invariant::Unknown; } // SAFETY: From 0665b90f4d310b1d832e7d11a9bc09e343eb89c7 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Mon, 14 Oct 2024 14:51:15 -0700 Subject: [PATCH 20/96] [pointer] Support generic invariant mapping (#1896) This commit adds a framework which supports encoding in the type system any `I -> I` mapping where `I` is any `Invariant` type. This permits us to make `cast_unsized`'s return value smarter, and as a result, allows us to remove a lot of `unsafe` code. Makes progress on #1122 --- src/impls.rs | 9 -- src/pointer/invariant.rs | 193 +++++++++++++++++++++++----- src/pointer/ptr.rs | 37 +++--- src/util/macro_util.rs | 2 +- src/util/macros.rs | 13 +- zerocopy-derive/src/enum.rs | 12 -- zerocopy-derive/src/output_tests.rs | 12 -- 7 files changed, 184 insertions(+), 94 deletions(-) diff --git a/src/impls.rs b/src/impls.rs index 53df018ae9..0a552d5231 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -290,15 +290,6 @@ safety_comment! { /// because `NonZeroXxx` and `xxx` have the same size. [1] Neither `r` /// nor `t` refer to any `UnsafeCell`s because neither `NonZeroXxx` [2] /// nor `xxx` do. - /// - Since the closure takes a `&xxx` argument, given a `Maybe<'a, - /// NonZeroXxx>` which satisfies the preconditions of - /// `TryFromBytes::::is_bit_valid`, it must be guaranteed - /// that the memory referenced by that `MabyeValid` always contains a - /// valid `xxx`. Since `NonZeroXxx`'s bytes are always initialized [1], - /// `is_bit_valid`'s precondition requires that the same is true of its - /// argument. Since `xxx`'s only bit validity invariant is that its - /// bytes must be initialized, this memory is guaranteed to contain a - /// valid `xxx`. /// - The impl must only return `true` for its argument if the original /// `Maybe` refers to a valid `NonZeroXxx`. The only /// `xxx` which is not also a valid `NonZeroXxx` is 0. [1] diff --git a/src/pointer/invariant.rs b/src/pointer/invariant.rs index 4d963398c7..c6543207dc 100644 --- a/src/pointer/invariant.rs +++ b/src/pointer/invariant.rs @@ -65,13 +65,22 @@ pub trait Aliasing: Sealed { /// Aliasing>::Variance<'a, T>` to inherit this variance. #[doc(hidden)] type Variance<'a, T: 'a + ?Sized>; + + #[doc(hidden)] + type MappedTo: Aliasing; } /// The alignment invariant of a [`Ptr`][super::Ptr]. -pub trait Alignment: Sealed {} +pub trait Alignment: Sealed { + #[doc(hidden)] + type MappedTo: Alignment; +} /// The validity invariant of a [`Ptr`][super::Ptr]. -pub trait Validity: Sealed {} +pub trait Validity: Sealed { + #[doc(hidden)] + type MappedTo: Validity; +} /// An [`Aliasing`] invariant which is either [`Shared`] or [`Exclusive`]. /// @@ -84,8 +93,12 @@ pub trait Reference: Aliasing + Sealed {} /// It is unknown whether any invariant holds. pub enum Unknown {} -impl Alignment for Unknown {} -impl Validity for Unknown {} +impl Alignment for Unknown { + type MappedTo = M::FromUnknown; +} +impl Validity for Unknown { + type MappedTo = M::FromUnknown; +} /// The `Ptr<'a, T>` does not permit any reads or writes from or to its referent. pub enum Inaccessible {} @@ -100,6 +113,7 @@ impl Aliasing for Inaccessible { // // [1] https://doc.rust-lang.org/1.81.0/reference/subtyping.html#variance type Variance<'a, T: 'a + ?Sized> = &'a T; + type MappedTo = M::FromInaccessible; } /// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a T`. @@ -114,6 +128,7 @@ pub enum Shared {} impl Aliasing for Shared { const IS_EXCLUSIVE: bool = false; type Variance<'a, T: 'a + ?Sized> = &'a T; + type MappedTo = M::FromShared; } impl Reference for Shared {} @@ -126,51 +141,60 @@ pub enum Exclusive {} impl Aliasing for Exclusive { const IS_EXCLUSIVE: bool = true; type Variance<'a, T: 'a + ?Sized> = &'a mut T; + type MappedTo = M::FromExclusive; } impl Reference for Exclusive {} -/// The referent is aligned: for `Ptr`, the referent's address is a multiple -/// of the `T`'s alignment. +/// The referent is aligned: for `Ptr`, the referent's address is a +/// multiple of the `T`'s alignment. pub enum Aligned {} -impl Alignment for Aligned {} +impl Alignment for Aligned { + type MappedTo = M::FromAligned; +} /// The byte ranges initialized in `T` are also initialized in the referent. /// /// Formally: uninitialized bytes may only be present in `Ptr`'s referent -/// where they are guaranteed to be present in `T`. This is a dynamic -/// property: if, at a particular byte offset, a valid enum discriminant is -/// set, the subsequent bytes may only have uninitialized bytes as -/// specificed by the corresponding enum. +/// where they are guaranteed to be present in `T`. This is a dynamic property: +/// if, at a particular byte offset, a valid enum discriminant is set, the +/// subsequent bytes may only have uninitialized bytes as specificed by the +/// corresponding enum. /// -/// Formally, given `len = size_of_val_raw(ptr)`, at every byte offset, `b`, -/// in the range `[0, len)`: -/// - If, in any instance `t: T` of length `len`, the byte at offset `b` in -/// `t` is initialized, then the byte at offset `b` within `*ptr` must be +/// Formally, given `len = size_of_val_raw(ptr)`, at every byte offset, `b`, in +/// the range `[0, len)`: +/// - If, in any instance `t: T` of length `len`, the byte at offset `b` in `t` +/// is initialized, then the byte at offset `b` within `*ptr` must be /// initialized. -/// - Let `c` be the contents of the byte range `[0, b)` in `*ptr`. Let `S` -/// be the subset of valid instances of `T` of length `len` which contain -/// `c` in the offset range `[0, b)`. If, in any instance of `t: T` in -/// `S`, the byte at offset `b` in `t` is initialized, then the byte at -/// offset `b` in `*ptr` must be initialized. +/// - Let `c` be the contents of the byte range `[0, b)` in `*ptr`. Let `S` be +/// the subset of valid instances of `T` of length `len` which contain `c` in +/// the offset range `[0, b)`. If, in any instance of `t: T` in `S`, the byte +/// at offset `b` in `t` is initialized, then the byte at offset `b` in `*ptr` +/// must be initialized. /// -/// Pragmatically, this means that if `*ptr` is guaranteed to contain an -/// enum type at a particular offset, and the enum discriminant stored in -/// `*ptr` corresponds to a valid variant of that enum type, then it is -/// guaranteed that the appropriate bytes of `*ptr` are initialized as -/// defined by that variant's bit validity (although note that the variant -/// may contain another enum type, in which case the same rules apply -/// depending on the state of its discriminant, and so on recursively). +/// Pragmatically, this means that if `*ptr` is guaranteed to contain an enum +/// type at a particular offset, and the enum discriminant stored in `*ptr` +/// corresponds to a valid variant of that enum type, then it is guaranteed +/// that the appropriate bytes of `*ptr` are initialized as defined by that +/// variant's bit validity (although note that the variant may contain another +/// enum type, in which case the same rules apply depending on the state of +/// its discriminant, and so on recursively). pub enum AsInitialized {} -impl Validity for AsInitialized {} +impl Validity for AsInitialized { + type MappedTo = M::FromAsInitialized; +} /// The byte ranges in the referent are fully initialized. In other words, if /// the referent is `N` bytes long, then it contains a bit-valid `[u8; N]`. pub enum Initialized {} -impl Validity for Initialized {} +impl Validity for Initialized { + type MappedTo = M::FromInitialized; +} /// The referent is bit-valid for `T`. pub enum Valid {} -impl Validity for Valid {} +impl Validity for Valid { + type MappedTo = M::FromValid; +} /// [`Ptr`](crate::Ptr) referents that permit unsynchronized read operations. /// @@ -231,3 +255,112 @@ mod sealed { impl Sealed for BecauseImmutable {} impl Sealed for BecauseExclusive {} } + +pub use mapping::*; +mod mapping { + use super::*; + + /// A mapping from one [`Aliasing`] type to another. + /// + /// An `AliasingMapping` is a type-level map which maps one `Aliasing` type + /// to another. It is always "total" in the sense of having a mapping for + /// any `A: Aliasing`. + /// + /// Given `A: Aliasing` and `M: AliasingMapping`, `M` can be applied to `A` + /// as [`MappedAliasing`](MappedAliasing). + /// + /// Mappings are used by [`Ptr`](crate::Ptr) conversion methods to preserve + /// or modify invariants as required by each method's semantics. + pub trait AliasingMapping { + type FromInaccessible: Aliasing; + type FromShared: Aliasing; + type FromExclusive: Aliasing; + } + + /// A mapping from one [`Alignment`] type to another. + /// + /// An `AlignmentMapping` is a type-level map which maps one `Alignment` + /// type to another. It is always "total" in the sense of having a mapping + /// for any `A: Alignment`. + /// + /// Given `A: Alignment` and `M: AlignmentMapping`, `M` can be applied to + /// `A` as [`MappedAlignment`](MappedAlignment). + /// + /// Mappings are used by [`Ptr`](crate::Ptr) conversion methods to preserve + /// or modify invariants as required by each method's semantics. + pub trait AlignmentMapping { + type FromUnknown: Alignment; + type FromAligned: Alignment; + } + + /// A mapping from one [`Validity`] type to another. + /// + /// An `ValidityMapping` is a type-level map which maps one `Validity` type + /// to another. It is always "total" in the sense of having a mapping for + /// any `A: Validity`. + /// + /// Given `V: Validity` and `M: ValidityMapping`, `M` can be applied to `V` + /// as [`MappedValidity`](MappedValidity). + /// + /// Mappings are used by [`Ptr`](crate::Ptr) conversion methods to preserve + /// or modify invariants as required by each method's semantics. + pub trait ValidityMapping { + type FromUnknown: Validity; + type FromAsInitialized: Validity; + type FromInitialized: Validity; + type FromValid: Validity; + } + + /// The application of the [`AliasingMapping`] `M` to the [`Aliasing`] `A`. + #[allow(type_alias_bounds)] + pub type MappedAliasing = A::MappedTo; + + /// The application of the [`AlignmentMapping`] `M` to the [`Alignment`] `A`. + #[allow(type_alias_bounds)] + pub type MappedAlignment = A::MappedTo; + + /// The application of the [`ValidityMapping`] `M` to the [`Validity`] `A`. + #[allow(type_alias_bounds)] + pub type MappedValidity = V::MappedTo; + + impl AliasingMapping + for ((Inaccessible, FromInaccessible), (Shared, FromShared), (Exclusive, FromExclusive)) + { + type FromInaccessible = FromInaccessible; + type FromShared = FromShared; + type FromExclusive = FromExclusive; + } + + impl AlignmentMapping + for ((Unknown, FromUnknown), (Shared, FromAligned)) + { + type FromUnknown = FromUnknown; + type FromAligned = FromAligned; + } + + impl< + FromUnknown: Validity, + FromAsInitialized: Validity, + FromInitialized: Validity, + FromValid: Validity, + > ValidityMapping + for ( + (Unknown, FromUnknown), + (AsInitialized, FromAsInitialized), + (Initialized, FromInitialized), + (Valid, FromValid), + ) + { + type FromUnknown = FromUnknown; + type FromAsInitialized = FromAsInitialized; + type FromInitialized = FromInitialized; + type FromValid = FromValid; + } + + impl ValidityMapping for (Initialized, FromInitialized) { + type FromUnknown = Unknown; + type FromAsInitialized = Unknown; + type FromInitialized = FromInitialized; + type FromValid = Unknown; + } +} diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index b8ecc4afb0..cb729dbb4f 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -713,7 +713,11 @@ mod _casts { pub unsafe fn cast_unsized_unchecked *mut U>( self, cast: F, - ) -> Ptr<'a, U, (I::Aliasing, Unknown, Unknown)> { + ) -> Ptr< + 'a, + U, + (I::Aliasing, Unknown, MappedValidity), + > { let ptr = cast(self.as_inner().as_non_null().as_ptr()); // SAFETY: Caller promises that `cast` returns a pointer whose @@ -770,8 +774,13 @@ mod _casts { // - `Inaccessible`: There are no restrictions we need to uphold. // 7. `ptr`, trivially, conforms to the alignment invariant of // `Unknown`. - // 8. `ptr`, trivially, conforms to the validity invariant of - // `Unknown`. + // 8. If `I::Validity = Unknown`, `AsInitialized`, or `Valid`, the + // output validity invariant is `Unknown`. `ptr` trivially + // conforms to this invariant. If `I::Validity = Initialized`, + // the output validity invariant is `Initialized`. Regardless of + // what subset of `self`'s referent is referred to by `ptr`, if + // all of `self`'s referent is initialized, then the same holds + // of `ptr`'s referent. unsafe { Ptr::new(ptr) } } @@ -788,7 +797,11 @@ mod _casts { pub unsafe fn cast_unsized( self, cast: F, - ) -> Ptr<'a, U, (I::Aliasing, Unknown, Unknown)> + ) -> Ptr< + 'a, + U, + (I::Aliasing, Unknown, MappedValidity), + > where T: Read, U: 'a + ?Sized + Read, @@ -842,14 +855,7 @@ mod _casts { }) }; - let ptr = ptr.bikeshed_recall_aligned(); - - // SAFETY: `ptr`'s referent begins as `Initialized`, denoting that - // all bytes of the referent are initialized bytes. The referent - // type is then casted to `[u8]`, whose only validity invariant is - // that its bytes are initialized. This validity invariant is - // satisfied by the `Initialized` invariant on the starting `ptr`. - unsafe { ptr.assume_validity::() } + ptr.bikeshed_recall_aligned().bikeshed_recall_valid() } } @@ -1082,12 +1088,7 @@ mod _project { // SAFETY: This method has the same safety preconditions as // `cast_unsized_unchecked`. - let ptr = unsafe { self.cast_unsized_unchecked(projector) }; - - // SAFETY: If all of the bytes of `self` are initialized (as - // promised by `I: Invariants`), then any - // subset of those bytes are also all initialized. - unsafe { ptr.assume_validity::() } + unsafe { self.cast_unsized_unchecked(projector) } } } diff --git a/src/util/macro_util.rs b/src/util/macro_util.rs index 7a904438ee..bd8898a4b8 100644 --- a/src/util/macro_util.rs +++ b/src/util/macro_util.rs @@ -421,7 +421,7 @@ macro_rules! assert_align_gt_eq { #[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`. #[macro_export] macro_rules! assert_size_eq { - ($t:ident, $u: ident) => {{ + ($t:ident, $u:ident) => {{ // The comments here should be read in the context of this macro's // invocations in `transmute_ref!` and `transmute_mut!`. if false { diff --git a/src/util/macros.rs b/src/util/macros.rs index 3e6fbed8a1..9b33757e59 100644 --- a/src/util/macros.rs +++ b/src/util/macros.rs @@ -52,10 +52,6 @@ macro_rules! safety_comment { /// referred to by `t`. /// - `r` refers to an object with `UnsafeCell`s at the same byte ranges as /// the object referred to by `t`. -/// - If the provided closure takes a `&$repr` argument, then given a `Ptr<'a, -/// $ty>` which satisfies the preconditions of -/// `TryFromBytes::<$ty>::is_bit_valid`, it must be guaranteed that the -/// memory referenced by that `Ptr` always contains a valid `$repr`. /// - The impl of `is_bit_valid` must only return `true` for its argument /// `Ptr<$repr>` if the original `Ptr<$ty>` refers to a valid `$ty`. macro_rules! unsafe_impl { @@ -153,9 +149,7 @@ macro_rules! unsafe_impl { #[allow(clippy::as_conversions)] let candidate = unsafe { candidate.cast_unsized_unchecked::<$repr, _>(|p| p as *mut _) }; - // SAFETY: The caller has promised that the referenced memory region - // will contain a valid `$repr`. - let $candidate = unsafe { candidate.assume_validity::() }; + let $candidate = candidate.bikeshed_recall_valid(); $is_bit_valid } }; @@ -177,11 +171,6 @@ macro_rules! unsafe_impl { #[allow(clippy::as_conversions)] let $candidate = unsafe { candidate.cast_unsized_unchecked::<$repr, _>(|p| p as *mut _) }; - // Restore the invariant that the referent bytes are initialized. - // SAFETY: The above cast does not uninitialize any referent bytes; - // they remain initialized. - let $candidate = unsafe { $candidate.assume_validity::() }; - $is_bit_valid } }; diff --git a/zerocopy-derive/src/enum.rs b/zerocopy-derive/src/enum.rs index 2bc9e033a7..2392919441 100644 --- a/zerocopy-derive/src/enum.rs +++ b/zerocopy-derive/src/enum.rs @@ -265,10 +265,6 @@ pub(crate) fn derive_is_bit_valid( } ) }; - // SAFETY: `cast_unsized_unchecked` removes the - // initialization invariant from `p`, so we re-assert that - // all of the bytes are initialized. - let variant = unsafe { variant.assume_initialized() }; < #variant_struct_ident #ty_generics as #trait_path >::is_bit_valid(variant) @@ -325,10 +321,6 @@ pub(crate) fn derive_is_bit_valid( p as *mut ___ZerocopyTagPrimitive }) }; - // SAFETY: `tag_ptr` is casted from `candidate`, whose referent - // is `Initialized`. Since we have not written uninitialized - // bytes into the referent, `tag_ptr` is also `Initialized`. - let tag_ptr = unsafe { tag_ptr.assume_initialized() }; tag_ptr.bikeshed_recall_valid().read_unaligned::<::zerocopy::BecauseImmutable>() }; @@ -347,10 +339,6 @@ pub(crate) fn derive_is_bit_valid( p as *mut ___ZerocopyRawEnum #ty_generics }) }; - // SAFETY: `cast_unsized_unchecked` removes the initialization - // invariant from `p`, so we re-assert that all of the bytes are - // initialized. - let raw_enum = unsafe { raw_enum.assume_initialized() }; // SAFETY: // - This projection returns a subfield of `this` using // `addr_of_mut!`. diff --git a/zerocopy-derive/src/output_tests.rs b/zerocopy-derive/src/output_tests.rs index 2ad4eb72d8..3244747171 100644 --- a/zerocopy-derive/src/output_tests.rs +++ b/zerocopy-derive/src/output_tests.rs @@ -591,13 +591,11 @@ fn test_try_from_bytes_enum() { let tag_ptr = unsafe { candidate.reborrow().cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyTagPrimitive }) }; - let tag_ptr = unsafe { tag_ptr.assume_initialized() }; tag_ptr.bikeshed_recall_valid().read_unaligned::<::zerocopy::BecauseImmutable>() }; let raw_enum = unsafe { candidate.cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyRawEnum<'a, N, X, Y> }) }; - let raw_enum = unsafe { raw_enum.assume_initialized() }; let variants = unsafe { raw_enum.project(|p: *mut ___ZerocopyRawEnum<'a, N, X, Y>| { core_reexport::ptr::addr_of_mut!((*p).variants) @@ -612,7 +610,6 @@ fn test_try_from_bytes_enum() { p as *mut ___ZerocopyVariantStruct_StructLike<'a, N, X, Y> }) }; - let variant = unsafe { variant.assume_initialized() }; <___ZerocopyVariantStruct_StructLike<'a, N, X, Y> as ::zerocopy ::TryFromBytes>::is_bit_valid ( variant) } @@ -622,7 +619,6 @@ fn test_try_from_bytes_enum() { p as *mut ___ZerocopyVariantStruct_TupleLike<'a, N, X, Y> }) }; - let variant = unsafe { variant.assume_initialized() }; <___ZerocopyVariantStruct_TupleLike<'a, N, X, Y> as ::zerocopy ::TryFromBytes>::is_bit_valid ( variant) } @@ -882,13 +878,11 @@ fn test_try_from_bytes_enum() { let tag_ptr = unsafe { candidate.reborrow().cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyTagPrimitive }) }; - let tag_ptr = unsafe { tag_ptr.assume_initialized() }; tag_ptr.bikeshed_recall_valid().read_unaligned::<::zerocopy::BecauseImmutable>() }; let raw_enum = unsafe { candidate.cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyRawEnum<'a, N, X, Y> }) }; - let raw_enum = unsafe { raw_enum.assume_initialized() }; let variants = unsafe { raw_enum.project(|p: *mut ___ZerocopyRawEnum<'a, N, X, Y>| { core_reexport::ptr::addr_of_mut!((*p).variants) @@ -903,7 +897,6 @@ fn test_try_from_bytes_enum() { p as *mut ___ZerocopyVariantStruct_StructLike<'a, N, X, Y> }) }; - let variant = unsafe { variant.assume_initialized() }; <___ZerocopyVariantStruct_StructLike<'a, N, X, Y> as ::zerocopy ::TryFromBytes>::is_bit_valid ( variant) } @@ -913,7 +906,6 @@ fn test_try_from_bytes_enum() { p as *mut ___ZerocopyVariantStruct_TupleLike<'a, N, X, Y> }) }; - let variant = unsafe { variant.assume_initialized() }; <___ZerocopyVariantStruct_TupleLike<'a, N, X, Y> as ::zerocopy ::TryFromBytes>::is_bit_valid ( variant) } @@ -1173,13 +1165,11 @@ fn test_try_from_bytes_enum() { let tag_ptr = unsafe { candidate.reborrow().cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyTagPrimitive }) }; - let tag_ptr = unsafe { tag_ptr.assume_initialized() }; tag_ptr.bikeshed_recall_valid().read_unaligned::<::zerocopy::BecauseImmutable>() }; let raw_enum = unsafe { candidate.cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyRawEnum<'a, N, X, Y> }) }; - let raw_enum = unsafe { raw_enum.assume_initialized() }; let variants = unsafe { raw_enum.project(|p: *mut ___ZerocopyRawEnum<'a, N, X, Y>| { core_reexport::ptr::addr_of_mut!((*p).variants) @@ -1194,7 +1184,6 @@ fn test_try_from_bytes_enum() { p as *mut ___ZerocopyVariantStruct_StructLike<'a, N, X, Y> }) }; - let variant = unsafe { variant.assume_initialized() }; <___ZerocopyVariantStruct_StructLike<'a, N, X, Y> as ::zerocopy ::TryFromBytes>::is_bit_valid ( variant) } @@ -1204,7 +1193,6 @@ fn test_try_from_bytes_enum() { p as *mut ___ZerocopyVariantStruct_TupleLike<'a, N, X, Y> }) }; - let variant = unsafe { variant.assume_initialized() }; <___ZerocopyVariantStruct_TupleLike<'a, N, X, Y> as ::zerocopy ::TryFromBytes>::is_bit_valid ( variant) } From 77a5f561a08061b8702bc257c24cd522c5c4fa39 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Tue, 15 Oct 2024 05:57:09 -0700 Subject: [PATCH 21/96] [ci] Roll pinned nightly toolchain (#1915) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 17edaf4ef0..8a8144e3d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.81.0" -pinned-nightly = "nightly-2024-10-13" +pinned-nightly = "nightly-2024-10-14" [package.metadata.docs.rs] all-features = true From 49749b7dbd6c8723c7cb20546987331d16407e20 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Tue, 15 Oct 2024 10:17:22 -0700 Subject: [PATCH 22/96] Remove items deprecated in 0.8 (#1916) gherrit-pr-id: I003d5360d1b7f7882a71490813eca50b39025f14 --- src/deprecated.rs | 211 ---------------------------------------------- src/lib.rs | 168 +----------------------------------- 2 files changed, 3 insertions(+), 376 deletions(-) delete mode 100644 src/deprecated.rs diff --git a/src/deprecated.rs b/src/deprecated.rs deleted file mode 100644 index 4c5e4981c8..0000000000 --- a/src/deprecated.rs +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright 2024 The Fuchsia Authors -// -// Licensed under the 2-Clause BSD License , Apache License, Version 2.0 -// , or the MIT -// license , at your option. -// This file may not be copied, modified, or distributed except according to -// those terms. - -//! Deprecated items. These are kept separate so that they don't clutter up -//! other modules. - -use super::*; - -impl Ref -where - B: ByteSlice, - T: KnownLayout + Immutable + ?Sized, -{ - #[deprecated(since = "0.8.0", note = "renamed to `Ref::from_bytes`")] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - pub fn new(bytes: B) -> Option> { - Self::from_bytes(bytes).ok() - } -} - -impl Ref -where - B: SplitByteSlice, - T: KnownLayout + Immutable + ?Sized, -{ - #[deprecated(since = "0.8.0", note = "renamed to `Ref::from_prefix`")] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - pub fn new_from_prefix(bytes: B) -> Option<(Ref, B)> { - Self::from_prefix(bytes).ok() - } -} - -impl Ref -where - B: SplitByteSlice, - T: KnownLayout + Immutable + ?Sized, -{ - #[deprecated(since = "0.8.0", note = "renamed to `Ref::from_suffix`")] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - pub fn new_from_suffix(bytes: B) -> Option<(B, Ref)> { - Self::from_suffix(bytes).ok() - } -} - -impl Ref -where - B: ByteSlice, - T: Unaligned + KnownLayout + Immutable + ?Sized, -{ - #[deprecated( - since = "0.8.0", - note = "use `Ref::from_bytes`; for `T: Unaligned`, the returned `CastError` implements `Into`" - )] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - pub fn new_unaligned(bytes: B) -> Option> { - Self::from_bytes(bytes).ok() - } -} - -impl Ref -where - B: SplitByteSlice, - T: Unaligned + KnownLayout + Immutable + ?Sized, -{ - #[deprecated( - since = "0.8.0", - note = "use `Ref::from_prefix`; for `T: Unaligned`, the returned `CastError` implements `Into`" - )] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - pub fn new_unaligned_from_prefix(bytes: B) -> Option<(Ref, B)> { - Self::from_prefix(bytes).ok() - } -} - -impl Ref -where - B: SplitByteSlice, - T: Unaligned + KnownLayout + Immutable + ?Sized, -{ - #[deprecated( - since = "0.8.0", - note = "use `Ref::from_suffix`; for `T: Unaligned`, the returned `CastError` implements `Into`" - )] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - pub fn new_unaligned_from_suffix(bytes: B) -> Option<(B, Ref)> { - Self::from_suffix(bytes).ok() - } -} - -impl Ref -where - B: ByteSlice, - T: Immutable, -{ - #[deprecated(since = "0.8.0", note = "`Ref::from_bytes` now supports slices")] - #[doc(hidden)] - #[inline(always)] - pub fn new_slice(bytes: B) -> Option> { - Self::from_bytes(bytes).ok() - } -} - -impl Ref -where - B: ByteSlice, - T: Unaligned + Immutable, -{ - #[deprecated( - since = "0.8.0", - note = "`Ref::from_bytes` now supports slices; for `T: Unaligned`, the returned `CastError` implements `Into`" - )] - #[doc(hidden)] - #[inline(always)] - pub fn new_slice_unaligned(bytes: B) -> Option> { - Ref::from_bytes(bytes).ok() - } -} - -impl<'a, B, T> Ref -where - B: 'a + IntoByteSlice<'a>, - T: FromBytes + Immutable, -{ - #[deprecated(since = "0.8.0", note = "`Ref::into_ref` now supports slices")] - #[doc(hidden)] - #[inline(always)] - pub fn into_slice(self) -> &'a [T] { - Ref::into_ref(self) - } -} - -impl<'a, B, T> Ref -where - B: 'a + IntoByteSliceMut<'a>, - T: FromBytes + IntoBytes + Immutable, -{ - #[deprecated(since = "0.8.0", note = "`Ref::into_mut` now supports slices")] - #[doc(hidden)] - #[inline(always)] - pub fn into_mut_slice(self) -> &'a mut [T] { - Ref::into_mut(self) - } -} - -impl Ref -where - B: SplitByteSlice, - T: Immutable, -{ - #[deprecated(since = "0.8.0", note = "replaced by `Ref::from_prefix_with_elems`")] - #[must_use = "has no side effects"] - #[doc(hidden)] - #[inline(always)] - pub fn new_slice_from_prefix(bytes: B, count: usize) -> Option<(Ref, B)> { - Ref::from_prefix_with_elems(bytes, count).ok() - } - - #[deprecated(since = "0.8.0", note = "replaced by `Ref::from_suffix_with_elems`")] - #[must_use = "has no side effects"] - #[doc(hidden)] - #[inline(always)] - pub fn new_slice_from_suffix(bytes: B, count: usize) -> Option<(B, Ref)> { - Ref::from_suffix_with_elems(bytes, count).ok() - } -} - -impl Ref -where - B: SplitByteSlice, - T: Unaligned + Immutable, -{ - #[deprecated( - since = "0.8.0", - note = "use `Ref::from_prefix_with_elems`; for `T: Unaligned`, the returned `CastError` implements `Into`" - )] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - pub fn new_slice_unaligned_from_prefix(bytes: B, count: usize) -> Option<(Ref, B)> { - Ref::from_prefix_with_elems(bytes, count).ok() - } - - #[deprecated( - since = "0.8.0", - note = "use `Ref::from_suffix_with_elems`; for `T: Unaligned`, the returned `CastError` implements `Into`" - )] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - pub fn new_slice_unaligned_from_suffix(bytes: B, count: usize) -> Option<(B, Ref)> { - Ref::from_suffix_with_elems(bytes, count).ok() - } -} diff --git a/src/lib.rs b/src/lib.rs index 2db7816c0e..0f95b10f29 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -322,7 +322,6 @@ pub mod util; pub mod byte_slice; pub mod byteorder; -mod deprecated; // This module is `pub` so that zerocopy's error types and error handling // documentation is grouped together in a cohesive module. In practice, we // expect most users to use the re-export of `error`'s items to avoid identifier @@ -3061,19 +3060,6 @@ pub unsafe trait FromZeros: TryFromBytes { Ok(unsafe { Box::from_raw(ptr.as_ptr()) }) } - #[deprecated(since = "0.8.0", note = "renamed to `FromZeros::new_box_zeroed_with_elems`")] - #[doc(hidden)] - #[cfg(feature = "alloc")] - #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] - #[must_use = "has no side effects (other than allocation)"] - #[inline(always)] - fn new_box_slice_zeroed(len: usize) -> Result, AllocError> - where - Self: Sized, - { - <[Self]>::new_box_zeroed_with_elems(len) - } - /// Creates a `Vec` from zeroed bytes. /// /// This function is useful for allocating large values of `Vec`s and @@ -4145,8 +4131,8 @@ pub unsafe trait FromBytes: FromZeros { /// ``` /// /// Since an explicit `count` is provided, this method supports types with - /// zero-sized trailing slice elements. Methods such as [`mut_from`] which - /// do not take an explicit count do not support such types. + /// zero-sized trailing slice elements. Methods such as [`mut_from_bytes`] + /// which do not take an explicit count do not support such types. /// /// ``` /// use zerocopy::*; @@ -4164,7 +4150,7 @@ pub unsafe trait FromBytes: FromZeros { /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` /// - /// [`mut_from`]: FromBytes::mut_from + /// [`mut_from_bytes`]: FromBytes::mut_from_bytes #[must_use = "has no side effects"] #[inline] fn mut_from_bytes_with_elems( @@ -4485,105 +4471,6 @@ pub unsafe trait FromBytes: FromZeros { Err(CastError::Validity(i)) => match i {}, } } - - #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::ref_from_bytes`")] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - fn ref_from(source: &[u8]) -> Option<&Self> - where - Self: KnownLayout + Immutable, - { - Self::ref_from_bytes(source).ok() - } - - #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::mut_from_bytes`")] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - fn mut_from(source: &mut [u8]) -> Option<&mut Self> - where - Self: KnownLayout + IntoBytes, - { - Self::mut_from_bytes(source).ok() - } - - #[deprecated(since = "0.8.0", note = "`FromBytes::ref_from_bytes` now supports slices")] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - fn slice_from(source: &[u8]) -> Option<&[Self]> - where - Self: Sized + Immutable, - { - <[Self]>::ref_from_bytes(source).ok() - } - - #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::ref_from_prefix_with_elems`")] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - fn slice_from_prefix(source: &[u8], count: usize) -> Option<(&[Self], &[u8])> - where - Self: Sized + Immutable, - { - <[Self]>::ref_from_prefix_with_elems(source, count).ok() - } - - #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::ref_from_suffix_with_elems`")] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - fn slice_from_suffix(source: &[u8], count: usize) -> Option<(&[u8], &[Self])> - where - Self: Sized + Immutable, - { - <[Self]>::ref_from_suffix_with_elems(source, count).ok() - } - - #[deprecated(since = "0.8.0", note = "`FromBytes::mut_from_bytes` now supports slices")] - #[must_use = "has no side effects"] - #[doc(hidden)] - #[inline(always)] - fn mut_slice_from(source: &mut [u8]) -> Option<&mut [Self]> - where - Self: Sized + IntoBytes, - { - <[Self]>::mut_from_bytes(source).ok() - } - - #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::mut_from_prefix_with_elems`")] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - fn mut_slice_from_prefix(source: &mut [u8], count: usize) -> Option<(&mut [Self], &mut [u8])> - where - Self: Sized + IntoBytes, - { - <[Self]>::mut_from_prefix_with_elems(source, count).ok() - } - - #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::mut_from_suffix_with_elems`")] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - fn mut_slice_from_suffix(source: &mut [u8], count: usize) -> Option<(&mut [u8], &mut [Self])> - where - Self: Sized + IntoBytes, - { - <[Self]>::mut_from_suffix_with_elems(source, count).ok() - } - - #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::read_from_bytes`")] - #[doc(hidden)] - #[must_use = "has no side effects"] - #[inline(always)] - fn read_from(source: &[u8]) -> Option - where - Self: Sized, - { - Self::read_from_bytes(source).ok() - } } /// Interprets the given affix of the given bytes as a `&Self`. @@ -5170,16 +5057,6 @@ pub unsafe trait IntoBytes { } Ok(()) } - - #[deprecated(since = "0.8.0", note = "`IntoBytes::as_bytes_mut` was renamed to `as_mut_bytes`")] - #[doc(hidden)] - #[inline] - fn as_bytes_mut(&mut self) -> &mut [u8] - where - Self: FromBytes, - { - self.as_mut_bytes() - } } /// Analyzes whether a type is [`Unaligned`]. @@ -5324,45 +5201,6 @@ pub unsafe trait Unaligned { Self: Sized; } -#[cfg(feature = "alloc")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] -mod alloc_support { - use super::*; - - /// Extends a `Vec` by pushing `additional` new items onto the end of the - /// vector. The new items are initialized with zeros. - #[doc(hidden)] - #[deprecated(since = "0.8.0", note = "moved to `FromZeros`")] - #[inline(always)] - pub fn extend_vec_zeroed( - v: &mut Vec, - additional: usize, - ) -> Result<(), AllocError> { - ::extend_vec_zeroed(v, additional) - } - - /// Inserts `additional` new items into `Vec` at `position`. The new - /// items are initialized with zeros. - /// - /// # Panics - /// - /// Panics if `position > v.len()`. - #[doc(hidden)] - #[deprecated(since = "0.8.0", note = "moved to `FromZeros`")] - #[inline(always)] - pub fn insert_vec_zeroed( - v: &mut Vec, - position: usize, - additional: usize, - ) -> Result<(), AllocError> { - ::insert_vec_zeroed(v, position, additional) - } -} - -#[cfg(feature = "alloc")] -#[doc(hidden)] -pub use alloc_support::*; - #[cfg(test)] #[allow( clippy::assertions_on_result_states, From f04c344fd9df972053f61f7193f8abf848536534 Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Tue, 15 Oct 2024 17:05:24 -0400 Subject: [PATCH 23/96] Fix flaky `TryFromBytes` tests (#1917) These tests depend on `src` being aligned to multiples of 2. With this commit, that dependency is explicitly enforced. --- src/lib.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0f95b10f29..23359d8279 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1960,7 +1960,7 @@ pub unsafe trait TryFromBytes { /// trailing_dst: [()], /// } /// - /// let src = &[85, 85][..]; + /// let src = 0xCAFEu16.as_bytes(); /// let zsty = ZSTy::try_ref_from_bytes_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` @@ -2067,7 +2067,7 @@ pub unsafe trait TryFromBytes { /// trailing_dst: [()], /// } /// - /// let src = &[85, 85][..]; + /// let src = 0xCAFEu16.as_bytes(); /// let (zsty, _) = ZSTy::try_ref_from_prefix_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` @@ -2156,7 +2156,7 @@ pub unsafe trait TryFromBytes { /// trailing_dst: [()], /// } /// - /// let src = &[85, 85][..]; + /// let src = 0xCAFEu16.as_bytes(); /// let (_, zsty) = ZSTy::try_ref_from_suffix_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` @@ -2246,7 +2246,8 @@ pub unsafe trait TryFromBytes { /// trailing_dst: [()], /// } /// - /// let src = &mut [85, 85][..]; + /// let mut src = 0xCAFEu16; + /// let src = src.as_mut_bytes(); /// let zsty = ZSTy::try_mut_from_bytes_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` @@ -2358,7 +2359,8 @@ pub unsafe trait TryFromBytes { /// trailing_dst: [()], /// } /// - /// let src = &mut [85, 85][..]; + /// let mut src = 0xCAFEu16; + /// let src = src.as_mut_bytes(); /// let (zsty, _) = ZSTy::try_mut_from_prefix_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` @@ -2452,7 +2454,8 @@ pub unsafe trait TryFromBytes { /// trailing_dst: [()], /// } /// - /// let src = &mut [85, 85][..]; + /// let mut src = 0xCAFEu16; + /// let src = src.as_mut_bytes(); /// let (_, zsty) = ZSTy::try_mut_from_suffix_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` From 70e5ef45b0df281cde57aa1f3b26bfa09310d06f Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Wed, 16 Oct 2024 19:13:59 -0700 Subject: [PATCH 24/96] Use #[marker] on nightly in CI (#1925) We eventually hope to make use of `#[marker]` traits once they're stable. This permits us to test to make sure the feature is as we expect and that our intended usage works. gherrit-pr-id: I3a111bf5647fdcc9805cbadf36f729ac69b28509 --- src/lib.rs | 2 +- src/pointer/invariant.rs | 43 +++++++++++++++++++--------------------- src/pointer/mod.rs | 3 +-- src/pointer/ptr.rs | 6 ------ src/util/macro_util.rs | 3 +-- src/util/macros.rs | 11 ++++++++++ 6 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 23359d8279..a15b15474a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -307,7 +307,7 @@ #![cfg_attr(doc_cfg, feature(doc_cfg))] #![cfg_attr( __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS, - feature(layout_for_ptr, strict_provenance, coverage_attribute) + feature(layout_for_ptr, strict_provenance, coverage_attribute, marker_trait_attr) )] // This is a hack to allow zerocopy-derive derives to work in this crate. They diff --git a/src/pointer/invariant.rs b/src/pointer/invariant.rs index c6543207dc..e52a458650 100644 --- a/src/pointer/invariant.rs +++ b/src/pointer/invariant.rs @@ -210,27 +210,27 @@ impl Validity for Valid { /// /// As a consequence, if `T: Read`, then any `Ptr` is /// permitted to perform unsynchronized reads from its referent. -pub trait Read {} +#[cfg_attr(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS, marker)] +pub unsafe trait Read {} -impl Read for T {} -impl Read for T {} - -/// Used to disambiguate [`Read`] impls. -pub trait ReadReason: Sealed {} - -/// Unsynchronized reads are permitted because only one live [`Ptr`](crate::Ptr) -/// or reference may exist to the referent bytes at a time. -#[derive(Copy, Clone, Debug)] -#[doc(hidden)] -pub enum BecauseExclusive {} -impl ReadReason for BecauseExclusive {} - -/// Unsynchronized reads are permitted because no live [`Ptr`](crate::Ptr)s or -/// references permit interior mutation. -#[derive(Copy, Clone, Debug)] -#[doc(hidden)] -pub enum BecauseImmutable {} -impl ReadReason for BecauseImmutable {} +define_because!( + /// Unsynchronized reads are permitted because only one live + /// [`Ptr`](crate::Ptr) or reference may exist to the referent bytes at a + /// time. + #[doc(hidden)] + pub BecauseExclusive +); +// SAFETY: The aliasing parameter is `Exclusive`. +unsafe impl Read for T {} + +define_because!( + /// Unsynchronized reads are permitted because no live [`Ptr`](crate::Ptr)s + /// or references permit interior mutation. + #[doc(hidden)] + pub BecauseImmutable +); +// SAFETY: `T: Immutable`. +unsafe impl Read for T {} use sealed::Sealed; mod sealed { @@ -251,9 +251,6 @@ mod sealed { impl Sealed for Valid {} impl Sealed for (A, AA, V) {} - - impl Sealed for BecauseImmutable {} - impl Sealed for BecauseExclusive {} } pub use mapping::*; diff --git a/src/pointer/mod.rs b/src/pointer/mod.rs index e7b8c0e802..1b9bd44234 100644 --- a/src/pointer/mod.rs +++ b/src/pointer/mod.rs @@ -14,7 +14,7 @@ pub mod invariant; mod ptr; #[doc(hidden)] -pub use invariant::{BecauseExclusive, BecauseImmutable, Read, ReadReason}; +pub use invariant::{BecauseExclusive, BecauseImmutable, Read}; #[doc(hidden)] pub use ptr::Ptr; @@ -48,7 +48,6 @@ where pub fn read_unaligned(self) -> T where T: Copy, - R: invariant::ReadReason, T: invariant::Read, { // SAFETY: By invariant on `MaybeAligned`, `raw` contains diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index cb729dbb4f..b476d1428f 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -658,7 +658,6 @@ mod _transitions { T: TryFromBytes + Read, I::Aliasing: Reference, I: Invariants, - R: crate::pointer::ReadReason, { // This call may panic. If that happens, it doesn't cause any soundness // issues, as we have not generated any invalid state which we need to @@ -805,8 +804,6 @@ mod _casts { where T: Read, U: 'a + ?Sized + Read, - R: ReadReason, - S: ReadReason, F: FnOnce(*mut T) -> *mut U, { // SAFETY: Because `T` and `U` both implement `Read`, @@ -829,7 +826,6 @@ mod _casts { #[allow(clippy::wrong_self_convention)] pub(crate) fn as_bytes(self) -> Ptr<'a, [u8], (I::Aliasing, Aligned, Valid)> where - R: ReadReason, T: Read, I::Aliasing: Reference, { @@ -919,7 +915,6 @@ mod _casts { CastError, > where - R: ReadReason, I::Aliasing: Reference, U: 'a + ?Sized + KnownLayout + Read, { @@ -983,7 +978,6 @@ mod _casts { where I::Aliasing: Reference, U: 'a + ?Sized + KnownLayout + Read, - R: ReadReason, { match self.try_cast_into(CastType::Prefix, meta) { Ok((slf, remainder)) => { diff --git a/src/util/macro_util.rs b/src/util/macro_util.rs index bd8898a4b8..9d3f6ed77c 100644 --- a/src/util/macro_util.rs +++ b/src/util/macro_util.rs @@ -25,7 +25,7 @@ use core::mem::{self, ManuallyDrop}; use core::ptr::{self, NonNull}; use crate::{ - pointer::invariant::{self, BecauseExclusive, BecauseImmutable, Invariants, ReadReason}, + pointer::invariant::{self, BecauseExclusive, BecauseImmutable, Invariants}, Immutable, IntoBytes, Ptr, TryFromBytes, Unalign, ValidityError, }; @@ -528,7 +528,6 @@ where Dst: TryFromBytes + invariant::Read, I: Invariants, I::Aliasing: invariant::Reference, - R: ReadReason, { static_assert!(Src, Dst => mem::size_of::() == mem::size_of::()); diff --git a/src/util/macros.rs b/src/util/macros.rs index 9b33757e59..263fde6ac7 100644 --- a/src/util/macros.rs +++ b/src/util/macros.rs @@ -655,3 +655,14 @@ macro_rules! static_assert_dst_is_not_zst { }, "cannot call this method on a dynamically-sized type whose trailing slice element is zero-sized"); }} } + +macro_rules! define_because { + ($(#[$attr:meta])* $vis:vis $name:ident) => { + #[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)] + $(#[$attr])* + $vis type $name = (); + #[cfg(not(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS))] + $(#[$attr])* + $vis enum $name {} + }; +} From d3e44e2973285fc792d03d4054c85ce7ab83c01e Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Thu, 17 Oct 2024 07:05:18 -0700 Subject: [PATCH 25/96] [ci] Roll pinned nightly toolchain (#1928) And allow `non_local_definitions`. --- Cargo.toml | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8a8144e3d5..bfc002456f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.81.0" -pinned-nightly = "nightly-2024-10-14" +pinned-nightly = "nightly-2024-10-16" [package.metadata.docs.rs] all-features = true diff --git a/src/lib.rs b/src/lib.rs index a15b15474a..32218dc8b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -203,7 +203,7 @@ // `unknown_lints` is `warn` by default and we deny warnings in CI, so without // this attribute, any unknown lint would cause a CI failure when testing with // our MSRV. -#![allow(unknown_lints, unreachable_patterns)] +#![allow(unknown_lints, non_local_definitions, unreachable_patterns)] #![deny(renamed_and_removed_lints)] #![deny( anonymous_parameters, From af67d9aa6296f33f13573ae08ea82970876024d6 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Thu, 17 Oct 2024 07:47:12 -0700 Subject: [PATCH 26/96] Use #[marker] on nightly in CI (#1926) We eventually hope to make use of `#[marker]` traits once they're stable. This permits us to test to make sure the feature is as we expect and that our intended usage works. gherrit-pr-id: I3a111bf5647fdcc9805cbadf36f729ac69b28509 From 5bd167fba2a0d5ff2c049f66483a8190220a9eb4 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Fri, 18 Oct 2024 05:52:58 -0700 Subject: [PATCH 27/96] [ci] Roll pinned stable toolchain (#1938) --- Cargo.toml | 2 +- tests/ui-stable/transmute-mut-dst-unsized.stderr | 2 +- tests/ui-stable/transmute-mut-src-dst-unsized.stderr | 2 +- tests/ui-stable/transmute-ref-dst-unsized.stderr | 2 +- tests/ui-stable/transmute-ref-src-dst-unsized.stderr | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bfc002456f..777cc12357 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. -pinned-stable = "1.81.0" +pinned-stable = "1.82.0" pinned-nightly = "nightly-2024-10-16" [package.metadata.docs.rs] diff --git a/tests/ui-stable/transmute-mut-dst-unsized.stderr b/tests/ui-stable/transmute-mut-dst-unsized.stderr index 8042fef016..bda6c417e9 100644 --- a/tests/ui-stable/transmute-mut-dst-unsized.stderr +++ b/tests/ui-stable/transmute-mut-dst-unsized.stderr @@ -47,7 +47,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` -note: required by an implicit `Sized` bound in `transmute` +note: required by an implicit `Sized` bound in `std::intrinsics::transmute` --> $RUST/core/src/intrinsics.rs | | pub fn transmute(src: Src) -> Dst; diff --git a/tests/ui-stable/transmute-mut-src-dst-unsized.stderr b/tests/ui-stable/transmute-mut-src-dst-unsized.stderr index 68ef6efd22..6fe2c8fbfc 100644 --- a/tests/ui-stable/transmute-mut-src-dst-unsized.stderr +++ b/tests/ui-stable/transmute-mut-src-dst-unsized.stderr @@ -144,7 +144,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` -note: required by an implicit `Sized` bound in `transmute` +note: required by an implicit `Sized` bound in `std::intrinsics::transmute` --> $RUST/core/src/intrinsics.rs | | pub fn transmute(src: Src) -> Dst; diff --git a/tests/ui-stable/transmute-ref-dst-unsized.stderr b/tests/ui-stable/transmute-ref-dst-unsized.stderr index 3361707c11..c3c53c2611 100644 --- a/tests/ui-stable/transmute-ref-dst-unsized.stderr +++ b/tests/ui-stable/transmute-ref-dst-unsized.stderr @@ -47,7 +47,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` -note: required by an implicit `Sized` bound in `transmute` +note: required by an implicit `Sized` bound in `std::intrinsics::transmute` --> $RUST/core/src/intrinsics.rs | | pub fn transmute(src: Src) -> Dst; diff --git a/tests/ui-stable/transmute-ref-src-dst-unsized.stderr b/tests/ui-stable/transmute-ref-src-dst-unsized.stderr index 3d6765cc3a..f1c285494a 100644 --- a/tests/ui-stable/transmute-ref-src-dst-unsized.stderr +++ b/tests/ui-stable/transmute-ref-src-dst-unsized.stderr @@ -144,7 +144,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` -note: required by an implicit `Sized` bound in `transmute` +note: required by an implicit `Sized` bound in `std::intrinsics::transmute` --> $RUST/core/src/intrinsics.rs | | pub fn transmute(src: Src) -> Dst; From 706dccfb395a6ac27f774e669ad7c643b5b3572f Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Fri, 18 Oct 2024 07:05:54 -0700 Subject: [PATCH 28/96] [ci] Roll pinned nightly toolchain (#1935) Co-authored-by: Joshua Liebow-Feeser --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 777cc12357..ffa22c7b15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.82.0" -pinned-nightly = "nightly-2024-10-16" +pinned-nightly = "nightly-2024-10-17" [package.metadata.docs.rs] all-features = true From 65e60aef966635fb16aa2e970f0de884ce935789 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Sat, 19 Oct 2024 07:56:19 -0700 Subject: [PATCH 29/96] [ci] Roll pinned nightly toolchain (#1947) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ffa22c7b15..c700a8e552 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.82.0" -pinned-nightly = "nightly-2024-10-17" +pinned-nightly = "nightly-2024-10-18" [package.metadata.docs.rs] all-features = true From 35d9d4f79ceb097eda47bbe8e229e7cf7c076a21 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Sun, 20 Oct 2024 05:55:32 -0700 Subject: [PATCH 30/96] [ci] Roll pinned nightly toolchain (#1950) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c700a8e552..4f2eb1aecd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.82.0" -pinned-nightly = "nightly-2024-10-18" +pinned-nightly = "nightly-2024-10-19" [package.metadata.docs.rs] all-features = true From 300ddc23180a9f34d0e12f77b21c9265e392eb53 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Mon, 21 Oct 2024 06:13:37 -0700 Subject: [PATCH 31/96] [ci] Roll pinned nightly toolchain (#1955) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4f2eb1aecd..913265c69c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.82.0" -pinned-nightly = "nightly-2024-10-19" +pinned-nightly = "nightly-2024-10-20" [package.metadata.docs.rs] all-features = true From 986e3c508d46695939d2bb5ce68299c83c7ed3ac Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Mon, 21 Oct 2024 09:06:02 -0700 Subject: [PATCH 32/96] [unsafe-fields] Initial commit (#1929) Makes progress on #1931 gherrit-pr-id: If0e198c377137dd941ebd5dc68787766a593e1eb --- .github/workflows/ci.yml | 70 ++++- Cargo.toml | 7 +- testutil/src/lib.rs | 2 +- tools/cargo-zerocopy/src/main.rs | 5 +- unsafe-fields/Cargo.toml | 21 ++ unsafe-fields/LICENSE-APACHE | 1 + unsafe-fields/LICENSE-BSD | 1 + unsafe-fields/LICENSE-MIT | 1 + unsafe-fields/src/lib.rs | 440 +++++++++++++++++++++++++++++++ 9 files changed, 544 insertions(+), 4 deletions(-) create mode 100644 unsafe-fields/Cargo.toml create mode 120000 unsafe-fields/LICENSE-APACHE create mode 120000 unsafe-fields/LICENSE-BSD create mode 120000 unsafe-fields/LICENSE-MIT create mode 100644 unsafe-fields/src/lib.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a9cfc928c1..4cac3d601a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,7 @@ permissions: read-all env: CARGO_TERM_COLOR: always + RUST_BACKTRACE: 1 RUSTFLAGS: -Dwarnings RUSTDOCFLAGS: -Dwarnings # `ZC_NIGHTLY_XXX` are flags that we add to `XXX` only on the nightly @@ -507,6 +508,73 @@ jobs: # `roll-pinned-toolchain-versions.yml`. kani-version: 0.55.0 + unsafe_fields: + runs-on: ubuntu-latest + needs: generate_cache + strategy: + # By default, this is set to `true`, which means that a single CI job + # failure will cause all outstanding jobs to be canceled. This slows down + # development because it means that errors need to be encountered and + # fixed one at a time. + fail-fast: false + matrix: + toolchain: [ + "msrv", + "stable", + "nightly", + ] + steps: + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - name: Configure environment variables + run: | + set -eo pipefail + ZC_TOOLCHAIN="$(./cargo.sh --version ${{ matrix.toolchain }})" + echo "ZC_TOOLCHAIN=$ZC_TOOLCHAIN" >> $GITHUB_ENV + - name: Install stable Rust for use in 'cargo.sh' + uses: dtolnay/rust-toolchain@00b49be78f40fba4e87296b2ead62868750bdd83 # stable + with: + toolchain: stable + - name: Install Rust with nightly toolchain (${{ env.ZC_TOOLCHAIN }}) and target aarch64_be-unknown-linux-gnu + uses: dtolnay/rust-toolchain@00b49be78f40fba4e87296b2ead62868750bdd83 # stable + with: + toolchain: ${{ env.ZC_TOOLCHAIN }} + components: clippy, rust-src + - name: Check + run: ./cargo.sh +${{ matrix.toolchain }} check --package unsafe-fields --verbose + - name: Check tests + run: ./cargo.sh +${{ matrix.toolchain }} check --tests --package unsafe-fields --verbose + - name: Build + run: ./cargo.sh +${{ matrix.toolchain }} build --package unsafe-fields --verbose + - name: Run tests + run: ./cargo.sh +${{ matrix.toolchain }} test --package unsafe-fields --verbose + - name: Clippy + run: ./cargo.sh +${{ matrix.toolchain }} clippy --package unsafe-fields --verbose + # See comment in next step for why we only run on nightly. + if: matrix.toolchain == 'nightly' + - name: Clippy tests + run: ./cargo.sh +${{ matrix.toolchain }} clippy --package unsafe-fields --tests --verbose + # Clippy improves the accuracy of lints over time, and fixes bugs. Only + # running Clippy on nightly allows us to avoid having to write code + # which is compatible with older versions of Clippy, which sometimes + # requires hacks to work around limitations that are fixed in more + # recent versions. + if: matrix.toolchain == 'nightly' + - name: Cargo doc + # We pass --document-private-items and --document-hidden items to ensure + # that documentation always builds even for these items. This makes + # future changes to make those items public/non-hidden more painless. + # Note that --document-hidden-items is unstable; if a future release + # breaks or removes it, we can just update CI to no longer pass that + # flag. + run: | + # Include arguments passed during docs.rs deployments to make sure those + # work properly. + set -eo pipefail + METADATA_DOCS_RS_RUSTDOC_ARGS="$(cargo metadata --format-version 1 | \ + jq -r ".packages[] | select(.name == \"unsafe-fields\").metadata.docs.rs.\"rustdoc-args\"[]" | tr '\n' ' ')" + export RUSTDOCFLAGS="${{ matrix.toolchain == 'nightly' && '-Z unstable-options --document-hidden-items $METADATA_DOCS_RS_RUSTDOC_ARGS'|| '' }} $RUSTDOCFLAGS" + ./cargo.sh +${{ matrix.toolchain }} doc --document-private-items --package unsafe-fields + # NEON intrinsics are currently broken on big-endian platforms. [1] This test ensures # that we don't accidentally attempt to compile these intrinsics on such platforms. We # can't use this as part of the build matrix because rustup doesn't support the @@ -670,7 +738,7 @@ jobs: # https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/troubleshooting-required-status-checks#handling-skipped-but-required-checks if: failure() runs-on: ubuntu-latest - needs: [build_test, kani,check_be_aarch64 , check_fmt, check_readme, check_versions, generate_cache, check-all-toolchains-tested, check-job-dependencies, run-git-hooks] + needs: [build_test, kani,check_be_aarch64, check_fmt, check_readme, check_versions, generate_cache, check-all-toolchains-tested, check-job-dependencies, run-git-hooks, unsafe_fields] steps: - name: Mark the job as failed run: exit 1 diff --git a/Cargo.toml b/Cargo.toml index 913265c69c..9f51d08eb0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,10 @@ # https://github.com/dtolnay/trybuild/issues/207#issuecomment-131227.594 [workspace] +[workspace.package] +# Inherited by zerocopy and unsafe-fields. +rust-version = "1.65.0" + [package] edition = "2021" name = "zerocopy" @@ -22,7 +26,7 @@ categories = ["embedded", "encoding", "no-std::no-alloc", "parsing", "rust-patte keywords = ["cast", "convert", "transmute", "transmutation", "type-punning"] license = "BSD-2-Clause OR Apache-2.0 OR MIT" repository = "https://github.com/google/zerocopy" -rust-version = "1.65.0" +rust-version = { workspace = true } exclude = [".*"] @@ -81,6 +85,7 @@ testutil = { path = "testutil" } # sometimes change the output format slightly, so a version mismatch can cause # CI test failures. trybuild = { version = "=1.0.90", features = ["diff"] } +unsafe-fields = { path = "./unsafe-fields" } # In tests, unlike in production, zerocopy-derive is not optional zerocopy-derive = { version = "=0.9.0-alpha.0", path = "zerocopy-derive" } # TODO(#381) Remove this dependency once we have our own layout gadgets. diff --git a/testutil/src/lib.rs b/testutil/src/lib.rs index d2cabede16..0056f100c9 100644 --- a/testutil/src/lib.rs +++ b/testutil/src/lib.rs @@ -49,7 +49,7 @@ impl PinnedVersions { .ok_or(format!("expected string value for path in Cargo.toml: {:?}", keys)) }; - let msrv = extract(&["package", "rust-version"])?; + let msrv = extract(&["workspace", "package", "rust-version"])?; let stable = extract(&["package", "metadata", "ci", "pinned-stable"])?; let nightly = extract(&["package", "metadata", "ci", "pinned-nightly"])?; Ok(PinnedVersions { msrv, stable, nightly }) diff --git a/tools/cargo-zerocopy/src/main.rs b/tools/cargo-zerocopy/src/main.rs index ec179b54f3..9b720297f9 100644 --- a/tools/cargo-zerocopy/src/main.rs +++ b/tools/cargo-zerocopy/src/main.rs @@ -112,14 +112,17 @@ impl Versions { fn get_toolchain_versions() -> Versions { let manifest_text = fs::read_to_string("Cargo.toml").unwrap(); let manifest = toml::from_str::(&manifest_text).unwrap(); + let manifest_table = manifest.as_table().unwrap(); + let workspace_package = + manifest_table["workspace"].as_table().unwrap()["package"].as_table().unwrap(); let package = manifest.as_table().unwrap()["package"].as_table().unwrap(); let metadata = package["metadata"].as_table().unwrap(); let build_rs = metadata["build-rs"].as_table().unwrap(); let ci = metadata["ci"].as_table().unwrap(); Versions { - msrv: package["rust-version"].as_str().unwrap().to_string(), + msrv: workspace_package["rust-version"].as_str().unwrap().to_string(), stable: ci["pinned-stable"].as_str().unwrap().to_string(), nightly: ci["pinned-nightly"].as_str().unwrap().to_string(), build_rs: build_rs.clone(), diff --git a/unsafe-fields/Cargo.toml b/unsafe-fields/Cargo.toml new file mode 100644 index 0000000000..f08c13895b --- /dev/null +++ b/unsafe-fields/Cargo.toml @@ -0,0 +1,21 @@ +# Copyright 2024 The Fuchsia Authors +# +# Licensed under a BSD-style license , Apache License, Version 2.0 +# , or the MIT +# license , at your option. +# This file may not be copied, modified, or distributed except according to +# those terms. + +[package] +name = "unsafe-fields" +version = "0.1.0" +edition = "2021" +license = "BSD-2-Clause OR Apache-2.0 OR MIT" +repository = "https://github.com/google/zerocopy" +rust-version = { workspace = true } + +exclude = [".*"] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "doc_cfg", "--generate-link-to-definition"] diff --git a/unsafe-fields/LICENSE-APACHE b/unsafe-fields/LICENSE-APACHE new file mode 120000 index 0000000000..965b606f33 --- /dev/null +++ b/unsafe-fields/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/unsafe-fields/LICENSE-BSD b/unsafe-fields/LICENSE-BSD new file mode 120000 index 0000000000..d37ba4277e --- /dev/null +++ b/unsafe-fields/LICENSE-BSD @@ -0,0 +1 @@ +../LICENSE-BSD \ No newline at end of file diff --git a/unsafe-fields/LICENSE-MIT b/unsafe-fields/LICENSE-MIT new file mode 120000 index 0000000000..76219eb72e --- /dev/null +++ b/unsafe-fields/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/unsafe-fields/src/lib.rs b/unsafe-fields/src/lib.rs new file mode 100644 index 0000000000..38ee867b79 --- /dev/null +++ b/unsafe-fields/src/lib.rs @@ -0,0 +1,440 @@ +// Copyright 2024 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +//! Support for unsafe fields. +//! +//! This crate provides the [`unsafe_fields!`] macro, which can be used to mark +//! fields as unsafe. Unsafe fields automatically have their types wrapped using +//! the [`Unsafe`] wrapper type. An `Unsafe` is intended to be used to for +//! struct, enum, or union fields which carry safety invariants. All accessors +//! are `unsafe`, which requires any use of an `Unsafe` field to be inside an +//! `unsafe` block. +//! +//! An unsafe field has the type `Unsafe`. `O` is +//! the enclosing type (struct, enum, or union), `F` is the type of the field, +//! and `NAME_HASH` is the hash of the field's name. `O` prevents swapping +//! unsafe fields of the same `F` type between different enclosing types, and +//! `NAME_HASH` prevents swapping different fields of the same `F` type within +//! the same enclosing type. Note that swapping the same field between instances +//! of the same type [cannot be prevented](crate#limitations). +//! +//! # Examples +//! +//! ``` +//! use unsafe_fields::{unsafe_fields, Unsafe}; +//! +//! unsafe_fields! { +//! /// A `usize` which is guaranteed to be even. +//! pub struct EvenUsize { +//! // INVARIANT: `n` is even. +//! #[unsafe] +//! n: usize, +//! } +//! } +//! +//! impl EvenUsize { +//! /// Constructs a new `EvenUsize`. +//! /// +//! /// Returns `None` if `n` is odd. +//! pub fn new(n: usize) -> Option { +//! if n % 2 != 0 { +//! return None; +//! } +//! // SAFETY: We just confirmed that `n` is even. +//! let n = unsafe { Unsafe::new(n) }; +//! Some(EvenUsize { n }) +//! } +//! } +//! ``` +//! +//! Attempting to swap unsafe fields of the same type is prevented: +//! +//! ```compile_fail,E0308 +//! use unsafe_fields::{unsafe_fields, Unsafe}; +//! +//! unsafe_fields! { +//! /// A range. +//! pub struct Range { +//! // INVARIANT: `lo <= hi`. +//! #[unsafe] +//! lo: usize, +//! #[unsafe] +//! hi: usize, +//! } +//! } +//! +//! impl Range { +//! pub fn swap(&mut self) { +//! // ERROR: Mismatched types +//! core::mem::swap(&mut self.lo, &mut self.hi); +//! } +//! } +//! ``` +//! +//! # Limitations +//! +//! Note that we cannot prevent `Unsafe`s from being swapped between the same +//! field in instances of the same type: +//! +//! ``` +//! use unsafe_fields::{unsafe_fields, Unsafe}; +//! +//! unsafe_fields! { +//! /// A `usize` which is guaranteed to be even. +//! pub struct EvenUsize { +//! // INVARIANT: `n` is even. +//! #[unsafe] +//! n: usize, +//! } +//! } +//! +//! pub fn swap(a: &mut EvenUsize, b: &mut EvenUsize) { +//! core::mem::swap(&mut a.n, &mut b.n); +//! } +//! ``` + +// Sometimes we want to use lints which were added after our MSRV. +// `unknown_lints` is `warn` by default and we deny warnings in CI, so without +// this attribute, any unknown lint would cause a CI failure when testing with +// our MSRV. +#![allow(unknown_lints, non_local_definitions, unreachable_patterns)] +#![deny(renamed_and_removed_lints)] +#![deny( + anonymous_parameters, + deprecated_in_future, + late_bound_lifetime_arguments, + missing_docs, + path_statements, + patterns_in_fns_without_body, + rust_2018_idioms, + trivial_numeric_casts, + unreachable_pub, + unsafe_op_in_unsafe_fn, + unused_extern_crates, + // We intentionally choose not to deny `unused_qualifications`. When items + // are added to the prelude (e.g., `core::mem::size_of`), this has the + // consequence of making some uses trigger this lint on the latest toolchain + // (e.g., `mem::size_of`), but fixing it (e.g. by replacing with `size_of`) + // does not work on older toolchains. + // + // We tested a more complicated fix in #1413, but ultimately decided that, + // since this lint is just a minor style lint, the complexity isn't worth it + // - it's fine to occasionally have unused qualifications slip through, + // especially since these do not affect our user-facing API in any way. + variant_size_differences +)] +#![deny( + clippy::all, + clippy::alloc_instead_of_core, + clippy::arithmetic_side_effects, + clippy::as_underscore, + clippy::assertions_on_result_states, + clippy::as_conversions, + clippy::correctness, + clippy::dbg_macro, + clippy::decimal_literal_representation, + clippy::double_must_use, + clippy::get_unwrap, + clippy::indexing_slicing, + clippy::missing_const_for_fn, + clippy::missing_inline_in_public_items, + clippy::missing_safety_doc, + clippy::must_use_candidate, + clippy::must_use_unit, + clippy::obfuscated_if_else, + clippy::perf, + clippy::print_stdout, + clippy::return_self_not_must_use, + clippy::std_instead_of_core, + clippy::style, + clippy::suspicious, + clippy::todo, + clippy::undocumented_unsafe_blocks, + clippy::unimplemented, + clippy::unnested_or_patterns, + clippy::unwrap_used, + clippy::use_debug +)] +#![allow(clippy::type_complexity)] +#![deny( + rustdoc::bare_urls, + rustdoc::broken_intra_doc_links, + rustdoc::invalid_codeblock_attributes, + rustdoc::invalid_html_tags, + rustdoc::invalid_rust_codeblocks, + rustdoc::missing_crate_level_docs, + rustdoc::private_intra_doc_links +)] + +use core::marker::PhantomData; + +/// A field with safety invariants. +/// +/// `Unsafe` should not be named directly - instead, use [`unsafe_fields!`] to +/// declare a type with unsafe fields. +/// +/// See the [crate-level documentation](crate) for more information. +#[repr(transparent)] +pub struct Unsafe { + _marker: PhantomData, + // INVARIANT: `field` is only modified via public `unsafe` methods. User code is never + // invoked implicitly except via public `unsafe` methods. + field: F, +} + +// NOTE on design: It may seem counter-intuitive to offer an impl of traits that +// don't require `unsafe` to call. Unfortunately, this is a fundamental +// requirement if users want to be able to mark their types as `Copy`. Luckily, +// we can implement `Copy` (and its unavoidable super-trait, `Clone`) without +// invoking user code or opening up the possibility of modifying the field. We +// do this by only implementing `Copy` and `Clone` when `F: Copy`. For `Clone`, +// the user is still able to provide a manual impl, so this does not +// fundamentally restrict what behavior can be supported. +impl Copy for Unsafe {} +impl Clone for Unsafe { + #[inline(always)] + #[allow(clippy::non_canonical_clone_impl)] + fn clone(&self) -> Self { + // SAFETY: We don't call any user-defined code here (only make a + // bit-for-bit copy of `self.field`), so there's no way to accidentally + // invoke user-defined code or modify `self.field`. + Unsafe { _marker: PhantomData, field: self.field } + } +} + +impl Unsafe { + /// Gets a reference to the inner value. + /// + /// # Safety + /// + /// The caller is responsible for upholding any safety invariants associated + /// with this field. + #[inline(always)] + pub const unsafe fn as_ref(&self) -> &F { + // SAFETY: This method is unsafe to call. + &self.field + } + + /// Gets a mutable reference to the inner value. + /// + /// # Safety + /// + /// The caller is responsible for upholding any safety invariants associated + /// with this field. + #[inline(always)] + pub unsafe fn as_mut(&mut self) -> &mut F { + // SAFETY: This method is unsafe to call. + &mut self.field + } +} + +impl Unsafe { + /// Constructs a new `Unsafe`. + /// + /// # Safety + /// + /// The caller is responsible for upholding any safety invariants associated + /// with this field. + #[inline(always)] + pub const unsafe fn new(field: F) -> Unsafe { + // SAFETY: This method is unsafe to call. + Unsafe { _marker: PhantomData, field } + } + + /// Extracts the inner `F` from `self`. + /// + /// # Safety + /// + /// The caller is responsible for upholding any safety invariants associated + /// with this field. + #[inline(always)] + pub const unsafe fn into(self) -> F { + use core::mem::ManuallyDrop; + let slf = ManuallyDrop::new(self); + + #[repr(C)] + union Transmute { + src: ManuallyDrop, + dst: ManuallyDrop, + } + + // We'd like to just return `self.field` here, but Rust would drop + // `self` in doing that, which we don't want. Even destructuring (ie, + // `let Unsafe { field, .. } = self`) also causes a drop. We also can't + // use `mem::transmute` because that requires all types to be concrete, + // so a union transmute is our only option. + // + // SAFETY: `ManuallyDrop>` has the same size and bit + // validity as `Unsafe<_, F, _>`. [1] `Unsafe<_, F, _>` is + // `#[repr(transparent)]` and has no other fields, and so it has the + // same size and bit validity as `F`. + // + // [1] Per https://doc.rust-lang.org/1.81.0/core/mem/struct.ManuallyDrop.html: + // + // `ManuallyDrop` is guaranteed to have the same layout and bit + // validity as `T` + let dst = unsafe { Transmute { src: slf }.dst }; + + // SAFETY (satisfaction of `Unsafe`'s field invariant): This method is + // unsafe to call. + ManuallyDrop::into_inner(dst) + } +} + +/// Defines a type with unsafe fields. +/// +/// See the [crate-level documentation](crate) for more information. +// TODO: Allow specifying *which* fields are unsafe. +#[macro_export] +macro_rules! unsafe_fields { + ($(#[$attr:meta])* $vis:vis struct $name:ident { + $($(#[$field_attr:tt])? $field:ident: $field_ty:ty),* $(,)? + }) => { + $(#[$attr])* + $vis struct $name { + $( + $field: unsafe_fields!(@field $(#[$field_attr])? $field: $field_ty), + )* + } + }; + (@field #[unsafe] $field:ident: $field_ty:ty) => { + $crate::Unsafe + }; + (@field $_field:ident: $field_ty:ty) => { + $field_ty + } +} + +#[doc(hidden)] +pub mod macro_util { + // TODO: Implement a stronger hash function so we can basically just ignore + // collisions. If users encounter collisions in practice, we can just deal + // with it then, publish a new version, and tell them to upgrade. + #[inline(always)] + #[must_use] + #[allow(clippy::as_conversions, clippy::indexing_slicing, clippy::arithmetic_side_effects)] + pub const fn hash_field_name(field_name: &str) -> u128 { + // An implementation of FxHasher, although returning a u128. Probably + // not as strong as it could be, but probably more collision resistant + // than normal 64-bit FxHasher. + let field_name = field_name.as_bytes(); + let mut hash = 0u128; + let mut i = 0; + while i < field_name.len() { + // This is just FxHasher's `0x517cc1b727220a95` constant + // concatenated back-to-back. + const K: u128 = 0x517cc1b727220a95517cc1b727220a95; + hash = (hash.rotate_left(5) ^ (field_name[i] as u128)).wrapping_mul(K); + i += 1; + } + hash + } +} + +#[cfg(test)] +#[allow(clippy::missing_const_for_fn)] +mod tests { + use super::*; + + unsafe_fields! { + /// A `Foo`. + #[allow(unused)] + struct Foo { + #[unsafe] + a: usize, + b: usize, + } + } + + unsafe_fields! { + /// A `Bar`. + #[allow(unused)] + struct Bar { + #[unsafe] + a: usize, + #[unsafe] + b: usize, + } + } + + #[test] + #[allow(clippy::undocumented_unsafe_blocks)] + fn test_unsafe_fieds() { + let mut _foo = Foo { a: unsafe { Unsafe::new(0) }, b: 0 }; + let mut _bar = Bar { a: unsafe { Unsafe::new(0) }, b: unsafe { Unsafe::new(0) } }; + } +} + +/// This module exists so that we can use rustdoc to perform compile-fail tests +/// rather than having to set up an entire trybuild set suite. +/// +/// ```compile_fail,E0308 +/// use unsafe_fields::*; +/// +/// unsafe_fields! { +/// struct Foo { +/// #[unsafe] +/// a: usize, +/// b: usize, +/// } +/// } +/// +/// impl Foo { +/// // Swapping an unsafe field with a non-unsafe field is a compile error. +/// fn swap(&mut self) { +/// core::mem::swap(&mut self.a, &mut self.b); +/// } +/// } +/// ``` +/// +/// ```compile_fail,E0308 +/// use unsafe_fields::*; +/// +/// unsafe_fields! { +/// struct Foo { +/// #[unsafe] +/// a: usize, +/// #[unsafe] +/// b: usize, +/// } +/// } +/// +/// impl Foo { +/// // Swapping an unsafe field with another unsafe field is a compile +/// // error. +/// fn swap(&mut self) { +/// core::mem::swap(&mut self.a, &mut self.b); +/// } +/// } +/// ``` +/// +/// ```compile_fail,E0308 +/// use unsafe_fields::*; +/// +/// unsafe_fields! { +/// struct Foo { +/// #[unsafe] +/// a: usize, +/// } +/// } +/// +/// unsafe_fields! { +/// struct Bar { +/// #[unsafe] +/// a: usize, +/// } +/// } +/// +/// // Swapping identically-named unsafe fields from different types is a +/// // compile error. +/// fn swap(foo: &mut Foo, bar: &mut Bar) { +/// core::mem::swap(&mut foo.a, &mut bar.a); +/// } +/// ``` +#[doc(hidden)] +pub mod compile_fail {} From f51d6662aeb8d707ab6e9558b8fdaff674245c0c Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Mon, 21 Oct 2024 12:41:13 -0700 Subject: [PATCH 33/96] [unsafe-fields] Add Cargo.toml description (#1959) Makes progress on #1931 gherrit-pr-id: Ib2708e8f233f624bcd1f2ec80b5dae91c7e1db46 --- unsafe-fields/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/unsafe-fields/Cargo.toml b/unsafe-fields/Cargo.toml index f08c13895b..9aba90fe3d 100644 --- a/unsafe-fields/Cargo.toml +++ b/unsafe-fields/Cargo.toml @@ -10,6 +10,7 @@ name = "unsafe-fields" version = "0.1.0" edition = "2021" +description = "Make it unsafe to access or modify fields with safety invariants" license = "BSD-2-Clause OR Apache-2.0 OR MIT" repository = "https://github.com/google/zerocopy" rust-version = { workspace = true } From 34f4e6e02817f873f0a8f13f62b61011d969672f Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Mon, 21 Oct 2024 14:55:27 -0700 Subject: [PATCH 34/96] [unsafe-fields] Add as_ref_checked (#1960) Release 0.2.0. Makes progress on #1931 gherrit-pr-id: I7ce0c981ed1f1bc1f4ff85dffef2a74114c6e76d --- .github/workflows/ci.yml | 18 +++++++++------- Cargo.toml | 3 ++- unsafe-fields/Cargo.toml | 8 +++++++- unsafe-fields/src/lib.rs | 44 ++++++++++++++++++++++++++++++---------- 4 files changed, 53 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4cac3d601a..aa6073cc6c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -523,6 +523,10 @@ jobs: "stable", "nightly", ] + features: [ + "", + "--features zerocopy_0_8", + ] steps: - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: Configure environment variables @@ -540,19 +544,19 @@ jobs: toolchain: ${{ env.ZC_TOOLCHAIN }} components: clippy, rust-src - name: Check - run: ./cargo.sh +${{ matrix.toolchain }} check --package unsafe-fields --verbose + run: ./cargo.sh +${{ matrix.toolchain }} check --package unsafe-fields ${{ matrix.features }} --verbose - name: Check tests - run: ./cargo.sh +${{ matrix.toolchain }} check --tests --package unsafe-fields --verbose + run: ./cargo.sh +${{ matrix.toolchain }} check --tests --package unsafe-fields ${{ matrix.features }} --verbose - name: Build - run: ./cargo.sh +${{ matrix.toolchain }} build --package unsafe-fields --verbose + run: ./cargo.sh +${{ matrix.toolchain }} build --package unsafe-fields ${{ matrix.features }} --verbose - name: Run tests - run: ./cargo.sh +${{ matrix.toolchain }} test --package unsafe-fields --verbose + run: ./cargo.sh +${{ matrix.toolchain }} test --package unsafe-fields ${{ matrix.features }} --verbose - name: Clippy - run: ./cargo.sh +${{ matrix.toolchain }} clippy --package unsafe-fields --verbose + run: ./cargo.sh +${{ matrix.toolchain }} clippy --package unsafe-fields ${{ matrix.features }} --verbose # See comment in next step for why we only run on nightly. if: matrix.toolchain == 'nightly' - name: Clippy tests - run: ./cargo.sh +${{ matrix.toolchain }} clippy --package unsafe-fields --tests --verbose + run: ./cargo.sh +${{ matrix.toolchain }} clippy --package unsafe-fields --tests ${{ matrix.features }} --verbose # Clippy improves the accuracy of lints over time, and fixes bugs. Only # running Clippy on nightly allows us to avoid having to write code # which is compatible with older versions of Clippy, which sometimes @@ -573,7 +577,7 @@ jobs: METADATA_DOCS_RS_RUSTDOC_ARGS="$(cargo metadata --format-version 1 | \ jq -r ".packages[] | select(.name == \"unsafe-fields\").metadata.docs.rs.\"rustdoc-args\"[]" | tr '\n' ' ')" export RUSTDOCFLAGS="${{ matrix.toolchain == 'nightly' && '-Z unstable-options --document-hidden-items $METADATA_DOCS_RS_RUSTDOC_ARGS'|| '' }} $RUSTDOCFLAGS" - ./cargo.sh +${{ matrix.toolchain }} doc --document-private-items --package unsafe-fields + ./cargo.sh +${{ matrix.toolchain }} doc --document-private-items --package unsafe-fields --all-features # NEON intrinsics are currently broken on big-endian platforms. [1] This test ensures # that we don't accidentally attempt to compile these intrinsics on such platforms. We diff --git a/Cargo.toml b/Cargo.toml index 9f51d08eb0..d408ab4a03 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,8 @@ # https://github.com/dtolnay/trybuild/issues/207#issuecomment-131227.594 [workspace] +members = ["unsafe-fields", "zerocopy-derive"] + [workspace.package] # Inherited by zerocopy and unsafe-fields. rust-version = "1.65.0" @@ -85,7 +87,6 @@ testutil = { path = "testutil" } # sometimes change the output format slightly, so a version mismatch can cause # CI test failures. trybuild = { version = "=1.0.90", features = ["diff"] } -unsafe-fields = { path = "./unsafe-fields" } # In tests, unlike in production, zerocopy-derive is not optional zerocopy-derive = { version = "=0.9.0-alpha.0", path = "zerocopy-derive" } # TODO(#381) Remove this dependency once we have our own layout gadgets. diff --git a/unsafe-fields/Cargo.toml b/unsafe-fields/Cargo.toml index 9aba90fe3d..adc98bbff5 100644 --- a/unsafe-fields/Cargo.toml +++ b/unsafe-fields/Cargo.toml @@ -8,7 +8,7 @@ [package] name = "unsafe-fields" -version = "0.1.0" +version = "0.2.0" edition = "2021" description = "Make it unsafe to access or modify fields with safety invariants" license = "BSD-2-Clause OR Apache-2.0 OR MIT" @@ -20,3 +20,9 @@ exclude = [".*"] [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "doc_cfg", "--generate-link-to-definition"] + + [lints.rust] + unexpected_cfgs = { level = "allow", check-cfg = ['cfg(doc_cfg)'] } + +[dependencies] +zerocopy_0_8 = { package = "zerocopy", path = "..", optional = true } diff --git a/unsafe-fields/src/lib.rs b/unsafe-fields/src/lib.rs index 38ee867b79..65bdb76b9f 100644 --- a/unsafe-fields/src/lib.rs +++ b/unsafe-fields/src/lib.rs @@ -13,7 +13,8 @@ //! the [`Unsafe`] wrapper type. An `Unsafe` is intended to be used to for //! struct, enum, or union fields which carry safety invariants. All accessors //! are `unsafe`, which requires any use of an `Unsafe` field to be inside an -//! `unsafe` block. +//! `unsafe` block. One exception is [`Unsafe::as_ref`], which is available when +//! the `zerocopy_0_8` feature is enabled. See its docs for more information. //! //! An unsafe field has the type `Unsafe`. `O` is //! the enclosing type (struct, enum, or union), `F` is the type of the field, @@ -23,6 +24,8 @@ //! the same enclosing type. Note that swapping the same field between instances //! of the same type [cannot be prevented](crate#limitations). //! +//! [immutable]: zerocopy_0_8::Immutable +//! //! # Examples //! //! ``` @@ -170,6 +173,7 @@ rustdoc::missing_crate_level_docs, rustdoc::private_intra_doc_links )] +#![cfg_attr(doc_cfg, feature(doc_cfg))] use core::marker::PhantomData; @@ -210,16 +214,41 @@ impl Clone for Unsafe Unsafe { /// Gets a reference to the inner value. /// + /// If [`F: Immutable`][immutable], prefer [`as_ref`], which is safe. + /// + /// [immutable]: zerocopy_0_8::Immutable + /// [`as_ref`]: Unsafe::as_ref + /// /// # Safety /// /// The caller is responsible for upholding any safety invariants associated /// with this field. #[inline(always)] - pub const unsafe fn as_ref(&self) -> &F { + pub const unsafe fn as_ref_unchecked(&self) -> &F { // SAFETY: This method is unsafe to call. &self.field } + /// Gets a reference to the inner value safely so long as the inner value is + /// immutable. + /// + /// If [`F: Immutable`][immutable], then `F` does not permit interior + /// mutation, and so it is safe to return a reference to it. + /// + /// [immutable]: zerocopy_0_8::Immutable + #[inline(always)] + #[cfg(feature = "zerocopy_0_8")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "zerocopy_0_8")))] + pub const fn as_ref(&self) -> &F + where + F: zerocopy_0_8::Immutable, + { + // SAFETY: `F: Immutable` guarantees that the returned `&F` cannot be + // used to mutate `self`, and so it cannot be used to violate any + // invariant. + unsafe { self.as_ref_unchecked() } + } + /// Gets a mutable reference to the inner value. /// /// # Safety @@ -234,7 +263,7 @@ impl Unsafe { } impl Unsafe { - /// Constructs a new `Unsafe`. + /// Constructs a new `Unsafe`. /// /// # Safety /// @@ -247,13 +276,8 @@ impl Unsafe { } /// Extracts the inner `F` from `self`. - /// - /// # Safety - /// - /// The caller is responsible for upholding any safety invariants associated - /// with this field. #[inline(always)] - pub const unsafe fn into(self) -> F { + pub const fn into(self) -> F { use core::mem::ManuallyDrop; let slf = ManuallyDrop::new(self); @@ -280,8 +304,6 @@ impl Unsafe { // validity as `T` let dst = unsafe { Transmute { src: slf }.dst }; - // SAFETY (satisfaction of `Unsafe`'s field invariant): This method is - // unsafe to call. ManuallyDrop::into_inner(dst) } } From 19c211e355c8ea4f28b92e2590118602febc9049 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Tue, 22 Oct 2024 05:51:17 -0700 Subject: [PATCH 35/96] [ci] Roll pinned nightly toolchain (#1963) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d408ab4a03..17698bf35b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.82.0" -pinned-nightly = "nightly-2024-10-20" +pinned-nightly = "nightly-2024-10-21" [package.metadata.docs.rs] all-features = true From 60a7497bb3af6083d31d6ccd3ad02bbd76ef42ad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Oct 2024 08:00:21 -0700 Subject: [PATCH 36/96] [CI] Bump actions/dependency-review-action from 4.3.4 to 4.3.5 (#1964) Bumps [actions/dependency-review-action](https://github.com/actions/dependency-review-action) from 4.3.4 to 4.3.5. - [Release notes](https://github.com/actions/dependency-review-action/releases) - [Commits](https://github.com/actions/dependency-review-action/compare/5a2ce3f5b92ee19cbb1541a4984c76d921601d7c...a6993e2c61fd5dc440b409aa1d6904921c5e1894) --- updated-dependencies: - dependency-name: actions/dependency-review-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/dependency-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 6e6f292f78..0c80c45396 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -32,4 +32,4 @@ jobs: - name: 'Checkout Repository' uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: 'Dependency Review' - uses: actions/dependency-review-action@5a2ce3f5b92ee19cbb1541a4984c76d921601d7c # v4.3.4 + uses: actions/dependency-review-action@a6993e2c61fd5dc440b409aa1d6904921c5e1894 # v4.3.5 From 0fae530a5b2e0566064548ed59f4918d424fd01b Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Tue, 22 Oct 2024 10:38:26 -0700 Subject: [PATCH 37/96] [unsafe-fields] Add README.md (#1961) Release 0.2.1. Makes progress on #1931 gherrit-pr-id: Icc9b6841e66c961989862ff6fb3b4f5140c54513 --- README.md | 2 +- ci/check_readme.sh | 4 +- tools/generate-readme/src/main.rs | 2 +- unsafe-fields/Cargo.toml | 2 +- unsafe-fields/README.md | 112 ++++++++++++++++++++++++++++++ unsafe-fields/src/lib.rs | 11 ++- 6 files changed, 126 insertions(+), 7 deletions(-) create mode 100644 unsafe-fields/README.md diff --git a/README.md b/README.md index 358a4a6a7e..6fa9a240f5 100644 --- a/README.md +++ b/README.md @@ -201,4 +201,4 @@ Zerocopy uses [GitHub Releases]. ## Disclaimer -Disclaimer: Zerocopy is not an officially supported Google product. +Disclaimer: This is not an officially supported Google product. diff --git a/ci/check_readme.sh b/ci/check_readme.sh index 241128d0d0..413f5a866d 100755 --- a/ci/check_readme.sh +++ b/ci/check_readme.sh @@ -16,4 +16,6 @@ set -eo pipefail cargo install -q cargo-readme --version 3.2.0 diff <(cargo -q run --manifest-path tools/Cargo.toml -p generate-readme) README.md >&2 -exit $? + +cd unsafe-fields +diff <(cargo -q run --manifest-path ../tools/Cargo.toml -p generate-readme) README.md >&2 diff --git a/tools/generate-readme/src/main.rs b/tools/generate-readme/src/main.rs index 8945caea7b..908231608b 100644 --- a/tools/generate-readme/src/main.rs +++ b/tools/generate-readme/src/main.rs @@ -27,7 +27,7 @@ made in the doc comment on `src/lib.rs` or in `tools/generate-readme`. const DISCLAIMER_FOOTER: &str = "\ ## Disclaimer -Disclaimer: Zerocopy is not an officially supported Google product.\ +Disclaimer: This is not an officially supported Google product.\ "; fn main() { diff --git a/unsafe-fields/Cargo.toml b/unsafe-fields/Cargo.toml index adc98bbff5..43ab479958 100644 --- a/unsafe-fields/Cargo.toml +++ b/unsafe-fields/Cargo.toml @@ -8,7 +8,7 @@ [package] name = "unsafe-fields" -version = "0.2.0" +version = "0.2.1" edition = "2021" description = "Make it unsafe to access or modify fields with safety invariants" license = "BSD-2-Clause OR Apache-2.0 OR MIT" diff --git a/unsafe-fields/README.md b/unsafe-fields/README.md new file mode 100644 index 0000000000..e004e263b2 --- /dev/null +++ b/unsafe-fields/README.md @@ -0,0 +1,112 @@ + + +# unsafe-fields + +Support for unsafe fields. + +This crate provides the `unsafe_fields!` macro, which can be used to mark +fields as unsafe. Unsafe fields automatically have their types wrapped using +the `Unsafe` wrapper type. An `Unsafe` is intended to be used to for +struct, enum, or union fields which carry safety invariants. All accessors +are `unsafe`, which requires any use of an `Unsafe` field to be inside an +`unsafe` block. One exception is `Unsafe::as_ref`, which is available when +the `zerocopy_0_8` feature is enabled. See its docs for more information. + +An unsafe field has the type `Unsafe`. `O` is +the enclosing type (struct, enum, or union), `F` is the type of the field, +and `NAME_HASH` is the hash of the field's name. `O` prevents swapping +unsafe fields of the same `F` type between different enclosing types, and +`NAME_HASH` prevents swapping different fields of the same `F` type within +the same enclosing type. Note that swapping the same field between instances +of the same type [cannot be prevented](crate#limitations). + +[immutable]: zerocopy_0_8::Immutable + +## Examples + +```rust +use unsafe_fields::{unsafe_fields, Unsafe}; + +unsafe_fields! { + /// A `usize` which is guaranteed to be even. + pub struct EvenUsize { + // INVARIANT: `n` is even. + #[unsafe] + n: usize, + } +} + +impl EvenUsize { + /// Constructs a new `EvenUsize`. + /// + /// Returns `None` if `n` is odd. + pub fn new(n: usize) -> Option { + if n % 2 != 0 { + return None; + } + // SAFETY: We just confirmed that `n` is even. + let n = unsafe { Unsafe::new(n) }; + Some(EvenUsize { n }) + } +} +``` + +Attempting to swap unsafe fields of the same type is prevented: + +```rust,compile_fail,E0308 +use unsafe_fields::{unsafe_fields, Unsafe}; + +unsafe_fields! { + /// A range. + pub struct Range { + // INVARIANT: `lo <= hi`. + #[unsafe] + lo: usize, + #[unsafe] + hi: usize, + } +} + +impl Range { + pub fn swap(&mut self) { + // ERROR: Mismatched types + core::mem::swap(&mut self.lo, &mut self.hi); + } +} +``` + +## Limitations + +Note that we cannot prevent `Unsafe`s from being swapped between the same +field in instances of the same type: + +```rust +use unsafe_fields::{unsafe_fields, Unsafe}; + +unsafe_fields! { + /// A `usize` which is guaranteed to be even. + pub struct EvenUsize { + // INVARIANT: `n` is even. + #[unsafe] + n: usize, + } +} + +pub fn swap(a: &mut EvenUsize, b: &mut EvenUsize) { + core::mem::swap(&mut a.n, &mut b.n); +} +``` + +## Disclaimer + +Disclaimer: This is not an officially supported Google product. diff --git a/unsafe-fields/src/lib.rs b/unsafe-fields/src/lib.rs index 65bdb76b9f..06566189e1 100644 --- a/unsafe-fields/src/lib.rs +++ b/unsafe-fields/src/lib.rs @@ -6,6 +6,11 @@ // This file may not be copied, modified, or distributed except according to // those terms. +// After updating the following doc comment, make sure to run the following +// command to update `README.md` based on its contents: +// +// cargo -q run --manifest-path ../tools/Cargo.toml -p generate-readme > README.md + //! Support for unsafe fields. //! //! This crate provides the [`unsafe_fields!`] macro, which can be used to mark @@ -28,7 +33,7 @@ //! //! # Examples //! -//! ``` +//! ```rust //! use unsafe_fields::{unsafe_fields, Unsafe}; //! //! unsafe_fields! { @@ -57,7 +62,7 @@ //! //! Attempting to swap unsafe fields of the same type is prevented: //! -//! ```compile_fail,E0308 +//! ```rust,compile_fail,E0308 //! use unsafe_fields::{unsafe_fields, Unsafe}; //! //! unsafe_fields! { @@ -84,7 +89,7 @@ //! Note that we cannot prevent `Unsafe`s from being swapped between the same //! field in instances of the same type: //! -//! ``` +//! ```rust //! use unsafe_fields::{unsafe_fields, Unsafe}; //! //! unsafe_fields! { From ef83307e63e250d33323940ccecd2ecfe2f8c546 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Wed, 23 Oct 2024 06:43:39 -0700 Subject: [PATCH 38/96] [ci] Roll pinned nightly toolchain (#1972) --- Cargo.toml | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 17698bf35b..0adc7b1d21 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.82.0" -pinned-nightly = "nightly-2024-10-21" +pinned-nightly = "nightly-2024-10-22" [package.metadata.docs.rs] all-features = true diff --git a/src/lib.rs b/src/lib.rs index 32218dc8b4..f2af6f8b9f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -307,7 +307,7 @@ #![cfg_attr(doc_cfg, feature(doc_cfg))] #![cfg_attr( __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS, - feature(layout_for_ptr, strict_provenance, coverage_attribute, marker_trait_attr) + feature(layout_for_ptr, coverage_attribute, marker_trait_attr) )] // This is a hack to allow zerocopy-derive derives to work in this crate. They From 557792720bb567f27ae8d66f9b573b73f971c440 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 23 Oct 2024 09:15:49 -0700 Subject: [PATCH 39/96] [CI] Bump github/codeql-action from 3.26.13 to 3.27.0 (#1973) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.26.13 to 3.27.0. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/f779452ac5af1c261dce0346a8f964149f49322b...662472033e021d55d94146f66f6058822b0b39fd) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index eaaad9f67f..11a4079dcf 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -66,6 +66,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13 + uses: github/codeql-action/upload-sarif@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 with: sarif_file: results.sarif From 6e10d001a786cb6ea6b06fb6323dc1e06ee472cc Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Thu, 24 Oct 2024 06:05:14 -0700 Subject: [PATCH 40/96] [ci] Roll pinned nightly toolchain (#1975) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 0adc7b1d21..91e269ef2f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.82.0" -pinned-nightly = "nightly-2024-10-22" +pinned-nightly = "nightly-2024-10-23" [package.metadata.docs.rs] all-features = true From a407be244f1dbe53a311d27c7c8470579e126177 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Oct 2024 13:26:36 +0000 Subject: [PATCH 41/96] [CI] Bump actions/checkout from 4.2.1 to 4.2.2 (#1977) Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.1 to 4.2.2. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871...11bd71901bbe5b1630ceea73d27597364c9af683) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 22 +++++++++---------- .github/workflows/dependency-review.yml | 2 +- .github/workflows/docs.yml | 2 +- .github/workflows/release-crate-version.yml | 2 +- .../roll-pinned-toolchain-versions.yml | 4 ++-- .github/workflows/scorecard.yml | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aa6073cc6c..4c9fd7ab9e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -176,7 +176,7 @@ jobs: name: Build & Test (${{ matrix.crate }} / ${{ matrix.toolchain }} / ${{ matrix.features }} / ${{ matrix.target }}) steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Populate cache uses: ./.github/actions/cache @@ -490,7 +490,7 @@ jobs: runs-on: ubuntu-latest name: 'Run tests under Kani' steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: model-checking/kani-github-action@f838096619a707b0f6b2118cf435eaccfa33e51f # v1.1 with: # Use `--features __internal_use_only_features_that_work_on_stable` @@ -528,7 +528,7 @@ jobs: "--features zerocopy_0_8", ] steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Configure environment variables run: | set -eo pipefail @@ -589,7 +589,7 @@ jobs: runs-on: ubuntu-latest name: Build (zerocopy / nightly / --simd / aarch64_be-unknown-linux-gnu) steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Configure environment variables run: | set -eo pipefail @@ -617,7 +617,7 @@ jobs: runs-on: ubuntu-latest name: Check Rust formatting steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Check Rust formatting run: ./ci/check_fmt.sh @@ -626,7 +626,7 @@ jobs: runs-on: ubuntu-latest name: Check README.md steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Populate cache uses: ./.github/actions/cache @@ -639,7 +639,7 @@ jobs: runs-on: ubuntu-latest name: Check crate versions match steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Populate cache uses: ./.github/actions/cache @@ -654,7 +654,7 @@ jobs: runs-on: ubuntu-latest name: Generate cache steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Populate cache uses: ./.github/actions/cache @@ -702,7 +702,7 @@ jobs: steps: - name: Install yq (for YAML parsing) run: go install github.com/mikefarah/yq/v4@latest - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run check run: ./ci/check_all_toolchains_tested.sh @@ -712,7 +712,7 @@ jobs: steps: - name: Install yq (for YAML parsing) run: go install github.com/mikefarah/yq/v4@latest - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run dependency check run: ./ci/check_job_dependencies.sh @@ -722,7 +722,7 @@ jobs: steps: - name: Install yq (for YAML parsing) run: go install github.com/mikefarah/yq/v4@latest - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run dependency check # Ensure that Git hooks execute successfully. # diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 0c80c45396..a86f979dad 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -30,6 +30,6 @@ jobs: egress-policy: audit - name: 'Checkout Repository' - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: 'Dependency Review' uses: actions/dependency-review-action@a6993e2c61fd5dc440b409aa1d6904921c5e1894 # v4.3.5 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index d30f3bf820..6e19289747 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -27,7 +27,7 @@ jobs: name: Build runs-on: ubuntu-latest steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Configure environment variables run: | set -eo pipefail diff --git a/.github/workflows/release-crate-version.yml b/.github/workflows/release-crate-version.yml index 8d99ba07a5..b5a3c6aeb8 100644 --- a/.github/workflows/release-crate-version.yml +++ b/.github/workflows/release-crate-version.yml @@ -26,7 +26,7 @@ jobs: name: Release new crate versions steps: - name: Checkout code - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ github.event.inputs.branch }} persist-credentials: false diff --git a/.github/workflows/roll-pinned-toolchain-versions.yml b/.github/workflows/roll-pinned-toolchain-versions.yml index 7592de8179..1908beba11 100644 --- a/.github/workflows/roll-pinned-toolchain-versions.yml +++ b/.github/workflows/roll-pinned-toolchain-versions.yml @@ -39,7 +39,7 @@ jobs: name: Roll pinned toolchain ${{ matrix.toolchain }} version on ${{ matrix.branch }} steps: - name: Checkout code - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ matrix.branch }} persist-credentials: false @@ -148,7 +148,7 @@ jobs: name: Roll pinned Kani version steps: - name: Checkout code - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ matrix.branch }} persist-credentials: false diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 11a4079dcf..a245b88c5f 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -37,7 +37,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false From a927e1e1b70e289dab737fa1be08a8c030b42898 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Fri, 25 Oct 2024 07:07:12 -0700 Subject: [PATCH 42/96] [ci] Roll pinned nightly toolchain (#1981) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 91e269ef2f..ee38479ac0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.82.0" -pinned-nightly = "nightly-2024-10-23" +pinned-nightly = "nightly-2024-10-24" [package.metadata.docs.rs] all-features = true From 31c90a3c981e91115242f4ccd3969911bcedd02b Mon Sep 17 00:00:00 2001 From: Eden Date: Sat, 26 Oct 2024 03:49:44 +0800 Subject: [PATCH 43/96] [CI] skip installation step when cache hit (#1978) * [ci] fix, showing cache hit, re-install dependencies * [ci] fix ci workflow to check the cache-hit output and add restore-key for wider cache range --- .github/actions/cache/action.yml | 7 +++++++ .github/workflows/ci.yml | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/actions/cache/action.yml b/.github/actions/cache/action.yml index 22b8600249..7940546975 100644 --- a/.github/actions/cache/action.yml +++ b/.github/actions/cache/action.yml @@ -8,12 +8,19 @@ name: Cache description: 'Caches cargo dependencies' +outputs: + cache-hit: + description: "Cache Hit" + value: ${{ steps.cache.outputs.cache-hit }} runs: using: composite steps: - uses: actions/cache@v4 + id: cache with: path: | ~/.cargo/ key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.toml') }} + restore-keys: | + ${{ runner.os }}-cargo- diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4c9fd7ab9e..2b6ec5b802 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -656,10 +656,11 @@ jobs: steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - name: Populate cache + - id: populate-cache uses: ./.github/actions/cache - name: Download dependencies + if: steps.populate-cache.outputs.cache-hit != 'true' run: | # Ensure all dependencies are downloaded - both for our crates and for # tools we use in CI. We don't care about these tools succeeding for From 056091830996647761fbee9e75d13f9bfb95bc7b Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Mon, 28 Oct 2024 05:51:18 -0700 Subject: [PATCH 44/96] [ci] Roll pinned nightly toolchain (#1986) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ee38479ac0..3e533cb23c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.82.0" -pinned-nightly = "nightly-2024-10-24" +pinned-nightly = "nightly-2024-10-27" [package.metadata.docs.rs] all-features = true From 609e98d07243a6b9de78d43e1f5dcacaeb3f72a3 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Tue, 29 Oct 2024 07:17:42 -0700 Subject: [PATCH 45/96] [ci] Roll pinned nightly toolchain (#1989) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3e533cb23c..a8d551114c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.82.0" -pinned-nightly = "nightly-2024-10-27" +pinned-nightly = "nightly-2024-10-28" [package.metadata.docs.rs] all-features = true From a6ce954c4610a93cb923e50621555b59030e5494 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Oct 2024 09:17:55 -0700 Subject: [PATCH 46/96] [CI] Bump actions/dependency-review-action from 4.3.5 to 4.4.0 (#1990) Bumps [actions/dependency-review-action](https://github.com/actions/dependency-review-action) from 4.3.5 to 4.4.0. - [Release notes](https://github.com/actions/dependency-review-action/releases) - [Commits](https://github.com/actions/dependency-review-action/compare/a6993e2c61fd5dc440b409aa1d6904921c5e1894...4081bf99e2866ebe428fc0477b69eb4fcda7220a) --- updated-dependencies: - dependency-name: actions/dependency-review-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/dependency-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index a86f979dad..6c8b4e378b 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -32,4 +32,4 @@ jobs: - name: 'Checkout Repository' uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: 'Dependency Review' - uses: actions/dependency-review-action@a6993e2c61fd5dc440b409aa1d6904921c5e1894 # v4.3.5 + uses: actions/dependency-review-action@4081bf99e2866ebe428fc0477b69eb4fcda7220a # v4.4.0 From a80c2d48265f0847cda34c8749c88b7996a003fe Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Wed, 30 Oct 2024 05:58:48 -0700 Subject: [PATCH 47/96] [ci] Roll pinned nightly toolchain (#1992) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a8d551114c..2c37606164 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.82.0" -pinned-nightly = "nightly-2024-10-28" +pinned-nightly = "nightly-2024-10-29" [package.metadata.docs.rs] all-features = true From 3eb2fb7681fa3a613223d7854f0ada4fda0b0305 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Thu, 31 Oct 2024 05:55:29 -0700 Subject: [PATCH 48/96] [ci] Roll pinned nightly toolchain (#1996) --- Cargo.toml | 2 +- tests/ui-nightly/invalid-impls/invalid-impls.stderr | 10 +++++----- .../tests/ui-nightly/derive_transparent.stderr | 10 +++++----- zerocopy-derive/tests/ui-nightly/enum.stderr | 2 +- .../tests/ui-nightly/late_compile_pass.stderr | 2 +- .../tests/ui-nightly/mid_compile_pass.stderr | 4 ++-- zerocopy-derive/tests/ui-nightly/struct.stderr | 12 ++++++------ zerocopy-derive/tests/ui-nightly/union.stderr | 2 +- 8 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2c37606164..92cba2d73a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.82.0" -pinned-nightly = "nightly-2024-10-29" +pinned-nightly = "nightly-2024-10-30" [package.metadata.docs.rs] all-features = true diff --git a/tests/ui-nightly/invalid-impls/invalid-impls.stderr b/tests/ui-nightly/invalid-impls/invalid-impls.stderr index ed76b4df2b..f3a11a0e2d 100644 --- a/tests/ui-nightly/invalid-impls/invalid-impls.stderr +++ b/tests/ui-nightly/invalid-impls/invalid-impls.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: zerocopy::TryFromBytes` is not satisfied --> tests/ui-nightly/invalid-impls/invalid-impls.rs:26:39 | 26 | impl_or_verify!(T => TryFromBytes for Foo); - | ^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `T`, which is required by `Foo: zerocopy::TryFromBytes` + | ^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `T` | = note: Consider adding `#[derive(TryFromBytes)]` to `T` note: required for `Foo` to implement `zerocopy::TryFromBytes` @@ -30,7 +30,7 @@ error[E0277]: the trait bound `T: zerocopy::FromZeros` is not satisfied --> tests/ui-nightly/invalid-impls/invalid-impls.rs:27:36 | 27 | impl_or_verify!(T => FromZeros for Foo); - | ^^^^^^ the trait `zerocopy::FromZeros` is not implemented for `T`, which is required by `Foo: zerocopy::FromZeros` + | ^^^^^^ the trait `zerocopy::FromZeros` is not implemented for `T` | = note: Consider adding `#[derive(FromZeros)]` to `T` note: required for `Foo` to implement `zerocopy::FromZeros` @@ -58,7 +58,7 @@ error[E0277]: the trait bound `T: zerocopy::FromBytes` is not satisfied --> tests/ui-nightly/invalid-impls/invalid-impls.rs:28:36 | 28 | impl_or_verify!(T => FromBytes for Foo); - | ^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `T`, which is required by `Foo: zerocopy::FromBytes` + | ^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `T` | = note: Consider adding `#[derive(FromBytes)]` to `T` note: required for `Foo` to implement `zerocopy::FromBytes` @@ -86,7 +86,7 @@ error[E0277]: the trait bound `T: zerocopy::IntoBytes` is not satisfied --> tests/ui-nightly/invalid-impls/invalid-impls.rs:29:36 | 29 | impl_or_verify!(T => IntoBytes for Foo); - | ^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `T`, which is required by `Foo: zerocopy::IntoBytes` + | ^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `T` | = note: Consider adding `#[derive(IntoBytes)]` to `T` note: required for `Foo` to implement `zerocopy::IntoBytes` @@ -114,7 +114,7 @@ error[E0277]: the trait bound `T: zerocopy::Unaligned` is not satisfied --> tests/ui-nightly/invalid-impls/invalid-impls.rs:30:36 | 30 | impl_or_verify!(T => Unaligned for Foo); - | ^^^^^^ the trait `zerocopy::Unaligned` is not implemented for `T`, which is required by `Foo: zerocopy::Unaligned` + | ^^^^^^ the trait `zerocopy::Unaligned` is not implemented for `T` | = note: Consider adding `#[derive(Unaligned)]` to `T` note: required for `Foo` to implement `zerocopy::Unaligned` diff --git a/zerocopy-derive/tests/ui-nightly/derive_transparent.stderr b/zerocopy-derive/tests/ui-nightly/derive_transparent.stderr index be89f5180e..d64855dc95 100644 --- a/zerocopy-derive/tests/ui-nightly/derive_transparent.stderr +++ b/zerocopy-derive/tests/ui-nightly/derive_transparent.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis --> tests/ui-nightly/derive_transparent.rs:34:23 | 34 | util_assert_impl_all!(TransparentStruct: TryFromBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy`, which is required by `TransparentStruct: zerocopy::TryFromBytes` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: @@ -31,7 +31,7 @@ error[E0277]: the trait bound `NotZerocopy: FromZeros` is not satisfied --> tests/ui-nightly/derive_transparent.rs:35:23 | 35 | util_assert_impl_all!(TransparentStruct: FromZeros); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromZeros` is not implemented for `NotZerocopy`, which is required by `TransparentStruct: FromZeros` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromZeros` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(FromZeros)]` to `NotZerocopy` = help: the following other types implement trait `FromZeros`: @@ -60,7 +60,7 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfie --> tests/ui-nightly/derive_transparent.rs:36:23 | 36 | util_assert_impl_all!(TransparentStruct: FromBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy`, which is required by `TransparentStruct: zerocopy::FromBytes` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(FromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::FromBytes`: @@ -89,7 +89,7 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfie --> tests/ui-nightly/derive_transparent.rs:37:23 | 37 | util_assert_impl_all!(TransparentStruct: IntoBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy`, which is required by `TransparentStruct: zerocopy::IntoBytes` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::IntoBytes`: @@ -118,7 +118,7 @@ error[E0277]: the trait bound `NotZerocopy: Unaligned` is not satisfied --> tests/ui-nightly/derive_transparent.rs:38:23 | 38 | util_assert_impl_all!(TransparentStruct: Unaligned); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `NotZerocopy`, which is required by `TransparentStruct: Unaligned` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(Unaligned)]` to `NotZerocopy` = help: the following other types implement trait `Unaligned`: diff --git a/zerocopy-derive/tests/ui-nightly/enum.stderr b/zerocopy-derive/tests/ui-nightly/enum.stderr index e395a0c908..e01edaeb19 100644 --- a/zerocopy-derive/tests/ui-nightly/enum.stderr +++ b/zerocopy-derive/tests/ui-nightly/enum.stderr @@ -513,7 +513,7 @@ error[E0277]: the trait bound `bool: FromBytes` is not satisfied --> tests/ui-nightly/enum.rs:191:10 | 191 | #[derive(FromBytes)] - | ^^^^^^^^^ the trait `FromBytes` is not implemented for `bool`, which is required by `FooU8: FromBytes` + | ^^^^^^^^^ the trait `FromBytes` is not implemented for `bool` | = note: Consider adding `#[derive(FromBytes)]` to `bool` = help: the following other types implement trait `FromBytes`: diff --git a/zerocopy-derive/tests/ui-nightly/late_compile_pass.stderr b/zerocopy-derive/tests/ui-nightly/late_compile_pass.stderr index 99f22d741a..d748d60039 100644 --- a/zerocopy-derive/tests/ui-nightly/late_compile_pass.stderr +++ b/zerocopy-derive/tests/ui-nightly/late_compile_pass.stderr @@ -250,7 +250,7 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfie --> tests/ui-nightly/late_compile_pass.rs:46:10 | 46 | #[derive(FromBytes)] - | ^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy`, which is required by `FromBytes1: zerocopy::FromBytes` + | ^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(FromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::FromBytes`: diff --git a/zerocopy-derive/tests/ui-nightly/mid_compile_pass.stderr b/zerocopy-derive/tests/ui-nightly/mid_compile_pass.stderr index df63b508f4..59829be7ec 100644 --- a/zerocopy-derive/tests/ui-nightly/mid_compile_pass.stderr +++ b/zerocopy-derive/tests/ui-nightly/mid_compile_pass.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: KnownLayout` is not satisfied --> tests/ui-nightly/mid_compile_pass.rs:59:26 | 59 | fn test_kl13(t: T) -> impl KnownLayout { - | ^^^^^^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `T`, which is required by `KL13: KnownLayout` + | ^^^^^^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `T` | = note: Consider adding `#[derive(KnownLayout)]` to `T` note: required for `KL13` to implement `KnownLayout` @@ -84,7 +84,7 @@ error[E0277]: the trait bound `T: KnownLayout` is not satisfied --> tests/ui-nightly/mid_compile_pass.rs:50:15 | 50 | assert_kl(kl) - | --------- ^^ the trait `KnownLayout` is not implemented for `T`, which is required by `KL12: KnownLayout` + | --------- ^^ the trait `KnownLayout` is not implemented for `T` | | | required by a bound introduced by this call | diff --git a/zerocopy-derive/tests/ui-nightly/struct.stderr b/zerocopy-derive/tests/ui-nightly/struct.stderr index bc9e0a8b7b..a776cec826 100644 --- a/zerocopy-derive/tests/ui-nightly/struct.stderr +++ b/zerocopy-derive/tests/ui-nightly/struct.stderr @@ -95,7 +95,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation 31 | #[derive(KnownLayout)] | ^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `KL00`, the trait `Sized` is not implemented for `[u8]`, which is required by `KL00: Sized` + = help: within `KL00`, the trait `Sized` is not implemented for `[u8]` note: required because it appears within the type `KL00` --> tests/ui-nightly/struct.rs:32:8 | @@ -114,7 +114,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation 36 | #[derive(KnownLayout)] | ^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `KL02`, the trait `Sized` is not implemented for `[u8]`, which is required by `KL02: Sized` + = help: within `KL02`, the trait `Sized` is not implemented for `[u8]` note: required because it appears within the type `KL02` --> tests/ui-nightly/struct.rs:37:8 | @@ -203,7 +203,7 @@ error[E0277]: the trait bound `UnsafeCell: zerocopy::Immutable` is not satis --> tests/ui-nightly/struct.rs:60:10 | 60 | #[derive(Immutable)] - | ^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `UnsafeCell`, which is required by `[UnsafeCell; 0]: zerocopy::Immutable` + | ^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `UnsafeCell` | = note: Consider adding `#[derive(Immutable)]` to `UnsafeCell` = help: the following other types implement trait `zerocopy::Immutable`: @@ -338,7 +338,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation 125 | #[derive(IntoBytes)] | ^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `IntoBytes4`, the trait `Sized` is not implemented for `[u8]`, which is required by `IntoBytes4: macro_util::__size_of::Sized` + = help: within `IntoBytes4`, the trait `Sized` is not implemented for `[u8]` note: required because it appears within the type `IntoBytes4` --> tests/ui-nightly/struct.rs:127:8 | @@ -358,7 +358,7 @@ error[E0277]: `[u8]` is unsized 129 | b: [u8], | ^^^^ `IntoBytes` needs all field types to be `Sized` in order to determine whether there is inter-field padding | - = help: the trait `Sized` is not implemented for `[u8]`, which is required by `[u8]: macro_util::__size_of::Sized` + = help: the trait `Sized` is not implemented for `[u8]` = note: consider using `#[repr(packed)]` to remove inter-field padding = note: `IntoBytes` does not require the fields of `#[repr(packed)]` types to be `Sized` = note: required for `[u8]` to implement `macro_util::__size_of::Sized` @@ -378,7 +378,7 @@ error[E0277]: the trait bound `AU16: Unaligned` is not satisfied --> tests/ui-nightly/struct.rs:161:28 | 161 | is_into_bytes_11::>(); - | ^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16`, which is required by `IntoBytes11: zerocopy::IntoBytes` + | ^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` | = note: Consider adding `#[derive(Unaligned)]` to `AU16` = help: the following other types implement trait `Unaligned`: diff --git a/zerocopy-derive/tests/ui-nightly/union.stderr b/zerocopy-derive/tests/ui-nightly/union.stderr index 9060b9947b..4a6210e7b1 100644 --- a/zerocopy-derive/tests/ui-nightly/union.stderr +++ b/zerocopy-derive/tests/ui-nightly/union.stderr @@ -66,7 +66,7 @@ error[E0277]: the trait bound `UnsafeCell<()>: zerocopy::Immutable` is not satis --> tests/ui-nightly/union.rs:24:10 | 24 | #[derive(Immutable)] - | ^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `UnsafeCell<()>`, which is required by `ManuallyDrop>: zerocopy::Immutable` + | ^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `UnsafeCell<()>` | = note: Consider adding `#[derive(Immutable)]` to `UnsafeCell<()>` = help: the following other types implement trait `zerocopy::Immutable`: From e9e8cfc2cd7c8cba7b530b24b24c9bc20eddd545 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Fri, 1 Nov 2024 05:55:04 -0700 Subject: [PATCH 49/96] [ci] Roll pinned nightly toolchain (#2003) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 92cba2d73a..25a09e899e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.82.0" -pinned-nightly = "nightly-2024-10-30" +pinned-nightly = "nightly-2024-10-31" [package.metadata.docs.rs] all-features = true From 6aba344b61ce71f78da32a3e8e4559af7500fa9c Mon Sep 17 00:00:00 2001 From: Aditya Pratap Singh Date: Fri, 1 Nov 2024 21:58:20 +0530 Subject: [PATCH 50/96] documented how to implement enums with endian-specific tags (#1993) --- src/lib.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index f2af6f8b9f..8660d3988d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1182,6 +1182,26 @@ pub unsafe trait Immutable { /// } /// ``` /// +/// # Portability +/// +/// To ensure consistent endianness for enums with multi-byte representations, +/// explicitly specify and convert each discriminant using `.to_le()` or +/// `.to_be()`; e.g.: +/// +/// ``` +/// # use zerocopy_derive::TryFromBytes; +/// // `DataStoreVersion` is encoded in little-endian. +/// #[derive(TryFromBytes)] +/// #[repr(u32)] +/// pub enum DataStoreVersion { +/// /// Version 1 of the data store. +/// V1 = 9u32.to_le(), +/// +/// /// Version 2 of the data store. +/// V2 = 10u32.to_le(), +/// } +/// ``` +/// /// [safety conditions]: trait@TryFromBytes#safety #[cfg(any(feature = "derive", test))] #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] From 947397172a81f12eae01cf11faa37730cd49a217 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Sat, 2 Nov 2024 06:53:20 -0700 Subject: [PATCH 51/96] [ci] Roll pinned nightly toolchain (#2006) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 25a09e899e..527f107d58 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.82.0" -pinned-nightly = "nightly-2024-10-31" +pinned-nightly = "nightly-2024-11-01" [package.metadata.docs.rs] all-features = true From f9e09fd978bd074a8544b962fad690958ea33a43 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Sun, 3 Nov 2024 15:02:30 -0800 Subject: [PATCH 52/96] [ci] Roll pinned nightly toolchain (#2008) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 527f107d58..4eb8c4a6e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.82.0" -pinned-nightly = "nightly-2024-11-01" +pinned-nightly = "nightly-2024-11-02" [package.metadata.docs.rs] all-features = true From 255babe875f371a6e2a9e01c258ce5ebc54bd6bb Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Mon, 4 Nov 2024 07:33:46 -0800 Subject: [PATCH 53/96] [ci] Roll pinned nightly toolchain (#2011) --- Cargo.toml | 2 +- .../transmute-mut-src-dst-not-references.stderr | 5 +++++ tests/ui-nightly/transmute-mut-src-immutable.stderr | 5 +++++ .../transmute-mut-src-not-a-reference.stderr | 5 +++++ .../transmute-ref-src-dst-not-references.stderr | 5 +++++ .../transmute-ref-src-not-a-reference.stderr | 5 +++++ zerocopy-derive/tests/ui-nightly/enum.stderr | 12 ++++++------ .../tests/ui-nightly/mid_compile_pass.stderr | 2 ++ zerocopy-derive/tests/ui-nightly/struct.stderr | 8 ++++---- zerocopy-derive/tests/ui-nightly/union.stderr | 4 ++-- 10 files changed, 40 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4eb8c4a6e0..ab36f791f2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.82.0" -pinned-nightly = "nightly-2024-11-02" +pinned-nightly = "nightly-2024-11-03" [package.metadata.docs.rs] all-features = true diff --git a/tests/ui-nightly/transmute-mut-src-dst-not-references.stderr b/tests/ui-nightly/transmute-mut-src-dst-not-references.stderr index bdd3f423ef..b66985f93e 100644 --- a/tests/ui-nightly/transmute-mut-src-dst-not-references.stderr +++ b/tests/ui-nightly/transmute-mut-src-dst-not-references.stderr @@ -30,6 +30,11 @@ note: in edition 2024, the requirement `!: FromBytes` will fail | ^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default = note: this warning originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `()` annotations to avoid fallback changes + --> src/macros.rs + | + | let e: &mut () = $e; + | ~~ warning: never type fallback affects this call to an `unsafe` function --> tests/ui-nightly/transmute-mut-src-dst-not-references.rs:17:44 diff --git a/tests/ui-nightly/transmute-mut-src-immutable.stderr b/tests/ui-nightly/transmute-mut-src-immutable.stderr index abaac99588..7f60c95c0e 100644 --- a/tests/ui-nightly/transmute-mut-src-immutable.stderr +++ b/tests/ui-nightly/transmute-mut-src-immutable.stderr @@ -26,6 +26,11 @@ note: in edition 2024, the requirement `!: FromBytes` will fail | ^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default = note: this warning originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `()` annotations to avoid fallback changes + --> src/macros.rs + | + | let e: &mut () = $e; + | ~~ warning: never type fallback affects this call to an `unsafe` function --> tests/ui-nightly/transmute-mut-src-immutable.rs:17:22 diff --git a/tests/ui-nightly/transmute-mut-src-not-a-reference.stderr b/tests/ui-nightly/transmute-mut-src-not-a-reference.stderr index 8fc4476d1e..491983e408 100644 --- a/tests/ui-nightly/transmute-mut-src-not-a-reference.stderr +++ b/tests/ui-nightly/transmute-mut-src-not-a-reference.stderr @@ -30,6 +30,11 @@ note: in edition 2024, the requirement `!: FromBytes` will fail | ^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default = note: this warning originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `()` annotations to avoid fallback changes + --> src/macros.rs + | + | let e: &mut () = $e; + | ~~ warning: never type fallback affects this call to an `unsafe` function --> tests/ui-nightly/transmute-mut-src-not-a-reference.rs:17:38 diff --git a/tests/ui-nightly/transmute-ref-src-dst-not-references.stderr b/tests/ui-nightly/transmute-ref-src-dst-not-references.stderr index 18ecbbdd74..adb3a17d39 100644 --- a/tests/ui-nightly/transmute-ref-src-dst-not-references.stderr +++ b/tests/ui-nightly/transmute-ref-src-dst-not-references.stderr @@ -93,6 +93,11 @@ note: in edition 2024, the requirement `!: IntoBytes` will fail | ^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default = note: this warning originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `()` annotations to avoid fallback changes + --> src/macros.rs + | + | let e: &() = $e; + | ~~ warning: never type fallback affects this call to an `unsafe` function --> tests/ui-nightly/transmute-ref-src-dst-not-references.rs:17:39 diff --git a/tests/ui-nightly/transmute-ref-src-not-a-reference.stderr b/tests/ui-nightly/transmute-ref-src-not-a-reference.stderr index 3a55b4c612..866f695ee4 100644 --- a/tests/ui-nightly/transmute-ref-src-not-a-reference.stderr +++ b/tests/ui-nightly/transmute-ref-src-not-a-reference.stderr @@ -30,6 +30,11 @@ note: in edition 2024, the requirement `!: IntoBytes` will fail | ^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default = note: this warning originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `()` annotations to avoid fallback changes + --> src/macros.rs + | + | let e: &() = $e; + | ~~ warning: never type fallback affects this call to an `unsafe` function --> tests/ui-nightly/transmute-ref-src-not-a-reference.rs:17:34 diff --git a/zerocopy-derive/tests/ui-nightly/enum.stderr b/zerocopy-derive/tests/ui-nightly/enum.stderr index e01edaeb19..a60591a05a 100644 --- a/zerocopy-derive/tests/ui-nightly/enum.stderr +++ b/zerocopy-derive/tests/ui-nightly/enum.stderr @@ -448,11 +448,11 @@ error[E0277]: `IntoBytes1` has inter-field padding 538 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) help: add `#![feature(trivial_bounds)]` to the crate attributes to enable @@ -466,11 +466,11 @@ error[E0277]: `IntoBytes2` has inter-field padding 549 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) help: add `#![feature(trivial_bounds)]` to the crate attributes to enable @@ -484,11 +484,11 @@ error[E0277]: `IntoBytes3` has inter-field padding 555 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) help: add `#![feature(trivial_bounds)]` to the crate attributes to enable diff --git a/zerocopy-derive/tests/ui-nightly/mid_compile_pass.stderr b/zerocopy-derive/tests/ui-nightly/mid_compile_pass.stderr index 59829be7ec..c80f1beee7 100644 --- a/zerocopy-derive/tests/ui-nightly/mid_compile_pass.stderr +++ b/zerocopy-derive/tests/ui-nightly/mid_compile_pass.stderr @@ -3,6 +3,8 @@ error[E0277]: the trait bound `T: KnownLayout` is not satisfied | 59 | fn test_kl13(t: T) -> impl KnownLayout { | ^^^^^^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `T` +60 | KL13(0u8, t) + | ------------ return type was inferred to be `KL13` here | = note: Consider adding `#[derive(KnownLayout)]` to `T` note: required for `KL13` to implement `KnownLayout` diff --git a/zerocopy-derive/tests/ui-nightly/struct.stderr b/zerocopy-derive/tests/ui-nightly/struct.stderr index a776cec826..200a12683b 100644 --- a/zerocopy-derive/tests/ui-nightly/struct.stderr +++ b/zerocopy-derive/tests/ui-nightly/struct.stderr @@ -302,11 +302,11 @@ error[E0277]: `IntoBytes2` has inter-field padding 107 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) help: add `#![feature(trivial_bounds)]` to the crate attributes to enable @@ -320,11 +320,11 @@ error[E0277]: `IntoBytes3` has inter-field padding 114 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) help: add `#![feature(trivial_bounds)]` to the crate attributes to enable diff --git a/zerocopy-derive/tests/ui-nightly/union.stderr b/zerocopy-derive/tests/ui-nightly/union.stderr index 4a6210e7b1..a88c311b73 100644 --- a/zerocopy-derive/tests/ui-nightly/union.stderr +++ b/zerocopy-derive/tests/ui-nightly/union.stderr @@ -93,11 +93,11 @@ error[E0277]: `IntoBytes2` has inter-field padding 39 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) help: add `#![feature(trivial_bounds)]` to the crate attributes to enable From c72fcbf4db8a287599534e854aef8b2c18e891ca Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Mon, 4 Nov 2024 08:52:34 -0800 Subject: [PATCH 54/96] Always inline layout validation and pointer cast code to optimize out panics in (#1997) (#2013) `validate_cast_and_convert_metadata`. If `try_cast_into` and `validate_cast_and_convert_metadata` are not inlined, then the compiler will include a panic in `validate_cast_and_convert_metadata`. If these functions are inlined, then the panic can be optimized out. Co-authored-by: Carl Lundin <108372512+clundin25@users.noreply.github.com> --- src/layout.rs | 1 + src/pointer/ptr.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/layout.rs b/src/layout.rs index 5aaf102f8a..e73fef409b 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -451,6 +451,7 @@ impl DstLayout { /// rely on `validate_cast_and_convert_metadata` panicking in any particular /// condition, even if `debug_assertions` are enabled. #[allow(unused)] + #[inline(always)] pub(crate) const fn validate_cast_and_convert_metadata( &self, addr: usize, diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index b476d1428f..c134139032 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -906,6 +906,7 @@ mod _casts { /// - If this is a prefix cast, `ptr` has the same address as `self`. /// - If this is a suffix cast, `remainder` has the same address as /// `self`. + #[inline(always)] pub(crate) fn try_cast_into( self, cast_type: CastType, From 3d5a8a6fb90db6f0c02af6097e2f804aef4f8128 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Mon, 4 Nov 2024 15:46:22 -0800 Subject: [PATCH 55/96] [ci] Add GitHub Action to backport PR (#2017) Closes #2014 gherrit-pr-id: I70bf2382d041da61ff8d85be9fc593cacc08e215 --- .github/workflows/backport-pr.yml | 52 +++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 .github/workflows/backport-pr.yml diff --git a/.github/workflows/backport-pr.yml b/.github/workflows/backport-pr.yml new file mode 100644 index 0000000000..da5f0a9b52 --- /dev/null +++ b/.github/workflows/backport-pr.yml @@ -0,0 +1,52 @@ +# Copyright 2024 The Fuchsia Authors +# +# Licensed under a BSD-style license , Apache License, Version 2.0 +# , or the MIT +# license , at your option. +# This file may not be copied, modified, or distributed except according to +# those terms. + +name: Backport PR +on: + workflow_dispatch: + inputs: + commit: + description: "Commit to backport" + required: true + target_branch: + description: "Target branch for the new PR" + required: true + default: 'main' + +permissions: read-all + +jobs: + release: + runs-on: ubuntu-latest + name: Backport PR + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + ref: ${{ github.event.inputs.target_branch }} + persist-credentials: false + - name: Cherry-pick commit + run: | + set -eo pipefail + git cherry-pick ${{ github.event.inputs.commit }} + + PR_TITLE="$(git log -1 --pretty=%s)" + echo "PR_TITLE=$PR_TITLE" >> $GITHUB_ENV + + AUTHOR="$(git log -1 --pretty='%an <%ae>')" + echo "AUTHOR=$AUTHOR" >> $GITHUB_ENV + + - name: Submit PR + uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7.0.5 + with: + author: "${{ env.AUTHOR }}" + committer: "${{ env.AUTHOR }}" + title: "${{ env.PR_TITLE }}" + branch: backport-${{ github.event.inputs.commit }} + push-to-fork: google-pr-creation-bot/zerocopy + token: ${{ secrets.GOOGLE_PR_CREATION_BOT_TOKEN }} From 375c032551b4ecd2a622ee4b4ec5d7a03d357552 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Mon, 4 Nov 2024 16:52:59 -0800 Subject: [PATCH 56/96] [ci][backport-pr] Fetch all commits, configure git author (#2018) gherrit-pr-id: I8c3db36d20b511c31ec774db68896f2fe4b539bb --- .github/workflows/backport-pr.yml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/backport-pr.yml b/.github/workflows/backport-pr.yml index da5f0a9b52..c663d55485 100644 --- a/.github/workflows/backport-pr.yml +++ b/.github/workflows/backport-pr.yml @@ -29,16 +29,27 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ github.event.inputs.target_branch }} + # Check out the entire repository so that the target commit is checked + # out (by default, only fetches the single commit identified by the + # `ref` argument). + fetch-depth: 0 persist-credentials: false - name: Cherry-pick commit run: | set -eo pipefail + + AUTHOR_NAME="$(git log -1 --pretty='%an' ${{ github.event.inputs.commit }})" + AUTHOR_EMAIL="$(git log -1 --pretty='%ae' ${{ github.event.inputs.commit }})" + + git config --global user.name "$AUTHOR_NAME" + git config --global user.email "$AUTHOR_EMAIL" + git cherry-pick ${{ github.event.inputs.commit }} - + PR_TITLE="$(git log -1 --pretty=%s)" echo "PR_TITLE=$PR_TITLE" >> $GITHUB_ENV - AUTHOR="$(git log -1 --pretty='%an <%ae>')" + AUTHOR="$AUTHOR_NAME <$AUTHOR_EMAIL>" echo "AUTHOR=$AUTHOR" >> $GITHUB_ENV - name: Submit PR From ace5bb0de76e150d2284984677892a5aaa34a36e Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Tue, 5 Nov 2024 04:51:27 -0800 Subject: [PATCH 57/96] [ci] Roll pinned nightly toolchain (#2023) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ab36f791f2..cf08c2db55 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.82.0" -pinned-nightly = "nightly-2024-11-03" +pinned-nightly = "nightly-2024-11-04" [package.metadata.docs.rs] all-features = true From 13c11f8646cc51c8e985967ac61f836945326d06 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Tue, 5 Nov 2024 13:17:40 -0800 Subject: [PATCH 58/96] [layout] Update test documentation (#2026) gherrit-pr-id: I8aec00c4246e0e9f80c90c3295ffd79921d4d8b3 --- src/layout.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/layout.rs b/src/layout.rs index e73fef409b..2a505b20c1 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -797,16 +797,15 @@ mod tests { /// This macro accepts arguments in the form of: /// - /// layout(_, _, _).validate(_, _, _), Ok(Some((_, _))) - /// | | | | | | | | - /// base_size ----+ | | | | | | | - /// align -----------+ | | | | | | - /// trailing_size ------+ | | | | | - /// addr ---------------------------+ | | | | - /// bytes_len -------------------------+ | | | - /// cast_type ----------------------------+ | | - /// elems ---------------------------------------------+ | - /// split_at ---------------------------------------------+ + /// layout(_, _).validate(_, _, _), Ok(Some((_, _))) + /// | | | | | | | + /// size ---------+ | | | | | | + /// align -----------+ | | | | | + /// addr ------------------------+ | | | | + /// bytes_len ----------------------+ | | | + /// cast_type -------------------------+ | | + /// elems ------------------------------------------+ | + /// split_at ------------------------------------------+ /// /// `.validate` is shorthand for `.validate_cast_and_convert_metadata` /// for brevity. @@ -839,7 +838,7 @@ mod tests { /// `a..b`). In this case, wrap the expression in parentheses, and it /// will become valid `tt`. macro_rules! test { - ($(:$sizes:expr =>)? + ( layout($size:tt, $align:tt) .validate($addr:tt, $bytes_len:tt, $cast_type:tt), $expect:pat $(,)? ) => { From 4de8504dbde75cad4ded6b3fd358beec6a619cb4 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Wed, 6 Nov 2024 07:22:39 -0800 Subject: [PATCH 59/96] [ci] Roll pinned nightly toolchain (#2029) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cf08c2db55..86ece0aa15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.82.0" -pinned-nightly = "nightly-2024-11-04" +pinned-nightly = "nightly-2024-11-05" [package.metadata.docs.rs] all-features = true From 3bcf6f388e15250ba02e564c1453a1bd06b0f5e0 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Wed, 6 Nov 2024 09:16:00 -0800 Subject: [PATCH 60/96] Relax `map_src` argument bound to `FnOnce` (#2012) (#2028) * Relax `map_src` argument bound to `FnOnce` Fixes #2009 * Release v0.8.9 Co-authored-by: Jack Wrenn --- src/error.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/error.rs b/src/error.rs index 729102727d..39b2a864bf 100644 --- a/src/error.rs +++ b/src/error.rs @@ -298,7 +298,7 @@ impl AlignmentError { /// }); /// ``` #[inline] - pub fn map_src(self, f: impl Fn(Src) -> NewSrc) -> AlignmentError { + pub fn map_src(self, f: impl FnOnce(Src) -> NewSrc) -> AlignmentError { AlignmentError { src: f(self.src), dst: SendSyncPhantomData::default() } } @@ -453,7 +453,7 @@ impl SizeError { /// }); /// ``` #[inline] - pub fn map_src(self, f: impl Fn(Src) -> NewSrc) -> SizeError { + pub fn map_src(self, f: impl FnOnce(Src) -> NewSrc) -> SizeError { SizeError { src: f(self.src), dst: SendSyncPhantomData::default() } } @@ -590,7 +590,7 @@ impl ValidityError { /// }); /// ``` #[inline] - pub fn map_src(self, f: impl Fn(Src) -> NewSrc) -> ValidityError { + pub fn map_src(self, f: impl FnOnce(Src) -> NewSrc) -> ValidityError { ValidityError { src: f(self.src), dst: SendSyncPhantomData::default() } } @@ -710,7 +710,7 @@ impl CastError { /// }); /// ``` #[inline] - pub fn map_src(self, f: impl Fn(Src) -> NewSrc) -> CastError { + pub fn map_src(self, f: impl FnOnce(Src) -> NewSrc) -> CastError { match self { Self::Alignment(e) => CastError::Alignment(e.map_src(f)), Self::Size(e) => CastError::Size(e.map_src(f)), @@ -831,7 +831,7 @@ impl TryCastError { /// }); /// ``` #[inline] - pub fn map_src(self, f: impl Fn(Src) -> NewSrc) -> TryCastError { + pub fn map_src(self, f: impl FnOnce(Src) -> NewSrc) -> TryCastError { match self { Self::Alignment(e) => TryCastError::Alignment(e.map_src(f)), Self::Size(e) => TryCastError::Size(e.map_src(f)), @@ -896,7 +896,7 @@ impl TryReadError { /// }); /// ``` #[inline] - pub fn map_src(self, f: impl Fn(Src) -> NewSrc) -> TryReadError { + pub fn map_src(self, f: impl FnOnce(Src) -> NewSrc) -> TryReadError { match self { Self::Alignment(i) => match i {}, Self::Size(e) => TryReadError::Size(e.map_src(f)), From 6fb430edea7765559276dc5320a057229d4fb64e Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Thu, 7 Nov 2024 05:02:44 -0800 Subject: [PATCH 61/96] [ci] Roll pinned nightly toolchain (#2032) --- Cargo.toml | 2 +- tests/ui-nightly/transmute-mut-dst-unsized.stderr | 4 ++-- tests/ui-nightly/transmute-mut-src-dst-unsized.stderr | 4 ++-- tests/ui-nightly/transmute-ref-dst-unsized.stderr | 4 ++-- tests/ui-nightly/transmute-ref-src-dst-unsized.stderr | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 86ece0aa15..8634980a67 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.82.0" -pinned-nightly = "nightly-2024-11-05" +pinned-nightly = "nightly-2024-11-06" [package.metadata.docs.rs] all-features = true diff --git a/tests/ui-nightly/transmute-mut-dst-unsized.stderr b/tests/ui-nightly/transmute-mut-dst-unsized.stderr index 74e58f7ad8..615be547eb 100644 --- a/tests/ui-nightly/transmute-mut-dst-unsized.stderr +++ b/tests/ui-nightly/transmute-mut-dst-unsized.stderr @@ -50,8 +50,8 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation note: required by an implicit `Sized` bound in `std::intrinsics::transmute` --> $RUST/core/src/intrinsics.rs | - | pub fn transmute(src: Src) -> Dst; - | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` + | pub const unsafe fn transmute(_src: Src) -> Dst { + | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time diff --git a/tests/ui-nightly/transmute-mut-src-dst-unsized.stderr b/tests/ui-nightly/transmute-mut-src-dst-unsized.stderr index 1cff579d97..9a17cf51c8 100644 --- a/tests/ui-nightly/transmute-mut-src-dst-unsized.stderr +++ b/tests/ui-nightly/transmute-mut-src-dst-unsized.stderr @@ -147,8 +147,8 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation note: required by an implicit `Sized` bound in `std::intrinsics::transmute` --> $RUST/core/src/intrinsics.rs | - | pub fn transmute(src: Src) -> Dst; - | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` + | pub const unsafe fn transmute(_src: Src) -> Dst { + | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time diff --git a/tests/ui-nightly/transmute-ref-dst-unsized.stderr b/tests/ui-nightly/transmute-ref-dst-unsized.stderr index 3eb5ad5087..34a9fff9ed 100644 --- a/tests/ui-nightly/transmute-ref-dst-unsized.stderr +++ b/tests/ui-nightly/transmute-ref-dst-unsized.stderr @@ -50,8 +50,8 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation note: required by an implicit `Sized` bound in `std::intrinsics::transmute` --> $RUST/core/src/intrinsics.rs | - | pub fn transmute(src: Src) -> Dst; - | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` + | pub const unsafe fn transmute(_src: Src) -> Dst { + | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time diff --git a/tests/ui-nightly/transmute-ref-src-dst-unsized.stderr b/tests/ui-nightly/transmute-ref-src-dst-unsized.stderr index 251e58c5d1..5cdec56f25 100644 --- a/tests/ui-nightly/transmute-ref-src-dst-unsized.stderr +++ b/tests/ui-nightly/transmute-ref-src-dst-unsized.stderr @@ -147,8 +147,8 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation note: required by an implicit `Sized` bound in `std::intrinsics::transmute` --> $RUST/core/src/intrinsics.rs | - | pub fn transmute(src: Src) -> Dst; - | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` + | pub const unsafe fn transmute(_src: Src) -> Dst { + | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time From af5399941e4fd26488a6be212a1dda47402da0c3 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Fri, 8 Nov 2024 10:56:22 -0800 Subject: [PATCH 62/96] Document that derives imply supertraits, where applicable. (#2038) (#2039) Fixes #2037 Co-authored-by: Jack Wrenn --- src/lib.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 8660d3988d..462519f575 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -923,9 +923,9 @@ safety_comment! { /// Analyzes whether a type is [`FromZeros`]. /// /// This derive analyzes, at compile time, whether the annotated type satisfies -/// the [safety conditions] of `FromZeros` and implements `FromZeros` if it is -/// sound to do so. This derive can be applied to structs, enums, and unions; -/// e.g.: +/// the [safety conditions] of `FromZeros` and implements `FromZeros` and its +/// supertraits if it is sound to do so. This derive can be applied to structs, +/// enums, and unions; e.g.: /// /// ``` /// # use zerocopy_derive::{FromZeros, Immutable}; @@ -3174,8 +3174,9 @@ pub unsafe trait FromZeros: TryFromBytes { /// Analyzes whether a type is [`FromBytes`]. /// /// This derive analyzes, at compile time, whether the annotated type satisfies -/// the [safety conditions] of `FromBytes` and implements `FromBytes` if it is -/// sound to do so. This derive can be applied to structs, enums, and unions; +/// the [safety conditions] of `FromBytes` and implements `FromBytes` and its +/// supertraits if it is sound to do so. This derive can be applied to structs, +/// enums, and unions; /// e.g.: /// /// ``` From d3157cc98ca5c23c430335d2e77dfd68924d7cdd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 06:57:49 -0800 Subject: [PATCH 63/96] [CI] Bump github/codeql-action from 3.27.0 to 3.27.1 (#2045) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.27.0 to 3.27.1. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/662472033e021d55d94146f66f6058822b0b39fd...4f3212b61783c3c68e8309a0f18a699764811cda) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index a245b88c5f..672c788b1b 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -66,6 +66,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 + uses: github/codeql-action/upload-sarif@4f3212b61783c3c68e8309a0f18a699764811cda # v3.27.1 with: sarif_file: results.sarif From 6c2a249588d0685198e8df61930f6a5ffe6d7d35 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Mon, 11 Nov 2024 15:52:58 -0800 Subject: [PATCH 64/96] Add `FromBytes::read_from_io` and `IntoBytes::write_to_io` (#2016) (#2046) Makes progress on #158. gherrit-pr-id: I9253d6be7407d8d8679ee355e4e71cd9b15b9ff7 Co-authored-by: Jack Wrenn --- src/lib.rs | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 462519f575..44699ac4a7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -359,6 +359,9 @@ use core::{ slice, }; +#[cfg(feature = "std")] +use std::io; + use crate::pointer::invariant::{self, BecauseExclusive}; #[cfg(any(feature = "alloc", test))] @@ -3068,10 +3071,7 @@ pub unsafe trait FromZeros: TryFromBytes { // "exposed" provenance, and thus Rust may have to assume that this // may consume provenance from any pointer whose provenance has been // exposed. - #[allow(fuzzy_provenance_casts)] - unsafe { - NonNull::new_unchecked(dangling) - } + unsafe { NonNull::new_unchecked(dangling) } }; let ptr = Self::raw_from_ptr_len(ptr, count); @@ -4495,6 +4495,48 @@ pub unsafe trait FromBytes: FromZeros { Err(CastError::Validity(i)) => match i {}, } } + + /// Reads a copy of `self` from an `io::Read`. + /// + /// This is useful for interfacing with operating system byte sinks (files, + /// sockets, etc.). + /// + /// # Examples + /// + /// ```no_run + /// use zerocopy::{byteorder::big_endian::*, FromBytes}; + /// use std::fs::File; + /// # use zerocopy_derive::*; + /// + /// #[derive(FromBytes)] + /// #[repr(C)] + /// struct BitmapFileHeader { + /// signature: [u8; 2], + /// size: U32, + /// reserved: U64, + /// offset: U64, + /// } + /// + /// let mut file = File::open("image.bin").unwrap(); + /// let header = BitmapFileHeader::read_from_io(&mut file).unwrap(); + /// ``` + #[cfg(feature = "std")] + #[inline(always)] + fn read_from_io(mut src: R) -> io::Result + where + Self: Sized, + R: io::Read, + { + let mut buf = MaybeUninit::::zeroed(); + let ptr = Ptr::from_mut(&mut buf); + // SAFETY: `buf` consists entirely of initialized, zeroed bytes. + let ptr = unsafe { ptr.assume_validity::() }; + let ptr = ptr.as_bytes::(); + src.read_exact(ptr.as_mut())?; + // SAFETY: `buf` entirely consists of initialized bytes, and `Self` is + // `FromBytes`. + Ok(unsafe { buf.assume_init() }) + } } /// Interprets the given affix of the given bytes as a `&Self`. @@ -5081,6 +5123,55 @@ pub unsafe trait IntoBytes { } Ok(()) } + + /// Writes a copy of `self` to an `io::Write`. + /// + /// This is a shorthand for `dst.write_all(self.as_bytes())`, and is useful + /// for interfacing with operating system byte sinks (files, sockets, etc.). + /// + /// # Examples + /// + /// ```no_run + /// use zerocopy::{byteorder::big_endian::U16, FromBytes, IntoBytes}; + /// use std::fs::File; + /// # use zerocopy_derive::*; + /// + /// #[derive(FromBytes, IntoBytes, Immutable, KnownLayout)] + /// #[repr(C, packed)] + /// struct GrayscaleImage { + /// height: U16, + /// width: U16, + /// pixels: [U16], + /// } + /// + /// let image = GrayscaleImage::ref_from_bytes(&[0, 0, 0, 0][..]).unwrap(); + /// let mut file = File::create("image.bin").unwrap(); + /// image.write_to_io(&mut file).unwrap(); + /// ``` + /// + /// If the write fails, `write_to_io` returns `Err` and a partial write may + /// have occured; e.g.: + /// + /// ``` + /// # use zerocopy::IntoBytes; + /// + /// let src = u128::MAX; + /// let mut dst = [0u8; 2]; + /// + /// let write_result = src.write_to_io(&mut dst[..]); + /// + /// assert!(write_result.is_err()); + /// assert_eq!(dst, [255, 255]); + /// ``` + #[cfg(feature = "std")] + #[inline(always)] + fn write_to_io(&self, mut dst: W) -> io::Result<()> + where + Self: Immutable, + W: io::Write, + { + dst.write_all(self.as_bytes()) + } } /// Analyzes whether a type is [`Unaligned`]. @@ -5795,6 +5886,20 @@ mod tests { assert_eq!(bytes, want); } + #[test] + #[cfg(feature = "std")] + fn test_read_write_io() { + let mut long_buffer = [0, 0, 0, 0]; + assert!(matches!(u16::MAX.write_to_io(&mut long_buffer[..]), Ok(()))); + assert_eq!(long_buffer, [255, 255, 0, 0]); + assert!(matches!(u16::read_from_io(&long_buffer[..]), Ok(u16::MAX))); + + let mut short_buffer = [0, 0]; + assert!(u32::MAX.write_to_io(&mut short_buffer[..]).is_err()); + assert_eq!(short_buffer, [255, 255]); + assert!(u32::read_from_io(&short_buffer[..]).is_err()); + } + #[test] fn test_try_from_bytes_try_read_from() { assert_eq!(::try_read_from_bytes(&[0]), Ok(false)); From 22b60397e7271986cb11f68a0b2c28ead4247859 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Nov 2024 08:31:55 -0800 Subject: [PATCH 65/96] [CI] Bump github/codeql-action from 3.27.1 to 3.27.2 (#2050) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.27.1 to 3.27.2. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/4f3212b61783c3c68e8309a0f18a699764811cda...9278e421667d5d90a2839487a482448c4ec7df4d) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 672c788b1b..8678956130 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -66,6 +66,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@4f3212b61783c3c68e8309a0f18a699764811cda # v3.27.1 + uses: github/codeql-action/upload-sarif@9278e421667d5d90a2839487a482448c4ec7df4d # v3.27.2 with: sarif_file: results.sarif From 9dc79c23ea616f28d6206d4ed3601331b514c605 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Nov 2024 08:50:25 -0500 Subject: [PATCH 66/96] [CI] Bump github/codeql-action from 3.27.2 to 3.27.3 (#2054) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.27.2 to 3.27.3. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/9278e421667d5d90a2839487a482448c4ec7df4d...396bb3e45325a47dd9ef434068033c6d5bb0d11a) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 8678956130..b61103ff63 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -66,6 +66,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@9278e421667d5d90a2839487a482448c4ec7df4d # v3.27.2 + uses: github/codeql-action/upload-sarif@396bb3e45325a47dd9ef434068033c6d5bb0d11a # v3.27.3 with: sarif_file: results.sarif From 90c438bd4861913339f0ef6e973b1aa671fa8cc7 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Wed, 13 Nov 2024 15:28:54 -0800 Subject: [PATCH 67/96] Suppot the unstable f16 and f128 types (#2042) (#2058) Closes #1999 Co-authored-by: Brezak --- Cargo.toml | 1 + README.md | 4 ++++ src/impls.rs | 4 ++++ src/lib.rs | 5 +++++ src/util/macros.rs | 31 +++++++++++++++++++++++++++++-- 5 files changed, 43 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8634980a67..78e6d5f29b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,6 +61,7 @@ alloc = [] derive = ["zerocopy-derive"] simd = [] simd-nightly = ["simd"] +float-nightly = [] std = ["alloc"] # This feature depends on all other features that work on the stable compiler. # We make no stability guarantees about this feature; it may be modified or diff --git a/README.md b/README.md index 6fa9a240f5..b419c05eda 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,10 @@ for network parsing. available on nightly. Since these types are unstable, support for any type may be removed at any point in the future. +- **`float-nightly`** + Adds support for the unstable `f16` and `f128` types. These types are + not yet fully implemented and may not be supported on all platforms. + [duplicate-import-errors]: https://github.com/google/zerocopy/issues/1587 [simd-layout]: https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html diff --git a/src/impls.rs b/src/impls.rs index 0a552d5231..321bad7fe3 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -72,6 +72,10 @@ safety_comment! { unsafe_impl!(isize: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(f32: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(f64: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); + #[cfg(feature = "float-nightly")] + unsafe_impl!(#[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] f16: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); + #[cfg(feature = "float-nightly")] + unsafe_impl!(#[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] f128: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); } safety_comment! { diff --git a/src/lib.rs b/src/lib.rs index 44699ac4a7..1ff923a509 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -137,6 +137,10 @@ //! available on nightly. Since these types are unstable, support for any type //! may be removed at any point in the future. //! +//! - **`float-nightly`** +//! Adds support for the unstable `f16` and `f128` types. These types are +//! not yet fully implemented and may not be supported on all platforms. +//! //! [duplicate-import-errors]: https://github.com/google/zerocopy/issues/1587 //! [simd-layout]: https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html //! @@ -304,6 +308,7 @@ all(feature = "simd-nightly", any(target_arch = "powerpc", target_arch = "powerpc64")), feature(stdarch_powerpc) )] +#![cfg_attr(feature = "float-nightly", feature(f16, f128))] #![cfg_attr(doc_cfg, feature(doc_cfg))] #![cfg_attr( __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS, diff --git a/src/util/macros.rs b/src/util/macros.rs index 263fde6ac7..5d9eb54a6a 100644 --- a/src/util/macros.rs +++ b/src/util/macros.rs @@ -62,10 +62,37 @@ macro_rules! unsafe_impl { unsafe_impl!(@method $trait $(; |$candidate: MaybeAligned<$repr>| $is_bit_valid)?); } }; + // Implement all `$traits` for `$ty` with no bounds. - ($ty:ty: $($traits:ident),*) => { - $( unsafe_impl!($ty: $traits); )* + // + // The 2 arms under this one are there so we can apply + // N attributes for each one of M trait implementations. + // The simple solution of: + // + // ($(#[$attrs:meta])* $ty:ty: $($traits:ident),*) => { + // $( unsafe_impl!( $(#[$attrs])* $ty: $traits ) );* + // } + // + // Won't work. The macro processor sees that the outer repetition + // contains both $attrs and $traits and expects them to match the same + // amount of fragments. + // + // To solve this we must: + // 1. Pack the attributes into a single token tree fragment we can match over. + // 2. Expand the traits. + // 3. Unpack and expand the attributes. + ($(#[$attrs:meta])* $ty:ty: $($traits:ident),*) => { + unsafe_impl!(@impl_traits_with_packed_attrs { $(#[$attrs])* } $ty: $($traits),*) }; + + (@impl_traits_with_packed_attrs $attrs:tt $ty:ty: $($traits:ident),*) => { + $( unsafe_impl!(@unpack_attrs $attrs $ty: $traits); )* + }; + + (@unpack_attrs { $(#[$attrs:meta])* } $ty:ty: $traits:ident) => { + unsafe_impl!($(#[$attrs])* $ty: $traits); + }; + // This arm is identical to the following one, except it contains a // preceding `const`. If we attempt to handle these with a single arm, there // is an inherent ambiguity between `const` (the keyword) and `const` (the From cfddcf1af8a02919695edfadafc24bd49ed9e0d2 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Wed, 13 Nov 2024 16:09:38 -0800 Subject: [PATCH 68/96] [derive] Suppress non_camel_case_types... (#2057) (#2060) ...in derive-generated code. Closes #2051 gherrit-pr-id: If3dbedcccd338435b5aa72dd724caaf9447b1baa Co-authored-by: Joshua Liebow-Feeser --- zerocopy-derive/src/enum.rs | 2 +- zerocopy-derive/src/lib.rs | 3 ++ zerocopy-derive/src/output_tests.rs | 33 ++++++++++++++++++-- zerocopy-derive/tests/enum_try_from_bytes.rs | 16 ++++++++++ 4 files changed, 50 insertions(+), 4 deletions(-) diff --git a/zerocopy-derive/src/enum.rs b/zerocopy-derive/src/enum.rs index 2392919441..438ed5a01f 100644 --- a/zerocopy-derive/src/enum.rs +++ b/zerocopy-derive/src/enum.rs @@ -35,7 +35,7 @@ pub(crate) fn generate_tag_enum(repr: &EnumRepr, data: &DataEnum) -> TokenStream quote! { #repr - #[allow(dead_code)] + #[allow(dead_code, non_camel_case_types)] enum ___ZerocopyTag { #(#variants,)* } diff --git a/zerocopy-derive/src/lib.rs b/zerocopy-derive/src/lib.rs index 5d2f3ef43f..df12b9be7c 100644 --- a/zerocopy-derive/src/lib.rs +++ b/zerocopy-derive/src/lib.rs @@ -1351,6 +1351,9 @@ fn impl_block( // TODO(#553): Add a test that generates a warning when // `#[allow(deprecated)]` isn't present. #[allow(deprecated)] + // While there are not currently any warnings that this suppresses (that + // we're aware of), it's good future-proofing hygiene. + #[automatically_derived] unsafe impl < #(#params),* > #trait_path for #type_ident < #(#param_idents),* > where #(#bounds,)* diff --git a/zerocopy-derive/src/output_tests.rs b/zerocopy-derive/src/output_tests.rs index 3244747171..175c128821 100644 --- a/zerocopy-derive/src/output_tests.rs +++ b/zerocopy-derive/src/output_tests.rs @@ -102,6 +102,7 @@ fn test_known_layout() { struct Foo; } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::KnownLayout for Foo where Self: ::zerocopy::util::macro_util::core_reexport::marker::Sized, @@ -134,6 +135,7 @@ fn test_immutable() { struct Foo; } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::Immutable for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} } @@ -148,6 +150,7 @@ fn test_try_from_bytes() { struct Foo; } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::TryFromBytes for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} @@ -171,6 +174,7 @@ fn test_from_zeros() { struct Foo; } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::TryFromBytes for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} @@ -185,6 +189,7 @@ fn test_from_zeros() { } #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::FromZeros for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} } @@ -199,6 +204,7 @@ fn test_from_bytes_struct() { struct Foo; } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::TryFromBytes for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} @@ -222,11 +228,13 @@ fn test_from_bytes_struct() { } #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::FromZeros for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} } #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::FromBytes for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} } @@ -243,6 +251,7 @@ fn test_from_bytes_union() { } } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::TryFromBytes for Foo where u8: ::zerocopy::TryFromBytes + ::zerocopy::Immutable, @@ -269,6 +278,7 @@ fn test_from_bytes_union() { } #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::FromZeros for Foo where u8: ::zerocopy::FromZeros + ::zerocopy::Immutable, @@ -277,6 +287,7 @@ fn test_from_bytes_union() { } #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::FromBytes for Foo where u8: ::zerocopy::FromBytes + ::zerocopy::Immutable, @@ -295,6 +306,7 @@ fn test_into_bytes() { struct Foo; } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::IntoBytes for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} } @@ -310,6 +322,7 @@ fn test_into_bytes() { } } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::IntoBytes for Foo where u8: ::zerocopy::IntoBytes, @@ -333,6 +346,7 @@ fn test_unaligned() { struct Foo; } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::Unaligned for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} } @@ -355,6 +369,7 @@ fn test_try_from_bytes_enum() { } } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl<'a: 'static, const N: usize, X, Y: Deref> ::zerocopy::TryFromBytes for ComplexWithGenerics<'a, { N }, X, Y> where @@ -377,7 +392,7 @@ fn test_try_from_bytes_enum() { { use ::zerocopy::util::macro_util::core_reexport; #[repr(u8)] - #[allow(dead_code)] + #[allow(dead_code, non_camel_case_types)] enum ___ZerocopyTag { UnitLike, StructLike, @@ -411,6 +426,7 @@ fn test_try_from_bytes_enum() { where X: Deref; #[allow(deprecated)] + #[automatically_derived] unsafe impl<'a: 'static, const N: usize, X, Y: Deref> ::zerocopy::TryFromBytes for ___ZerocopyVariantStruct_StructLike<'a, { N }, X, Y> where @@ -506,6 +522,7 @@ fn test_try_from_bytes_enum() { where X: Deref; #[allow(deprecated)] + #[automatically_derived] unsafe impl<'a: 'static, const N: usize, X, Y: Deref> ::zerocopy::TryFromBytes for ___ZerocopyVariantStruct_TupleLike<'a, { N }, X, Y> where @@ -642,6 +659,7 @@ fn test_try_from_bytes_enum() { } } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl<'a: 'static, const N: usize, X, Y: Deref> ::zerocopy::TryFromBytes for ComplexWithGenerics<'a, { N }, X, Y> where @@ -664,7 +682,7 @@ fn test_try_from_bytes_enum() { { use ::zerocopy::util::macro_util::core_reexport; #[repr(u32)] - #[allow(dead_code)] + #[allow(dead_code, non_camel_case_types)] enum ___ZerocopyTag { UnitLike, StructLike, @@ -698,6 +716,7 @@ fn test_try_from_bytes_enum() { where X: Deref; #[allow(deprecated)] + #[automatically_derived] unsafe impl<'a: 'static, const N: usize, X, Y: Deref> ::zerocopy::TryFromBytes for ___ZerocopyVariantStruct_StructLike<'a, { N }, X, Y> where @@ -793,6 +812,7 @@ fn test_try_from_bytes_enum() { where X: Deref; #[allow(deprecated)] + #[automatically_derived] unsafe impl<'a: 'static, const N: usize, X, Y: Deref> ::zerocopy::TryFromBytes for ___ZerocopyVariantStruct_TupleLike<'a, { N }, X, Y> where @@ -929,6 +949,7 @@ fn test_try_from_bytes_enum() { } } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl<'a: 'static, const N: usize, X, Y: Deref> ::zerocopy::TryFromBytes for ComplexWithGenerics<'a, { N }, X, Y> where @@ -951,7 +972,7 @@ fn test_try_from_bytes_enum() { { use ::zerocopy::util::macro_util::core_reexport; #[repr(C)] - #[allow(dead_code)] + #[allow(dead_code, non_camel_case_types)] enum ___ZerocopyTag { UnitLike, StructLike, @@ -985,6 +1006,7 @@ fn test_try_from_bytes_enum() { where X: Deref; #[allow(deprecated)] + #[automatically_derived] unsafe impl<'a: 'static, const N: usize, X, Y: Deref> ::zerocopy::TryFromBytes for ___ZerocopyVariantStruct_StructLike<'a, { N }, X, Y> where @@ -1080,6 +1102,7 @@ fn test_try_from_bytes_enum() { where X: Deref; #[allow(deprecated)] + #[automatically_derived] unsafe impl<'a: 'static, const N: usize, X, Y: Deref> ::zerocopy::TryFromBytes for ___ZerocopyVariantStruct_TupleLike<'a, { N }, X, Y> where @@ -1471,6 +1494,7 @@ fn test_from_bytes_enum() { } } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::TryFromBytes for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} @@ -1494,11 +1518,13 @@ fn test_from_bytes_enum() { } #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::FromZeros for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} } #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::FromBytes for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} } @@ -1775,6 +1801,7 @@ fn test_try_from_bytes_trivial_is_bit_valid_enum() { } } expands to { #[allow(deprecated)] + #[automatically_derived] unsafe impl ::zerocopy::TryFromBytes for Foo { fn only_derive_is_allowed_to_implement_this_trait() {} diff --git a/zerocopy-derive/tests/enum_try_from_bytes.rs b/zerocopy-derive/tests/enum_try_from_bytes.rs index 8b866c411b..b3f5884281 100644 --- a/zerocopy-derive/tests/enum_try_from_bytes.rs +++ b/zerocopy-derive/tests/enum_try_from_bytes.rs @@ -626,3 +626,19 @@ fn test_trivial_is_bit_valid() { util_assert_not_impl_any!(FooU8: imp::FromBytes); util::test_trivial_is_bit_valid::(); } + +#[deny(non_camel_case_types)] +mod issue_2051 { + use super::*; + + // Test that the `non_camel_case_types` lint isn't triggered by generated code. + // Prevents regressions of #2051. + #[repr(u32)] + #[derive(imp::TryFromBytes)] + #[allow(non_camel_case_types)] + pub enum Code { + I32_ADD, + I32_SUB, + I32_MUL, + } +} From 7a3c01c381b783ce1c9bac659ebd2bbf95ea9c18 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Nov 2024 10:37:33 -0500 Subject: [PATCH 69/96] [CI] Bump codecov/codecov-action from 4 to 5 (#2067) Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 4 to 5. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v4...v5) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2b6ec5b802..85a9eb045c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -476,7 +476,7 @@ jobs: matrix.target == 'x86_64-unknown-linux-gnu' - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} files: lcov.info From 6394871dd625c2207204ff045eac75b5423c0be1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Nov 2024 15:38:10 +0000 Subject: [PATCH 70/96] [CI] Bump github/codeql-action from 3.27.3 to 3.27.4 (#2068) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.27.3 to 3.27.4. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/396bb3e45325a47dd9ef434068033c6d5bb0d11a...ea9e4e37992a54ee68a9622e985e60c8e8f12d9f) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index b61103ff63..7290b687d5 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -66,6 +66,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@396bb3e45325a47dd9ef434068033c6d5bb0d11a # v3.27.3 + uses: github/codeql-action/upload-sarif@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # v3.27.4 with: sarif_file: results.sarif From 2bac3e58728c39607fad9db4e9ef17c9181cbbb8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Nov 2024 10:36:13 -0500 Subject: [PATCH 71/96] [CI] Bump step-security/harden-runner from 2.10.1 to 2.10.2 (#2079) Bumps [step-security/harden-runner](https://github.com/step-security/harden-runner) from 2.10.1 to 2.10.2. - [Release notes](https://github.com/step-security/harden-runner/releases) - [Commits](https://github.com/step-security/harden-runner/compare/91182cccc01eb5e619899d80e4e971d6181294a7...0080882f6c36860b6ba35c610c98ce87d4e2f26f) --- updated-dependencies: - dependency-name: step-security/harden-runner dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/dependency-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 6c8b4e378b..6a2c0d5e1d 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -25,7 +25,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit From ed40b20640826acb5fad21f2af2efdf6592cd30b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 09:01:06 -0500 Subject: [PATCH 72/96] [CI] Bump actions/dependency-review-action from 4.4.0 to 4.5.0 (#2090) Bumps [actions/dependency-review-action](https://github.com/actions/dependency-review-action) from 4.4.0 to 4.5.0. - [Release notes](https://github.com/actions/dependency-review-action/releases) - [Commits](https://github.com/actions/dependency-review-action/compare/4081bf99e2866ebe428fc0477b69eb4fcda7220a...3b139cfc5fae8b618d3eae3675e383bb1769c019) --- updated-dependencies: - dependency-name: actions/dependency-review-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/dependency-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 6a2c0d5e1d..3bb60c004e 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -32,4 +32,4 @@ jobs: - name: 'Checkout Repository' uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: 'Dependency Review' - uses: actions/dependency-review-action@4081bf99e2866ebe428fc0477b69eb4fcda7220a # v4.4.0 + uses: actions/dependency-review-action@3b139cfc5fae8b618d3eae3675e383bb1769c019 # v4.5.0 From 51bc4df582e16f3afbe31d65291c3fb78ee092d3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 14:01:22 +0000 Subject: [PATCH 73/96] [CI] Bump github/codeql-action from 3.27.4 to 3.27.5 (#2089) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.27.4 to 3.27.5. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/ea9e4e37992a54ee68a9622e985e60c8e8f12d9f...f09c1c0a94de965c15400f5634aa42fac8fb8f88) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 7290b687d5..3e93fa5c87 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -66,6 +66,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # v3.27.4 + uses: github/codeql-action/upload-sarif@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 with: sarif_file: results.sarif From de1c6d856f866864e5471156754cc3e81eda1448 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Tue, 3 Dec 2024 05:23:39 -0800 Subject: [PATCH 74/96] [ci] Roll pinned stable toolchain (#2120) --- Cargo.toml | 2 +- tests/ui-stable/transmute-mut-const.stderr | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 78e6d5f29b..34cd3f0c25 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. -pinned-stable = "1.82.0" +pinned-stable = "1.83.0" pinned-nightly = "nightly-2024-11-06" [package.metadata.docs.rs] diff --git a/tests/ui-stable/transmute-mut-const.stderr b/tests/ui-stable/transmute-mut-const.stderr index 076dcf54ac..f080090720 100644 --- a/tests/ui-stable/transmute-mut-const.stderr +++ b/tests/ui-stable/transmute-mut-const.stderr @@ -13,14 +13,6 @@ note: `const` item defined here | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(const_item_mutation)]` on by default -error[E0658]: mutable references are not allowed in constants - --> tests/ui-stable/transmute-mut-const.rs:20:52 - | -20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #57349 for more information - error[E0015]: cannot call non-const fn `transmute_mut::<'_, '_, [u8; 2], [u8; 2]>` in constants --> tests/ui-stable/transmute-mut-const.rs:20:37 | From 775a1ba68d999e0b00404147151f9cec22f0e775 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Dec 2024 13:46:48 +0000 Subject: [PATCH 75/96] [CI] Bump github/codeql-action from 3.27.5 to 3.27.6 (#2122) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.27.5 to 3.27.6. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/f09c1c0a94de965c15400f5634aa42fac8fb8f88...aa578102511db1f4524ed59b8cc2bae4f6e88195) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 3e93fa5c87..1d2e95eb63 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -66,6 +66,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 + uses: github/codeql-action/upload-sarif@aa578102511db1f4524ed59b8cc2bae4f6e88195 # v3.27.6 with: sarif_file: results.sarif From 9a2fce6f4410f4fc92a25f6bc923980df8089e8e Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Tue, 3 Dec 2024 08:02:53 -0800 Subject: [PATCH 76/96] [derive] Don't emit #[cfg(coverage_nightly)] (#2123) (#2126) As of nightly-2024-11-20 - specifically [1] - this triggers an `unexpected_cfgs` lint even when emitted in derive-generated code. [1] https://github.com/rust-lang/rust/pull/132577 Fixes #2117 gherrit-pr-id: I9d536f0ea08475afe0b65411b225aa55f4db449a --- zerocopy-derive/tests/issue_2117.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 zerocopy-derive/tests/issue_2117.rs diff --git a/zerocopy-derive/tests/issue_2117.rs b/zerocopy-derive/tests/issue_2117.rs new file mode 100644 index 0000000000..1ee809ae70 --- /dev/null +++ b/zerocopy-derive/tests/issue_2117.rs @@ -0,0 +1,20 @@ +// Copyright 2024 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +// See comment in `include.rs` for why we disable the prelude. +#![no_implicit_prelude] +#![allow(warnings)] +#![forbid(unexpected_cfgs)] + +include!("include.rs"); + +// Make sure no unexpected `cfg`s are emitted by our derives (see #2117). + +#[derive(imp::KnownLayout)] +#[repr(C)] +pub struct Test(pub [u8; 32]); From a3f102d26efea1e64533750639e16ce68faca36f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Dec 2024 13:12:38 -0500 Subject: [PATCH 77/96] [CI] Bump github/codeql-action from 3.27.6 to 3.27.7 (#2148) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.27.6 to 3.27.7. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/aa578102511db1f4524ed59b8cc2bae4f6e88195...babb554ede22fd5605947329c4d04d8e7a0b8155) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 1d2e95eb63..74576bdb6c 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -66,6 +66,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@aa578102511db1f4524ed59b8cc2bae4f6e88195 # v3.27.6 + uses: github/codeql-action/upload-sarif@babb554ede22fd5605947329c4d04d8e7a0b8155 # v3.27.7 with: sarif_file: results.sarif From 89c652ab68ca2e21bd1ffda342869c68fe6756b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Dec 2024 10:04:49 -0500 Subject: [PATCH 78/96] [CI] Bump actions/upload-artifact from 4.4.3 to 4.5.0 (#2168) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.4.3 to 4.5.0. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882...6f51ac03b9356f520e9adb1b1b7802705f340c2b) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 74576bdb6c..c9d9a32325 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -58,7 +58,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 with: name: SARIF file path: results.sarif From 1d6fa5647ae94a8cc51a6b369e34285f1b3bb898 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 22 Dec 2024 07:52:24 -0500 Subject: [PATCH 79/96] [CI] Bump github/codeql-action from 3.27.7 to 3.27.9 (#2156) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.27.7 to 3.27.9. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/babb554ede22fd5605947329c4d04d8e7a0b8155...df409f7d9260372bd5f19e5b04e83cb3c43714ae) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index c9d9a32325..147801dea7 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -66,6 +66,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@babb554ede22fd5605947329c4d04d8e7a0b8155 # v3.27.7 + uses: github/codeql-action/upload-sarif@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9 with: sarif_file: results.sarif From 98b95d37defdd4c6bf41837b86a3094bcbc09f27 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Tue, 28 Jan 2025 10:46:44 -0800 Subject: [PATCH 80/96] [ci] Roll pinned stable toolchain (#2225) gherrit-pr-id: I57f775eb6a25ab060c7f4473bac30287e01e0b68 --- .github/workflows/ci.yml | 4 ++++ Cargo.toml | 2 +- .../invalid-impls/invalid-impls.stderr | 10 ++++----- .../transmute-mut-dst-unsized.stderr | 6 ++--- ...ransmute-mut-src-dst-not-references.stderr | 9 ++++++-- .../transmute-mut-src-dst-unsized.stderr | 6 ++--- .../transmute-mut-src-immutable.stderr | 9 ++++++-- .../transmute-mut-src-not-a-reference.stderr | 9 ++++++-- .../transmute-ref-dst-unsized.stderr | 6 ++--- ...ransmute-ref-src-dst-not-references.stderr | 11 +++++++--- .../transmute-ref-src-dst-unsized.stderr | 6 ++--- .../transmute-ref-src-not-a-reference.stderr | 11 +++++++--- .../tests/ui-stable/derive_transparent.stderr | 10 ++++----- zerocopy-derive/tests/ui-stable/enum.stderr | 14 ++++++------ .../tests/ui-stable/late_compile_pass.stderr | 2 +- .../tests/ui-stable/mid_compile_pass.stderr | 6 +++-- zerocopy-derive/tests/ui-stable/struct.stderr | 20 ++++++++--------- zerocopy-derive/tests/ui-stable/union.stderr | 22 ++++++++++++++++--- .../union_into_bytes_cfg.stderr | 16 ++++++++++++++ 19 files changed, 121 insertions(+), 58 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 85a9eb045c..4217cd9144 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -102,6 +102,10 @@ jobs: toolchain: "zerocopy-core-error" - crate: "zerocopy-derive" toolchain: "zerocopy-diagnostic-on-unimplemented" + # Exclude stable/wasm since wasm is no longer provided via rustup on + # stable. + - toolchain: "stable" + target: "wasm32-wasi" # Exclude most targets targets from the `zerocopy-core-error` # toolchain since the `zerocopy-core-error` feature is unrelated to # compilation target. This only leaves i686 and x86_64 targets. diff --git a/Cargo.toml b/Cargo.toml index 34cd3f0c25..b9f323555f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. -pinned-stable = "1.83.0" +pinned-stable = "1.84.0" pinned-nightly = "nightly-2024-11-06" [package.metadata.docs.rs] diff --git a/tests/ui-stable/invalid-impls/invalid-impls.stderr b/tests/ui-stable/invalid-impls/invalid-impls.stderr index e3d9429d9a..cd97538db4 100644 --- a/tests/ui-stable/invalid-impls/invalid-impls.stderr +++ b/tests/ui-stable/invalid-impls/invalid-impls.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: zerocopy::TryFromBytes` is not satisfied --> tests/ui-stable/invalid-impls/invalid-impls.rs:26:39 | 26 | impl_or_verify!(T => TryFromBytes for Foo); - | ^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `T`, which is required by `Foo: zerocopy::TryFromBytes` + | ^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `T` | = note: Consider adding `#[derive(TryFromBytes)]` to `T` note: required for `Foo` to implement `zerocopy::TryFromBytes` @@ -30,7 +30,7 @@ error[E0277]: the trait bound `T: zerocopy::FromZeros` is not satisfied --> tests/ui-stable/invalid-impls/invalid-impls.rs:27:36 | 27 | impl_or_verify!(T => FromZeros for Foo); - | ^^^^^^ the trait `zerocopy::FromZeros` is not implemented for `T`, which is required by `Foo: zerocopy::FromZeros` + | ^^^^^^ the trait `zerocopy::FromZeros` is not implemented for `T` | = note: Consider adding `#[derive(FromZeros)]` to `T` note: required for `Foo` to implement `zerocopy::FromZeros` @@ -58,7 +58,7 @@ error[E0277]: the trait bound `T: zerocopy::FromBytes` is not satisfied --> tests/ui-stable/invalid-impls/invalid-impls.rs:28:36 | 28 | impl_or_verify!(T => FromBytes for Foo); - | ^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `T`, which is required by `Foo: zerocopy::FromBytes` + | ^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `T` | = note: Consider adding `#[derive(FromBytes)]` to `T` note: required for `Foo` to implement `zerocopy::FromBytes` @@ -86,7 +86,7 @@ error[E0277]: the trait bound `T: zerocopy::IntoBytes` is not satisfied --> tests/ui-stable/invalid-impls/invalid-impls.rs:29:36 | 29 | impl_or_verify!(T => IntoBytes for Foo); - | ^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `T`, which is required by `Foo: zerocopy::IntoBytes` + | ^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `T` | = note: Consider adding `#[derive(IntoBytes)]` to `T` note: required for `Foo` to implement `zerocopy::IntoBytes` @@ -114,7 +114,7 @@ error[E0277]: the trait bound `T: zerocopy::Unaligned` is not satisfied --> tests/ui-stable/invalid-impls/invalid-impls.rs:30:36 | 30 | impl_or_verify!(T => Unaligned for Foo); - | ^^^^^^ the trait `zerocopy::Unaligned` is not implemented for `T`, which is required by `Foo: zerocopy::Unaligned` + | ^^^^^^ the trait `zerocopy::Unaligned` is not implemented for `T` | = note: Consider adding `#[derive(Unaligned)]` to `T` note: required for `Foo` to implement `zerocopy::Unaligned` diff --git a/tests/ui-stable/transmute-mut-dst-unsized.stderr b/tests/ui-stable/transmute-mut-dst-unsized.stderr index bda6c417e9..c1114a9b8f 100644 --- a/tests/ui-stable/transmute-mut-dst-unsized.stderr +++ b/tests/ui-stable/transmute-mut-dst-unsized.stderr @@ -48,10 +48,10 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation | = help: the trait `Sized` is not implemented for `[u8]` note: required by an implicit `Sized` bound in `std::intrinsics::transmute` - --> $RUST/core/src/intrinsics.rs + --> $RUST/core/src/intrinsics/mod.rs | - | pub fn transmute(src: Src) -> Dst; - | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` + | pub const unsafe fn transmute(_src: Src) -> Dst { + | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time diff --git a/tests/ui-stable/transmute-mut-src-dst-not-references.stderr b/tests/ui-stable/transmute-mut-src-dst-not-references.stderr index e84fd72ceb..8dadfb1529 100644 --- a/tests/ui-stable/transmute-mut-src-dst-not-references.stderr +++ b/tests/ui-stable/transmute-mut-src-dst-not-references.stderr @@ -20,7 +20,7 @@ warning: this function depends on never type fallback being `()` 17 | const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 = help: specify the types explicitly note: in edition 2024, the requirement `!: FromBytes` will fail @@ -30,6 +30,11 @@ note: in edition 2024, the requirement `!: FromBytes` will fail | ^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default = note: this warning originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `()` annotations to avoid fallback changes + --> src/macros.rs + | + | let e: &mut () = $e; + | ~~ warning: never type fallback affects this call to an `unsafe` function --> tests/ui-stable/transmute-mut-src-dst-not-references.rs:17:44 @@ -37,7 +42,7 @@ warning: never type fallback affects this call to an `unsafe` function 17 | const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 = help: specify the type explicitly = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default diff --git a/tests/ui-stable/transmute-mut-src-dst-unsized.stderr b/tests/ui-stable/transmute-mut-src-dst-unsized.stderr index 6fe2c8fbfc..2e18b12fac 100644 --- a/tests/ui-stable/transmute-mut-src-dst-unsized.stderr +++ b/tests/ui-stable/transmute-mut-src-dst-unsized.stderr @@ -145,10 +145,10 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation | = help: the trait `Sized` is not implemented for `[u8]` note: required by an implicit `Sized` bound in `std::intrinsics::transmute` - --> $RUST/core/src/intrinsics.rs + --> $RUST/core/src/intrinsics/mod.rs | - | pub fn transmute(src: Src) -> Dst; - | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` + | pub const unsafe fn transmute(_src: Src) -> Dst { + | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time diff --git a/tests/ui-stable/transmute-mut-src-immutable.stderr b/tests/ui-stable/transmute-mut-src-immutable.stderr index 1d1f58951a..daa08f5b78 100644 --- a/tests/ui-stable/transmute-mut-src-immutable.stderr +++ b/tests/ui-stable/transmute-mut-src-immutable.stderr @@ -16,7 +16,7 @@ warning: this function depends on never type fallback being `()` 15 | fn ref_src_immutable() { | ^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 = help: specify the types explicitly note: in edition 2024, the requirement `!: FromBytes` will fail @@ -26,6 +26,11 @@ note: in edition 2024, the requirement `!: FromBytes` will fail | ^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default = note: this warning originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `()` annotations to avoid fallback changes + --> src/macros.rs + | + | let e: &mut () = $e; + | ~~ warning: never type fallback affects this call to an `unsafe` function --> tests/ui-stable/transmute-mut-src-immutable.rs:17:22 @@ -33,7 +38,7 @@ warning: never type fallback affects this call to an `unsafe` function 17 | let _: &mut u8 = transmute_mut!(&0u8); | ^^^^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 = help: specify the type explicitly = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default diff --git a/tests/ui-stable/transmute-mut-src-not-a-reference.stderr b/tests/ui-stable/transmute-mut-src-not-a-reference.stderr index c927ada929..f9b3f9bbd8 100644 --- a/tests/ui-stable/transmute-mut-src-not-a-reference.stderr +++ b/tests/ui-stable/transmute-mut-src-not-a-reference.stderr @@ -20,7 +20,7 @@ warning: this function depends on never type fallback being `()` 17 | const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 = help: specify the types explicitly note: in edition 2024, the requirement `!: FromBytes` will fail @@ -30,6 +30,11 @@ note: in edition 2024, the requirement `!: FromBytes` will fail | ^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default = note: this warning originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `()` annotations to avoid fallback changes + --> src/macros.rs + | + | let e: &mut () = $e; + | ~~ warning: never type fallback affects this call to an `unsafe` function --> tests/ui-stable/transmute-mut-src-not-a-reference.rs:17:38 @@ -37,7 +42,7 @@ warning: never type fallback affects this call to an `unsafe` function 17 | const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 = help: specify the type explicitly = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default diff --git a/tests/ui-stable/transmute-ref-dst-unsized.stderr b/tests/ui-stable/transmute-ref-dst-unsized.stderr index c3c53c2611..62a31bae90 100644 --- a/tests/ui-stable/transmute-ref-dst-unsized.stderr +++ b/tests/ui-stable/transmute-ref-dst-unsized.stderr @@ -48,10 +48,10 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation | = help: the trait `Sized` is not implemented for `[u8]` note: required by an implicit `Sized` bound in `std::intrinsics::transmute` - --> $RUST/core/src/intrinsics.rs + --> $RUST/core/src/intrinsics/mod.rs | - | pub fn transmute(src: Src) -> Dst; - | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` + | pub const unsafe fn transmute(_src: Src) -> Dst { + | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time diff --git a/tests/ui-stable/transmute-ref-src-dst-not-references.stderr b/tests/ui-stable/transmute-ref-src-dst-not-references.stderr index 0a8ecb4648..2822bc4394 100644 --- a/tests/ui-stable/transmute-ref-src-dst-not-references.stderr +++ b/tests/ui-stable/transmute-ref-src-dst-not-references.stderr @@ -83,7 +83,7 @@ warning: this function depends on never type fallback being `()` 17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 = help: specify the types explicitly note: in edition 2024, the requirement `!: IntoBytes` will fail @@ -93,6 +93,11 @@ note: in edition 2024, the requirement `!: IntoBytes` will fail | ^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default = note: this warning originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `()` annotations to avoid fallback changes + --> src/macros.rs + | + | let e: &() = $e; + | ~~ warning: never type fallback affects this call to an `unsafe` function --> tests/ui-stable/transmute-ref-src-dst-not-references.rs:17:39 @@ -100,7 +105,7 @@ warning: never type fallback affects this call to an `unsafe` function 17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 = help: specify the type explicitly = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default @@ -112,7 +117,7 @@ warning: never type fallback affects this call to an `unsafe` function 17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 = help: specify the type explicitly = note: this warning originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-stable/transmute-ref-src-dst-unsized.stderr b/tests/ui-stable/transmute-ref-src-dst-unsized.stderr index f1c285494a..1e84a9ec65 100644 --- a/tests/ui-stable/transmute-ref-src-dst-unsized.stderr +++ b/tests/ui-stable/transmute-ref-src-dst-unsized.stderr @@ -145,10 +145,10 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation | = help: the trait `Sized` is not implemented for `[u8]` note: required by an implicit `Sized` bound in `std::intrinsics::transmute` - --> $RUST/core/src/intrinsics.rs + --> $RUST/core/src/intrinsics/mod.rs | - | pub fn transmute(src: Src) -> Dst; - | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` + | pub const unsafe fn transmute(_src: Src) -> Dst { + | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time diff --git a/tests/ui-stable/transmute-ref-src-not-a-reference.stderr b/tests/ui-stable/transmute-ref-src-not-a-reference.stderr index 5914621d1c..4b3f63560c 100644 --- a/tests/ui-stable/transmute-ref-src-not-a-reference.stderr +++ b/tests/ui-stable/transmute-ref-src-not-a-reference.stderr @@ -20,7 +20,7 @@ warning: this function depends on never type fallback being `()` 17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 = help: specify the types explicitly note: in edition 2024, the requirement `!: IntoBytes` will fail @@ -30,6 +30,11 @@ note: in edition 2024, the requirement `!: IntoBytes` will fail | ^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default = note: this warning originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `()` annotations to avoid fallback changes + --> src/macros.rs + | + | let e: &() = $e; + | ~~ warning: never type fallback affects this call to an `unsafe` function --> tests/ui-stable/transmute-ref-src-not-a-reference.rs:17:34 @@ -37,7 +42,7 @@ warning: never type fallback affects this call to an `unsafe` function 17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 = help: specify the type explicitly = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default @@ -49,7 +54,7 @@ warning: never type fallback affects this call to an `unsafe` function 17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 = help: specify the type explicitly = note: this warning originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/zerocopy-derive/tests/ui-stable/derive_transparent.stderr b/zerocopy-derive/tests/ui-stable/derive_transparent.stderr index b274b65433..989336f4f6 100644 --- a/zerocopy-derive/tests/ui-stable/derive_transparent.stderr +++ b/zerocopy-derive/tests/ui-stable/derive_transparent.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis --> tests/ui-stable/derive_transparent.rs:34:23 | 34 | util_assert_impl_all!(TransparentStruct: TryFromBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy`, which is required by `TransparentStruct: zerocopy::TryFromBytes` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: @@ -31,7 +31,7 @@ error[E0277]: the trait bound `NotZerocopy: FromZeros` is not satisfied --> tests/ui-stable/derive_transparent.rs:35:23 | 35 | util_assert_impl_all!(TransparentStruct: FromZeros); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromZeros` is not implemented for `NotZerocopy`, which is required by `TransparentStruct: FromZeros` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromZeros` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(FromZeros)]` to `NotZerocopy` = help: the following other types implement trait `FromZeros`: @@ -60,7 +60,7 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfie --> tests/ui-stable/derive_transparent.rs:36:23 | 36 | util_assert_impl_all!(TransparentStruct: FromBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy`, which is required by `TransparentStruct: zerocopy::FromBytes` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(FromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::FromBytes`: @@ -89,7 +89,7 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfie --> tests/ui-stable/derive_transparent.rs:37:23 | 37 | util_assert_impl_all!(TransparentStruct: IntoBytes); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy`, which is required by `TransparentStruct: zerocopy::IntoBytes` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::IntoBytes`: @@ -118,7 +118,7 @@ error[E0277]: the trait bound `NotZerocopy: Unaligned` is not satisfied --> tests/ui-stable/derive_transparent.rs:38:23 | 38 | util_assert_impl_all!(TransparentStruct: Unaligned); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `NotZerocopy`, which is required by `TransparentStruct: Unaligned` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(Unaligned)]` to `NotZerocopy` = help: the following other types implement trait `Unaligned`: diff --git a/zerocopy-derive/tests/ui-stable/enum.stderr b/zerocopy-derive/tests/ui-stable/enum.stderr index 95bb47e651..0ed978f913 100644 --- a/zerocopy-derive/tests/ui-stable/enum.stderr +++ b/zerocopy-derive/tests/ui-stable/enum.stderr @@ -423,11 +423,11 @@ error[E0277]: `IntoBytes1` has inter-field padding 538 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -437,11 +437,11 @@ error[E0277]: `IntoBytes2` has inter-field padding 549 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -451,11 +451,11 @@ error[E0277]: `IntoBytes3` has inter-field padding 555 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -476,7 +476,7 @@ error[E0277]: the trait bound `bool: FromBytes` is not satisfied --> tests/ui-stable/enum.rs:191:10 | 191 | #[derive(FromBytes)] - | ^^^^^^^^^ the trait `FromBytes` is not implemented for `bool`, which is required by `FooU8: FromBytes` + | ^^^^^^^^^ the trait `FromBytes` is not implemented for `bool` | = note: Consider adding `#[derive(FromBytes)]` to `bool` = help: the following other types implement trait `FromBytes`: diff --git a/zerocopy-derive/tests/ui-stable/late_compile_pass.stderr b/zerocopy-derive/tests/ui-stable/late_compile_pass.stderr index b6dbb04980..32f1ed8844 100644 --- a/zerocopy-derive/tests/ui-stable/late_compile_pass.stderr +++ b/zerocopy-derive/tests/ui-stable/late_compile_pass.stderr @@ -210,7 +210,7 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfie --> tests/ui-stable/late_compile_pass.rs:46:10 | 46 | #[derive(FromBytes)] - | ^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy`, which is required by `FromBytes1: zerocopy::FromBytes` + | ^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(FromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::FromBytes`: diff --git a/zerocopy-derive/tests/ui-stable/mid_compile_pass.stderr b/zerocopy-derive/tests/ui-stable/mid_compile_pass.stderr index 6b1875b036..20581d45f8 100644 --- a/zerocopy-derive/tests/ui-stable/mid_compile_pass.stderr +++ b/zerocopy-derive/tests/ui-stable/mid_compile_pass.stderr @@ -2,7 +2,9 @@ error[E0277]: the trait bound `T: KnownLayout` is not satisfied --> tests/ui-stable/mid_compile_pass.rs:59:26 | 59 | fn test_kl13(t: T) -> impl KnownLayout { - | ^^^^^^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `T`, which is required by `KL13: KnownLayout` + | ^^^^^^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `T` +60 | KL13(0u8, t) + | ------------ return type was inferred to be `KL13` here | = note: Consider adding `#[derive(KnownLayout)]` to `T` note: required for `KL13` to implement `KnownLayout` @@ -84,7 +86,7 @@ error[E0277]: the trait bound `T: KnownLayout` is not satisfied --> tests/ui-stable/mid_compile_pass.rs:50:15 | 50 | assert_kl(kl) - | --------- ^^ the trait `KnownLayout` is not implemented for `T`, which is required by `KL12: KnownLayout` + | --------- ^^ the trait `KnownLayout` is not implemented for `T` | | | required by a bound introduced by this call | diff --git a/zerocopy-derive/tests/ui-stable/struct.stderr b/zerocopy-derive/tests/ui-stable/struct.stderr index 789d291606..148a56520e 100644 --- a/zerocopy-derive/tests/ui-stable/struct.stderr +++ b/zerocopy-derive/tests/ui-stable/struct.stderr @@ -92,7 +92,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation 31 | #[derive(KnownLayout)] | ^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `KL00`, the trait `Sized` is not implemented for `[u8]`, which is required by `KL00: Sized` + = help: within `KL00`, the trait `Sized` is not implemented for `[u8]` note: required because it appears within the type `KL00` --> tests/ui-stable/struct.rs:32:8 | @@ -107,7 +107,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation 36 | #[derive(KnownLayout)] | ^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `KL02`, the trait `Sized` is not implemented for `[u8]`, which is required by `KL02: Sized` + = help: within `KL02`, the trait `Sized` is not implemented for `[u8]` note: required because it appears within the type `KL02` --> tests/ui-stable/struct.rs:37:8 | @@ -180,7 +180,7 @@ error[E0277]: the trait bound `UnsafeCell: zerocopy::Immutable` is not satis --> tests/ui-stable/struct.rs:60:10 | 60 | #[derive(Immutable)] - | ^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `UnsafeCell`, which is required by `[UnsafeCell; 0]: zerocopy::Immutable` + | ^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `UnsafeCell` | = note: Consider adding `#[derive(Immutable)]` to `UnsafeCell` = help: the following other types implement trait `zerocopy::Immutable`: @@ -271,11 +271,11 @@ error[E0277]: `IntoBytes2` has inter-field padding 107 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -285,11 +285,11 @@ error[E0277]: `IntoBytes3` has inter-field padding 114 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -299,7 +299,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation 125 | #[derive(IntoBytes)] | ^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `IntoBytes4`, the trait `Sized` is not implemented for `[u8]`, which is required by `IntoBytes4: macro_util::__size_of::Sized` + = help: within `IntoBytes4`, the trait `Sized` is not implemented for `[u8]` note: required because it appears within the type `IntoBytes4` --> tests/ui-stable/struct.rs:127:8 | @@ -319,7 +319,7 @@ error[E0277]: `[u8]` is unsized 129 | b: [u8], | ^^^^ `IntoBytes` needs all field types to be `Sized` in order to determine whether there is inter-field padding | - = help: the trait `Sized` is not implemented for `[u8]`, which is required by `[u8]: macro_util::__size_of::Sized` + = help: the trait `Sized` is not implemented for `[u8]` = note: consider using `#[repr(packed)]` to remove inter-field padding = note: `IntoBytes` does not require the fields of `#[repr(packed)]` types to be `Sized` = note: required for `[u8]` to implement `macro_util::__size_of::Sized` @@ -339,7 +339,7 @@ error[E0277]: the trait bound `AU16: Unaligned` is not satisfied --> tests/ui-stable/struct.rs:161:28 | 161 | is_into_bytes_11::>(); - | ^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16`, which is required by `IntoBytes11: zerocopy::IntoBytes` + | ^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` | = note: Consider adding `#[derive(Unaligned)]` to `AU16` = help: the following other types implement trait `Unaligned`: diff --git a/zerocopy-derive/tests/ui-stable/union.stderr b/zerocopy-derive/tests/ui-stable/union.stderr index 141929e115..1dcd617478 100644 --- a/zerocopy-derive/tests/ui-stable/union.stderr +++ b/zerocopy-derive/tests/ui-stable/union.stderr @@ -62,11 +62,27 @@ error: must have #[repr(C)], #[repr(transparent)], or #[repr(packed)] attribute | = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) +warning: unexpected `cfg` condition name: `zerocopy_derive_union_into_bytes` + --> tests/ui-stable/union.rs:39:10 + | +39 | #[derive(IntoBytes)] + | ^^^^^^^^^ + | + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `docsrs`, `doctest`, `feature`, `fmt_debug`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` + = help: consider using a Cargo feature instead + = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint: + [lints.rust] + unexpected_cfgs = { level = "warn", check-cfg = ['cfg(zerocopy_derive_union_into_bytes)'] } + = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(zerocopy_derive_union_into_bytes)");` to the top of the `build.rs` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + = note: this warning originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0277]: the trait bound `UnsafeCell<()>: zerocopy::Immutable` is not satisfied --> tests/ui-stable/union.rs:24:10 | 24 | #[derive(Immutable)] - | ^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `UnsafeCell<()>`, which is required by `ManuallyDrop>: zerocopy::Immutable` + | ^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `UnsafeCell<()>` | = note: Consider adding `#[derive(Immutable)]` to `UnsafeCell<()>` = help: the following other types implement trait `zerocopy::Immutable`: @@ -89,11 +105,11 @@ error[E0277]: `IntoBytes2` has inter-field padding 39 | #[derive(IntoBytes)] | ^^^^^^^^^ types with padding cannot implement `IntoBytes` | - = help: the trait `PaddingFree` is not implemented for `()` = note: consider using `zerocopy::Unalign` to lower the alignment of individual fields = note: consider adding explicit fields where padding would be = note: consider using `#[repr(packed)]` to remove inter-field padding - = help: the trait `PaddingFree` is implemented for `()` + = help: the trait `PaddingFree` is not implemented for `()` + but trait `PaddingFree` is implemented for it = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/zerocopy-derive/tests/ui-stable/union_into_bytes_cfg/union_into_bytes_cfg.stderr b/zerocopy-derive/tests/ui-stable/union_into_bytes_cfg/union_into_bytes_cfg.stderr index e4e35d6256..2e21f9d709 100644 --- a/zerocopy-derive/tests/ui-stable/union_into_bytes_cfg/union_into_bytes_cfg.stderr +++ b/zerocopy-derive/tests/ui-stable/union_into_bytes_cfg/union_into_bytes_cfg.stderr @@ -6,3 +6,19 @@ error: requires --cfg zerocopy_derive_union_into_bytes; | ^^^^^^^^^ | = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: unexpected `cfg` condition name: `zerocopy_derive_union_into_bytes` + --> tests/ui-stable/union_into_bytes_cfg/union_into_bytes_cfg.rs:20:10 + | +20 | #[derive(IntoBytes)] + | ^^^^^^^^^ + | + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `docsrs`, `doctest`, `feature`, `fmt_debug`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` + = help: consider using a Cargo feature instead + = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint: + [lints.rust] + unexpected_cfgs = { level = "warn", check-cfg = ['cfg(zerocopy_derive_union_into_bytes)'] } + = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(zerocopy_derive_union_into_bytes)");` to the top of the `build.rs` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + = note: this warning originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) From 77846a9139799c82a05de618e75d9bf15a703d57 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Fri, 31 Jan 2025 08:58:30 -0800 Subject: [PATCH 81/96] [ci] Roll pinned stable toolchain (#2281) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b9f323555f..8ffab557ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. -pinned-stable = "1.84.0" +pinned-stable = "1.84.1" pinned-nightly = "nightly-2024-11-06" [package.metadata.docs.rs] From 99dab138a0693efff728b9adafe8d9afa32f1b78 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Wed, 5 Feb 2025 12:28:46 -0800 Subject: [PATCH 82/96] [pointer][invariant] Remove AliasingMapping, Inaccessible (#2301) We previously used `AliasingMapping`s and `Inaccessible` to model `UnsafeCell` agreement. This abuses the notion of a mapping since one doesn't ever actually want to change the aliasing of a pointer (and certainly not to `Inaccessible`) - really this was meant to model pointer casts which should never be performed. In addition to being an awkward fit, the presence of `Inaccessible` meant that code could not assume that any `Aliasing` invariant permitted reading, and so we had to add extra machinery to work around this. Future commits will use a different, simpler model for denoting `UnsafeCell` agreement or disagreement. While we're here, make `Read` slightly more permissive, implemented for `A: Aliasing, T: Immutable` rather than just `A: Reference, T: Immutable`. Makes progress on #1122, #1866 gherrit-pr-id: I1ac2ae177a235083e33b09fc848423220d3da042 --- src/pointer/invariant.rs | 58 +++++----------------------------------- 1 file changed, 6 insertions(+), 52 deletions(-) diff --git a/src/pointer/invariant.rs b/src/pointer/invariant.rs index e52a458650..42c9ca63bc 100644 --- a/src/pointer/invariant.rs +++ b/src/pointer/invariant.rs @@ -55,6 +55,11 @@ impl Invariants for (A, AA, V) { } /// The aliasing invariant of a [`Ptr`][super::Ptr]. +/// +/// All aliasing invariants must permit reading from the bytes of a pointer's +/// referent which are not covered by [`UnsafeCell`]s. +/// +/// [`UnsafeCell`]: core::cell::UnsafeCell pub trait Aliasing: Sealed { /// Is `Self` [`Exclusive`]? #[doc(hidden)] @@ -65,9 +70,6 @@ pub trait Aliasing: Sealed { /// Aliasing>::Variance<'a, T>` to inherit this variance. #[doc(hidden)] type Variance<'a, T: 'a + ?Sized>; - - #[doc(hidden)] - type MappedTo: Aliasing; } /// The alignment invariant of a [`Ptr`][super::Ptr]. @@ -100,22 +102,6 @@ impl Validity for Unknown { type MappedTo = M::FromUnknown; } -/// The `Ptr<'a, T>` does not permit any reads or writes from or to its referent. -pub enum Inaccessible {} - -impl Aliasing for Inaccessible { - const IS_EXCLUSIVE: bool = false; - - // SAFETY: Inaccessible `Ptr`s permit neither reads nor writes, and so it - // doesn't matter how long the referent actually lives. Thus, covariance is - // fine (and is chosen because it is maximally permissive). Shared - // references are covariant [1]. - // - // [1] https://doc.rust-lang.org/1.81.0/reference/subtyping.html#variance - type Variance<'a, T: 'a + ?Sized> = &'a T; - type MappedTo = M::FromInaccessible; -} - /// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a T`. /// /// The referent of a shared-aliased `Ptr` may be concurrently referenced by any @@ -128,7 +114,6 @@ pub enum Shared {} impl Aliasing for Shared { const IS_EXCLUSIVE: bool = false; type Variance<'a, T: 'a + ?Sized> = &'a T; - type MappedTo = M::FromShared; } impl Reference for Shared {} @@ -141,7 +126,6 @@ pub enum Exclusive {} impl Aliasing for Exclusive { const IS_EXCLUSIVE: bool = true; type Variance<'a, T: 'a + ?Sized> = &'a mut T; - type MappedTo = M::FromExclusive; } impl Reference for Exclusive {} @@ -230,7 +214,7 @@ define_because!( pub BecauseImmutable ); // SAFETY: `T: Immutable`. -unsafe impl Read for T {} +unsafe impl Read for T {} use sealed::Sealed; mod sealed { @@ -240,7 +224,6 @@ mod sealed { impl Sealed for Unknown {} - impl Sealed for Inaccessible {} impl Sealed for Shared {} impl Sealed for Exclusive {} @@ -257,23 +240,6 @@ pub use mapping::*; mod mapping { use super::*; - /// A mapping from one [`Aliasing`] type to another. - /// - /// An `AliasingMapping` is a type-level map which maps one `Aliasing` type - /// to another. It is always "total" in the sense of having a mapping for - /// any `A: Aliasing`. - /// - /// Given `A: Aliasing` and `M: AliasingMapping`, `M` can be applied to `A` - /// as [`MappedAliasing`](MappedAliasing). - /// - /// Mappings are used by [`Ptr`](crate::Ptr) conversion methods to preserve - /// or modify invariants as required by each method's semantics. - pub trait AliasingMapping { - type FromInaccessible: Aliasing; - type FromShared: Aliasing; - type FromExclusive: Aliasing; - } - /// A mapping from one [`Alignment`] type to another. /// /// An `AlignmentMapping` is a type-level map which maps one `Alignment` @@ -308,10 +274,6 @@ mod mapping { type FromValid: Validity; } - /// The application of the [`AliasingMapping`] `M` to the [`Aliasing`] `A`. - #[allow(type_alias_bounds)] - pub type MappedAliasing = A::MappedTo; - /// The application of the [`AlignmentMapping`] `M` to the [`Alignment`] `A`. #[allow(type_alias_bounds)] pub type MappedAlignment = A::MappedTo; @@ -320,14 +282,6 @@ mod mapping { #[allow(type_alias_bounds)] pub type MappedValidity = V::MappedTo; - impl AliasingMapping - for ((Inaccessible, FromInaccessible), (Shared, FromShared), (Exclusive, FromExclusive)) - { - type FromInaccessible = FromInaccessible; - type FromShared = FromShared; - type FromExclusive = FromExclusive; - } - impl AlignmentMapping for ((Unknown, FromUnknown), (Shared, FromAligned)) { From 146fd48942166fd11a5ba2fbb06fc20ad0ce5b98 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Thu, 6 Feb 2025 11:06:44 -0800 Subject: [PATCH 83/96] [ci] Permit skipping cargo-semver-checks step (#2084) (#2309) This is triggered when the most recent commit in a PR has a commit message which contains the string `SKIP_CARGO_SEMVER_CHECKS=1` on its own line. SKIP_CARGO_SEMVER_CHECKS=1 Closes #2083 gherrit-pr-id: Iffcecec3b7abfd48a67011d5979aa075b68da0ba --- .github/workflows/ci.yml | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4217cd9144..d0d6af5f6e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -419,6 +419,25 @@ jobs: export RUSTDOCFLAGS="${{ matrix.toolchain == 'nightly' && '-Z unstable-options --document-hidden-items $METADATA_DOCS_RS_RUSTDOC_ARGS'|| '' }} $RUSTDOCFLAGS" ./cargo.sh +${{ matrix.toolchain }} doc --document-private-items --package ${{ matrix.crate }} ${{ matrix.features }} + # If the commit message contains the line `SKIP_CARGO_SEMVER_CHECKS=1`, then + # skip the cargo-semver-checks step. + - name: Check whether to skip cargo-semver-checks + run: | + set -eo pipefail + + if [ "${{ github.event_name }}" == "pull_request" ]; then + # Invoked from a PR - get the PR body directly + MESSAGE="${{ github.event.pull_request.body }}" + else + # Invoked from the merge queue - get the commit message + MESSAGE="$(git log -1 --pretty=%B ${{ github.sha }})" + fi + + if echo "$MESSAGE" | grep '^\s*SKIP_CARGO_SEMVER_CHECKS=1\s*$' > /dev/null; then + echo "Found 'SKIP_CARGO_SEMVER_CHECKS=1' in commit message; skipping cargo-semver-checks..." | tee -a $GITHUB_STEP_SUMMARY + echo "ZC_SKIP_CARGO_SEMVER_CHECKS=1" >> $GITHUB_ENV + fi + # Check semver compatibility with the most recently-published version on # crates.io. We do this in the matrix rather than in its own job so that it # gets run on different targets. Some of our API is target-specific (e.g., @@ -448,7 +467,8 @@ jobs: matrix.crate == 'zerocopy' && matrix.features == '--features __internal_use_only_features_that_work_on_stable' && matrix.toolchain == 'stable' && - matrix.target != 'wasm32-wasi' + matrix.target != 'wasm32-wasi' && + env.ZC_SKIP_CARGO_SEMVER_CHECKS != '1' # TODO(#453): Doing this as a matrix step is a hack that allows us to depend # on the fact that toolchains have already been installed. We currently only From 3acb652f1444fb5610b34bab8d4a7c70c53193e4 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Thu, 6 Feb 2025 11:51:51 -0800 Subject: [PATCH 84/96] Add initial support for unsized `MaybeUninit` wrapper type (#2055) (#2310) This is achieved by adding a `MaybeUninit` associated type to `KnownLayout`, whose layout is identical to `Self` except that it admits uninitialized bytes in all positions. For sized types, this is bound to `mem::MaybeUninit`. For potentially unsized structs, we synthesize a doppelganger with the same `repr`, whose leading fields are wrapped in `mem::MaybeUninit` and whose trailing field is the `MaybeUninit` associated type of struct's original trailing field type. This type-level recursion bottoms out at `[T]`, whose `MaybeUninit` associated type is bound to `[mem::MaybeUninit]`. Makes progress towards #1797 SKIP_CARGO_SEMVER_CHECKS=1 gherrit-pr-id: Idfc357094e28b54a15d947141241ca2da83dcc91 Co-authored-by: Jack Wrenn --- .github/workflows/ci.yml | 4 +- src/impls.rs | 30 +- src/lib.rs | 130 ++++----- src/util/macros.rs | 12 + src/util/mod.rs | 128 +++++++++ src/wrappers.rs | 190 +++++++++++-- ...nostic-not-implemented-known-layout.stderr | 4 +- ...nostic-not-implemented-known-layout.stderr | 4 +- ...nostic-not-implemented-known-layout.stderr | 4 +- zerocopy-derive/src/lib.rs | 260 ++++++++++++++---- zerocopy-derive/src/output_tests.rs | 100 +++++++ .../tests/ui-msrv/mid_compile_pass.stderr | 12 +- zerocopy-derive/tests/ui-msrv/struct.stderr | 8 +- .../tests/ui-nightly/mid_compile_pass.stderr | 13 +- .../tests/ui-nightly/struct.stderr | 8 +- .../tests/ui-stable/mid_compile_pass.stderr | 13 +- zerocopy-derive/tests/ui-stable/struct.stderr | 8 +- 17 files changed, 749 insertions(+), 179 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d0d6af5f6e..cc1b722e95 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -181,6 +181,8 @@ jobs: steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 2 - name: Populate cache uses: ./.github/actions/cache @@ -427,7 +429,7 @@ jobs: if [ "${{ github.event_name }}" == "pull_request" ]; then # Invoked from a PR - get the PR body directly - MESSAGE="${{ github.event.pull_request.body }}" + MESSAGE="$(git log -1 --pretty=%B ${{ github.event.pull_request.head.sha }})" else # Invoked from the merge queue - get the commit message MESSAGE="$(git log -1 --pretty=%B ${{ github.sha }})" diff --git a/src/impls.rs b/src/impls.rs index 321bad7fe3..c4184694ab 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -7,6 +7,8 @@ // This file may not be copied, modified, or distributed except according to // those terms. +use core::mem::MaybeUninit as CoreMaybeUninit; + use super::*; safety_comment! { @@ -619,14 +621,14 @@ safety_comment! { /// SAFETY: /// `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`: /// `MaybeUninit` has no restrictions on its contents. - unsafe_impl!(T => TryFromBytes for MaybeUninit); - unsafe_impl!(T => FromZeros for MaybeUninit); - unsafe_impl!(T => FromBytes for MaybeUninit); + unsafe_impl!(T => TryFromBytes for CoreMaybeUninit); + unsafe_impl!(T => FromZeros for CoreMaybeUninit); + unsafe_impl!(T => FromBytes for CoreMaybeUninit); } -impl_for_transparent_wrapper!(T: Immutable => Immutable for MaybeUninit); -impl_for_transparent_wrapper!(T: Unaligned => Unaligned for MaybeUninit); -assert_unaligned!(MaybeUninit<()>, MaybeUninit); +impl_for_transparent_wrapper!(T: Immutable => Immutable for CoreMaybeUninit); +impl_for_transparent_wrapper!(T: Unaligned => Unaligned for CoreMaybeUninit); +assert_unaligned!(CoreMaybeUninit<()>, CoreMaybeUninit); impl_for_transparent_wrapper!(T: ?Sized + Immutable => Immutable for ManuallyDrop); impl_for_transparent_wrapper!(T: ?Sized + TryFromBytes => TryFromBytes for ManuallyDrop); @@ -1235,8 +1237,8 @@ mod tests { ManuallyDrop>, ManuallyDrop<[UnsafeCell]>, ManuallyDrop<[UnsafeCell]>, - MaybeUninit, - MaybeUninit>, + CoreMaybeUninit, + CoreMaybeUninit>, Wrapping> ); @@ -1278,9 +1280,9 @@ mod tests { Option, Option, Option, - MaybeUninit, - MaybeUninit, - MaybeUninit>, + CoreMaybeUninit, + CoreMaybeUninit, + CoreMaybeUninit>, ManuallyDrop>, ManuallyDrop<[UnsafeCell]>, ManuallyDrop<[UnsafeCell]>, @@ -1742,9 +1744,9 @@ mod tests { assert_impls!(ManuallyDrop<[UnsafeCell]>: KnownLayout, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned, !Immutable); assert_impls!(ManuallyDrop<[UnsafeCell]>: KnownLayout, TryFromBytes, FromZeros, IntoBytes, Unaligned, !Immutable, !FromBytes); - assert_impls!(MaybeUninit: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, Unaligned, !IntoBytes); - assert_impls!(MaybeUninit: KnownLayout, TryFromBytes, FromZeros, FromBytes, !Immutable, !IntoBytes, !Unaligned); - assert_impls!(MaybeUninit>: KnownLayout, TryFromBytes, FromZeros, FromBytes, Unaligned, !Immutable, !IntoBytes); + assert_impls!(CoreMaybeUninit: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, Unaligned, !IntoBytes); + assert_impls!(CoreMaybeUninit: KnownLayout, TryFromBytes, FromZeros, FromBytes, !Immutable, !IntoBytes, !Unaligned); + assert_impls!(CoreMaybeUninit>: KnownLayout, TryFromBytes, FromZeros, FromBytes, Unaligned, !Immutable, !IntoBytes); assert_impls!(Wrapping: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); // This test is important because it allows us to test our hand-rolled diff --git a/src/lib.rs b/src/lib.rs index 1ff923a509..2c2c653422 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -354,7 +354,7 @@ use core::{ fmt::{self, Debug, Display, Formatter}, hash::Hasher, marker::PhantomData, - mem::{self, ManuallyDrop, MaybeUninit}, + mem::{self, ManuallyDrop, MaybeUninit as CoreMaybeUninit}, num::{ NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping, @@ -711,6 +711,15 @@ pub unsafe trait KnownLayout { /// This is `()` for sized types and `usize` for slice DSTs. type PointerMetadata: PointerMetadata; + /// A maybe-uninitialized analog of `Self` + /// + /// # Safety + /// + /// `Self::LAYOUT` and `Self::MaybeUninit::LAYOUT` are identical. + /// `Self::MaybeUninit` admits uninitialized bytes in all positions. + #[doc(hidden)] + type MaybeUninit: ?Sized + KnownLayout; + /// The layout of `Self`. /// /// # Safety @@ -843,6 +852,35 @@ unsafe impl KnownLayout for [T] { type PointerMetadata = usize; + // SAFETY: `CoreMaybeUninit::LAYOUT` and `T::LAYOUT` are identical + // because `CoreMaybeUninit` has the same size and alignment as `T` [1]. + // Consequently, `[CoreMaybeUninit]::LAYOUT` and `[T]::LAYOUT` are + // identical, because they both lack a fixed-sized prefix and because they + // inherit the alignments of their inner element type (which are identical) + // [2][3]. + // + // `[CoreMaybeUninit]` admits uninitialized bytes at all positions + // because `CoreMaybeUninit` admits uninitialized bytes at all positions + // and because the inner elements of `[CoreMaybeUninit]` are laid out + // back-to-back [2][3]. + // + // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1: + // + // `MaybeUninit` is guaranteed to have the same size, alignment, and ABI as + // `T` + // + // [2] Per https://doc.rust-lang.org/1.82.0/reference/type-layout.html#slice-layout: + // + // Slices have the same layout as the section of the array they slice. + // + // [3] Per https://doc.rust-lang.org/1.82.0/reference/type-layout.html#array-layout: + // + // An array of `[T; N]` has a size of `size_of::() * N` and the same + // alignment of `T`. Arrays are laid out so that the zero-based `nth` + // element of the array is offset from the start of the array by `n * + // size_of::()` bytes. + type MaybeUninit = [CoreMaybeUninit]; + const LAYOUT: DstLayout = DstLayout::for_slice::(); // SAFETY: `.cast` preserves address and provenance. The returned pointer @@ -895,9 +933,11 @@ impl_known_layout!( T => Option, T: ?Sized => PhantomData, T => Wrapping, - T => MaybeUninit, + T => CoreMaybeUninit, T: ?Sized => *const T, - T: ?Sized => *mut T + T: ?Sized => *mut T, + T: ?Sized => &'_ T, + T: ?Sized => &'_ mut T, ); impl_known_layout!(const N: usize, T => [T; N]); @@ -928,6 +968,21 @@ safety_comment! { unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] UnsafeCell); } +safety_comment! { + /// SAFETY: + /// - By consequence of the invariant on `T::MaybeUninit` that `T::LAYOUT` + /// and `T::MaybeUninit::LAYOUT` are equal, `T` and `T::MaybeUninit` + /// have the same: + /// - Fixed prefix size + /// - Alignment + /// - (For DSTs) trailing slice element size + /// - By consequence of the above, referents `T::MaybeUninit` and `T` have + /// the require the same kind of pointer metadata, and thus it is valid to + /// perform an `as` cast from `*mut T` and `*mut T::MaybeUninit`, and this + /// operation preserves referent size (ie, `size_of_val_raw`). + unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T::MaybeUninit)] MaybeUninit); +} + /// Analyzes whether a type is [`FromZeros`]. /// /// This derive analyzes, at compile time, whether the annotated type satisfies @@ -2547,7 +2602,7 @@ pub unsafe trait TryFromBytes { where Self: Sized, { - let candidate = match MaybeUninit::::read_from_bytes(source) { + let candidate = match CoreMaybeUninit::::read_from_bytes(source) { Ok(candidate) => candidate, Err(e) => { return Err(TryReadError::Size(e.with_dst())); @@ -2608,7 +2663,7 @@ pub unsafe trait TryFromBytes { where Self: Sized, { - let (candidate, suffix) = match MaybeUninit::::read_from_prefix(source) { + let (candidate, suffix) = match CoreMaybeUninit::::read_from_prefix(source) { Ok(candidate) => candidate, Err(e) => { return Err(TryReadError::Size(e.with_dst())); @@ -2670,7 +2725,7 @@ pub unsafe trait TryFromBytes { where Self: Sized, { - let (prefix, candidate) = match MaybeUninit::::read_from_suffix(source) { + let (prefix, candidate) = match CoreMaybeUninit::::read_from_suffix(source) { Ok(candidate) => candidate, Err(e) => { return Err(TryReadError::Size(e.with_dst())); @@ -2743,7 +2798,7 @@ fn swap((t, u): (T, U)) -> (U, T) { #[inline(always)] unsafe fn try_read_from( source: S, - mut candidate: MaybeUninit, + mut candidate: CoreMaybeUninit, ) -> Result> { // We use `from_mut` despite not mutating via `c_ptr` so that we don't need // to add a `T: Immutable` bound. @@ -3032,60 +3087,11 @@ pub unsafe trait FromZeros: TryFromBytes { where Self: KnownLayout, { - let size = match count.size_for_metadata(Self::LAYOUT) { - Some(size) => size, - None => return Err(AllocError), - }; - - let align = Self::LAYOUT.align.get(); - - // TODO(https://github.com/rust-lang/rust/issues/55724): Use - // `Layout::repeat` once it's stabilized. - let layout = Layout::from_size_align(size, align).or(Err(AllocError))?; - - let ptr = if layout.size() != 0 { - // TODO(#429): Add a "SAFETY" comment and remove this `allow`. - #[allow(clippy::undocumented_unsafe_blocks)] - let ptr = unsafe { alloc::alloc::alloc_zeroed(layout) }; - match NonNull::new(ptr) { - Some(ptr) => ptr, - None => return Err(AllocError), - } - } else { - // We use `transmute` instead of an `as` cast since Miri (with - // strict provenance enabled) notices and complains that an `as` - // cast creates a pointer with no provenance. Miri isn't smart - // enough to realize that we're only executing this branch when - // we're constructing a zero-sized `Box`, which doesn't require - // provenance. - // - // SAFETY: any initialized bit sequence is a bit-valid `*mut u8`. - // All bits of a `usize` are initialized. - #[allow(clippy::useless_transmute)] - let dangling = unsafe { mem::transmute::(align) }; - // SAFETY: `dangling` is constructed from `Self::LAYOUT.align`, - // which is a `NonZeroUsize`, which is guaranteed to be non-zero. - // - // `Box<[T]>` does not allocate when `T` is zero-sized or when `len` - // is zero, but it does require a non-null dangling pointer for its - // allocation. - // - // TODO(https://github.com/rust-lang/rust/issues/95228): Use - // `std::ptr::without_provenance` once it's stable. That may - // optimize better. As written, Rust may assume that this consumes - // "exposed" provenance, and thus Rust may have to assume that this - // may consume provenance from any pointer whose provenance has been - // exposed. - unsafe { NonNull::new_unchecked(dangling) } - }; - - let ptr = Self::raw_from_ptr_len(ptr, count); - - // TODO(#429): Add a "SAFETY" comment and remove this `allow`. Make sure - // to include a justification that `ptr.as_ptr()` is validly-aligned in - // the ZST case (in which we manually construct a dangling pointer). - #[allow(clippy::undocumented_unsafe_blocks)] - Ok(unsafe { Box::from_raw(ptr.as_ptr()) }) + // SAFETY: `alloc::alloc::alloc_zeroed` is a valid argument of + // `new_box`. The referent of the pointer returned by `alloc_zeroed` + // (and, consequently, the `Box` derived from it) is a valid instance of + // `Self`, because `Self` is `FromZeros`. + unsafe { crate::util::new_box(count, alloc::alloc::alloc_zeroed) } } /// Creates a `Vec` from zeroed bytes. @@ -4532,7 +4538,7 @@ pub unsafe trait FromBytes: FromZeros { Self: Sized, R: io::Read, { - let mut buf = MaybeUninit::::zeroed(); + let mut buf = CoreMaybeUninit::::zeroed(); let ptr = Ptr::from_mut(&mut buf); // SAFETY: `buf` consists entirely of initialized, zeroed bytes. let ptr = unsafe { ptr.assume_validity::() }; diff --git a/src/util/macros.rs b/src/util/macros.rs index 5d9eb54a6a..2b19779ced 100644 --- a/src/util/macros.rs +++ b/src/util/macros.rs @@ -546,6 +546,17 @@ macro_rules! impl_known_layout { type PointerMetadata = (); + // SAFETY: `CoreMaybeUninit::LAYOUT` and `T::LAYOUT` are + // identical because `CoreMaybeUninit` has the same size and + // alignment as `T` [1], and `CoreMaybeUninit` admits + // uninitialized bytes in all positions. + // + // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1: + // + // `MaybeUninit` is guaranteed to have the same size, + // alignment, and ABI as `T` + type MaybeUninit = core::mem::MaybeUninit; + const LAYOUT: crate::DstLayout = crate::DstLayout::for_type::<$ty>(); // SAFETY: `.cast` preserves address and provenance. @@ -588,6 +599,7 @@ macro_rules! unsafe_impl_known_layout { fn only_derive_is_allowed_to_implement_this_trait() {} type PointerMetadata = <$repr as KnownLayout>::PointerMetadata; + type MaybeUninit = <$repr as KnownLayout>::MaybeUninit; const LAYOUT: DstLayout = <$repr as KnownLayout>::LAYOUT; diff --git a/src/util/mod.rs b/src/util/mod.rs index dd2e5bdd61..ad59881f96 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -679,6 +679,134 @@ pub(crate) unsafe fn copy_unchecked(src: &[u8], dst: &mut [u8]) { }; } +/// Unsafely transmutes the given `src` into a type `Dst`. +/// +/// # Safety +/// +/// The value `src` must be a valid instance of `Dst`. +#[inline(always)] +pub(crate) const unsafe fn transmute_unchecked(src: Src) -> Dst { + static_assert!(Src, Dst => core::mem::size_of::() == core::mem::size_of::()); + + #[repr(C)] + union Transmute { + src: ManuallyDrop, + dst: ManuallyDrop, + } + + // SAFETY: Since `Transmute` is `#[repr(C)]`, its `src` and `dst` + // fields both start at the same offset and the types of those fields are + // transparent wrappers around `Src` and `Dst` [1]. Consequently, + // initializng `Transmute` with with `src` and then reading out `dst` is + // equivalent to transmuting from `Src` to `Dst` [2]. Transmuting from `src` + // to `Dst` is valid because — by contract on the caller — `src` is a valid + // instance of `Dst`. + // + // [1] Per https://doc.rust-lang.org/1.82.0/std/mem/struct.ManuallyDrop.html: + // + // `ManuallyDrop` is guaranteed to have the same layout and bit + // validity as `T`, and is subject to the same layout optimizations as + // `T`. + // + // [2] Per https://doc.rust-lang.org/1.82.0/reference/items/unions.html#reading-and-writing-union-fields: + // + // Effectively, writing to and then reading from a union with the C + // representation is analogous to a transmute from the type used for + // writing to the type used for reading. + unsafe { ManuallyDrop::into_inner(Transmute { src: ManuallyDrop::new(src) }.dst) } +} + +/// Uses `allocate` to create a `Box`. +/// +/// # Errors +/// +/// Returns an error on allocation failure. Allocation failure is guaranteed +/// never to cause a panic or an abort. +/// +/// # Safety +/// +/// `allocate` must be either `alloc::alloc::alloc` or +/// `alloc::alloc::alloc_zeroed`. The referent of the box returned by `new_box` +/// has the same bit-validity as the referent of the pointer returned by the +/// given `allocate` and sufficient size to store `T` with `meta`. +#[must_use = "has no side effects (other than allocation)"] +#[cfg(feature = "alloc")] +#[inline] +pub(crate) unsafe fn new_box( + meta: T::PointerMetadata, + allocate: unsafe fn(core::alloc::Layout) -> *mut u8, +) -> Result, crate::error::AllocError> +where + T: ?Sized + crate::KnownLayout, +{ + use crate::error::AllocError; + use crate::PointerMetadata; + use core::alloc::Layout; + + let size = match meta.size_for_metadata(T::LAYOUT) { + Some(size) => size, + None => return Err(AllocError), + }; + + let align = T::LAYOUT.align.get(); + + // TODO(https://github.com/rust-lang/rust/issues/55724): Use + // `Layout::repeat` once it's stabilized. + let layout = Layout::from_size_align(size, align).or(Err(AllocError))?; + + let ptr = if layout.size() != 0 { + // SAFETY: By contract on the caller, `allocate` is either + // `alloc::alloc::alloc` or `alloc::alloc::alloc_zeroed`. The above + // check ensures their shared safety precondition: that the supplied + // layout is not zero-sized type [1]. + // + // [1] Per https://doc.rust-lang.org/stable/std/alloc/trait.GlobalAlloc.html#tymethod.alloc: + // + // This function is unsafe because undefined behavior can result if + // the caller does not ensure that layout has non-zero size. + let ptr = unsafe { allocate(layout) }; + match NonNull::new(ptr) { + Some(ptr) => ptr, + None => return Err(AllocError), + } + } else { + let align = T::LAYOUT.align.get(); + // We use `transmute` instead of an `as` cast since Miri (with strict + // provenance enabled) notices and complains that an `as` cast creates a + // pointer with no provenance. Miri isn't smart enough to realize that + // we're only executing this branch when we're constructing a zero-sized + // `Box`, which doesn't require provenance. + // + // SAFETY: any initialized bit sequence is a bit-valid `*mut u8`. All + // bits of a `usize` are initialized. + #[allow(clippy::useless_transmute)] + let dangling = unsafe { mem::transmute::(align) }; + // SAFETY: `dangling` is constructed from `T::LAYOUT.align`, which is a + // `NonZeroUsize`, which is guaranteed to be non-zero. + // + // `Box<[T]>` does not allocate when `T` is zero-sized or when `len` is + // zero, but it does require a non-null dangling pointer for its + // allocation. + // + // TODO(https://github.com/rust-lang/rust/issues/95228): Use + // `std::ptr::without_provenance` once it's stable. That may optimize + // better. As written, Rust may assume that this consumes "exposed" + // provenance, and thus Rust may have to assume that this may consume + // provenance from any pointer whose provenance has been exposed. + unsafe { NonNull::new_unchecked(dangling) } + }; + + let ptr = T::raw_from_ptr_len(ptr, meta); + + // TODO(#429): Add a "SAFETY" comment and remove this `allow`. Make sure to + // include a justification that `ptr.as_ptr()` is validly-aligned in the ZST + // case (in which we manually construct a dangling pointer) and to justify + // why `Box` is safe to drop (it's because `allocate` uses the system + // allocator). + #[allow(clippy::undocumented_unsafe_blocks)] + Ok(unsafe { alloc::boxed::Box::from_raw(ptr.as_ptr()) }) +} + /// Since we support multiple versions of Rust, there are often features which /// have been stabilized in the most recent stable release which do not yet /// exist (stably) on our MSRV. This module provides polyfills for those diff --git a/src/wrappers.rs b/src/wrappers.rs index ac2442486e..fb6b3047a6 100644 --- a/src/wrappers.rs +++ b/src/wrappers.rs @@ -6,7 +6,7 @@ // This file may not be copied, modified, or distributed except according to // those terms. -use core::hash::Hash; +use core::{fmt, hash::Hash}; use super::*; @@ -166,20 +166,8 @@ impl Unalign { /// Consumes `self`, returning the inner `T`. #[inline(always)] pub const fn into_inner(self) -> T { - // Use this instead of `mem::transmute` since the latter can't tell - // that `Unalign` and `T` have the same size. - #[repr(C)] - union Transmute { - u: ManuallyDrop>, - t: ManuallyDrop, - } - - // SAFETY: Since `Unalign` is `#[repr(C, packed)]`, it has the same - // layout as `T`. `ManuallyDrop` is guaranteed to have the same - // layout as `U`, and so `ManuallyDrop>` has the same layout - // as `ManuallyDrop`. Since `Transmute` is `#[repr(C)]`, its `t` - // and `u` fields both start at the same offset (namely, 0) within the - // union. + // SAFETY: Since `Unalign` is `#[repr(C, packed)]`, it has the same size + // and bit validity as `T`. // // We do this instead of just destructuring in order to prevent // `Unalign`'s `Drop::drop` from being run, since dropping is not @@ -187,7 +175,7 @@ impl Unalign { // // TODO(https://github.com/rust-lang/rust/issues/73255): Destructure // instead of using unsafe. - unsafe { ManuallyDrop::into_inner(Transmute { u: ManuallyDrop::new(self) }.t) } + unsafe { crate::util::transmute_unchecked(self) } } /// Attempts to return a reference to the wrapped `T`, failing if `self` is @@ -459,6 +447,139 @@ impl Display for Unalign { } } +/// A wrapper type to construct uninitialized instances of `T`. +/// +/// `MaybeUninit` is identical to the [standard library +/// `MaybeUninit`][core-maybe-uninit] type except that it supports unsized +/// types. +/// +/// # Layout +/// +/// The same layout guarantees and caveats apply to `MaybeUninit` as apply to +/// the [standard library `MaybeUninit`][core-maybe-uninit] with one exception: +/// for `T: !Sized`, there is no single value for `T`'s size. Instead, for such +/// types, the following are guaranteed: +/// - Every [valid size][valid-size] for `T` is a valid size for +/// `MaybeUninit` and vice versa +/// - Given `t: *const T` and `m: *const MaybeUninit` with identical fat +/// pointer metadata, `t` and `m` address the same number of bytes (and +/// likewise for `*mut`) +/// +/// [core-maybe-uninit]: core::mem::MaybeUninit +/// [valid-size]: crate::KnownLayout#what-is-a-valid-size +#[repr(transparent)] +#[doc(hidden)] +pub struct MaybeUninit( + // SAFETY: `MaybeUninit` has the same size as `T`, because (by invariant + // on `T::MaybeUninit`) `T::MaybeUninit` has `T::LAYOUT` identical to `T`, + // and because (invariant on `T::LAYOUT`) we can trust that `LAYOUT` + // accurately reflects the layout of `T`. By invariant on `T::MaybeUninit`, + // it admits uninitialized bytes in all positions. Because `MabyeUninit` is + // marked `repr(transparent)`, these properties additionally hold true for + // `Self`. + T::MaybeUninit, +); + +#[doc(hidden)] +impl MaybeUninit { + /// Constructs a `MaybeUninit` initialized with the given value. + #[inline(always)] + pub const fn new(val: T) -> Self + where + T: Sized, + Self: Sized, + { + // SAFETY: It is valid to transmute `val` to `MaybeUninit` because it + // is both valid to transmute `val` to `T::MaybeUninit`, and it is valid + // to transmute from `T::MaybeUninit` to `MaybeUninit`. + // + // First, it is valid to transmute `val` to `T::MaybeUninit` because, by + // invariant on `T::MaybeUninit`: + // - For `T: Sized`, `T` and `T::MaybeUninit` have the same size. + // - All byte sequences of the correct size are valid values of + // `T::MaybeUninit`. + // + // Second, it is additionally valid to transmute from `T::MaybeUninit` + // to `MaybeUninit`, because `MaybeUninit` is a + // `repr(transparent)` wrapper around `T::MaybeUninit`. + // + // These two transmutes are collapsed into one so we don't need to add a + // `T::MaybeUninit: Sized` bound to this function's `where` clause. + unsafe { crate::util::transmute_unchecked(val) } + } + + /// Constructs an uninitialized `MaybeUninit`. + #[must_use] + #[inline(always)] + pub const fn uninit() -> Self + where + T: Sized, + Self: Sized, + { + let uninit = CoreMaybeUninit::::uninit(); + // SAFETY: It is valid to transmute from `CoreMaybeUninit` to + // `MaybeUninit` since they both admit uninitialized bytes in all + // positions, and they have the same size (i.e., that of `T`). + // + // `MaybeUninit` has the same size as `T`, because (by invariant on + // `T::MaybeUninit`) `T::MaybeUninit` has `T::LAYOUT` identical to `T`, + // and because (invariant on `T::LAYOUT`) we can trust that `LAYOUT` + // accurately reflects the layout of `T`. + // + // `CoreMaybeUninit` has the same size as `T` [1] and admits + // uninitialized bytes in all positions. + // + // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1: + // + // `MaybeUninit` is guaranteed to have the same size, alignment, + // and ABI as `T` + unsafe { crate::util::transmute_unchecked(uninit) } + } + + /// Creates a `Box>`. + /// + /// This function is useful for allocating large, uninit values on the heap + /// without ever creating a temporary instance of `Self` on the stack. + /// + /// # Errors + /// + /// Returns an error on allocation failure. Allocation failure is guaranteed + /// never to cause a panic or an abort. + #[cfg(feature = "alloc")] + #[inline] + pub fn new_boxed_uninit(meta: T::PointerMetadata) -> Result, AllocError> { + // SAFETY: `alloc::alloc::alloc_zeroed` is a valid argument of + // `new_box`. The referent of the pointer returned by `alloc` (and, + // consequently, the `Box` derived from it) is a valid instance of + // `Self`, because `Self` is `MaybeUninit` and thus admits arbitrary + // (un)initialized bytes. + unsafe { crate::util::new_box(meta, alloc::alloc::alloc) } + } + + /// Extracts the value from the `MaybeUninit` container. + /// + /// # Safety + /// + /// The caller must ensure that `self` is in an bit-valid state. Depending + /// on subsequent use, it may also need to be in a library-valid state. + #[inline(always)] + pub const unsafe fn assume_init(self) -> T + where + T: Sized, + Self: Sized, + { + // SAFETY: The caller guarantees that `self` is in an bit-valid state. + unsafe { crate::util::transmute_unchecked(self) } + } +} + +impl fmt::Debug for MaybeUninit { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad(core::any::type_name::()) + } +} + #[cfg(test)] mod tests { use core::panic::AssertUnwindSafe; @@ -553,7 +674,7 @@ mod tests { } #[test] - fn test_copy_clone() { + fn test_unalign_copy_clone() { // Test that `Copy` and `Clone` do not cause soundness issues. This test // is mainly meant to exercise UB that would be caught by Miri. @@ -568,7 +689,7 @@ mod tests { } #[test] - fn test_trait_impls() { + fn test_unalign_trait_impls() { let zero = Unalign::new(0u8); let one = Unalign::new(1u8); @@ -595,4 +716,37 @@ mod tests { assert_eq!(format!("{}", zero), format!("{}", 0u8)); assert_eq!(format!("{}", one), format!("{}", 1u8)); } + + #[test] + #[allow(clippy::as_conversions)] + fn test_maybe_uninit() { + // int + { + let input = 42; + let uninit = MaybeUninit::new(input); + // SAFETY: `uninit` is in an initialized state + let output = unsafe { uninit.assume_init() }; + assert_eq!(input, output); + } + + // thin ref + { + let input = 42; + let uninit = MaybeUninit::new(&input); + // SAFETY: `uninit` is in an initialized state + let output = unsafe { uninit.assume_init() }; + assert_eq!(&input as *const _, output as *const _); + assert_eq!(input, *output); + } + + // wide ref + { + let input = [1, 2, 3, 4]; + let uninit = MaybeUninit::new(&input[..]); + // SAFETY: `uninit` is in an initialized state + let output = unsafe { uninit.assume_init() }; + assert_eq!(&input[..] as *const _, output as *const _); + assert_eq!(input, *output); + } + } } diff --git a/tests/ui-msrv/diagnostic-not-implemented-known-layout.stderr b/tests/ui-msrv/diagnostic-not-implemented-known-layout.stderr index 4fc50b9f2e..0d6ea1ceaa 100644 --- a/tests/ui-msrv/diagnostic-not-implemented-known-layout.stderr +++ b/tests/ui-msrv/diagnostic-not-implemented-known-layout.stderr @@ -5,14 +5,14 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::KnownLayout` is not satisf | ^^^^^^^^^^^ the trait `zerocopy::KnownLayout` is not implemented for `NotZerocopy` | = help: the following other types implement trait `zerocopy::KnownLayout`: + &T + &mut T () *const T *mut T AU16 AtomicBool AtomicI16 - AtomicI32 - AtomicI64 and $N others note: required by a bound in `takes_known_layout` --> tests/ui-msrv/diagnostic-not-implemented-known-layout.rs:21:26 diff --git a/tests/ui-nightly/diagnostic-not-implemented-known-layout.stderr b/tests/ui-nightly/diagnostic-not-implemented-known-layout.stderr index 2509defb7b..812547839d 100644 --- a/tests/ui-nightly/diagnostic-not-implemented-known-layout.stderr +++ b/tests/ui-nightly/diagnostic-not-implemented-known-layout.stderr @@ -6,14 +6,14 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::KnownLayout` is not satisf | = note: Consider adding `#[derive(KnownLayout)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::KnownLayout`: + &T + &mut T () *const T *mut T AU16 AtomicBool AtomicI16 - AtomicI32 - AtomicI64 and $N others note: required by a bound in `takes_known_layout` --> tests/ui-nightly/diagnostic-not-implemented-known-layout.rs:21:26 diff --git a/tests/ui-stable/diagnostic-not-implemented-known-layout.stderr b/tests/ui-stable/diagnostic-not-implemented-known-layout.stderr index bfeec2263d..af5564c89f 100644 --- a/tests/ui-stable/diagnostic-not-implemented-known-layout.stderr +++ b/tests/ui-stable/diagnostic-not-implemented-known-layout.stderr @@ -6,14 +6,14 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::KnownLayout` is not satisf | = note: Consider adding `#[derive(KnownLayout)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::KnownLayout`: + &T + &mut T () *const T *mut T AU16 AtomicBool AtomicI16 - AtomicI32 - AtomicI64 and $N others note: required by a bound in `takes_known_layout` --> tests/ui-stable/diagnostic-not-implemented-known-layout.rs:21:26 diff --git a/zerocopy-derive/src/lib.rs b/zerocopy-derive/src/lib.rs index df12b9be7c..4b717c1494 100644 --- a/zerocopy-derive/src/lib.rs +++ b/zerocopy-derive/src/lib.rs @@ -139,8 +139,10 @@ fn derive_known_layout_inner(ast: &DeriveInput, _top_level: Trait) -> Result Result::PointerMetadata; - - // SAFETY: `LAYOUT` accurately describes the layout of `Self`. - // The layout of `Self` is reflected using a sequence of - // invocations of `DstLayout::{new_zst,extend,pad_to_align}`. - // The documentation of these items vows that invocations in - // this manner will acurately describe a type, so long as: - // - // - that type is `repr(C)`, - // - its fields are enumerated in the order they appear, - // - the presence of `repr_align` and `repr_packed` are correctly accounted for. - // - // We respect all three of these preconditions here. This - // expansion is only used if `is_repr_c_struct`, we enumerate - // the fields in order, and we extract the values of `align(N)` - // and `packed(N)`. - const LAYOUT: ::zerocopy::DstLayout = { - use ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize; - use ::zerocopy::{DstLayout, KnownLayout}; - - let repr_align = #repr_align; - let repr_packed = #repr_packed; - - DstLayout::new_zst(repr_align) - #(.extend(DstLayout::for_type::<#leading_fields_tys>(), repr_packed))* - .extend(<#trailing_field_ty as KnownLayout>::LAYOUT, repr_packed) - .pad_to_align() - }; - + let make_methods = |trailing_field_ty| { + quote! { // SAFETY: // - The returned pointer has the same address and provenance as // `bytes`: @@ -238,8 +210,111 @@ fn derive_known_layout_inner(ast: &DeriveInput, _top_level: Trait) -> Result Self::PointerMetadata { <#trailing_field_ty>::pointer_to_metadata(ptr as *mut _) } - ), - ) + } + }; + + let inner_extras = { + let leading_fields_tys = leading_fields_tys.clone(); + let methods = make_methods(*trailing_field_ty); + let (_, ty_generics, _) = ast.generics.split_for_impl(); + + quote!( + type PointerMetadata = <#trailing_field_ty as ::zerocopy::KnownLayout>::PointerMetadata; + + type MaybeUninit = __ZerocopyKnownLayoutMaybeUninit #ty_generics; + + // SAFETY: `LAYOUT` accurately describes the layout of `Self`. + // The layout of `Self` is reflected using a sequence of + // invocations of `DstLayout::{new_zst,extend,pad_to_align}`. + // The documentation of these items vows that invocations in + // this manner will acurately describe a type, so long as: + // + // - that type is `repr(C)`, + // - its fields are enumerated in the order they appear, + // - the presence of `repr_align` and `repr_packed` are correctly accounted for. + // + // We respect all three of these preconditions here. This + // expansion is only used if `is_repr_c_struct`, we enumerate + // the fields in order, and we extract the values of `align(N)` + // and `packed(N)`. + const LAYOUT: ::zerocopy::DstLayout = { + use ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize; + use ::zerocopy::{DstLayout, KnownLayout}; + + let repr_align = #repr_align; + let repr_packed = #repr_packed; + + DstLayout::new_zst(repr_align) + #(.extend(DstLayout::for_type::<#leading_fields_tys>(), repr_packed))* + .extend(<#trailing_field_ty as KnownLayout>::LAYOUT, repr_packed) + .pad_to_align() + }; + + #methods + ) + }; + + let outer_extras = { + let ident = &ast.ident; + let vis = &ast.vis; + let params = &ast.generics.params; + let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); + + let predicates = if let Some(where_clause) = where_clause { + where_clause.predicates.clone() + } else { + Default::default() + }; + + let methods = make_methods(&parse_quote! { + <#trailing_field_ty as ::zerocopy::KnownLayout>::MaybeUninit + }); + + quote! { + // SAFETY: This has the same layout as the derive target type, + // except that it admits uninit bytes. This is ensured by using the + // same repr as the target type, and by using field types which have + // the same layout as the target type's fields, except that they + // admit uninit bytes. + #repr + #[doc(hidden)] + #vis struct __ZerocopyKnownLayoutMaybeUninit<#params> ( + #(::zerocopy::util::macro_util::core_reexport::mem::MaybeUninit<#leading_fields_tys>,)* + <#trailing_field_ty as ::zerocopy::KnownLayout>::MaybeUninit + ) + where + #trailing_field_ty: ::zerocopy::KnownLayout, + #predicates; + + // SAFETY: We largely defer to the `KnownLayout` implementation on + // the derive target type (both by using the same tokens, and by + // deferring to impl via type-level indirection). This is sound, + // since `__ZerocopyKnownLayoutMaybeUninit` is guaranteed to + // have the same layout as the derive target type, except that + // `__ZerocopyKnownLayoutMaybeUninit` admits uninit bytes. + unsafe impl #impl_generics ::zerocopy::KnownLayout for __ZerocopyKnownLayoutMaybeUninit #ty_generics + where + #trailing_field_ty: ::zerocopy::KnownLayout, + // This bound may appear to be superfluous, but is required + // on our MSRV (1.55) to avoid an ICE. + <#trailing_field_ty as ::zerocopy::KnownLayout>::MaybeUninit: ::zerocopy::KnownLayout, + #predicates + { + #[allow(clippy::missing_inline_in_public_items)] + fn only_derive_is_allowed_to_implement_this_trait() {} + + type PointerMetadata = <#ident #ty_generics as ::zerocopy::KnownLayout>::PointerMetadata; + + type MaybeUninit = Self; + + const LAYOUT: ::zerocopy::DstLayout = <#ident #ty_generics as ::zerocopy::KnownLayout>::LAYOUT; + + #methods + } + } + }; + + (SelfBounds::None, inner_extras, Some(outer_extras)) } else { // For enums, unions, and non-`repr(C)` structs, we require that // `Self` is sized, and as a result don't need to reason about the @@ -248,6 +323,8 @@ fn derive_known_layout_inner(ast: &DeriveInput, _top_level: Trait) -> Result; // SAFETY: `LAYOUT` is guaranteed to accurately describe the // layout of `Self`, because that is the documented safety @@ -270,6 +347,7 @@ fn derive_known_layout_inner(ast: &DeriveInput, _top_level: Trait) -> Result () {} ), + None, ) }; @@ -292,7 +370,8 @@ fn derive_known_layout_inner(ast: &DeriveInput, _top_level: Trait) -> Result { @@ -305,7 +384,8 @@ fn derive_known_layout_inner(ast: &DeriveInput, _top_level: Trait) -> Result { @@ -318,7 +398,8 @@ fn derive_known_layout_inner(ast: &DeriveInput, _top_level: Trait) -> Result TokenStream { SelfBounds::None, None, None, + None, ), Data::Enum(enm) => impl_block( ast, @@ -343,6 +425,7 @@ fn derive_no_cell_inner(ast: &DeriveInput, _top_level: Trait) -> TokenStream { SelfBounds::None, None, None, + None, ), Data::Union(unn) => impl_block( ast, @@ -352,6 +435,7 @@ fn derive_no_cell_inner(ast: &DeriveInput, _top_level: Trait) -> TokenStream { SelfBounds::None, None, None, + None, ), } } @@ -452,6 +536,7 @@ fn derive_try_from_bytes_struct( SelfBounds::None, None, Some(extras), + None, )) } @@ -509,6 +594,7 @@ fn derive_try_from_bytes_union( SelfBounds::None, None, Some(extras), + None, ) } @@ -545,6 +631,7 @@ fn derive_try_from_bytes_enum( SelfBounds::None, None, Some(extra), + None, )) } @@ -641,7 +728,16 @@ unsafe fn gen_trivial_is_bit_valid_unchecked() -> proc_macro2::TokenStream { /// A struct is `FromZeros` if: /// - all fields are `FromZeros` fn derive_from_zeros_struct(ast: &DeriveInput, strct: &DataStruct) -> TokenStream { - impl_block(ast, strct, Trait::FromZeros, FieldBounds::ALL_SELF, SelfBounds::None, None, None) + impl_block( + ast, + strct, + Trait::FromZeros, + FieldBounds::ALL_SELF, + SelfBounds::None, + None, + None, + None, + ) } /// Returns `Ok(index)` if variant `index` of the enum has a discriminant of @@ -777,6 +873,7 @@ fn derive_from_zeros_enum(ast: &DeriveInput, enm: &DataEnum) -> Result TokenStream { // compatibility with `derive(TryFromBytes)` on unions; not for soundness. let field_type_trait_bounds = FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::Immutable)]); - impl_block(ast, unn, Trait::FromZeros, field_type_trait_bounds, SelfBounds::None, None, None) + impl_block( + ast, + unn, + Trait::FromZeros, + field_type_trait_bounds, + SelfBounds::None, + None, + None, + None, + ) } /// A struct is `FromBytes` if: /// - all fields are `FromBytes` fn derive_from_bytes_struct(ast: &DeriveInput, strct: &DataStruct) -> TokenStream { - impl_block(ast, strct, Trait::FromBytes, FieldBounds::ALL_SELF, SelfBounds::None, None, None) + impl_block( + ast, + strct, + Trait::FromBytes, + FieldBounds::ALL_SELF, + SelfBounds::None, + None, + None, + None, + ) } /// An enum is `FromBytes` if: @@ -825,7 +940,16 @@ fn derive_from_bytes_enum(ast: &DeriveInput, enm: &DataEnum) -> Result TokenStream { // compatibility with `derive(TryFromBytes)` on unions; not for soundness. let field_type_trait_bounds = FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::Immutable)]); - impl_block(ast, unn, Trait::FromBytes, field_type_trait_bounds, SelfBounds::None, None, None) + impl_block( + ast, + unn, + Trait::FromBytes, + field_type_trait_bounds, + SelfBounds::None, + None, + None, + None, + ) } fn derive_into_bytes_struct(ast: &DeriveInput, strct: &DataStruct) -> Result { @@ -925,6 +1058,7 @@ fn derive_into_bytes_struct(ast: &DeriveInput, strct: &DataStruct) -> Result Result Result Result Result impl '_ + Iterator( input: &DeriveInput, data: &D, @@ -1200,7 +1347,8 @@ fn impl_block( field_type_trait_bounds: FieldBounds, self_type_trait_bounds: SelfBounds, padding_check: Option, - extras: Option, + inner_extras: Option, + outer_extras: Option, ) -> TokenStream { // In this documentation, we will refer to this hypothetical struct: // @@ -1347,7 +1495,7 @@ fn impl_block( } }); - quote! { + let impl_tokens = quote! { // TODO(#553): Add a test that generates a warning when // `#[allow(deprecated)]` isn't present. #[allow(deprecated)] @@ -1360,7 +1508,21 @@ fn impl_block( { fn only_derive_is_allowed_to_implement_this_trait() {} - #extras + #inner_extras + } + }; + + if let Some(outer_extras) = outer_extras { + // So that any items defined in `#outer_extras` don't conflict with + // existing names defined in this scope. + quote! { + const _: () = { + #impl_tokens + + #outer_extras + }; } + } else { + impl_tokens } } diff --git a/zerocopy-derive/src/output_tests.rs b/zerocopy-derive/src/output_tests.rs index 175c128821..7226d600a9 100644 --- a/zerocopy-derive/src/output_tests.rs +++ b/zerocopy-derive/src/output_tests.rs @@ -111,6 +111,8 @@ fn test_known_layout() { type PointerMetadata = (); + type MaybeUninit = ::zerocopy::util::macro_util::core_reexport::mem::MaybeUninit; + const LAYOUT: ::zerocopy::DstLayout = ::zerocopy::DstLayout::for_type::(); #[inline(always)] @@ -126,6 +128,104 @@ fn test_known_layout() { } } no_build } + + test! { + KnownLayout { + #[repr(C, align(2))] + struct Foo(T, U); + } + expands to { + const _: () = { + #[allow(deprecated)] + #[automatically_derived] + unsafe impl ::zerocopy::KnownLayout for Foo + where + U: ::zerocopy::KnownLayout, + { + fn only_derive_is_allowed_to_implement_this_trait() {} + type PointerMetadata = ::PointerMetadata; + type MaybeUninit = __ZerocopyKnownLayoutMaybeUninit; + const LAYOUT: ::zerocopy::DstLayout = { + use ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize; + use ::zerocopy::{DstLayout, KnownLayout}; + let repr_align = ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize::new( + 2u32 as usize, + ); + let repr_packed = ::zerocopy::util::macro_util::core_reexport::option::Option::None; + DstLayout::new_zst(repr_align) + .extend(DstLayout::for_type::(), repr_packed) + .extend(::LAYOUT, repr_packed) + .pad_to_align() + }; + #[inline(always)] + fn raw_from_ptr_len( + bytes: ::zerocopy::util::macro_util::core_reexport::ptr::NonNull, + meta: Self::PointerMetadata, + ) -> ::zerocopy::util::macro_util::core_reexport::ptr::NonNull { + use ::zerocopy::KnownLayout; + let trailing = ::raw_from_ptr_len(bytes, meta); + let slf = trailing.as_ptr() as *mut Self; + unsafe { + ::zerocopy::util::macro_util::core_reexport::ptr::NonNull::new_unchecked( + slf, + ) + } + } + #[inline(always)] + fn pointer_to_metadata(ptr: *mut Self) -> Self::PointerMetadata { + ::pointer_to_metadata(ptr as *mut _) + } + } + #[repr(C)] + #[repr(align(2))] + #[doc(hidden)] + struct __ZerocopyKnownLayoutMaybeUninit( + ::zerocopy::util::macro_util::core_reexport::mem::MaybeUninit, + ::MaybeUninit, + ) + where + U: ::zerocopy::KnownLayout; + unsafe impl ::zerocopy::KnownLayout + for __ZerocopyKnownLayoutMaybeUninit + where + U: ::zerocopy::KnownLayout, + ::MaybeUninit: ::zerocopy::KnownLayout, + { + #[allow(clippy::missing_inline_in_public_items)] + fn only_derive_is_allowed_to_implement_this_trait() {} + type PointerMetadata = as ::zerocopy::KnownLayout>::PointerMetadata; + type MaybeUninit = Self; + const LAYOUT: ::zerocopy::DstLayout = as ::zerocopy::KnownLayout>::LAYOUT; + #[inline(always)] + fn raw_from_ptr_len( + bytes: ::zerocopy::util::macro_util::core_reexport::ptr::NonNull, + meta: Self::PointerMetadata, + ) -> ::zerocopy::util::macro_util::core_reexport::ptr::NonNull { + use ::zerocopy::KnownLayout; + let trailing = <::MaybeUninit as KnownLayout>::raw_from_ptr_len( + bytes, + meta, + ); + let slf = trailing.as_ptr() as *mut Self; + unsafe { + ::zerocopy::util::macro_util::core_reexport::ptr::NonNull::new_unchecked( + slf, + ) + } + } + #[inline(always)] + fn pointer_to_metadata(ptr: *mut Self) -> Self::PointerMetadata { + <::MaybeUninit>::pointer_to_metadata( + ptr as *mut _, + ) + } + } + }; + } no_build + } } #[test] diff --git a/zerocopy-derive/tests/ui-msrv/mid_compile_pass.stderr b/zerocopy-derive/tests/ui-msrv/mid_compile_pass.stderr index 2538c9deb4..8908ba21f9 100644 --- a/zerocopy-derive/tests/ui-msrv/mid_compile_pass.stderr +++ b/zerocopy-derive/tests/ui-msrv/mid_compile_pass.stderr @@ -79,11 +79,11 @@ help: consider removing the `?Sized` bound to make the type parameter `Sized` 39 + fn test_kl06(kl: &KL06) { | -error[E0277]: the trait bound `T: KnownLayout` is not satisfied +error[E0277]: the trait bound `KL12: KnownLayout` is not satisfied --> tests/ui-msrv/mid_compile_pass.rs:50:15 | 50 | assert_kl(kl) - | --------- ^^ the trait `KnownLayout` is not implemented for `T` + | --------- ^^ the trait `KnownLayout` is not implemented for `KL12` | | | required by a bound introduced by this call | @@ -98,7 +98,9 @@ note: required by a bound in `assert_kl` 23 | fn assert_kl(_: &T) {} | ^^^^^^^^^^^ required by this bound in `assert_kl` = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider further restricting this bound +help: consider borrowing here | -49 | fn test_kl12(kl: &KL12) { - | +++++++++++++++++++++++ +50 | assert_kl(&kl) + | + +50 | assert_kl(&mut kl) + | ++++ diff --git a/zerocopy-derive/tests/ui-msrv/struct.stderr b/zerocopy-derive/tests/ui-msrv/struct.stderr index ed72562beb..41aefa9711 100644 --- a/zerocopy-derive/tests/ui-msrv/struct.stderr +++ b/zerocopy-derive/tests/ui-msrv/struct.stderr @@ -123,14 +123,14 @@ error[E0277]: the trait bound `NotKnownLayoutDst: zerocopy::KnownLayout` is not | ^^^^^^^^^^^ the trait `zerocopy::KnownLayout` is not implemented for `NotKnownLayoutDst` | = help: the following other types implement trait `zerocopy::KnownLayout`: + &T + &mut T () *const T *mut T AU16 AtomicBool AtomicI16 - AtomicI32 - AtomicI64 and $N others = help: see issue #48214 = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -142,14 +142,14 @@ error[E0277]: the trait bound `NotKnownLayout: zerocopy::KnownLayout` is not sat | ^^^^^^^^^^^ the trait `zerocopy::KnownLayout` is not implemented for `NotKnownLayout` | = help: the following other types implement trait `zerocopy::KnownLayout`: + &T + &mut T () *const T *mut T AU16 AtomicBool AtomicI16 - AtomicI32 - AtomicI64 and $N others = help: see issue #48214 = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/zerocopy-derive/tests/ui-nightly/mid_compile_pass.stderr b/zerocopy-derive/tests/ui-nightly/mid_compile_pass.stderr index c80f1beee7..7793e88745 100644 --- a/zerocopy-derive/tests/ui-nightly/mid_compile_pass.stderr +++ b/zerocopy-derive/tests/ui-nightly/mid_compile_pass.stderr @@ -82,15 +82,14 @@ help: consider removing the `?Sized` bound to make the type parameter `Sized` 39 + fn test_kl06(kl: &KL06) { | -error[E0277]: the trait bound `T: KnownLayout` is not satisfied +error[E0277]: the trait bound `KL12: KnownLayout` is not satisfied --> tests/ui-nightly/mid_compile_pass.rs:50:15 | 50 | assert_kl(kl) - | --------- ^^ the trait `KnownLayout` is not implemented for `T` + | --------- ^^ the trait `KnownLayout` is not implemented for `KL12` | | | required by a bound introduced by this call | - = note: Consider adding `#[derive(KnownLayout)]` to `T` note: required for `KL12` to implement `KnownLayout` --> tests/ui-nightly/mid_compile_pass.rs:45:10 | @@ -102,7 +101,9 @@ note: required by a bound in `assert_kl` 23 | fn assert_kl(_: &T) {} | ^^^^^^^^^^^ required by this bound in `assert_kl` = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider further restricting this bound +help: consider borrowing here | -49 | fn test_kl12(kl: &KL12) { - | +++++++++++++++++++++++ +50 | assert_kl(&kl) + | + +50 | assert_kl(&mut kl) + | ++++ diff --git a/zerocopy-derive/tests/ui-nightly/struct.stderr b/zerocopy-derive/tests/ui-nightly/struct.stderr index 200a12683b..8952da8ddd 100644 --- a/zerocopy-derive/tests/ui-nightly/struct.stderr +++ b/zerocopy-derive/tests/ui-nightly/struct.stderr @@ -135,14 +135,14 @@ error[E0277]: the trait bound `NotKnownLayoutDst: zerocopy::KnownLayout` is not | = note: Consider adding `#[derive(KnownLayout)]` to `NotKnownLayoutDst` = help: the following other types implement trait `zerocopy::KnownLayout`: + &T + &mut T () *const T *mut T AU16 AtomicBool AtomicI16 - AtomicI32 - AtomicI64 and $N others = help: see issue #48214 = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -159,14 +159,14 @@ error[E0277]: the trait bound `NotKnownLayout: zerocopy::KnownLayout` is not sat | = note: Consider adding `#[derive(KnownLayout)]` to `NotKnownLayout` = help: the following other types implement trait `zerocopy::KnownLayout`: + &T + &mut T () *const T *mut T AU16 AtomicBool AtomicI16 - AtomicI32 - AtomicI64 and $N others = help: see issue #48214 = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/zerocopy-derive/tests/ui-stable/mid_compile_pass.stderr b/zerocopy-derive/tests/ui-stable/mid_compile_pass.stderr index 20581d45f8..6082eda01e 100644 --- a/zerocopy-derive/tests/ui-stable/mid_compile_pass.stderr +++ b/zerocopy-derive/tests/ui-stable/mid_compile_pass.stderr @@ -82,15 +82,14 @@ help: consider removing the `?Sized` bound to make the type parameter `Sized` 39 + fn test_kl06(kl: &KL06) { | -error[E0277]: the trait bound `T: KnownLayout` is not satisfied +error[E0277]: the trait bound `KL12: KnownLayout` is not satisfied --> tests/ui-stable/mid_compile_pass.rs:50:15 | 50 | assert_kl(kl) - | --------- ^^ the trait `KnownLayout` is not implemented for `T` + | --------- ^^ the trait `KnownLayout` is not implemented for `KL12` | | | required by a bound introduced by this call | - = note: Consider adding `#[derive(KnownLayout)]` to `T` note: required for `KL12` to implement `KnownLayout` --> tests/ui-stable/mid_compile_pass.rs:45:10 | @@ -102,7 +101,9 @@ note: required by a bound in `assert_kl` 23 | fn assert_kl(_: &T) {} | ^^^^^^^^^^^ required by this bound in `assert_kl` = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider further restricting this bound +help: consider borrowing here | -49 | fn test_kl12(kl: &KL12) { - | +++++++++++++++++++++++ +50 | assert_kl(&kl) + | + +50 | assert_kl(&mut kl) + | ++++ diff --git a/zerocopy-derive/tests/ui-stable/struct.stderr b/zerocopy-derive/tests/ui-stable/struct.stderr index 148a56520e..30d0902e8d 100644 --- a/zerocopy-derive/tests/ui-stable/struct.stderr +++ b/zerocopy-derive/tests/ui-stable/struct.stderr @@ -124,14 +124,14 @@ error[E0277]: the trait bound `NotKnownLayoutDst: zerocopy::KnownLayout` is not | = note: Consider adding `#[derive(KnownLayout)]` to `NotKnownLayoutDst` = help: the following other types implement trait `zerocopy::KnownLayout`: + &T + &mut T () *const T *mut T AU16 AtomicBool AtomicI16 - AtomicI32 - AtomicI64 and $N others = help: see issue #48214 = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -144,14 +144,14 @@ error[E0277]: the trait bound `NotKnownLayout: zerocopy::KnownLayout` is not sat | = note: Consider adding `#[derive(KnownLayout)]` to `NotKnownLayout` = help: the following other types implement trait `zerocopy::KnownLayout`: + &T + &mut T () *const T *mut T AU16 AtomicBool AtomicI16 - AtomicI32 - AtomicI64 and $N others = help: see issue #48214 = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) From 64df858404874d8a27140487825ed153c558cb08 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Thu, 6 Feb 2025 12:47:50 -0800 Subject: [PATCH 85/96] Implement KnownLayout for f16 and f128 (#2250) (#2312) Co-authored-by: usamoi --- src/impls.rs | 21 ++++++++++++++++++++- src/lib.rs | 8 ++++++++ src/util/macros.rs | 5 +++-- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/impls.rs b/src/impls.rs index c4184694ab..a79b82e7d7 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -1538,6 +1538,16 @@ mod tests { IntoBytes, !Unaligned ); + #[cfg(feature = "float-nightly")] + assert_impls!( + f16: KnownLayout, + Immutable, + TryFromBytes, + FromZeros, + FromBytes, + IntoBytes, + !Unaligned + ); assert_impls!( f32: KnownLayout, Immutable, @@ -1556,7 +1566,16 @@ mod tests { IntoBytes, !Unaligned ); - + #[cfg(feature = "float-nightly")] + assert_impls!( + f128: KnownLayout, + Immutable, + TryFromBytes, + FromZeros, + FromBytes, + IntoBytes, + !Unaligned + ); assert_impls!( bool: KnownLayout, Immutable, diff --git a/src/lib.rs b/src/lib.rs index 2c2c653422..b6c7876730 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -929,6 +929,14 @@ impl_known_layout!( NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize ); #[rustfmt::skip] +#[cfg(feature = "float-nightly")] +impl_known_layout!( + #[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] + f16, + #[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] + f128 +); +#[rustfmt::skip] impl_known_layout!( T => Option, T: ?Sized => PhantomData, diff --git a/src/util/macros.rs b/src/util/macros.rs index 2b19779ced..67840e2875 100644 --- a/src/util/macros.rs +++ b/src/util/macros.rs @@ -532,12 +532,13 @@ macro_rules! impl_known_layout { ($($tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => { $(impl_known_layout!(@inner , $tyvar $(: ?$optbound)? => $ty);)* }; - ($($ty:ty),*) => { $(impl_known_layout!(@inner , => $ty);)* }; - (@inner $(const $constvar:ident : $constty:ty)? , $($tyvar:ident $(: ?$optbound:ident)?)? => $ty:ty) => { + ($($(#[$attrs:meta])* $ty:ty),*) => { $(impl_known_layout!(@inner , => $(#[$attrs])* $ty);)* }; + (@inner $(const $constvar:ident : $constty:ty)? , $($tyvar:ident $(: ?$optbound:ident)?)? => $(#[$attrs:meta])* $ty:ty) => { const _: () = { use core::ptr::NonNull; #[allow(non_local_definitions)] + $(#[$attrs])* // SAFETY: Delegates safety to `DstLayout::for_type`. unsafe impl<$($tyvar $(: ?$optbound)?)? $(, const $constvar : $constty)?> KnownLayout for $ty { #[allow(clippy::missing_inline_in_public_items)] From 66d39a94cf3f727b2b9a7bd4c62f91371009ad85 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Thu, 6 Feb 2025 12:57:44 -0800 Subject: [PATCH 86/96] Practice good `Self` hygiene (#2127) (#2313) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit revises the `KnownLayout` derive on `repr(C)` target structs to preserve the correct resolution of `Self` when constructing `__ZerocopyKnownLayoutMaybeUninit`. This type contains a `MaybeUninit` version of each of the target struct's field types. Previously, it achieved this by simply copying the tokens corresponding to field types from the definition of the target struct into the definition of `__ZerocopyKnownLayoutMaybeUninit` However, on types like this: #[repr(C)] struct Struct([u8; Self::N]); …this approach is insufficient. Pasted into `__ZerocopyKnownLayoutMaybeUninit`, `Self` ceases to refer to the target struct and instead refers to `__ZerocopyKnownLayoutMaybeUninit`. To preserve `Self` hygiene, this commit defines a struct for projecting the field types of the target struct based on their index: pub unsafe trait Field { type Type: ?Sized; } …then implements it for each of the field types of the target struct; e.g.: struct Index; impl Field> for Struct { type Type = [u8; Self::N]; } With this, the fields of `__ZerocopyKnownLayoutMaybeUninit` can be defined hygienically; e.g., as `>::Type`. Fixes #2116 Co-authored-by: Jack Wrenn --- src/util/macro_util.rs | 14 ++++ zerocopy-derive/src/ext.rs | 25 +++--- zerocopy-derive/src/lib.rs | 82 +++++++++++++++----- zerocopy-derive/src/output_tests.rs | 55 ++++++++++--- zerocopy-derive/tests/struct_known_layout.rs | 62 ++++++++++++--- 5 files changed, 188 insertions(+), 50 deletions(-) diff --git a/src/util/macro_util.rs b/src/util/macro_util.rs index 9d3f6ed77c..fcc7ca2397 100644 --- a/src/util/macro_util.rs +++ b/src/util/macro_util.rs @@ -29,6 +29,20 @@ use crate::{ Immutable, IntoBytes, Ptr, TryFromBytes, Unalign, ValidityError, }; +/// Projects the type of the field at `Index` in `Self`. +/// +/// The `Index` parameter is any sort of handle that identifies the field; its +/// definition is the obligation of the implementer. +/// +/// # Safety +/// +/// Unsafe code may assume that this accurately reflects the definition of +/// `Self`. +pub unsafe trait Field { + /// The type of the field at `Index`. + type Type: ?Sized; +} + #[cfg_attr( zerocopy_diagnostic_on_unimplemented, diagnostic::on_unimplemented( diff --git a/zerocopy-derive/src/ext.rs b/zerocopy-derive/src/ext.rs index 9b446f53a9..d1be8cf373 100644 --- a/zerocopy-derive/src/ext.rs +++ b/zerocopy-derive/src/ext.rs @@ -8,7 +8,7 @@ use proc_macro2::{Span, TokenStream}; use quote::ToTokens; -use syn::{Data, DataEnum, DataStruct, DataUnion, Field, Ident, Index, Type}; +use syn::{Data, DataEnum, DataStruct, DataUnion, Field, Ident, Index, Type, Visibility}; pub(crate) trait DataExt { /// Extracts the names and types of all fields. For enums, extracts the names @@ -19,15 +19,15 @@ pub(crate) trait DataExt { /// makes sense because we don't care about where they live - we just care /// about transitive ownership. But for field names, we'd only use them when /// generating is_bit_valid, which cares about where they live. - fn fields(&self) -> Vec<(TokenStream, &Type)>; + fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)>; - fn variants(&self) -> Vec>; + fn variants(&self) -> Vec>; fn tag(&self) -> Option; } impl DataExt for Data { - fn fields(&self) -> Vec<(TokenStream, &Type)> { + fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)> { match self { Data::Struct(strc) => strc.fields(), Data::Enum(enm) => enm.fields(), @@ -35,7 +35,7 @@ impl DataExt for Data { } } - fn variants(&self) -> Vec> { + fn variants(&self) -> Vec> { match self { Data::Struct(strc) => strc.variants(), Data::Enum(enm) => enm.variants(), @@ -53,11 +53,11 @@ impl DataExt for Data { } impl DataExt for DataStruct { - fn fields(&self) -> Vec<(TokenStream, &Type)> { + fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)> { map_fields(&self.fields) } - fn variants(&self) -> Vec> { + fn variants(&self) -> Vec> { vec![self.fields()] } @@ -67,11 +67,11 @@ impl DataExt for DataStruct { } impl DataExt for DataEnum { - fn fields(&self) -> Vec<(TokenStream, &Type)> { + fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)> { map_fields(self.variants.iter().flat_map(|var| &var.fields)) } - fn variants(&self) -> Vec> { + fn variants(&self) -> Vec> { self.variants.iter().map(|var| map_fields(&var.fields)).collect() } @@ -81,11 +81,11 @@ impl DataExt for DataEnum { } impl DataExt for DataUnion { - fn fields(&self) -> Vec<(TokenStream, &Type)> { + fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)> { map_fields(&self.fields.named) } - fn variants(&self) -> Vec> { + fn variants(&self) -> Vec> { vec![self.fields()] } @@ -96,12 +96,13 @@ impl DataExt for DataUnion { fn map_fields<'a>( fields: impl 'a + IntoIterator, -) -> Vec<(TokenStream, &'a Type)> { +) -> Vec<(&'a Visibility, TokenStream, &'a Type)> { fields .into_iter() .enumerate() .map(|(idx, f)| { ( + &f.vis, f.ident .as_ref() .map(ToTokens::to_token_stream) diff --git a/zerocopy-derive/src/lib.rs b/zerocopy-derive/src/lib.rs index 4b717c1494..ccef0496d2 100644 --- a/zerocopy-derive/src/lib.rs +++ b/zerocopy-derive/src/lib.rs @@ -144,8 +144,8 @@ fn derive_known_layout_inner(ast: &DeriveInput, _top_level: Trait) -> Result Result = + fields.iter().map(|(_vis, name, _ty)| field_index(name)).collect(); + + // Define the collection of type-level field handles. + let field_defs = field_indices.iter().zip(&fields).map(|(idx, (vis, _, _))| { + quote! { + #[allow(non_camel_case_types)] + #vis struct #idx; + } + }); + + let field_impls = field_indices.iter().zip(&fields).map(|(idx, (_, _, ty))| quote! { + // SAFETY: `#ty` is the type of `#ident`'s field at `#idx`. + unsafe impl #impl_generics ::zerocopy::util::macro_util::Field<#idx> for #ident #ty_generics + where + #predicates + { + type Type = #ty; + } + }); + + let trailing_field_index = field_index(trailing_field_name); + let leading_field_indices = + leading_fields.iter().map(|(_vis, name, _ty)| field_index(name)); + + let trailing_field_ty = quote! { + <#ident #ty_generics as + ::zerocopy::util::macro_util::Field<#trailing_field_index> + >::Type + }; + let methods = make_methods(&parse_quote! { <#trailing_field_ty as ::zerocopy::KnownLayout>::MaybeUninit }); quote! { + #(#field_defs)* + + #(#field_impls)* + // SAFETY: This has the same layout as the derive target type, - // except that it admits uninit bytes. This is ensured by using the - // same repr as the target type, and by using field types which have - // the same layout as the target type's fields, except that they - // admit uninit bytes. + // except that it admits uninit bytes. This is ensured by using + // the same repr as the target type, and by using field types + // which have the same layout as the target type's fields, + // except that they admit uninit bytes. We indirect through + // `Field` to ensure that occurrences of `Self` resolve to + // `#ty`, not `__ZerocopyKnownLayoutMaybeUninit` (see #2116). #repr #[doc(hidden)] #vis struct __ZerocopyKnownLayoutMaybeUninit<#params> ( - #(::zerocopy::util::macro_util::core_reexport::mem::MaybeUninit<#leading_fields_tys>,)* + #(::zerocopy::util::macro_util::core_reexport::mem::MaybeUninit< + <#ident #ty_generics as + ::zerocopy::util::macro_util::Field<#leading_field_indices> + >::Type + >,)* <#trailing_field_ty as ::zerocopy::KnownLayout>::MaybeUninit ) where @@ -295,9 +341,6 @@ fn derive_known_layout_inner(ast: &DeriveInput, _top_level: Trait) -> Result::MaybeUninit: ::zerocopy::KnownLayout, #predicates { #[allow(clippy::missing_inline_in_public_items)] @@ -494,8 +537,8 @@ fn derive_try_from_bytes_struct( ) -> Result { let extras = try_gen_trivial_is_bit_valid(ast, top_level).unwrap_or_else(|| { let fields = strct.fields(); - let field_names = fields.iter().map(|(name, _ty)| name); - let field_tys = fields.iter().map(|(_name, ty)| ty); + let field_names = fields.iter().map(|(_vis, name, _ty)| name); + let field_tys = fields.iter().map(|(_vis, _name, ty)| ty); quote!( // SAFETY: We use `is_bit_valid` to validate that each field is // bit-valid, and only return `true` if all of them are. The bit @@ -552,8 +595,8 @@ fn derive_try_from_bytes_union( FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::Immutable)]); let extras = try_gen_trivial_is_bit_valid(ast, top_level).unwrap_or_else(|| { let fields = unn.fields(); - let field_names = fields.iter().map(|(name, _ty)| name); - let field_tys = fields.iter().map(|(_name, ty)| ty); + let field_names = fields.iter().map(|(_vis, name, _ty)| name); + let field_tys = fields.iter().map(|(_vis, _name, ty)| ty); quote!( // SAFETY: We use `is_bit_valid` to validate that any field is // bit-valid; we only return `true` if at least one of them is. The @@ -1419,12 +1462,13 @@ fn impl_block( parse_quote!(#ty: #(#traits)+*) } let field_type_bounds: Vec<_> = match (field_type_trait_bounds, &fields[..]) { - (FieldBounds::All(traits), _) => { - fields.iter().map(|(_name, ty)| bound_tt(ty, normalize_bounds(trt, traits))).collect() - } + (FieldBounds::All(traits), _) => fields + .iter() + .map(|(_vis, _name, ty)| bound_tt(ty, normalize_bounds(trt, traits))) + .collect(), (FieldBounds::None, _) | (FieldBounds::Trailing(..), []) => vec![], (FieldBounds::Trailing(traits), [.., last]) => { - vec![bound_tt(last.1, normalize_bounds(trt, traits))] + vec![bound_tt(last.2, normalize_bounds(trt, traits))] } (FieldBounds::Explicit(bounds), _) => bounds, }; @@ -1436,7 +1480,7 @@ fn impl_block( let padding_check_bound = padding_check.and_then(|check| (!fields.is_empty()).then_some(check)).map(|check| { let variant_types = variants.iter().map(|var| { - let types = var.iter().map(|(_name, ty)| ty); + let types = var.iter().map(|(_vis, _name, ty)| ty); quote!([#(#types),*]) }); let validator_context = check.validator_macro_context(); diff --git a/zerocopy-derive/src/output_tests.rs b/zerocopy-derive/src/output_tests.rs index 7226d600a9..1297997408 100644 --- a/zerocopy-derive/src/output_tests.rs +++ b/zerocopy-derive/src/output_tests.rs @@ -176,20 +176,47 @@ fn test_known_layout() { ::pointer_to_metadata(ptr as *mut _) } } + #[allow(non_camel_case_types)] + struct __Zerocopy_Field_0; + #[allow(non_camel_case_types)] + struct __Zerocopy_Field_1; + unsafe impl ::zerocopy::util::macro_util::Field<__Zerocopy_Field_0> + for Foo { + type Type = T; + } + unsafe impl ::zerocopy::util::macro_util::Field<__Zerocopy_Field_1> + for Foo { + type Type = U; + } #[repr(C)] #[repr(align(2))] #[doc(hidden)] struct __ZerocopyKnownLayoutMaybeUninit( - ::zerocopy::util::macro_util::core_reexport::mem::MaybeUninit, - ::MaybeUninit, + ::zerocopy::util::macro_util::core_reexport::mem::MaybeUninit< + as ::zerocopy::util::macro_util::Field<__Zerocopy_Field_0>>::Type, + >, + < as ::zerocopy::util::macro_util::Field< + __Zerocopy_Field_1, + >>::Type as ::zerocopy::KnownLayout>::MaybeUninit, ) where - U: ::zerocopy::KnownLayout; - unsafe impl ::zerocopy::KnownLayout - for __ZerocopyKnownLayoutMaybeUninit + as ::zerocopy::util::macro_util::Field< + __Zerocopy_Field_1, + >>::Type: ::zerocopy::KnownLayout; + unsafe impl ::zerocopy::KnownLayout for __ZerocopyKnownLayoutMaybeUninit where - U: ::zerocopy::KnownLayout, - ::MaybeUninit: ::zerocopy::KnownLayout, + as ::zerocopy::util::macro_util::Field< + __Zerocopy_Field_1, + >>::Type: ::zerocopy::KnownLayout, { #[allow(clippy::missing_inline_in_public_items)] fn only_derive_is_allowed_to_implement_this_trait() {} @@ -205,7 +232,12 @@ fn test_known_layout() { meta: Self::PointerMetadata, ) -> ::zerocopy::util::macro_util::core_reexport::ptr::NonNull { use ::zerocopy::KnownLayout; - let trailing = <::MaybeUninit as KnownLayout>::raw_from_ptr_len( + let trailing = << as ::zerocopy::util::macro_util::Field< + __Zerocopy_Field_1, + >>::Type as ::zerocopy::KnownLayout>::MaybeUninit as KnownLayout>::raw_from_ptr_len( bytes, meta, ); @@ -218,7 +250,12 @@ fn test_known_layout() { } #[inline(always)] fn pointer_to_metadata(ptr: *mut Self) -> Self::PointerMetadata { - <::MaybeUninit>::pointer_to_metadata( + << as ::zerocopy::util::macro_util::Field< + __Zerocopy_Field_1, + >>::Type as ::zerocopy::KnownLayout>::MaybeUninit>::pointer_to_metadata( ptr as *mut _, ) } diff --git a/zerocopy-derive/tests/struct_known_layout.rs b/zerocopy-derive/tests/struct_known_layout.rs index 1cfc584099..e34843f644 100644 --- a/zerocopy-derive/tests/struct_known_layout.rs +++ b/zerocopy-derive/tests/struct_known_layout.rs @@ -10,6 +10,8 @@ #![no_implicit_prelude] #![allow(warnings)] +extern crate rustversion; + include!("include.rs"); #[derive(imp::KnownLayout)] @@ -46,16 +48,56 @@ util_assert_impl_all!(TypeParams<'static, (), imp::IntoIter<()>>: imp::KnownLayo util_assert_impl_all!(TypeParams<'static, util::AU16, imp::IntoIter<()>>: imp::KnownLayout); // Deriving `KnownLayout` should work if the struct has bounded parameters. +// +// N.B. We limit this test to rustc >= 1.62, since earlier versions of rustc ICE +// when `KnownLayout` is derived on a `repr(C)` struct whose trailing field +// contains non-static lifetimes. +#[rustversion::since(1.62)] +const _: () = { + #[derive(imp::KnownLayout)] + #[repr(C)] + struct WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::KnownLayout, const N: usize>( + [T; N], + imp::PhantomData<&'a &'b ()>, + ) + where + 'a: 'b, + 'b: 'a, + T: 'a + 'b + imp::KnownLayout; + + util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::KnownLayout); +}; + +const _: () = { + // Similar to the previous test, except that the trailing field contains + // only static lifetimes. This is exercisable on all supported toolchains. + + #[derive(imp::KnownLayout)] + #[repr(C)] + struct WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::KnownLayout, const N: usize>( + &'a &'b [T; N], + imp::PhantomData<&'static ()>, + ) + where + 'a: 'b, + 'b: 'a, + T: 'a + 'b + imp::KnownLayout; + + util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::KnownLayout); +}; + +// Deriving `KnownLayout` should work if the struct references `Self`. See +// #2116. #[derive(imp::KnownLayout)] #[repr(C)] -struct WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::KnownLayout, const N: usize>( - [T; N], - imp::PhantomData<&'a &'b ()>, -) -where - 'a: 'b, - 'b: 'a, - T: 'a + 'b + imp::KnownLayout; - -util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::KnownLayout); +struct WithSelfReference { + leading: [u8; Self::N], + trailing: [[u8; Self::N]], +} + +impl WithSelfReference { + const N: usize = 42; +} + +util_assert_impl_all!(WithSelfReference: imp::KnownLayout); From 17e7e4d98c9d2cd49c94307e2276b7ce377aa74a Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Fri, 7 Feb 2025 10:15:00 -0800 Subject: [PATCH 87/96] [derive] Fix bug with KnownLayout on repr(packed) (#2307) (#2317) Fixes #2302 gherrit-pr-id: If68c1724be15c4df3ec936a12cf854908650a639 Co-authored-by: Joshua Liebow-Feeser --- zerocopy-derive/src/lib.rs | 10 +++++++++- zerocopy-derive/src/output_tests.rs | 14 ++++++++------ zerocopy-derive/tests/struct_known_layout.rs | 11 +++++++++++ 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/zerocopy-derive/src/lib.rs b/zerocopy-derive/src/lib.rs index ccef0496d2..869ed6675b 100644 --- a/zerocopy-derive/src/lib.rs +++ b/zerocopy-derive/src/lib.rs @@ -326,7 +326,15 @@ fn derive_known_layout_inner(ast: &DeriveInput, _top_level: Trait) -> Result >::Type >,)* - <#trailing_field_ty as ::zerocopy::KnownLayout>::MaybeUninit + // NOTE(#2302): We wrap in `ManuallyDrop` here in case the + // type we're operating on is both generic and + // `repr(packed)`. In that case, Rust needs to know that the + // type is *either* `Sized` or has a trivial `Drop`. + // `ManuallyDrop` has a trivial `Drop`, and so satisfies + // this requirement. + ::zerocopy::util::macro_util::core_reexport::mem::ManuallyDrop< + <#trailing_field_ty as ::zerocopy::KnownLayout>::MaybeUninit + > ) where #trailing_field_ty: ::zerocopy::KnownLayout, diff --git a/zerocopy-derive/src/output_tests.rs b/zerocopy-derive/src/output_tests.rs index 1297997408..cc3f2573b9 100644 --- a/zerocopy-derive/src/output_tests.rs +++ b/zerocopy-derive/src/output_tests.rs @@ -195,12 +195,14 @@ fn test_known_layout() { ::zerocopy::util::macro_util::core_reexport::mem::MaybeUninit< as ::zerocopy::util::macro_util::Field<__Zerocopy_Field_0>>::Type, >, - < as ::zerocopy::util::macro_util::Field< - __Zerocopy_Field_1, - >>::Type as ::zerocopy::KnownLayout>::MaybeUninit, + ::zerocopy::util::macro_util::core_reexport::mem::ManuallyDrop< + < as ::zerocopy::util::macro_util::Field< + __Zerocopy_Field_1, + >>::Type as ::zerocopy::KnownLayout>::MaybeUninit + >, ) where { + payload: P, +} + +util_assert_impl_all!(Packet: imp::KnownLayout); From c43bbed1c48b4062ee1f9dd7371ad8b6285a6913 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Fri, 14 Feb 2025 12:07:06 -0800 Subject: [PATCH 88/96] Add `Src: FromBytes` in `try_transmute_mut!`, `Self: IntoBytes` to `TryFromBytes::try_mut*` (#2343) * Enforce `Src: FromBytes` in `try_transmute_mut!` (#2229) Ensures that the source reference remains valid after the transmuted (and possibly mutated) destination is dropped. Makes progress on #2226 gherrit-pr-id: I425e7d5103cb3b2a9e7107bf9df0743dca2e08cb * Add `Self: IntoBytes` bound to `TryFromBytes::try_mut*` Consider that `MaybeUninit` is `TryFromBytes`. If a `&mut [u8]` is cast into a `&mut MaybeUninit`, then uninit bytes are written, the shadowed `&mut [u8]`'s referent will no longer be valid. Makes progress towards #2226 and #1866. gherrit-pr-id: Ib233c4d0643e0690c53a37a08d9845e5fe43249c --------- Co-authored-by: Jack Wrenn Co-authored-by: Jack Wrenn --- src/impls.rs | 50 +++++++- src/lib.rs | 86 +++++++------- src/macros.rs | 22 ++-- src/util/macro_util.rs | 8 +- ..._transmute_mut-dst-not-tryfrombytes.stderr | 25 +++- .../try_transmute_mut-src-not-frombytes.rs | 1 + ...try_transmute_mut-src-not-frombytes.stderr | 100 ++++++++++++++++ ...try_transmute_mut-src-not-intobytes.stderr | 103 +++++++++++++--- ..._transmute_mut-dst-not-tryfrombytes.stderr | 29 ++++- .../try_transmute_mut-src-not-frombytes.rs | 24 ++++ ...try_transmute_mut-src-not-frombytes.stderr | 104 +++++++++++++++++ .../try_transmute_mut-src-not-intobytes.rs | 16 ++- ...try_transmute_mut-src-not-intobytes.stderr | 110 +++++++++++++++--- ..._transmute_mut-dst-not-tryfrombytes.stderr | 29 ++++- .../try_transmute_mut-src-not-frombytes.rs | 1 + ...try_transmute_mut-src-not-frombytes.stderr | 104 +++++++++++++++++ ...try_transmute_mut-src-not-intobytes.stderr | 110 +++++++++++++++--- 17 files changed, 806 insertions(+), 116 deletions(-) create mode 120000 tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs create mode 100644 tests/ui-msrv/try_transmute_mut-src-not-frombytes.stderr create mode 100644 tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs create mode 100644 tests/ui-nightly/try_transmute_mut-src-not-frombytes.stderr create mode 120000 tests/ui-stable/try_transmute_mut-src-not-frombytes.rs create mode 100644 tests/ui-stable/try_transmute_mut-src-not-frombytes.stderr diff --git a/src/impls.rs b/src/impls.rs index a79b82e7d7..c5b8694732 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -1164,6 +1164,24 @@ mod tests { } } + pub(super) trait TestTryFromMut { + #[allow(clippy::needless_lifetimes)] + fn test_try_from_mut<'bytes>( + &self, + bytes: &'bytes mut [u8], + ) -> Option>; + } + + impl TestTryFromMut for AutorefWrapper { + #[allow(clippy::needless_lifetimes)] + fn test_try_from_mut<'bytes>( + &self, + bytes: &'bytes mut [u8], + ) -> Option> { + Some(T::try_mut_from_bytes(bytes).ok()) + } + } + pub(super) trait TestTryReadFrom { fn test_try_read_from(&self, bytes: &[u8]) -> Option>; } @@ -1255,6 +1273,25 @@ mod tests { None } + #[allow(clippy::needless_lifetimes)] + fn test_try_from_mut<'bytes>(&mut self, _bytes: &'bytes mut [u8]) -> Option> { + assert_on_allowlist!( + test_try_from_mut($ty): + Option>>, + Option<&'static UnsafeCell>, + Option<&'static mut UnsafeCell>, + Option>>, + Option, + Option, + Option, + Option, + *const NotZerocopy, + *mut NotZerocopy + ); + + None + } + fn test_try_read_from(&mut self, _bytes: &[u8]) -> Option> { assert_on_allowlist!( test_try_read_from($ty): @@ -1363,8 +1400,10 @@ mod tests { let bytes_mut = &mut vec.as_mut_slice()[offset..offset+size]; bytes_mut.copy_from_slice(bytes); - let res = <$ty as TryFromBytes>::try_mut_from_bytes(bytes_mut); - assert!(res.is_ok(), "{}::try_mut_from_bytes({:?}): got `Err`, expected `Ok`", stringify!($ty), val); + let res = ww.test_try_from_mut(bytes_mut); + if let Some(res) = res { + assert!(res.is_some(), "{}::try_mut_from_bytes({:?}): got `None`, expected `Some`", stringify!($ty), val); + } } let res = bytes.and_then(|bytes| ww.test_try_read_from(bytes)); @@ -1384,8 +1423,11 @@ mod tests { assert!(res.is_none(), "{}::try_ref_from_bytes({:?}): got Some, expected None", stringify!($ty), c); } - let res = <$ty as TryFromBytes>::try_mut_from_bytes(c); - assert!(res.is_err(), "{}::try_mut_from_bytes({:?}): got Ok, expected Err", stringify!($ty), c); + let res = w.test_try_from_mut(c); + if let Some(res) = res { + assert!(res.is_none(), "{}::try_mut_from_bytes({:?}): got Some, expected None", stringify!($ty), c); + } + let res = w.test_try_read_from(c); if let Some(res) = res { diff --git a/src/lib.rs b/src/lib.rs index b6c7876730..b97393f765 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1713,8 +1713,8 @@ pub unsafe trait TryFromBytes { /// use zerocopy::*; /// # use zerocopy_derive::*; /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: [u8; 2], /// trailing_dst: [()], @@ -1731,17 +1731,17 @@ pub unsafe trait TryFromBytes { /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C)] /// struct C0C0(C0, C0); /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, @@ -1769,7 +1769,7 @@ pub unsafe trait TryFromBytes { #[inline] fn try_mut_from_bytes(bytes: &mut [u8]) -> Result<&mut Self, TryCastError<&mut [u8], Self>> where - Self: KnownLayout, + Self: KnownLayout + IntoBytes, { static_assert_dst_is_not_zst!(Self); match Ptr::from_mut(bytes).try_cast_into_no_leftover::(None) { @@ -1821,8 +1821,8 @@ pub unsafe trait TryFromBytes { /// use zerocopy::*; /// # use zerocopy_derive::*; /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: [u8; 2], /// trailing_dst: [()], @@ -1839,17 +1839,17 @@ pub unsafe trait TryFromBytes { /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C)] /// struct C0C0(C0, C0); /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, @@ -1882,7 +1882,7 @@ pub unsafe trait TryFromBytes { source: &mut [u8], ) -> Result<(&mut Self, &mut [u8]), TryCastError<&mut [u8], Self>> where - Self: KnownLayout, + Self: KnownLayout + IntoBytes, { static_assert_dst_is_not_zst!(Self); try_mut_from_prefix_suffix(source, CastType::Prefix, None) @@ -1916,8 +1916,8 @@ pub unsafe trait TryFromBytes { /// use zerocopy::*; /// # use zerocopy_derive::*; /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: u16, /// trailing_dst: [()], @@ -1934,17 +1934,17 @@ pub unsafe trait TryFromBytes { /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C)] /// struct C0C0(C0, C0); /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, @@ -1977,7 +1977,7 @@ pub unsafe trait TryFromBytes { source: &mut [u8], ) -> Result<(&mut [u8], &mut Self), TryCastError<&mut [u8], Self>> where - Self: KnownLayout, + Self: KnownLayout + IntoBytes, { static_assert_dst_is_not_zst!(Self); try_mut_from_prefix_suffix(source, CastType::Suffix, None).map(swap) @@ -2286,17 +2286,17 @@ pub unsafe trait TryFromBytes { /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C)] /// struct C0C0(C0, C0); /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, @@ -2330,8 +2330,8 @@ pub unsafe trait TryFromBytes { /// use zerocopy::*; /// # use zerocopy_derive::*; /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: NonZeroU16, /// trailing_dst: [()], @@ -2351,7 +2351,7 @@ pub unsafe trait TryFromBytes { count: usize, ) -> Result<&mut Self, TryCastError<&mut [u8], Self>> where - Self: KnownLayout, + Self: KnownLayout + IntoBytes, { match Ptr::from_mut(source).try_cast_into_no_leftover::(Some(count)) { @@ -2397,17 +2397,17 @@ pub unsafe trait TryFromBytes { /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C)] /// struct C0C0(C0, C0); /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, @@ -2443,8 +2443,8 @@ pub unsafe trait TryFromBytes { /// use zerocopy::*; /// # use zerocopy_derive::*; /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: NonZeroU16, /// trailing_dst: [()], @@ -2464,7 +2464,7 @@ pub unsafe trait TryFromBytes { count: usize, ) -> Result<(&mut Self, &mut [u8]), TryCastError<&mut [u8], Self>> where - Self: KnownLayout, + Self: KnownLayout + IntoBytes, { try_mut_from_prefix_suffix(source, CastType::Prefix, Some(count)) } @@ -2492,17 +2492,17 @@ pub unsafe trait TryFromBytes { /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. - /// #[derive(TryFromBytes, KnownLayout)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C)] /// struct C0C0(C0, C0); /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, @@ -2538,8 +2538,8 @@ pub unsafe trait TryFromBytes { /// use zerocopy::*; /// # use zerocopy_derive::*; /// - /// #[derive(TryFromBytes, KnownLayout)] - /// #[repr(C)] + /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] + /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: NonZeroU16, /// trailing_dst: [()], @@ -2559,7 +2559,7 @@ pub unsafe trait TryFromBytes { count: usize, ) -> Result<(&mut [u8], &mut Self), TryCastError<&mut [u8], Self>> where - Self: KnownLayout, + Self: KnownLayout + IntoBytes, { try_mut_from_prefix_suffix(source, CastType::Suffix, Some(count)).map(swap) } @@ -2771,7 +2771,7 @@ fn try_ref_from_prefix_suffix( +fn try_mut_from_prefix_suffix( candidate: &mut [u8], cast_type: CastType, meta: Option, diff --git a/src/macros.rs b/src/macros.rs index d1d32c81b4..51200bf54e 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -249,8 +249,8 @@ macro_rules! transmute_ref { /// const fn transmute_mut<'src, 'dst, Src, Dst>(src: &'src mut Src) -> &'dst mut Dst /// where /// 'src: 'dst, -/// Src: FromBytes + IntoBytes + Immutable, -/// Dst: FromBytes + IntoBytes + Immutable, +/// Src: FromBytes + IntoBytes, +/// Dst: FromBytes + IntoBytes, /// size_of::() == size_of::(), /// align_of::() >= align_of::(), /// { @@ -325,9 +325,9 @@ macro_rules! transmute_mut { #[allow(unused, clippy::diverging_sub_expression)] if false { // This branch, though never taken, ensures that the type of `e` is - // `&mut T` where `T: 't + Sized + FromBytes + IntoBytes + Immutable` - // and that the type of this macro expression is `&mut U` where `U: - // 'u + Sized + FromBytes + IntoBytes + Immutable`. + // `&mut T` where `T: 't + Sized + FromBytes + IntoBytes` and that + // the type of this macro expression is `&mut U` where `U: 'u + + // Sized + FromBytes + IntoBytes`. // We use immutable references here rather than mutable so that, if // this macro is used in a const context (in which, as of this @@ -577,8 +577,8 @@ macro_rules! try_transmute_ref { /// ```ignore /// fn try_transmute_mut(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> /// where -/// Src: IntoBytes, -/// Dst: TryFromBytes, +/// Src: FromBytes + IntoBytes, +/// Dst: TryFromBytes + IntoBytes, /// size_of::() == size_of::(), /// align_of::() >= align_of::(), /// { @@ -888,9 +888,9 @@ mod tests { #[test] fn test_try_transmute_mut() { // Test that memory is transmuted with `try_transmute_mut` as expected. - let array_of_bools = &mut [false, true, false, true, false, true, false, true]; + let array_of_u8s = &mut [0u8, 1, 0, 1, 0, 1, 0, 1]; let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]]; - let x: Result<&mut [[u8; 2]; 4], _> = try_transmute_mut!(array_of_bools); + let x: Result<&mut [[u8; 2]; 4], _> = try_transmute_mut!(array_of_u8s); assert_eq!(x, Ok(array_of_arrays)); let array_of_bools = &mut [false, true, false, true, false, true, false, true]; @@ -903,8 +903,8 @@ mod tests { let array_of_bools = &mut [false, true, false, true, false, true, false, true]; let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]]; { - let x: Result<&mut [[u8; 2]; 4], _> = try_transmute_mut!(array_of_bools); - assert_eq!(x, Ok(array_of_arrays)); + let x: Result<&mut [bool; 8], _> = try_transmute_mut!(array_of_arrays); + assert_eq!(x, Ok(array_of_bools)); } // Test that `try_transmute_mut!` supports decreasing alignment. diff --git a/src/util/macro_util.rs b/src/util/macro_util.rs index fcc7ca2397..1ee8a36d4e 100644 --- a/src/util/macro_util.rs +++ b/src/util/macro_util.rs @@ -26,7 +26,7 @@ use core::ptr::{self, NonNull}; use crate::{ pointer::invariant::{self, BecauseExclusive, BecauseImmutable, Invariants}, - Immutable, IntoBytes, Ptr, TryFromBytes, Unalign, ValidityError, + FromBytes, Immutable, IntoBytes, Ptr, TryFromBytes, Unalign, ValidityError, }; /// Projects the type of the field at `Index` in `Self`. @@ -538,6 +538,8 @@ fn try_cast_or_pme( ValidityError, Dst>, > where + // TODO(#2226): There should be a `Src: FromBytes` bound here, but doing so + // requires deeper surgery. Src: IntoBytes + invariant::Read, Dst: TryFromBytes + invariant::Read, I: Invariants, @@ -658,8 +660,8 @@ where #[inline(always)] pub fn try_transmute_mut(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> where - Src: IntoBytes, - Dst: TryFromBytes, + Src: FromBytes + IntoBytes, + Dst: TryFromBytes + IntoBytes, { match try_cast_or_pme::(Ptr::from_mut(src)) { Ok(ptr) => { diff --git a/tests/ui-msrv/try_transmute_mut-dst-not-tryfrombytes.stderr b/tests/ui-msrv/try_transmute_mut-dst-not-tryfrombytes.stderr index a682314f09..0879aff9e5 100644 --- a/tests/ui-msrv/try_transmute_mut-dst-not-tryfrombytes.stderr +++ b/tests/ui-msrv/try_transmute_mut-dst-not-tryfrombytes.stderr @@ -17,10 +17,33 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satis note: required by a bound in `try_transmute_mut` --> src/util/macro_util.rs | - | Dst: TryFromBytes, + | Dst: TryFromBytes + IntoBytes, | ^^^^^^^^^^^^ required by this bound in `try_transmute_mut` = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied + --> tests/ui-msrv/try_transmute_mut-dst-not-tryfrombytes.rs:20:63 + | +20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others +note: required by a bound in `try_transmute_mut` + --> src/util/macro_util.rs + | + | Dst: TryFromBytes + IntoBytes, + | ^^^^^^^^^ required by this bound in `try_transmute_mut` + = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-msrv/try_transmute_mut-dst-not-tryfrombytes.rs:20:33 | diff --git a/tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs b/tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs new file mode 120000 index 0000000000..b0e1ecf000 --- /dev/null +++ b/tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs @@ -0,0 +1 @@ +../ui-nightly/try_transmute_mut-src-not-frombytes.rs \ No newline at end of file diff --git a/tests/ui-msrv/try_transmute_mut-src-not-frombytes.stderr b/tests/ui-msrv/try_transmute_mut-src-not-frombytes.stderr new file mode 100644 index 0000000000..5d47d0122f --- /dev/null +++ b/tests/ui-msrv/try_transmute_mut-src-not-frombytes.stderr @@ -0,0 +1,100 @@ +error[E0277]: the trait bound `Src: FromBytes` is not satisfied + --> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Src` + | required by a bound introduced by this call + | + = help: the following other types implement trait `FromBytes`: + () + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + AtomicU32 + and $N others +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Src: FromBytes` is not satisfied + --> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src` + | + = help: the following other types implement trait `FromBytes`: + () + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + AtomicU32 + and $N others +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Dst: FromBytes` is not satisfied + --> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = help: the following other types implement trait `FromBytes`: + () + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + AtomicU32 + and $N others +note: required by a bound in `AssertDstIsFromBytes` + --> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied + --> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = help: the following other types implement trait `IntoBytes`: + () + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others +note: required by a bound in `AssertDstIsIntoBytes` + --> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsIntoBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-msrv/try_transmute_mut-src-not-intobytes.stderr b/tests/ui-msrv/try_transmute_mut-src-not-intobytes.stderr index ff726ab6d9..5afba09b9f 100644 --- a/tests/ui-msrv/try_transmute_mut-src-not-intobytes.stderr +++ b/tests/ui-msrv/try_transmute_mut-src-not-intobytes.stderr @@ -1,25 +1,100 @@ -error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied - --> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:19:52 +error[E0277]: the trait bound `Src: IntoBytes` is not satisfied + --> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40 | -19 | let src_not_into_bytes: Result<&mut AU16, _> = try_transmute_mut!(src); - | ^^^^^^^^^^^^^^^^^^^^^^^ - | | - | the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` - | required by a bound introduced by this call +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `Src` + | required by a bound introduced by this call | - = help: the following other types implement trait `zerocopy::IntoBytes`: + = help: the following other types implement trait `IntoBytes`: () - AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize + AtomicU16 and $N others -note: required by a bound in `try_transmute_mut` - --> src/util/macro_util.rs +note: required by a bound in `AssertSrcIsIntoBytes` + --> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40 | - | Src: IntoBytes, - | ^^^^^^^^^ required by this bound in `try_transmute_mut` - = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsIntoBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Src: IntoBytes` is not satisfied + --> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Src` + | + = help: the following other types implement trait `IntoBytes`: + () + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others +note: required by a bound in `AssertSrcIsIntoBytes` + --> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsIntoBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Dst: FromBytes` is not satisfied + --> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = help: the following other types implement trait `FromBytes`: + () + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + AtomicU32 + and $N others +note: required by a bound in `AssertDstIsFromBytes` + --> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied + --> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = help: the following other types implement trait `IntoBytes`: + () + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others +note: required by a bound in `AssertDstIsIntoBytes` + --> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsIntoBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-nightly/try_transmute_mut-dst-not-tryfrombytes.stderr b/tests/ui-nightly/try_transmute_mut-dst-not-tryfrombytes.stderr index ae0d3114af..29b392ef80 100644 --- a/tests/ui-nightly/try_transmute_mut-dst-not-tryfrombytes.stderr +++ b/tests/ui-nightly/try_transmute_mut-dst-not-tryfrombytes.stderr @@ -44,10 +44,37 @@ note: required by a bound in `try_transmute_mut` | pub fn try_transmute_mut(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> | ----------------- required by a bound in this function ... - | Dst: TryFromBytes, + | Dst: TryFromBytes + IntoBytes, | ^^^^^^^^^^^^ required by this bound in `try_transmute_mut` = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied + --> tests/ui-nightly/try_transmute_mut-dst-not-tryfrombytes.rs:20:63 + | +20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | + = note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy` + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others +note: required by a bound in `try_transmute_mut` + --> src/util/macro_util.rs + | + | pub fn try_transmute_mut(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> + | ----------------- required by a bound in this function +... + | Dst: TryFromBytes + IntoBytes, + | ^^^^^^^^^ required by this bound in `try_transmute_mut` + = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-nightly/try_transmute_mut-dst-not-tryfrombytes.rs:20:63 | diff --git a/tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs b/tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs new file mode 100644 index 0000000000..12b2e0d328 --- /dev/null +++ b/tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs @@ -0,0 +1,24 @@ +// Copyright 2024 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +extern crate zerocopy; + +use zerocopy::transmute_mut; + +#[derive(zerocopy::IntoBytes)] +#[repr(C)] +struct Src; + +#[derive(zerocopy::TryFromBytes)] +#[repr(C)] +struct Dst; + +fn main() { + // `try_transmute_mut` requires that the source type implements `FromBytes` + let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); +} diff --git a/tests/ui-nightly/try_transmute_mut-src-not-frombytes.stderr b/tests/ui-nightly/try_transmute_mut-src-not-frombytes.stderr new file mode 100644 index 0000000000..5a55338881 --- /dev/null +++ b/tests/ui-nightly/try_transmute_mut-src-not-frombytes.stderr @@ -0,0 +1,104 @@ +error[E0277]: the trait bound `Src: FromBytes` is not satisfied + --> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Src` + | required by a bound introduced by this call + | + = note: Consider adding `#[derive(FromBytes)]` to `Src` + = help: the following other types implement trait `FromBytes`: + () + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + AtomicU32 + and $N others +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Src: FromBytes` is not satisfied + --> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src` + | + = note: Consider adding `#[derive(FromBytes)]` to `Src` + = help: the following other types implement trait `FromBytes`: + () + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + AtomicU32 + and $N others +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Dst: FromBytes` is not satisfied + --> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = note: Consider adding `#[derive(FromBytes)]` to `Dst` + = help: the following other types implement trait `FromBytes`: + () + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + AtomicU32 + and $N others +note: required by a bound in `AssertDstIsFromBytes` + --> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied + --> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = note: Consider adding `#[derive(IntoBytes)]` to `Dst` + = help: the following other types implement trait `IntoBytes`: + () + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others +note: required by a bound in `AssertDstIsIntoBytes` + --> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsIntoBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs b/tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs index 1987bf15b2..fa3b7032d0 100644 --- a/tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs +++ b/tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs @@ -6,15 +6,19 @@ // This file may not be copied, modified, or distributed except according to // those terms. -include!("../../zerocopy-derive/tests/include.rs"); - extern crate zerocopy; -use util::{NotZerocopy, AU16}; -use zerocopy::try_transmute_mut; +use zerocopy::transmute_mut; + +#[derive(zerocopy::FromBytes)] +#[repr(C)] +struct Src; + +#[derive(zerocopy::TryFromBytes)] +#[repr(C)] +struct Dst; fn main() { // `try_transmute_mut` requires that the source type implements `IntoBytes` - let src = &mut NotZerocopy(AU16(0)); - let src_not_into_bytes: Result<&mut AU16, _> = try_transmute_mut!(src); + let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); } diff --git a/tests/ui-nightly/try_transmute_mut-src-not-intobytes.stderr b/tests/ui-nightly/try_transmute_mut-src-not-intobytes.stderr index 44b7e66233..66868266d2 100644 --- a/tests/ui-nightly/try_transmute_mut-src-not-intobytes.stderr +++ b/tests/ui-nightly/try_transmute_mut-src-not-intobytes.stderr @@ -1,26 +1,104 @@ -error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied - --> tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs:19:52 +error[E0277]: the trait bound `Src: IntoBytes` is not satisfied + --> tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs:23:40 | -19 | let src_not_into_bytes: Result<&mut AU16, _> = try_transmute_mut!(src); - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `Src` + | required by a bound introduced by this call | - = note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy` - = help: the following other types implement trait `zerocopy::IntoBytes`: + = note: Consider adding `#[derive(IntoBytes)]` to `Src` + = help: the following other types implement trait `IntoBytes`: () - AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize + AtomicU16 and $N others -note: required by a bound in `try_transmute_mut` - --> src/util/macro_util.rs - | - | pub fn try_transmute_mut(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> - | ----------------- required by a bound in this function - | where - | Src: IntoBytes, - | ^^^^^^^^^ required by this bound in `try_transmute_mut` - = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +note: required by a bound in `AssertSrcIsIntoBytes` + --> tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsIntoBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Src: IntoBytes` is not satisfied + --> tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Src` + | + = note: Consider adding `#[derive(IntoBytes)]` to `Src` + = help: the following other types implement trait `IntoBytes`: + () + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others +note: required by a bound in `AssertSrcIsIntoBytes` + --> tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsIntoBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Dst: FromBytes` is not satisfied + --> tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = note: Consider adding `#[derive(FromBytes)]` to `Dst` + = help: the following other types implement trait `FromBytes`: + () + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + AtomicU32 + and $N others +note: required by a bound in `AssertDstIsFromBytes` + --> tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied + --> tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = note: Consider adding `#[derive(IntoBytes)]` to `Dst` + = help: the following other types implement trait `IntoBytes`: + () + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others +note: required by a bound in `AssertDstIsIntoBytes` + --> tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsIntoBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-stable/try_transmute_mut-dst-not-tryfrombytes.stderr b/tests/ui-stable/try_transmute_mut-dst-not-tryfrombytes.stderr index 7f608de647..0fc9f2b51e 100644 --- a/tests/ui-stable/try_transmute_mut-dst-not-tryfrombytes.stderr +++ b/tests/ui-stable/try_transmute_mut-dst-not-tryfrombytes.stderr @@ -44,10 +44,37 @@ note: required by a bound in `try_transmute_mut` | pub fn try_transmute_mut(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> | ----------------- required by a bound in this function ... - | Dst: TryFromBytes, + | Dst: TryFromBytes + IntoBytes, | ^^^^^^^^^^^^ required by this bound in `try_transmute_mut` = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied + --> tests/ui-stable/try_transmute_mut-dst-not-tryfrombytes.rs:20:63 + | +20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` + | + = note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy` + = help: the following other types implement trait `zerocopy::IntoBytes`: + () + AU16 + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + and $N others +note: required by a bound in `try_transmute_mut` + --> src/util/macro_util.rs + | + | pub fn try_transmute_mut(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> + | ----------------- required by a bound in this function +... + | Dst: TryFromBytes + IntoBytes, + | ^^^^^^^^^ required by this bound in `try_transmute_mut` + = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-stable/try_transmute_mut-dst-not-tryfrombytes.rs:20:63 | diff --git a/tests/ui-stable/try_transmute_mut-src-not-frombytes.rs b/tests/ui-stable/try_transmute_mut-src-not-frombytes.rs new file mode 120000 index 0000000000..b0e1ecf000 --- /dev/null +++ b/tests/ui-stable/try_transmute_mut-src-not-frombytes.rs @@ -0,0 +1 @@ +../ui-nightly/try_transmute_mut-src-not-frombytes.rs \ No newline at end of file diff --git a/tests/ui-stable/try_transmute_mut-src-not-frombytes.stderr b/tests/ui-stable/try_transmute_mut-src-not-frombytes.stderr new file mode 100644 index 0000000000..9c60ac19b3 --- /dev/null +++ b/tests/ui-stable/try_transmute_mut-src-not-frombytes.stderr @@ -0,0 +1,104 @@ +error[E0277]: the trait bound `Src: FromBytes` is not satisfied + --> tests/ui-stable/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Src` + | required by a bound introduced by this call + | + = note: Consider adding `#[derive(FromBytes)]` to `Src` + = help: the following other types implement trait `FromBytes`: + () + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + AtomicU32 + and $N others +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-stable/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Src: FromBytes` is not satisfied + --> tests/ui-stable/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src` + | + = note: Consider adding `#[derive(FromBytes)]` to `Src` + = help: the following other types implement trait `FromBytes`: + () + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + AtomicU32 + and $N others +note: required by a bound in `AssertSrcIsFromBytes` + --> tests/ui-stable/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Dst: FromBytes` is not satisfied + --> tests/ui-stable/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = note: Consider adding `#[derive(FromBytes)]` to `Dst` + = help: the following other types implement trait `FromBytes`: + () + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + AtomicU32 + and $N others +note: required by a bound in `AssertDstIsFromBytes` + --> tests/ui-stable/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied + --> tests/ui-stable/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = note: Consider adding `#[derive(IntoBytes)]` to `Dst` + = help: the following other types implement trait `IntoBytes`: + () + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others +note: required by a bound in `AssertDstIsIntoBytes` + --> tests/ui-stable/try_transmute_mut-src-not-frombytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsIntoBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-stable/try_transmute_mut-src-not-intobytes.stderr b/tests/ui-stable/try_transmute_mut-src-not-intobytes.stderr index a5185e12ef..371917bbbb 100644 --- a/tests/ui-stable/try_transmute_mut-src-not-intobytes.stderr +++ b/tests/ui-stable/try_transmute_mut-src-not-intobytes.stderr @@ -1,26 +1,104 @@ -error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied - --> tests/ui-stable/try_transmute_mut-src-not-intobytes.rs:19:52 +error[E0277]: the trait bound `Src: IntoBytes` is not satisfied + --> tests/ui-stable/try_transmute_mut-src-not-intobytes.rs:23:40 | -19 | let src_not_into_bytes: Result<&mut AU16, _> = try_transmute_mut!(src); - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `Src` + | required by a bound introduced by this call | - = note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy` - = help: the following other types implement trait `zerocopy::IntoBytes`: + = note: Consider adding `#[derive(IntoBytes)]` to `Src` + = help: the following other types implement trait `IntoBytes`: () - AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize + AtomicU16 and $N others -note: required by a bound in `try_transmute_mut` - --> src/util/macro_util.rs - | - | pub fn try_transmute_mut(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> - | ----------------- required by a bound in this function - | where - | Src: IntoBytes, - | ^^^^^^^^^ required by this bound in `try_transmute_mut` - = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +note: required by a bound in `AssertSrcIsIntoBytes` + --> tests/ui-stable/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsIntoBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Src: IntoBytes` is not satisfied + --> tests/ui-stable/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Src` + | + = note: Consider adding `#[derive(IntoBytes)]` to `Src` + = help: the following other types implement trait `IntoBytes`: + () + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others +note: required by a bound in `AssertSrcIsIntoBytes` + --> tests/ui-stable/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsIntoBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Dst: FromBytes` is not satisfied + --> tests/ui-stable/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `FromBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = note: Consider adding `#[derive(FromBytes)]` to `Dst` + = help: the following other types implement trait `FromBytes`: + () + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + AtomicU32 + and $N others +note: required by a bound in `AssertDstIsFromBytes` + --> tests/ui-stable/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied + --> tests/ui-stable/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `IntoBytes` is not implemented for `Dst` + | required by a bound introduced by this call + | + = note: Consider adding `#[derive(IntoBytes)]` to `Dst` + = help: the following other types implement trait `IntoBytes`: + () + AtomicBool + AtomicI16 + AtomicI32 + AtomicI64 + AtomicI8 + AtomicIsize + AtomicU16 + and $N others +note: required by a bound in `AssertDstIsIntoBytes` + --> tests/ui-stable/try_transmute_mut-src-not-intobytes.rs:23:40 + | +23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsIntoBytes` + = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) From 28b55b9c438e8fc6e8a76833373c75a981a0537d Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Mon, 17 Feb 2025 13:34:58 -0800 Subject: [PATCH 89/96] [pointer] Store validity in the referent type (#2334) Previously, validity was stored as part of the `I: Invariants` type parameter on a `Ptr`. In this commit, we migrate the validity to being stored as the `V` in `Ptr`; `I` now only stores aliasing and alignment. Bit validity is subtle, in that the pair of referent type and validity invariant define a set of bit patterns which may appear in the `Ptr`'s referent. By encoding the validity in the referent type instead of in the `I` parameter, we ensure that the validity of the referent is captured entirely by a single type parameter rather than by a pair of two separate type parameters. This makes future changes (e.g. #1359) easier to model. This idea was originally proposed in https://github.com/google/zerocopy/issues/1866#issuecomment-2654625725 Makes progress on #1866 gherrit-pr-id: Ia73ca4e5dfb3b20f71ed72ffda24dd7450c427ba --- src/pointer/invariant.rs | 152 +++++++------ src/pointer/mod.rs | 8 +- src/pointer/ptr.rs | 470 ++++++++++++++++++++------------------- src/util/macro_util.rs | 12 +- src/util/macros.rs | 8 +- src/util/mod.rs | 46 ++-- 6 files changed, 370 insertions(+), 326 deletions(-) diff --git a/src/pointer/invariant.rs b/src/pointer/invariant.rs index 42c9ca63bc..c0d0cd746e 100644 --- a/src/pointer/invariant.rs +++ b/src/pointer/invariant.rs @@ -10,48 +10,42 @@ //! The parameterized invariants of a [`Ptr`][super::Ptr]. //! -//! Invariants are encoded as ([`Aliasing`], [`Alignment`], [`Validity`]) -//! triples implementing the [`Invariants`] trait. +//! A `Ptr` has the following invariants: +//! - [`V: Validity`][validity-trait] encodes the bit validity of `Ptr`'s +//! referent, which is of type [`V::Inner`][validity-inner] +//! - [`I: Invariants`][invariants-trait], where +//! [`I::Aliasing`][invariants-aliasing] and +//! [`I::Alignment`][invariants-alignment] encode the `Ptr`'s aliasing and +//! alignment invariants respectively +//! +//! [validity-trait]: Validity +//! [validity-inner]: Validity::Inner +//! [invariants-trait]: Invariants +//! [invariants-aliasing]: Invariants::Aliasing +//! [invariants-alignment]: Invariants::Alignment + +use core::marker::PhantomData; -/// The invariants of a [`Ptr`][super::Ptr]. +/// The aliasing and alignment invariants of a [`Ptr`][super::Ptr]. pub trait Invariants: Sealed { type Aliasing: Aliasing; type Alignment: Alignment; - type Validity: Validity; /// Invariants identical to `Self` except with a different aliasing /// invariant. - type WithAliasing: Invariants< - Aliasing = A, - Alignment = Self::Alignment, - Validity = Self::Validity, - >; + type WithAliasing: Invariants; /// Invariants identical to `Self` except with a different alignment /// invariant. - type WithAlignment: Invariants< - Aliasing = Self::Aliasing, - Alignment = A, - Validity = Self::Validity, - >; - - /// Invariants identical to `Self` except with a different validity - /// invariant. - type WithValidity: Invariants< - Aliasing = Self::Aliasing, - Alignment = Self::Alignment, - Validity = V, - >; + type WithAlignment: Invariants; } -impl Invariants for (A, AA, V) { +impl Invariants for (A, AA) { type Aliasing = A; type Alignment = AA; - type Validity = V; - type WithAliasing = (AB, AA, V); - type WithAlignment = (A, AB, V); - type WithValidity = (A, AA, VB); + type WithAliasing = (AB, AA); + type WithAlignment = (A, AB); } /// The aliasing invariant of a [`Ptr`][super::Ptr]. @@ -79,7 +73,24 @@ pub trait Alignment: Sealed { } /// The validity invariant of a [`Ptr`][super::Ptr]. +/// +/// A `V: Validity` defines both the referent type of a `Ptr` +/// ([`V::Inner`](Validity::Inner)) and the bit validity of the referent value. +/// Bit validity specifies a set, `S`, of possible values which may exist at the +/// `Ptr`'s referent. Code operating on a `Ptr` may assume that bit validity +/// holds - namely, that it will only observe referent values in `S`. It must +/// also uphold bit validity - namely, it must only write values in `S` to the +/// referent. +/// +/// The specific definition of `S` for a given validity type (i.e., `V: +/// Validity`) is documented on that type. +/// +/// The available validities are [`Uninit`], [`AsInitialized`], [`Initialized`], +/// and [`Valid`]. pub trait Validity: Sealed { + type Inner: ?Sized; + type WithInner: Validity; + #[doc(hidden)] type MappedTo: Validity; } @@ -98,8 +109,16 @@ pub enum Unknown {} impl Alignment for Unknown { type MappedTo = M::FromUnknown; } -impl Validity for Unknown { - type MappedTo = M::FromUnknown; + +/// A validity which permits arbitrary bytes - including uninitialized bytes - +/// at any byte offset. +pub struct Uninit(PhantomData); + +impl Validity for Uninit { + type Inner = T; + type WithInner = Uninit; + + type MappedTo = M::FromUninit; } /// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a T`. @@ -138,11 +157,11 @@ impl Alignment for Aligned { /// The byte ranges initialized in `T` are also initialized in the referent. /// -/// Formally: uninitialized bytes may only be present in `Ptr`'s referent -/// where they are guaranteed to be present in `T`. This is a dynamic property: -/// if, at a particular byte offset, a valid enum discriminant is set, the -/// subsequent bytes may only have uninitialized bytes as specificed by the -/// corresponding enum. +/// Formally: uninitialized bytes may only be present in +/// `Ptr>`'s referent where they are guaranteed to be present +/// in `T`. This is a dynamic property: if, at a particular byte offset, a valid +/// enum discriminant is set, the subsequent bytes may only have uninitialized +/// bytes as specificed by the corresponding enum. /// /// Formally, given `len = size_of_val_raw(ptr)`, at every byte offset, `b`, in /// the range `[0, len)`: @@ -162,22 +181,28 @@ impl Alignment for Aligned { /// variant's bit validity (although note that the variant may contain another /// enum type, in which case the same rules apply depending on the state of /// its discriminant, and so on recursively). -pub enum AsInitialized {} -impl Validity for AsInitialized { - type MappedTo = M::FromAsInitialized; +pub struct AsInitialized(PhantomData); +impl Validity for AsInitialized { + type Inner = T; + type WithInner = AsInitialized; + type MappedTo = M::FromAsInitialized; } /// The byte ranges in the referent are fully initialized. In other words, if /// the referent is `N` bytes long, then it contains a bit-valid `[u8; N]`. -pub enum Initialized {} -impl Validity for Initialized { - type MappedTo = M::FromInitialized; +pub struct Initialized(PhantomData); +impl Validity for Initialized { + type Inner = T; + type WithInner = Initialized; + type MappedTo = M::FromInitialized; } /// The referent is bit-valid for `T`. -pub enum Valid {} -impl Validity for Valid { - type MappedTo = M::FromValid; +pub struct Valid(PhantomData); +impl Validity for Valid { + type Inner = T; + type WithInner = Valid; + type MappedTo = M::FromValid; } /// [`Ptr`](crate::Ptr) referents that permit unsynchronized read operations. @@ -224,16 +249,18 @@ mod sealed { impl Sealed for Unknown {} + impl Sealed for Uninit {} + impl Sealed for Shared {} impl Sealed for Exclusive {} impl Sealed for Aligned {} - impl Sealed for AsInitialized {} - impl Sealed for Initialized {} - impl Sealed for Valid {} + impl Sealed for AsInitialized {} + impl Sealed for Initialized {} + impl Sealed for Valid {} - impl Sealed for (A, AA, V) {} + impl Sealed for (A, AA) {} } pub use mapping::*; @@ -268,10 +295,10 @@ mod mapping { /// Mappings are used by [`Ptr`](crate::Ptr) conversion methods to preserve /// or modify invariants as required by each method's semantics. pub trait ValidityMapping { - type FromUnknown: Validity; - type FromAsInitialized: Validity; - type FromInitialized: Validity; - type FromValid: Validity; + type FromUninit: Validity; + type FromAsInitialized: Validity; + type FromInitialized: Validity; + type FromValid: Validity; } /// The application of the [`AlignmentMapping`] `M` to the [`Alignment`] `A`. @@ -280,7 +307,8 @@ mod mapping { /// The application of the [`ValidityMapping`] `M` to the [`Validity`] `A`. #[allow(type_alias_bounds)] - pub type MappedValidity = V::MappedTo; + pub type MappedValidity = + as Validity>::WithInner; impl AlignmentMapping for ((Unknown, FromUnknown), (Shared, FromAligned)) @@ -290,28 +318,28 @@ mod mapping { } impl< - FromUnknown: Validity, + FromUninit: Validity, FromAsInitialized: Validity, FromInitialized: Validity, FromValid: Validity, > ValidityMapping for ( - (Unknown, FromUnknown), + (Unknown, FromUninit), (AsInitialized, FromAsInitialized), (Initialized, FromInitialized), (Valid, FromValid), ) { - type FromUnknown = FromUnknown; - type FromAsInitialized = FromAsInitialized; - type FromInitialized = FromInitialized; - type FromValid = FromValid; + type FromUninit = FromUninit::WithInner; + type FromAsInitialized = FromAsInitialized::WithInner; + type FromInitialized = FromInitialized::WithInner; + type FromValid = FromValid::WithInner; } impl ValidityMapping for (Initialized, FromInitialized) { - type FromUnknown = Unknown; - type FromAsInitialized = Unknown; - type FromInitialized = FromInitialized; - type FromValid = Unknown; + type FromUninit = Uninit; + type FromAsInitialized = Uninit; + type FromInitialized = FromInitialized::WithInner; + type FromValid = Uninit; } } diff --git a/src/pointer/mod.rs b/src/pointer/mod.rs index 1b9bd44234..5d38a92b90 100644 --- a/src/pointer/mod.rs +++ b/src/pointer/mod.rs @@ -25,14 +25,14 @@ use crate::Unaligned; /// /// [`TryFromBytes::is_bit_valid`]: crate::TryFromBytes::is_bit_valid pub type Maybe<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Unknown> = - Ptr<'a, T, (Aliasing, Alignment, invariant::Initialized)>; + Ptr<'a, invariant::Initialized, (Aliasing, Alignment)>; /// A semi-user-facing wrapper type representing a maybe-aligned reference, for /// use in [`TryFromBytes::is_bit_valid`]. /// /// [`TryFromBytes::is_bit_valid`]: crate::TryFromBytes::is_bit_valid pub type MaybeAligned<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Unknown> = - Ptr<'a, T, (Aliasing, Alignment, invariant::Valid)>; + Ptr<'a, invariant::Valid, (Aliasing, Alignment)>; // These methods are defined on the type alias, `MaybeAligned`, so as to bring // them to the forefront of the rendered rustdoc for that type alias. @@ -77,10 +77,10 @@ where } /// Checks if the referent is zeroed. -pub(crate) fn is_zeroed(ptr: Ptr<'_, T, I>) -> bool +pub(crate) fn is_zeroed(ptr: Ptr<'_, invariant::Initialized, I>) -> bool where T: crate::Immutable + crate::KnownLayout, - I: invariant::Invariants, + I: invariant::Invariants, I::Aliasing: invariant::Reference, { ptr.as_bytes::().as_ref().iter().all(|&byte| byte == 0) diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index c134139032..90087aafdf 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -20,49 +20,49 @@ mod def { /// A raw pointer with more restrictions. /// - /// `Ptr` is similar to [`NonNull`], but it is more restrictive in the - /// following ways (note that these requirements only hold of non-zero-sized - /// referents): + /// `Ptr` where [`V: Validity`](Validity) is similar to + /// [`NonNull`], but it is more restrictive in the following ways + /// (note that these requirements only hold of non-zero-sized referents): /// - It must derive from a valid allocation. /// - It must reference a byte range which is contained inside the /// allocation from which it derives. /// - As a consequence, the byte range it references must have a size /// which does not overflow `isize`. /// - /// Depending on how `Ptr` is parameterized, it may have additional + /// Depending on how `Ptr` is parameterized, it may have additional /// invariants: + /// - `ptr` conforms to the validity invariant of [`V`](invariant::Validity) /// - `ptr` conforms to the aliasing invariant of /// [`I::Aliasing`](invariant::Aliasing). /// - `ptr` conforms to the alignment invariant of /// [`I::Alignment`](invariant::Alignment). - /// - `ptr` conforms to the validity invariant of - /// [`I::Validity`](invariant::Validity). /// /// `Ptr<'a, T>` is [covariant] in `'a` and `T`. /// /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html - pub struct Ptr<'a, T, I> + pub struct Ptr<'a, V, I> where - T: ?Sized, + V: Validity, + V::Inner: 'a, I: Invariants, { /// # Invariants /// - /// 0. `ptr` conforms to the aliasing invariant of + /// 0. `ptr`'s referent conforms to the validity invariant of + /// [`V`](invariant::Validity) + /// 1. `ptr` conforms to the aliasing invariant of /// [`I::Aliasing`](invariant::Aliasing). - /// 1. `ptr` conforms to the alignment invariant of + /// 2. `ptr` conforms to the alignment invariant of /// [`I::Alignment`](invariant::Alignment). - /// 2. `ptr` conforms to the validity invariant of - /// [`I::Validity`](invariant::Validity). // SAFETY: `PtrInner<'a, T>` is covariant over `'a` and `T`. - ptr: PtrInner<'a, T>, - _variance: PhantomData<::Variance<'a, T>>, + ptr: PtrInner<'a, V::Inner>, + _variance: PhantomData<::Variance<'a, V::Inner>>, _invariants: PhantomData, } - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, V, I> Ptr<'a, V, I> where - T: 'a + ?Sized, + V: Validity, I: Invariants, { /// Constructs a `Ptr` from a [`NonNull`]. @@ -82,13 +82,13 @@ mod def { /// address space. /// 5. If `ptr`'s referent is not zero sized, then `A` is guaranteed to /// live for at least `'a`. - /// 6. `ptr` conforms to the aliasing invariant of + /// 6. `ptr` conforms to the validity invariant of + /// [`V`](invariant::Validity). + /// 7. `ptr` conforms to the aliasing invariant of /// [`I::Aliasing`](invariant::Aliasing). - /// 7. `ptr` conforms to the alignment invariant of + /// 8. `ptr` conforms to the alignment invariant of /// [`I::Alignment`](invariant::Alignment). - /// 8. `ptr` conforms to the validity invariant of - /// [`I::Validity`](invariant::Validity). - pub(super) const unsafe fn new(ptr: NonNull) -> Ptr<'a, T, I> { + pub(super) const unsafe fn new(ptr: NonNull) -> Ptr<'a, V, I> { // SAFETY: The caller has promised (in 0 - 5) to satisfy all safety // invariants of `PtrInner::new`. let ptr = unsafe { PtrInner::new(ptr) }; @@ -103,13 +103,13 @@ mod def { /// /// The caller promises that: /// - /// 0. `ptr` conforms to the aliasing invariant of + /// 0. `ptr` conforms to the validity invariant of + /// [`V`](invariant::Validity). + /// 1. `ptr` conforms to the aliasing invariant of /// [`I::Aliasing`](invariant::Aliasing). - /// 1. `ptr` conforms to the alignment invariant of + /// 2. `ptr` conforms to the alignment invariant of /// [`I::Alignment`](invariant::Alignment). - /// 2. `ptr` conforms to the validity invariant of - /// [`I::Validity`](invariant::Validity). - pub(super) const unsafe fn from_inner(ptr: PtrInner<'a, T>) -> Ptr<'a, T, I> { + pub(super) const unsafe fn from_inner(ptr: PtrInner<'a, V::Inner>) -> Ptr<'a, V, I> { // SAFETY: The caller has promised to satisfy all safety invariants // of `Ptr`. Self { ptr, _variance: PhantomData, _invariants: PhantomData } @@ -120,7 +120,7 @@ mod def { /// Note that this method does not consume `self`. The caller should /// watch out for `unsafe` code which uses the returned value in a way /// that violates the safety invariants of `self`. - pub(crate) const fn as_inner(&self) -> PtrInner<'a, T> { + pub(crate) const fn as_inner(&self) -> PtrInner<'a, V::Inner> { self.ptr } } @@ -136,9 +136,9 @@ mod _external { /// SAFETY: Shared pointers are safely `Copy`. `Ptr`'s other invariants /// (besides aliasing) are unaffected by the number of references that exist /// to `Ptr`'s referent. - impl<'a, T, I> Copy for Ptr<'a, T, I> + impl Copy for Ptr<'_, V, I> where - T: 'a + ?Sized, + V: Validity, I: Invariants, { } @@ -146,9 +146,9 @@ mod _external { /// SAFETY: Shared pointers are safely `Clone`. `Ptr`'s other invariants /// (besides aliasing) are unaffected by the number of references that exist /// to `Ptr`'s referent. - impl<'a, T, I> Clone for Ptr<'a, T, I> + impl Clone for Ptr<'_, V, I> where - T: 'a + ?Sized, + V: Validity, I: Invariants, { #[inline] @@ -157,9 +157,9 @@ mod _external { } } - impl<'a, T, I> Debug for Ptr<'a, T, I> + impl Debug for Ptr<'_, V, I> where - T: 'a + ?Sized, + V: Validity, I: Invariants, { #[inline] @@ -175,51 +175,44 @@ mod _conversions { use crate::util::{AlignmentVariance, Covariant, TransparentWrapper, ValidityVariance}; /// `&'a T` → `Ptr<'a, T>` - impl<'a, T> Ptr<'a, T, (Shared, Aligned, Valid)> - where - T: 'a + ?Sized, - { + impl<'a, T: ?Sized> Ptr<'a, Valid, (Shared, Aligned)> { /// Constructs a `Ptr` from a shared reference. #[doc(hidden)] #[inline] pub fn from_ref(ptr: &'a T) -> Self { let inner = PtrInner::from_ref(ptr); // SAFETY: - // 0. `ptr`, by invariant on `&'a T`, conforms to the aliasing + // 0. `ptr`, by invariant on `&'a T`, conforms to the validity + // invariant of `Valid`. + // 1. `ptr`, by invariant on `&'a T`, conforms to the aliasing // invariant of `Shared`. - // 1. `ptr`, by invariant on `&'a T`, conforms to the alignment + // 2. `ptr`, by invariant on `&'a T`, conforms to the alignment // invariant of `Aligned`. - // 2. `ptr`, by invariant on `&'a T`, conforms to the validity - // invariant of `Valid`. unsafe { Self::from_inner(inner) } } } /// `&'a mut T` → `Ptr<'a, T>` - impl<'a, T> Ptr<'a, T, (Exclusive, Aligned, Valid)> - where - T: 'a + ?Sized, - { + impl<'a, T: ?Sized> Ptr<'a, Valid, (Exclusive, Aligned)> { /// Constructs a `Ptr` from an exclusive reference. #[inline] pub(crate) fn from_mut(ptr: &'a mut T) -> Self { let inner = PtrInner::from_mut(ptr); // SAFETY: - // 0. `ptr`, by invariant on `&'a mut T`, conforms to the aliasing + // 0. `ptr`, by invariant on `&'a mut T`, conforms to the validity + // invariant of `Valid`. + // 1. `ptr`, by invariant on `&'a mut T`, conforms to the aliasing // invariant of `Exclusive`. - // 1. `ptr`, by invariant on `&'a mut T`, conforms to the alignment + // 2. `ptr`, by invariant on `&'a mut T`, conforms to the alignment // invariant of `Aligned`. - // 2. `ptr`, by invariant on `&'a mut T`, conforms to the validity - // invariant of `Valid`. unsafe { Self::from_inner(inner) } } } /// `Ptr<'a, T>` → `&'a T` - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, T: ?Sized, I> Ptr<'a, Valid, I> where - T: 'a + ?Sized, - I: Invariants, + I: Invariants, I::Aliasing: Reference, { /// Converts `self` to a shared reference. @@ -247,8 +240,8 @@ mod _conversions { // This is ensured by contract on all `PtrInner`s. // // 3. The pointer must point to an initialized instance of `T`. This - // is ensured by-contract on `Ptr`, because the `I::Validity` is - // `Valid`. + // is ensured by-contract on `Ptr`, because the validity is + // `Valid`. // // 4. You must enforce Rust’s aliasing rules. This is ensured by // contract on `Ptr`, because `I::Aliasing: Reference`. Either it @@ -262,9 +255,9 @@ mod _conversions { } } - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, V, I> Ptr<'a, V, I> where - T: 'a + ?Sized, + V: Validity, I: Invariants, I::Aliasing: Reference, { @@ -276,20 +269,20 @@ mod _conversions { #[doc(hidden)] #[inline] #[allow(clippy::needless_lifetimes)] // Allows us to name the lifetime in the safety comment below. - pub fn reborrow<'b>(&'b mut self) -> Ptr<'b, T, I> + pub fn reborrow<'b>(&'b mut self) -> Ptr<'b, V, I> where 'a: 'b, { // SAFETY: The following all hold by invariant on `self`, and thus // hold of `ptr = self.as_inner()`: - // 0. SEE BELOW. - // 1. `ptr` conforms to the alignment invariant of - // [`I::Alignment`](invariant::Alignment). - // 2. `ptr` conforms to the validity invariant of - // [`I::Validity`](invariant::Validity). + // 0. `ptr` conforms to the validity invariant of + // [`V`](invariant::Validity). + // 1. SEE BELOW. + // 2. `ptr` conforms to the alignment invariant of + // [`I::Alignment`](invariant::Alignment). // - // For aliasing (6 above), since `I::Aliasing: Reference`, - // there are two cases for `I::Aliasing`: + // For aliasing, since `I::Aliasing: Reference`, there are two cases + // for `I::Aliasing`: // - For `invariant::Shared`: `'a` outlives `'b`, and so the // returned `Ptr` does not permit accessing the referent any // longer than is possible via `self`. For shared aliasing, it is @@ -310,10 +303,7 @@ mod _conversions { } /// `Ptr<'a, T>` → `&'a mut T` - impl<'a, T> Ptr<'a, T, (Exclusive, Aligned, Valid)> - where - T: 'a + ?Sized, - { + impl<'a, T: ?Sized> Ptr<'a, Valid, (Exclusive, Aligned)> { /// Converts `self` to a mutable reference. #[allow(clippy::wrong_self_convention)] pub(crate) fn as_mut(self) -> &'a mut T { @@ -335,8 +325,8 @@ mod _conversions { // This is ensured by contract on all `PtrInner`s. // // 3. The pointer must point to an initialized instance of `T`. This - // is ensured by-contract on `Ptr`, because the validity - // invariant is `Valid`. + // is ensured by-contract on `Ptr`, because the validity is + // `Valid`. // // 4. You must enforce Rust’s aliasing rules. This is ensured by // contract on `Ptr`, because the `ALIASING_INVARIANT` is @@ -349,9 +339,10 @@ mod _conversions { } /// `Ptr<'a, T = Wrapper>` → `Ptr<'a, U>` - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, V, I> Ptr<'a, V, I> where - T: 'a + TransparentWrapper + ?Sized, + V: 'a + Validity, + V::Inner: TransparentWrapper, I: Invariants, { /// Converts `self` to a transparent wrapper type into a `Ptr` to the @@ -360,11 +351,15 @@ mod _conversions { self, ) -> Ptr< 'a, - T::Inner, + <::ValidityVariance as ValidityVariance>::Applied< + V, + ::Inner, + >, ( I::Aliasing, - >::Applied, - >::Applied, + <::AlignmentVariance as AlignmentVariance>::Applied< + I::Alignment, + >, ), > { // SAFETY: @@ -377,31 +372,38 @@ mod _conversions { // byte ranges. Since `p` and the returned pointer address the // same byte range, they refer to `UnsafeCell`s at the same byte // ranges. - let c = unsafe { self.cast_unsized_unchecked(|p| T::cast_into_inner(p)) }; + let c = unsafe { self.cast_unsized_unchecked(V::Inner::cast_into_inner) }; // SAFETY: By invariant on `TransparentWrapper`, since `self` // satisfies the alignment invariant `I::Alignment`, `c` (of type // `T::Inner`) satisfies the given "applied" alignment invariant. let c = unsafe { - c.assume_alignment::<>::Applied>() + c.assume_alignment::<<::AlignmentVariance as AlignmentVariance>::Applied::>() }; // SAFETY: By invariant on `TransparentWrapper`, since `self` - // satisfies the validity invariant `I::Validity`, `c` (of type - // `T::Inner`) satisfies the given "applied" validity invariant. + // satisfies the validity invariant `V`, `c` (of type + // `V::Inner::Inner`) satisfies the given "applied" validity + // invariant. let c = unsafe { - c.assume_validity::<>::Applied>() + c.assume_validity::<<::ValidityVariance as ValidityVariance>::Applied::Inner>>() }; - c + c.unify_validity() } } /// `Ptr<'a, T, (_, _, _)>` → `Ptr<'a, Unalign, (_, Aligned, _)>` - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, V, I> Ptr<'a, V, I> where + V: Validity, I: Invariants, { /// Converts a `Ptr` an unaligned `T` into a `Ptr` to an aligned /// `Unalign`. - pub(crate) fn into_unalign(self) -> Ptr<'a, crate::Unalign, I::WithAlignment> { + pub(crate) fn into_unalign( + self, + ) -> Ptr<'a, V::WithInner>, I::WithAlignment> + where + V::Inner: Sized, + { // SAFETY: // - This cast preserves provenance. // - This cast preserves address. `Unalign` promises to have the @@ -411,11 +413,11 @@ mod _conversions { // `UnsafeCell`s at the same locations as `p`. let ptr = unsafe { #[allow(clippy::as_conversions)] - self.cast_unsized_unchecked(|p: *mut T| p as *mut crate::Unalign) + self.cast_unsized_unchecked(|p: *mut V::Inner| p as *mut crate::Unalign) }; // SAFETY: `Unalign` promises to have the same bit validity as // `T`. - let ptr = unsafe { ptr.assume_validity::() }; + let ptr = unsafe { ptr.assume_validity::() }; // SAFETY: `Unalign` promises to have alignment 1, and so it is // trivially aligned. let ptr = unsafe { ptr.assume_alignment::() }; @@ -429,9 +431,9 @@ mod _transitions { use super::*; use crate::{AlignmentError, TryFromBytes, ValidityError}; - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, V, I> Ptr<'a, V, I> where - T: 'a + ?Sized, + V: Validity, I: Invariants, { /// Returns a `Ptr` with [`Exclusive`] aliasing if `self` already has @@ -444,7 +446,7 @@ mod _transitions { #[inline] pub(crate) fn into_exclusive_or_post_monomorphization_error( self, - ) -> Ptr<'a, T, I::WithAliasing> { + ) -> Ptr<'a, V, I::WithAliasing> { // NOTE(https://github.com/rust-lang/rust/issues/131625): We do this // rather than just having `Aliasing::IS_EXCLUSIVE` have the panic // behavior because doing it that way causes rustdoc to fail while @@ -471,12 +473,15 @@ mod _transitions { unsafe { self.assume_exclusive() } } - /// Assumes that `self` satisfies the invariants `H`. + /// Assumes that `self` satisfies the invariants `W` and `H`. /// /// # Safety /// - /// The caller promises that `self` satisfies the invariants `H`. - const unsafe fn assume_invariants(self) -> Ptr<'a, T, H> { + /// The caller promises that `self` satisfies the invariants `W` and + /// `H`. + const unsafe fn assume_invariants, H: Invariants>( + self, + ) -> Ptr<'a, W, H> { // SAFETY: The caller has promised to satisfy all parameterized // invariants of `Ptr`. `Ptr`'s other invariants are satisfied // by-contract by the source `Ptr`. @@ -485,14 +490,27 @@ mod _transitions { /// Helps the type system unify two distinct invariant types which are /// actually the same. - pub(crate) const fn unify_invariants< - H: Invariants, - >( - self, - ) -> Ptr<'a, T, H> { + pub(crate) const fn unify_invariants(self) -> Ptr<'a, V, H> + where + H: Invariants, + { // SAFETY: The associated type bounds on `H` ensure that the // invariants are unchanged. - unsafe { self.assume_invariants::() } + unsafe { self.assume_invariants::() } + } + + /// Helps the type system unify two distinct validity invariants which + /// are actually the same. + pub(crate) const fn unify_validity(self) -> Ptr<'a, W, I> + where + W: Validity = V>, + { + // SAFETY: The associated type bounds on `W` ensure that the + // validity invariant is unchanged. In particular, `Inner = + // V::Inner` ensures that the target types are the same, and + // `WithInner = V` ensures that `W` and `V` are the same + // type of validity (e.g., both `Initialized`). + unsafe { self.assume_invariants::() } } /// Assumes that `self` satisfies the aliasing requirement of `A`. @@ -504,7 +522,7 @@ mod _transitions { #[inline] pub(crate) const unsafe fn assume_aliasing( self, - ) -> Ptr<'a, T, I::WithAliasing> { + ) -> Ptr<'a, V, I::WithAliasing> { // SAFETY: The caller promises that `self` satisfies the aliasing // requirements of `A`. unsafe { self.assume_invariants() } @@ -521,7 +539,7 @@ mod _transitions { #[inline] pub(crate) const unsafe fn assume_exclusive( self, - ) -> Ptr<'a, T, I::WithAliasing> { + ) -> Ptr<'a, V, I::WithAliasing> { // SAFETY: The caller promises that `self` satisfies the aliasing // requirements of `Exclusive`. unsafe { self.assume_aliasing::() } @@ -537,7 +555,7 @@ mod _transitions { #[inline] pub(crate) const unsafe fn assume_alignment( self, - ) -> Ptr<'a, T, I::WithAlignment> { + ) -> Ptr<'a, V, I::WithAlignment> { // SAFETY: The caller promises that `self`'s referent is // well-aligned for `T` if required by `A` . unsafe { self.assume_invariants() } @@ -547,12 +565,12 @@ mod _transitions { /// on success. pub(crate) fn bikeshed_try_into_aligned( self, - ) -> Result>, AlignmentError> + ) -> Result>, AlignmentError> where - T: Sized, + V::Inner: Sized, { if let Err(err) = - crate::util::validate_aligned_to::<_, T>(self.as_inner().as_non_null()) + crate::util::validate_aligned_to::<_, V::Inner>(self.as_inner().as_non_null()) { return Err(err.with_src(self)); } @@ -565,9 +583,9 @@ mod _transitions { #[inline] // TODO(#859): Reconsider the name of this method before making it // public. - pub(crate) const fn bikeshed_recall_aligned(self) -> Ptr<'a, T, I::WithAlignment> + pub(crate) const fn bikeshed_recall_aligned(self) -> Ptr<'a, V, I::WithAlignment> where - T: crate::Unaligned, + V::Inner: crate::Unaligned, { // SAFETY: The bound `T: Unaligned` ensures that `T` has no // non-trivial alignment requirement. @@ -575,18 +593,20 @@ mod _transitions { } /// Assumes that `self`'s referent conforms to the validity requirement - /// of `V`. + /// of `W`. /// /// # Safety /// /// The caller promises that `self`'s referent conforms to the validity - /// requirement of `V`. + /// requirement of `W`. #[doc(hidden)] #[must_use] #[inline] - pub const unsafe fn assume_validity(self) -> Ptr<'a, T, I::WithValidity> { + pub const unsafe fn assume_validity( + self, + ) -> Ptr<'a, W::WithInner, I> { // SAFETY: The caller promises that `self`'s referent conforms to - // the validity requirement of `V`. + // the validity requirement of `W`. unsafe { self.assume_invariants() } } @@ -599,10 +619,10 @@ mod _transitions { #[doc(hidden)] #[must_use] #[inline] - pub const unsafe fn assume_initialized(self) -> Ptr<'a, T, I::WithValidity> { + pub const unsafe fn assume_initialized(self) -> Ptr<'a, Initialized, I> { // SAFETY: The caller has promised to uphold the safety // preconditions. - unsafe { self.assume_validity::() } + unsafe { self.assume_validity::>() } } /// A shorthand for `self.assume_validity()`. @@ -614,27 +634,40 @@ mod _transitions { #[doc(hidden)] #[must_use] #[inline] - pub const unsafe fn assume_valid(self) -> Ptr<'a, T, I::WithValidity> { + pub const unsafe fn assume_valid(self) -> Ptr<'a, Valid, I> { // SAFETY: The caller has promised to uphold the safety // preconditions. - unsafe { self.assume_validity::() } + unsafe { self.assume_validity::>() } } + /// Forgets that `self`'s referent is validly-aligned for `T`. + #[doc(hidden)] + #[must_use] + #[inline] + pub const fn forget_aligned(self) -> Ptr<'a, V, I::WithAlignment> { + // SAFETY: `Unknown` is less restrictive than `Aligned`. + unsafe { self.assume_invariants() } + } + } + + impl<'a, T, I> Ptr<'a, Initialized, I> + where + T: ?Sized, + I: Invariants, + { /// Recalls that `self`'s referent is bit-valid for `T`. #[doc(hidden)] #[must_use] #[inline] // TODO(#859): Reconsider the name of this method before making it // public. - pub const fn bikeshed_recall_valid(self) -> Ptr<'a, T, I::WithValidity> + pub const fn bikeshed_recall_valid(self) -> Ptr<'a, Valid, I> where T: crate::FromBytes, - I: Invariants, { // SAFETY: The bound `T: FromBytes` ensures that any initialized - // sequence of bytes is bit-valid for `T`. `I: Invariants` ensures that all of the referent bytes - // are initialized. + // sequence of bytes is bit-valid for `T`. `V = Initialized` + // ensures that all of the referent bytes are initialized. unsafe { self.assume_valid() } } @@ -653,11 +686,10 @@ mod _transitions { #[inline] pub(crate) fn try_into_valid( mut self, - ) -> Result>, ValidityError> + ) -> Result, I>, ValidityError> where T: TryFromBytes + Read, I::Aliasing: Reference, - I: Invariants, { // This call may panic. If that happens, it doesn't cause any soundness // issues, as we have not generated any invalid state which we need to @@ -670,15 +702,6 @@ mod _transitions { Err(ValidityError::new(self)) } } - - /// Forgets that `self`'s referent is validly-aligned for `T`. - #[doc(hidden)] - #[must_use] - #[inline] - pub const fn forget_aligned(self) -> Ptr<'a, T, I::WithAlignment> { - // SAFETY: `Unknown` is less restrictive than `Aligned`. - unsafe { self.assume_invariants() } - } } } @@ -687,9 +710,9 @@ mod _casts { use super::*; use crate::{CastError, SizeError}; - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, V, I> Ptr<'a, V, I> where - T: 'a + ?Sized, + V: Validity, I: Invariants, { /// Casts to a different (unsized) target type without checking interior @@ -709,14 +732,11 @@ mod _casts { /// at ranges identical to those at which `UnsafeCell`s exist in `*p` #[doc(hidden)] #[inline] - pub unsafe fn cast_unsized_unchecked *mut U>( + pub unsafe fn cast_unsized_unchecked *mut T>( self, cast: F, - ) -> Ptr< - 'a, - U, - (I::Aliasing, Unknown, MappedValidity), - > { + ) -> Ptr<'a, MappedValidity, (I::Aliasing, Unknown)> + { let ptr = cast(self.as_inner().as_non_null().as_ptr()); // SAFETY: Caller promises that `cast` returns a pointer whose @@ -747,7 +767,14 @@ mod _casts { // space. // 5. By invariant on `self`, if `self`'s referent is not zero // sized, then `A` is guaranteed to live for at least `'a`. - // 6. `ptr` conforms to the aliasing invariant of `I::Aliasing`: + // 6. If `V = Unknown`, `AsInitialized`, or `Valid`, the output + // validity invariant is `Unknown`. `ptr` trivially conforms to + // this invariant. If `V = Initialized`, the output validity + // invariant is `Initialized`. Regardless of what subset of + // `self`'s referent is referred to by `ptr`, if all of `self`'s + // referent is initialized, then the same holds of `ptr`'s + // referent. + // 7. `ptr` conforms to the aliasing invariant of `I::Aliasing`: // - `Exclusive`: `self` is the only `Ptr` or reference which is // permitted to read or modify the referent for the lifetime // `'a`. Since we consume `self` by value, the returned pointer @@ -771,15 +798,8 @@ mod _casts { // invariant on `self`, no other code assumes that this will // not happen. // - `Inaccessible`: There are no restrictions we need to uphold. - // 7. `ptr`, trivially, conforms to the alignment invariant of + // 8. `ptr`, trivially, conforms to the alignment invariant of // `Unknown`. - // 8. If `I::Validity = Unknown`, `AsInitialized`, or `Valid`, the - // output validity invariant is `Unknown`. `ptr` trivially - // conforms to this invariant. If `I::Validity = Initialized`, - // the output validity invariant is `Initialized`. Regardless of - // what subset of `self`'s referent is referred to by `ptr`, if - // all of `self`'s referent is initialized, then the same holds - // of `ptr`'s referent. unsafe { Ptr::new(ptr) } } @@ -793,38 +813,34 @@ mod _casts { /// - `u` has the same provenance as `p` #[doc(hidden)] #[inline] - pub unsafe fn cast_unsized( + pub unsafe fn cast_unsized( self, cast: F, - ) -> Ptr< - 'a, - U, - (I::Aliasing, Unknown, MappedValidity), - > + ) -> Ptr<'a, MappedValidity, (I::Aliasing, Unknown)> where - T: Read, - U: 'a + ?Sized + Read, - F: FnOnce(*mut T) -> *mut U, + V::Inner: Read, + T: 'a + ?Sized + Read, + F: FnOnce(*mut V::Inner) -> *mut T, { - // SAFETY: Because `T` and `U` both implement `Read`, - // either: + // SAFETY: Because `T::Inner` and `W` both implement + // `Read`, either: // - `I::Aliasing` is `Exclusive` - // - `T` and `U` are both `Immutable`, in which case they trivially - // contain `UnsafeCell`s at identical locations + // - `V::Inner` and `W` are both `Immutable`, in which case they + // trivially contain `UnsafeCell`s at identical locations // // The caller promises all other safety preconditions. unsafe { self.cast_unsized_unchecked(cast) } } } - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, T, I> Ptr<'a, Initialized, I> where - T: 'a + KnownLayout + ?Sized, - I: Invariants, + T: ?Sized + KnownLayout, + I: Invariants, { /// Casts this pointer-to-initialized into a pointer-to-bytes. #[allow(clippy::wrong_self_convention)] - pub(crate) fn as_bytes(self) -> Ptr<'a, [u8], (I::Aliasing, Aligned, Valid)> + pub(crate) fn as_bytes(self) -> Ptr<'a, Valid<[u8]>, (I::Aliasing, Aligned)> where T: Read, I::Aliasing: Reference, @@ -844,7 +860,7 @@ mod _casts { // pointer's address, and `bytes` is the length of `p`, so the // returned pointer addresses the same bytes as `p` // - `slice_from_raw_parts_mut` and `.cast` both preserve provenance - let ptr: Ptr<'a, [u8], _> = unsafe { + let ptr: Ptr<'a, Initialized<[u8]>, _> = unsafe { self.cast_unsized(|p: *mut T| { #[allow(clippy::as_conversions)] core::ptr::slice_from_raw_parts_mut(p.cast::(), bytes) @@ -855,24 +871,24 @@ mod _casts { } } - impl<'a, T, I, const N: usize> Ptr<'a, [T; N], I> + impl<'a, V, T, I, const N: usize> Ptr<'a, V, I> where - T: 'a, + V: Validity, I: Invariants, { /// Casts this pointer-to-array into a slice. #[allow(clippy::wrong_self_convention)] - pub(crate) fn as_slice(self) -> Ptr<'a, [T], I> { + pub(crate) fn as_slice(self) -> Ptr<'a, V::WithInner<[T]>, I> { let slice = self.as_inner().as_slice(); // SAFETY: Note that, by post-condition on `PtrInner::as_slice`, // `slice` refers to the same byte range as `self.as_inner()`. // - // 6. Thus, `slice` conforms to the aliasing invariant of + // 6. By the above lemma, `slice` conforms to the validity invariant + // of `V` because `self` does. + // 7. Thus, `slice` conforms to the aliasing invariant of // `I::Aliasing` because `self` does. - // 7. By the above lemma, `slice` conforms to the alignment + // 8. By the above lemma, `slice` conforms to the alignment // invariant of `I::Alignment` because `self` does. - // 8. By the above lemma, `slice` conforms to the validity invariant - // of `I::Validity` because `self` does. unsafe { Ptr::from_inner(slice) } } } @@ -880,20 +896,21 @@ mod _casts { /// For caller convenience, these methods are generic over alignment /// invariant. In practice, the referent is always well-aligned, because the /// alignment of `[u8]` is 1. - impl<'a, I> Ptr<'a, [u8], I> + impl<'a, I> Ptr<'a, Valid<[u8]>, I> where - I: Invariants, + I: Invariants, { - /// Attempts to cast `self` to a `U` using the given cast type. + /// Attempts to cast `self` to a `Ptr>` using the given + /// cast type. /// - /// If `U` is a slice DST and pointer metadata (`meta`) is provided, + /// If `T` is a slice DST and pointer metadata (`meta`) is provided, /// then the cast will only succeed if it would produce an object with /// the given metadata. /// - /// Returns `None` if the resulting `U` would be invalidly-aligned, if - /// no `U` can fit in `self`, or if the provided pointer metadata - /// describes an invalid instance of `U`. On success, returns a pointer - /// to the largest-possible `U` which fits in `self`. + /// Returns `None` if the resulting `T` would be invalidly-aligned, if + /// no `T` can fit in `self`, or if the provided pointer metadata + /// describes an invalid instance of `T`. On success, returns a pointer + /// to the largest-possible `T` which fits in `self`. /// /// # Safety /// @@ -907,17 +924,17 @@ mod _casts { /// - If this is a suffix cast, `remainder` has the same address as /// `self`. #[inline(always)] - pub(crate) fn try_cast_into( + pub(crate) fn try_cast_into( self, cast_type: CastType, - meta: Option, + meta: Option, ) -> Result< - (Ptr<'a, U, (I::Aliasing, Aligned, Initialized)>, Ptr<'a, [u8], I>), - CastError, + (Ptr<'a, Initialized, (I::Aliasing, Aligned)>, Ptr<'a, Valid<[u8]>, I>), + CastError, > where I::Aliasing: Reference, - U: 'a + ?Sized + KnownLayout + Read, + T: KnownLayout + Read + ?Sized, { let (inner, remainder) = self.as_inner().try_cast_into(cast_type, meta).map_err(|err| { @@ -930,41 +947,41 @@ mod _casts { })?; // SAFETY: - // 0. Since `U: Read`, either: + // 0. By trait bound, `self` - and thus `target` - is a bit-valid + // `[u8]`. All bit-valid `[u8]`s have all of their bytes + // initialized, so `ptr` conforms to the validity invariant of + // `Initialized`. + // 1. Since `W: Read`, either: // - `I::Aliasing` is `Exclusive`, in which case both `src` and // `ptr` conform to `Exclusive` - // - `I::Aliasing` is `Shared` or `Inaccessible` and `U` is + // - `I::Aliasing` is `Shared` or `Inaccessible` and `W` is // `Immutable` (we already know that `[u8]: Immutable`). In - // this case, neither `U` nor `[u8]` permit mutation, and so + // this case, neither `W` nor `[u8]` permit mutation, and so // `Shared` aliasing is satisfied. `Inaccessible` is trivially // satisfied since it imposes no requirements. - // 1. `ptr` conforms to the alignment invariant of `Aligned` because + // 2. `ptr` conforms to the alignment invariant of `Aligned` because // it is derived from `try_cast_into`, which promises that the - // object described by `target` is validly aligned for `U`. - // 2. By trait bound, `self` - and thus `target` - is a bit-valid - // `[u8]`. All bit-valid `[u8]`s have all of their bytes - // initialized, so `ptr` conforms to the validity invariant of - // `Initialized`. + // object described by `target` is validly aligned for `W`. let res = unsafe { Ptr::from_inner(inner) }; // SAFETY: - // 0. `self` and `remainder` both have the type `[u8]`. Thus, they - // have `UnsafeCell`s at the same locations. Type casting does - // not affect aliasing. - // 1. `[u8]` has no alignment requirement. - // 2. `self` has validity `Valid` and has type `[u8]`. Since + // 0. `self` has validity `Valid` and has type `[u8]`. Since // `remainder` references a subset of `self`'s referent, it is // also bit-valid. + // 1. `self` and `remainder` both have the type `[u8]`. Thus, they + // have `UnsafeCell`s at the same locations. Type casting does + // not affect aliasing. + // 2. `[u8]` has no alignment requirement. let remainder = unsafe { Ptr::from_inner(remainder) }; Ok((res, remainder)) } - /// Attempts to cast `self` into a `U`, failing if all of the bytes of - /// `self` cannot be treated as a `U`. + /// Attempts to cast `self` into a `Ptr>`, failing if all + /// of the bytes of `self`'s referent cannot be treated as a `T`. /// /// In particular, this method fails if `self` is not validly-aligned - /// for `U` or if `self`'s size is not a valid size for `U`. + /// for `T` or if `self`'s size is not a valid size for `T`. /// /// # Safety /// @@ -972,13 +989,13 @@ mod _casts { /// references the same byte range as `self`. #[allow(unused)] #[inline(always)] - pub(crate) fn try_cast_into_no_leftover( + pub(crate) fn try_cast_into_no_leftover( self, - meta: Option, - ) -> Result, CastError> + meta: Option, + ) -> Result, (I::Aliasing, Aligned)>, CastError> where I::Aliasing: Reference, - U: 'a + ?Sized + KnownLayout + Read, + T: ?Sized + KnownLayout + Read, { match self.try_cast_into(CastType::Prefix, meta) { Ok((slf, remainder)) => { @@ -998,7 +1015,7 @@ mod _casts { // `slf`. let slf = unsafe { slf.assume_alignment::() }; let slf = slf.unify_invariants(); - Err(CastError::Size(SizeError::<_, U>::new(slf))) + Err(CastError::Size(SizeError::<_, T>::new(slf))) } } Err(err) => Err(err), @@ -1006,9 +1023,9 @@ mod _casts { } } - impl<'a, T, I> Ptr<'a, core::cell::UnsafeCell, I> + impl<'a, V, T: ?Sized, I> Ptr<'a, V, I> where - T: 'a + ?Sized, + V: Validity>, I: Invariants, { /// Converts this `Ptr` into a pointer to the underlying data. @@ -1021,7 +1038,7 @@ mod _casts { /// [`UnsafeCell::get_mut`]: core::cell::UnsafeCell::get_mut #[must_use] #[inline(always)] - pub fn get_mut(self) -> Ptr<'a, T, I> { + pub fn get_mut(self) -> Ptr<'a, V::WithInner, I> { // SAFETY: The closure uses an `as` cast, which preserves address // range and provenance. #[allow(clippy::as_conversions)] @@ -1050,7 +1067,7 @@ mod _casts { // `UnsafeCell` has the same in-memory representation as its // inner type `T`. A consequence of this guarantee is that it is // possible to convert between `T` and `UnsafeCell`. - let ptr = unsafe { ptr.assume_validity::() }; + let ptr = unsafe { ptr.assume_validity::() }; ptr.unify_invariants() } } @@ -1060,10 +1077,9 @@ mod _casts { mod _project { use super::*; - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, T: ?Sized, I> Ptr<'a, Initialized, I> where - T: 'a + ?Sized, - I: Invariants, + I: Invariants, { /// Projects a field from `self`. /// @@ -1073,10 +1089,10 @@ mod _project { /// `cast_unsized_unchecked`. #[doc(hidden)] #[inline] - pub unsafe fn project( + pub unsafe fn project( self, - projector: impl FnOnce(*mut T) -> *mut U, - ) -> Ptr<'a, U, (I::Aliasing, Unknown, Initialized)> { + projector: impl FnOnce(*mut T) -> *mut W, + ) -> Ptr<'a, Initialized, (I::Aliasing, Unknown)> { // TODO(#1122): If `cast_unsized` were able to reason that, when // casting from an `Initialized` pointer, the result is another // `Initialized` pointer, we could remove this method entirely. @@ -1087,9 +1103,9 @@ mod _project { } } - impl<'a, T, I> Ptr<'a, [T], I> + impl Ptr<'_, V, I> where - T: 'a, + V: Validity, I: Invariants, { /// The number of slice elements in the object referenced by `self`. @@ -1102,23 +1118,23 @@ mod _project { } } - impl<'a, T, I> Ptr<'a, [T], I> + impl<'a, V, T, I> Ptr<'a, V, I> where - T: 'a, + V: Validity, I: Invariants, I::Aliasing: Reference, { /// Iteratively projects the elements `Ptr` from `Ptr<[T]>`. - pub(crate) fn iter(&self) -> impl Iterator> { + pub(crate) fn iter(&self) -> impl Iterator, I>> { // SAFETY: - // 0. `elem` conforms to the aliasing invariant of `I::Aliasing` + // 0. `elem`, conditionally, conforms to the validity invariant of + // `V`. If `elem` is projected from data valid for `[T]`, `elem` + // will be valid for `T`. + // 1. `elem` conforms to the aliasing invariant of `I::Aliasing` // because projection does not impact the aliasing invariant. - // 1. `elem`, conditionally, conforms to the validity invariant of + // 2. `elem`, conditionally, conforms to the validity invariant of // `I::Alignment`. If `elem` is projected from data well-aligned // for `[T]`, `elem` will be valid for `T`. - // 2. `elem`, conditionally, conforms to the validity invariant of - // `I::Validity`. If `elem` is projected from data valid for - // `[T]`, `elem` will be valid for `T`. self.as_inner().iter().map(|elem| unsafe { Ptr::from_inner(elem) }) } } @@ -1176,7 +1192,7 @@ mod tests { // SAFETY: The bytes in `slf` must be initialized. unsafe fn validate_and_get_len( - slf: Ptr<'_, T, (Shared, Aligned, Initialized)>, + slf: Ptr<'_, Initialized, (Shared, Aligned)>, ) -> usize { let t = slf.bikeshed_recall_valid().as_ref(); diff --git a/src/util/macro_util.rs b/src/util/macro_util.rs index 1ee8a36d4e..4a7af46962 100644 --- a/src/util/macro_util.rs +++ b/src/util/macro_util.rs @@ -25,7 +25,7 @@ use core::mem::{self, ManuallyDrop}; use core::ptr::{self, NonNull}; use crate::{ - pointer::invariant::{self, BecauseExclusive, BecauseImmutable, Invariants}, + pointer::invariant::{self, BecauseExclusive, BecauseImmutable, Invariants, Valid}, FromBytes, Immutable, IntoBytes, Ptr, TryFromBytes, Unalign, ValidityError, }; @@ -532,17 +532,17 @@ pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( #[doc(hidden)] #[inline] fn try_cast_or_pme( - src: Ptr<'_, Src, I>, + src: Ptr<'_, Valid, I>, ) -> Result< - Ptr<'_, Dst, (I::Aliasing, invariant::Unknown, invariant::Valid)>, - ValidityError, Dst>, + Ptr<'_, Valid, (I::Aliasing, invariant::Unknown)>, + ValidityError, I>, Dst>, > where // TODO(#2226): There should be a `Src: FromBytes` bound here, but doing so // requires deeper surgery. Src: IntoBytes + invariant::Read, Dst: TryFromBytes + invariant::Read, - I: Invariants, + I: Invariants, I::Aliasing: invariant::Reference, { static_assert!(Src, Dst => mem::size_of::() == mem::size_of::()); @@ -576,7 +576,7 @@ where // SAFETY: `ptr` is `src`, and has the same alignment invariant. let ptr = unsafe { ptr.assume_alignment::() }; // SAFETY: `ptr` is `src` and has the same validity invariant. - let ptr = unsafe { ptr.assume_validity::() }; + let ptr = unsafe { ptr.assume_validity::() }; Err(ValidityError::new(ptr.unify_invariants())) } } diff --git a/src/util/macros.rs b/src/util/macros.rs index 67840e2875..ef12e7b1ab 100644 --- a/src/util/macros.rs +++ b/src/util/macros.rs @@ -266,13 +266,13 @@ macro_rules! impl_for_transparent_wrapper { #[allow(dead_code, clippy::missing_inline_in_public_items)] #[cfg_attr(coverage_nightly, coverage(off))] fn only_derive_is_allowed_to_implement_this_trait() { - use crate::{pointer::invariant::Invariants, util::*}; + use crate::util::*; impl_for_transparent_wrapper!(@define_is_transparent_wrapper $trait); #[cfg_attr(coverage_nightly, coverage(off))] - const fn f() { - is_transparent_wrapper::(); + const fn f<$($tyvar $(: $(? $optbound +)* $($bound +)*)?)?>() { + is_transparent_wrapper::<$ty>(); } } @@ -343,7 +343,7 @@ macro_rules! impl_for_transparent_wrapper { }; (@define_is_transparent_wrapper $trait:ident, $variance:ident) => { #[cfg_attr(coverage_nightly, coverage(off))] - const fn is_transparent_wrapper + ?Sized>() + const fn is_transparent_wrapper + ?Sized>() where W::Inner: $trait, {} diff --git a/src/util/mod.rs b/src/util/mod.rs index ad59881f96..6cf924d9db 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -22,7 +22,7 @@ use core::{ use crate::{ error::AlignmentError, - pointer::invariant::{self, Invariants}, + pointer::invariant::{self, Validity}, Unalign, }; @@ -46,12 +46,12 @@ use crate::{ /// [`T::AlignmentVariance`]: TransparentWrapper::AlignmentVariance /// [`T::ValidityVariance`]: TransparentWrapper::ValidityVariance #[doc(hidden)] -pub unsafe trait TransparentWrapper { +pub unsafe trait TransparentWrapper { type Inner: ?Sized; type UnsafeCellVariance; - type AlignmentVariance: AlignmentVariance; - type ValidityVariance: ValidityVariance; + type AlignmentVariance: AlignmentVariance; + type ValidityVariance: ValidityVariance; /// Casts a wrapper pointer to an inner pointer. /// @@ -72,38 +72,38 @@ pub unsafe trait TransparentWrapper { #[allow(unreachable_pub)] #[doc(hidden)] -pub trait AlignmentVariance { - type Applied: invariant::Alignment; +pub trait AlignmentVariance { + type Applied: invariant::Alignment; } #[allow(unreachable_pub)] #[doc(hidden)] -pub trait ValidityVariance { - type Applied: invariant::Validity; +pub trait ValidityVariance { + type Applied: invariant::Validity; } #[doc(hidden)] #[allow(missing_copy_implementations, missing_debug_implementations)] pub enum Covariant {} -impl AlignmentVariance for Covariant { - type Applied = I; +impl AlignmentVariance for Covariant { + type Applied = A; } -impl ValidityVariance for Covariant { - type Applied = I; +impl ValidityVariance for Covariant { + type Applied = V::WithInner; } #[doc(hidden)] #[allow(missing_copy_implementations, missing_debug_implementations)] pub enum Invariant {} -impl AlignmentVariance for Invariant { - type Applied = invariant::Unknown; +impl AlignmentVariance for Invariant { + type Applied = invariant::Unknown; } -impl ValidityVariance for Invariant { - type Applied = invariant::Unknown; +impl ValidityVariance for Invariant { + type Applied = invariant::Uninit; } // SAFETY: @@ -114,7 +114,7 @@ impl ValidityVariance for Invariant { // // `MaybeUninit` is guaranteed to have the same size, alignment, and ABI as // `T` -unsafe impl TransparentWrapper for MaybeUninit { +unsafe impl TransparentWrapper for MaybeUninit { type Inner = T; // SAFETY: `MaybeUninit` has `UnsafeCell`s covering the same byte ranges @@ -170,7 +170,7 @@ unsafe impl TransparentWrapper for MaybeUninit { // // `ManuallyDrop` is guaranteed to have the same layout and bit validity as // `T` -unsafe impl TransparentWrapper for ManuallyDrop { +unsafe impl TransparentWrapper for ManuallyDrop { type Inner = T; // SAFETY: Per [1], `ManuallyDrop` has `UnsafeCell`s covering the same @@ -224,7 +224,7 @@ unsafe impl TransparentWrapper for ManuallyDrop // [1] Per https://doc.rust-lang.org/1.81.0/std/num/struct.Wrapping.html#layout-1: // // `Wrapping` is guaranteed to have the same layout and ABI as `T`. -unsafe impl TransparentWrapper for Wrapping { +unsafe impl TransparentWrapper for Wrapping { type Inner = T; // SAFETY: Per [1], `Wrapping` has the same layout as `T`. Since its @@ -287,7 +287,7 @@ unsafe impl TransparentWrapper for Wrapping { // // `UnsafeCell` has the same in-memory representation as its inner type // `T`. -unsafe impl TransparentWrapper for UnsafeCell { +unsafe impl TransparentWrapper for UnsafeCell { type Inner = T; // SAFETY: Since we set this to `Invariant`, we make no safety claims. @@ -333,7 +333,7 @@ unsafe impl TransparentWrapper for UnsafeCell { // SAFETY: `Unalign` promises to have the same size as `T`. // // See inline comments for other safety justifications. -unsafe impl TransparentWrapper for Unalign { +unsafe impl TransparentWrapper for Unalign { type Inner = T; // SAFETY: `Unalign` promises to have `UnsafeCell`s covering the same @@ -385,7 +385,7 @@ macro_rules! unsafe_impl_transparent_wrapper_for_atomic { ($(#[$attr:meta])* $atomic:ty [$native:ty], $($atomics:ty [$natives:ty]),* $(,)?) => { $(#[$attr])* // SAFETY: See safety comment in next match arm. - unsafe impl crate::util::TransparentWrapper for $atomic { + unsafe impl crate::util::TransparentWrapper for $atomic { unsafe_impl_transparent_wrapper_for_atomic!(@inner $atomic [$native]); } unsafe_impl_transparent_wrapper_for_atomic!($(#[$attr])* $($atomics [$natives],)*); @@ -401,7 +401,7 @@ macro_rules! unsafe_impl_transparent_wrapper_for_atomic { // This type has the same size and bit validity as the underlying // integer type $(#[$attr])* - unsafe impl<$tyvar, I: crate::invariant::Invariants> crate::util::TransparentWrapper for $atomic { + unsafe impl<$tyvar> crate::util::TransparentWrapper for $atomic { unsafe_impl_transparent_wrapper_for_atomic!(@inner $atomic [$native]); } }; From 9322a2c366ba368bf5e21b2da595fd82ea2879ce Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Mon, 17 Feb 2025 14:13:35 -0800 Subject: [PATCH 90/96] [pointer] Remove Ptr::project method (#2339) Now that #1122 is complete in #1896, `project` is redundant. gherrit-pr-id: I15d38f2f1fffad82caa70ea6eb18dffcd6504495 --- src/pointer/ptr.rs | 26 ---------- zerocopy-derive/src/enum.rs | 2 +- zerocopy-derive/src/lib.rs | 4 +- zerocopy-derive/src/output_tests.rs | 78 ++++++++++++++--------------- 4 files changed, 42 insertions(+), 68 deletions(-) diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index 90087aafdf..d09a31a582 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -1077,32 +1077,6 @@ mod _casts { mod _project { use super::*; - impl<'a, T: ?Sized, I> Ptr<'a, Initialized, I> - where - I: Invariants, - { - /// Projects a field from `self`. - /// - /// # Safety - /// - /// `project` has the same safety preconditions as - /// `cast_unsized_unchecked`. - #[doc(hidden)] - #[inline] - pub unsafe fn project( - self, - projector: impl FnOnce(*mut T) -> *mut W, - ) -> Ptr<'a, Initialized, (I::Aliasing, Unknown)> { - // TODO(#1122): If `cast_unsized` were able to reason that, when - // casting from an `Initialized` pointer, the result is another - // `Initialized` pointer, we could remove this method entirely. - - // SAFETY: This method has the same safety preconditions as - // `cast_unsized_unchecked`. - unsafe { self.cast_unsized_unchecked(projector) } - } - } - impl Ptr<'_, V, I> where V: Validity, diff --git a/zerocopy-derive/src/enum.rs b/zerocopy-derive/src/enum.rs index 438ed5a01f..75a91895bf 100644 --- a/zerocopy-derive/src/enum.rs +++ b/zerocopy-derive/src/enum.rs @@ -349,7 +349,7 @@ pub(crate) fn derive_is_bit_valid( // subfield pointer just points to a smaller portion of the // overall struct. let variants = unsafe { - raw_enum.project(|p: *mut ___ZerocopyRawEnum #ty_generics| { + raw_enum.cast_unsized_unchecked(|p: *mut ___ZerocopyRawEnum #ty_generics| { core_reexport::ptr::addr_of_mut!((*p).variants) }) }; diff --git a/zerocopy-derive/src/lib.rs b/zerocopy-derive/src/lib.rs index 869ed6675b..4f139f1aa0 100644 --- a/zerocopy-derive/src/lib.rs +++ b/zerocopy-derive/src/lib.rs @@ -571,7 +571,7 @@ fn derive_try_from_bytes_struct( let project = |slf: *mut Self| ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).#field_names); - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; <#field_tys as ::zerocopy::TryFromBytes>::is_bit_valid(field_candidate) @@ -629,7 +629,7 @@ fn derive_try_from_bytes_union( let project = |slf: *mut Self| ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).#field_names); - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; <#field_tys as ::zerocopy::TryFromBytes>::is_bit_valid(field_candidate) diff --git a/zerocopy-derive/src/output_tests.rs b/zerocopy-derive/src/output_tests.rs index cc3f2573b9..4c8be6d2e3 100644 --- a/zerocopy-derive/src/output_tests.rs +++ b/zerocopy-derive/src/output_tests.rs @@ -591,7 +591,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).0) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -609,7 +609,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).2) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -617,7 +617,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).3) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -625,7 +625,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).4) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -633,7 +633,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).5) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; <[(X, Y); N] as ::zerocopy::TryFromBytes>::is_bit_valid(field_candidate) } && { @@ -641,7 +641,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).6) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; , @@ -685,7 +685,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).0) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -703,7 +703,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).2) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -711,7 +711,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).3) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; as ::zerocopy::TryFromBytes>::is_bit_valid( field_candidate, @@ -721,7 +721,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).4) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; , @@ -753,7 +753,7 @@ fn test_try_from_bytes_enum() { candidate.cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyRawEnum<'a, N, X, Y> }) }; let variants = unsafe { - raw_enum.project(|p: *mut ___ZerocopyRawEnum<'a, N, X, Y>| { + raw_enum.cast_unsized_unchecked(|p: *mut ___ZerocopyRawEnum<'a, N, X, Y>| { core_reexport::ptr::addr_of_mut!((*p).variants) }) }; @@ -881,7 +881,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).0) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -899,7 +899,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).2) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -907,7 +907,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).3) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -915,7 +915,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).4) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -923,7 +923,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).5) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; <[(X, Y); N] as ::zerocopy::TryFromBytes>::is_bit_valid(field_candidate) } && { @@ -931,7 +931,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).6) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; , @@ -975,7 +975,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).0) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -993,7 +993,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).2) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -1001,7 +1001,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).3) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; as ::zerocopy::TryFromBytes>::is_bit_valid( field_candidate, @@ -1011,7 +1011,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).4) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; , @@ -1043,7 +1043,7 @@ fn test_try_from_bytes_enum() { candidate.cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyRawEnum<'a, N, X, Y> }) }; let variants = unsafe { - raw_enum.project(|p: *mut ___ZerocopyRawEnum<'a, N, X, Y>| { + raw_enum.cast_unsized_unchecked(|p: *mut ___ZerocopyRawEnum<'a, N, X, Y>| { core_reexport::ptr::addr_of_mut!((*p).variants) }) }; @@ -1171,7 +1171,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).0) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -1189,7 +1189,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).2) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -1197,7 +1197,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).3) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -1205,7 +1205,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).4) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -1213,7 +1213,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).5) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; <[(X, Y); N] as ::zerocopy::TryFromBytes>::is_bit_valid(field_candidate) } && { @@ -1221,7 +1221,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).6) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; , @@ -1265,7 +1265,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).0) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -1283,7 +1283,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).2) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; ::is_bit_valid(field_candidate) } && { @@ -1291,7 +1291,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).3) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; as ::zerocopy::TryFromBytes>::is_bit_valid( field_candidate, @@ -1301,7 +1301,7 @@ fn test_try_from_bytes_enum() { let project = |slf: *mut Self| { ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).4) }; - candidate.reborrow().project(project) + candidate.reborrow().cast_unsized_unchecked(project) }; , @@ -1333,7 +1333,7 @@ fn test_try_from_bytes_enum() { candidate.cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyRawEnum<'a, N, X, Y> }) }; let variants = unsafe { - raw_enum.project(|p: *mut ___ZerocopyRawEnum<'a, N, X, Y>| { + raw_enum.cast_unsized_unchecked(|p: *mut ___ZerocopyRawEnum<'a, N, X, Y>| { core_reexport::ptr::addr_of_mut!((*p).variants) }) }; From 79ec7c4375a3ee43844a9b0fc716707859acf140 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Tue, 18 Feb 2025 08:44:56 -0800 Subject: [PATCH 91/96] [pointer] Fix Ptr[Inner] variance (#2351) Previously, `Ptr<'a, T>` and `PtrInner<'a, T>` documented themselves to be covariant in both `'a` and `T`. This was true for `PtrInner`, but not for `Ptr`, which used GATs, which are invariant. This is also not the desired variance: for `Exclusive` aliasing, the desired variance matches that of `&mut` references - namely, covariant in `'a` but invariant in `T`. This commit fixes this by making `Ptr<'a, T>` and `PtrInner<'a, T>` unconditionally covariant in `'a` and invariant in `T`. gherrit-pr-id: I29f8429d9d7b14026313f030f8dc1e895a98ad56 --- src/pointer/inner.rs | 11 +++---- src/pointer/invariant.rs | 8 ----- src/pointer/ptr.rs | 9 +++--- tests/ui-msrv/ptr-is-invariant-over-v.rs | 1 + tests/ui-msrv/ptr-is-invariant-over-v.stderr | 31 +++++++++++++++++++ tests/ui-nightly/ptr-is-invariant-over-v.rs | 20 ++++++++++++ .../ui-nightly/ptr-is-invariant-over-v.stderr | 31 +++++++++++++++++++ tests/ui-stable/ptr-is-invariant-over-v.rs | 1 + .../ui-stable/ptr-is-invariant-over-v.stderr | 31 +++++++++++++++++++ 9 files changed, 124 insertions(+), 19 deletions(-) create mode 120000 tests/ui-msrv/ptr-is-invariant-over-v.rs create mode 100644 tests/ui-msrv/ptr-is-invariant-over-v.stderr create mode 100644 tests/ui-nightly/ptr-is-invariant-over-v.rs create mode 100644 tests/ui-nightly/ptr-is-invariant-over-v.stderr create mode 120000 tests/ui-stable/ptr-is-invariant-over-v.rs create mode 100644 tests/ui-stable/ptr-is-invariant-over-v.stderr diff --git a/src/pointer/inner.rs b/src/pointer/inner.rs index 48d4e8f113..ac0938424f 100644 --- a/src/pointer/inner.rs +++ b/src/pointer/inner.rs @@ -22,7 +22,7 @@ mod _def { use super::*; /// The inner pointer stored inside a [`Ptr`][crate::Ptr]. /// - /// `Ptr<'a, T>` is [covariant] in `'a` and `T`. + /// `PtrInner<'a, T>` is [covariant] in `'a` and invariant in `T`. /// /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html pub(crate) struct PtrInner<'a, T> @@ -42,14 +42,13 @@ mod _def { /// address space. /// 5. If `ptr`'s referent is not zero sized,`A` is guaranteed to live /// for at least `'a`. - // SAFETY: `NonNull` is covariant over `T` [1]. - // - // [1]: https://doc.rust-lang.org/std/ptr/struct.NonNull.html ptr: NonNull, - // SAFETY: `&'a T` is covariant over `'a` [1]. + // SAFETY: `&'a UnsafeCell` is covariant in `'a` and invariant in `T` + // [1]. We use this construction rather than the equivalent `&mut T`, + // because our MSRV of 1.65 prohibits `&mut` types in const contexts. // // [1] https://doc.rust-lang.org/1.81.0/reference/subtyping.html#variance - _marker: PhantomData<&'a T>, + _marker: PhantomData<&'a core::cell::UnsafeCell>, } impl<'a, T: 'a + ?Sized> Copy for PtrInner<'a, T> {} diff --git a/src/pointer/invariant.rs b/src/pointer/invariant.rs index c0d0cd746e..06c2733ce2 100644 --- a/src/pointer/invariant.rs +++ b/src/pointer/invariant.rs @@ -58,12 +58,6 @@ pub trait Aliasing: Sealed { /// Is `Self` [`Exclusive`]? #[doc(hidden)] const IS_EXCLUSIVE: bool; - - /// A type which has the correct variance over `'a` and `T` for this - /// aliasing invariant. `Ptr` stores a `::Variance<'a, T>` to inherit this variance. - #[doc(hidden)] - type Variance<'a, T: 'a + ?Sized>; } /// The alignment invariant of a [`Ptr`][super::Ptr]. @@ -132,7 +126,6 @@ impl Validity for Uninit { pub enum Shared {} impl Aliasing for Shared { const IS_EXCLUSIVE: bool = false; - type Variance<'a, T: 'a + ?Sized> = &'a T; } impl Reference for Shared {} @@ -144,7 +137,6 @@ impl Reference for Shared {} pub enum Exclusive {} impl Aliasing for Exclusive { const IS_EXCLUSIVE: bool = true; - type Variance<'a, T: 'a + ?Sized> = &'a mut T; } impl Reference for Exclusive {} diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index d09a31a582..59ec627479 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -37,7 +37,7 @@ mod def { /// - `ptr` conforms to the alignment invariant of /// [`I::Alignment`](invariant::Alignment). /// - /// `Ptr<'a, T>` is [covariant] in `'a` and `T`. + /// `Ptr<'a, T>` is [covariant] in `'a` and invariant in `T`. /// /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html pub struct Ptr<'a, V, I> @@ -54,9 +54,8 @@ mod def { /// [`I::Aliasing`](invariant::Aliasing). /// 2. `ptr` conforms to the alignment invariant of /// [`I::Alignment`](invariant::Alignment). - // SAFETY: `PtrInner<'a, T>` is covariant over `'a` and `T`. + // SAFETY: `PtrInner<'a, T>` is covariant in `'a` and invariant in `T`. ptr: PtrInner<'a, V::Inner>, - _variance: PhantomData<::Variance<'a, V::Inner>>, _invariants: PhantomData, } @@ -94,7 +93,7 @@ mod def { let ptr = unsafe { PtrInner::new(ptr) }; // SAFETY: The caller has promised (in 6 - 8) to satisfy all safety // invariants of `Ptr`. - Self { ptr, _variance: PhantomData, _invariants: PhantomData } + Self { ptr, _invariants: PhantomData } } /// Constructs a new `Ptr` from a [`PtrInner`]. @@ -112,7 +111,7 @@ mod def { pub(super) const unsafe fn from_inner(ptr: PtrInner<'a, V::Inner>) -> Ptr<'a, V, I> { // SAFETY: The caller has promised to satisfy all safety invariants // of `Ptr`. - Self { ptr, _variance: PhantomData, _invariants: PhantomData } + Self { ptr, _invariants: PhantomData } } /// Converts this `Ptr` to a [`PtrInner`]. diff --git a/tests/ui-msrv/ptr-is-invariant-over-v.rs b/tests/ui-msrv/ptr-is-invariant-over-v.rs new file mode 120000 index 0000000000..d29c80df7b --- /dev/null +++ b/tests/ui-msrv/ptr-is-invariant-over-v.rs @@ -0,0 +1 @@ +../ui-nightly/ptr-is-invariant-over-v.rs \ No newline at end of file diff --git a/tests/ui-msrv/ptr-is-invariant-over-v.stderr b/tests/ui-msrv/ptr-is-invariant-over-v.stderr new file mode 100644 index 0000000000..792e45aa5e --- /dev/null +++ b/tests/ui-msrv/ptr-is-invariant-over-v.stderr @@ -0,0 +1,31 @@ +error: lifetime may not live long enough + --> tests/ui-msrv/ptr-is-invariant-over-v.rs:10:5 + | +6 | fn _when_exclusive<'big: 'small, 'small>( + | ---- ------ lifetime `'small` defined here + | | + | lifetime `'big` defined here +... +10 | _small = big; + | ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big` + | + = help: consider adding the following bound: `'small: 'big` + = note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (invariant::Exclusive, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant + = note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V` + = help: see for more information about variance + +error: lifetime may not live long enough + --> tests/ui-msrv/ptr-is-invariant-over-v.rs:17:5 + | +13 | fn _when_shared<'big: 'small, 'small>( + | ---- ------ lifetime `'small` defined here + | | + | lifetime `'big` defined here +... +17 | _small = big; + | ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big` + | + = help: consider adding the following bound: `'small: 'big` + = note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (Shared, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant + = note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V` + = help: see for more information about variance diff --git a/tests/ui-nightly/ptr-is-invariant-over-v.rs b/tests/ui-nightly/ptr-is-invariant-over-v.rs new file mode 100644 index 0000000000..cc6b6985c4 --- /dev/null +++ b/tests/ui-nightly/ptr-is-invariant-over-v.rs @@ -0,0 +1,20 @@ +use zerocopy::pointer::{ + invariant::{Aligned, Exclusive, Shared, Valid}, + Ptr, +}; + +fn _when_exclusive<'big: 'small, 'small>( + big: Ptr<'small, Valid<&'big u32>, (Exclusive, Aligned)>, + mut _small: Ptr<'small, Valid<&'small u32>, (Exclusive, Aligned)>, +) { + _small = big; +} + +fn _when_shared<'big: 'small, 'small>( + big: Ptr<'small, Valid<&'big u32>, (Shared, Aligned)>, + mut _small: Ptr<'small, Valid<&'small u32>, (Shared, Aligned)>, +) { + _small = big; +} + +fn main() {} diff --git a/tests/ui-nightly/ptr-is-invariant-over-v.stderr b/tests/ui-nightly/ptr-is-invariant-over-v.stderr new file mode 100644 index 0000000000..180e764976 --- /dev/null +++ b/tests/ui-nightly/ptr-is-invariant-over-v.stderr @@ -0,0 +1,31 @@ +error: lifetime may not live long enough + --> tests/ui-nightly/ptr-is-invariant-over-v.rs:10:5 + | +6 | fn _when_exclusive<'big: 'small, 'small>( + | ---- ------ lifetime `'small` defined here + | | + | lifetime `'big` defined here +... +10 | _small = big; + | ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big` + | + = help: consider adding the following bound: `'small: 'big` + = note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (invariant::Exclusive, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant + = note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V` + = help: see for more information about variance + +error: lifetime may not live long enough + --> tests/ui-nightly/ptr-is-invariant-over-v.rs:17:5 + | +13 | fn _when_shared<'big: 'small, 'small>( + | ---- ------ lifetime `'small` defined here + | | + | lifetime `'big` defined here +... +17 | _small = big; + | ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big` + | + = help: consider adding the following bound: `'small: 'big` + = note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (Shared, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant + = note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V` + = help: see for more information about variance diff --git a/tests/ui-stable/ptr-is-invariant-over-v.rs b/tests/ui-stable/ptr-is-invariant-over-v.rs new file mode 120000 index 0000000000..d29c80df7b --- /dev/null +++ b/tests/ui-stable/ptr-is-invariant-over-v.rs @@ -0,0 +1 @@ +../ui-nightly/ptr-is-invariant-over-v.rs \ No newline at end of file diff --git a/tests/ui-stable/ptr-is-invariant-over-v.stderr b/tests/ui-stable/ptr-is-invariant-over-v.stderr new file mode 100644 index 0000000000..ff1d040488 --- /dev/null +++ b/tests/ui-stable/ptr-is-invariant-over-v.stderr @@ -0,0 +1,31 @@ +error: lifetime may not live long enough + --> tests/ui-stable/ptr-is-invariant-over-v.rs:10:5 + | +6 | fn _when_exclusive<'big: 'small, 'small>( + | ---- ------ lifetime `'small` defined here + | | + | lifetime `'big` defined here +... +10 | _small = big; + | ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big` + | + = help: consider adding the following bound: `'small: 'big` + = note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (invariant::Exclusive, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant + = note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V` + = help: see for more information about variance + +error: lifetime may not live long enough + --> tests/ui-stable/ptr-is-invariant-over-v.rs:17:5 + | +13 | fn _when_shared<'big: 'small, 'small>( + | ---- ------ lifetime `'small` defined here + | | + | lifetime `'big` defined here +... +17 | _small = big; + | ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big` + | + = help: consider adding the following bound: `'small: 'big` + = note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (Shared, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant + = note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V` + = help: see for more information about variance From 1339ee9d6a06e7111d79685524d75d9f7a3fa169 Mon Sep 17 00:00:00 2001 From: Alyssa Haroldsen Date: Wed, 19 Feb 2025 05:26:19 -0800 Subject: [PATCH 92/96] Fix soundness of FromBytes::read_from_io (#2320) See #2319. Includes a Miri test confirming the previous unsoundness. gherrit-pr-id: Iede94c196c710c74d970c93935f1539e07446e50 --- src/lib.rs | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b97393f765..c831a91f18 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4546,9 +4546,17 @@ pub unsafe trait FromBytes: FromZeros { Self: Sized, R: io::Read, { - let mut buf = CoreMaybeUninit::::zeroed(); + // NOTE(#2319, #2320): We do `buf.zero()` separately rather than + // constructing `let buf = CoreMaybeUninit::zeroed()` because, if `Self` + // contains padding bytes, then a typed copy of `CoreMaybeUninit` + // will not necessarily preserve zeros written to those padding byte + // locations, and so `buf` could contain uninitialized bytes. + let mut buf = CoreMaybeUninit::::uninit(); + buf.zero(); + let ptr = Ptr::from_mut(&mut buf); - // SAFETY: `buf` consists entirely of initialized, zeroed bytes. + // SAFETY: After `buf.zero()`, `buf` consists entirely of initialized, + // zeroed bytes. let ptr = unsafe { ptr.assume_validity::() }; let ptr = ptr.as_bytes::(); src.read_exact(ptr.as_mut())?; @@ -5905,6 +5913,36 @@ mod tests { assert_eq!(bytes, want); } + #[test] + #[cfg(feature = "std")] + fn test_read_io_with_padding_soundness() { + // This test is designed to exhibit potential UB in + // `FromBytes::read_from_io`. (see #2319, #2320). + + // On most platforms (where `align_of::() == 2`), `WithPadding` + // will have inter-field padding between `x` and `y`. + #[derive(FromBytes)] + #[repr(C)] + struct WithPadding { + x: u8, + y: u16, + } + struct ReadsInRead; + impl std::io::Read for ReadsInRead { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + // This body branches on every byte of `buf`, ensuring that it + // exhibits UB if any byte of `buf` is uninitialized. + if buf.iter().all(|&x| x == 0) { + Ok(buf.len()) + } else { + buf.iter_mut().for_each(|x| *x = 0); + Ok(buf.len()) + } + } + } + assert!(matches!(WithPadding::read_from_io(ReadsInRead), Ok(WithPadding { x: 0, y: 0 }))); + } + #[test] #[cfg(feature = "std")] fn test_read_write_io() { From 7ed40f1115f4b35df98d60a02e3e133791209e95 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Wed, 19 Feb 2025 13:31:23 -0800 Subject: [PATCH 93/96] [release-new-crate-versions] Release on v0.8.x by default (#2362) --- .github/workflows/release-crate-version.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-crate-version.yml b/.github/workflows/release-crate-version.yml index b5a3c6aeb8..99a5a4825b 100644 --- a/.github/workflows/release-crate-version.yml +++ b/.github/workflows/release-crate-version.yml @@ -16,7 +16,7 @@ on: branch: description: 'Branch to update' required: true - default: 'main' + default: 'v0.8.x' permissions: read-all From c3aaddcbb6df7712b6b5f0d871daae6cd2772804 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Wed, 19 Feb 2025 15:51:22 -0800 Subject: [PATCH 94/96] [readme] Explain maintenance, thank contributors (#2360) (#2363) Add jswrenn as an author in `Cargo.toml` files. gherrit-pr-id: I50cc283e73af52a110de292c7fd92426fea21e26 --- Cargo.toml | 5 +++-- README.md | 8 ++++++++ src/lib.rs | 8 ++++++++ zerocopy-derive/Cargo.toml | 2 +- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8ffab557ac..f9fbb41bb9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,14 +15,15 @@ members = ["unsafe-fields", "zerocopy-derive"] [workspace.package] -# Inherited by zerocopy and unsafe-fields. +# Inherited by workspace members. rust-version = "1.65.0" +authors = ["Joshua Liebow-Feeser ", "Jack Wrenn "] [package] edition = "2021" name = "zerocopy" version = "0.9.0-alpha.0" -authors = ["Joshua Liebow-Feeser "] +authors = { workspace = true } description = "Zerocopy makes zero-cost memory manipulation effortless. We write \"unsafe\" so you don't have to." categories = ["embedded", "encoding", "no-std::no-alloc", "parsing", "rust-patterns"] keywords = ["cast", "convert", "transmute", "transmutation", "type-punning"] diff --git a/README.md b/README.md index b419c05eda..658879908f 100644 --- a/README.md +++ b/README.md @@ -203,6 +203,14 @@ Zerocopy uses [GitHub Releases]. [GitHub Releases]: https://github.com/google/zerocopy/releases +## Thanks + +Zerocopy is maintained by engineers at Google and Amazon with help from +[many wonderful contributors][contributors]. Thank you to everyone who has +lent a hand in making Rust a little more secure! + +[contributors]: https://github.com/google/zerocopy/graphs/contributors + ## Disclaimer Disclaimer: This is not an officially supported Google product. diff --git a/src/lib.rs b/src/lib.rs index c831a91f18..ee28450019 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -202,6 +202,14 @@ //! Zerocopy uses [GitHub Releases]. //! //! [GitHub Releases]: https://github.com/google/zerocopy/releases +//! +//! # Thanks +//! +//! Zerocopy is maintained by engineers at Google and Amazon with help from +//! [many wonderful contributors][contributors]. Thank you to everyone who has +//! lent a hand in making Rust a little more secure! +//! +//! [contributors]: https://github.com/google/zerocopy/graphs/contributors // Sometimes we want to use lints which were added after our MSRV. // `unknown_lints` is `warn` by default and we deny warnings in CI, so without diff --git a/zerocopy-derive/Cargo.toml b/zerocopy-derive/Cargo.toml index d348ef482e..b9aff0bf0c 100644 --- a/zerocopy-derive/Cargo.toml +++ b/zerocopy-derive/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" name = "zerocopy-derive" version = "0.9.0-alpha.0" -authors = ["Joshua Liebow-Feeser "] +authors = { workspace = true } description = "Custom derive for traits from the zerocopy crate" license = "BSD-2-Clause OR Apache-2.0 OR MIT" repository = "https://github.com/google/zerocopy" From 8ee868d49e0db56e488c034b0fd615204c128aa9 Mon Sep 17 00:00:00 2001 From: Google PR Creation Bot <145818923+google-pr-creation-bot@users.noreply.github.com> Date: Thu, 20 Feb 2025 10:00:59 -0800 Subject: [PATCH 95/96] [ci] Roll pinned stable toolchain (#2366) --- Cargo.toml | 2 +- tests/ui-stable/invalid-impls/invalid-impls.stderr | 10 +++++----- tests/ui-stable/transmute-mut-const.stderr | 2 +- .../transmute-mut-src-dst-not-references.stderr | 4 ++-- tests/ui-stable/transmute-mut-src-immutable.stderr | 4 ++-- .../ui-stable/transmute-mut-src-not-a-reference.stderr | 4 ++-- .../transmute-ref-src-dst-not-references.stderr | 6 +++--- .../ui-stable/transmute-ref-src-not-a-reference.stderr | 6 +++--- .../tests/ui-stable/mid_compile_pass.stderr | 2 +- zerocopy-derive/tests/ui-stable/union.stderr | 8 +++----- .../union_into_bytes_cfg/union_into_bytes_cfg.stderr | 8 +++----- 11 files changed, 26 insertions(+), 30 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f9fbb41bb9..f851781483 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ zerocopy-diagnostic-on-unimplemented = "1.78.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. -pinned-stable = "1.84.1" +pinned-stable = "1.85.0" pinned-nightly = "nightly-2024-11-06" [package.metadata.docs.rs] diff --git a/tests/ui-stable/invalid-impls/invalid-impls.stderr b/tests/ui-stable/invalid-impls/invalid-impls.stderr index cd97538db4..532cb326f3 100644 --- a/tests/ui-stable/invalid-impls/invalid-impls.stderr +++ b/tests/ui-stable/invalid-impls/invalid-impls.stderr @@ -21,7 +21,7 @@ note: required by a bound in `_::Subtrait` 26 | impl_or_verify!(T => TryFromBytes for Foo); | --------------------------------------------- in this macro invocation = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider restricting type parameter `T` +help: consider restricting type parameter `T` with trait `TryFromBytes` | 26 | impl_or_verify!(T: zerocopy::TryFromBytes => TryFromBytes for Foo); | ++++++++++++++++++++++++ @@ -49,7 +49,7 @@ note: required by a bound in `_::Subtrait` 27 | impl_or_verify!(T => FromZeros for Foo); | ------------------------------------------ in this macro invocation = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider restricting type parameter `T` +help: consider restricting type parameter `T` with trait `FromZeros` | 27 | impl_or_verify!(T: zerocopy::FromZeros => FromZeros for Foo); | +++++++++++++++++++++ @@ -77,7 +77,7 @@ note: required by a bound in `_::Subtrait` 28 | impl_or_verify!(T => FromBytes for Foo); | ------------------------------------------ in this macro invocation = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider restricting type parameter `T` +help: consider restricting type parameter `T` with trait `FromBytes` | 28 | impl_or_verify!(T: zerocopy::FromBytes => FromBytes for Foo); | +++++++++++++++++++++ @@ -105,7 +105,7 @@ note: required by a bound in `_::Subtrait` 29 | impl_or_verify!(T => IntoBytes for Foo); | ------------------------------------------ in this macro invocation = note: this error originates in the derive macro `IntoBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider restricting type parameter `T` +help: consider restricting type parameter `T` with trait `IntoBytes` | 29 | impl_or_verify!(T: zerocopy::IntoBytes => IntoBytes for Foo); | +++++++++++++++++++++ @@ -133,7 +133,7 @@ note: required by a bound in `_::Subtrait` 30 | impl_or_verify!(T => Unaligned for Foo); | ------------------------------------------ in this macro invocation = note: this error originates in the derive macro `Unaligned` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider restricting type parameter `T` +help: consider restricting type parameter `T` with trait `Unaligned` | 30 | impl_or_verify!(T: zerocopy::Unaligned => Unaligned for Foo); | +++++++++++++++++++++ diff --git a/tests/ui-stable/transmute-mut-const.stderr b/tests/ui-stable/transmute-mut-const.stderr index f080090720..2a3388e0d2 100644 --- a/tests/ui-stable/transmute-mut-const.stderr +++ b/tests/ui-stable/transmute-mut-const.stderr @@ -13,7 +13,7 @@ note: `const` item defined here | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(const_item_mutation)]` on by default -error[E0015]: cannot call non-const fn `transmute_mut::<'_, '_, [u8; 2], [u8; 2]>` in constants +error[E0015]: cannot call non-const function `transmute_mut::<'_, '_, [u8; 2], [u8; 2]>` in constants --> tests/ui-stable/transmute-mut-const.rs:20:37 | 20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); diff --git a/tests/ui-stable/transmute-mut-src-dst-not-references.stderr b/tests/ui-stable/transmute-mut-src-dst-not-references.stderr index 8dadfb1529..35eac70b26 100644 --- a/tests/ui-stable/transmute-mut-src-dst-not-references.stderr +++ b/tests/ui-stable/transmute-mut-src-dst-not-references.stderr @@ -21,7 +21,7 @@ warning: this function depends on never type fallback being `()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see issue #123748 + = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: FromBytes` will fail --> tests/ui-stable/transmute-mut-src-dst-not-references.rs:17:44 @@ -43,7 +43,7 @@ warning: never type fallback affects this call to an `unsafe` function | ^^^^^^^^^^^^^^^^^^^^^^ | = warning: this changes meaning in Rust 2024 and in a future release in all editions! - = note: for more information, see issue #123748 + = note: for more information, see = help: specify the type explicitly = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default = note: this warning originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-stable/transmute-mut-src-immutable.stderr b/tests/ui-stable/transmute-mut-src-immutable.stderr index daa08f5b78..e839777aa8 100644 --- a/tests/ui-stable/transmute-mut-src-immutable.stderr +++ b/tests/ui-stable/transmute-mut-src-immutable.stderr @@ -17,7 +17,7 @@ warning: this function depends on never type fallback being `()` | ^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see issue #123748 + = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: FromBytes` will fail --> tests/ui-stable/transmute-mut-src-immutable.rs:17:22 @@ -39,7 +39,7 @@ warning: never type fallback affects this call to an `unsafe` function | ^^^^^^^^^^^^^^^^^^^^ | = warning: this changes meaning in Rust 2024 and in a future release in all editions! - = note: for more information, see issue #123748 + = note: for more information, see = help: specify the type explicitly = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default = note: this warning originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-stable/transmute-mut-src-not-a-reference.stderr b/tests/ui-stable/transmute-mut-src-not-a-reference.stderr index f9b3f9bbd8..ea715472cb 100644 --- a/tests/ui-stable/transmute-mut-src-not-a-reference.stderr +++ b/tests/ui-stable/transmute-mut-src-not-a-reference.stderr @@ -21,7 +21,7 @@ warning: this function depends on never type fallback being `()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see issue #123748 + = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: FromBytes` will fail --> tests/ui-stable/transmute-mut-src-not-a-reference.rs:17:38 @@ -43,7 +43,7 @@ warning: never type fallback affects this call to an `unsafe` function | ^^^^^^^^^^^^^^^^^^^^^^ | = warning: this changes meaning in Rust 2024 and in a future release in all editions! - = note: for more information, see issue #123748 + = note: for more information, see = help: specify the type explicitly = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default = note: this warning originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-stable/transmute-ref-src-dst-not-references.stderr b/tests/ui-stable/transmute-ref-src-dst-not-references.stderr index 2822bc4394..de4df6bf98 100644 --- a/tests/ui-stable/transmute-ref-src-dst-not-references.stderr +++ b/tests/ui-stable/transmute-ref-src-dst-not-references.stderr @@ -84,7 +84,7 @@ warning: this function depends on never type fallback being `()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see issue #123748 + = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: IntoBytes` will fail --> tests/ui-stable/transmute-ref-src-dst-not-references.rs:17:39 @@ -106,7 +106,7 @@ warning: never type fallback affects this call to an `unsafe` function | ^^^^^^^^^^^^^^^^^^^^^^ | = warning: this changes meaning in Rust 2024 and in a future release in all editions! - = note: for more information, see issue #123748 + = note: for more information, see = help: specify the type explicitly = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default = note: this warning originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -118,6 +118,6 @@ warning: never type fallback affects this call to an `unsafe` function | ^^^^^^^^^^^^^^^^^^^^^^ | = warning: this changes meaning in Rust 2024 and in a future release in all editions! - = note: for more information, see issue #123748 + = note: for more information, see = help: specify the type explicitly = note: this warning originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-stable/transmute-ref-src-not-a-reference.stderr b/tests/ui-stable/transmute-ref-src-not-a-reference.stderr index 4b3f63560c..a9b2745bca 100644 --- a/tests/ui-stable/transmute-ref-src-not-a-reference.stderr +++ b/tests/ui-stable/transmute-ref-src-not-a-reference.stderr @@ -21,7 +21,7 @@ warning: this function depends on never type fallback being `()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! - = note: for more information, see issue #123748 + = note: for more information, see = help: specify the types explicitly note: in edition 2024, the requirement `!: IntoBytes` will fail --> tests/ui-stable/transmute-ref-src-not-a-reference.rs:17:34 @@ -43,7 +43,7 @@ warning: never type fallback affects this call to an `unsafe` function | ^^^^^^^^^^^^^^^^^^^^^^ | = warning: this changes meaning in Rust 2024 and in a future release in all editions! - = note: for more information, see issue #123748 + = note: for more information, see = help: specify the type explicitly = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default = note: this warning originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -55,6 +55,6 @@ warning: never type fallback affects this call to an `unsafe` function | ^^^^^^^^^^^^^^^^^^^^^^ | = warning: this changes meaning in Rust 2024 and in a future release in all editions! - = note: for more information, see issue #123748 + = note: for more information, see = help: specify the type explicitly = note: this warning originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/zerocopy-derive/tests/ui-stable/mid_compile_pass.stderr b/zerocopy-derive/tests/ui-stable/mid_compile_pass.stderr index 6082eda01e..3a937f8fdf 100644 --- a/zerocopy-derive/tests/ui-stable/mid_compile_pass.stderr +++ b/zerocopy-derive/tests/ui-stable/mid_compile_pass.stderr @@ -13,7 +13,7 @@ note: required for `KL13` to implement `KnownLayout` 55 | #[derive(KnownLayout)] | ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider restricting type parameter `T` +help: consider restricting type parameter `T` with trait `KnownLayout` | 59 | fn test_kl13(t: T) -> impl KnownLayout { | +++++++++++++++++++++++ diff --git a/zerocopy-derive/tests/ui-stable/union.stderr b/zerocopy-derive/tests/ui-stable/union.stderr index 1dcd617478..b1486a74af 100644 --- a/zerocopy-derive/tests/ui-stable/union.stderr +++ b/zerocopy-derive/tests/ui-stable/union.stderr @@ -69,11 +69,9 @@ warning: unexpected `cfg` condition name: `zerocopy_derive_union_into_bytes` | ^^^^^^^^^ | = help: expected names are: `clippy`, `debug_assertions`, `doc`, `docsrs`, `doctest`, `feature`, `fmt_debug`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` - = help: consider using a Cargo feature instead - = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint: - [lints.rust] - unexpected_cfgs = { level = "warn", check-cfg = ['cfg(zerocopy_derive_union_into_bytes)'] } - = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(zerocopy_derive_union_into_bytes)");` to the top of the `build.rs` + = note: using a cfg inside a derive macro will use the cfgs from the destination crate and not the ones from the defining crate + = help: try referring to `IntoBytes` crate for guidance on how handle this unexpected cfg + = help: the derive macro `IntoBytes` may come from an old version of the `zerocopy_derive` crate, try updating your dependency with `cargo update -p zerocopy_derive` = note: see for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default = note: this warning originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/zerocopy-derive/tests/ui-stable/union_into_bytes_cfg/union_into_bytes_cfg.stderr b/zerocopy-derive/tests/ui-stable/union_into_bytes_cfg/union_into_bytes_cfg.stderr index 2e21f9d709..71a6b57e4f 100644 --- a/zerocopy-derive/tests/ui-stable/union_into_bytes_cfg/union_into_bytes_cfg.stderr +++ b/zerocopy-derive/tests/ui-stable/union_into_bytes_cfg/union_into_bytes_cfg.stderr @@ -14,11 +14,9 @@ warning: unexpected `cfg` condition name: `zerocopy_derive_union_into_bytes` | ^^^^^^^^^ | = help: expected names are: `clippy`, `debug_assertions`, `doc`, `docsrs`, `doctest`, `feature`, `fmt_debug`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` - = help: consider using a Cargo feature instead - = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint: - [lints.rust] - unexpected_cfgs = { level = "warn", check-cfg = ['cfg(zerocopy_derive_union_into_bytes)'] } - = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(zerocopy_derive_union_into_bytes)");` to the top of the `build.rs` + = note: using a cfg inside a derive macro will use the cfgs from the destination crate and not the ones from the defining crate + = help: try referring to `IntoBytes` crate for guidance on how handle this unexpected cfg + = help: the derive macro `IntoBytes` may come from an old version of the `zerocopy_derive` crate, try updating your dependency with `cargo update -p zerocopy_derive` = note: see for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default = note: this warning originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) From 02f59828316a55c99188c4bcda6ed4f566b85fe5 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Fri, 7 Feb 2025 14:56:24 -0800 Subject: [PATCH 96/96] [WIP] Transmute Co-authored-by: Jack Wrenn gherrit-pr-id: I8d5d162c1b6fe43e3dcb90a6dc5bf58a7a203bf8 --- src/error.rs | 14 ++ src/lib.rs | 30 ++- src/pointer/mod.rs | 1 + src/pointer/ptr.rs | 151 +++++++++++- src/pointer/transmute.rs | 505 +++++++++++++++++++++++++++++++++++++++ src/ref.rs | 8 +- src/util/macro_util.rs | 197 +++++++-------- src/util/macros.rs | 2 +- 8 files changed, 784 insertions(+), 124 deletions(-) create mode 100644 src/pointer/transmute.rs diff --git a/src/error.rs b/src/error.rs index 39b2a864bf..8bfd4dd9d2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -594,6 +594,20 @@ impl ValidityError { ValidityError { src: f(self.src), dst: SendSyncPhantomData::default() } } + /// Changes the destination type. + /// + /// # Safety + /// + /// `NewDst` must have the same validity - as implemented by + /// [`TryFromBytes::is_bit_valid`] - as `Dst`. + pub(crate) unsafe fn with_dst(self) -> ValidityError { + // SAFETY: There is currently no invariant required of `dst`, so this + // method's safety precondition is unnecessary. However, we require it + // to be forwards-compatible with a point in time where we add an + // invariant to the `Dst` type. + ValidityError { src: self.src, dst: SendSyncPhantomData::default() } + } + /// Converts the error into a general [`ConvertError`]. pub(crate) const fn into(self) -> ConvertError { ConvertError::Validity(self) diff --git a/src/lib.rs b/src/lib.rs index ee28450019..81d62fb070 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -375,7 +375,10 @@ use core::{ #[cfg(feature = "std")] use std::io; -use crate::pointer::invariant::{self, BecauseExclusive}; +use crate::pointer::{ + invariant::{self, BecauseExclusive}, + transmute::BecauseRead, +}; #[cfg(any(feature = "alloc", test))] extern crate alloc; @@ -1790,7 +1793,7 @@ pub unsafe trait TryFromBytes { // calling `try_into_valid` (and thus `is_bit_valid`) with a shared // pointer when `Self: !Immutable`. Since `Self: Immutable`, this panic // condition will not happen. - match source.try_into_valid() { + match source.try_into_valid::<(pointer::transmute::BecauseRead, _)>() { Ok(source) => Ok(source.as_mut()), Err(e) => { Err(e.map_src(|src| src.as_bytes::().as_mut()).into()) @@ -2372,7 +2375,7 @@ pub unsafe trait TryFromBytes { // calling `try_into_valid` (and thus `is_bit_valid`) with a shared // pointer when `Self: !Immutable`. Since `Self: Immutable`, this panic // condition will not happen. - match source.try_into_valid() { + match source.try_into_valid::<(BecauseRead, _)>() { Ok(source) => Ok(source.as_mut()), Err(e) => { Err(e.map_src(|src| src.as_bytes::().as_mut()).into()) @@ -2779,7 +2782,7 @@ fn try_ref_from_prefix_suffix( +fn try_mut_from_prefix_suffix( candidate: &mut [u8], cast_type: CastType, meta: Option, @@ -2794,7 +2797,7 @@ fn try_mut_from_prefix_suffix() { Ok(valid) => Ok((valid.as_mut(), prefix_suffix.as_mut())), Err(e) => Err(e.map_src(|src| src.as_bytes::().as_mut()).into()), } @@ -3508,7 +3511,7 @@ pub unsafe trait FromBytes: FromZeros { { static_assert_dst_is_not_zst!(Self); match Ptr::from_ref(source).try_cast_into_no_leftover::<_, BecauseImmutable>(None) { - Ok(ptr) => Ok(ptr.bikeshed_recall_valid().as_ref()), + Ok(ptr) => Ok(ptr.transmute().as_ref()), Err(err) => Err(err.map_src(|src| src.as_ref())), } } @@ -3744,7 +3747,7 @@ pub unsafe trait FromBytes: FromZeros { { static_assert_dst_is_not_zst!(Self); match Ptr::from_mut(source).try_cast_into_no_leftover::<_, BecauseExclusive>(None) { - Ok(ptr) => Ok(ptr.bikeshed_recall_valid().as_mut()), + Ok(ptr) => Ok(ptr.bikeshed_recall_valid::<(BecauseRead, BecauseExclusive)>().as_mut()), Err(err) => Err(err.map_src(|src| src.as_mut())), } } @@ -3983,7 +3986,7 @@ pub unsafe trait FromBytes: FromZeros { let source = Ptr::from_ref(source); let maybe_slf = source.try_cast_into_no_leftover::<_, BecauseImmutable>(Some(count)); match maybe_slf { - Ok(slf) => Ok(slf.bikeshed_recall_valid().as_ref()), + Ok(slf) => Ok(slf.transmute().as_ref()), Err(err) => Err(err.map_src(|s| s.as_ref())), } } @@ -4214,7 +4217,7 @@ pub unsafe trait FromBytes: FromZeros { let source = Ptr::from_mut(source); let maybe_slf = source.try_cast_into_no_leftover::<_, BecauseImmutable>(Some(count)); match maybe_slf { - Ok(slf) => Ok(slf.bikeshed_recall_valid().as_mut()), + Ok(slf) => Ok(slf.bikeshed_recall_valid::<(BecauseRead, BecauseExclusive)>().as_mut()), Err(err) => Err(err.map_src(|s| s.as_mut())), } } @@ -4590,7 +4593,7 @@ fn ref_from_prefix_suffix( let (slf, prefix_suffix) = Ptr::from_ref(source) .try_cast_into::<_, BecauseImmutable>(cast_type, meta) .map_err(|err| err.map_src(|s| s.as_ref()))?; - Ok((slf.bikeshed_recall_valid().as_ref(), prefix_suffix.as_ref())) + Ok((slf.transmute().as_ref(), prefix_suffix.as_ref())) } /// Interprets the given affix of the given bytes as a `&mut Self` without @@ -4602,7 +4605,7 @@ fn ref_from_prefix_suffix( /// If there are insufficient bytes, or if that affix of `source` is not /// appropriately aligned, this returns `Err`. #[inline(always)] -fn mut_from_prefix_suffix( +fn mut_from_prefix_suffix( source: &mut [u8], meta: Option, cast_type: CastType, @@ -4610,7 +4613,10 @@ fn mut_from_prefix_suffix( let (slf, prefix_suffix) = Ptr::from_mut(source) .try_cast_into::<_, BecauseExclusive>(cast_type, meta) .map_err(|err| err.map_src(|s| s.as_mut()))?; - Ok((slf.bikeshed_recall_valid().as_mut(), prefix_suffix.as_mut())) + Ok(( + slf.transmute::, _, (BecauseRead, _), _>().as_mut(), + prefix_suffix.as_mut(), + )) } /// Analyzes whether a type is [`IntoBytes`]. diff --git a/src/pointer/mod.rs b/src/pointer/mod.rs index 5d38a92b90..ddaf1600f6 100644 --- a/src/pointer/mod.rs +++ b/src/pointer/mod.rs @@ -12,6 +12,7 @@ mod inner; #[doc(hidden)] pub mod invariant; mod ptr; +pub(crate) mod transmute; #[doc(hidden)] pub use invariant::{BecauseExclusive, BecauseImmutable, Read}; diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index 59ec627479..b676b2b6b9 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -171,7 +171,10 @@ mod _external { /// Methods for converting to and from `Ptr` and Rust's safe reference types. mod _conversions { use super::*; - use crate::util::{AlignmentVariance, Covariant, TransparentWrapper, ValidityVariance}; + use crate::{ + pointer::transmute::{CastFrom, TransmuteFromAlignment, TransmuteFromPtr}, + util::{AlignmentVariance, Covariant, TransparentWrapper, ValidityVariance}, + }; /// `&'a T` → `Ptr<'a, T>` impl<'a, T: ?Sized> Ptr<'a, Valid, (Shared, Aligned)> { @@ -337,6 +340,54 @@ mod _conversions { } } + /// `Ptr<'a, T>` → `Ptr<'a, U>` + impl<'a, V, I> Ptr<'a, V, I> + where + V: Validity, + I: Invariants, + { + /// # Safety + /// - TODO: `UnsafeCell` agreement + /// - The caller promises that the returned `Ptr` satisfies alignment + /// `A` + /// - The caller promises that the returned `Ptr` satisfies validity `V` + pub(crate) unsafe fn transmute_unchecked(self) -> Ptr<'a, U, (I::Aliasing, A)> + where + A: Alignment, + U: Validity, + U::Inner: CastFrom, + { + // SAFETY: + // - By invariant on `CastFrom::cast_from`: + // - This cast preserves address and referent size, and thus the + // returned pointer addresses the same bytes as `p` + // - This cast preserves provenance + // - TODO: `UnsafeCell` agreement + let ptr = + unsafe { self.cast_unsized_unchecked::(|p| U::Inner::cast_from(p)) }; + // SAFETY: The caller promises that alignment is satisfied. + let ptr = unsafe { ptr.assume_alignment() }; + // SAFETY: The caller promises that validity is satisfied. + let ptr = unsafe { ptr.assume_validity::() }; + ptr.unify_validity() + } + + pub(crate) fn transmute(self) -> Ptr<'a, U, (I::Aliasing, A)> + where + A: Alignment, + U: TransmuteFromPtr, + U::Inner: TransmuteFromAlignment + CastFrom, + { + // SAFETY: + // - TODO: `UnsafeCell` agreement + // - By invariant on `TransmuteFromPtr`, it is sound to treat the + // resulting pointer as having alignment `A` + // - By invariant on `TransmuteFromPtr`, it is sound to treat the + // resulting pointer as having validity `V` + unsafe { self.transmute_unchecked() } + } + } + /// `Ptr<'a, T = Wrapper>` → `Ptr<'a, U>` impl<'a, V, I> Ptr<'a, V, I> where @@ -428,7 +479,10 @@ mod _conversions { /// State transitions between invariants. mod _transitions { use super::*; - use crate::{AlignmentError, TryFromBytes, ValidityError}; + use crate::{ + pointer::transmute::{CastFrom, TransmuteFromPtr, TryTransmuteFromPtr}, + AlignmentError, TryFromBytes, ValidityError, + }; impl<'a, V, I> Ptr<'a, V, I> where @@ -649,6 +703,22 @@ mod _transitions { } } + impl<'a, V, I> Ptr<'a, V, I> + where + V: Validity, + I: Invariants, + I::Aliasing: Reference, + { + /// Forgets that `self` is an `Exclusive` pointer, downgrading it to a + /// `Shared` pointer. + #[doc(hidden)] + #[must_use] + #[inline] + pub const fn forget_exclusive(self) -> Ptr<'a, V, I::WithAliasing> { + unsafe { self.assume_invariants() } + } + } + impl<'a, T, I> Ptr<'a, Initialized, I> where T: ?Sized, @@ -660,14 +730,12 @@ mod _transitions { #[inline] // TODO(#859): Reconsider the name of this method before making it // public. - pub const fn bikeshed_recall_valid(self) -> Ptr<'a, Valid, I> + pub fn bikeshed_recall_valid(self) -> Ptr<'a, Valid, I> where - T: crate::FromBytes, + Valid: TransmuteFromPtr, I::Aliasing, R>, + as Validity>::Inner: CastFrom, { - // SAFETY: The bound `T: FromBytes` ensures that any initialized - // sequence of bytes is bit-valid for `T`. `V = Initialized` - // ensures that all of the referent bytes are initialized. - unsafe { self.assume_valid() } + self.transmute().unify_invariants() } /// Checks that `self`'s referent is validly initialized for `T`, @@ -687,7 +755,12 @@ mod _transitions { mut self, ) -> Result, I>, ValidityError> where - T: TryFromBytes + Read, + T: TryFromBytes, // + Read, + Valid: TryTransmuteFromPtr, I::Aliasing, R>, + // NOTE: This bound ought to be implied, but leaving it out causes + // Rust to infinite loop during trait solving. + as Validity>::Inner: + crate::pointer::transmute::CastFrom< as Validity>::Inner>, I::Aliasing: Reference, { // This call may panic. If that happens, it doesn't cause any soundness @@ -702,12 +775,63 @@ mod _transitions { } } } + + impl<'a, V, I> Ptr<'a, V, I> + where + V: Validity, + I: Invariants, + { + /// Attempts to transmute a `Ptr` into a `Ptr`. + /// + /// # Panics + /// + /// This method will panic if + /// [`U::is_bit_valid`][TryFromBytes::is_bit_valid] panics. + /// + /// # Safety + /// + /// On success, the returned `Ptr` addresses the same bytes as `self`. + /// + /// On error, unsafe code may rely on this method's returned + /// `ValidityError` containing `self`. + #[inline] + pub(crate) fn try_transmute( + mut self, + ) -> Result>, ValidityError> + where + U: Validity + TryTransmuteFromPtr, + U::Inner: TryFromBytes + CastFrom, + Initialized: TransmuteFromPtr, + // TODO: The `Sized` bound here is only required in order to call + // `.bikeshed_try_into_aligned`. There are other ways of getting the + // alignment of a type, and we could use these if we need to drop + // this bound. + as Validity>::Inner: Sized + CastFrom, + I::Aliasing: Reference, + { + let is_bit_valid = { + let ptr = self.reborrow(); + let ptr = ptr.transmute::, Unknown, _, _>(); + // This call may panic. If that happens, it doesn't cause any + // soundness issues, as we have not generated any invalid state + // which we need to fix before returning. + ::is_bit_valid(ptr) + }; + + if is_bit_valid { + let ptr = unsafe { self.transmute_unchecked() }; + Ok(ptr.unify_invariants()) + } else { + Err(ValidityError::new(self)) + } + } + } } /// Casts of the referent type. mod _casts { use super::*; - use crate::{CastError, SizeError}; + use crate::{pointer::transmute::BecauseRead, CastError, SizeError}; impl<'a, V, I> Ptr<'a, V, I> where @@ -866,7 +990,7 @@ mod _casts { }) }; - ptr.bikeshed_recall_aligned().bikeshed_recall_valid() + ptr.bikeshed_recall_aligned().bikeshed_recall_valid::<(BecauseRead, _)>() } } @@ -1125,6 +1249,7 @@ mod tests { mod test_ptr_try_cast_into_soundness { use super::*; + use crate::IntoBytes; // This test is designed so that if `Ptr::try_cast_into_xxx` are // buggy, it will manifest as unsoundness that Miri can detect. @@ -1164,7 +1289,9 @@ mod tests { }; // SAFETY: The bytes in `slf` must be initialized. - unsafe fn validate_and_get_len( + unsafe fn validate_and_get_len< + T: ?Sized + KnownLayout + FromBytes + Immutable, + >( slf: Ptr<'_, Initialized, (Shared, Aligned)>, ) -> usize { let t = slf.bikeshed_recall_valid().as_ref(); diff --git a/src/pointer/transmute.rs b/src/pointer/transmute.rs new file mode 100644 index 0000000000..c6d266ca44 --- /dev/null +++ b/src/pointer/transmute.rs @@ -0,0 +1,505 @@ +// Copyright 2025 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +use core::{ + cell::UnsafeCell, + mem::{ManuallyDrop, MaybeUninit}, + num::Wrapping, +}; + +use crate::{pointer::invariant::*, FromBytes, Immutable, IntoBytes, Unalign}; + +define_because!(pub(crate) BecauseBidirectional); +define_because!(pub(crate) BecauseRead); +define_because!(pub(crate) BecauseFoo); +define_because!(BecauseExclusive); +define_because!(BecauseUnchanged); +define_because!(BecauseUnaligned); + +// TODO: Confirm that we don't need to explicitly mention size (that should be +// handled automatically by impls, usually via a `TransmuteFrom` bound). + +/// # Safety +/// +/// ## Post-conditions +/// +/// Given `Dst: TryTransmuteFromPtr`, callers may assume the +/// following: +/// +/// Given `src: Ptr` where `SI: Invariants`, if the referent of `src` contains a `Dst` which conforms to the +/// validity `DV`, then it is sound to transmute `src` into `dst: Ptr` +/// whre `DI: Invariants`. +/// +/// TODO: Mention alignment +/// +/// ## Pre-conditions +/// +/// Given `src: Ptr`, `dst: Ptr`, `SI: Invariants`, and `DV: Invariants`, `Dst: +/// TryTransmuteFromPtr` is sound if all of the following +/// hold: +/// - Forwards transmutation: Any of the following hold: +/// - So long as `dst` is active, no mutation of `dst`'s referent is allowed +/// except via `dst` itself +/// - The set of `DV`-valid `Dst`s is a superset of the set of `SV`-valid +/// `Src`s +/// - Reverse transmutation: Any of the following hold: +/// - `dst` does not permit mutation of its referent +/// - The set of `DV`-valid `Dst`s is a subset of the set of `SV`-valid +/// `Src`s +/// - `UnsafeCell` agreement: TODO +/// +/// ## Proof +/// +/// TODO: Prove that the pre-conditions imply the post-conditions. +#[cfg_attr(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS, marker)] +pub(crate) unsafe trait TryTransmuteFromPtr: + Validity +where + Self::Inner: CastFrom, +{ +} + +// SAFETY: +// - Forwards transmutation: Since `Src::Inner: Read`, one of the +// following holds: +// - `Src: Immutable`, so no mutation of `dst`'s referent is permitted via +// `src`. No other references to the same referent may exist which are typed +// using `T: !Immutable`, as this would permit violating `Src: Immutable`'s +// soundness precondition. +// - Aliasing `A` is `Exclusive`, so `dst` is the only reference permitted to +// mutate its referent. +// - Reverse transmutation: Since `Src: TransmuteFrom`, `Dst`'s validity +// set is a subset of `Src`'s validity set. +// - Since `Src::Inner: Read` and `Dst::Inner: Read`, one of the following +// holds: +// - Aliasing `A` is `Exclusive`, in which case `UnsafeCell`s do not need to +// agree +// - `Src::Inner: Immutable` and `Dst::Inner: Immutable`, in which case +// `UnsafeCell`s trivially agree +unsafe impl TryTransmuteFromPtr for Dst +where + Src: Validity + TransmuteFrom, + Dst: Validity, + Src::Inner: Read, + Dst::Inner: Read + CastFrom, + A: Aliasing, +{ +} + +unsafe impl TryTransmuteFromPtr for Dst +where + Src: Validity, + Dst: Validity, + Src::Inner: Immutable, + Dst::Inner: Immutable + CastFrom, +{ +} + +// SAFETY: +// - Forwards transmutation: `Dst: TransmuteFrom` guarantees that +// the set of `DV`-valid `Dst`s is a supserset of the set of `SV`-valid +// `Src`s. +// - Reverse transmutation: `Src: TransmuteFrom` guarantees that +// the set of `DV`-valid `Dst`s is a subset of the set of `SV`-valid `Src`s. +// - `UnsafeCell` agreement guaranteed by `Src: UnsafeCellsAgree + Dst: +// UnsafeCellsAgree`. +unsafe impl TryTransmuteFromPtr for Dst +where + A: Aliasing, + Src: Validity + TransmuteFrom, + Dst: Validity + TransmuteFrom, + Src::Inner: UnsafeCellsAgree, + Dst::Inner: UnsafeCellsAgree + CastFrom, +{ +} + +// SAFETY: +// - Forwards transmutation: `Src: Immutable` guarantees that no mutation of +// `dst`'s referent is possible via `src`. No other references to the same +// referent may exist which are typed using `T: !Immutable`, as this would +// permit violating `Src: Immutable`'s soundness precondition. +// - Reverse transmutation: `Src: TransmuteFrom` guarantees that +// the set of `DV`-valid `Dst`s is a subset of the set of `SV`-valid `Src`s. +// - `UnsafeCell` agreement guaranteed by `Src: Immutable + Dst: Immutable`. +unsafe impl TryTransmuteFromPtr for Dst +where + A: Aliasing, + Src: Validity + TransmuteFrom, + Dst: Validity, + Src::Inner: Immutable, + Dst::Inner: Immutable + CastFrom, +{ +} + +// TODO: Try to delete this impl and see if things still work + +// SAFETY: +// - Forwards transmutation: Because aliasing is `Exclusive`, `dst` is the only +// reference permitted to mutate its referent. +// - Reverse transmutation: `Src: TransmuteFrom` guarantees that +// the set of `DV`-valid `Dst`s is a subset of the set of `SV`-valid `Src`s. +// - `UnsafeCell` agreement is not necessary because aliasing is `Exclusive`. +unsafe impl TryTransmuteFromPtr for Dst +where + Src: Validity + TransmuteFrom, + Dst: Validity, + Dst::Inner: CastFrom, +{ +} + +#[cfg_attr(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS, marker)] +pub(crate) unsafe trait TransmuteFromPtr: + TryTransmuteFromPtr + TransmuteFrom +where + Self::Inner: CastFrom, +{ +} + +unsafe impl TransmuteFromPtr for Dst +where + Dst::Inner: CastFrom, + Dst: TransmuteFrom + TryTransmuteFromPtr, +{ +} + +#[marker] +pub(crate) unsafe trait TransmuteFromAlignment {} + +pub(crate) unsafe trait CastFrom { + /// Casts a `*mut T` to a `*mut Self`. + /// + /// # Safety + /// + /// The resulting pointer has the same address and provenance as `ptr`, and + /// addresses the same number of bytes. + fn cast_from(ptr: *mut Src) -> *mut Self; +} + +/// Pairs of types which have `UnsafeCells` covering the same byte ranges. +/// +/// # Safety +/// +/// Let `t: &T` and `u: &U`. Let `len = min(size_of_val(t), size_of_val(u))`. If +/// `U: UnsafeCellsAgree`, then the first `len` bytes of `t` and the first +/// `len` bytes of `u` have `UnsafeCell`s covering the same byte ranges. This +/// condition must hold for all `t: &T` and for all `u: &U`. +/// +/// Note that this safety invariant supports either or both of `T` and `U` being +/// unsized. +pub(crate) unsafe trait UnsafeCellsAgree +where + T: UnsafeCellsAgree, +{ +} + +// SAFETY: `T` has `UnsafeCell`s covering the same byte ranges as itself by +// definition. +unsafe impl UnsafeCellsAgree for T {} + +#[marker] +pub(crate) unsafe trait TransmuteFrom {} + +unsafe impl CastFrom for Src { + fn cast_from(ptr: *mut Src) -> *mut Src { + // SAFETY: `ptr` trivially has the same address as, addresses the same + // number of bytes as, and has the same provenance as `ptr`. + ptr + } +} + +unsafe impl TransmuteFrom for Src {} + +unsafe impl TransmuteFromAlignment for Src {} +unsafe impl + TransmuteFromAlignment for Dst +{ +} + +// TODO: Make sure to clarify that, for unsized types, this specifically refers +// to a cast that does not perform a metadata fix-up operation. +pub(crate) unsafe trait SizeGtEq {} + +unsafe impl SizeGtEq for T {} + +unsafe impl TransmuteFrom> for Valid +where + Dst: FromBytes, + Src: SizeGtEq, +{ +} + +unsafe impl TransmuteFrom> for Valid +where + Src: IntoBytes, + Dst: FromBytes, + Src: SizeGtEq, +{ +} + +unsafe impl TransmuteFrom> for Initialized +where + Src: IntoBytes, + Src: SizeGtEq, +{ +} + +// SAFETY: `MaybeUninit` has `UnsafeCell`s covering the same byte ranges as +// `T`. This is not explicitly documented, but it can be inferred. Per [1] in +// the following safety comment, `MaybeUninit` has the same size as `T`. +// Further, note the signature of `MaybeUninit::assume_init_ref` [1]: +// +// pub unsafe fn assume_init_ref(&self) -> &T +// +// If the argument `&MaybeUninit` and the returned `&T` had `UnsafeCell`s at +// different offsets, this would be unsound. Its existence is proof that this is +// not the case. +// +// [1] https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#method.assume_init_ref +unsafe impl UnsafeCellsAgree for MaybeUninit {} +// SAFETY: See previous safety comment. +unsafe impl UnsafeCellsAgree> for T {} + +unsafe impl TransmuteFrom for Valid> where + Src::Inner: Sized +{ +} +unsafe impl TransmuteFrom for AsInitialized> where + Src::Inner: Sized +{ +} + +unsafe impl TransmuteFrom> for Initialized> {} + +unsafe impl TransmuteFrom>> for Initialized {} + +unsafe impl TransmuteFromAlignment + for MaybeUninit +{ +} +unsafe impl TransmuteFromAlignment, A, A, BecauseUnchanged> + for Src +{ +} + +unsafe impl CastFrom for MaybeUninit { + fn cast_from(ptr: *mut Src) -> *mut MaybeUninit { + // SAFETY: `.cast()` preserves address and provenance. Since + // `MaybeUninit` has the same size as `Src` [1], it also preserves + // size. + // + // [1] Per https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#layout-1: + // + // `MaybeUninit` is guaranteed to have the same size, alignment, + // and ABI as `T`. + ptr.cast() + } +} + +unsafe impl CastFrom> for Src { + fn cast_from(ptr: *mut MaybeUninit) -> *mut Src { + // SAFETY: `.cast()` preserves address and provenance. Since + // `MaybeUninit` has the same size as `Src` [1], it also preserves + // size. + // + // [1] Per https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#layout-1: + // + // `MaybeUninit` is guaranteed to have the same size, alignment, + // and ABI as `T`. + ptr.cast() + } +} + +// SAFETY: Per [1], `ManuallyDrop` has `UnsafeCell`s covering the same byte +// ranges as `Inner = T`. +// +// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html: +// +// `ManuallyDrop` is guaranteed to have the same layout and bit validity as +// `T`, and is subject to the same layout optimizations as `T`. As a +// consequence, it has no effect on the assumptions that the compiler makes +// about its contents. +unsafe impl UnsafeCellsAgree for ManuallyDrop {} +// SAFETY: See previous safety comment. +unsafe impl UnsafeCellsAgree> for T {} + +unsafe impl TransmuteFrom for Src::WithInner> {} +unsafe impl TransmuteFrom>> for Src {} + +unsafe impl TransmuteFromAlignment + for ManuallyDrop +{ +} +unsafe impl + TransmuteFromAlignment, A, A, BecauseUnchanged> for Src +{ +} + +unsafe impl CastFrom for ManuallyDrop { + fn cast_from(ptr: *mut Src) -> *mut ManuallyDrop { + // SAFETY: An `as` cast preserves address and provenance. Since + // `ManuallyDrop` has the same size as `Src` [1], it also preserves + // size. + // + // [1] Per https://doc.rust-lang.org/nightly/core/mem/struct.ManuallyDrop.html: + // + // `ManuallyDrop` is guaranteed to have the same layout and bit + // validity as `T` + ptr as *mut ManuallyDrop + } +} + +unsafe impl CastFrom> for Src { + fn cast_from(ptr: *mut ManuallyDrop) -> *mut Src { + // SAFETY: An `as` cast preserves address and provenance. Since + // `ManuallyDrop` has the same size as `Src` [1], it also preserves + // size. + // + // [1] Per https://doc.rust-lang.org/nightly/core/mem/struct.ManuallyDrop.html: + // + // `ManuallyDrop` is guaranteed to have the same layout and bit + // validity as `T` + ptr as *mut Src + } +} + +// SAFETY: Per [1], `Wrapping` has the same layout as `T`. Since its single +// field (of type `T`) is public, it would be a breaking change to add or remove +// fields. Thus, we know that `Wrapping` contains a `T` (as opposed to just +// having the same size and alignment as `T`) with no pre- or post-padding. +// Thus, `Wrapping` must have `UnsafeCell`s covering the same byte ranges as +// `Inner = T`. +// +// [1] Per https://doc.rust-lang.org/1.81.0/std/num/struct.Wrapping.html#layout-1: +// +// `Wrapping` is guaranteed to have the same layout and ABI as `T`. +unsafe impl UnsafeCellsAgree for Wrapping {} +// SAFETY: See previous safety comment. +unsafe impl UnsafeCellsAgree> for T {} + +unsafe impl TransmuteFrom for Src::WithInner> where + Src::Inner: Sized +{ +} +unsafe impl TransmuteFrom>> for Src where + Src::Inner: Sized +{ +} + +unsafe impl TransmuteFromAlignment + for Wrapping +{ +} +unsafe impl TransmuteFromAlignment, A, A, BecauseUnchanged> + for Src +{ +} + +unsafe impl CastFrom for Wrapping { + fn cast_from(ptr: *mut Src) -> *mut Wrapping { + // SAFETY: `.cast()` preserves address and provenance. Since + // `Wrapping` has the same size as `Src` [1], it also preserves size. + // + // [1] Per https://doc.rust-lang.org/core/num/struct.Wrapping.html#layout-1: + // + // `Wrapping` is guaranteed to have the same layout and ABI as `T`. + ptr.cast() + } +} + +unsafe impl CastFrom> for Src { + fn cast_from(ptr: *mut Wrapping) -> *mut Src { + // SAFETY: `.cast()` preserves address and provenance. Since + // `Wrapping` has the same size as `Src` [1], it also preserves size. + // + // [1] Per https://doc.rust-lang.org/core/num/struct.Wrapping.html#layout-1: + // + // `Wrapping` is guaranteed to have the same layout and ABI as `T`. + ptr.cast() + } +} + +unsafe impl TransmuteFrom for Src::WithInner> {} +unsafe impl TransmuteFrom>> for Src {} + +unsafe impl TransmuteFromAlignment + for UnsafeCell +{ +} +unsafe impl + TransmuteFromAlignment, A, A, BecauseUnchanged> for Src +{ +} + +unsafe impl CastFrom for UnsafeCell { + fn cast_from(ptr: *mut Src) -> *mut UnsafeCell { + // SAFETY: An `as` cast preserves address and provenance. Since + // `UnsafeCell` has the same size as `Src`, it also preserves size. + // + // [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout: + // + // `UnsafeCell` has the same in-memory representation as its inner + // type `T`. + ptr as *mut UnsafeCell + } +} + +unsafe impl CastFrom> for Src { + fn cast_from(ptr: *mut UnsafeCell) -> *mut Src { + // SAFETY: An `as` cast preserves address and provenance. Since + // `UnsafeCell` has the same size as `Src`, it also preserves size. + // + // [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout: + // + // `UnsafeCell` has the same in-memory representation as its inner + // type `T`. + ptr as *mut Src + } +} + +// SAFETY: `Unalign` promises to have `UnsafeCell`s covering the same byte +// ranges as `Inner = T`. +unsafe impl UnsafeCellsAgree for Unalign {} +// SAFETY: `Unalign` promises to have `UnsafeCell`s covering the same byte +// ranges as `Inner = T`. +unsafe impl UnsafeCellsAgree> for T {} + +unsafe impl TransmuteFrom for Src::WithInner> where + Src::Inner: Sized +{ +} +unsafe impl TransmuteFrom>> for Src where + Src::Inner: Sized +{ +} + +unsafe impl TransmuteFromAlignment + for Unalign +{ +} +unsafe impl TransmuteFromAlignment, A, Unknown, BecauseUnchanged> + for Src +{ +} + +unsafe impl CastFrom for Unalign { + fn cast_from(ptr: *mut Src) -> *mut Unalign { + // SAFETY: `.cast()` preserves address and provenance. Since + // `Unalign` has the same size as `T`, it also preserves size. + ptr.cast() + } +} + +unsafe impl CastFrom> for Src { + fn cast_from(ptr: *mut Unalign) -> *mut Src { + // SAFETY: `.cast()` preserves address and provenance. Since + // `Unalign` has the same size as `T`, it also preserves size. + ptr.cast() + } +} diff --git a/src/ref.rs b/src/ref.rs index 5a01b01442..153b4e1d3b 100644 --- a/src/ref.rs +++ b/src/ref.rs @@ -624,7 +624,7 @@ where let ptr = Ptr::from_ref(b.into_byte_slice()) .try_cast_into_no_leftover::(None) .expect("zerocopy internal error: into_ref should be infallible"); - let ptr = ptr.bikeshed_recall_valid(); + let ptr = ptr.transmute(); ptr.as_ref() } } @@ -658,7 +658,7 @@ where let ptr = Ptr::from_mut(b.into_byte_slice_mut()) .try_cast_into_no_leftover::(None) .expect("zerocopy internal error: into_ref should be infallible"); - let ptr = ptr.bikeshed_recall_valid(); + let ptr = ptr.bikeshed_recall_valid::<(BecauseRead, BecauseExclusive)>(); ptr.as_mut() } } @@ -770,7 +770,7 @@ where let ptr = Ptr::from_ref(b.deref()) .try_cast_into_no_leftover::(None) .expect("zerocopy internal error: Deref::deref should be infallible"); - let ptr = ptr.bikeshed_recall_valid(); + let ptr = ptr.transmute(); ptr.as_ref() } } @@ -799,7 +799,7 @@ where let ptr = Ptr::from_mut(b.deref_mut()) .try_cast_into_no_leftover::(None) .expect("zerocopy internal error: DerefMut::deref_mut should be infallible"); - let ptr = ptr.bikeshed_recall_valid(); + let ptr = ptr.bikeshed_recall_valid::<(BecauseRead, BecauseExclusive)>(); ptr.as_mut() } } diff --git a/src/util/macro_util.rs b/src/util/macro_util.rs index 4a7af46962..817dc36142 100644 --- a/src/util/macro_util.rs +++ b/src/util/macro_util.rs @@ -25,8 +25,11 @@ use core::mem::{self, ManuallyDrop}; use core::ptr::{self, NonNull}; use crate::{ - pointer::invariant::{self, BecauseExclusive, BecauseImmutable, Invariants, Valid}, - FromBytes, Immutable, IntoBytes, Ptr, TryFromBytes, Unalign, ValidityError, + pointer::{ + invariant::{self, Valid}, + transmute::{CastFrom, SizeGtEq, TransmuteFrom}, + }, + FromBytes, Immutable, IntoBytes, Ptr, TryFromBytes, ValidityError, }; /// Projects the type of the field at `Index` in `Self`. @@ -512,76 +515,6 @@ pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( unsafe { &mut *dst } } -/// Is a given source a valid instance of `Dst`? -/// -/// If so, returns `src` casted to a `Ptr`. Otherwise returns `None`. -/// -/// # Safety -/// -/// Unsafe code may assume that, if `try_cast_or_pme(src)` returns `Some`, -/// `*src` is a bit-valid instance of `Dst`, and that the size of `Src` is -/// greater than or equal to the size of `Dst`. -/// -/// # Panics -/// -/// `try_cast_or_pme` may either produce a post-monomorphization error or a -/// panic if `Dst` not the same size as `Src`. Otherwise, `try_cast_or_pme` -/// panics under the same circumstances as [`is_bit_valid`]. -/// -/// [`is_bit_valid`]: TryFromBytes::is_bit_valid -#[doc(hidden)] -#[inline] -fn try_cast_or_pme( - src: Ptr<'_, Valid, I>, -) -> Result< - Ptr<'_, Valid, (I::Aliasing, invariant::Unknown)>, - ValidityError, I>, Dst>, -> -where - // TODO(#2226): There should be a `Src: FromBytes` bound here, but doing so - // requires deeper surgery. - Src: IntoBytes + invariant::Read, - Dst: TryFromBytes + invariant::Read, - I: Invariants, - I::Aliasing: invariant::Reference, -{ - static_assert!(Src, Dst => mem::size_of::() == mem::size_of::()); - - // SAFETY: This is a pointer cast, satisfying the following properties: - // - `p as *mut Dst` addresses a subset of the `bytes` addressed by `src`, - // because we assert above that the size of `Dst` equal to the size of - // `Src`. - // - `p as *mut Dst` is a provenance-preserving cast - #[allow(clippy::as_conversions)] - let c_ptr = unsafe { src.cast_unsized(|p| p as *mut Dst) }; - - // SAFETY: `c_ptr` is derived from `src` which is `IntoBytes`. By - // invariant on `IntoByte`s, `c_ptr`'s referent consists entirely of - // initialized bytes. - let c_ptr = unsafe { c_ptr.assume_initialized() }; - - match c_ptr.try_into_valid() { - Ok(ptr) => Ok(ptr), - Err(err) => { - // Re-cast `Ptr` to `Ptr`. - let ptr = err.into_src(); - // SAFETY: This is a pointer cast, satisfying the following - // properties: - // - `p as *mut Src` addresses a subset of the `bytes` addressed by - // `ptr`, because we assert above that the size of `Dst` is equal - // to the size of `Src`. - // - `p as *mut Src` is a provenance-preserving cast - #[allow(clippy::as_conversions)] - let ptr = unsafe { ptr.cast_unsized(|p| p as *mut Src) }; - // SAFETY: `ptr` is `src`, and has the same alignment invariant. - let ptr = unsafe { ptr.assume_alignment::() }; - // SAFETY: `ptr` is `src` and has the same validity invariant. - let ptr = unsafe { ptr.assume_validity::() }; - Err(ValidityError::new(ptr.unify_invariants())) - } - } -} - /// Attempts to transmute `Src` into `Dst`. /// /// A helper for `try_transmute!`. @@ -599,19 +532,30 @@ where Src: IntoBytes, Dst: TryFromBytes, { - let mut src = ManuallyDrop::new(src); - let ptr = Ptr::from_mut(&mut src); - // Wrapping `Dst` in `Unalign` ensures that this cast does not fail due to - // alignment requirements. - match try_cast_or_pme::<_, ManuallyDrop>, _, BecauseExclusive>(ptr) { - Ok(ptr) => { - let dst = ptr.bikeshed_recall_aligned().as_mut(); - // SAFETY: By shadowing `dst`, we ensure that `dst` is not re-used - // after taking its inner value. - let dst = unsafe { ManuallyDrop::take(dst) }; - Ok(dst.into_inner()) - } - Err(_) => Err(ValidityError::new(ManuallyDrop::into_inner(src))), + static_assert!(Src, Dst => mem::size_of::() == mem::size_of::()); + + let mu_src = mem::MaybeUninit::new(src); + let mu_src_copy = unsafe { core::ptr::read(&mu_src) }; + // SAFETY: `MaybeUninit` has no validity constraints. + let mut mu_dst: mem::MaybeUninit = + unsafe { crate::util::transmute_unchecked(mu_src_copy) }; + + let ptr = Ptr::from_mut(&mut mu_dst); + + // SAFETY: Since `Src: IntoBytes`, and since `size_of::() == + // size_of::()` by the preceding assertion, all of `mu_dst`'s bytes are + // initialized. + let ptr = unsafe { ptr.assume_validity::() }; + + let ptr = ptr + .transmute::, invariant::Aligned, (crate::BecauseRead, _), _>(); + + if Dst::is_bit_valid(ptr.forget_aligned()) { + Ok(unsafe { mu_dst.assume_init() }) + } else { + // SAFETY: `mu_src` was constructed from `src` and never modified, so it + // is still bit-valid. + Err(ValidityError::new(unsafe { mu_src.assume_init() })) } } @@ -631,17 +575,47 @@ where pub fn try_transmute_ref(src: &Src) -> Result<&Dst, ValidityError<&Src, Dst>> where Src: IntoBytes + Immutable, - Dst: TryFromBytes + Immutable, + Dst: TryFromBytes + Immutable + CastFrom, { - match try_cast_or_pme::(Ptr::from_ref(src)) { + static_assert!(Src, Dst => mem::size_of::() <= mem::size_of::()); + + #[derive(IntoBytes, Immutable)] + #[repr(transparent)] + struct S(Src); + + #[derive(TryFromBytes, Immutable)] + #[repr(transparent)] + struct D(Dst); + + unsafe impl SizeGtEq> for S {} + + unsafe impl CastFrom> for D { + fn cast_from(ptr: *mut S) -> *mut D { + ptr.cast() + } + } + + let src: *const Src = src; + let src: &S = unsafe { &*src.cast() }; + + match Ptr::from_ref(src).try_transmute::>, _, _>() { Ok(ptr) => { static_assert!(Src, Dst => mem::align_of::() <= mem::align_of::()); // SAFETY: We have checked that `Dst` does not have a stricter - // alignment requirement than `Src`. + // alignment requirement than `Src`. Since `S` and `D` are + // `#[repr(transparent)]`, this also implies that `D` does not + // have a stricter alignment requirement than `S`. + // `Ptr::try_transmute` promises to return a pointer which addresses + // the same bytes as its receiver (`Ptr::from_ref(src)`), which was + // guaranteed to be validly-aligned for `S`, and thus its + // return value is validly-aligned for `D`. let ptr = unsafe { ptr.assume_alignment::() }; - Ok(ptr.as_ref()) + Ok(&ptr.as_ref().0) + } + Err(err) => { + let err = err.map_src(Ptr::as_ref).map_src(|src| &src.0); + Err(unsafe { err.with_dst::() }) } - Err(err) => Err(err.map_src(Ptr::as_ref)), } } @@ -661,17 +635,50 @@ where pub fn try_transmute_mut(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> where Src: FromBytes + IntoBytes, - Dst: TryFromBytes + IntoBytes, + Dst: TryFromBytes + IntoBytes + CastFrom, { - match try_cast_or_pme::(Ptr::from_mut(src)) { + static_assert!(Src, Dst => mem::size_of::() == mem::size_of::()); + + #[derive(FromBytes, IntoBytes)] + #[repr(transparent)] + struct S(Src); + + #[derive(TryFromBytes, IntoBytes)] + #[repr(transparent)] + struct D(Dst); + + unsafe impl SizeGtEq> for D {} + unsafe impl SizeGtEq> for S {} + + unsafe impl CastFrom> for D { + fn cast_from(ptr: *mut S) -> *mut D { + ptr.cast() + } + } + + let src: *mut Src = src; + let src: &mut S = unsafe { &mut *src.cast() }; + + match Ptr::from_mut(src) + .try_transmute::>, (crate::BecauseRead, _), (crate::BecauseRead, _)>() + { Ok(ptr) => { static_assert!(Src, Dst => mem::align_of::() <= mem::align_of::()); // SAFETY: We have checked that `Dst` does not have a stricter - // alignment requirement than `Src`. + // alignment requirement than `Src`. Since `S` and `D` are + // `#[repr(transparent)]`, this also implies that `D` does not + // have a stricter alignment requirement than `S`. + // `Ptr::try_transmute` promises to return a pointer which addresses + // the same bytes as its receiver (`Ptr::from_ref(src)`), which was + // guaranteed to be validly-aligned for `S`, and thus its + // return value is validly-aligned for `D`. let ptr = unsafe { ptr.assume_alignment::() }; - Ok(ptr.as_mut()) + Ok(&mut ptr.as_mut().0) + } + Err(err) => { + let err = err.map_src(Ptr::as_mut).map_src(|src| &mut src.0); + Err(unsafe { err.with_dst::() }) } - Err(err) => Err(err.map_src(Ptr::as_mut)), } } diff --git a/src/util/macros.rs b/src/util/macros.rs index ef12e7b1ab..9717b8f7a0 100644 --- a/src/util/macros.rs +++ b/src/util/macros.rs @@ -176,7 +176,7 @@ macro_rules! unsafe_impl { #[allow(clippy::as_conversions)] let candidate = unsafe { candidate.cast_unsized_unchecked::<$repr, _>(|p| p as *mut _) }; - let $candidate = candidate.bikeshed_recall_valid(); + let $candidate = candidate.bikeshed_recall_valid::<(BecauseRead, _)>(); $is_bit_valid } };