1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
use rustc::mir;
use rustc::mir::interpret::EvalResult;
use super::{EvalContext, Machine};
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
pub fn inc_step_counter_and_detect_loops(&mut self) -> EvalResult<'tcx, ()> {
const DETECTOR_SNAPSHOT_PERIOD: isize = 256;
{
let steps = &mut self.steps_since_detector_enabled;
*steps += 1;
if *steps < 0 {
return Ok(());
}
*steps %= DETECTOR_SNAPSHOT_PERIOD;
if *steps != 0 {
return Ok(());
}
}
if self.loop_detector.is_empty() {
self.tcx.sess.span_warn(self.frame().span,
"Constant evaluating a complex constant, this might take some time");
}
self.loop_detector.observe_and_analyze(&self.machine, &self.stack, &self.memory)
}
pub fn step(&mut self) -> EvalResult<'tcx, bool> {
if self.stack.is_empty() {
return Ok(false);
}
let block = self.frame().block;
let stmt_id = self.frame().stmt;
let mir = self.mir();
let basic_block = &mir.basic_blocks()[block];
let old_frames = self.cur_frame();
if let Some(stmt) = basic_block.statements.get(stmt_id) {
assert_eq!(old_frames, self.cur_frame());
self.statement(stmt)?;
return Ok(true);
}
self.inc_step_counter_and_detect_loops()?;
let terminator = basic_block.terminator();
assert_eq!(old_frames, self.cur_frame());
self.terminator(terminator)?;
Ok(true)
}
fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<'tcx> {
trace!("{:?}", stmt);
use rustc::mir::StatementKind::*;
let frame_idx = self.cur_frame();
self.tcx.span = stmt.source_info.span;
self.memory.tcx.span = stmt.source_info.span;
match stmt.kind {
Assign(ref place, ref rvalue) => self.eval_rvalue_into_place(rvalue, place)?,
SetDiscriminant {
ref place,
variant_index,
} => {
let dest = self.eval_place(place)?;
let dest_ty = self.place_ty(place);
self.write_discriminant_value(dest_ty, dest, variant_index)?;
}
StorageLive(local) => {
let old_val = self.frame_mut().storage_live(local);
self.deallocate_local(old_val)?;
}
StorageDead(local) => {
let old_val = self.frame_mut().storage_dead(local);
self.deallocate_local(old_val)?;
}
ReadForMatch(..) => {}
Validate(op, ref places) => {
for operand in places {
M::validation_op(self, op, operand)?;
}
}
EndRegion(ce) => {
M::end_region(self, Some(ce))?;
}
UserAssertTy(..) => {}
Nop => {}
InlineAsm { .. } => return err!(InlineAsm),
}
self.stack[frame_idx].stmt += 1;
Ok(())
}
fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<'tcx> {
trace!("{:?}", terminator.kind);
self.tcx.span = terminator.source_info.span;
self.memory.tcx.span = terminator.source_info.span;
self.eval_terminator(terminator)?;
if !self.stack.is_empty() {
trace!("// {:?}", self.frame().block);
}
Ok(())
}
}