]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/interpret/terminator.rs
Various minor/cosmetic improvements to code
[rust.git] / src / librustc_mir / interpret / terminator.rs
1 // Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use std::borrow::Cow;
12
13 use rustc::{mir, ty};
14 use rustc::ty::layout::{self, TyLayout, LayoutOf};
15 use syntax::source_map::Span;
16 use rustc_target::spec::abi::Abi;
17
18 use rustc::mir::interpret::{EvalResult, PointerArithmetic, EvalErrorKind, Scalar};
19 use super::{
20     EvalContext, Machine, Immediate, OpTy, PlaceTy, MPlaceTy, Operand, StackPopCleanup
21 };
22
23 impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
24     #[inline]
25     pub fn goto_block(&mut self, target: Option<mir::BasicBlock>) -> EvalResult<'tcx> {
26         if let Some(target) = target {
27             self.frame_mut().block = target;
28             self.frame_mut().stmt = 0;
29             Ok(())
30         } else {
31             err!(Unreachable)
32         }
33     }
34
35     pub(super) fn eval_terminator(
36         &mut self,
37         terminator: &mir::Terminator<'tcx>,
38     ) -> EvalResult<'tcx> {
39         use rustc::mir::TerminatorKind::*;
40         match terminator.kind {
41             Return => {
42                 self.frame().return_place.map(|r| self.dump_place(*r));
43                 self.pop_stack_frame()?
44             }
45
46             Goto { target } => self.goto_block(Some(target))?,
47
48             SwitchInt {
49                 ref discr,
50                 ref values,
51                 ref targets,
52                 ..
53             } => {
54                 let discr = self.read_immediate(self.eval_operand(discr, None)?)?;
55                 trace!("SwitchInt({:?})", *discr);
56
57                 // Branch to the `otherwise` case by default, if no match is found.
58                 let mut target_block = targets[targets.len() - 1];
59
60                 for (index, &const_int) in values.iter().enumerate() {
61                     // Compare using binary_op, to also support pointer values
62                     let const_int = Scalar::from_uint(const_int, discr.layout.size);
63                     let (res, _) = self.binary_op(mir::BinOp::Eq,
64                         discr.to_scalar()?, discr.layout,
65                         const_int, discr.layout,
66                     )?;
67                     if res.to_bool()? {
68                         target_block = targets[index];
69                         break;
70                     }
71                 }
72
73                 self.goto_block(Some(target_block))?;
74             }
75
76             Call {
77                 ref func,
78                 ref args,
79                 ref destination,
80                 ..
81             } => {
82                 let (dest, ret) = match *destination {
83                     Some((ref lv, target)) => (Some(self.eval_place(lv)?), Some(target)),
84                     None => (None, None),
85                 };
86
87                 let func = self.eval_operand(func, None)?;
88                 let (fn_def, abi) = match func.layout.ty.sty {
89                     ty::FnPtr(sig) => {
90                         let caller_abi = sig.abi();
91                         let fn_ptr = self.read_scalar(func)?.to_ptr()?;
92                         let instance = self.memory.get_fn(fn_ptr)?;
93                         (instance, caller_abi)
94                     }
95                     ty::FnDef(def_id, substs) => {
96                         let sig = func.layout.ty.fn_sig(*self.tcx);
97                         (self.resolve(def_id, substs)?, sig.abi())
98                     },
99                     _ => {
100                         let msg = format!("can't handle callee of type {:?}", func.layout.ty);
101                         return err!(Unimplemented(msg));
102                     }
103                 };
104                 let args = self.eval_operands(args)?;
105                 self.eval_fn_call(
106                     fn_def,
107                     terminator.source_info.span,
108                     abi,
109                     &args[..],
110                     dest,
111                     ret,
112                 )?;
113             }
114
115             Drop {
116                 ref location,
117                 target,
118                 ..
119             } => {
120                 // FIXME(CTFE): forbid drop in const eval
121                 let place = self.eval_place(location)?;
122                 let ty = place.layout.ty;
123                 trace!("TerminatorKind::drop: {:?}, type {}", location, ty);
124
125                 let instance = ::monomorphize::resolve_drop_in_place(*self.tcx, ty);
126                 self.drop_in_place(
127                     place,
128                     instance,
129                     terminator.source_info.span,
130                     target,
131                 )?;
132             }
133
134             Assert {
135                 ref cond,
136                 expected,
137                 ref msg,
138                 target,
139                 ..
140             } => {
141                 let cond_val = self.read_immediate(self.eval_operand(cond, None)?)?
142                     .to_scalar()?.to_bool()?;
143                 if expected == cond_val {
144                     self.goto_block(Some(target))?;
145                 } else {
146                     // Compute error message
147                     use rustc::mir::interpret::EvalErrorKind::*;
148                     return match *msg {
149                         BoundsCheck { ref len, ref index } => {
150                             let len = self.read_immediate(self.eval_operand(len, None)?)
151                                 .expect("can't eval len").to_scalar()?
152                                 .to_bits(self.memory().pointer_size())? as u64;
153                             let index = self.read_immediate(self.eval_operand(index, None)?)
154                                 .expect("can't eval index").to_scalar()?
155                                 .to_bits(self.memory().pointer_size())? as u64;
156                             err!(BoundsCheck { len, index })
157                         }
158                         Overflow(op) => Err(Overflow(op).into()),
159                         OverflowNeg => Err(OverflowNeg.into()),
160                         DivisionByZero => Err(DivisionByZero.into()),
161                         RemainderByZero => Err(RemainderByZero.into()),
162                         GeneratorResumedAfterReturn |
163                         GeneratorResumedAfterPanic => unimplemented!(),
164                         _ => bug!(),
165                     };
166                 }
167             }
168
169             Yield { .. } |
170             GeneratorDrop |
171             DropAndReplace { .. } |
172             Resume |
173             Abort => unimplemented!("{:#?}", terminator.kind),
174             FalseEdges { .. } => bug!("should have been eliminated by\
175                                       `simplify_branches` mir pass"),
176             FalseUnwind { .. } => bug!("should have been eliminated by\
177                                        `simplify_branches` mir pass"),
178             Unreachable => return err!(Unreachable),
179         }
180
181         Ok(())
182     }
183
184     fn check_argument_compat(
185         rust_abi: bool,
186         caller: TyLayout<'tcx>,
187         callee: TyLayout<'tcx>,
188     ) -> bool {
189         if caller.ty == callee.ty {
190             // No question
191             return true;
192         }
193         if !rust_abi {
194             // Don't risk anything
195             return false;
196         }
197         // Compare layout
198         match (&caller.abi, &callee.abi) {
199             // Different valid ranges are okay (once we enforce validity,
200             // that will take care to make it UB to leave the range, just
201             // like for transmute).
202             (layout::Abi::Scalar(ref caller), layout::Abi::Scalar(ref callee)) =>
203                 caller.value == callee.value,
204             (layout::Abi::ScalarPair(ref caller1, ref caller2),
205              layout::Abi::ScalarPair(ref callee1, ref callee2)) =>
206                 caller1.value == callee1.value && caller2.value == callee2.value,
207             // Be conservative
208             _ => false
209         }
210     }
211
212     /// Pass a single argument, checking the types for compatibility.
213     fn pass_argument(
214         &mut self,
215         rust_abi: bool,
216         caller_arg: &mut impl Iterator<Item=OpTy<'tcx, M::PointerTag>>,
217         callee_arg: PlaceTy<'tcx, M::PointerTag>,
218     ) -> EvalResult<'tcx> {
219         if rust_abi && callee_arg.layout.is_zst() {
220             // Nothing to do.
221             trace!("Skipping callee ZST");
222             return Ok(());
223         }
224         let caller_arg = caller_arg.next()
225             .ok_or_else(|| EvalErrorKind::FunctionArgCountMismatch)?;
226         if rust_abi {
227             debug_assert!(!caller_arg.layout.is_zst(), "ZSTs must have been already filtered out");
228         }
229         // Now, check
230         if !Self::check_argument_compat(rust_abi, caller_arg.layout, callee_arg.layout) {
231             return err!(FunctionArgMismatch(caller_arg.layout.ty, callee_arg.layout.ty));
232         }
233         // We allow some transmutes here
234         self.copy_op_transmute(caller_arg, callee_arg)
235     }
236
237     /// Call this function -- pushing the stack frame and initializing the arguments.
238     fn eval_fn_call(
239         &mut self,
240         instance: ty::Instance<'tcx>,
241         span: Span,
242         caller_abi: Abi,
243         args: &[OpTy<'tcx, M::PointerTag>],
244         dest: Option<PlaceTy<'tcx, M::PointerTag>>,
245         ret: Option<mir::BasicBlock>,
246     ) -> EvalResult<'tcx> {
247         trace!("eval_fn_call: {:#?}", instance);
248
249         match instance.def {
250             ty::InstanceDef::Intrinsic(..) => {
251                 if caller_abi != Abi::RustIntrinsic {
252                     return err!(FunctionAbiMismatch(caller_abi, Abi::RustIntrinsic));
253                 }
254                 // The intrinsic itself cannot diverge, so if we got here without a return
255                 // place... (can happen e.g., for transmute returning `!`)
256                 let dest = match dest {
257                     Some(dest) => dest,
258                     None => return err!(Unreachable)
259                 };
260                 M::call_intrinsic(self, instance, args, dest)?;
261                 // No stack frame gets pushed, the main loop will just act as if the
262                 // call completed.
263                 self.goto_block(ret)?;
264                 self.dump_place(*dest);
265                 Ok(())
266             }
267             ty::InstanceDef::VtableShim(..) |
268             ty::InstanceDef::ClosureOnceShim { .. } |
269             ty::InstanceDef::FnPtrShim(..) |
270             ty::InstanceDef::DropGlue(..) |
271             ty::InstanceDef::CloneShim(..) |
272             ty::InstanceDef::Item(_) => {
273                 // ABI check
274                 {
275                     let callee_abi = {
276                         let instance_ty = instance.ty(*self.tcx);
277                         match instance_ty.sty {
278                             ty::FnDef(..) =>
279                                 instance_ty.fn_sig(*self.tcx).abi(),
280                             ty::Closure(..) => Abi::RustCall,
281                             ty::Generator(..) => Abi::Rust,
282                             _ => bug!("unexpected callee ty: {:?}", instance_ty),
283                         }
284                     };
285                     // Rust and RustCall are compatible
286                     let normalize_abi = |abi| if abi == Abi::RustCall { Abi::Rust } else { abi };
287                     if normalize_abi(caller_abi) != normalize_abi(callee_abi) {
288                         return err!(FunctionAbiMismatch(caller_abi, callee_abi));
289                     }
290                 }
291
292                 // We need MIR for this fn
293                 let mir = match M::find_fn(self, instance, args, dest, ret)? {
294                     Some(mir) => mir,
295                     None => return Ok(()),
296                 };
297
298                 self.push_stack_frame(
299                     instance,
300                     span,
301                     mir,
302                     dest,
303                     StackPopCleanup::Goto(ret),
304                 )?;
305
306                 // We want to pop this frame again in case there was an error, to put
307                 // the blame in the right location.  Until the 2018 edition is used in
308                 // the compiler, we have to do this with an immediately invoked function.
309                 let res = (||{
310                     trace!(
311                         "caller ABI: {:?}, args: {:#?}",
312                         caller_abi,
313                         args.iter()
314                             .map(|arg| (arg.layout.ty, format!("{:?}", **arg)))
315                             .collect::<Vec<_>>()
316                     );
317                     trace!(
318                         "spread_arg: {:?}, locals: {:#?}",
319                         mir.spread_arg,
320                         mir.args_iter()
321                             .map(|local|
322                                 (local, self.layout_of_local(self.frame(), local).unwrap().ty)
323                             )
324                             .collect::<Vec<_>>()
325                     );
326
327                     // Figure out how to pass which arguments.
328                     // We have two iterators: Where the arguments come from,
329                     // and where they go to.
330                     let rust_abi = match caller_abi {
331                         Abi::Rust | Abi::RustCall => true,
332                         _ => false
333                     };
334
335                     // For where they come from: If the ABI is RustCall, we untuple the
336                     // last incoming argument.  These two iterators do not have the same type,
337                     // so to keep the code paths uniform we accept an allocation
338                     // (for RustCall ABI only).
339                     let caller_args : Cow<[OpTy<'tcx, M::PointerTag>]> =
340                         if caller_abi == Abi::RustCall && !args.is_empty() {
341                             // Untuple
342                             let (&untuple_arg, args) = args.split_last().unwrap();
343                             trace!("eval_fn_call: Will pass last argument by untupling");
344                             Cow::from(args.iter().map(|&a| Ok(a))
345                                 .chain((0..untuple_arg.layout.fields.count()).into_iter()
346                                     .map(|i| self.operand_field(untuple_arg, i as u64))
347                                 )
348                                 .collect::<EvalResult<Vec<OpTy<'tcx, M::PointerTag>>>>()?)
349                         } else {
350                             // Plain arg passing
351                             Cow::from(args)
352                         };
353                     // Skip ZSTs
354                     let mut caller_iter = caller_args.iter()
355                         .filter(|op| !rust_abi || !op.layout.is_zst())
356                         .map(|op| *op);
357
358                     // Now we have to spread them out across the callee's locals,
359                     // taking into account the `spread_arg`.  If we could write
360                     // this is a single iterator (that handles `spread_arg`), then
361                     // `pass_argument` would be the loop body. It takes care to
362                     // not advance `caller_iter` for ZSTs.
363                     let mut locals_iter = mir.args_iter();
364                     while let Some(local) = locals_iter.next() {
365                         let dest = self.eval_place(&mir::Place::Local(local))?;
366                         if Some(local) == mir.spread_arg {
367                             // Must be a tuple
368                             for i in 0..dest.layout.fields.count() {
369                                 let dest = self.place_field(dest, i as u64)?;
370                                 self.pass_argument(rust_abi, &mut caller_iter, dest)?;
371                             }
372                         } else {
373                             // Normal argument
374                             self.pass_argument(rust_abi, &mut caller_iter, dest)?;
375                         }
376                     }
377                     // Now we should have no more caller args
378                     if caller_iter.next().is_some() {
379                         trace!("Caller has too many args over");
380                         return err!(FunctionArgCountMismatch);
381                     }
382                     // Don't forget to check the return type!
383                     if let Some(caller_ret) = dest {
384                         let callee_ret = self.eval_place(&mir::Place::Local(mir::RETURN_PLACE))?;
385                         if !Self::check_argument_compat(
386                             rust_abi,
387                             caller_ret.layout,
388                             callee_ret.layout,
389                         ) {
390                             return err!(FunctionRetMismatch(
391                                 caller_ret.layout.ty, callee_ret.layout.ty
392                             ));
393                         }
394                     } else {
395                         let callee_layout =
396                             self.layout_of_local(self.frame(), mir::RETURN_PLACE)?;
397                         if !callee_layout.abi.is_uninhabited() {
398                             return err!(FunctionRetMismatch(
399                                 self.tcx.types.never, callee_layout.ty
400                             ));
401                         }
402                     }
403                     Ok(())
404                 })();
405                 match res {
406                     Err(err) => {
407                         self.stack.pop();
408                         Err(err)
409                     }
410                     Ok(v) => Ok(v)
411                 }
412             }
413             // cannot use the shim here, because that will only result in infinite recursion
414             ty::InstanceDef::Virtual(_, idx) => {
415                 let ptr_size = self.pointer_size();
416                 let ptr = self.deref_operand(args[0])?;
417                 let vtable = ptr.vtable()?;
418                 self.memory.check_align(vtable.into(), self.tcx.data_layout.pointer_align.abi)?;
419                 let fn_ptr = self.memory.get(vtable.alloc_id)?.read_ptr_sized(
420                     self,
421                     vtable.offset(ptr_size * (idx as u64 + 3), self)?,
422                 )?.to_ptr()?;
423                 let instance = self.memory.get_fn(fn_ptr)?;
424
425                 // We have to patch the self argument, in particular get the layout
426                 // expected by the actual function. Cannot just use "field 0" due to
427                 // Box<self>.
428                 let mut args = args.to_vec();
429                 let pointee = args[0].layout.ty.builtin_deref(true).unwrap().ty;
430                 let fake_fat_ptr_ty = self.tcx.mk_mut_ptr(pointee);
431                 args[0].layout = self.layout_of(fake_fat_ptr_ty)?.field(self, 0)?;
432                 args[0].op = Operand::Immediate(Immediate::Scalar(ptr.ptr.into())); // strip vtable
433                 trace!("Patched self operand to {:#?}", args[0]);
434                 // recurse with concrete function
435                 self.eval_fn_call(instance, span, caller_abi, &args, dest, ret)
436             }
437         }
438     }
439
440     fn drop_in_place(
441         &mut self,
442         place: PlaceTy<'tcx, M::PointerTag>,
443         instance: ty::Instance<'tcx>,
444         span: Span,
445         target: mir::BasicBlock,
446     ) -> EvalResult<'tcx> {
447         trace!("drop_in_place: {:?},\n  {:?}, {:?}", *place, place.layout.ty, instance);
448         // We take the address of the object.  This may well be unaligned, which is fine
449         // for us here.  However, unaligned accesses will probably make the actual drop
450         // implementation fail -- a problem shared by rustc.
451         let place = self.force_allocation(place)?;
452
453         let (instance, place) = match place.layout.ty.sty {
454             ty::Dynamic(..) => {
455                 // Dropping a trait object.
456                 self.unpack_dyn_trait(place)?
457             }
458             _ => (instance, place),
459         };
460
461         let arg = OpTy {
462             op: Operand::Immediate(place.to_ref()),
463             layout: self.layout_of(self.tcx.mk_mut_ptr(place.layout.ty))?,
464         };
465
466         let ty = self.tcx.mk_unit(); // return type is ()
467         let dest = MPlaceTy::dangling(self.layout_of(ty)?, self);
468
469         self.eval_fn_call(
470             instance,
471             span,
472             Abi::Rust,
473             &[arg],
474             Some(dest.into()),
475             Some(target),
476         )
477     }
478 }