Skip to content

Commit 20db781

Browse files
committed
Auto merge of #53671 - RalfJung:miri-refactor, r=<try>
Miri engine cleanup * Unify the two maps in memory to store the allocation and its kind together. * Share the handling of statics between CTFE and miri: The miri engine always uses "lazy" `AllocType::Static` when encountering a static. Acessing that static invokes CTFE (no matter the machine). The machine only has any influence when writing to a static, which CTFE outright rejects (but miri makes a copy-on-write). * Add an `AllocId` to by-ref consts so miri can use them as operands without making copies. * Move responsibilities around for the `eval_fn_call` machine hook: The hook just has to find the MIR (or entirely take care of everything); pushing the new stack frame is taken care of by the miri engine. * Expose the intrinsics and lang items implemented by CTFE so miri does not have to reimplement them. * Allow Machine to hook into foreign statics (used by miri to get rid of some other hacks). * Clean up function calling. * Switch const sanity check to work on operands, not mplaces. * Move const_eval out of rustc_mir::interpret, to make sure that it does not access private implementation details. In particular, we can finally make `eval_operand` take `&self`. :-) Should be merged after #53609, across which I will rebase.
2 parents b638d8c + c4c51be commit 20db781

35 files changed

+1596
-1408
lines changed

src/Cargo.lock

-2
Original file line numberDiff line numberDiff line change
@@ -1240,9 +1240,7 @@ dependencies = [
12401240
"colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
12411241
"compiletest_rs 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
12421242
"env_logger 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)",
1243-
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
12441243
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
1245-
"regex 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
12461244
]
12471245

12481246
[[package]]

src/librustc/ich/impls_ty.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,8 @@ for ::mir::interpret::ConstValue<'gcx> {
384384
a.hash_stable(hcx, hasher);
385385
b.hash_stable(hcx, hasher);
386386
}
387-
ByRef(alloc, offset) => {
387+
ByRef(id, alloc, offset) => {
388+
id.hash_stable(hcx, hasher);
388389
alloc.hash_stable(hcx, hasher);
389390
offset.hash_stable(hcx, hasher);
390391
}
@@ -446,7 +447,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::Allocation {
446447
}
447448
self.undef_mask.hash_stable(hcx, hasher);
448449
self.align.hash_stable(hcx, hasher);
449-
self.runtime_mutability.hash_stable(hcx, hasher);
450+
self.mutability.hash_stable(hcx, hasher);
450451
}
451452
}
452453

