From 59dad415731e76d01022c9e347e67d52468fccb6 Mon Sep 17 00:00:00 2001 From: rodrimati1992 Date: Fri, 10 Apr 2020 19:23:27 -0300 Subject: [PATCH] Fixed lifetime unsoundness in `arr` macro. Added doctests (that don't appear in the public documentation) for cases that are expected to compile,and not compile. --- src/arr.rs | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 5 deletions(-) diff --git a/src/arr.rs b/src/arr.rs index 7710124e45..ebe6875008 100644 --- a/src/arr.rs +++ b/src/arr.rs @@ -25,20 +25,30 @@ pub type Inc = >::Output; #[doc(hidden)] #[macro_export] macro_rules! arr_impl { + (@replace_expr $e:expr)=>{ + 1 + }; ($T:ty; $N:ty, [$($x:expr),*], []) => ({ - unsafe { $crate::transmute::<_, $crate::GenericArray<$T, $N>>([$($x),*]) } + const __ARR_LENGTH:usize=0 $(+ $crate::arr_impl!(@replace_expr $x) )*; + fn __do_transmute<'a, T, N: $crate::ArrayLength>(arr: [T; __ARR_LENGTH]) -> $crate::GenericArray { + unsafe { $crate::transmute(arr) } + } + + let _:[();<$N as $crate::typenum::Unsigned>::USIZE]=[();__ARR_LENGTH]; + + __do_transmute::<$T,$N>([$($x),*]) }); ($T:ty; $N:ty, [], [$x1:expr]) => ( - arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1 as $T], []) + $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1], []) ); ($T:ty; $N:ty, [], [$x1:expr, $($x:expr),+]) => ( - arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1 as $T], [$($x),+]) + $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1], [$($x),+]) ); ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr]) => ( - arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1 as $T], []) + $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1], []) ); ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr, $($x:expr),+]) => ( - arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1 as $T], [$($x),+]) + $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1], [$($x),+]) ); } @@ -55,3 +65,62 @@ macro_rules! arr { ($($x:expr,)+) => (arr![$($x),*]); () => ("""Macro requires a type, e.g. `let array = arr![u32; 1, 2, 3];`") } + + +mod doctests_only{ + /// + /// # With ellision + /// + /// Testing that lifetimes aren't transmuted when they're ellided. + /// + /// ```compile_fail + /// #[macro_use] extern crate generic_array; + /// fn main() { + /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'static A { + /// arr![&A; a][0] + /// } + /// } + /// ``` + /// + /// ```rust + /// #[macro_use] extern crate generic_array; + /// fn main() { + /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'a A { + /// arr![&A; a][0] + /// } + /// } + /// ``` + /// + /// # Without ellision + /// + /// Testing that lifetimes aren't transmuted when they're specified explicitly. + /// + /// ```compile_fail + /// #[macro_use] extern crate generic_array; + /// fn main() { + /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'static A { + /// arr![&'a A; a][0] + /// } + /// } + /// ``` + /// + /// ```compile_fail + /// #[macro_use] extern crate generic_array; + /// fn main() { + /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'static A { + /// arr![&'static A; a][0] + /// } + /// } + /// ``` + /// + /// ```rust + /// #[macro_use] extern crate generic_array; + /// fn main() { + /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'a A { + /// arr![&'a A; a][0] + /// } + /// } + /// ``` + #[allow(dead_code)] + pub enum DocTests{} +}