]> git.proxmox.com Git - rustc.git/blame - src/librustc_mir/interpret/terminator/mod.rs
New upstream version 1.27.1+dfsg1
[rustc.git] / src / librustc_mir / interpret / terminator / mod.rs
CommitLineData
ea8adc8c 1use rustc::mir;
ff7c6d11
XL
2use rustc::ty::{self, Ty};
3use rustc::ty::layout::LayoutOf;
ea8adc8c 4use syntax::codemap::Span;
83c7162d 5use rustc_target::spec::abi::Abi;
ea8adc8c 6
ff7c6d11 7use rustc::mir::interpret::{EvalResult, PrimVal, Value};
0531ce1d 8use super::{EvalContext, Place, Machine, ValTy};
ea8adc8c
XL
9
10use rustc_data_structures::indexed_vec::Idx;
ff7c6d11 11use interpret::memory::HasMemory;
ea8adc8c
XL
12
13mod drop;
14
0531ce1d 15impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
ea8adc8c
XL
16 pub fn goto_block(&mut self, target: mir::BasicBlock) {
17 self.frame_mut().block = target;
18 self.frame_mut().stmt = 0;
19 }
20
21 pub(super) fn eval_terminator(
22 &mut self,
23 terminator: &mir::Terminator<'tcx>,
24 ) -> EvalResult<'tcx> {
25 use rustc::mir::TerminatorKind::*;
26 match terminator.kind {
27 Return => {
ff7c6d11 28 self.dump_local(self.frame().return_place);
ea8adc8c
XL
29 self.pop_stack_frame()?
30 }
31
32 Goto { target } => self.goto_block(target),
33
34 SwitchInt {
35 ref discr,
36 ref values,
37 ref targets,
38 ..
39 } => {
ea8adc8c
XL
40 let discr_val = self.eval_operand(discr)?;
41 let discr_prim = self.value_to_primval(discr_val)?;
42
43 // Branch to the `otherwise` case by default, if no match is found.
44 let mut target_block = targets[targets.len() - 1];
45
0531ce1d 46 for (index, &const_int) in values.iter().enumerate() {
83c7162d 47 if discr_prim.to_bytes()? == const_int {
ea8adc8c
XL
48 target_block = targets[index];
49 break;
50 }
51 }
52
53 self.goto_block(target_block);
54 }
55
56 Call {
57 ref func,
58 ref args,
59 ref destination,
60 ..
61 } => {
62 let destination = match *destination {
ff7c6d11 63 Some((ref lv, target)) => Some((self.eval_place(lv)?, target)),
ea8adc8c
XL
64 None => None,
65 };
66
ff7c6d11
XL
67 let func = self.eval_operand(func)?;
68 let (fn_def, sig) = match func.ty.sty {
ea8adc8c 69 ty::TyFnPtr(sig) => {
ff7c6d11 70 let fn_ptr = self.value_to_primval(func)?.to_ptr()?;
ea8adc8c 71 let instance = self.memory.get_fn(fn_ptr)?;
0531ce1d 72 let instance_ty = instance.ty(*self.tcx);
ea8adc8c
XL
73 match instance_ty.sty {
74 ty::TyFnDef(..) => {
0531ce1d
XL
75 let real_sig = instance_ty.fn_sig(*self.tcx);
76 let sig = self.tcx.normalize_erasing_late_bound_regions(
77 ty::ParamEnv::reveal_all(),
78 &sig,
79 );
80 let real_sig = self.tcx.normalize_erasing_late_bound_regions(
81 ty::ParamEnv::reveal_all(),
82 &real_sig,
83 );
ea8adc8c
XL
84 if !self.check_sig_compat(sig, real_sig)? {
85 return err!(FunctionPointerTyMismatch(real_sig, sig));
86 }
87 }
88 ref other => bug!("instance def ty: {:?}", other),
89 }
90 (instance, sig)
91 }
92 ty::TyFnDef(def_id, substs) => (
ff7c6d11 93 self.resolve(def_id, substs)?,
0531ce1d 94 func.ty.fn_sig(*self.tcx),
ea8adc8c
XL
95 ),
96 _ => {
ff7c6d11 97 let msg = format!("can't handle callee of type {:?}", func.ty);
ea8adc8c
XL
98 return err!(Unimplemented(msg));
99 }
100 };
101 let args = self.operands_to_args(args)?;
0531ce1d
XL
102 let sig = self.tcx.normalize_erasing_late_bound_regions(
103 ty::ParamEnv::reveal_all(),
104 &sig,
105 );
ea8adc8c
XL
106 self.eval_fn_call(
107 fn_def,
108 destination,
109 &args,
110 terminator.source_info.span,
111 sig,
112 )?;
113 }
114
115 Drop {
116 ref location,
117 target,
118 ..
119 } => {
120 // FIXME(CTFE): forbid drop in const eval
ff7c6d11
XL
121 let place = self.eval_place(location)?;
122 let ty = self.place_ty(location);
0531ce1d
XL
123 let ty = self.tcx.subst_and_normalize_erasing_regions(
124 self.substs(),
125 ty::ParamEnv::reveal_all(),
126 &ty,
127 );
ea8adc8c
XL
128 trace!("TerminatorKind::drop: {:?}, type {}", location, ty);
129
0531ce1d 130 let instance = ::monomorphize::resolve_drop_in_place(*self.tcx, ty);
ff7c6d11
XL
131 self.drop_place(
132 place,
ea8adc8c
XL
133 instance,
134 ty,
135 terminator.source_info.span,
136 target,
137 )?;
138 }
139
140 Assert {
141 ref cond,
142 expected,
143 ref msg,
144 target,
145 ..
146 } => {
147 let cond_val = self.eval_operand_to_primval(cond)?.to_bool()?;
148 if expected == cond_val {
149 self.goto_block(target);
150 } else {
83c7162d 151 use rustc::mir::interpret::EvalErrorKind::*;
ea8adc8c
XL
152 return match *msg {
153 BoundsCheck { ref len, ref index } => {
ea8adc8c
XL
154 let len = self.eval_operand_to_primval(len)
155 .expect("can't eval len")
156 .to_u64()?;
157 let index = self.eval_operand_to_primval(index)
158 .expect("can't eval index")
159 .to_u64()?;
83c7162d 160 err!(BoundsCheck { len, index })
ea8adc8c 161 }
83c7162d
XL
162 Overflow(op) => Err(Overflow(op).into()),
163 OverflowNeg => Err(OverflowNeg.into()),
164 DivisionByZero => Err(DivisionByZero.into()),
165 RemainderByZero => Err(RemainderByZero.into()),
ea8adc8c
XL
166 GeneratorResumedAfterReturn |
167 GeneratorResumedAfterPanic => unimplemented!(),
83c7162d 168 _ => bug!(),
ea8adc8c
XL
169 };
170 }
171 }
172
173 Yield { .. } => unimplemented!("{:#?}", terminator.kind),
174 GeneratorDrop => unimplemented!(),
175 DropAndReplace { .. } => unimplemented!(),
176 Resume => unimplemented!(),
ff7c6d11
XL
177 Abort => unimplemented!(),
178 FalseEdges { .. } => bug!("should have been eliminated by `simplify_branches` mir pass"),
2c00a5a8 179 FalseUnwind { .. } => bug!("should have been eliminated by `simplify_branches` mir pass"),
ea8adc8c
XL
180 Unreachable => return err!(Unreachable),
181 }
182
183 Ok(())
184 }
185
186 /// Decides whether it is okay to call the method with signature `real_sig` using signature `sig`.
187 /// FIXME: This should take into account the platform-dependent ABI description.
188 fn check_sig_compat(
189 &mut self,
190 sig: ty::FnSig<'tcx>,
191 real_sig: ty::FnSig<'tcx>,
192 ) -> EvalResult<'tcx, bool> {
ff7c6d11 193 fn check_ty_compat<'tcx>(ty: Ty<'tcx>, real_ty: Ty<'tcx>) -> bool {
ea8adc8c
XL
194 if ty == real_ty {
195 return true;
196 } // This is actually a fast pointer comparison
197 return match (&ty.sty, &real_ty.sty) {
198 // Permit changing the pointer type of raw pointers and references as well as
199 // mutability of raw pointers.
200 // TODO: Should not be allowed when fat pointers are involved.
ff7c6d11
XL
201 (&ty::TyRawPtr(_), &ty::TyRawPtr(_)) => true,
202 (&ty::TyRef(_, _), &ty::TyRef(_, _)) => {
ea8adc8c
XL
203 ty.is_mutable_pointer() == real_ty.is_mutable_pointer()
204 }
205 // rule out everything else
206 _ => false,
207 };
208 }
209
210 if sig.abi == real_sig.abi && sig.variadic == real_sig.variadic &&
211 sig.inputs_and_output.len() == real_sig.inputs_and_output.len() &&
212 sig.inputs_and_output
213 .iter()
214 .zip(real_sig.inputs_and_output)
215 .all(|(ty, real_ty)| check_ty_compat(ty, real_ty))
216 {
217 // Definitely good.
218 return Ok(true);
219 }
220
221 if sig.variadic || real_sig.variadic {
222 // We're not touching this
223 return Ok(false);
224 }
225
226 // We need to allow what comes up when a non-capturing closure is cast to a fn().
227 match (sig.abi, real_sig.abi) {
228 (Abi::Rust, Abi::RustCall) // check the ABIs. This makes the test here non-symmetric.
229 if check_ty_compat(sig.output(), real_sig.output()) && real_sig.inputs_and_output.len() == 3 => {
230 // First argument of real_sig must be a ZST
231 let fst_ty = real_sig.inputs_and_output[0];
ff7c6d11 232 if self.layout_of(fst_ty)?.is_zst() {
ea8adc8c
XL
233 // Second argument must be a tuple matching the argument list of sig
234 let snd_ty = real_sig.inputs_and_output[1];
235 match snd_ty.sty {
0531ce1d 236 ty::TyTuple(tys) if sig.inputs().len() == tys.len() =>
ea8adc8c
XL
237 if sig.inputs().iter().zip(tys).all(|(ty, real_ty)| check_ty_compat(ty, real_ty)) {
238 return Ok(true)
239 },
240 _ => {}
241 }
242 }
243 }
244 _ => {}
245 };
246
247 // Nope, this doesn't work.
248 return Ok(false);
249 }
250
251 fn eval_fn_call(
252 &mut self,
253 instance: ty::Instance<'tcx>,
ff7c6d11 254 destination: Option<(Place, mir::BasicBlock)>,
ea8adc8c
XL
255 args: &[ValTy<'tcx>],
256 span: Span,
257 sig: ty::FnSig<'tcx>,
258 ) -> EvalResult<'tcx> {
259 trace!("eval_fn_call: {:#?}", instance);
260 match instance.def {
261 ty::InstanceDef::Intrinsic(..) => {
262 let (ret, target) = match destination {
263 Some(dest) => dest,
264 _ => return err!(Unreachable),
265 };
266 let ty = sig.output();
ff7c6d11
XL
267 let layout = self.layout_of(ty)?;
268 M::call_intrinsic(self, instance, args, ret, layout, target)?;
ea8adc8c
XL
269 self.dump_local(ret);
270 Ok(())
271 }
272 // FIXME: figure out why we can't just go through the shim
273 ty::InstanceDef::ClosureOnceShim { .. } => {
274 if M::eval_fn_call(self, instance, destination, args, span, sig)? {
275 return Ok(());
276 }
277 let mut arg_locals = self.frame().mir.args_iter();
278 match sig.abi {
279 // closure as closure once
280 Abi::RustCall => {
281 for (arg_local, &valty) in arg_locals.zip(args) {
ff7c6d11 282 let dest = self.eval_place(&mir::Place::Local(arg_local))?;
ea8adc8c
XL
283 self.write_value(valty, dest)?;
284 }
285 }
286 // non capture closure as fn ptr
287 // need to inject zst ptr for closure object (aka do nothing)
288 // and need to pack arguments
289 Abi::Rust => {
290 trace!(
291 "arg_locals: {:?}",
292 self.frame().mir.args_iter().collect::<Vec<_>>()
293 );
294 trace!("args: {:?}", args);
295 let local = arg_locals.nth(1).unwrap();
296 for (i, &valty) in args.into_iter().enumerate() {
ff7c6d11 297 let dest = self.eval_place(&mir::Place::Local(local).field(
ea8adc8c
XL
298 mir::Field::new(i),
299 valty.ty,
300 ))?;
301 self.write_value(valty, dest)?;
302 }
303 }
304 _ => bug!("bad ABI for ClosureOnceShim: {:?}", sig.abi),
305 }
306 Ok(())
307 }
308 ty::InstanceDef::FnPtrShim(..) |
309 ty::InstanceDef::DropGlue(..) |
310 ty::InstanceDef::CloneShim(..) |
311 ty::InstanceDef::Item(_) => {
312 // Push the stack frame, and potentially be entirely done if the call got hooked
313 if M::eval_fn_call(self, instance, destination, args, span, sig)? {
314 return Ok(());
315 }
316
317 // Pass the arguments
318 let mut arg_locals = self.frame().mir.args_iter();
319 trace!("ABI: {:?}", sig.abi);
320 trace!(
321 "arg_locals: {:?}",
322 self.frame().mir.args_iter().collect::<Vec<_>>()
323 );
324 trace!("args: {:?}", args);
325 match sig.abi {
326 Abi::RustCall => {
327 assert_eq!(args.len(), 2);
328
329 {
330 // write first argument
331 let first_local = arg_locals.next().unwrap();
ff7c6d11 332 let dest = self.eval_place(&mir::Place::Local(first_local))?;
ea8adc8c
XL
333 self.write_value(args[0], dest)?;
334 }
335
336 // unpack and write all other args
ff7c6d11
XL
337 let layout = self.layout_of(args[1].ty)?;
338 if let ty::TyTuple(..) = args[1].ty.sty {
339 if self.frame().mir.args_iter().count() == layout.fields.count() + 1 {
ea8adc8c 340 match args[1].value {
ff7c6d11
XL
341 Value::ByRef(ptr, align) => {
342 for (i, arg_local) in arg_locals.enumerate() {
343 let field = layout.field(&self, i)?;
344 let offset = layout.fields.offset(i).bytes();
345 let arg = Value::ByRef(ptr.offset(offset, &self)?,
346 align.min(field.align));
ea8adc8c 347 let dest =
ff7c6d11 348 self.eval_place(&mir::Place::Local(arg_local))?;
ea8adc8c
XL
349 trace!(
350 "writing arg {:?} to {:?} (type: {})",
351 arg,
352 dest,
ff7c6d11 353 field.ty
ea8adc8c
XL
354 );
355 let valty = ValTy {
356 value: arg,
ff7c6d11 357 ty: field.ty,
ea8adc8c
XL
358 };
359 self.write_value(valty, dest)?;
360 }
361 }
362 Value::ByVal(PrimVal::Undef) => {}
363 other => {
ff7c6d11
XL
364 trace!("{:#?}, {:#?}", other, layout);
365 let mut layout = layout;
366 'outer: loop {
367 for i in 0..layout.fields.count() {
368 let field = layout.field(&self, i)?;
369 if layout.fields.offset(i).bytes() == 0 && layout.size == field.size {
370 layout = field;
371 continue 'outer;
372 }
373 }
374 break;
375 }
376 let dest = self.eval_place(&mir::Place::Local(
ea8adc8c
XL
377 arg_locals.next().unwrap(),
378 ))?;
379 let valty = ValTy {
380 value: other,
ff7c6d11 381 ty: layout.ty,
ea8adc8c
XL
382 };
383 self.write_value(valty, dest)?;
384 }
385 }
386 } else {
387 trace!("manual impl of rust-call ABI");
388 // called a manual impl of a rust-call function
ff7c6d11
XL
389 let dest = self.eval_place(
390 &mir::Place::Local(arg_locals.next().unwrap()),
ea8adc8c
XL
391 )?;
392 self.write_value(args[1], dest)?;
393 }
394 } else {
395 bug!(
396 "rust-call ABI tuple argument was {:#?}, {:#?}",
397 args[1].ty,
398 layout
399 );
400 }
401 }
402 _ => {
403 for (arg_local, &valty) in arg_locals.zip(args) {
ff7c6d11 404 let dest = self.eval_place(&mir::Place::Local(arg_local))?;
ea8adc8c
XL
405 self.write_value(valty, dest)?;
406 }
407 }
408 }
409 Ok(())
410 }
411 // cannot use the shim here, because that will only result in infinite recursion
412 ty::InstanceDef::Virtual(_, idx) => {
413 let ptr_size = self.memory.pointer_size();
ff7c6d11
XL
414 let ptr_align = self.tcx.data_layout.pointer_align;
415 let (ptr, vtable) = self.into_ptr_vtable_pair(args[0].value)?;
0531ce1d 416 let fn_ptr = self.memory.read_ptr_sized(
ff7c6d11
XL
417 vtable.offset(ptr_size * (idx as u64 + 3), &self)?,
418 ptr_align
ea8adc8c
XL
419 )?.to_ptr()?;
420 let instance = self.memory.get_fn(fn_ptr)?;
421 let mut args = args.to_vec();
ff7c6d11 422 let ty = self.layout_of(args[0].ty)?.field(&self, 0)?.ty;
ea8adc8c
XL
423 args[0].ty = ty;
424 args[0].value = ptr.to_value();
425 // recurse with concrete function
426 self.eval_fn_call(instance, destination, &args, span, sig)
427 }
428 }
429 }
430}