@@ -516,7 +517,6 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> {
516517
InvalidMemoryAccess |
517518
InvalidFunctionPointer |
518519
InvalidBool |
519-
InvalidDiscriminant |
520520
InvalidNullPointerUsage |
521521
ReadPointerAsBytes |
522522
ReadBytesAsPointer |
@@ -549,6 +549,7 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> {
549549
GeneratorResumedAfterReturn |
550550
GeneratorResumedAfterPanic |
551551
InfiniteLoop => {}
552+
InvalidDiscriminant(val) => val.hash_stable(hcx, hasher),
552553
Panic { ref msg, ref file, line, col } => {
553554
msg.hash_stable(hcx, hasher);
554555
file.hash_stable(hcx, hasher);

src/librustc/mir/interpret/error.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ pub enum EvalErrorKind<'tcx, O> {
190190
InvalidMemoryAccess,
191191
InvalidFunctionPointer,
192192
InvalidBool,
193-
InvalidDiscriminant,
193+
InvalidDiscriminant(u128),
194194
PointerOutOfBounds {
195195
ptr: Pointer,
196196
access: bool,
@@ -302,7 +302,7 @@ impl<'tcx, O> EvalErrorKind<'tcx, O> {
302302
"tried to use a function pointer after offsetting it",
303303
InvalidBool =>
304304
"invalid boolean value read",
305-
InvalidDiscriminant =>
305+
InvalidDiscriminant(..) =>
306306
"invalid enum discriminant value read",
307307
PointerOutOfBounds { .. } =>
308308
"pointer offset outside bounds of allocation",
@@ -488,6 +488,8 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
488488
align {}", size.bytes(), align.abi(), size2.bytes(), align2.abi()),
489489
Panic { ref msg, line, col, ref file } =>
490490
write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col),
491+
InvalidDiscriminant(val) =>
492+
write!(f, "encountered invalid enum discriminant {}", val),
491493
_ => write!(f, "{}", self.description()),
492494
}
493495
}

src/librustc/mir/interpret/mod.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,8 @@ impl fmt::Display for AllocId {
393393
pub enum AllocType<'tcx, M> {
394394
/// The alloc id is used as a function pointer
395395
Function(Instance<'tcx>),
396-
/// The alloc id points to a static variable
396+
/// The alloc id points to a "lazy" static variable that did not get computed (yet).
397+
/// This is also used to break the cycle in recursive statics.
397398
Static(DefId),
398399
/// The alloc id points to memory
399400
Memory(M)
@@ -496,13 +497,14 @@ pub struct Allocation {
496497
pub undef_mask: UndefMask,
497498
/// The alignment of the allocation to detect unaligned reads.
498499
pub align: Align,
499-
/// Whether the allocation (of a static) should be put into mutable memory when codegenning
500-
///
501-
/// Only happens for `static mut` or `static` with interior mutability
502-
pub runtime_mutability: Mutability,
500+
/// Whether the allocation is mutable.
501+
/// Also used by codegen to determine if a static should be put into mutable memory,
502+
/// which happens for `static mut` and `static` with interior mutability.
503+
pub mutability: Mutability,
503504
}
504505

505506
impl Allocation {
507+
/// Creates a read-only allocation initialized by the given bytes
506508
pub fn from_bytes(slice: &[u8], align: Align) -> Self {
507509
let mut undef_mask = UndefMask::new(Size::ZERO);
508510
undef_mask.grow(Size::from_bytes(slice.len() as u64), true);
@@ -511,7 +513,7 @@ impl Allocation {
511513
relocations: Relocations::new(),
512514
undef_mask,
513515
align,
514-
runtime_mutability: Mutability::Immutable,
516+
mutability: Mutability::Immutable,
515517
}
516518
}
517519

@@ -526,7 +528,7 @@ impl Allocation {
526528
relocations: Relocations::new(),
527529
undef_mask: UndefMask::new(size),
528530
align,
529-
runtime_mutability: Mutability::Immutable,
531+
mutability: Mutability::Mutable,
530532
}
531533
}
532534
}

src/librustc/mir/interpret/value.rs

+94-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use ty::layout::{HasDataLayout, Size};
1414
use ty::subst::Substs;
1515
use hir::def_id::DefId;
1616

17-
use super::{EvalResult, Pointer, PointerArithmetic, Allocation};
17+
use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend};
1818

1919
/// Represents a constant value in Rust. Scalar and ScalarPair are optimizations which
2020
/// matches the LocalValue optimizations for easy conversions between Value and ConstValue.
@@ -32,8 +32,9 @@ pub enum ConstValue<'tcx> {
3232
///
3333
/// The second field may be undef in case of `Option<usize>::None`
3434
ScalarPair(Scalar, ScalarMaybeUndef),
35-
/// Used only for the remaining cases. An allocation + offset into the allocation
36-
ByRef(&'tcx Allocation, Size),
35+
/// Used only for the remaining cases. An allocation + offset into the allocation.
36+
/// Invariant: The AllocId matches the allocation.
37+
ByRef(AllocId, &'tcx Allocation, Size),
3738
}
3839

3940
impl<'tcx> ConstValue<'tcx> {
@@ -185,6 +186,57 @@ impl<'tcx> Scalar {
185186
_ => err!(InvalidBool),
186187
}
187188
}
189+
190+
pub fn to_char(self) -> EvalResult<'tcx, char> {
191+
let val = self.to_u32()?;
192+
match ::std::char::from_u32(val) {
193+
Some(c) => Ok(c),
194+
None => err!(InvalidChar(val as u128)),
195+
}
196+
}
197+
198+
pub fn to_u8(self) -> EvalResult<'static, u8> {
199+
let sz = Size::from_bits(8);
200+
let b = self.to_bits(sz)?;
201+
assert_eq!(b as u8 as u128, b);
202+
Ok(b as u8)
203+
}
204+
205+
pub fn to_u32(self) -> EvalResult<'static, u32> {
206+
let sz = Size::from_bits(32);
207+
let b = self.to_bits(sz)?;
208+
assert_eq!(b as u32 as u128, b);
209+
Ok(b as u32)
210+
}
211+
212+
pub fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64> {
213+
let b = self.to_bits(cx.data_layout().pointer_size)?;
214+
assert_eq!(b as u64 as u128, b);
215+
Ok(b as u64)
216+
}
217+
218+
pub fn to_i8(self) -> EvalResult<'static, i8> {
219+
let sz = Size::from_bits(8);
220+
let b = self.to_bits(sz)?;
221+
let b = sign_extend(b, sz) as i128;
222+
assert_eq!(b as i8 as i128, b);
223+
Ok(b as i8)
224+
}
225+
226+
pub fn to_i32(self) -> EvalResult<'static, i32> {
227+
let sz = Size::from_bits(32);
228+
let b = self.to_bits(sz)?;
229+
let b = sign_extend(b, sz) as i128;
230+
assert_eq!(b as i32 as i128, b);
231+
Ok(b as i32)
232+
}
233+
234+
pub fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64> {
235+
let b = self.to_bits(cx.data_layout().pointer_size)?;
236+
let b = sign_extend(b, cx.data_layout().pointer_size) as i128;
237+
assert_eq!(b as i64 as i128, b);
238+
Ok(b as i64)
239+
}
188240
}
189241

