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/48] [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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] 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/48] 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/48] 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/48] [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/48] 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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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/48] [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 510c8fbe9e52881a279ed6e7817a5779d4fe30c7 Mon Sep 17 00:00:00 2001 From: Aditya-PS-05 Date: Thu, 31 Oct 2024 13:00:59 +0530 Subject: [PATCH 48/48] ci: enforce Pinned-Dependencies check in CI for PRs --- .github/workflows/scorecard.yml | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index a245b88c5f..68a3aa2a0a 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -18,9 +18,12 @@ on: # To guarantee Maintained check is occasionally updated. See # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained schedule: - - cron: '29 15 * * 6' + - cron: "29 15 * * 6" push: - branches: [ "main" ] + branches: ["main"] + # Add pull_request trigger to check PRs + pull_request: + branches: ["main"] # Declare default permissions as read only. permissions: read-all @@ -55,6 +58,24 @@ jobs: # - See https://github.com/ossf/scorecard-action#publishing-results. publish_results: true + # Enable only Pinned-Dependencies check + checks: pinned-dependencies + + # Add step to fail if Pinned-Dependencies check fails + - name: "Check Pinned Dependencies Score" + run: | + score=$(jq -r '.runs[0].results[] | select(.ruleId=="pinned-dependencies") | .score' results.sarif) + if (( $(echo "$score < 9" | bc -l) )); then + echo "Pinned-Dependencies check failed with score: $score" + echo "Please ensure all dependencies are pinned to specific versions." + echo "Common locations to check:" + echo "- GitHub Actions workflow files (.github/workflows/*.yml)" + echo "- Package manager files (package.json, requirements.txt, etc.)" + echo "- Docker images in Dockerfiles" + exit 1 + fi + echo "Pinned-Dependencies check passed with score: $score" + # 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" @@ -69,3 +90,11 @@ jobs: uses: github/codeql-action/upload-sarif@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 with: sarif_file: results.sarif + + # Reference to the main all-jobs-succeed job + all-jobs-succeed: + needs: [analysis] + if: false # This job never runs, it's just for dependency tracking + runs-on: ubuntu-latest + steps: + - run: echo "This job is never executed, it exists only for dependency tracking"