Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 641251b

Browse files
committedFeb 22, 2023
Add new CheckMaybeUninit MIR transform
This MIR transform inserts the same validity checks from `mem::{uninitialized,zeroed}` to `MaybeUninit::{uninit,zeroed}().assume_init()`. We have been panicking in `mem::uninit` on invalid values for quite some time now, and it has helped to get people off the unsound API and towards using `MaybeUninit<T>`. While correct usage of `MaybeUninit<T>` is clearly documented, some people still use it incorrectly and simply replaced their wrong `mem::uninit` usage with `MaybeUninit::uninit().assume_init()`. This is not any more correct than the old version, and we should still emit panics in these cases. As this can't be done in the library only, we need this MIR pass to insert the calls. For now, it only detects direct usages of `MaybeUninit::uninit().assume_init()` but it could be extended in the future to do more advanced dataflow analysis.
1 parent b869e84 commit 641251b

15 files changed

+712
-342
lines changed
 

‎compiler/rustc_hir/src/lang_items.rs

+4
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,10 @@ language_item_table! {
328328
RangeTo, sym::RangeTo, range_to_struct, Target::Struct, GenericRequirement::None;
329329

330330
String, sym::String, string, Target::Struct, GenericRequirement::None;
331+
332+
// Lang item because the compiler inserts calls to it when uninit memory is used
333+
AssertUninitValid, sym::assert_uninit_valid, assert_uninit_valid, Target::Fn, GenericRequirement::Exact(1);
334+
AssertZeroValid, sym::assert_zero_valid, assert_zero_valid, Target::Fn, GenericRequirement::Exact(1);
331335
}
332336

