diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 154830c2e77e0..82cc1b7f66166 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -239,6 +239,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeEvaluator { type MemoryKinds = !; const MUT_STATIC_KIND: Option = None; // no mutating of statics allowed + const DETECT_LOOPS: bool = true; fn find_fn<'a>( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index f7277f8d27610..740d4e038df7e 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -65,6 +65,8 @@ pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { /// detector period. pub(super) steps_since_detector_enabled: isize, + /// Extra state to detect loops. + /// FIXME: Move this to the CTFE machine's state, out of the general miri engine. pub(super) loop_detector: InfiniteLoopDetector<'a, 'mir, 'tcx, M>, } @@ -110,6 +112,7 @@ pub struct Frame<'mir, 'tcx: 'mir> { pub stmt: usize, } +// Not using the macro because that does not support types depending on 'tcx impl<'a, 'mir, 'tcx: 'mir> HashStable> for Frame<'mir, 'tcx> { fn hash_stable( &self, @@ -144,11 +147,14 @@ pub enum StackPopCleanup { None { cleanup: bool }, } +// Can't use the macro here because that does not support named enum fields. impl<'a> HashStable> for StackPopCleanup { fn hash_stable( &self, hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { + hasher: &mut StableHasher) + { + mem::discriminant(self).hash_stable(hcx, hasher); match self { StackPopCleanup::Goto(ref block) => block.hash_stable(hcx, hasher), StackPopCleanup::None { cleanup } => cleanup.hash_stable(hcx, hasher), diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index 61963f6d3d354..f33cb4791029a 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -12,29 +12,29 @@ //! This separation exists to ensure that no fancy miri features like //! interpreting common C functions leak into CTFE. -use std::hash::Hash; - use rustc::hir::def_id::DefId; -use rustc::ich::StableHashingContext; use rustc::mir::interpret::{Allocation, EvalResult, Scalar}; use rustc::mir; use rustc::ty::{self, layout::TyLayout, query::TyCtxtAt}; -use rustc_data_structures::stable_hasher::HashStable; use super::{EvalContext, PlaceTy, OpTy}; /// Methods of this trait signifies a point where CTFE evaluation would fail /// and some use case dependent behaviour can instead be applied -pub trait Machine<'mir, 'tcx>: Clone + Eq + Hash + for<'a> HashStable> { +pub trait Machine<'mir, 'tcx>: Clone + Eq { /// Additional data that can be accessed via the Memory - type MemoryData: Clone + Eq + Hash + for<'a> HashStable>; + type MemoryData: Clone + Eq; /// Additional memory kinds a machine wishes to distinguish from the builtin ones - type MemoryKinds: ::std::fmt::Debug + Copy + Clone + Eq + Hash; + type MemoryKinds: ::std::fmt::Debug + Copy + Clone + Eq; /// The memory kind to use for mutated statics -- or None if those are not supported. const MUT_STATIC_KIND: Option; + /// Whether to attempt to detect infinite loops (any kind of infinite + /// execution, really). + const DETECT_LOOPS: bool; + /// Entry point to all function calls. /// /// Returns either the mir to use for the call, or `None` if execution should diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index d01593ca5e91c..64e0aeaaab7f0 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -13,6 +13,7 @@ //! All high-level functions to write to memory work on places as destinations. use std::convert::TryFrom; +use std::mem; use rustc::ich::StableHashingContext; use rustc::mir; @@ -57,11 +58,13 @@ pub enum Place { }, } +// Can't use the macro here because that does not support named enum fields. impl<'a> HashStable> for Place { fn hash_stable( &self, hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - + hasher: &mut StableHasher) + { + mem::discriminant(self).hash_stable(hcx, hasher); match self { Place::Ptr(mem_place) => mem_place.hash_stable(hcx, hasher), diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs index 8aa053baae9f0..0e8466905eb76 100644 --- a/src/librustc_mir/interpret/snapshot.rs +++ b/src/librustc_mir/interpret/snapshot.rs @@ -62,14 +62,13 @@ impl<'a, 'mir, 'tcx, M> InfiniteLoopDetector<'a, 'mir, 'tcx, M> pub fn observe_and_analyze( &mut self, tcx: &TyCtxt<'b, 'tcx, 'tcx>, - machine: &M, memory: &Memory<'a, 'mir, 'tcx, M>, stack: &[Frame<'mir, 'tcx>], ) -> EvalResult<'tcx, ()> { let mut hcx = tcx.get_stable_hashing_context(); let mut hasher = StableHasher::::new(); - (machine, stack).hash_stable(&mut hcx, &mut hasher); + stack.hash_stable(&mut hcx, &mut hasher); let hash = hasher.finish(); if self.hashes.insert(hash) { @@ -79,7 +78,7 @@ impl<'a, 'mir, 'tcx, M> InfiniteLoopDetector<'a, 'mir, 'tcx, M> info!("snapshotting the state of the interpreter"); - if self.snapshots.insert(EvalSnapshot::new(machine, memory, stack)) { + if self.snapshots.insert(EvalSnapshot::new(memory, stack)) { // Spurious collision or first cycle return Ok(()) } @@ -345,7 +344,6 @@ impl<'a, 'b, 'mir, 'tcx, M> SnapshotContext<'b> for Memory<'a, 'mir, 'tcx, M> /// The virtual machine state during const-evaluation at a given point in time. struct EvalSnapshot<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { - machine: M, memory: Memory<'a, 'mir, 'tcx, M>, stack: Vec>, } @@ -354,21 +352,20 @@ impl<'a, 'mir, 'tcx, M> EvalSnapshot<'a, 'mir, 'tcx, M> where M: Machine<'mir, 'tcx>, { fn new( - machine: &M, memory: &Memory<'a, 'mir, 'tcx, M>, - stack: &[Frame<'mir, 'tcx>]) -> Self { - + stack: &[Frame<'mir, 'tcx>] + ) -> Self { EvalSnapshot { - machine: machine.clone(), memory: memory.clone(), stack: stack.into(), } } fn snapshot<'b: 'a>(&'b self) - -> (&'b M, MemorySnapshot<'b, 'mir, 'tcx, M>, Vec>) { - let EvalSnapshot{ machine, memory, stack } = self; - (&machine, memory.snapshot(), stack.iter().map(|frame| frame.snapshot(memory)).collect()) + -> (MemorySnapshot<'b, 'mir, 'tcx, M>, Vec>) + { + let EvalSnapshot{ memory, stack } = self; + (memory.snapshot(), stack.iter().map(|frame| frame.snapshot(memory)).collect()) } } @@ -384,6 +381,8 @@ impl<'a, 'mir, 'tcx, M> Hash for EvalSnapshot<'a, 'mir, 'tcx, M> } } +// Not using the macro because we need special handling for `memory`, which the macro +// does not support at the same time as the extra bounds on the type. impl<'a, 'b, 'mir, 'tcx, M> HashStable> for EvalSnapshot<'a, 'mir, 'tcx, M> where M: Machine<'mir, 'tcx>, @@ -391,10 +390,10 @@ impl<'a, 'b, 'mir, 'tcx, M> HashStable> fn hash_stable( &self, hcx: &mut StableHashingContext<'b>, - hasher: &mut StableHasher) { - - let EvalSnapshot{ machine, memory, stack } = self; - (machine, &memory.data, stack).hash_stable(hcx, hasher); + hasher: &mut StableHasher) + { + let EvalSnapshot{ memory: _, stack } = self; + stack.hash_stable(hcx, hasher); } } diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 545333e879176..2835a46e7662d 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -65,6 +65,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { } } + if !M::DETECT_LOOPS { + return Ok(()); + } + if self.loop_detector.is_empty() { // First run of the loop detector @@ -75,7 +79,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { self.loop_detector.observe_and_analyze( &self.tcx, - &self.machine, &self.memory, &self.stack[..], )