Skip to content

Commit

Permalink
Lower MSRV to 1.60
Browse files Browse the repository at this point in the history
Modify the way that certain memory safety properties are validated in
our `transmute!`, `transmute_ref!`, and `transmute_mut!` macros to allow
that code to compile on 1.60.

Makes progress on #554
  • Loading branch information
joshlf committed Oct 27, 2023
1 parent f47b4df commit f3b9e02
Show file tree
Hide file tree
Showing 79 changed files with 1,551 additions and 402 deletions.
12 changes: 6 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
[workspace]

[package]
edition = "2021"
edition = "2018"
name = "zerocopy"
version = "0.7.18"
version = "0.7.19"
authors = ["Joshua Liebow-Feeser <[email protected]>"]
description = "Utilities for zero-copy parsing and serialization"
license = "BSD-2-Clause OR Apache-2.0 OR MIT"
repository = "https://github.com/google/zerocopy"
rust-version = "1.61.0"
rust-version = "1.60.0"

exclude = [".*"]

Expand All @@ -45,7 +45,7 @@ simd-nightly = ["simd"]
__internal_use_only_features_that_work_on_stable = ["alloc", "derive", "simd"]

[dependencies]
zerocopy-derive = { version = "=0.7.18", path = "zerocopy-derive", optional = true }
zerocopy-derive = { version = "=0.7.19", path = "zerocopy-derive", optional = true }

[dependencies.byteorder]
version = "1.3"
Expand All @@ -56,7 +56,7 @@ optional = true
# 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.7.18", path = "zerocopy-derive" }
zerocopy-derive = { version = "=0.7.19", path = "zerocopy-derive" }

[dev-dependencies]
assert_matches = "1.5"
Expand All @@ -71,4 +71,4 @@ testutil = { path = "testutil" }
# CI test failures.
trybuild = { version = "=1.0.85", features = ["diff"] }
# In tests, unlike in production, zerocopy-derive is not optional
zerocopy-derive = { version = "=0.7.18", path = "zerocopy-derive" }
zerocopy-derive = { version = "=0.7.19", path = "zerocopy-derive" }
81 changes: 52 additions & 29 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2007,10 +2007,14 @@ macro_rules! transmute {
// This branch, though never taken, ensures that the type of `e` is
// `AsBytes` and that the type of this macro invocation expression
// is `FromBytes`.
const fn transmute<T: $crate::AsBytes, U: $crate::FromBytes>(_t: T) -> U {
loop {}
}
transmute(e)

struct AssertIsAsBytes<T: $crate::AsBytes>(T);
let _ = AssertIsAsBytes(e);

struct AssertIsFromBytes<U: $crate::FromBytes>(U);
#[allow(unused, unreachable_code)]
let u = AssertIsFromBytes(loop {});
u.0
} else {
// SAFETY: `core::mem::transmute` ensures that the type of `e` and
// the type of this macro invocation expression have the same size.
Expand Down Expand Up @@ -2092,10 +2096,14 @@ macro_rules! transmute_ref {
// `&T` where `T: 't + Sized + AsBytes`, that the type of this macro
// expression is `&U` where `U: 'u + Sized + FromBytes`, and that
// `'t` outlives `'u`.
const fn transmute<'u, 't: 'u, T: 't + Sized + $crate::AsBytes, U: 'u + Sized + $crate::FromBytes>(_t: &'t T) -> &'u U {
loop {}
}
transmute(e)

struct AssertIsAsBytes<'a, T: ::core::marker::Sized + $crate::AsBytes>(&'a T);
let _ = AssertIsAsBytes(e);

struct AssertIsFromBytes<'a, U: ::core::marker::Sized + $crate::FromBytes>(&'a U);
#[allow(unused, unreachable_code)]
let u = AssertIsFromBytes(loop {});
u.0
} else if false {
// This branch, though never taken, ensures that `size_of::<T>() ==
// size_of::<U>()` and that that `align_of::<T>() >=
Expand Down Expand Up @@ -2136,11 +2144,9 @@ macro_rules! transmute_ref {
// `core::mem::transmute`, this macro would not work in `std`
// contexts in which `core` was not manually imported. This is not a
// problem for 2018 edition crates.
unsafe {
// Clippy: It's okay to transmute a type to itself.
#[allow(clippy::useless_transmute)]
$crate::macro_util::core_reexport::mem::transmute(e)
}

// SAFETY: TODO
unsafe { $crate::macro_util::transmute_ref(e) }
}
}}
}
Expand Down Expand Up @@ -2191,22 +2197,41 @@ macro_rules! transmute_mut {
// because there's no way, in a generic context, to enforce that two
// types have the same size or alignment.

let e = $e;
// Ensure that the source type is a mutable reference.
let e = &mut *$e;

#[allow(unused, clippy::diverging_sub_expression)]
if false {
// This branch, though never taken, ensures that the type of `e` is
// `&mut T` where `T: 't + Sized + AsBytes + FromBytes`, that the
// `&mut T` where `T: 't + Sized + FromBytes + AsBytes`, that the
// type of this macro expression is `&mut U` where `U: 'u + Sized +
// AsBytes + FromBytes`.
fn transmute<'t, T, U>(_t: &'t mut T) -> &'t mut U
where
T: 't + Sized + $crate::AsBytes + $crate::FromBytes,
U: 't + Sized + $crate::AsBytes + $crate::FromBytes,
{
loop {}
// FromBytes + AsBytes`.

// We use immutable references here rather than mutable so that, if
// this macro is used in a const context (in which, as of this
// writing, mutable references are banned), the error message
// appears to originate in the user's code rather than in the
// internals of this macro.
struct AssertSrcIsFromBytes<'a, T: ::core::marker::Sized + $crate::FromBytes>(&'a T);
struct AssertSrcIsAsBytes<'a, T: ::core::marker::Sized + $crate::AsBytes>(&'a T);
struct AssertDstIsFromBytes<'a, T: ::core::marker::Sized + $crate::FromBytes>(&'a T);
struct AssertDstIsAsBytes<'a, T: ::core::marker::Sized + $crate::AsBytes>(&'a T);

if true {
let _ = AssertSrcIsFromBytes(&*e);
} else {
let _ = AssertSrcIsAsBytes(&*e);
}

if true {
#[allow(unused, unreachable_code)]
let u = AssertDstIsFromBytes(loop {});
&mut *u.0
} else {
#[allow(unused, unreachable_code)]
let u = AssertDstIsAsBytes(loop {});
&mut *u.0
}
transmute(e)
} else if false {
// This branch, though never taken, ensures that `size_of::<T>() ==
// size_of::<U>()` and that that `align_of::<T>() >=
Expand Down Expand Up @@ -2248,11 +2273,9 @@ macro_rules! transmute_mut {
// `core::mem::transmute`, this macro would not work in `std`
// contexts in which `core` was not manually imported. This is not a
// problem for 2018 edition crates.
unsafe {
// Clippy: It's okay to transmute a type to itself.
#[allow(clippy::useless_transmute)]
$crate::macro_util::core_reexport::mem::transmute(e)
}

// SAFETY: TODO
unsafe { $crate::macro_util::transmute_mut(e) }
}
}}
}
Expand Down Expand Up @@ -3654,7 +3677,7 @@ pub use alloc_support::*;
mod tests {
#![allow(clippy::unreadable_literal)]

use core::ops::Deref;
use core::{convert::TryInto as _, ops::Deref};

use static_assertions::assert_impl_all;

Expand Down
39 changes: 39 additions & 0 deletions src/macro_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,45 @@ macro_rules! assert_size_eq {
}};
}

/// Transmutes a reference of one type to a reference of another type.
///
/// # Safety
///
/// The caller must guarantee that:
/// - `Src: AsBytes`
/// - `Dst: FromBytes`
/// - `size_of::<Src>() == size_of::<Dst>()`
/// - `align_of::<Src>() >= align_of::<Dst>()`
#[inline(always)]
pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
src: &'src Src,
) -> &'dst Dst {
let src: *const Src = src;
let dst = src.cast::<Dst>();
// SAFETY: TODO
unsafe { &*dst }
}

/// Transmutes a mutable reference of one type to a mutable reference of another
/// type.
///
/// # Safety
///
/// The caller must guarantee that:
/// - `Src: FromBytes + AsBytes`
/// - `Dst: FromBytes + AsBytes`
/// - `size_of::<Src>() == size_of::<Dst>()`
/// - `align_of::<Src>() >= align_of::<Dst>()`
#[inline(always)]
pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
src: &'src mut Src,
) -> &'dst mut Dst {
let src: *mut Src = src;
let dst = src.cast::<Dst>();
// SAFETY: TODO
unsafe { &mut *dst }
}

pub mod core_reexport {
pub mod mem {
pub use core::mem::transmute;
Expand Down
4 changes: 2 additions & 2 deletions tests/ui-msrv/include_value_not_from_bytes.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ error[E0277]: the trait bound `UnsafeCell<u32>: FromBytes` is not satisfied
12 | include_value!("../../testdata/include_value/data");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `UnsafeCell<u32>`
|
note: required by a bound in `NOT_FROM_BYTES::transmute`
note: required by a bound in `AssertIsFromBytes`
--> tests/ui-msrv/include_value_not_from_bytes.rs:12:5
|
12 | include_value!("../../testdata/include_value/data");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `NOT_FROM_BYTES::transmute`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes`
= note: this error originates in the macro `$crate::transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
4 changes: 2 additions & 2 deletions tests/ui-msrv/transmute-dst-not-frombytes.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied
18 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0));
| ^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `NotZerocopy`
|
note: required by a bound in `DST_NOT_FROM_BYTES::transmute`
note: required by a bound in `AssertIsFromBytes`
--> tests/ui-msrv/transmute-dst-not-frombytes.rs:18:41
|
18 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0));
| ^^^^^^^^^^^^^^^^^^^ required by this bound in `DST_NOT_FROM_BYTES::transmute`
| ^^^^^^^^^^^^^^^^^^^ 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)
2 changes: 1 addition & 1 deletion tests/ui-msrv/transmute-mut-alignment-increase.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ error[E0658]: mutable references are not allowed in constants
|
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information

