Skip to content

Commit 8c2d0f4

Browse files
committed
Auto merge of #57145 - RalfJung:panic-if-uninhabited, r=alexcrichton
panic when calling MaybeUninhabited::into_inner on uninhabited type I do this by adding an internal-only intrinsic `panic_if_uninhabited`. I have no idea what I am doing here, just mindlessly copying code around, so please review carefully!
2 parents 6861426 + c118b17 commit 8c2d0f4

File tree

5 files changed

+96
-53
lines changed

5 files changed

+96
-53
lines changed

src/libcore/intrinsics.rs

+5
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,11 @@ extern "rust-intrinsic" {
690690
/// crate it is invoked in.
691691
pub fn type_id<T: ?Sized + 'static>() -> u64;
692692

693+
/// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited:
694+
/// This will statically either panic, or do nothing.
695+
#[cfg(not(stage0))]
696+
pub fn panic_if_uninhabited<T>();
697+
693698
/// Creates a value initialized to zero.
694699
///
695700
/// `init` is unsafe because it returns a zeroed-out datum,

src/libcore/mem.rs

+6
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,8 @@ pub const fn needs_drop<T>() -> bool {
492492
#[rustc_deprecated(since = "2.0.0", reason = "use `mem::MaybeUninit::zeroed` instead")]
493493
#[stable(feature = "rust1", since = "1.0.0")]
494494
pub unsafe fn zeroed<T>() -> T {
495+
#[cfg(not(stage0))]
496+
intrinsics::panic_if_uninhabited::<T>();
495497
intrinsics::init()
496498
}
497499

@@ -624,6 +626,8 @@ pub unsafe fn zeroed<T>() -> T {
624626
#[rustc_deprecated(since = "2.0.0", reason = "use `mem::MaybeUninit::uninitialized` instead")]
625627
#[stable(feature = "rust1", since = "1.0.0")]
626628
pub unsafe fn uninitialized<T>() -> T {
629+
#[cfg(not(stage0))]
630+
intrinsics::panic_if_uninhabited::<T>();
627631
intrinsics::uninit()
628632
}
629633

@@ -1128,6 +1132,8 @@ impl<T> MaybeUninit<T> {
11281132
#[unstable(feature = "maybe_uninit", issue = "53491")]
11291133
#[inline(always)]
11301134
pub unsafe fn into_inner(self) -> T {
1135+
#[cfg(not(stage0))]
1136+
intrinsics::panic_if_uninhabited::<T>();
11311137
ManuallyDrop::into_inner(self.value)
11321138
}
11331139

src/librustc_codegen_ssa/mir/block.rs

+50-46
Original file line numberDiff line numberDiff line change
@@ -500,53 +500,57 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
500500
_ => bx.new_fn_type(sig, &extra_args)
501501
};
502502

503-
// emit a panic instead of instantiating an uninhabited type
504-
if (intrinsic == Some("init") || intrinsic == Some("uninit")) &&
505-
fn_ty.ret.layout.abi.is_uninhabited()
506-
{
507-
let loc = bx.sess().source_map().lookup_char_pos(span.lo());
508-
let filename = Symbol::intern(&loc.file.name.to_string()).as_str();
509-
let filename = bx.const_str_slice(filename);
510-
let line = bx.const_u32(loc.line as u32);
511-
let col = bx.const_u32(loc.col.to_usize() as u32 + 1);
512-
let align = tcx.data_layout.aggregate_align.abi
513-
.max(tcx.data_layout.i32_align.abi)
514-
.max(tcx.data_layout.pointer_align.abi);
515-
516-
let str = format!(
517-
"Attempted to instantiate uninhabited type {} using mem::{}",
518-
sig.output(),
519-
if intrinsic == Some("init") { "zeroed" } else { "uninitialized" }
520-
);
521-
let msg_str = Symbol::intern(&str).as_str();
522-
let msg_str = bx.const_str_slice(msg_str);
523-
let msg_file_line_col = bx.const_struct(
524-
&[msg_str, filename, line, col],
525-
false,
526-
);
527-
let msg_file_line_col = bx.static_addr_of(
528-
msg_file_line_col,
529-
align,
530-
Some("panic_loc"),
531-
);
503+
// emit a panic or a NOP for `panic_if_uninhabited`
504+
if intrinsic == Some("panic_if_uninhabited") {
505+
let ty = instance.unwrap().substs.type_at(0);
506+
let layout = bx.layout_of(ty);
507+
if layout.abi.is_uninhabited() {
508+
let loc = bx.sess().source_map().lookup_char_pos(span.lo());
509+
let filename = Symbol::intern(&loc.file.name.to_string()).as_str();
510+
let filename = bx.const_str_slice(filename);
511+
let line = bx.const_u32(loc.line as u32);
512+
let col = bx.const_u32(loc.col.to_usize() as u32 + 1);
513+
let align = tcx.data_layout.aggregate_align.abi
514+
.max(tcx.data_layout.i32_align.abi)
515+
.max(tcx.data_layout.pointer_align.abi);
516+
517+
let str = format!(
518+
"Attempted to instantiate uninhabited type {}",
519+
ty
520+
);
521+
let msg_str = Symbol::intern(&str).as_str();
522+
let msg_str = bx.const_str_slice(msg_str);
523+
let msg_file_line_col = bx.const_struct(
524+
&[msg_str, filename, line, col],
525+
false,
526+
);
527+
let msg_file_line_col = bx.static_addr_of(
528+
msg_file_line_col,
529+
align,
530+
Some("panic_loc"),
531+
);
532532

533-
// Obtain the panic entry point.
534-
let def_id =
535-
common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem);
536-
let instance = ty::Instance::mono(bx.tcx(), def_id);
537-
let fn_ty = bx.fn_type_of_instance(&instance);
538-
let llfn = bx.get_fn(instance);
539-
540-
// Codegen the actual panic invoke/call.
541-
do_call(
542-
self,
543-
&mut bx,
544-
fn_ty,
545-
llfn,
546-
&[msg_file_line_col],
547-
destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)),
548-
cleanup,
549-
);
533+
// Obtain the panic entry point.
534+
let def_id =
535+
common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem);
536+
let instance = ty::Instance::mono(bx.tcx(), def_id);
537+
let fn_ty = bx.fn_type_of_instance(&instance);
538+
let llfn = bx.get_fn(instance);
539+
540+
// Codegen the actual panic invoke/call.
541+
do_call(
542+
self,
543+
&mut bx,
544+
fn_ty,
545+
llfn,
546+
&[msg_file_line_col],
547+
destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)),
548+
cleanup,
549+
);
550+
} else {
551+
// a NOP
552+
funclet_br(self, &mut bx, destination.as_ref().unwrap().1);
553+
}
550554
return;
551555
}
552556