333337
pub enum GenericRequirement {

‎compiler/rustc_middle/src/mir/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -3022,6 +3022,11 @@ impl fmt::Debug for Location {
30223022
impl Location {
30233023
pub const START: Location = Location { block: START_BLOCK, statement_index: 0 };
30243024

3025+
/// Create a new location at the start of a basic block.
3026+
pub fn start_of_block(block: BasicBlock) -> Self {
3027+
Self { block, statement_index: 0 }
3028+
}
3029+
30253030
/// Returns the location immediately after this one within the enclosing block.
30263031
///
30273032
/// Note that if this location represents a terminator, then the
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
//! This pass inserts the same validity checks into `MaybeUninit::{uninit,zeroed}().assert_init()`
2+
//! as in `mem::{uninitialized,zeroed}`.
3+
//!
4+
//! Note that this module uses `uninit` to mean `uninit` or `zeroed` unless `zeroed` is used explicitly.
5+
//!
6+
//! It does this by first finding a call to `MaybeUninit::uninit`, and then figuring out
7+
//! whether the successor basic block is a call to `MaybeUninit::assume_init` on the same local.
8+
9+
use rustc_const_eval::interpret;
10+
use rustc_hir::def_id::DefId;
11+
use rustc_middle::mir::patch::MirPatch;
12+
use rustc_middle::mir::{
13+
BasicBlock, BasicBlockData, Body, Constant, ConstantKind, Operand, Place, SourceInfo,
14+
Terminator, TerminatorKind,
15+
};
16+
use rustc_middle::ty::{self, List, SubstsRef, TyCtxt};
17+
use rustc_span::{sym, Span};
18+
19+
use crate::MirPass;
20+
21+
pub struct CheckMaybeUninit;
22+
23+
impl<'tcx> MirPass<'tcx> for CheckMaybeUninit {
24+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
25+
let mut patch = MirPatch::new(body);
26+
27+
for (mu_uninit_bb, _) in body.basic_blocks.iter_enumerated() {
28+
let terminator = body.basic_blocks[mu_uninit_bb].terminator();
29+
30+
let TerminatorKind::Call {
31+
func: mu_uninit_func,
32+
target: assume_init_bb,
33+
destination: uninit_place,
34+
..
35+
} = &terminator.kind else {
36+
continue;
37+
};
38+
39+
let Some((mu_method_def_id, substs)) = mu_uninit_func.const_fn_def() else {
40+
continue;
41+
};
42+
43+
let Some(assume_init_bb) = assume_init_bb else {
44+
continue;
45+
};
46+
47+
let Some((assume_init_operand, assume_init_call_span)) = is_block_just_assume_init(tcx, &body.basic_blocks[*assume_init_bb]) else {
48+
continue;
49+
};
50+
51+
let Some(assume_init_place) = assume_init_operand.place() else {
52+
continue;
53+
};
54+
55+
if assume_init_place != *uninit_place {
56+
// The calls here are a little sketchy, but the place that is assumed to be init is not the place that was just crated
57+
// as uninit, so we conservatively bail out.
58+
continue;
59+
}
60+
61+
// Select the right assertion intrinsic to call depending on which MaybeUninit method we called
62+
let Some(init_check_def_id) = get_init_check_def_id(tcx, mu_method_def_id) else {
63+
continue;
64+
};
65+
66+
let assert_valid_bb = make_assert_valid_bb(
67+
&mut patch,
68+
tcx,
69+
assume_init_call_span,
70+
init_check_def_id,
71+
*assume_init_bb,
72+
substs,
73+
);
74+
75+
let mut new_uninit_terminator = terminator.kind.clone();
76+
match new_uninit_terminator {
77+
TerminatorKind::Call { ref mut target, .. } => {
78+
*target = Some(assert_valid_bb);
79+
}
80+
_ => unreachable!("terminator must be TerminatorKind::Call as checked above"),
81+
}
82+
83+
patch.patch_terminator(mu_uninit_bb, new_uninit_terminator);
84+
}
85+
86+
patch.apply(body);
87+
}
88+
}
89+
90+
fn is_block_just_assume_init<'tcx, 'blk>(
91+
tcx: TyCtxt<'tcx>,
92+
block: &'blk BasicBlockData<'tcx>,
93+
) -> Option<(&'blk Operand<'tcx>, Span)> {
94+
if block.statements.is_empty()
95+
&& let TerminatorKind::Call {
96+
func,
97+
args,
98+
fn_span,
99+
..
100+
} = &block.terminator().kind
101+
&& let Some((def_id, _)) = func.const_fn_def()
102+
&& tcx.is_diagnostic_item(sym::assume_init, def_id)
103+
{
104+
args.get(0).map(|operand| (operand, *fn_span))
105+
} else {
106+
None
107+
}
108+
}
109+
110+
fn get_init_check_def_id(tcx: TyCtxt<'_>, mu_method_def_id: DefId) -> Option<DefId> {
111+
if tcx.is_diagnostic_item(sym::maybe_uninit_uninit, mu_method_def_id) {
112+
tcx.lang_items().assert_uninit_valid()
113+
} else if tcx.is_diagnostic_item(sym::maybe_uninit_zeroed, mu_method_def_id) {
114+
tcx.lang_items().assert_zero_valid()
115+
} else {
116+
None
117+
}
118+
}
119+
120+
fn make_assert_valid_bb<'tcx>(
121+
patch: &mut MirPatch<'tcx>,
122+
tcx: TyCtxt<'tcx>,
123+
fn_span: Span,
124+
init_check_def_id: DefId,
125+
target_bb: BasicBlock,
126+
substs: SubstsRef<'tcx>,
127+
) -> BasicBlock {
128+
let func = make_fn_operand_for_assert_valid(tcx, init_check_def_id, fn_span, substs);
129+
130+
let local = patch.new_temp(tcx.types.unit, fn_span);
131+
132+
let terminator = TerminatorKind::Call {
133+
func,
134+
args: vec![],
135+
destination: Place { local, projection: List::empty() },
136+
target: Some(target_bb),
137+
cleanup: Some(patch.resume_block()),
138+
from_hir_call: true,
139+
fn_span,
140+
};
141+
142+
let terminator = Terminator { source_info: SourceInfo::outermost(fn_span), kind: terminator };
143+
144+
let bb_data = BasicBlockData::new(Some(terminator));
145+
146+
let block = patch.new_block(bb_data);
147+
block
148+
}
149+
150+
fn make_fn_operand_for_assert_valid<'tcx>(
151+
tcx: TyCtxt<'tcx>,
152+
def_id: DefId,
153+
span: Span,
154+
substs: SubstsRef<'tcx>,
155+
) -> Operand<'tcx> {
156+
let fn_ty = ty::FnDef(def_id, substs);
157+
let fn_ty = tcx.mk_ty(fn_ty);
158+
159+
Operand::Constant(Box::new(Constant {
160+
span,
161+
literal: ConstantKind::Val(interpret::ConstValue::ZeroSized, fn_ty),
162+
user_ty: None,
163+
}))
164+
}

