From 503026b622d1095770178fbe606a4ba783216992 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Nov 2019 17:21:37 +0100 Subject: [PATCH 01/10] mem::zeroed/uninit: panic on types that do not permit zero-initialization --- src/libcore/intrinsics.rs | 10 ++ src/libcore/mem/mod.rs | 6 + src/librustc/ty/layout.rs | 30 ----- src/librustc_codegen_ssa/mir/block.rs | 31 ++++- src/librustc_index/vec.rs | 2 +- src/librustc_target/abi/mod.rs | 115 ++++++++++++++++++ src/librustc_target/lib.rs | 3 + src/librustc_typeck/check/intrinsic.rs | 5 +- .../intrinsics/panic-uninitialized-zeroed.rs | 113 +++++++++++++++++ .../never_type/panic-uninitialized-zeroed.rs | 102 ---------------- 10 files changed, 280 insertions(+), 137 deletions(-) create mode 100644 src/test/ui/intrinsics/panic-uninitialized-zeroed.rs delete mode 100644 src/test/ui/never_type/panic-uninitialized-zeroed.rs diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 94928211a978a..c02dabcacde85 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -721,6 +721,16 @@ extern "rust-intrinsic" { /// This will statically either panic, or do nothing. pub fn panic_if_uninhabited(); + /// A guard for unsafe functions that cannot ever be executed if `T` does not permit + /// zero-initialization: This will statically either panic, or do nothing. + #[cfg(not(bootstrap))] + pub fn panic_if_zero_invalid(); + + /// A guard for unsafe functions that cannot ever be executed if `T` has invalid + /// bit patterns: This will statically either panic, or do nothing. + #[cfg(not(bootstrap))] + pub fn panic_if_any_invalid(); + /// Gets a reference to a static `Location` indicating where it was called. #[rustc_const_unstable(feature = "const_caller_location", issue = "47809")] pub fn caller_location() -> &'static crate::panic::Location<'static>; diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index 9eb151cf528a5..124eb37fff17e 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -495,6 +495,9 @@ pub const fn needs_drop() -> bool { #[allow(deprecated)] #[rustc_diagnostic_item = "mem_zeroed"] pub unsafe fn zeroed() -> T { + #[cfg(not(bootstrap))] + intrinsics::panic_if_zero_invalid::(); + #[cfg(bootstrap)] intrinsics::panic_if_uninhabited::(); intrinsics::init() } @@ -528,6 +531,9 @@ pub unsafe fn zeroed() -> T { #[allow(deprecated)] #[rustc_diagnostic_item = "mem_uninitialized"] pub unsafe fn uninitialized() -> T { + #[cfg(not(bootstrap))] + intrinsics::panic_if_any_invalid::(); + #[cfg(bootstrap)] intrinsics::panic_if_uninhabited::(); intrinsics::uninit() } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index e8bf2eb9a12c9..6b5f540e5b830 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1907,36 +1907,6 @@ impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> { } } -pub trait MaybeResult { - type Error; - - fn from(x: Result) -> Self; - fn to_result(self) -> Result; -} - -impl MaybeResult for T { - type Error = !; - - fn from(x: Result) -> Self { - let Ok(x) = x; - x - } - fn to_result(self) -> Result { - Ok(self) - } -} - -impl MaybeResult for Result { - type Error = E; - - fn from(x: Result) -> Self { - x - } - fn to_result(self) -> Result { - self - } -} - pub type TyLayout<'tcx> = ::rustc_target::abi::TyLayout<'tcx, Ty<'tcx>>; impl<'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'tcx>> { diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index a1b54607b809e..923e2486ace68 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -521,11 +521,36 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } // Emit a panic or a no-op for `panic_if_uninhabited`. - if intrinsic == Some("panic_if_uninhabited") { + // These are intrinsics that compile to panics so that we can get a message + // which mentions the offending type, even from a const context. + #[derive(Debug, PartialEq)] + enum PanicIntrinsic { IfUninhabited, IfZeroInvalid, IfAnyInvalid }; + let panic_intrinsic = intrinsic.and_then(|i| match i { + "panic_if_uninhabited" => Some(PanicIntrinsic::IfUninhabited), + "panic_if_zero_invalid" => Some(PanicIntrinsic::IfZeroInvalid), + "panic_if_any_invalid" => Some(PanicIntrinsic::IfAnyInvalid), + _ => None + }); + if let Some(intrinsic) = panic_intrinsic { + use PanicIntrinsic::*; let ty = instance.unwrap().substs.type_at(0); let layout = bx.layout_of(ty); - if layout.abi.is_uninhabited() { - let msg_str = format!("Attempted to instantiate uninhabited type {}", ty); + let do_panic = match intrinsic { + IfUninhabited => layout.abi.is_uninhabited(), + IfZeroInvalid => // We unwrap as the error type is `!`. + !layout.might_permit_raw_init(&bx, /*zero:*/ true).unwrap(), + IfAnyInvalid => // We unwrap as the error type is `!`. + !layout.might_permit_raw_init(&bx, /*zero:*/ false).unwrap(), + }; + if do_panic { + let msg_str = if layout.abi.is_uninhabited() { + // Use this error even for the other intrinsics as it is more precise. + format!("attempted to instantiate uninhabited type `{}`", ty) + } else if intrinsic == IfZeroInvalid { + format!("attempted to zero-initialize type `{}`, which is invalid", ty) + } else { + format!("attempted to leave type `{}` uninitialized, which is invalid", ty) + }; let msg = bx.const_str(Symbol::intern(&msg_str)); let location = self.get_caller_location(&mut bx, span).immediate(); diff --git a/src/librustc_index/vec.rs b/src/librustc_index/vec.rs index 1dfe97238a3df..7020939fa20b2 100644 --- a/src/librustc_index/vec.rs +++ b/src/librustc_index/vec.rs @@ -196,7 +196,7 @@ macro_rules! newtype_index { #[inline] fn index(self) -> usize { - usize::from(self) + self.as_usize() } } diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index edd0ba46f7565..13a0eb66f32a5 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -919,6 +919,7 @@ impl<'a, Ty> Deref for TyLayout<'a, Ty> { } } +/// Trait for context types that can compute layouts of things. pub trait LayoutOf { type Ty; type TyLayout; @@ -929,6 +930,39 @@ pub trait LayoutOf { } } +/// The `TyLayout` above will always be a `MaybeResult>`. +/// We can't add the bound due to the lifetime, but this trait is still useful when +/// writing code that's generic over the `LayoutOf` impl. +pub trait MaybeResult { + type Error; + + fn from(x: Result) -> Self; + fn to_result(self) -> Result; +} + +impl MaybeResult for T { + type Error = !; + + fn from(x: Result) -> Self { + let Ok(x) = x; + x + } + fn to_result(self) -> Result { + Ok(self) + } +} + +impl MaybeResult for Result { + type Error = E; + + fn from(x: Result) -> Self { + x + } + fn to_result(self) -> Result { + self + } +} + #[derive(Copy, Clone, PartialEq, Eq)] pub enum PointerKind { /// Most general case, we know no restrictions to tell LLVM. @@ -969,6 +1003,9 @@ impl<'a, Ty> TyLayout<'a, Ty> { { Ty::for_variant(self, cx, variant_index) } + + /// Callers might want to use `C: LayoutOf>` + /// to allow recursion (see `might_permit_zero_init` below for an example). pub fn field(self, cx: &C, i: usize) -> C::TyLayout where Ty: TyLayoutMethods<'a, C>, @@ -976,6 +1013,7 @@ impl<'a, Ty> TyLayout<'a, Ty> { { Ty::field(self, cx, i) } + pub fn pointee_info_at(self, cx: &C, offset: Size) -> Option where Ty: TyLayoutMethods<'a, C>, @@ -999,4 +1037,81 @@ impl<'a, Ty> TyLayout<'a, Ty> { Abi::Aggregate { sized } => sized && self.size.bytes() == 0, } } + + /// Determines if this type permits "raw" initialization by just transmuting some + /// memory into an instance of `T`. + /// `zero` indicates if the memory is zero-initialized, or alternatively + /// left entirely uninitialized. + /// This is conservative: in doubt, it will answer `true`. + pub fn might_permit_raw_init( + self, + cx: &C, + zero: bool, + ) -> Result + where + Self: Copy, + Ty: TyLayoutMethods<'a, C>, + C: LayoutOf> + { + let scalar_allows_raw_init = move |s: &Scalar| -> bool { + let range = &s.valid_range; + if zero { + // The range must contain 0. + range.contains(&0) || + (*range.start() > *range.end()) // wrap-around allows 0 + } else { + // The range must include all values. + *range.start() == range.end().wrapping_add(1) + } + }; + + // Abi is the most informative here. + let res = match &self.abi { + Abi::Uninhabited => false, // definitely UB + Abi::Scalar(s) => scalar_allows_raw_init(s), + Abi::ScalarPair(s1, s2) => + scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2), + Abi::Vector { element: s, count } => + *count == 0 || scalar_allows_raw_init(s), + Abi::Aggregate { .. } => { + match self.variants { + Variants::Multiple { .. } => + if zero { + // FIXME: could we identify the variant with discriminant 0, check that? + true + } else { + // FIXME: This needs to have some sort of discriminant, + // which cannot be undef. But for now we are conservative. + true + }, + Variants::Single { .. } => { + // For aggregates, recurse. + match self.fields { + FieldPlacement::Union(..) => true, // An all-0 unit is fine. + FieldPlacement::Array { .. } => + // FIXME: The widely use smallvec 0.6 creates uninit arrays + // with any element type, so let us not (yet) complain about that. + // count == 0 || + // self.field(cx, 0).to_result()?.might_permit_raw_init(cx, zero)? + true, + FieldPlacement::Arbitrary { ref offsets, .. } => { + let mut res = true; + // Check that all fields accept zero-init. + for idx in 0..offsets.len() { + let field = self.field(cx, idx).to_result()?; + if !field.might_permit_raw_init(cx, zero)? { + res = false; + break; + } + } + res + } + } + } + } + } + }; + trace!("might_permit_raw_init({:?}, zero={}) = {}", self.details, zero, res); + Ok(res) + } } diff --git a/src/librustc_target/lib.rs b/src/librustc_target/lib.rs index 71150e74f70d4..3c397eb444d1d 100644 --- a/src/librustc_target/lib.rs +++ b/src/librustc_target/lib.rs @@ -10,6 +10,9 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(bool_to_option)] #![feature(nll)] +#![feature(never_type)] +#![feature(associated_type_bounds)] +#![feature(exhaustive_patterns)] #[macro_use] extern crate log; diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 3572eda5c1399..321932fb193a0 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -147,7 +147,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { ), "rustc_peek" => (1, vec![param(0)], param(0)), "caller_location" => (0, vec![], tcx.caller_location_ty()), - "panic_if_uninhabited" => (1, Vec::new(), tcx.mk_unit()), + "panic_if_uninhabited" | + "panic_if_zero_invalid" | + "panic_if_any_invalid" => + (1, Vec::new(), tcx.mk_unit()), "init" => (1, Vec::new(), param(0)), "uninit" => (1, Vec::new(), param(0)), "forget" => (1, vec![param(0)], tcx.mk_unit()), diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs new file mode 100644 index 0000000000000..937f949a7b00b --- /dev/null +++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -0,0 +1,113 @@ +// run-pass +// ignore-wasm32-bare compiled with panic=abort by default + +// This test checks panic emitted from `mem::{uninitialized,zeroed}`. + +#![feature(never_type)] +#![allow(deprecated, invalid_value)] + +use std::{mem, panic}; +use std::ptr::NonNull; + +#[allow(dead_code)] +struct Foo { + x: u8, + y: !, +} + +enum Bar {} + +#[allow(dead_code)] +enum OneVariant { Variant(i32) } + +fn test_panic_msg(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) { + let err = panic::catch_unwind(op).err(); + assert_eq!( + err.as_ref().and_then(|a| a.downcast_ref::()).map(|s| &**s), + Some(msg) + ); +} + +fn main() { + unsafe { + // Uninitialized types + test_panic_msg( + || mem::uninitialized::(), + "attempted to instantiate uninhabited type `!`" + ); + test_panic_msg( + || mem::zeroed::(), + "attempted to instantiate uninhabited type `!`" + ); + test_panic_msg( + || mem::MaybeUninit::::uninit().assume_init(), + "attempted to instantiate uninhabited type `!`" + ); + + test_panic_msg( + || mem::uninitialized::(), + "attempted to instantiate uninhabited type `Foo`" + ); + test_panic_msg( + || mem::zeroed::(), + "attempted to instantiate uninhabited type `Foo`" + ); + test_panic_msg( + || mem::MaybeUninit::::uninit().assume_init(), + "attempted to instantiate uninhabited type `Foo`" + ); + + test_panic_msg( + || mem::uninitialized::(), + "attempted to instantiate uninhabited type `Bar`" + ); + test_panic_msg( + || mem::zeroed::(), + "attempted to instantiate uninhabited type `Bar`" + ); + test_panic_msg( + || mem::MaybeUninit::::uninit().assume_init(), + "attempted to instantiate uninhabited type `Bar`" + ); + + // Types that do not like zero-initialziation + test_panic_msg( + || mem::uninitialized::(), + "attempted to leave type `fn()` uninitialized, which is invalid" + ); + test_panic_msg( + || mem::zeroed::(), + "attempted to zero-initialize type `fn()`, which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<*const dyn Send>(), + "attempted to leave type `*const dyn std::marker::Send` uninitialized, which is invalid" + ); + test_panic_msg( + || mem::zeroed::<*const dyn Send>(), + "attempted to zero-initialize type `*const dyn std::marker::Send`, which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<(NonNull, u32, u32)>(), + "attempted to leave type `(std::ptr::NonNull, u32, u32)` uninitialized, \ + which is invalid" + ); + test_panic_msg( + || mem::zeroed::<(NonNull, u32, u32)>(), + "attempted to zero-initialize type `(std::ptr::NonNull, u32, u32)`, \ + which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::(), + "attempted to leave type `bool` uninitialized, which is invalid" + ); + + // Some things that should work. + let _val = mem::zeroed::(); + let _val = mem::zeroed::(); + let _val = mem::zeroed::>(); + } +} diff --git a/src/test/ui/never_type/panic-uninitialized-zeroed.rs b/src/test/ui/never_type/panic-uninitialized-zeroed.rs deleted file mode 100644 index e0c30160b9e94..0000000000000 --- a/src/test/ui/never_type/panic-uninitialized-zeroed.rs +++ /dev/null @@ -1,102 +0,0 @@ -// run-pass -// ignore-wasm32-bare compiled with panic=abort by default -// This test checks that instantiating an uninhabited type via `mem::{uninitialized,zeroed}` results -// in a runtime panic. - -#![feature(never_type)] -#![allow(deprecated, invalid_value)] - -use std::{mem, panic}; - -#[allow(dead_code)] -struct Foo { - x: u8, - y: !, -} - -enum Bar {} - -fn main() { - unsafe { - assert_eq!( - panic::catch_unwind(|| { - mem::uninitialized::() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type !" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::zeroed::() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type !" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::MaybeUninit::::uninit().assume_init() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type !" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::uninitialized::() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type Foo" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::zeroed::() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type Foo" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::MaybeUninit::::uninit().assume_init() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type Foo" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::uninitialized::() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type Bar" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::zeroed::() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type Bar" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::MaybeUninit::::uninit().assume_init() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type Bar" - })), - Some(true) - ); - } -} From 6fd909b2b1dd2789e0f1af79283c6105fa502ca3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Nov 2019 11:07:00 +0100 Subject: [PATCH 02/10] reference tracking issue --- src/librustc_target/abi/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 13a0eb66f32a5..4e4ef46909095 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -1077,10 +1077,11 @@ impl<'a, Ty> TyLayout<'a, Ty> { match self.variants { Variants::Multiple { .. } => if zero { - // FIXME: could we identify the variant with discriminant 0, check that? + // FIXME(#66151): + // could we identify the variant with discriminant 0, check that? true } else { - // FIXME: This needs to have some sort of discriminant, + // FIXME(#66151): This needs to have some sort of discriminant, // which cannot be undef. But for now we are conservative. true }, @@ -1089,7 +1090,7 @@ impl<'a, Ty> TyLayout<'a, Ty> { match self.fields { FieldPlacement::Union(..) => true, // An all-0 unit is fine. FieldPlacement::Array { .. } => - // FIXME: The widely use smallvec 0.6 creates uninit arrays + // FIXME(#66151): The widely use smallvec 0.6 creates uninit arrays // with any element type, so let us not (yet) complain about that. // count == 0 || // self.field(cx, 0).to_result()?.might_permit_raw_init(cx, zero)? From d78c4aa62ec0382d85e88b44cce2c087c5357f53 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Nov 2019 12:19:44 +0100 Subject: [PATCH 03/10] use valid_range_exclusive for correct overflow handling --- src/librustc_target/abi/mod.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 4e4ef46909095..c48e7de6b0486 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -1051,17 +1051,20 @@ impl<'a, Ty> TyLayout<'a, Ty> { where Self: Copy, Ty: TyLayoutMethods<'a, C>, - C: LayoutOf> + C: LayoutOf> + HasDataLayout { let scalar_allows_raw_init = move |s: &Scalar| -> bool { - let range = &s.valid_range; if zero { + let range = &s.valid_range; // The range must contain 0. range.contains(&0) || (*range.start() > *range.end()) // wrap-around allows 0 } else { - // The range must include all values. - *range.start() == range.end().wrapping_add(1) + // The range must include all values. `valid_range_exclusive` handles + // the wrap-around using target arithmetic; with wrap-around then the full + // range is one where `start == end`. + let range = s.valid_range_exclusive(cx); + range.start == range.end } }; From df6a3a0ed216a8548130f9b431964531a1bc7633 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Nov 2019 12:24:26 +0100 Subject: [PATCH 04/10] test some more things that should not panic --- .../intrinsics/panic-uninitialized-zeroed.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs index 937f949a7b00b..9c869947bfa10 100644 --- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs +++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -6,8 +6,11 @@ #![feature(never_type)] #![allow(deprecated, invalid_value)] -use std::{mem, panic}; -use std::ptr::NonNull; +use std::{ + mem::{self, MaybeUninit}, + panic, + ptr::NonNull, +}; #[allow(dead_code)] struct Foo { @@ -40,7 +43,7 @@ fn main() { "attempted to instantiate uninhabited type `!`" ); test_panic_msg( - || mem::MaybeUninit::::uninit().assume_init(), + || MaybeUninit::::uninit().assume_init(), "attempted to instantiate uninhabited type `!`" ); @@ -53,7 +56,7 @@ fn main() { "attempted to instantiate uninhabited type `Foo`" ); test_panic_msg( - || mem::MaybeUninit::::uninit().assume_init(), + || MaybeUninit::::uninit().assume_init(), "attempted to instantiate uninhabited type `Foo`" ); @@ -66,7 +69,7 @@ fn main() { "attempted to instantiate uninhabited type `Bar`" ); test_panic_msg( - || mem::MaybeUninit::::uninit().assume_init(), + || MaybeUninit::::uninit().assume_init(), "attempted to instantiate uninhabited type `Bar`" ); @@ -109,5 +112,11 @@ fn main() { let _val = mem::zeroed::(); let _val = mem::zeroed::(); let _val = mem::zeroed::>(); + let _val = mem::zeroed::>>(); + let _val = mem::uninitialized::>(); + + // We don't panic for these just to be conservative. They are UB as of now (2019-11-09). + let _val = mem::uninitialized::(); + let _val = mem::uninitialized::<*const ()>(); } } From b133d6776fde22e944eb7f266ee165ffcf7cdb09 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Nov 2019 09:00:29 +0100 Subject: [PATCH 05/10] make it even more conservative, and note some FIXMEs --- src/librustc_codegen_ssa/mir/block.rs | 2 ++ src/librustc_target/abi/mod.rs | 18 +++++++++++++----- .../intrinsics/panic-uninitialized-zeroed.rs | 2 ++ 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 923e2486ace68..ae3d8442add67 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -526,6 +526,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { #[derive(Debug, PartialEq)] enum PanicIntrinsic { IfUninhabited, IfZeroInvalid, IfAnyInvalid }; let panic_intrinsic = intrinsic.and_then(|i| match i { + // FIXME: Move to symbols instead of strings. "panic_if_uninhabited" => Some(PanicIntrinsic::IfUninhabited), "panic_if_zero_invalid" => Some(PanicIntrinsic::IfZeroInvalid), "panic_if_any_invalid" => Some(PanicIntrinsic::IfAnyInvalid), @@ -555,6 +556,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let location = self.get_caller_location(&mut bx, span).immediate(); // Obtain the panic entry point. + // FIXME: dedup this with `codegen_assert_terminator` above. let def_id = common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem); let instance = ty::Instance::mono(bx.tcx(), def_id); diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index c48e7de6b0486..71f97ca85832c 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -1043,6 +1043,10 @@ impl<'a, Ty> TyLayout<'a, Ty> { /// `zero` indicates if the memory is zero-initialized, or alternatively /// left entirely uninitialized. /// This is conservative: in doubt, it will answer `true`. + /// + /// FIXME: Once we removed all the conservatism, we could alternatively + /// create an all-0/all-undef constant and run the vonst value validator to see if + /// this is a valid value for the given type. pub fn might_permit_raw_init( self, cx: &C, @@ -1095,11 +1099,14 @@ impl<'a, Ty> TyLayout<'a, Ty> { FieldPlacement::Array { .. } => // FIXME(#66151): The widely use smallvec 0.6 creates uninit arrays // with any element type, so let us not (yet) complain about that. - // count == 0 || - // self.field(cx, 0).to_result()?.might_permit_raw_init(cx, zero)? + /* count == 0 || + self.field(cx, 0).to_result()?.might_permit_raw_init(cx, zero)? */ true, - FieldPlacement::Arbitrary { ref offsets, .. } => { - let mut res = true; + FieldPlacement::Arbitrary { .. } => { + // FIXME(#66151) cargo depends on sized-chunks 0.3.0 which + // has some illegal zero-initialization, so let us not (yet) + // complain about aggregates either. + /* let mut res = true; // Check that all fields accept zero-init. for idx in 0..offsets.len() { let field = self.field(cx, idx).to_result()?; @@ -1108,7 +1115,8 @@ impl<'a, Ty> TyLayout<'a, Ty> { break; } } - res + res */ + true } } } diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs index 9c869947bfa10..a1b2a1af2c434 100644 --- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs +++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -92,6 +92,7 @@ fn main() { "attempted to zero-initialize type `*const dyn std::marker::Send`, which is invalid" ); + /* FIXME(#66151) we conservatively do not error here yet. test_panic_msg( || mem::uninitialized::<(NonNull, u32, u32)>(), "attempted to leave type `(std::ptr::NonNull, u32, u32)` uninitialized, \ @@ -102,6 +103,7 @@ fn main() { "attempted to zero-initialize type `(std::ptr::NonNull, u32, u32)`, \ which is invalid" ); + */ test_panic_msg( || mem::uninitialized::(), From 6e66f586a0da51fbd4cafa2e1da914cf07c65503 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Feb 2020 22:45:28 +0100 Subject: [PATCH 06/10] fmt --- src/librustc_codegen_ssa/mir/block.rs | 16 +++++++----- src/librustc_target/abi/mod.rs | 34 ++++++++++++-------------- src/librustc_typeck/check/intrinsic.rs | 7 +++--- 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index ae3d8442add67..7c5a17d43b6da 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -524,13 +524,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // These are intrinsics that compile to panics so that we can get a message // which mentions the offending type, even from a const context. #[derive(Debug, PartialEq)] - enum PanicIntrinsic { IfUninhabited, IfZeroInvalid, IfAnyInvalid }; + enum PanicIntrinsic { + IfUninhabited, + IfZeroInvalid, + IfAnyInvalid, + }; let panic_intrinsic = intrinsic.and_then(|i| match i { // FIXME: Move to symbols instead of strings. "panic_if_uninhabited" => Some(PanicIntrinsic::IfUninhabited), "panic_if_zero_invalid" => Some(PanicIntrinsic::IfZeroInvalid), "panic_if_any_invalid" => Some(PanicIntrinsic::IfAnyInvalid), - _ => None + _ => None, }); if let Some(intrinsic) = panic_intrinsic { use PanicIntrinsic::*; @@ -538,10 +542,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let layout = bx.layout_of(ty); let do_panic = match intrinsic { IfUninhabited => layout.abi.is_uninhabited(), - IfZeroInvalid => // We unwrap as the error type is `!`. - !layout.might_permit_raw_init(&bx, /*zero:*/ true).unwrap(), - IfAnyInvalid => // We unwrap as the error type is `!`. - !layout.might_permit_raw_init(&bx, /*zero:*/ false).unwrap(), + // We unwrap as the error type is `!`. + IfZeroInvalid => !layout.might_permit_raw_init(&bx, /*zero:*/ true).unwrap(), + // We unwrap as the error type is `!`. + IfAnyInvalid => !layout.might_permit_raw_init(&bx, /*zero:*/ false).unwrap(), }; if do_panic { let msg_str = if layout.abi.is_uninhabited() { diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 71f97ca85832c..c043d87f69f9d 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -1047,22 +1047,17 @@ impl<'a, Ty> TyLayout<'a, Ty> { /// FIXME: Once we removed all the conservatism, we could alternatively /// create an all-0/all-undef constant and run the vonst value validator to see if /// this is a valid value for the given type. - pub fn might_permit_raw_init( - self, - cx: &C, - zero: bool, - ) -> Result + pub fn might_permit_raw_init(self, cx: &C, zero: bool) -> Result where Self: Copy, Ty: TyLayoutMethods<'a, C>, - C: LayoutOf> + HasDataLayout + C: LayoutOf> + HasDataLayout, { let scalar_allows_raw_init = move |s: &Scalar| -> bool { if zero { let range = &s.valid_range; // The range must contain 0. - range.contains(&0) || - (*range.start() > *range.end()) // wrap-around allows 0 + range.contains(&0) || (*range.start() > *range.end()) // wrap-around allows 0 } else { // The range must include all values. `valid_range_exclusive` handles // the wrap-around using target arithmetic; with wrap-around then the full @@ -1076,13 +1071,11 @@ impl<'a, Ty> TyLayout<'a, Ty> { let res = match &self.abi { Abi::Uninhabited => false, // definitely UB Abi::Scalar(s) => scalar_allows_raw_init(s), - Abi::ScalarPair(s1, s2) => - scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2), - Abi::Vector { element: s, count } => - *count == 0 || scalar_allows_raw_init(s), + Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2), + Abi::Vector { element: s, count } => *count == 0 || scalar_allows_raw_init(s), Abi::Aggregate { .. } => { match self.variants { - Variants::Multiple { .. } => + Variants::Multiple { .. } => { if zero { // FIXME(#66151): // could we identify the variant with discriminant 0, check that? @@ -1091,17 +1084,20 @@ impl<'a, Ty> TyLayout<'a, Ty> { // FIXME(#66151): This needs to have some sort of discriminant, // which cannot be undef. But for now we are conservative. true - }, + } + } Variants::Single { .. } => { // For aggregates, recurse. match self.fields { FieldPlacement::Union(..) => true, // An all-0 unit is fine. FieldPlacement::Array { .. } => - // FIXME(#66151): The widely use smallvec 0.6 creates uninit arrays - // with any element type, so let us not (yet) complain about that. - /* count == 0 || - self.field(cx, 0).to_result()?.might_permit_raw_init(cx, zero)? */ - true, + // FIXME(#66151): The widely use smallvec 0.6 creates uninit arrays + // with any element type, so let us not (yet) complain about that. + /* count == 0 || + self.field(cx, 0).to_result()?.might_permit_raw_init(cx, zero)? */ + { + true + } FieldPlacement::Arbitrary { .. } => { // FIXME(#66151) cargo depends on sized-chunks 0.3.0 which // has some illegal zero-initialization, so let us not (yet) diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 321932fb193a0..d2a358c3e09b8 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -147,10 +147,9 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { ), "rustc_peek" => (1, vec![param(0)], param(0)), "caller_location" => (0, vec![], tcx.caller_location_ty()), - "panic_if_uninhabited" | - "panic_if_zero_invalid" | - "panic_if_any_invalid" => - (1, Vec::new(), tcx.mk_unit()), + "panic_if_uninhabited" | "panic_if_zero_invalid" | "panic_if_any_invalid" => { + (1, Vec::new(), tcx.mk_unit()) + } "init" => (1, Vec::new(), param(0)), "uninit" => (1, Vec::new(), param(0)), "forget" => (1, vec![param(0)], tcx.mk_unit()), From 729f4cd9ae9a619677afaa4c389e000c03e5b22b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 Feb 2020 09:21:02 +0100 Subject: [PATCH 07/10] we cannot short-circuit just becuase the Abi seems harmless also add tests for ScalarPair enums --- src/librustc_target/abi/mod.rs | 63 ++++--------------- .../intrinsics/panic-uninitialized-zeroed.rs | 48 +++++++++++++- 2 files changed, 59 insertions(+), 52 deletions(-) diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index c043d87f69f9d..aa9474233a4ea 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -1045,7 +1045,7 @@ impl<'a, Ty> TyLayout<'a, Ty> { /// This is conservative: in doubt, it will answer `true`. /// /// FIXME: Once we removed all the conservatism, we could alternatively - /// create an all-0/all-undef constant and run the vonst value validator to see if + /// create an all-0/all-undef constant and run the const value validator to see if /// this is a valid value for the given type. pub fn might_permit_raw_init(self, cx: &C, zero: bool) -> Result where @@ -1067,59 +1067,22 @@ impl<'a, Ty> TyLayout<'a, Ty> { } }; - // Abi is the most informative here. - let res = match &self.abi { + // Check the ABI. + let valid = match &self.abi { Abi::Uninhabited => false, // definitely UB Abi::Scalar(s) => scalar_allows_raw_init(s), Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2), Abi::Vector { element: s, count } => *count == 0 || scalar_allows_raw_init(s), - Abi::Aggregate { .. } => { - match self.variants { - Variants::Multiple { .. } => { - if zero { - // FIXME(#66151): - // could we identify the variant with discriminant 0, check that? - true - } else { - // FIXME(#66151): This needs to have some sort of discriminant, - // which cannot be undef. But for now we are conservative. - true - } - } - Variants::Single { .. } => { - // For aggregates, recurse. - match self.fields { - FieldPlacement::Union(..) => true, // An all-0 unit is fine. - FieldPlacement::Array { .. } => - // FIXME(#66151): The widely use smallvec 0.6 creates uninit arrays - // with any element type, so let us not (yet) complain about that. - /* count == 0 || - self.field(cx, 0).to_result()?.might_permit_raw_init(cx, zero)? */ - { - true - } - FieldPlacement::Arbitrary { .. } => { - // FIXME(#66151) cargo depends on sized-chunks 0.3.0 which - // has some illegal zero-initialization, so let us not (yet) - // complain about aggregates either. - /* let mut res = true; - // Check that all fields accept zero-init. - for idx in 0..offsets.len() { - let field = self.field(cx, idx).to_result()?; - if !field.might_permit_raw_init(cx, zero)? { - res = false; - break; - } - } - res */ - true - } - } - } - } - } + Abi::Aggregate { .. } => true, // Cannot be excluded *right now*. }; - trace!("might_permit_raw_init({:?}, zero={}) = {}", self.details, zero, res); - Ok(res) + if !valid { + // This is definitely not okay. + trace!("might_permit_raw_init({:?}, zero={}): not valid", self.details, zero); + return Ok(false); + } + + // If we have not found an error yet, we need to recursively descend. + // FIXME(#66151): For now, we are conservative and do not do this. + Ok(true) } } diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs index a1b2a1af2c434..be0df0ea2541c 100644 --- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs +++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -7,9 +7,10 @@ #![allow(deprecated, invalid_value)] use std::{ - mem::{self, MaybeUninit}, + mem::{self, MaybeUninit, ManuallyDrop}, panic, ptr::NonNull, + num, }; #[allow(dead_code)] @@ -23,6 +24,18 @@ enum Bar {} #[allow(dead_code)] enum OneVariant { Variant(i32) } +// An enum with ScalarPair layout +#[allow(dead_code)] +enum LR { + Left(i64), + Right(i64), +} +#[allow(dead_code, non_camel_case_types)] +enum LR_NonZero { + Left(num::NonZeroI64), + Right(num::NonZeroI64), +} + fn test_panic_msg(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) { let err = panic::catch_unwind(op).err(); assert_eq!( @@ -33,7 +46,7 @@ fn test_panic_msg(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) { fn main() { unsafe { - // Uninitialized types + // Uninhabited types test_panic_msg( || mem::uninitialized::(), "attempted to instantiate uninhabited type `!`" @@ -93,6 +106,26 @@ fn main() { ); /* FIXME(#66151) we conservatively do not error here yet. + test_panic_msg( + || mem::uninitialized::(), + "attempted to leave type `LR_NonZero` uninitialized, which is invalid" + ); + test_panic_msg( + || mem::zeroed::(), + "attempted to zero-initialize type `LR_NonZero`, which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::>(), + "attempted to leave type `std::mem::ManuallyDrop` uninitialized, \ + which is invalid" + ); + test_panic_msg( + || mem::zeroed::>(), + "attempted to zero-initialize type `std::mem::ManuallyDrop`, \ + which is invalid" + ); + test_panic_msg( || mem::uninitialized::<(NonNull, u32, u32)>(), "attempted to leave type `(std::ptr::NonNull, u32, u32)` uninitialized, \ @@ -105,13 +138,24 @@ fn main() { ); */ + // Types that can be zero, but not uninit. test_panic_msg( || mem::uninitialized::(), "attempted to leave type `bool` uninitialized, which is invalid" ); + test_panic_msg( + || mem::uninitialized::(), + "attempted to leave type `LR` uninitialized, which is invalid" + ); + test_panic_msg( + || mem::uninitialized::>(), + "attempted to leave type `std::mem::ManuallyDrop` uninitialized, which is invalid" + ); // Some things that should work. let _val = mem::zeroed::(); + let _val = mem::zeroed::(); + let _val = mem::zeroed::>(); let _val = mem::zeroed::(); let _val = mem::zeroed::>(); let _val = mem::zeroed::>>(); From bfe593e03a0f73ee52ac666be17e963957ef628f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 29 Feb 2020 09:29:51 +0100 Subject: [PATCH 08/10] clarify a comment in the test --- src/test/ui/intrinsics/panic-uninitialized-zeroed.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs index be0df0ea2541c..02f8ecaa4eec5 100644 --- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs +++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -161,7 +161,9 @@ fn main() { let _val = mem::zeroed::>>(); let _val = mem::uninitialized::>(); - // We don't panic for these just to be conservative. They are UB as of now (2019-11-09). + // These are UB because they have not been officially blessed, but we await the resolution + // of before doing + // anything about that. let _val = mem::uninitialized::(); let _val = mem::uninitialized::<*const ()>(); } From 7c84e451d533f12d3a1a7b35ca66bdd02ecf17fc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 29 Feb 2020 09:40:40 +0100 Subject: [PATCH 09/10] move panic intrinsic codegen to helper function --- src/librustc_codegen_ssa/mir/block.rs | 158 +++++++++++++++----------- 1 file changed, 92 insertions(+), 66 deletions(-) diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 7c5a17d43b6da..c8d352cd2dd98 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -434,6 +434,89 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { helper.do_call(self, &mut bx, fn_abi, llfn, &args, None, cleanup); } + /// Returns `true` if this is indeed a panic intrinsic and codegen is done. + fn codegen_panic_intrinsic( + &mut self, + helper: &TerminatorCodegenHelper<'tcx>, + bx: &mut Bx, + intrinsic: Option<&str>, + instance: Option>, + span: Span, + destination: &Option<(mir::Place<'tcx>, mir::BasicBlock)>, + cleanup: Option, + ) -> bool { + // Emit a panic or a no-op for `panic_if_uninhabited`. + // These are intrinsics that compile to panics so that we can get a message + // which mentions the offending type, even from a const context. + #[derive(Debug, PartialEq)] + enum PanicIntrinsic { + IfUninhabited, + IfZeroInvalid, + IfAnyInvalid, + }; + let panic_intrinsic = intrinsic.and_then(|i| match i { + // FIXME: Move to symbols instead of strings. + "panic_if_uninhabited" => Some(PanicIntrinsic::IfUninhabited), + "panic_if_zero_invalid" => Some(PanicIntrinsic::IfZeroInvalid), + "panic_if_any_invalid" => Some(PanicIntrinsic::IfAnyInvalid), + _ => None, + }); + if let Some(intrinsic) = panic_intrinsic { + use PanicIntrinsic::*; + let ty = instance.unwrap().substs.type_at(0); + let layout = bx.layout_of(ty); + let do_panic = match intrinsic { + IfUninhabited => layout.abi.is_uninhabited(), + // We unwrap as the error type is `!`. + IfZeroInvalid => !layout.might_permit_raw_init(bx, /*zero:*/ true).unwrap(), + // We unwrap as the error type is `!`. + IfAnyInvalid => !layout.might_permit_raw_init(bx, /*zero:*/ false).unwrap(), + }; + if do_panic { + let msg_str = if layout.abi.is_uninhabited() { + // Use this error even for the other intrinsics as it is more precise. + format!("attempted to instantiate uninhabited type `{}`", ty) + } else if intrinsic == IfZeroInvalid { + format!("attempted to zero-initialize type `{}`, which is invalid", ty) + } else { + format!("attempted to leave type `{}` uninitialized, which is invalid", ty) + }; + let msg = bx.const_str(Symbol::intern(&msg_str)); + let location = self.get_caller_location(bx, span).immediate(); + + // Obtain the panic entry point. + // FIXME: dedup this with `codegen_assert_terminator` above. + let def_id = + common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem); + let instance = ty::Instance::mono(bx.tcx(), def_id); + let fn_abi = FnAbi::of_instance(bx, instance, &[]); + let llfn = bx.get_fn_addr(instance); + + if let Some((_, target)) = destination.as_ref() { + helper.maybe_sideeffect(self.mir, bx, &[*target]); + } + // Codegen the actual panic invoke/call. + helper.do_call( + self, + bx, + fn_abi, + llfn, + &[msg.0, msg.1, location], + destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)), + cleanup, + ); + } else { + // a NOP + let target = destination.as_ref().unwrap().1; + helper.maybe_sideeffect(self.mir, bx, &[target]); + helper.funclet_br(self, bx, target) + } + true + } else { + false + } + } + fn codegen_call_terminator( &mut self, helper: TerminatorCodegenHelper<'tcx>, @@ -520,72 +603,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bug!("`miri_start_panic` should never end up in compiled code"); } - // Emit a panic or a no-op for `panic_if_uninhabited`. - // These are intrinsics that compile to panics so that we can get a message - // which mentions the offending type, even from a const context. - #[derive(Debug, PartialEq)] - enum PanicIntrinsic { - IfUninhabited, - IfZeroInvalid, - IfAnyInvalid, - }; - let panic_intrinsic = intrinsic.and_then(|i| match i { - // FIXME: Move to symbols instead of strings. - "panic_if_uninhabited" => Some(PanicIntrinsic::IfUninhabited), - "panic_if_zero_invalid" => Some(PanicIntrinsic::IfZeroInvalid), - "panic_if_any_invalid" => Some(PanicIntrinsic::IfAnyInvalid), - _ => None, - }); - if let Some(intrinsic) = panic_intrinsic { - use PanicIntrinsic::*; - let ty = instance.unwrap().substs.type_at(0); - let layout = bx.layout_of(ty); - let do_panic = match intrinsic { - IfUninhabited => layout.abi.is_uninhabited(), - // We unwrap as the error type is `!`. - IfZeroInvalid => !layout.might_permit_raw_init(&bx, /*zero:*/ true).unwrap(), - // We unwrap as the error type is `!`. - IfAnyInvalid => !layout.might_permit_raw_init(&bx, /*zero:*/ false).unwrap(), - }; - if do_panic { - let msg_str = if layout.abi.is_uninhabited() { - // Use this error even for the other intrinsics as it is more precise. - format!("attempted to instantiate uninhabited type `{}`", ty) - } else if intrinsic == IfZeroInvalid { - format!("attempted to zero-initialize type `{}`, which is invalid", ty) - } else { - format!("attempted to leave type `{}` uninitialized, which is invalid", ty) - }; - let msg = bx.const_str(Symbol::intern(&msg_str)); - let location = self.get_caller_location(&mut bx, span).immediate(); - - // Obtain the panic entry point. - // FIXME: dedup this with `codegen_assert_terminator` above. - let def_id = - common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem); - let instance = ty::Instance::mono(bx.tcx(), def_id); - let fn_abi = FnAbi::of_instance(&bx, instance, &[]); - let llfn = bx.get_fn_addr(instance); - - if let Some((_, target)) = destination.as_ref() { - helper.maybe_sideeffect(self.mir, &mut bx, &[*target]); - } - // Codegen the actual panic invoke/call. - helper.do_call( - self, - &mut bx, - fn_abi, - llfn, - &[msg.0, msg.1, location], - destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)), - cleanup, - ); - } else { - // a NOP - let target = destination.as_ref().unwrap().1; - helper.maybe_sideeffect(self.mir, &mut bx, &[target]); - helper.funclet_br(self, &mut bx, target) - } + if self.codegen_panic_intrinsic( + &helper, + &mut bx, + intrinsic, + instance, + span, + destination, + cleanup, + ) { return; } From a09c33e36205991bb633a848d1e9c7604ae43ce8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 29 Feb 2020 09:41:59 +0100 Subject: [PATCH 10/10] move pattern to fn argument --- src/librustc_target/abi/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index aa9474233a4ea..d8788611878a0 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -943,8 +943,7 @@ pub trait MaybeResult { impl MaybeResult for T { type Error = !; - fn from(x: Result) -> Self { - let Ok(x) = x; + fn from(Ok(x): Result) -> Self { x } fn to_result(self) -> Result {