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

Make macros robust against never type fallback #1339

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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ zerocopy-panic-in-const = "1.57.0"
[package.metadata.ci]
# The versions of the stable and nightly compiler toolchains to use in CI.
pinned-stable = "1.78.0"
pinned-nightly = "nightly-2024-05-20"
pinned-nightly = "nightly-2024-05-21"

[package.metadata.docs.rs]
all-features = true
Expand Down
42 changes: 36 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4321,6 +4321,13 @@ macro_rules! transmute {
// to enforce this so long as the types are concrete.

let e = $e;

#[allow(unknown_lints)]
// This code's soundness depends upon the inferred types being the
// correct ones. This lint catches cases in which that behavior is
// implicitly violated. We have no reason to expect it to happen - none
// of this code diverges, producing the never type - but it's a hedge.
#[deny(never_type_fallback_flowing_into_unsafe)]
if false {
// This branch, though never taken, ensures that the type of `e` is
// `IntoBytes` and that the type of this macro invocation expression
Expand Down Expand Up @@ -4439,7 +4446,12 @@ macro_rules! transmute_ref {
// (note that mutable references are implicitly reborrowed here).
let e: &_ = $e;

#[allow(unused, clippy::diverging_sub_expression)]
#[allow(unused, unknown_lints, clippy::diverging_sub_expression)]
// This code's soundness depends upon the inferred types being the
// correct ones. This lint catches cases in which that behavior is
// implicitly violated. We have no reason to expect it to happen - none
// of this code diverges, producing the never type - but it's a hedge.
#[deny(never_type_fallback_flowing_into_unsafe)]
if false {
// This branch, though never taken, ensures that the type of `e` is
// `&T` where `T: 't + Sized + IntoBytes + Immutable`, that the type of
Expand Down Expand Up @@ -4484,8 +4496,11 @@ macro_rules! transmute_ref {
// value returned from this branch.
let u;

$crate::assert_size_eq!(t, u);
$crate::assert_align_gt_eq!(t, u);
// SAFETY: This branch is never executed.
unsafe { $crate::unsafe_assert_size_eq!(t, u) };

// SAFETY: This branch is never executed.
unsafe { $crate::unsafe_assert_align_gt_eq!(t, u) };

&u
} else {
Expand Down Expand Up @@ -4586,7 +4601,12 @@ macro_rules! transmute_mut {
// Ensure that the source type is a mutable reference.
let e: &mut _ = $e;

#[allow(unused, clippy::diverging_sub_expression)]
#[allow(unused, unknown_lints, clippy::diverging_sub_expression)]
// This code's soundness depends upon the inferred types being the
// correct ones. This lint catches cases in which that behavior is
// implicitly violated. We have no reason to expect it to happen - none
// of this code diverges, producing the never type - but it's a hedge.
#[deny(never_type_fallback_flowing_into_unsafe)]
if false {
// This branch, though never taken, ensures that the type of `e` is
// `&mut T` where `T: 't + Sized + FromBytes + IntoBytes + Immutable`
Expand Down Expand Up @@ -4640,8 +4660,11 @@ macro_rules! transmute_mut {
// the value returned from this branch.
let u;

$crate::assert_size_eq!(t, u);
$crate::assert_align_gt_eq!(t, u);
// SAFETY: This branch is never executed.
unsafe { $crate::unsafe_assert_size_eq!(t, u) };

// SAFETY: This branch is never executed.
unsafe { $crate::unsafe_assert_align_gt_eq!(t, u) };

&mut u
} else {
Expand Down Expand Up @@ -4710,6 +4733,13 @@ macro_rules! try_transmute {
// to enforce this so long as the types are concrete.

let e = $e;

#[allow(unknown_lints)]
// This code's soundness depends upon the inferred types being the
// correct ones. This lint catches cases in which that behavior is
// implicitly violated. We have no reason to expect it to happen - none
// of this code diverges, producing the never type - but it's a hedge.
#[deny(never_type_fallback_flowing_into_unsafe)]
if false {
// Check that the sizes of the source and destination types are
// equal.
Expand Down
92 changes: 45 additions & 47 deletions src/macro_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,63 +299,61 @@ macro_rules! union_has_padding {
};
}

/// Does `t` have alignment greater than or equal to `u`? If not, this macro
/// produces a compile error. It must be invoked in a dead codepath. This is
/// used in `transmute_ref!` and `transmute_mut!`.
/// Does `$t` have alignment greater than or equal to `$u`? If not, this macro
/// produces a compile error. It must be invoked in a dead codepath.
///
/// # Safety
///
/// The code generated by this macro must never be executed.
#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
#[macro_export]
macro_rules! assert_align_gt_eq {
macro_rules! unsafe_assert_align_gt_eq {
($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 {
// The type wildcard in this bound is inferred to be `T` because
// `align_of.into_t()` is assigned to `t` (which has type `T`).
let align_of: $crate::macro_util::AlignOf<_> = unreachable!();
$t = align_of.into_t();
// `max_aligns` is inferred to have type `MaxAlignsOf<T, U>` because
// of the inferred types of `t` and `u`.
let mut max_aligns = $crate::macro_util::MaxAlignsOf::new($t, $u);

// This transmute will only compile successfully if
// `align_of::<T>() == max(align_of::<T>(), align_of::<U>())` - in
// other words, if `align_of::<T>() >= align_of::<U>()`.
//
// SAFETY: This code is never run.
max_aligns = unsafe {
// Clippy: We can't annotate the types; this macro is designed
// to infer the types from the calling context.
#[allow(clippy::missing_transmute_annotations)]
$crate::macro_util::core_reexport::mem::transmute(align_of)
};
} else {
loop {}
}

// The type wildcard in this bound is inferred to be `T` because
// `align_of.into_t()` is assigned to `$t` (which has type `T`).
let align_of: $crate::macro_util::AlignOf<_> = unreachable!();
$t = align_of.into_t();
// `max_aligns` is inferred to have type `MaxAlignsOf<T, U>` because of
// the inferred types of `$t` and `$u`.
let mut max_aligns = $crate::macro_util::MaxAlignsOf::new($t, $u);

// This transmute will only compile successfully if `align_of::<T>() ==
// max(align_of::<T>(), align_of::<U>())` - in other words, if
// `align_of::<T>() >= align_of::<U>()`.
//
// SAFETY: The caller promises that this code is never run.
max_aligns = {
// Clippy: We can't annotate the types; this macro is designed
// to infer the types from the calling context.
#[allow(clippy::missing_transmute_annotations)]
$crate::macro_util::core_reexport::mem::transmute(align_of)
};
}};
}

/// Do `t` and `u` have the same size? If not, this macro produces a compile
/// error. It must be invoked in a dead codepath. This is used in
/// `transmute_ref!` and `transmute_mut!`.
/// Do `$t` and `$u` have the same size? If not, this macro produces a compile
/// error. It must be invoked in a dead codepath.
///
/// # Safety
///
/// The code generated by this macro must never be executed.
#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
#[macro_export]
macro_rules! assert_size_eq {
($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 {
// SAFETY: This code is never run.
$u = unsafe {
// Clippy:
// - It's okay to transmute a type to itself.
// - We can't annotate the types; this macro is designed to
// infer the types from the calling context.
#[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)]
$crate::macro_util::core_reexport::mem::transmute($t)
};
} else {
loop {}
}
macro_rules! unsafe_assert_size_eq {
($t:ident, $u:ident) => {{
// Clippy:
// - It's okay to transmute a type to itself.
// - We can't annotate the types; this macro is designed to infer the
// types from the types of `$t` and `$u`.
//
// SAFETY: The caller promises that this code is never executed.
$u = {
#[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)]
$crate::macro_util::core_reexport::mem::transmute($t)
};
}};
}

Expand Down
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 @@ -6,7 +6,7 @@ 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::unsafe_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
Expand Down
4 changes: 2 additions & 2 deletions tests/ui-msrv/transmute-mut-dst-generic.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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::unsafe_assert_size_eq` (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
Expand All @@ -16,4 +16,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-
|
= note: source type: `AlignOf<u8>` (8 bits)
= note: target type: `MaxAlignsOf<u8, T>` (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::unsafe_assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
8 changes: 4 additions & 4 deletions tests/ui-msrv/transmute-mut-dst-unsized.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ 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)
= note: this error originates in the macro `$crate::unsafe_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
Expand All @@ -49,7 +49,7 @@ note: required by a bound in `transmute`
|
| pub fn transmute<T, U>(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::unsafe_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
Expand All @@ -63,7 +63,7 @@ note: required by `MaxAlignsOf::<T, U>::new`
|
| pub fn new(_t: T, _u: U) -> MaxAlignsOf<T, U> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= 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::unsafe_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
Expand All @@ -77,7 +77,7 @@ 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)
= note: this error originates in the macro `$crate::unsafe_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
Expand Down
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 @@ -6,7 +6,7 @@ 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::unsafe_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
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 @@ -6,7 +6,7 @@ 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::unsafe_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
Expand Down
4 changes: 2 additions & 2 deletions tests/ui-msrv/transmute-mut-src-dst-generic.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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::unsafe_assert_size_eq` (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
Expand All @@ -16,4 +16,4 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-
|
= note: source type: `AlignOf<T>` (size can vary because of T)
= note: target type: `MaxAlignsOf<T, U>` (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::unsafe_assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
Loading
Loading