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