‎compiler/rustc_mir_transform/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ mod add_call_guards;
4848
mod add_moves_for_packed_drops;
4949
mod add_retag;
5050
mod check_const_item_mutation;
51+
mod check_maybe_uninit;
5152
mod check_packed_ref;
5253
pub mod check_unsafety;
5354
// This pass is public to allow external drivers to perform MIR cleanup
@@ -300,6 +301,7 @@ fn mir_const(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> &Steal<
300301
&Lint(check_const_item_mutation::CheckConstItemMutation),
301302
&Lint(function_item_references::FunctionItemReferences),
302303
// What we need to do constant evaluation.
304+
&check_maybe_uninit::CheckMaybeUninit,
303305
&simplify::SimplifyCfg::new("initial"),
304306
&rustc_peek::SanityCheck, // Just a lint
305307
],
@@ -497,6 +499,8 @@ fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>
497499
/// After this series of passes, no lifetime analysis based on borrowing can be done.
498500
fn run_analysis_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
499501
let passes: &[&dyn MirPass<'tcx>] = &[
502+
// FIXME: Preferably we'd run this before const eval once the stability of the wrapper function is figured out
503+
&check_maybe_uninit::CheckMaybeUninit,
500504
&cleanup_post_borrowck::CleanupPostBorrowck,
501505
&remove_noop_landing_pads::RemoveNoopLandingPads,
502506
&simplify::SimplifyCfg::new("early-opt"),

‎compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ symbols! {
383383
assert_mem_uninitialized_valid,
384384
assert_ne_macro,
385385
assert_receiver_is_total_eq,
386+
assert_uninit_valid,
386387
assert_zero_valid,
387388
asserting,
388389
associated_const_equality,

‎library/core/src/intrinsics.rs

+46
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,14 @@ extern "rust-intrinsic" {
964964
#[rustc_safe_intrinsic]
965965
pub fn assert_mem_uninitialized_valid<T>();
966966

967+
/// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing.
968+
///
969+
/// This intrinsic does not have a stable counterpart.
970+
#[rustc_const_unstable(feature = "const_assert_type2", issue = "none")]
971+
#[rustc_safe_intrinsic]
972+
#[cfg(bootstrap)]
973+
pub fn assert_uninit_valid<T>();
974+
967975
/// Gets a reference to a static `Location` indicating where it was called.
968976
///
969977
/// Note that, unlike most intrinsics, this is safe to call;
@@ -2527,3 +2535,41 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
25272535
write_bytes(dst, val, count)
25282536
}
25292537
}
2538+
2539+
// Wrappers around the init assertion intrinsics. Calls to these
2540+
// are inserted in the check_maybe_uninit mir pass
2541+
2542+
#[unstable(
2543+
feature = "maybe_uninit_checks_internals",
2544+
issue = "none",
2545+
reason = "implementation detail of panics on invalid MaybeUninit usage"
2546+
)]
2547+
#[rustc_allow_const_fn_unstable(const_assert_type2)]
2548+
#[rustc_const_stable(
2549+
feature = "const_maybe_uninit_checks_internals",
2550+
since = "CURRENT_RUSTC_VERSION"
2551+
)]
2552+
#[cfg_attr(not(bootstrap), lang = "assert_zero_valid")]
2553+
#[track_caller]
2554+
pub const fn assert_zero_valid_wrapper<T>() {
2555+
assert_zero_valid::<T>();
2556+
}
2557+
2558+
#[unstable(
2559+
feature = "maybe_uninit_checks_internals",
2560+
issue = "none",
2561+
reason = "implementation detail of panics on invalid MaybeUninit usage"
2562+
)]
2563+
#[rustc_allow_const_fn_unstable(const_assert_type2)]
2564+
#[rustc_const_stable(
2565+
feature = "const_maybe_uninit_checks_internals",
2566+
since = "CURRENT_RUSTC_VERSION"
2567+
)]
2568+
#[cfg_attr(not(bootstrap), lang = "assert_uninit_valid")]
2569+
#[track_caller]
2570+
pub const fn assert_uninit_valid_wrapper<T>() {
2571+
#[cfg(bootstrap)]
2572+
assert_uninit_valid::<T>();
2573+
#[cfg(not(bootstrap))]
2574+
assert_mem_uninitialized_valid::<T>();
2575+
}

‎library/core/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@
103103
#![feature(const_align_of_val_raw)]
104104
#![feature(const_alloc_layout)]
105105
#![feature(const_arguments_as_str)]
106+
#![feature(const_assert_type2)]
106107
#![feature(const_array_into_iter_constructors)]
107108
#![feature(const_bigint_helper_methods)]
108109
#![feature(const_black_box)]

‎library/core/src/mem/maybe_uninit.rs

+4
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,10 @@ impl<T> MaybeUninit<T> {
624624
// This also means that `self` must be a `value` variant.
625625
unsafe {
626626
intrinsics::assert_inhabited::<T>();
627+
628+
// When this function is called directly after <MaybeUninit<T>>::uninit, we insert calls to
629+
// `intrinsics::assert_zero_valid_wrapper` or `intrinsics::assert_uninit_valid_wrapper` respectively.
630+
627631
ManuallyDrop::into_inner(self.value)
628632
}
629633
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
- // MIR for `main` before CheckMaybeUninit
2+
+ // MIR for `main` after CheckMaybeUninit
3+
4+
| User Type Annotations
5+
| 0: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: TypeOf(DefId(2:2022 ~ core[4f75]::mem::maybe_uninit::{impl#2}::uninit), UserSubsts { substs: [^0], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(2:2019 ~ core[4f75]::mem::maybe_uninit::{impl#2}), self_ty: std::mem::MaybeUninit<u8> }) }) }, span: $DIR/check-maybe-uninit.rs:6:17: 6:42, inferred_ty: fn() -> std::mem::MaybeUninit<u8> {std::mem::MaybeUninit::<u8>::uninit}
6+
| 1: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: TypeOf(DefId(2:2022 ~ core[4f75]::mem::maybe_uninit::{impl#2}::uninit), UserSubsts { substs: [^0], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(2:2019 ~ core[4f75]::mem::maybe_uninit::{impl#2}), self_ty: std::mem::MaybeUninit<std::string::String> }) }) }, span: $DIR/check-maybe-uninit.rs:7:17: 7:46, inferred_ty: fn() -> std::mem::MaybeUninit<std::string::String> {std::mem::MaybeUninit::<std::string::String>::uninit}
7+
|
8+
fn main() -> () {
9+
let mut _0: (); // return place in scope 0 at $DIR/check-maybe-uninit.rs:+0:11: +0:11
10+
let mut _1: u8; // in scope 0 at $DIR/check-maybe-uninit.rs:+2:17: +2:58
11+
let mut _2: std::mem::MaybeUninit<u8>; // in scope 0 at $DIR/check-maybe-uninit.rs:+2:17: +2:44
12+
let mut _3: std::string::String; // in scope 0 at $DIR/check-maybe-uninit.rs:+3:17: +3:62
13+
let mut _4: std::mem::MaybeUninit<std::string::String>; // in scope 0 at $DIR/check-maybe-uninit.rs:+3:17: +3:48
14+
+ let mut _5: (); // in scope 0 at $DIR/check-maybe-uninit.rs:+2:45: +2:58
15+
+ let mut _6: (); // in scope 0 at $DIR/check-maybe-uninit.rs:+3:49: +3:62
16+
scope 1 {
17+
scope 2 {
18+
scope 3 {
19+
}
20+
}
21+
}
22+
23+
bb0: {
24+
StorageLive(_1); // scope 1 at $DIR/check-maybe-uninit.rs:+2:17: +2:58
25+
StorageLive(_2); // scope 1 at $DIR/check-maybe-uninit.rs:+2:17: +2:44
26+
- _2 = MaybeUninit::<u8>::uninit() -> [return: bb1, unwind: bb6]; // scope 1 at $DIR/check-maybe-uninit.rs:+2:17: +2:44
27+
+ _2 = MaybeUninit::<u8>::uninit() -> [return: bb7, unwind: bb6]; // scope 1 at $DIR/check-maybe-uninit.rs:+2:17: +2:44
28+
// mir::Constant
29+
// + span: $DIR/check-maybe-uninit.rs:6:17: 6:42
30+
// + user_ty: UserType(0)
31+
// + literal: Const { ty: fn() -> MaybeUninit<u8> {MaybeUninit::<u8>::uninit}, val: Value(<ZST>) }
32+
}
33+
34+
bb1: {
35+
_1 = MaybeUninit::<u8>::assume_init(move _2) -> [return: bb2, unwind: bb6]; // scope 1 at $DIR/check-maybe-uninit.rs:+2:17: +2:58
36+
// mir::Constant
37+
// + span: $DIR/check-maybe-uninit.rs:6:45: 6:56
38+
// + literal: Const { ty: unsafe fn(MaybeUninit<u8>) -> u8 {MaybeUninit::<u8>::assume_init}, val: Value(<ZST>) }
39+
}
40+
41+
bb2: {
42+
StorageDead(_2); // scope 1 at $DIR/check-maybe-uninit.rs:+2:57: +2:58
43+
StorageDead(_1); // scope 1 at $DIR/check-maybe-uninit.rs:+2:58: +2:59
44+
StorageLive(_3); // scope 2 at $DIR/check-maybe-uninit.rs:+3:17: +3:62
45+
StorageLive(_4); // scope 2 at $DIR/check-maybe-uninit.rs:+3:17: +3:48
46+
- _4 = MaybeUninit::<String>::uninit() -> [return: bb3, unwind: bb6]; // scope 2 at $DIR/check-maybe-uninit.rs:+3:17: +3:48
47+
+ _4 = MaybeUninit::<String>::uninit() -> [return: bb8, unwind: bb6]; // scope 2 at $DIR/check-maybe-uninit.rs:+3:17: +3:48
48+
// mir::Constant
49+
// + span: $DIR/check-maybe-uninit.rs:7:17: 7:46
50+
// + user_ty: UserType(1)
51+
// + literal: Const { ty: fn() -> MaybeUninit<String> {MaybeUninit::<String>::uninit}, val: Value(<ZST>) }
52+
}
53+
54+
bb3: {
55+
_3 = MaybeUninit::<String>::assume_init(move _4) -> [return: bb4, unwind: bb6]; // scope 2 at $DIR/check-maybe-uninit.rs:+3:17: +3:62
56+
// mir::Constant
57+
// + span: $DIR/check-maybe-uninit.rs:7:49: 7:60
58+
// + literal: Const { ty: unsafe fn(MaybeUninit<String>) -> String {MaybeUninit::<String>::assume_init}, val: Value(<ZST>) }
59+
}
60+
61+
bb4: {
62+
StorageDead(_4); // scope 2 at $DIR/check-maybe-uninit.rs:+3:61: +3:62
63+
drop(_3) -> [return: bb5, unwind: bb6]; // scope 2 at $DIR/check-maybe-uninit.rs:+3:62: +3:63
64+
}
65+
66+
bb5: {
67+
StorageDead(_3); // scope 2 at $DIR/check-maybe-uninit.rs:+3:62: +3:63
68+
_0 = const (); // scope 1 at $DIR/check-maybe-uninit.rs:+1:5: +4:6
69+
return; // scope 0 at $DIR/check-maybe-uninit.rs:+5:2: +5:2
70+
}
71+
72+
bb6 (cleanup): {
73+
resume; // scope 0 at $DIR/check-maybe-uninit.rs:+0:1: +5:2
74+
+ }
75+
+
76+
+ bb7: {
77+
+ _5 = <ZST>: fn() {assert_uninit_valid_wrapper::<u8>}() -> [return: bb1, unwind: bb6]; // scope 0 at $DIR/check-maybe-uninit.rs:+2:45: +2:58
78+
+ // mir::Constant
79+
+ // + span: $DIR/check-maybe-uninit.rs:6:45: 6:58
80+
+ // + literal: Const { ty: fn() {assert_uninit_valid_wrapper::<u8>}, val: Value(ValTree::Branch(..)) }
81+
+ }
82+
+
83+
+ bb8: {
84+
+ _6 = <ZST>: fn() {assert_uninit_valid_wrapper::<String>}() -> [return: bb3, unwind: bb6]; // scope 0 at $DIR/check-maybe-uninit.rs:+3:49: +3:62
85+
+ // mir::Constant
86+
+ // + span: $DIR/check-maybe-uninit.rs:7:49: 7:62
87+
+ // + literal: Const { ty: fn() {assert_uninit_valid_wrapper::<String>}, val: Value(ValTree::Branch(..)) }
88+
}
89+
}
90+

‎tests/mir-opt/check_maybe_uninit.rs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use std::mem::MaybeUninit;
2+
3+
// EMIT_MIR check_maybe_uninit.main.CheckMaybeUninit.diff
4+
fn main() {
5+
unsafe {
6+
let _ = MaybeUninit::<u8>::uninit().assume_init();
7+
let _ = MaybeUninit::<String>::uninit().assume_init();
8+
}
9+
}
+63-9
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,75 @@
1-
error[E0080]: evaluation of constant value failed
2-
--> $DIR/assert-type-intrinsics.rs:12:9
1+
error: any use of this value will cause an error
2+
--> $DIR/assert-type-intrinsics.rs:14:36
33
|
4+
LL | const _BAD1: () = unsafe {
5+
| ---------------
46
LL | MaybeUninit::<!>::uninit().assume_init();
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
7+
| ^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
8+
|
9+
= note: `#[deny(const_err)]` on by default
10+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
11+
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
612

7-
error[E0080]: evaluation of constant value failed
8-
--> $DIR/assert-type-intrinsics.rs:16:9
13+
error: any use of this value will cause an error
14+
--> $DIR/assert-type-intrinsics.rs:17:9
15+
|
16+
LL | const _BAD2: () = {
17+
| ---------------
18+
LL | intrinsics::assert_uninit_valid::<bool>();
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `bool` uninitialized, which is invalid
920
|
10-
LL | intrinsics::assert_mem_uninitialized_valid::<&'static i32>();
11-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `&i32` uninitialized, which is invalid
21+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
22+
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
1223

13-
error[E0080]: evaluation of constant value failed
24+
error: any use of this value will cause an error
1425
--> $DIR/assert-type-intrinsics.rs:20:9
1526
|
27+
LL | const _BAD3: () = {
28+
| ---------------
1629
LL | intrinsics::assert_zero_valid::<&'static i32>();
1730
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `&i32`, which is invalid
31+
|
32+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
33+
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
1834

1935
error: aborting due to 3 previous errors
2036

21-
For more information about this error, try `rustc --explain E0080`.
37+
Future incompatibility report: Future breakage diagnostic:
38+
error: any use of this value will cause an error
39+
--> $DIR/assert-type-intrinsics.rs:14:36
40+
|
41+
LL | const _BAD1: () = unsafe {
42+
| ---------------
43+
LL | MaybeUninit::<!>::uninit().assume_init();
44+
| ^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
45+
|
46+
= note: `#[deny(const_err)]` on by default
47+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
48+
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
49+
50+
Future breakage diagnostic:
51+
error: any use of this value will cause an error
52+
--> $DIR/assert-type-intrinsics.rs:17:9
53+
|
54+
LL | const _BAD2: () = {
55+
| ---------------
56+
LL | intrinsics::assert_uninit_valid::<bool>();
57+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `bool` uninitialized, which is invalid
58+
|
59+
= note: `#[deny(const_err)]` on by default
60+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
61+
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
62+
63+
Future breakage diagnostic:
64+
error: any use of this value will cause an error
65+
--> $DIR/assert-type-intrinsics.rs:20:9
66+
|
67+
LL | const _BAD3: () = {
68+
| ---------------
69+
LL | intrinsics::assert_zero_valid::<&'static i32>();
70+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `&i32`, which is invalid
71+
|
72+
= note: `#[deny(const_err)]` on by default
73+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
74+
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
75+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use std::mem::MaybeUninit;
2+
3+
// Make sure it panics during const eval as well
4+
const X: () = {
5+
unsafe { MaybeUninit::<&'static ()>::uninit().assume_init(); } //~ WARN: the type `&()` does not permit being left uninitialized
6+
unsafe { MaybeUninit::<bool>::uninit().assume_init(); } //~ WARN: the type `bool` does not permit being left uninitialized
7+
unsafe { MaybeUninit::<char>::uninit().assume_init(); } //~ WARN: the type `char` does not permit being left uninitialized
8+
unsafe { MaybeUninit::<u8>::uninit().assume_init(); } //~ WARN: the type `u8` does not permit being left uninitialized
9+
};
10+
//~^^^^^ ERROR: any use of this value will cause an error
11+
//~| WARN: this was previously accepted by the compiler but is being phased out
12+
13+
fn main() {
14+
println!("{X:?}");
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
error: any use of this value will cause an error
2+
--> $DIR/maybe_uninit_checks_consts_invalid.rs:5:51
3+
|
4+
LL | const X: () = {
5+
| -----------
6+
LL | unsafe { MaybeUninit::<&'static ()>::uninit().assume_init(); }
7+
| ^^^^^^^^^^^^^ aborted execution: attempted to leave type `&()` uninitialized, which is invalid
8+
|
9+
= note: `#[deny(const_err)]` on by default
10+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
11+
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
12+
13+
warning: the type `&()` does not permit being left uninitialized
14+
--> $DIR/maybe_uninit_checks_consts_invalid.rs:5:14
15+
|
16+
LL | unsafe { MaybeUninit::<&'static ()>::uninit().assume_init(); }
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
18+
| |
19+
| this code causes undefined behavior when executed
20+
| help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
21+
|
22+
= note: `#[warn(invalid_value)]` on by default
23+
= note: references must be non-null
24+
25+
warning: the type `bool` does not permit being left uninitialized
26+
--> $DIR/maybe_uninit_checks_consts_invalid.rs:6:14
27+
|
28+
LL | unsafe { MaybeUninit::<bool>::uninit().assume_init(); }
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
30+
| |
31+
| this code causes undefined behavior when executed
32+
| help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
33+
|
34+
= note: booleans must be either `true` or `false`
35+
36+
warning: the type `char` does not permit being left uninitialized
37+
--> $DIR/maybe_uninit_checks_consts_invalid.rs:7:14
38+
|
39+
LL | unsafe { MaybeUninit::<char>::uninit().assume_init(); }
40+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
41+
| |
42+
| this code causes undefined behavior when executed
43+
| help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
44+
|
45+
= note: characters must be a valid Unicode codepoint
46+
47+
warning: the type `u8` does not permit being left uninitialized
48+
--> $DIR/maybe_uninit_checks_consts_invalid.rs:8:14
49+
|
50+
LL | unsafe { MaybeUninit::<u8>::uninit().assume_init(); }
51+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
52+
| |
53+
| this code causes undefined behavior when executed
54+
| help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
55+
|
56+
= note: integers must not be uninitialized
57+
58+
error: aborting due to previous error; 4 warnings emitted
59+
60+
Future incompatibility report: Future breakage diagnostic:
61+
error: any use of this value will cause an error
62+
--> $DIR/maybe_uninit_checks_consts_invalid.rs:5:51
63+
|
64+
LL | const X: () = {
65+
| -----------
66+
LL | unsafe { MaybeUninit::<&'static ()>::uninit().assume_init(); }
67+
| ^^^^^^^^^^^^^ aborted execution: attempted to leave type `&()` uninitialized, which is invalid
68+
|
69+
= note: `#[deny(const_err)]` on by default
70+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
71+
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
72+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// run-pass
2+
3+
use std::mem::MaybeUninit;
4+
5+
// This test makes sure MU is still usable in consts
6+
const X: () = {
7+
unsafe { MaybeUninit::<MaybeUninit<u8>>::uninit().assume_init(); }
8+
unsafe { MaybeUninit::<()>::uninit().assume_init(); }
9+
};
10+
11+
fn main() {
12+
println!("{X:?}");
13+
}

‎tests/ui/intrinsics/panic-uninitialized-zeroed.rs

+221-333
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.