]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/interpret/terminator.rs
drop glue takes in mutable references, it should reflect that in its type
[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         caller: TyLayout<'tcx>,
186         callee: TyLayout<'tcx>,
187     ) -> bool {
188         if caller.ty == callee.ty {
189             // No question
190             return true;
191         }
192         // Compare layout
193         match (&caller.abi, &callee.abi) {
194             (layout::Abi::Scalar(ref caller), layout::Abi::Scalar(ref callee)) =>
195                 // Different valid ranges are okay (once we enforce validity,
196                 // that will take care to make it UB to leave the range, just
197                 // like for transmute).
198                 caller.value == callee.value,
199             (layout::Abi::ScalarPair(ref caller1, ref caller2),
200              layout::Abi::ScalarPair(ref callee1, ref callee2)) =>
201                 caller1.value == callee1.value && caller2.value == callee2.value,
202             // Be conservative
203             _ => false
204         }
205     }
206
207     /// Pass a single argument, checking the types for compatibility.
208     fn pass_argument(
209         &mut self,
210         skip_zst: bool,
211         caller_arg: &mut impl Iterator<Item=OpTy<'tcx, M::PointerTag>>,
212         callee_arg: PlaceTy<'tcx, M::PointerTag>,
213     ) -> EvalResult<'tcx> {
214         if skip_zst && callee_arg.layout.is_zst() {
215             // Nothing to do.
216             trace!("Skipping callee ZST");
217             return Ok(());
218         }
219         let caller_arg = caller_arg.next()
220             .ok_or_else(|| EvalErrorKind::FunctionArgCountMismatch)?;
221         if skip_zst {
222             debug_assert!(!caller_arg.layout.is_zst(), "ZSTs must have been already filtered out");
223         }
224         // Now, check
225         if !Self::check_argument_compat(caller_arg.layout, callee_arg.layout) {
226             return err!(FunctionArgMismatch(caller_arg.layout.ty, callee_arg.layout.ty));
227         }
228         // We allow some transmutes here
229         self.copy_op_transmute(caller_arg, callee_arg)
230     }
231
232     /// Call this function -- pushing the stack frame and initializing the arguments.
233     fn eval_fn_call(
234         &mut self,
235         instance: ty::Instance<'tcx>,
236         span: Span,
237         caller_abi: Abi,
238         args: &[OpTy<'tcx, M::PointerTag>],
239         dest: Option<PlaceTy<'tcx, M::PointerTag>>,
240         ret: Option<mir::BasicBlock>,
241     ) -> EvalResult<'tcx> {
242         trace!("eval_fn_call: {:#?}", instance);
243
244         match instance.def {
245             ty::InstanceDef::Intrinsic(..) => {
246                 if caller_abi != Abi::RustIntrinsic {
247                     return err!(FunctionAbiMismatch(caller_abi, Abi::RustIntrinsic));
248                 }
249                 // The intrinsic itself cannot diverge, so if we got here without a return
250                 // place... (can happen e.g. for transmute returning `!`)
251                 let dest = match dest {
252                     Some(dest) => dest,
253                     None => return err!(Unreachable)
254                 };
255                 M::call_intrinsic(self, instance, args, dest)?;
256                 // No stack frame gets pushed, the main loop will just act as if the
257                 // call completed.
258                 self.goto_block(ret)?;
259                 self.dump_place(*dest);
260                 Ok(())
261             }
262             ty::InstanceDef::VtableShim(..) |
263             ty::InstanceDef::ClosureOnceShim { .. } |
264             ty::InstanceDef::FnPtrShim(..) |
265             ty::InstanceDef::DropGlue(..) |
266             ty::InstanceDef::CloneShim(..) |
267             ty::InstanceDef::Item(_) => {
268                 // ABI check
269                 {
270                     let callee_abi = {
271                         let instance_ty = instance.ty(*self.tcx);
272                         match instance_ty.sty {
273                             ty::FnDef(..) =>
274                                 instance_ty.fn_sig(*self.tcx).abi(),
275                             ty::Closure(..) => Abi::RustCall,
276                             ty::Generator(..) => Abi::Rust,
277                             _ => bug!("unexpected callee ty: {:?}", instance_ty),
278                         }
279                     };
280                     // Rust and RustCall are compatible
281                     let normalize_abi = |abi| if abi == Abi::RustCall { Abi::Rust } else { abi };
282                     if normalize_abi(caller_abi) != normalize_abi(callee_abi) {
283                         return err!(FunctionAbiMismatch(caller_abi, callee_abi));
284                     }
285                 }
286
287                 // We need MIR for this fn
288                 let mir = match M::find_fn(self, instance, args, dest, ret)? {
289                     Some(mir) => mir,
290                     None => return Ok(()),
291                 };
292
293                 self.push_stack_frame(
294                     instance,
295                     span,
296                     mir,
297                     dest,
298                     StackPopCleanup::Goto(ret),
299                 )?;
300
301                 // We want to pop this frame again in case there was an error, to put
302                 // the blame in the right location.  Until the 2018 edition is used in
303                 // the compiler, we have to do this with an immediately invoked function.
304                 let res = (||{
305                     trace!(
306                         "caller ABI: {:?}, args: {:#?}",
307                         caller_abi,
308                         args.iter()
309                             .map(|arg| (arg.layout.ty, format!("{:?}", **arg)))
310                             .collect::<Vec<_>>()
311                     );
312                     trace!(
313                         "spread_arg: {:?}, locals: {:#?}",
314                         mir.spread_arg,
315                         mir.args_iter()
316                             .map(|local|
317                                 (local, self.layout_of_local(self.frame(), local).unwrap().ty)
318                             )
319                             .collect::<Vec<_>>()
320                     );
321
322                     // Figure out how to pass which arguments.
323                     // We have two iterators: Where the arguments come from,
324                     // and where they go to.
325                     let skip_zst = match caller_abi {
326                         Abi::Rust | Abi::RustCall => true,
327                         _ => false
328                     };
329
330                     // For where they come from: If the ABI is RustCall, we untuple the
331                     // last incoming argument.  These two iterators do not have the same type,
332                     // so to keep the code paths uniform we accept an allocation
333                     // (for RustCall ABI only).
334                     let caller_args : Cow<[OpTy<'tcx, M::PointerTag>]> =
335                         if caller_abi == Abi::RustCall && !args.is_empty() {
336                             // Untuple
337                             let (&untuple_arg, args) = args.split_last().unwrap();
338                             trace!("eval_fn_call: Will pass last argument by untupling");
339                             Cow::from(args.iter().map(|&a| Ok(a))
340                                 .chain((0..untuple_arg.layout.fields.count()).into_iter()
341                                     .map(|i| self.operand_field(untuple_arg, i as u64))
342                                 )
343                                 .collect::<EvalResult<Vec<OpTy<'tcx, M::PointerTag>>>>()?)
344                         } else {
345                             // Plain arg passing
346                             Cow::from(args)
347                         };
348                     // Skip ZSTs
349                     let mut caller_iter = caller_args.iter()
350                         .filter(|op| !skip_zst || !op.layout.is_zst())
351                         .map(|op| *op);
352
353                     // Now we have to spread them out across the callee's locals,
354                     // taking into account the `spread_arg`.  If we could write
355                     // this is a single iterator (that handles `spread_arg`), then
356                     // `pass_argument` would be the loop body. It takes care to
357                     // not advance `caller_iter` for ZSTs.
358                     let mut locals_iter = mir.args_iter();
359                     while let Some(local) = locals_iter.next() {
360                         let dest = self.eval_place(&mir::Place::Local(local))?;
361                         if Some(local) == mir.spread_arg {
362                             // Must be a tuple
363                             for i in 0..dest.layout.fields.count() {
364                                 let dest = self.place_field(dest, i as u64)?;
365                                 self.pass_argument(skip_zst, &mut caller_iter, dest)?;
366                             }
367                         } else {
368                             // Normal argument
369                             self.pass_argument(skip_zst, &mut caller_iter, dest)?;
370                         }
371                     }
372                     // Now we should have no more caller args
373                     if caller_iter.next().is_some() {
374                         trace!("Caller has too many args over");
375                         return err!(FunctionArgCountMismatch);
376                     }
377                     // Don't forget to check the return type!
378                     if let Some(caller_ret) = dest {
379                         let callee_ret = self.eval_place(&mir::Place::Local(mir::RETURN_PLACE))?;
380                         if !Self::check_argument_compat(caller_ret.layout, callee_ret.layout) {
381                             return err!(FunctionRetMismatch(
382                                 caller_ret.layout.ty, callee_ret.layout.ty
383                             ));
384                         }
385                     } else {
386                         let callee_layout =
387                             self.layout_of_local(self.frame(), mir::RETURN_PLACE)?;
388                         if !callee_layout.abi.is_uninhabited() {
389                             return err!(FunctionRetMismatch(
390                                 self.tcx.types.never, callee_layout.ty
391                             ));
392                         }
393                     }
394                     Ok(())
395                 })();
396                 match res {
397                     Err(err) => {
398                         self.stack.pop();
399                         Err(err)
400                     }
401                     Ok(v) => Ok(v)
402                 }
403             }
404             // cannot use the shim here, because that will only result in infinite recursion
405             ty::InstanceDef::Virtual(_, idx) => {
406                 let ptr_size = self.pointer_size();
407                 let ptr_align = self.tcx.data_layout.pointer_align;
408                 let ptr = self.deref_operand(args[0])?;
409                 let vtable = ptr.vtable()?;
410                 let fn_ptr = self.memory.read_ptr_sized(
411                     vtable.offset(ptr_size * (idx as u64 + 3), self)?,
412                     ptr_align
413                 )?.to_ptr()?;
414                 let instance = self.memory.get_fn(fn_ptr)?;
415
416                 // We have to patch the self argument, in particular get the layout
417                 // expected by the actual function. Cannot just use "field 0" due to
418                 // Box<self>.
419                 let mut args = args.to_vec();
420                 let pointee = args[0].layout.ty.builtin_deref(true).unwrap().ty;
421                 let fake_fat_ptr_ty = self.tcx.mk_mut_ptr(pointee);
422                 args[0].layout = self.layout_of(fake_fat_ptr_ty)?.field(self, 0)?;
423                 args[0].op = Operand::Immediate(Immediate::Scalar(ptr.ptr.into())); // strip vtable
424                 trace!("Patched self operand to {:#?}", args[0]);
425                 // recurse with concrete function
426                 self.eval_fn_call(instance, span, caller_abi, &args, dest, ret)
427             }
428         }
429     }
430
431     fn drop_in_place(
432         &mut self,
433         place: PlaceTy<'tcx, M::PointerTag>,
434         instance: ty::Instance<'tcx>,
435         span: Span,
436         target: mir::BasicBlock,
437     ) -> EvalResult<'tcx> {
438         trace!("drop_in_place: {:?},\n  {:?}, {:?}", *place, place.layout.ty, instance);
439         // We take the address of the object.  This may well be unaligned, which is fine
440         // for us here.  However, unaligned accesses will probably make the actual drop
441         // implementation fail -- a problem shared by rustc.
442         let place = self.force_allocation(place)?;
443
444         let (instance, place) = match place.layout.ty.sty {
445             ty::Dynamic(..) => {
446                 // Dropping a trait object.
447                 self.unpack_dyn_trait(place)?
448             }
449             _ => (instance, place),
450         };
451
452         let arg = OpTy {
453             op: Operand::Immediate(place.to_ref()),
454             layout: self.layout_of(self.tcx.mk_mut_ptr(place.layout.ty))?,
455         };
456
457         let ty = self.tcx.mk_unit(); // return type is ()
458         let dest = MPlaceTy::dangling(self.layout_of(ty)?, self);
459
460         self.eval_fn_call(
461             instance,
462             span,
463             Abi::Rust,
464             &[arg],
465             Some(dest.into()),
466             Some(target),
467         )
468     }
469 }