From da9b1874d83329a13f1aee8b16823df6ebf9d889 Mon Sep 17 00:00:00 2001 From: Christofer Nolander Date: Sun, 13 Oct 2024 06:06:43 +0200 Subject: [PATCH] add `track_caller` feature (#276) closes #68 --- Cargo.toml | 4 ++++ src/allocation.rs | 1 + src/checked.rs | 8 ++++++++ src/contiguous.rs | 2 ++ src/internal.rs | 10 ++++++++++ src/lib.rs | 42 ++++++++++++++++++++++++++---------------- 6 files changed, 51 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2362266..fbc8f73 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,9 @@ const_zeroed = [] # MSRV 1.75.0: support const `zeroed()` # Do not use if you can avoid it, because this is **unsound**!!!! unsound_ptr_pod_impl = [] +# MSRV 1.46.0: adds the `#[track_caller]` attribute to functions which may panic +track_caller = [] + # Enables all features that are both sound and supported on the latest stable # version of Rust, with the exception of `extern_crate_alloc` and # `extern_crate_std`. @@ -57,6 +60,7 @@ latest_stable_rust = [ "derive", "min_const_generics", "must_cast", + "track_caller", "wasm_simd", "zeroable_atomics", "zeroable_maybe_uninit", diff --git a/src/allocation.rs b/src/allocation.rs index 8c5ac80..817e23c 100644 --- a/src/allocation.rs +++ b/src/allocation.rs @@ -891,6 +891,7 @@ pub fn box_bytes_of(input: Box) -> BoxBytes { /// This is [`try_from_box_bytes`] but will panic on error and the input will be /// dropped. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub fn from_box_bytes( input: BoxBytes, ) -> Box { diff --git a/src/checked.rs b/src/checked.rs index c3b131e..05e0137 100644 --- a/src/checked.rs +++ b/src/checked.rs @@ -413,6 +413,7 @@ pub fn try_cast_slice_mut< /// /// This is [`try_from_bytes`] but will panic on error. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub fn from_bytes(s: &[u8]) -> &T { match try_from_bytes(s) { Ok(t) => t, @@ -426,6 +427,7 @@ pub fn from_bytes(s: &[u8]) -> &T { /// /// This is [`try_from_bytes_mut`] but will panic on error. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub fn from_bytes_mut(s: &mut [u8]) -> &mut T { match try_from_bytes_mut(s) { Ok(t) => t, @@ -438,6 +440,7 @@ pub fn from_bytes_mut(s: &mut [u8]) -> &mut T { /// ## Panics /// * This is like `try_pod_read_unaligned` but will panic on failure. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub fn pod_read_unaligned(bytes: &[u8]) -> T { match try_pod_read_unaligned(bytes) { Ok(t) => t, @@ -451,6 +454,7 @@ pub fn pod_read_unaligned(bytes: &[u8]) -> T { /// /// * This is like [`try_cast`], but will panic on a size mismatch. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub fn cast(a: A) -> B { match try_cast(a) { Ok(t) => t, @@ -464,6 +468,7 @@ pub fn cast(a: A) -> B { /// /// This is [`try_cast_mut`] but will panic on error. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub fn cast_mut< A: NoUninit + AnyBitPattern, B: NoUninit + CheckedBitPattern, @@ -482,6 +487,7 @@ pub fn cast_mut< /// /// This is [`try_cast_ref`] but will panic on error. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub fn cast_ref(a: &A) -> &B { match try_cast_ref(a) { Ok(t) => t, @@ -495,6 +501,7 @@ pub fn cast_ref(a: &A) -> &B { /// /// This is [`try_cast_slice`] but will panic on error. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub fn cast_slice(a: &[A]) -> &[B] { match try_cast_slice(a) { Ok(t) => t, @@ -508,6 +515,7 @@ pub fn cast_slice(a: &[A]) -> &[B] { /// /// This is [`try_cast_slice_mut`] but will panic on error. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub fn cast_slice_mut< A: NoUninit + AnyBitPattern, B: NoUninit + CheckedBitPattern, diff --git a/src/contiguous.rs b/src/contiguous.rs index 91308d0..0db3b48 100644 --- a/src/contiguous.rs +++ b/src/contiguous.rs @@ -118,6 +118,7 @@ pub unsafe trait Contiguous: Copy + 'static { /// This is undefined behavior regardless, so it could have been the nasal /// demons at that point anyway ;). #[inline] + #[cfg_attr(feature = "track_caller", track_caller)] fn from_integer(value: Self::Int) -> Option { // Guard against an illegal implementation of Contiguous. Annoyingly we // can't rely on `transmute` to do this for us (see below), but @@ -153,6 +154,7 @@ pub unsafe trait Contiguous: Copy + 'static { /// This is undefined behavior regardless, so it could have been the nasal /// demons at that point anyway ;). #[inline] + #[cfg_attr(feature = "track_caller", track_caller)] fn into_integer(self) -> Self::Int { // Guard against an illegal implementation of Contiguous. Annoyingly we // can't rely on `transmute` to do the size check for us (see diff --git a/src/internal.rs b/src/internal.rs index cbca509..9baeb4e 100644 --- a/src/internal.rs +++ b/src/internal.rs @@ -23,6 +23,7 @@ possibility code branch. #[cfg(not(target_arch = "spirv"))] #[cold] #[inline(never)] +#[cfg_attr(feature = "track_caller", track_caller)] pub(crate) fn something_went_wrong( _src: &str, _err: D, ) -> ! { @@ -75,6 +76,7 @@ pub(crate) unsafe fn bytes_of_mut(t: &mut T) -> &mut [u8] { /// /// This is [`try_from_bytes`] but will panic on error. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub(crate) unsafe fn from_bytes(s: &[u8]) -> &T { match try_from_bytes(s) { Ok(t) => t, @@ -88,6 +90,7 @@ pub(crate) unsafe fn from_bytes(s: &[u8]) -> &T { /// /// This is [`try_from_bytes_mut`] but will panic on error. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub(crate) unsafe fn from_bytes_mut(s: &mut [u8]) -> &mut T { match try_from_bytes_mut(s) { Ok(t) => t, @@ -115,6 +118,7 @@ pub(crate) unsafe fn try_pod_read_unaligned( /// ## Panics /// * This is like `try_pod_read_unaligned` but will panic on failure. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub(crate) unsafe fn pod_read_unaligned(bytes: &[u8]) -> T { match try_pod_read_unaligned(bytes) { Ok(t) => t, @@ -127,6 +131,7 @@ pub(crate) unsafe fn pod_read_unaligned(bytes: &[u8]) -> T { /// ## Panics /// * If `align` is not a power of two. This includes when `align` is zero. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub(crate) fn is_aligned_to(ptr: *const (), align: usize) -> bool { #[cfg(feature = "align_offset")] { @@ -186,6 +191,7 @@ pub(crate) unsafe fn try_from_bytes_mut( /// /// * This is like [`try_cast`](try_cast), but will panic on a size mismatch. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub(crate) unsafe fn cast(a: A) -> B { if size_of::() == size_of::() { unsafe { transmute!(a) } @@ -200,6 +206,7 @@ pub(crate) unsafe fn cast(a: A) -> B { /// /// This is [`try_cast_mut`] but will panic on error. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub(crate) unsafe fn cast_mut(a: &mut A) -> &mut B { if size_of::() == size_of::() && align_of::() >= align_of::() { // Plz mr compiler, just notice that we can't ever hit Err in this case. @@ -221,6 +228,7 @@ pub(crate) unsafe fn cast_mut(a: &mut A) -> &mut B { /// /// This is [`try_cast_ref`] but will panic on error. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub(crate) unsafe fn cast_ref(a: &A) -> &B { if size_of::() == size_of::() && align_of::() >= align_of::() { // Plz mr compiler, just notice that we can't ever hit Err in this case. @@ -242,6 +250,7 @@ pub(crate) unsafe fn cast_ref(a: &A) -> &B { /// /// This is [`try_cast_slice`] but will panic on error. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub(crate) unsafe fn cast_slice(a: &[A]) -> &[B] { match try_cast_slice(a) { Ok(b) => b, @@ -255,6 +264,7 @@ pub(crate) unsafe fn cast_slice(a: &[A]) -> &[B] { /// /// This is [`try_cast_slice_mut`] but will panic on error. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub(crate) unsafe fn cast_slice_mut(a: &mut [A]) -> &mut [B] { match try_cast_slice_mut(a) { Ok(b) => b, diff --git a/src/lib.rs b/src/lib.rs index a8cddfa..2d7f270 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -123,18 +123,20 @@ macro_rules! transmute { ($val:expr) => { ::core::mem::transmute_copy(&::core::mem::ManuallyDrop::new($val)) }; - // This arm is for use in const contexts, where the borrow required to use transmute_copy poses an issue - // since the compiler hedges that the type being borrowed could have interior mutability. - ($srcty:ty; $dstty:ty; $val:expr) => { - { - #[repr(C)] - union Transmute { - src: ::core::mem::ManuallyDrop, - dst: ::core::mem::ManuallyDrop, - } - ::core::mem::ManuallyDrop::into_inner(Transmute::<$srcty, $dstty> { src: ::core::mem::ManuallyDrop::new($val) }.dst) + // This arm is for use in const contexts, where the borrow required to use + // transmute_copy poses an issue since the compiler hedges that the type + // being borrowed could have interior mutability. + ($srcty:ty; $dstty:ty; $val:expr) => {{ + #[repr(C)] + union Transmute { + src: ::core::mem::ManuallyDrop, + dst: ::core::mem::ManuallyDrop, } - } + ::core::mem::ManuallyDrop::into_inner( + Transmute::<$srcty, $dstty> { src: ::core::mem::ManuallyDrop::new($val) } + .dst, + ) + }}; } /// A macro to implement marker traits for various simd types. @@ -210,12 +212,12 @@ pub use bytemuck_derive::{ /// The things that can go wrong when casting between [`Pod`] data forms. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum PodCastError { - /// You tried to cast a reference into a reference to a type with a higher alignment - /// requirement but the input reference wasn't aligned. + /// You tried to cast a reference into a reference to a type with a higher + /// alignment requirement but the input reference wasn't aligned. TargetAlignmentGreaterAndInputNotAligned, - /// If the element size of a slice changes, then the output slice changes length - /// accordingly. If the output slice wouldn't be a whole number of elements, - /// then the conversion fails. + /// If the element size of a slice changes, then the output slice changes + /// length accordingly. If the output slice wouldn't be a whole number of + /// elements, then the conversion fails. OutputSliceWouldHaveSlop, /// When casting an individual `T`, `&T`, or `&mut T` value the /// source size and destination size must be an exact match. @@ -262,6 +264,7 @@ pub fn bytes_of_mut(t: &mut T) -> &mut [u8] { /// /// This is like [`try_from_bytes`] but will panic on error. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub fn from_bytes(s: &[u8]) -> &T { unsafe { internal::from_bytes(s) } } @@ -272,6 +275,7 @@ pub fn from_bytes(s: &[u8]) -> &T { /// /// This is like [`try_from_bytes_mut`] but will panic on error. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub fn from_bytes_mut(s: &mut [u8]) -> &mut T { unsafe { internal::from_bytes_mut(s) } } @@ -298,6 +302,7 @@ pub fn try_pod_read_unaligned( /// ## Panics /// * This is like `try_pod_read_unaligned` but will panic on failure. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub fn pod_read_unaligned(bytes: &[u8]) -> T { unsafe { internal::pod_read_unaligned(bytes) } } @@ -332,6 +337,7 @@ pub fn try_from_bytes_mut( /// /// * This is like [`try_cast`], but will panic on a size mismatch. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub fn cast(a: A) -> B { unsafe { internal::cast(a) } } @@ -342,6 +348,7 @@ pub fn cast(a: A) -> B { /// /// This is [`try_cast_mut`] but will panic on error. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub fn cast_mut( a: &mut A, ) -> &mut B { @@ -354,6 +361,7 @@ pub fn cast_mut( /// /// This is [`try_cast_ref`] but will panic on error. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub fn cast_ref(a: &A) -> &B { unsafe { internal::cast_ref(a) } } @@ -364,6 +372,7 @@ pub fn cast_ref(a: &A) -> &B { /// /// This is [`try_cast_slice`] but will panic on error. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub fn cast_slice(a: &[A]) -> &[B] { unsafe { internal::cast_slice(a) } } @@ -374,6 +383,7 @@ pub fn cast_slice(a: &[A]) -> &[B] { /// /// This is [`try_cast_slice_mut`] but will panic on error. #[inline] +#[cfg_attr(feature = "track_caller", track_caller)] pub fn cast_slice_mut< A: NoUninit + AnyBitPattern, B: NoUninit + AnyBitPattern,