Skip to content

Relax NoCell bound on transmute_mut! #1049

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

Closed
wants to merge 1 commit into from
Closed
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
42 changes: 21 additions & 21 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4550,9 +4550,10 @@ macro_rules! transmute_ref {
/// another type of the same size.
///
/// The expression `$e` must have a concrete type, `&mut T`, where `T: Sized +
/// IntoBytes`. The `transmute_mut!` expression must also have a concrete type,
/// `&mut U` (`U` is inferred from the calling context), where `U: Sized +
/// FromBytes`. It must be the case that `align_of::<T>() >= align_of::<U>()`.
/// FromBytes + IntoBytes`. The `transmute_mut!` expression must also have a
/// concrete type, `&mut U` (`U` is inferred from the calling context), where
/// `U: Sized + FromBytes + IntoBytes`. It must be the case that
/// `align_of::<T>() >= align_of::<U>()`.
///
/// The lifetime of the input type, `&mut T`, must be the same as or outlive the
/// lifetime of the output type, `&mut U`.
Expand Down Expand Up @@ -4617,9 +4618,9 @@ macro_rules! transmute_mut {
#[allow(unused, clippy::diverging_sub_expression)]
if false {
// This branch, though never taken, ensures that the type of `e` is
// `&mut T` where `T: 't + Sized + FromBytes + IntoBytes + NoCell`
// and that the type of this macro expression is `&mut U` where `U:
// 'u + Sized + FromBytes + IntoBytes + NoCell`.
// `&mut T` where `T: 't + Sized + FromBytes + IntoBytes` and that
// the type of this macro expression is `&mut U` where `U: 'u +
// Sized + FromBytes + IntoBytes`.

// We use immutable references here rather than mutable so that, if
// this macro is used in a const context (in which, as of this
Expand All @@ -4629,20 +4630,16 @@ macro_rules! transmute_mut {
struct AssertSrcIsSized<'a, T: ::core::marker::Sized>(&'a T);
struct AssertSrcIsFromBytes<'a, T: ?::core::marker::Sized + $crate::FromBytes>(&'a T);
struct AssertSrcIsIntoBytes<'a, T: ?::core::marker::Sized + $crate::IntoBytes>(&'a T);
struct AssertSrcIsNoCell<'a, T: ?::core::marker::Sized + $crate::NoCell>(&'a T);
struct AssertDstIsSized<'a, T: ::core::marker::Sized>(&'a T);
struct AssertDstIsFromBytes<'a, T: ?::core::marker::Sized + $crate::FromBytes>(&'a T);
struct AssertDstIsIntoBytes<'a, T: ?::core::marker::Sized + $crate::IntoBytes>(&'a T);
struct AssertDstIsNoCell<'a, T: ?::core::marker::Sized + $crate::NoCell>(&'a T);

if true {
let _ = AssertSrcIsSized(&*e);
} else if true {
let _ = AssertSrcIsFromBytes(&*e);
} else if true {
let _ = AssertSrcIsIntoBytes(&*e);
} else {
let _ = AssertSrcIsNoCell(&*e);
let _ = AssertSrcIsIntoBytes(&*e);
}

