Skip to content

Commit adf39cc

Browse files
committed
Improve safety
1 parent 8e6fa42 commit adf39cc

File tree

2 files changed

+48
-9
lines changed

2 files changed

+48
-9
lines changed

utils/zerofrom/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub use crate::zero_from::ZeroFrom;
3838
#[cfg(feature = "alloc")]
3939
#[doc(hidden)] // for macros
4040
pub mod internal {
41+
pub use crate::zf_transparent::cast_transparent_box;
4142
pub use alloc::boxed::Box;
4243
pub use alloc::rc::Rc;
43-
pub use crate::zf_transparent::cast_transparent_box;
4444
}

utils/zerofrom/src/zf_transparent.rs

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ use alloc::boxed::Box;
1010
///
1111
/// # Safety
1212
///
13-
/// `Outer` is `repr(transparent)` and has one non-zero-sized field
14-
/// of type `Inner`.
13+
/// `Outer` is `repr(transparent)` and has one non-zero-sized field of type `Inner`.
14+
///
15+
/// Suggestion: explicitly setting the generic parameters to two types satisfying this invariant
16+
/// makes the fn safe to call.
1517
#[cfg(feature = "alloc")]
1618
#[inline(always)]
17-
pub unsafe fn cast_transparent_box<Outer, Inner>(inner: Box<Inner>) -> Box<Outer> {
19+
pub unsafe fn cast_transparent_box<Inner, Outer>(inner: Box<Inner>) -> Box<Outer> {
1820
// Safety:
1921
//
2022
// - Both boxes have the same allocator (the global allocator).
@@ -82,29 +84,28 @@ macro_rules! transparent {
8284
$(
8385
impl<'zf> $crate::ZeroFrom<'zf, $inner_zf> for &'zf $outer {
8486
fn zero_from(inner: &'zf $inner) -> Self {
85-
unsafe { core::mem::transmute(inner) }
87+
unsafe { core::mem::transmute::<&$inner, &$outer>(inner) }
8688
}
8789
}
8890
)?
8991
$(impl $outer {
9092
$(
9193
$(#[$meta_ref])*
9294
$vis_ref fn $fn_ref(inner: &$inner_ref) -> &Self {
93-
unsafe { core::mem::transmute(inner) }
95+
unsafe { core::mem::transmute::<&$inner, &$outer>(inner) }
9496
}
9597
)?
9698
$(
9799
$(#[$meta_slice])*
98100
$vis_slice fn $fn_slice(inner: &[$inner_slice]) -> &[Self] {
99-
unsafe { core::mem::transmute(inner) }
101+
unsafe { core::mem::transmute::<&[$inner], &[$outer]>(inner) }
100102
}
101103
)?
102104
$(
103105
$(#[$meta_box])*
104106
$vis_box fn $fn_box(inner: $crate::internal::Box<$inner_box>) -> $crate::internal::Box<Self> {
105107
// Safety: $outer is repr(transparent) over $inner.
106-
// TODO: Enforce that $inner is the same as $inner_box
107-
unsafe { $crate::internal::cast_transparent_box(inner) }
108+
unsafe { $crate::internal::cast_transparent_box::<$inner, $outer>(inner) }
108109
}
109110
)?
110111
$(
@@ -116,3 +117,41 @@ macro_rules! transparent {
116117
})?
117118
};
118119
}
120+
121+
/// Additional tests for failure modes.
122+
///
123+
/// ```compile_fail,E0053
124+
/// zerofrom::transparent! {
125+
/// #[repr(transparent)]
126+
/// pub struct Foo(String);
127+
/// // Wrong types in these positions!
128+
/// impl ZeroFrom<&Foo> for &String;
129+
/// };
130+
/// ```
131+
///
132+
/// ```compile_fail,E0308
133+
/// zerofrom::transparent! {
134+
/// #[repr(transparent)]
135+
/// pub struct Foo(String);
136+
/// impl {
137+
/// @ref
138+
/// // Wrong type in this position!
139+
/// pub fn from(&Foo) -> &Self;
140+
/// }
141+
/// };
142+
/// ```
143+
///
144+
/// ```compile_fail,E0308
145+
/// zerofrom::transparent! {
146+
/// #[repr(transparent)]
147+
/// pub struct Foo(String);
148+
/// impl {
149+
/// @slice
150+
/// // Wrong type in this position!
151+
/// pub fn from(&[Foo]) -> &[Self];
152+
/// }
153+
/// };
154+
/// ```
155+
///
156+
/// TODO: Rc
157+
mod _tests {}

0 commit comments

Comments
 (0)