src/librustc_typeck/check/intrinsic.rs

+1
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
133133
], tcx.types.usize)
134134
}
135135
"rustc_peek" => (1, vec![param(0)], param(0)),
136+
"panic_if_uninhabited" => (1, Vec::new(), tcx.mk_unit()),
136137
"init" => (1, Vec::new(), param(0)),
137138
"uninit" => (1, Vec::new(), param(0)),
138139
"forget" => (1, vec![param(0)], tcx.mk_unit()),

src/test/run-pass/panic-uninitialized-zeroed.rs

+34-7
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// This test checks that instantiating an uninhabited type via `mem::{uninitialized,zeroed}` results
33
// in a runtime panic.
44

5-
#![feature(never_type)]
5+
#![feature(never_type, maybe_uninit)]
66

77
use std::{mem, panic};
88

@@ -20,7 +20,7 @@ fn main() {
2020
panic::catch_unwind(|| {
2121
mem::uninitialized::<!>()
2222
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
23-
s == "Attempted to instantiate uninhabited type ! using mem::uninitialized"
23+
s == "Attempted to instantiate uninhabited type !"
2424
})),
2525
Some(true)
2626
);
@@ -29,7 +29,16 @@ fn main() {
2929
panic::catch_unwind(|| {
3030
mem::zeroed::<!>()
3131
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
32-
s == "Attempted to instantiate uninhabited type ! using mem::zeroed"
32+
s == "Attempted to instantiate uninhabited type !"
33+
})),
34+
Some(true)
35+
);
36+
37+
assert_eq!(
38+
panic::catch_unwind(|| {
39+
mem::MaybeUninit::<!>::uninitialized().into_inner()
40+
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
41+
s == "Attempted to instantiate uninhabited type !"
3342
})),
3443
Some(true)
3544
);
@@ -38,7 +47,7 @@ fn main() {
3847
panic::catch_unwind(|| {
3948
mem::uninitialized::<Foo>()
4049
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
41-
s == "Attempted to instantiate uninhabited type Foo using mem::uninitialized"
50+
s == "Attempted to instantiate uninhabited type Foo"
4251
})),
4352
Some(true)
4453
);
@@ -47,7 +56,16 @@ fn main() {
4756
panic::catch_unwind(|| {
4857
mem::zeroed::<Foo>()
4958
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
50-
s == "Attempted to instantiate uninhabited type Foo using mem::zeroed"
59+
s == "Attempted to instantiate uninhabited type Foo"
60+
})),
61+
Some(true)
62+
);
63+
64+
assert_eq!(
65+
panic::catch_unwind(|| {
66+
mem::MaybeUninit::<Foo>::uninitialized().into_inner()
67+
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
68+
s == "Attempted to instantiate uninhabited type Foo"
5169
})),
5270
Some(true)
5371
);
@@ -56,7 +74,7 @@ fn main() {
5674
panic::catch_unwind(|| {
5775
mem::uninitialized::<Bar>()
5876
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
59-
s == "Attempted to instantiate uninhabited type Bar using mem::uninitialized"
77+
s == "Attempted to instantiate uninhabited type Bar"
6078
})),
6179
Some(true)
6280
);
@@ -65,7 +83,16 @@ fn main() {
6583
panic::catch_unwind(|| {
6684
mem::zeroed::<Bar>()
6785
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
68-
s == "Attempted to instantiate uninhabited type Bar using mem::zeroed"
86+
s == "Attempted to instantiate uninhabited type Bar"
87+
})),
88+
Some(true)
89+
);
90+
91+
assert_eq!(
92+
panic::catch_unwind(|| {
93+
mem::MaybeUninit::<Bar>::uninitialized().into_inner()
94+
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
95+
s == "Attempted to instantiate uninhabited type Bar"
6996
})),
7097
Some(true)
7198
);

0 commit comments

Comments
 (0)