error[E0015]: cannot call non-const fn `INCREASE_ALIGNMENT::transmute::<[u8; 2], AU16>` in constants
error[E0015]: cannot call non-const fn `transmute_mut::<[u8; 2], AU16>` in constants
--> tests/ui-msrv/transmute-mut-alignment-increase.rs:19:39
|
19 | const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]);
Expand Down
2 changes: 1 addition & 1 deletion tests/ui-msrv/transmute-mut-const.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ error[E0658]: mutable references are not allowed in constants
|
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information

error[E0015]: cannot call non-const fn `CONST_CONTEXT::transmute::<[u8; 2], [u8; 2]>` in constants
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);
Expand Down
20 changes: 20 additions & 0 deletions tests/ui-msrv/transmute-mut-dst-not-a-reference.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,23 @@ error[E0308]: mismatched types
= note: expected type `usize`
found mutable reference `&mut _`
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)

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 _`
|
= note: expected type `usize`
found mutable reference `&mut _`
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)

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 _`
|
= note: expected type `usize`
found mutable reference `&mut _`
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
7 changes: 2 additions & 5 deletions tests/ui-msrv/transmute-mut-dst-not-asbytes.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@ error[E0277]: the trait bound `Dst: AsBytes` is not satisfied
24 | const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `Dst`
|
note: required by a bound in `DST_NOT_AS_BYTES::transmute`
note: required by a bound in `AssertDstIsAsBytes`
--> tests/ui-msrv/transmute-mut-dst-not-asbytes.rs:24:36
|
24 | const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^
| |
| required by a bound in this
| required by this bound in `DST_NOT_AS_BYTES::transmute`
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsAsBytes`
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
7 changes: 2 additions & 5 deletions tests/ui-msrv/transmute-mut-dst-not-frombytes.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@ error[E0277]: the trait bound `Dst: FromBytes` is not satisfied
24 | const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Dst`
|
note: required by a bound in `DST_NOT_FROM_BYTES::transmute`
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 a bound in this
| required by this bound in `DST_NOT_FROM_BYTES::transmute`
| ^^^^^^^^^^^^^^^^^^^^^^^^ 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)
38 changes: 31 additions & 7 deletions tests/ui-msrv/transmute-mut-dst-unsized.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,25 @@ 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 a bound in `DST_UNSIZED::transmute`
note: required by a bound in `AssertDstIsFromBytes`
--> 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 `DST_UNSIZED::transmute`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes`
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the 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 a bound in `AssertDstIsAsBytes`
--> 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 `AssertDstIsAsBytes`
= 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
Expand Down Expand Up @@ -44,11 +58,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 a bound in `std::intrinsics::transmute`
--> $RUST/core/src/intrinsics.rs
|
| pub fn transmute<T, U>(e: T) -> U;
| ^ required by this bound in `std::intrinsics::transmute`
note: required by a 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
Expand Down Expand Up @@ -78,3 +88,17 @@ note: required by a bound in `MaxAlignsOf`
| pub union MaxAlignsOf<T, U> {
| ^ 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-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 a bound in `transmute_mut`
--> src/macro_util.rs
|
| 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)
2 changes: 1 addition & 1 deletion tests/ui-msrv/transmute-mut-size-decrease.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ error[E0658]: mutable references are not allowed in constants
|
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information

error[E0015]: cannot call non-const fn `DECREASE_SIZE::transmute::<[u8; 2], u8>` in constants
error[E0015]: cannot call non-const fn `transmute_mut::<[u8; 2], u8>` in constants
--> tests/ui-msrv/transmute-mut-size-decrease.rs:17:32
|
17 | const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]);
Expand Down
2 changes: 1 addition & 1 deletion tests/ui-msrv/transmute-mut-size-increase.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ error[E0658]: mutable references are not allowed in constants
|
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information

error[E0015]: cannot call non-const fn `INCREASE_SIZE::transmute::<u8, [u8; 2]>` in constants
error[E0015]: cannot call non-const fn `transmute_mut::<u8, [u8; 2]>` in constants
--> tests/ui-msrv/transmute-mut-size-increase.rs:17:37
|
17 | const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8);
Expand Down
Loading

0 comments on commit f3b9e02

Please sign in to comment.