panic when calling MaybeUninhabited::into_inner on uninhabited type
This commit is contained in:
parent
a7be40c65a
commit
fff905bc69
5 changed files with 99 additions and 51 deletions
|
@ -690,6 +690,11 @@ extern "rust-intrinsic" {
|
|||
/// crate it is invoked in.
|
||||
pub fn type_id<T: ?Sized + 'static>() -> u64;
|
||||
|
||||
/// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited:
|
||||
/// This will statically either panic, or do nothing.
|
||||
#[cfg(not(stage0))]
|
||||
pub fn panic_if_uninhabited<T>();
|
||||
|
||||
/// Creates a value initialized to zero.
|
||||
///
|
||||
/// `init` is unsafe because it returns a zeroed-out datum,
|
||||
|
|
|
@ -492,6 +492,8 @@ pub const fn needs_drop<T>() -> bool {
|
|||
#[rustc_deprecated(since = "2.0.0", reason = "use `mem::MaybeUninit::zeroed` instead")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub unsafe fn zeroed<T>() -> T {
|
||||
#[cfg(not(stage0))]
|
||||
intrinsics::panic_if_uninhabited::<T>();
|
||||
intrinsics::init()
|
||||
}
|
||||
|
||||
|
@ -624,6 +626,8 @@ pub unsafe fn zeroed<T>() -> T {
|
|||
#[rustc_deprecated(since = "2.0.0", reason = "use `mem::MaybeUninit::uninitialized` instead")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub unsafe fn uninitialized<T>() -> T {
|
||||
#[cfg(not(stage0))]
|
||||
intrinsics::panic_if_uninhabited::<T>();
|
||||
intrinsics::uninit()
|
||||
}
|
||||
|
||||
|
@ -1128,6 +1132,8 @@ impl<T> MaybeUninit<T> {
|
|||
#[unstable(feature = "maybe_uninit", issue = "53491")]
|
||||
#[inline(always)]
|
||||
pub unsafe fn into_inner(self) -> T {
|
||||
#[cfg(not(stage0))]
|
||||
intrinsics::panic_if_uninhabited::<T>();
|
||||
ManuallyDrop::into_inner(self.value)
|
||||
}
|
||||
|
||||
|
|
|
@ -500,53 +500,62 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
_ => bx.new_fn_type(sig, &extra_args)
|
||||
};
|
||||
|
||||
// emit a panic instead of instantiating an uninhabited type
|
||||
if (intrinsic == Some("init") || intrinsic == Some("uninit")) &&
|
||||
fn_ty.ret.layout.abi.is_uninhabited()
|
||||
{
|
||||
let loc = bx.sess().source_map().lookup_char_pos(span.lo());
|
||||
let filename = Symbol::intern(&loc.file.name.to_string()).as_str();
|
||||
let filename = bx.const_str_slice(filename);
|
||||
let line = bx.const_u32(loc.line as u32);
|
||||
let col = bx.const_u32(loc.col.to_usize() as u32 + 1);
|
||||
let align = tcx.data_layout.aggregate_align.abi
|
||||
.max(tcx.data_layout.i32_align.abi)
|
||||
.max(tcx.data_layout.pointer_align.abi);
|
||||
// emit a panic or a NOP for `panic_if_uninhabited`
|
||||
if intrinsic == Some("panic_if_uninhabited") {
|
||||
let ty = match callee.layout.ty.sty {
|
||||
ty::FnDef(_, substs) => {
|
||||
substs.type_at(0)
|
||||
}
|
||||
_ => bug!("{} is not callable as intrinsic", callee.layout.ty)
|
||||
};
|
||||
let layout = bx.layout_of(ty);
|
||||
if layout.abi.is_uninhabited() {
|
||||
let loc = bx.sess().source_map().lookup_char_pos(span.lo());
|
||||
let filename = Symbol::intern(&loc.file.name.to_string()).as_str();
|
||||
let filename = bx.const_str_slice(filename);
|
||||
let line = bx.const_u32(loc.line as u32);
|
||||
let col = bx.const_u32(loc.col.to_usize() as u32 + 1);
|
||||
let align = tcx.data_layout.aggregate_align.abi
|
||||
.max(tcx.data_layout.i32_align.abi)
|
||||
.max(tcx.data_layout.pointer_align.abi);
|
||||
|
||||
let str = format!(
|
||||
"Attempted to instantiate uninhabited type {} using mem::{}",
|
||||
sig.output(),
|
||||
if intrinsic == Some("init") { "zeroed" } else { "uninitialized" }
|
||||
);
|
||||
let msg_str = Symbol::intern(&str).as_str();
|
||||
let msg_str = bx.const_str_slice(msg_str);
|
||||
let msg_file_line_col = bx.const_struct(
|
||||
&[msg_str, filename, line, col],
|
||||
false,
|
||||
);
|
||||
let msg_file_line_col = bx.static_addr_of(
|
||||
msg_file_line_col,
|
||||
align,
|
||||
Some("panic_loc"),
|
||||
);
|
||||
let str = format!(
|
||||
"Attempted to instantiate uninhabited type {}",
|
||||
ty
|
||||
);
|
||||
let msg_str = Symbol::intern(&str).as_str();
|
||||
let msg_str = bx.const_str_slice(msg_str);
|
||||
let msg_file_line_col = bx.const_struct(
|
||||
&[msg_str, filename, line, col],
|
||||
false,
|
||||
);
|
||||
let msg_file_line_col = bx.static_addr_of(
|
||||
msg_file_line_col,
|
||||
align,
|
||||
Some("panic_loc"),
|
||||
);
|
||||
|
||||
// Obtain the panic entry point.
|
||||
let def_id =
|
||||
common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem);
|
||||
let instance = ty::Instance::mono(bx.tcx(), def_id);
|
||||
let fn_ty = bx.fn_type_of_instance(&instance);
|
||||
let llfn = bx.get_fn(instance);
|
||||
// Obtain the panic entry point.
|
||||
let def_id =
|
||||
common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem);
|
||||
let instance = ty::Instance::mono(bx.tcx(), def_id);
|
||||
let fn_ty = bx.fn_type_of_instance(&instance);
|
||||
let llfn = bx.get_fn(instance);
|
||||
|
||||
// Codegen the actual panic invoke/call.
|
||||
do_call(
|
||||
self,
|
||||
&mut bx,
|
||||
fn_ty,
|
||||
llfn,
|
||||
&[msg_file_line_col],
|
||||
destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)),
|
||||
cleanup,
|
||||
);
|
||||
// Codegen the actual panic invoke/call.
|
||||
do_call(
|
||||
self,
|
||||
&mut bx,
|
||||
fn_ty,
|
||||
llfn,
|
||||
&[msg_file_line_col],
|
||||
destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)),
|
||||
cleanup,
|
||||
);
|
||||
} else {
|
||||
// a NOP
|
||||
funclet_br(self, &mut bx, destination.as_ref().unwrap().1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -133,6 +133,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
], tcx.types.usize)
|
||||
}
|
||||
"rustc_peek" => (1, vec![param(0)], param(0)),
|
||||
"panic_if_uninhabited" => (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()),
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// This test checks that instantiating an uninhabited type via `mem::{uninitialized,zeroed}` results
|
||||
// in a runtime panic.
|
||||
|
||||
#![feature(never_type)]
|
||||
#![feature(never_type, maybe_uninit)]
|
||||
|
||||
use std::{mem, panic};
|
||||
|
||||
|
@ -20,7 +20,7 @@ fn main() {
|
|||
panic::catch_unwind(|| {
|
||||
mem::uninitialized::<!>()
|
||||
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
|
||||
s == "Attempted to instantiate uninhabited type ! using mem::uninitialized"
|
||||
s == "Attempted to instantiate uninhabited type !"
|
||||
})),
|
||||
Some(true)
|
||||
);
|
||||
|
@ -29,7 +29,16 @@ fn main() {
|
|||
panic::catch_unwind(|| {
|
||||
mem::zeroed::<!>()
|
||||
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
|
||||
s == "Attempted to instantiate uninhabited type ! using mem::zeroed"
|
||||
s == "Attempted to instantiate uninhabited type !"
|
||||
})),
|
||||
Some(true)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
panic::catch_unwind(|| {
|
||||
mem::MaybeUninit::<!>::uninitialized().into_inner()
|
||||
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
|
||||
s == "Attempted to instantiate uninhabited type !"
|
||||
})),
|
||||
Some(true)
|
||||
);
|
||||
|
@ -38,7 +47,7 @@ fn main() {
|
|||
panic::catch_unwind(|| {
|
||||
mem::uninitialized::<Foo>()
|
||||
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
|
||||
s == "Attempted to instantiate uninhabited type Foo using mem::uninitialized"
|
||||
s == "Attempted to instantiate uninhabited type Foo"
|
||||
})),
|
||||
Some(true)
|
||||
);
|
||||
|
@ -47,7 +56,16 @@ fn main() {
|
|||
panic::catch_unwind(|| {
|
||||
mem::zeroed::<Foo>()
|
||||
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
|
||||
s == "Attempted to instantiate uninhabited type Foo using mem::zeroed"
|
||||
s == "Attempted to instantiate uninhabited type Foo"
|
||||
})),
|
||||
Some(true)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
panic::catch_unwind(|| {
|
||||
mem::MaybeUninit::<Foo>::uninitialized().into_inner()
|
||||
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
|
||||
s == "Attempted to instantiate uninhabited type Foo"
|
||||
})),
|
||||
Some(true)
|
||||
);
|
||||
|
@ -56,7 +74,7 @@ fn main() {
|
|||
panic::catch_unwind(|| {
|
||||
mem::uninitialized::<Bar>()
|
||||
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
|
||||
s == "Attempted to instantiate uninhabited type Bar using mem::uninitialized"
|
||||
s == "Attempted to instantiate uninhabited type Bar"
|
||||
})),
|
||||
Some(true)
|
||||
);
|
||||
|
@ -65,7 +83,16 @@ fn main() {
|
|||
panic::catch_unwind(|| {
|
||||
mem::zeroed::<Bar>()
|
||||
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
|
||||
s == "Attempted to instantiate uninhabited type Bar using mem::zeroed"
|
||||
s == "Attempted to instantiate uninhabited type Bar"
|
||||
})),
|
||||
Some(true)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
panic::catch_unwind(|| {
|
||||
mem::MaybeUninit::<Bar>::uninitialized().into_inner()
|
||||
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
|
||||
s == "Attempted to instantiate uninhabited type Bar"
|
||||
})),
|
||||
Some(true)
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue