Skip to content

Commit 691a03c

Browse files
authored
Rollup merge of rust-lang#100043 - RalfJung:scalar-always-init, r=oli-obk
interpret: remove support for uninitialized scalars With Miri no longer supporting `-Zmiri-allow-uninit-numbers`, we no longer need to support storing uninit data in a `Scalar`. We anyway already only use this representation for types with *initialized* `Scalar` layout (and we have to, due to partial initialization), so let's get rid of the `ScalarMaybeUninit` type entirely. I tried to stage this into meaningful commits, but the one that changes `read_immediate` to always trigger UB on uninit is the largest chunk of the PR and I don't see how it could be subdivided. Fixes rust-lang/miri#2187 r? ````@oli-obk````
2 parents de7e652 + c11fa89 commit 691a03c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+506
-935
lines changed

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::interpret::eval_nullary_intrinsic;
33
use crate::interpret::{
44
intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, CtfeValidationMode, GlobalId,
55
Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking,
6-
ScalarMaybeUninit, StackPopCleanup,
6+
StackPopCleanup,
77
};
88

99
use rustc_hir::def::DefKind;
@@ -170,10 +170,7 @@ pub(super) fn op_to_const<'tcx>(
170170
// see comment on `let try_as_immediate` above
171171
Err(imm) => match *imm {
172172
_ if imm.layout.is_zst() => ConstValue::ZeroSized,
173-
Immediate::Scalar(x) => match x {
174-
ScalarMaybeUninit::Scalar(s) => ConstValue::Scalar(s),
175-
ScalarMaybeUninit::Uninit => to_const_value(&op.assert_mem_place()),
176-
},
173+
Immediate::Scalar(x) => ConstValue::Scalar(x),
177174
Immediate::ScalarPair(a, b) => {
178175
debug!("ScalarPair(a: {:?}, b: {:?})", a, b);
179176
// We know `offset` is relative to the allocation, so we can use `into_parts`.

compiler/rustc_const_eval/src/const_eval/machine.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -347,8 +347,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
347347
};
348348
match intrinsic_name {
349349
sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
350-
let a = ecx.read_immediate(&args[0])?.to_scalar()?;
351-
let b = ecx.read_immediate(&args[1])?.to_scalar()?;
350+
let a = ecx.read_scalar(&args[0])?;
351+
let b = ecx.read_scalar(&args[1])?;
352352
let cmp = if intrinsic_name == sym::ptr_guaranteed_eq {
353353
ecx.guaranteed_eq(a, b)?
354354
} else {

compiler/rustc_const_eval/src/const_eval/valtrees.rs

+5-10
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use super::machine::CompileTimeEvalContext;
33
use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES};
44
use crate::interpret::{
55
intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta,
6-
MemoryKind, PlaceTy, Scalar, ScalarMaybeUninit,
6+
MemoryKind, PlaceTy, Scalar,
77
};
88
use crate::interpret::{MPlaceTy, Value};
99
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
@@ -90,7 +90,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
9090
let Ok(val) = ecx.read_immediate(&place.into()) else {
9191
return Err(ValTreeCreationError::Other);
9292
};
93-
let val = val.to_scalar().unwrap();
93+
let val = val.to_scalar();
9494
*num_nodes += 1;
9595

9696
Ok(ty::ValTree::Leaf(val.assert_int()))
@@ -349,11 +349,7 @@ fn valtree_into_mplace<'tcx>(
349349
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
350350
let scalar_int = valtree.unwrap_leaf();
351351
debug!("writing trivial valtree {:?} to place {:?}", scalar_int, place);
352-
ecx.write_immediate(
353-
Immediate::Scalar(ScalarMaybeUninit::Scalar(scalar_int.into())),
354-
&place.into(),
355-
)
356-
.unwrap();
352+
ecx.write_immediate(Immediate::Scalar(scalar_int.into()), &place.into()).unwrap();
357353
}
358354
ty::Ref(_, inner_ty, _) => {
359355
let mut pointee_place = create_pointee_place(ecx, *inner_ty, valtree);
@@ -366,11 +362,10 @@ fn valtree_into_mplace<'tcx>(
366362
let imm = match inner_ty.kind() {
367363
ty::Slice(_) | ty::Str => {
368364
let len = valtree.unwrap_branch().len();
369-
let len_scalar =
370-
ScalarMaybeUninit::Scalar(Scalar::from_machine_usize(len as u64, &tcx));
365+
let len_scalar = Scalar::from_machine_usize(len as u64, &tcx);
371366

372367
Immediate::ScalarPair(
373-
ScalarMaybeUninit::from_maybe_pointer((*pointee_place).ptr, &tcx),
368+
Scalar::from_maybe_pointer((*pointee_place).ptr, &tcx),
374369
len_scalar,
375370
)
376371
}

compiler/rustc_const_eval/src/interpret/cast.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
123123
match src.layout.ty.kind() {
124124
// Floating point
125125
Float(FloatTy::F32) => {
126-
return Ok(self.cast_from_float(src.to_scalar()?.to_f32()?, cast_ty).into());
126+
return Ok(self.cast_from_float(src.to_scalar().to_f32()?, cast_ty).into());
127127
}
128128
Float(FloatTy::F64) => {
129-
return Ok(self.cast_from_float(src.to_scalar()?.to_f64()?, cast_ty).into());
129+
return Ok(self.cast_from_float(src.to_scalar().to_f64()?, cast_ty).into());
130130
}
131131
// The rest is integer/pointer-"like", including fn ptr casts
132132
_ => assert!(
@@ -153,7 +153,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
153153
assert_eq!(dest_layout.size, self.pointer_size());
154154
assert!(src.layout.ty.is_unsafe_ptr());
155155
return match **src {
156-
Immediate::ScalarPair(data, _) => Ok(data.check_init()?.into()),
156+
Immediate::ScalarPair(data, _) => Ok(data.into()),
157157
Immediate::Scalar(..) => span_bug!(
158158
self.cur_span(),
159159
"{:?} input to a fat-to-thin cast ({:?} -> {:?})",
@@ -167,7 +167,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
167167
}
168168

169169
// # The remaining source values are scalar and "int-like".
170-
let scalar = src.to_scalar()?;
170+
let scalar = src.to_scalar();
171171
Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into())
172172
}
173173

@@ -179,7 +179,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
179179
assert_matches!(src.layout.ty.kind(), ty::RawPtr(_) | ty::FnPtr(_));
180180
assert!(cast_ty.is_integral());
181181

182-
let scalar = src.to_scalar()?;
182+
let scalar = src.to_scalar();
183183
let ptr = scalar.to_pointer(self)?;
184184
match ptr.into_pointer_or_addr() {
185185
Ok(ptr) => M::expose_ptr(self, ptr)?,
@@ -197,7 +197,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
197197
assert_matches!(cast_ty.kind(), ty::RawPtr(_));
198198

199199
// First cast to usize.
200-
let scalar = src.to_scalar()?;
200+
let scalar = src.to_scalar();
201201
let addr = self.cast_from_int_like(scalar, src.layout, self.tcx.types.usize)?;
202202
let addr = addr.to_machine_usize(self)?;
203203

@@ -291,7 +291,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
291291

292292
match (&src_pointee_ty.kind(), &dest_pointee_ty.kind()) {
293293
(&ty::Array(_, length), &ty::Slice(_)) => {
294-
let ptr = self.read_immediate(src)?.to_scalar()?;
294+
let ptr = self.read_scalar(src)?;
295295
// u64 cast is from usize to u64, which is always good
296296
let val =
297297
Immediate::new_slice(ptr, length.eval_usize(*self.tcx, self.param_env), self);
@@ -303,7 +303,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
303303
// A NOP cast that doesn't actually change anything, should be allowed even with mismatching vtables.
304304
return self.write_immediate(*val, dest);
305305
}
306-
let (old_data, old_vptr) = val.to_scalar_pair()?;
306+
let (old_data, old_vptr) = val.to_scalar_pair();
307307
let old_vptr = old_vptr.to_pointer(self)?;
308308
let (ty, old_trait) = self.get_ptr_vtable(old_vptr)?;
309309
if old_trait != data_a.principal() {
@@ -315,7 +315,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
315315
(_, &ty::Dynamic(ref data, _)) => {
316316
// Initial cast from sized to dyn trait
317317
let vtable = self.get_vtable_ptr(src_pointee_ty, data.principal())?;
318-
let ptr = self.read_immediate(src)?.to_scalar()?;
318+
let ptr = self.read_scalar(src)?;
319319
let val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx);
320320
self.write_immediate(val, dest)
321321
}

compiler/rustc_const_eval/src/interpret/eval_context.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayou
2121
use super::{
2222
AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace,
2323
MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, PointerArithmetic, Provenance,
24-
Scalar, ScalarMaybeUninit, StackPopJump,
24+
Scalar, StackPopJump,
2525
};
2626
use crate::transform::validate::equal_up_to_regions;
2727

@@ -991,16 +991,16 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug
991991
}
992992
LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => {
993993
write!(fmt, " {:?}", val)?;
994-
if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _size)) = val {
994+
if let Scalar::Ptr(ptr, _size) = val {
995995
allocs.push(ptr.provenance.get_alloc_id());
996996
}
997997
}
998998
LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => {
999999
write!(fmt, " ({:?}, {:?})", val1, val2)?;
1000-
if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _size)) = val1 {
1000+
if let Scalar::Ptr(ptr, _size) = val1 {
10011001
allocs.push(ptr.provenance.get_alloc_id());
10021002
}
1003-
if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _size)) = val2 {
1003+
if let Scalar::Ptr(ptr, _size) = val2 {
10041004
allocs.push(ptr.provenance.get_alloc_id());
10051005
}
10061006
}

compiler/rustc_const_eval/src/interpret/intrinsics.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
184184
| sym::bitreverse => {
185185
let ty = substs.type_at(0);
186186
let layout_of = self.layout_of(ty)?;
187-
let val = self.read_scalar(&args[0])?.check_init()?;
187+
let val = self.read_scalar(&args[0])?;
188188
let bits = val.to_bits(layout_of.size)?;
189189
let kind = match layout_of.abi {
190190
Abi::Scalar(scalar) => scalar.primitive(),
@@ -256,7 +256,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
256256
let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, &l, &r)?;
257257
if overflowed {
258258
let layout = self.layout_of(substs.type_at(0))?;
259-
let r_val = r.to_scalar()?.to_bits(layout.size)?;
259+
let r_val = r.to_scalar().to_bits(layout.size)?;
260260
if let sym::unchecked_shl | sym::unchecked_shr = intrinsic_name {
261261
throw_ub_format!("overflowing shift by {} in `{}`", r_val, intrinsic_name);
262262
} else {
@@ -269,9 +269,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
269269
// rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW))
270270
// rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW))
271271
let layout = self.layout_of(substs.type_at(0))?;
272-
let val = self.read_scalar(&args[0])?.check_init()?;
272+
let val = self.read_scalar(&args[0])?;
273273
let val_bits = val.to_bits(layout.size)?;
274-
let raw_shift = self.read_scalar(&args[1])?.check_init()?;
274+
let raw_shift = self.read_scalar(&args[1])?;
275275
let raw_shift_bits = raw_shift.to_bits(layout.size)?;
276276
let width_bits = u128::from(layout.size.bits());
277277
let shift_bits = raw_shift_bits % width_bits;
@@ -507,7 +507,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
507507
self.copy_op(&args[0], dest, /*allow_transmute*/ false)?;
508508
}
509509
sym::assume => {
510-
let cond = self.read_scalar(&args[0])?.check_init()?.to_bool()?;
510+
let cond = self.read_scalar(&args[0])?.to_bool()?;
511511
if !cond {
512512
throw_ub_format!("`assume` intrinsic called with `false`");
513513
}
@@ -570,7 +570,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
570570
// term since the sign of the second term can be inferred from this and
571571
// the fact that the operation has overflowed (if either is 0 no
572572
// overflow can occur)
573-
let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?;
573+
let first_term: u128 = l.to_scalar().to_bits(l.layout.size)?;
574574
let first_term_positive = first_term & (1 << (num_bits - 1)) == 0;
575575
if first_term_positive {
576576
// Negative overflow not possible since the positive first term

compiler/rustc_const_eval/src/interpret/machine.rs

+5-13
Original file line numberDiff line numberDiff line change
@@ -123,18 +123,15 @@ pub trait Machine<'mir, 'tcx>: Sized {
123123
/// Whether memory accesses should be alignment-checked.
124124
fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
125125

126-
/// Whether, when checking alignment, we should `force_int` and thus support
126+
/// Whether, when checking alignment, we should look at the actual address and thus support
127127
/// custom alignment logic based on whatever the integer address happens to be.
128128
///
129-
/// Requires Provenance::OFFSET_IS_ADDR to be true.
130-
fn force_int_for_alignment_check(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
129+
/// If this returns true, Provenance::OFFSET_IS_ADDR must be true.
130+
fn use_addr_for_alignment_check(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
131131

132132
/// Whether to enforce the validity invariant
133133
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
134134

135-
/// Whether to enforce integers and floats being initialized.
136-
fn enforce_number_init(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
137-
138135
/// Whether function calls should be [ABI](CallAbi)-checked.
139136
fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
140137
true
@@ -437,16 +434,11 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
437434
type FrameExtra = ();
438435

439436
#[inline(always)]
440-
fn force_int_for_alignment_check(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
441-
// We do not support `force_int`.
437+
fn use_addr_for_alignment_check(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
438+
// We do not support `use_addr`.
442439
false
443440
}
444441

445-
#[inline(always)]
446-
fn enforce_number_init(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
447-
true
448-
}
449-
450442
#[inline(always)]
451443
fn checked_binop_checks_overflow(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
452444
true

compiler/rustc_const_eval/src/interpret/memory.rs

+9-23
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ use rustc_target::abi::{Align, HasDataLayout, Size};
2121
use super::{
2222
alloc_range, AllocId, AllocMap, AllocRange, Allocation, CheckInAllocMsg, GlobalAlloc, InterpCx,
2323
InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Provenance, Scalar,
24-
ScalarMaybeUninit,
2524
};
2625

2726
#[derive(Debug, PartialEq, Copy, Clone)]
@@ -445,8 +444,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
445444
// Test align. Check this last; if both bounds and alignment are violated
446445
// we want the error to be about the bounds.
447446
if let Some(align) = align {
448-
if M::force_int_for_alignment_check(self) {
449-
// `force_int_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true.
447+
if M::use_addr_for_alignment_check(self) {
448+
// `use_addr_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true.
450449
check_offset_align(ptr.addr().bytes(), align)?;
451450
} else {
452451
// Check allocation alignment and offset alignment.
@@ -901,11 +900,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a,
901900
/// Reading and writing.
902901
impl<'tcx, 'a, Prov: Provenance, Extra> AllocRefMut<'a, 'tcx, Prov, Extra> {
903902
/// `range` is relative to this allocation reference, not the base of the allocation.
904-
pub fn write_scalar(
905-
&mut self,
906-
range: AllocRange,
907-
val: ScalarMaybeUninit<Prov>,
908-
) -> InterpResult<'tcx> {
903+
pub fn write_scalar(&mut self, range: AllocRange, val: Scalar<Prov>) -> InterpResult<'tcx> {
909904
let range = self.range.subrange(range);
910905
debug!("write_scalar at {:?}{range:?}: {val:?}", self.alloc_id);
911906
Ok(self
@@ -915,11 +910,7 @@ impl<'tcx, 'a, Prov: Provenance, Extra> AllocRefMut<'a, 'tcx, Prov, Extra> {
915910
}
916911

917912
/// `offset` is relative to this allocation reference, not the base of the allocation.
918-
pub fn write_ptr_sized(
919-
&mut self,
920-
offset: Size,
921-
val: ScalarMaybeUninit<Prov>,
922-
) -> InterpResult<'tcx> {
913+
pub fn write_ptr_sized(&mut self, offset: Size, val: Scalar<Prov>) -> InterpResult<'tcx> {
923914
self.write_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size), val)
924915
}
925916

@@ -938,7 +929,7 @@ impl<'tcx, 'a, Prov: Provenance, Extra> AllocRef<'a, 'tcx, Prov, Extra> {
938929
&self,
939930
range: AllocRange,
940931
read_provenance: bool,
941-
) -> InterpResult<'tcx, ScalarMaybeUninit<Prov>> {
932+
) -> InterpResult<'tcx, Scalar<Prov>> {
942933
let range = self.range.subrange(range);
943934
let res = self
944935
.alloc
@@ -949,28 +940,23 @@ impl<'tcx, 'a, Prov: Provenance, Extra> AllocRef<'a, 'tcx, Prov, Extra> {
949940
}
950941

951942
/// `range` is relative to this allocation reference, not the base of the allocation.
952-
pub fn read_integer(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit<Prov>> {
943+
pub fn read_integer(&self, range: AllocRange) -> InterpResult<'tcx, Scalar<Prov>> {
953944
self.read_scalar(range, /*read_provenance*/ false)
954945
}
955946

956947
/// `offset` is relative to this allocation reference, not the base of the allocation.
957-
pub fn read_pointer(&self, offset: Size) -> InterpResult<'tcx, ScalarMaybeUninit<Prov>> {
948+
pub fn read_pointer(&self, offset: Size) -> InterpResult<'tcx, Scalar<Prov>> {
958949
self.read_scalar(
959950
alloc_range(offset, self.tcx.data_layout().pointer_size),
960951
/*read_provenance*/ true,
961952
)
962953
}
963954

964955
/// `range` is relative to this allocation reference, not the base of the allocation.
965-
pub fn check_bytes(
966-
&self,
967-
range: AllocRange,
968-
allow_uninit: bool,
969-
allow_ptr: bool,
970-
) -> InterpResult<'tcx> {
956+
pub fn check_bytes(&self, range: AllocRange) -> InterpResult<'tcx> {
971957
Ok(self
972958
.alloc
973-
.check_bytes(&self.tcx, self.range.subrange(range), allow_uninit, allow_ptr)
959+
.check_bytes(&self.tcx, self.range.subrange(range))
974960
.map_err(|e| e.to_interp_error(self.alloc_id))?)
975961
}
976962

0 commit comments

Comments
 (0)