Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lower MSRV to 1.60 #561

Merged
merged 1 commit into from
Oct 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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" }
147 changes: 70 additions & 77 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 @@ -2080,22 +2084,24 @@ macro_rules! transmute_ref {
// because there's no way, in a generic context, to enforce that two
// types have the same size or alignment.

// Reborrow so that mutable references are supported too.
//
// In the rest of the comments, we refer only to `&T` since this
// reborrow ensures that `e` is an immutable reference.
let e = &*$e;
// Ensure that the source type is a reference or a mutable reference
// (note that mutable references are implicitly reborrowed here).
let e: &_ = $e;

#[allow(unused, clippy::diverging_sub_expression)]
if false {
// This branch, though never taken, ensures that the type of `e` is
// `&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 All @@ -2115,32 +2121,14 @@ macro_rules! transmute_ref {

&u
} else {
// SAFETY:
// - We know that the input and output types are both `Sized` (ie,
// thin) references thanks to the trait bounds on `transmute`
// above, and thanks to the fact that transmute takes and returns
// references.
// - We know that it is sound to view the target type of the input
// reference (`T`) as the target type of the output reference
// (`U`) because `T: AsBytes` and `U: FromBytes` (guaranteed by
// trait bounds on `transmute`) and because `size_of::<T>() ==
// size_of::<U>()` (guaranteed by the `assert_size_eq` above).
// - We know that alignment is not increased thanks to the
// `assert_align_gt_eq` above.
//
// We use this reexport of `core::mem::transmute` because we know it
// will always be available for crates which are using the 2015
// edition of Rust. By contrast, if we were to use
// `std::mem::transmute`, this macro would not work for such crates
// in `no_std` contexts, and if we were to use
// `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: For source type `Src` and destination type `Dst`:
// - We know that `Src: AsBytes` and `Dst: FromBytes` thanks to the
// uses of `AssertIsAsBytes` and `AssertIsFromBytes` above.
// - We know that `size_of::<Src>() == size_of::<Dst>()` thanks to
// the use of `assert_size_eq!` above.
// - We know that `align_of::<Src>() >= align_of::<Dst>()` thanks to
// the use of `assert_align_gt_eq!` above.
unsafe { $crate::macro_util::transmute_ref(e) }
}
}}
}
Expand Down Expand Up @@ -2191,22 +2179,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 All @@ -2226,33 +2233,16 @@ macro_rules! transmute_mut {

&mut u
} else {
// SAFETY:
// - We know that the input and output types are both `Sized` (ie,
// thin) references thanks to the trait bounds on `transmute`
// above, and thanks to the fact that transmute takes and returns
// references.
// - We know that it is sound to view the target type of the input
// reference (`T`) as the target type of the output reference
// (`U`) and visa versa because `T: AsBytes + FromBytes` and `U:
// AsBytes + FromBytes` (guaranteed by trait bounds on
// `transmute`) and because `size_of::<T>() == size_of::<U>()`
// (guaranteed by the `assert_size_eq` above).
// - We know that alignment is not increased thanks to the
// `assert_align_gt_eq` above.
//
// We use this reexport of `core::mem::transmute` because we know it
// will always be available for crates which are using the 2015
// edition of Rust. By contrast, if we were to use
// `std::mem::transmute`, this macro would not work for such crates
// in `no_std` contexts, and if we were to use
// `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: For source type `Src` and destination type `Dst`:
// - We know that `Src: FromBytes + AsBytes` and `Dst: FromBytes +
// AsBytes` thanks to the uses of `AssertSrcIsFromBytes`,
// `AssertSrcIsAsBytes`, `AssertDstIsFromBytes`, and
// `AssertDstIsAsBytes` above.
// - We know that `size_of::<Src>() == size_of::<Dst>()` thanks to
// the use of `assert_size_eq!` above.
// - We know that `align_of::<Src>() >= align_of::<Dst>()` thanks to
// the use of `assert_align_gt_eq!` above.
unsafe { $crate::macro_util::transmute_mut(e) }
}
}}
}
Expand Down Expand Up @@ -3479,6 +3469,8 @@ mod alloc_support {

#[cfg(test)]
mod tests {
use core::convert::TryFrom as _;

use super::*;

#[test]
Expand Down Expand Up @@ -3654,7 +3646,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 Expand Up @@ -4424,6 +4416,7 @@ mod tests {
panic!("PanicOnDrop::drop");
}
}
#[allow(clippy::let_unit_value)]
let _: () = transmute!(PanicOnDrop(()));

// Test that `transmute!` is legal in a const context.
Expand Down
60 changes: 60 additions & 0 deletions src/macro_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,66 @@ 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:
// - We know that it is sound to view the target type of the input reference
// (`Src`) as the target type of the output reference (`Dst`) because the
// caller has guaranteed that `Src: AsBytes`, `Dst: FromBytes`, and
// `size_of::<Src>() == size_of::<Dst>()`.
// - We know that there are no `UnsafeCell`s, and thus we don't have to
// worry about `UnsafeCell` overlap, because `Src: AsBytes` and `Dst:
// FromBytes` both forbid `UnsafeCell`s.
// - 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.
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:
// - We know that it is sound to view the target type of the input reference
// (`Src`) as the target type of the output reference (`Dst`) and
// vice-versa because the caller has guaranteed that `Src: FromBytes +
// AsBytes`, `Dst: FromBytes + AsBytes`, and `size_of::<Src>() ==
// size_of::<Dst>()`.
// - We know that there are no `UnsafeCell`s, and thus we don't have to
// worry about `UnsafeCell` overlap, because `Src: FromBytes + AsBytes`
// and `Dst: FromBytes + AsBytes` forbid `UnsafeCell`s.
// - 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.
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)
Loading