if true {
Expand All @@ -4653,13 +4650,9 @@ macro_rules! transmute_mut {
#[allow(unused, unreachable_code)]
let u = AssertDstIsFromBytes(loop {});
&mut *u.0
} else if true {
#[allow(unused, unreachable_code)]
let u = AssertDstIsIntoBytes(loop {});
&mut *u.0
} else {
#[allow(unused, unreachable_code)]
let u = AssertDstIsNoCell(loop {});
let u = AssertDstIsIntoBytes(loop {});
&mut *u.0
}
} else if false {
Expand All @@ -4682,11 +4675,10 @@ macro_rules! transmute_mut {
&mut u
} else {
// SAFETY: For source type `Src` and destination type `Dst`:
// - We know that `Src: FromBytes + IntoBytes + NoCell` and `Dst:
// FromBytes + IntoBytes + NoCell` thanks to the uses of
// `AssertSrcIsFromBytes`, `AssertSrcIsIntoBytes`,
// `AssertSrcIsNoCell`, `AssertDstIsFromBytes`,
// `AssertDstIsIntoBytes`, and `AssertDstIsNoCell` above.
// - We know that `Src: FromBytes + IntoBytes` and `Dst: FromBytes +
// IntoBytes` thanks to the uses of `AssertSrcIsFromBytes`,
// `AssertSrcIsIntoBytes`, `AssertDstIsFromBytes`, and
// `AssertDstIsIntoBytes` 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
Expand Down Expand Up @@ -7418,6 +7410,14 @@ mod tests {
#[allow(clippy::useless_transmute)]
let y: &u8 = transmute_mut!(&mut x);
assert_eq!(*y, 0);

// Test that the referents can contain `UnsafeCell`s.
let mut src = AtomicU8::new(42);
{
let dst: &mut AtomicI8 = transmute_mut!(&mut src);
*dst.get_mut() += 1;
}
assert_eq!(src.into_inner(), 43);
}

#[test]
Expand Down
9 changes: 4 additions & 5 deletions src/macro_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,8 +378,8 @@ pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
/// # Safety
///
/// The caller must guarantee that:
/// - `Src: FromBytes + IntoBytes + NoCell`
/// - `Dst: FromBytes + IntoBytes + NoCell`
/// - `Src: FromBytes + IntoBytes`
/// - `Dst: FromBytes + IntoBytes`
/// - `size_of::<Src>() == size_of::<Dst>()`
/// - `align_of::<Src>() >= align_of::<Dst>()`
// TODO(#686): Consider removing the `NoCell` requirement.
Expand All @@ -395,9 +395,8 @@ pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
// vice-versa because the caller has guaranteed that `Src: FromBytes +
// IntoBytes`, `Dst: FromBytes + IntoBytes`, 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: NoCell`
// and `Dst: NoCell`.
// - We know that `src` is exclusively aliased, so there are no other active
// references that could be used to create a data race with `&mut 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.
Expand Down
10 changes: 0 additions & 10 deletions tests/ui-msrv/transmute-mut-dst-not-a-reference.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,3 @@ 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)
21 changes: 17 additions & 4 deletions tests/ui-msrv/transmute-mut-dst-not-nocell.stderr
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
error[E0277]: the trait bound `Dst: NoCell` is not satisfied
--> tests/ui-msrv/transmute-mut-dst-not-nocell.rs:24:35
error[E0658]: mutable references are not allowed in constants
--> tests/ui-msrv/transmute-mut-dst-not-nocell.rs:24:50
|
24 | const DST_NOT_NO_CELL: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NoCell` is not implemented for `Dst`
| ^^^^^^^^
|
note: required by `AssertDstIsNoCell`
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information

error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
--> tests/ui-msrv/transmute-mut-dst-not-nocell.rs:24:35
|
24 | const DST_NOT_NO_CELL: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= 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-dst-not-nocell.rs:24:55
|
24 | const DST_NOT_NO_CELL: &mut Dst = transmute_mut!(&mut Src);
| --------------------^^^-
| | |
| | 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`
28 changes: 14 additions & 14 deletions tests/ui-msrv/transmute-mut-src-not-nocell.stderr
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
error[E0277]: the trait bound `Src: NoCell` is not satisfied
--> tests/ui-msrv/transmute-mut-src-not-nocell.rs:24:35
error[E0658]: mutable references are not allowed in constants
--> tests/ui-msrv/transmute-mut-src-not-nocell.rs:24:50
|
24 | const SRC_NOT_NO_CELL: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NoCell` is not implemented for `Src`
| ^^^^^^^^
|
note: required by `AssertSrcIsNoCell`
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information

error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
--> tests/ui-msrv/transmute-mut-src-not-nocell.rs:24:35
|
24 | const SRC_NOT_NO_CELL: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= 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: NoCell` is not satisfied
--> tests/ui-msrv/transmute-mut-src-not-nocell.rs:24:35
error[E0716]: temporary value dropped while borrowed
--> tests/ui-msrv/transmute-mut-src-not-nocell.rs:24:55
|
24 | const SRC_NOT_NO_CELL: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NoCell` is not implemented for `Src`
|
note: required by a bound in `AssertSrcIsNoCell`
--> tests/ui-msrv/transmute-mut-src-not-nocell.rs:24:35
|
24 | const SRC_NOT_NO_CELL: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsNoCell`
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
| --------------------^^^-
| | |
| | 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`
10 changes: 0 additions & 10 deletions tests/ui-nightly/transmute-mut-dst-not-a-reference.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,6 @@ error[E0308]: mismatched types
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-nightly/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-nightly/transmute-mut-dst-not-a-reference.rs:17:36
|
Expand Down
4 changes: 2 additions & 2 deletions tests/ui-nightly/transmute-mut-dst-not-nocell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ use zerocopy::transmute_mut;

fn main() {}

#[derive(zerocopy::FromBytes, zerocopy::IntoBytes, zerocopy::NoCell)]
#[derive(zerocopy::FromBytes, zerocopy::IntoBytes)]
#[repr(C)]
struct Src;

#[derive(zerocopy::FromBytes, zerocopy::IntoBytes)]
#[repr(C)]
struct Dst;

// `transmute_mut` requires that the destination type implements `NoCell`
// `transmute_mut` des not require that the destination type implements `NoCell`
const DST_NOT_NO_CELL: &mut Dst = transmute_mut!(&mut Src);
28 changes: 10 additions & 18 deletions tests/ui-nightly/transmute-mut-dst-not-nocell.stderr
Original file line number Diff line number Diff line change
@@ -1,25 +1,17 @@
error[E0277]: the trait bound `Dst: NoCell` is not satisfied
--> tests/ui-nightly/transmute-mut-dst-not-nocell.rs:24:35
error[E0658]: mutable references are not allowed in constants
--> tests/ui-nightly/transmute-mut-dst-not-nocell.rs:24:50
|
24 | const DST_NOT_NO_CELL: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^
| |
| the trait `NoCell` is not implemented for `Dst`
| required by a bound introduced by this call
| ^^^^^^^^
|
= help: the following other types implement trait `NoCell`:
bool
char
isize
i8
i16
i32
i64
i128
and $N others
note: required by a bound in `AssertDstIsNoCell`
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable

error[E0015]: cannot call non-const fn `transmute_mut::<'_, '_, Src, Dst>` in constants
--> tests/ui-nightly/transmute-mut-dst-not-nocell.rs:24:35
|
24 | const DST_NOT_NO_CELL: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsNoCell`
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= 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)
4 changes: 2 additions & 2 deletions tests/ui-nightly/transmute-mut-src-not-nocell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ fn main() {}
#[repr(C)]
struct Src;

