Skip to content

Commit

Permalink
Make macros robust against never type fallback
Browse files Browse the repository at this point in the history
  • Loading branch information
joshlf committed May 22, 2024
1 parent 419d89e commit 11be39e
Show file tree
Hide file tree
Showing 62 changed files with 338 additions and 208 deletions.
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

0 comments on commit 11be39e

Please sign in to comment.