190242
impl From<Pointer> for Scalar {
@@ -228,22 +280,61 @@ impl From<Scalar> for ScalarMaybeUndef {
228280
}
229281

230282
impl<'tcx> ScalarMaybeUndef {
283+
#[inline]
231284
pub fn not_undef(self) -> EvalResult<'static, Scalar> {
232285
match self {
233286
ScalarMaybeUndef::Scalar(scalar) => Ok(scalar),
234287
ScalarMaybeUndef::Undef => err!(ReadUndefBytes),
235288
}
236289
}
237290

291+
#[inline(always)]
238292
pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
239293
self.not_undef()?.to_ptr()
240294
}
241295

296+
#[inline(always)]
242297
pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
243298
self.not_undef()?.to_bits(target_size)
244299
}
245300

301+
#[inline(always)]
246302
pub fn to_bool(self) -> EvalResult<'tcx, bool> {
247303
self.not_undef()?.to_bool()
248304
}
305+
306+
#[inline(always)]
307+
pub fn to_char(self) -> EvalResult<'tcx, char> {
308+
self.not_undef()?.to_char()
309+
}
310+
311+
#[inline(always)]
312+
pub fn to_u8(self) -> EvalResult<'tcx, u8> {
313+
self.not_undef()?.to_u8()
314+
}
315+
316+
#[inline(always)]
317+
pub fn to_u32(self) -> EvalResult<'tcx, u32> {
318+
self.not_undef()?.to_u32()
319+
}
320+
321+
#[inline(always)]
322+
pub fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'tcx, u64> {
323+
self.not_undef()?.to_usize(cx)
324+
}
325+
326+
#[inline(always)]
327+
pub fn to_i8(self) -> EvalResult<'tcx, i8> {
328+
self.not_undef()?.to_i8()
329+
}
330+
331+
#[inline(always)]
332+
pub fn to_i32(self) -> EvalResult<'tcx, i32> {
333+
self.not_undef()?.to_i32()
334+
}
335+
336+
#[inline(always)]
337+
pub fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'tcx, i64> {
338+
self.not_undef()?.to_isize(cx)
339+
}
249340
}

src/librustc/ty/context.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1043,13 +1043,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
10431043
}
10441044

10451045
let interned = self.global_arenas.const_allocs.alloc(alloc);
1046-
if let Some(prev) = allocs.replace(interned) {
1046+
if let Some(prev) = allocs.replace(interned) { // insert into interner
10471047
bug!("Tried to overwrite interned Allocation: {:#?}", prev)
10481048
}
10491049
interned
10501050
}
10511051

1052-
/// Allocates a byte or string literal for `mir::interpret`
1052+
/// Allocates a byte or string literal for `mir::interpret`, read-only
10531053
pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId {
10541054
// create an allocation that just contains these bytes
10551055
let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes);