#[derive(zerocopy::FromBytes, zerocopy::IntoBytes, zerocopy::NoCell)]
#[derive(zerocopy::FromBytes, zerocopy::IntoBytes)]
#[repr(C)]
struct Dst;

// `transmute_mut` requires that the source type implements `NoCell`
// `transmute_mut` does not require that the source type implements `NoCell`
const SRC_NOT_NO_CELL: &mut Dst = transmute_mut!(&mut Src);
47 changes: 8 additions & 39 deletions tests/ui-nightly/transmute-mut-src-not-nocell.stderr
Original file line number Diff line number Diff line change
@@ -1,48 +1,17 @@
error[E0277]: the trait bound `Src: NoCell` is not satisfied
--> tests/ui-nightly/transmute-mut-src-not-nocell.rs:24:35
error[E0658]: mutable references are not allowed in constants
--> tests/ui-nightly/transmute-mut-src-not-nocell.rs:24:50
|
24 | const SRC_NOT_NO_CELL: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^
| |
| the trait `NoCell` is not implemented for `Src`
| required by a bound introduced by this call
| ^^^^^^^^
|
= help: the following other types implement trait `NoCell`:
bool
char
isize
i8
i16
i32
i64
i128
and $N others
note: required by a bound in `AssertSrcIsNoCell`
--> tests/ui-nightly/transmute-mut-src-not-nocell.rs:24:35
|
24 | const SRC_NOT_NO_CELL: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsNoCell`
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable

error[E0277]: the trait bound `Src: NoCell` is not satisfied
error[E0015]: cannot call non-const fn `transmute_mut::<'_, '_, Src, Dst>` in constants
--> tests/ui-nightly/transmute-mut-src-not-nocell.rs:24:35
|
24 | const SRC_NOT_NO_CELL: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NoCell` is not implemented for `Src`
|
= help: the following other types implement trait `NoCell`:
bool
char
isize
i8
i16
i32
i64
i128
and $N others
note: required by a bound in `AssertSrcIsNoCell`
--> tests/ui-nightly/transmute-mut-src-not-nocell.rs:24:35
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
24 | const SRC_NOT_NO_CELL: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsNoCell`
= 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)
10 changes: 0 additions & 10 deletions tests/ui-stable/transmute-mut-dst-not-a-reference.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,6 @@ error[E0308]: mismatched types
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-stable/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-stable/transmute-mut-dst-not-a-reference.rs:17:36
|
Expand Down
Loading