src/librustc/ty/structural_impls.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ impl<'a, 'tcx, O: Lift<'tcx>> Lift<'tcx> for interpret::EvalErrorKind<'a, O> {
498498
InvalidMemoryAccess => InvalidMemoryAccess,
499499
InvalidFunctionPointer => InvalidFunctionPointer,
500500
InvalidBool => InvalidBool,
501-
InvalidDiscriminant => InvalidDiscriminant,
501+
InvalidDiscriminant(val) => InvalidDiscriminant(val),
502502
PointerOutOfBounds {
503503
ptr,
504504
access,
@@ -1139,7 +1139,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> {
11391139
match *self {
11401140
ConstValue::Scalar(v) => ConstValue::Scalar(v),
11411141
ConstValue::ScalarPair(a, b) => ConstValue::ScalarPair(a, b),
1142-
ConstValue::ByRef(alloc, offset) => ConstValue::ByRef(alloc, offset),
1142+
ConstValue::ByRef(id, alloc, offset) => ConstValue::ByRef(id, alloc, offset),
11431143
ConstValue::Unevaluated(def_id, substs) => {
11441144
ConstValue::Unevaluated(def_id, substs.fold_with(folder))
11451145
}
@@ -1150,7 +1150,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> {
11501150
match *self {
11511151
ConstValue::Scalar(_) |
11521152
ConstValue::ScalarPair(_, _) |
1153-
ConstValue::ByRef(_, _) => false,
1153+
ConstValue::ByRef(_, _, _) => false,
11541154
ConstValue::Unevaluated(_, substs) => substs.visit_with(visitor),
11551155
}
11561156
}

src/librustc_codegen_llvm/mir/constant.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ pub fn scalar_to_llvm(
5757
let base_addr = match alloc_type {
5858
Some(AllocType::Memory(alloc)) => {
5959
let init = const_alloc_to_llvm(cx, alloc);
60-
if alloc.runtime_mutability == Mutability::Mutable {
60+
if alloc.mutability == Mutability::Mutable {
6161
consts::addr_of_mut(cx, init, alloc.align, None)
6262
} else {
6363
consts::addr_of(cx, init, alloc.align, None)
@@ -134,7 +134,7 @@ pub fn codegen_static_initializer(
134134
let static_ = cx.tcx.const_eval(param_env.and(cid))?;
135135

136136
let alloc = match static_.val {
137-
ConstValue::ByRef(alloc, n) if n.bytes() == 0 => alloc,
137+
ConstValue::ByRef(_, alloc, n) if n.bytes() == 0 => alloc,
138138
_ => bug!("static const eval returned {:#?}", static_),
139139
};
140140
Ok((const_alloc_to_llvm(cx, alloc), alloc))

src/librustc_codegen_llvm/mir/operand.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ impl OperandRef<'ll, 'tcx> {
126126
};
127127
OperandValue::Pair(a_llval, b_llval)
128128
},
129-
ConstValue::ByRef(alloc, offset) => {
129+
ConstValue::ByRef(_, alloc, offset) => {
130130
return Ok(PlaceRef::from_const_alloc(bx, layout, alloc, offset).load(bx));
131131
},
132132
};

src/librustc_codegen_llvm/mir/place.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
458458
let layout = cx.layout_of(self.monomorphize(&ty));
459459
match bx.tcx().const_eval(param_env.and(cid)) {
460460
Ok(val) => match val.val {
461-
mir::interpret::ConstValue::ByRef(alloc, offset) => {
461+
mir::interpret::ConstValue::ByRef(_, alloc, offset) => {
462462
PlaceRef::from_const_alloc(bx, layout, alloc, offset)
463463
}
464464
_ => bug!("promoteds should have an allocation: {:?}", val),

src/librustc_lint/builtin.rs

+7-13
Original file line numberDiff line numberDiff line change
@@ -1614,21 +1614,15 @@ fn validate_const<'a, 'tcx>(
16141614
gid: ::rustc::mir::interpret::GlobalId<'tcx>,
16151615
what: &str,
16161616
) {
1617-
let mut ecx = ::rustc_mir::interpret::mk_eval_cx(tcx, gid.instance, param_env).unwrap();
1617+
let ecx = ::rustc_mir::interpret::mk_eval_cx(tcx, gid.instance, param_env).unwrap();
16181618
let result = (|| {
1619-
use rustc_target::abi::LayoutOf;
1620-
use rustc_mir::interpret::OpTy;
1621-
1622-
let op = ecx.const_value_to_op(constant.val)?;
1623-
let layout = ecx.layout_of(constant.ty)?;
1624-
let place = ecx.allocate_op(OpTy { op, layout })?.into();
1625-
1626-
let mut todo = vec![(place, Vec::new())];
1619+
let op = ecx.const_to_op(constant)?;
1620+
let mut todo = vec![(op, Vec::new())];
16271621
let mut seen = FxHashSet();
1628-
seen.insert(place);
1629-
while let Some((place, mut path)) = todo.pop() {
1630-
ecx.validate_mplace(
1631-
place,
1622+
seen.insert(op);
1623+
while let Some((op, mut path)) = todo.pop() {
1624+
ecx.validate_operand(
1625+
op,
16321626
&mut path,
16331627
&mut seen,
16341628
&mut todo,

0 commit comments

Comments
 (0)