terminator.rs 20.5 KB
Newer Older
1 2
use std::borrow::Cow;

3
use rustc::{mir, ty};
4
use rustc::ty::Instance;
5
use rustc::ty::layout::{self, TyLayout, LayoutOf};
D
Donato Sciarra 已提交
6
use syntax::source_map::Span;
7
use rustc_target::spec::abi::Abi;
8

9
use rustc::mir::interpret::{InterpResult, PointerArithmetic, InterpError, Scalar};
R
Ralf Jung 已提交
10
use super::{
K
kenta7777 已提交
11
    InterpretCx, Machine, Immediate, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup
R
Ralf Jung 已提交
12
};
13

14
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpretCx<'mir, 'tcx, M> {
R
Ralf Jung 已提交
15
    #[inline]
16
    pub fn goto_block(&mut self, target: Option<mir::BasicBlock>) -> InterpResult<'tcx> {
R
Ralf Jung 已提交
17 18 19 20 21 22 23
        if let Some(target) = target {
            self.frame_mut().block = target;
            self.frame_mut().stmt = 0;
            Ok(())
        } else {
            err!(Unreachable)
        }
24 25
    }

26 27 28
    pub(super) fn eval_terminator(
        &mut self,
        terminator: &mir::Terminator<'tcx>,
29
    ) -> InterpResult<'tcx> {
30
        use rustc::mir::TerminatorKind::*;
31
        match terminator.kind {
S
Scott Olson 已提交
32
            Return => {
R
Ralf Jung 已提交
33
                self.frame().return_place.map(|r| self.dump_place(*r));
S
Scott Olson 已提交
34 35
                self.pop_stack_frame()?
            }
36

R
Ralf Jung 已提交
37
            Goto { target } => self.goto_block(Some(target))?,
38

R
rustfmt  
Ralf Jung 已提交
39 40 41 42 43 44
            SwitchInt {
                ref discr,
                ref values,
                ref targets,
                ..
            } => {
45
                let discr = self.read_immediate(self.eval_operand(discr, None)?)?;
R
Ralf Jung 已提交
46
                trace!("SwitchInt({:?})", *discr);
47 48 49 50

                // Branch to the `otherwise` case by default, if no match is found.
                let mut target_block = targets[targets.len() - 1];

O
Oliver Schneider 已提交
51
                for (index, &const_int) in values.iter().enumerate() {
52
                    // Compare using binary_op, to also support pointer values
53
                    let const_int = Scalar::from_uint(const_int, discr.layout.size);
R
Ralf Jung 已提交
54
                    let (res, _) = self.binary_op(mir::BinOp::Eq,
55 56
                        discr,
                        ImmTy::from_scalar(const_int, discr.layout),
57
                    )?;
R
Ralf Jung 已提交
58
                    if res.to_bool()? {
59 60 61 62 63
                        target_block = targets[index];
                        break;
                    }
                }

R
Ralf Jung 已提交
64
                self.goto_block(Some(target_block))?;
65 66
            }

R
rustfmt  
Ralf Jung 已提交
67 68 69 70 71 72
            Call {
                ref func,
                ref args,
                ref destination,
                ..
            } => {
R
Ralf Jung 已提交
73 74 75
                let (dest, ret) = match *destination {
                    Some((ref lv, target)) => (Some(self.eval_place(lv)?), Some(target)),
                    None => (None, None),
76
                };
77

78
                let func = self.eval_operand(func, None)?;
79
                let (fn_def, abi) = match func.layout.ty.sty {
V
varkor 已提交
80
                    ty::FnPtr(sig) => {
81
                        let caller_abi = sig.abi();
C
Christian Poveda 已提交
82
                        let fn_ptr = self.force_ptr(self.read_scalar(func)?.not_undef()?)?;
83
                        let instance = self.memory.get_fn(fn_ptr)?;
84
                        (instance, caller_abi)
R
rustfmt  
Ralf Jung 已提交
85
                    }
R
Ralf Jung 已提交
86 87
                    ty::FnDef(def_id, substs) => {
                        let sig = func.layout.ty.fn_sig(*self.tcx);
88
                        (self.resolve(def_id, substs)?, sig.abi())
R
Ralf Jung 已提交
89
                    },
90
                    _ => {
R
Ralf Jung 已提交
91
                        let msg = format!("can't handle callee of type {:?}", func.layout.ty);
92
                        return err!(Unimplemented(msg));
93
                    }
94
                };
R
Ralf Jung 已提交
95
                let args = self.eval_operands(args)?;
R
rustfmt  
Ralf Jung 已提交
96 97
                self.eval_fn_call(
                    fn_def,
98 99
                    terminator.source_info.span,
                    abi,
R
Ralf Jung 已提交
100
                    &args[..],
R
Ralf Jung 已提交
101 102
                    dest,
                    ret,
R
rustfmt  
Ralf Jung 已提交
103
                )?;
104 105
            }

R
rustfmt  
Ralf Jung 已提交
106 107 108 109 110
            Drop {
                ref location,
                target,
                ..
            } => {
111
                // FIXME(CTFE): forbid drop in const eval
O
Oliver Schneider 已提交
112
                let place = self.eval_place(location)?;
R
Ralf Jung 已提交
113
                let ty = place.layout.ty;
114
                trace!("TerminatorKind::drop: {:?}, type {}", location, ty);
O
Oliver Schneider 已提交
115

116
                let instance = Instance::resolve_drop_in_place(*self.tcx, ty);
117
                self.drop_in_place(
O
Oliver Schneider 已提交
118
                    place,
R
rustfmt  
Ralf Jung 已提交
119 120
                    instance,
                    terminator.source_info.span,
121
                    target,
R
rustfmt  
Ralf Jung 已提交
122
                )?;
O
Oliver Schneider 已提交
123
            }
124

R
rustfmt  
Ralf Jung 已提交
125 126 127 128 129 130 131
            Assert {
                ref cond,
                expected,
                ref msg,
                target,
                ..
            } => {
132
                let cond_val = self.read_immediate(self.eval_operand(cond, None)?)?
133
                    .to_scalar()?.to_bool()?;
134
                if expected == cond_val {
R
Ralf Jung 已提交
135
                    self.goto_block(Some(target))?;
136
                } else {
137
                    // Compute error message
K
kenta7777 已提交
138
                    use rustc::mir::interpret::InterpError::*;
139
                    return match *msg {
O
Oliver Schneider 已提交
140
                        BoundsCheck { ref len, ref index } => {
141
                            let len = self.read_immediate(self.eval_operand(len, None)?)
142
                                .expect("can't eval len").to_scalar()?
143
                                .to_bits(self.memory().pointer_size())? as u64;
144
                            let index = self.read_immediate(self.eval_operand(index, None)?)
145
                                .expect("can't eval index").to_scalar()?
146
                                .to_bits(self.memory().pointer_size())? as u64;
147
                            err!(BoundsCheck { len, index })
R
rustfmt  
Ralf Jung 已提交
148
                        }
149 150
                        Overflow(op) => Err(Overflow(op).into()),
                        OverflowNeg => Err(OverflowNeg.into()),
151 152
                        DivisionByZero => Err(DivisionByZero.into()),
                        RemainderByZero => Err(RemainderByZero.into()),
O
Oliver Schneider 已提交
153 154
                        GeneratorResumedAfterReturn |
                        GeneratorResumedAfterPanic => unimplemented!(),
155
                        _ => bug!(),
R
rustfmt  
Ralf Jung 已提交
156
                    };
157
                }
R
rustfmt  
Ralf Jung 已提交
158
            }
159

160 161 162 163 164
            Yield { .. } |
            GeneratorDrop |
            DropAndReplace { .. } |
            Resume |
            Abort => unimplemented!("{:#?}", terminator.kind),
B
Bernardo Meurer 已提交
165 166 167 168
            FalseEdges { .. } => bug!("should have been eliminated by\
                                      `simplify_branches` mir pass"),
            FalseUnwind { .. } => bug!("should have been eliminated by\
                                       `simplify_branches` mir pass"),
169
            Unreachable => return err!(Unreachable),
170 171 172 173 174
        }

        Ok(())
    }

175
    fn check_argument_compat(
176
        rust_abi: bool,
177 178 179 180 181 182
        caller: TyLayout<'tcx>,
        callee: TyLayout<'tcx>,
    ) -> bool {
        if caller.ty == callee.ty {
            // No question
            return true;
183
        }
184 185 186 187
        if !rust_abi {
            // Don't risk anything
            return false;
        }
188 189
        // Compare layout
        match (&caller.abi, &callee.abi) {
190 191 192
            // Different valid ranges are okay (once we enforce validity,
            // that will take care to make it UB to leave the range, just
            // like for transmute).
193 194
            (layout::Abi::Scalar(ref caller), layout::Abi::Scalar(ref callee)) =>
                caller.value == callee.value,
195 196 197
            (layout::Abi::ScalarPair(ref caller1, ref caller2),
             layout::Abi::ScalarPair(ref callee1, ref callee2)) =>
                caller1.value == callee1.value && caller2.value == callee2.value,
198 199
            // Be conservative
            _ => false
200
        }
201
    }
202

203 204 205
    /// Pass a single argument, checking the types for compatibility.
    fn pass_argument(
        &mut self,
206
        rust_abi: bool,
207 208
        caller_arg: &mut impl Iterator<Item=OpTy<'tcx, M::PointerTag>>,
        callee_arg: PlaceTy<'tcx, M::PointerTag>,
209
    ) -> InterpResult<'tcx> {
210
        if rust_abi && callee_arg.layout.is_zst() {
211 212 213
            // Nothing to do.
            trace!("Skipping callee ZST");
            return Ok(());
214
        }
215
        let caller_arg = caller_arg.next()
K
kenta7777 已提交
216
            .ok_or_else(|| InterpError::FunctionArgCountMismatch)?;
217
        if rust_abi {
218 219 220
            debug_assert!(!caller_arg.layout.is_zst(), "ZSTs must have been already filtered out");
        }
        // Now, check
221
        if !Self::check_argument_compat(rust_abi, caller_arg.layout, callee_arg.layout) {
222 223
            return err!(FunctionArgMismatch(caller_arg.layout.ty, callee_arg.layout.ty));
        }
224 225
        // We allow some transmutes here
        self.copy_op_transmute(caller_arg, callee_arg)
226 227
    }

R
Ralf Jung 已提交
228
    /// Call this function -- pushing the stack frame and initializing the arguments.
229 230
    fn eval_fn_call(
        &mut self,
O
Oliver Schneider 已提交
231
        instance: ty::Instance<'tcx>,
232 233
        span: Span,
        caller_abi: Abi,
234 235
        args: &[OpTy<'tcx, M::PointerTag>],
        dest: Option<PlaceTy<'tcx, M::PointerTag>>,
R
Ralf Jung 已提交
236
        ret: Option<mir::BasicBlock>,
237
    ) -> InterpResult<'tcx> {
O
Oliver Schneider 已提交
238
        trace!("eval_fn_call: {:#?}", instance);
R
Ralf Jung 已提交
239

O
Oliver Schneider 已提交
240 241
        match instance.def {
            ty::InstanceDef::Intrinsic(..) => {
242 243 244
                if caller_abi != Abi::RustIntrinsic {
                    return err!(FunctionAbiMismatch(caller_abi, Abi::RustIntrinsic));
                }
R
Ralf Jung 已提交
245
                // The intrinsic itself cannot diverge, so if we got here without a return
246
                // place... (can happen e.g., for transmute returning `!`)
R
Ralf Jung 已提交
247
                let dest = match dest {
O
Oliver Schneider 已提交
248
                    Some(dest) => dest,
R
Ralf Jung 已提交
249
                    None => return err!(Unreachable)
250
                };
R
Ralf Jung 已提交
251 252 253 254 255
                M::call_intrinsic(self, instance, args, dest)?;
                // No stack frame gets pushed, the main loop will just act as if the
                // call completed.
                self.goto_block(ret)?;
                self.dump_place(*dest);
O
Oliver Schneider 已提交
256
                Ok(())
R
rustfmt  
Ralf Jung 已提交
257
            }
M
Masaki Hara 已提交
258
            ty::InstanceDef::VtableShim(..) |
R
Ralf Jung 已提交
259
            ty::InstanceDef::ClosureOnceShim { .. } |
260 261
            ty::InstanceDef::FnPtrShim(..) |
            ty::InstanceDef::DropGlue(..) |
262
            ty::InstanceDef::CloneShim(..) |
O
Oliver Schneider 已提交
263
            ty::InstanceDef::Item(_) => {
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
                // ABI check
                {
                    let callee_abi = {
                        let instance_ty = instance.ty(*self.tcx);
                        match instance_ty.sty {
                            ty::FnDef(..) =>
                                instance_ty.fn_sig(*self.tcx).abi(),
                            ty::Closure(..) => Abi::RustCall,
                            ty::Generator(..) => Abi::Rust,
                            _ => bug!("unexpected callee ty: {:?}", instance_ty),
                        }
                    };
                    // Rust and RustCall are compatible
                    let normalize_abi = |abi| if abi == Abi::RustCall { Abi::Rust } else { abi };
                    if normalize_abi(caller_abi) != normalize_abi(callee_abi) {
                        return err!(FunctionAbiMismatch(caller_abi, callee_abi));
                    }
                }

                // We need MIR for this fn
284 285
                let body = match M::find_fn(self, instance, args, dest, ret)? {
                    Some(body) => body,
R
Ralf Jung 已提交
286 287 288 289 290 291
                    None => return Ok(()),
                };

                self.push_stack_frame(
                    instance,
                    span,
292
                    body,
R
Ralf Jung 已提交
293
                    dest,
R
Ralf Jung 已提交
294 295
                    StackPopCleanup::Goto(ret),
                )?;
O
Oliver Schneider 已提交
296

297 298 299 300 301 302 303 304 305 306 307 308 309
                // We want to pop this frame again in case there was an error, to put
                // the blame in the right location.  Until the 2018 edition is used in
                // the compiler, we have to do this with an immediately invoked function.
                let res = (||{
                    trace!(
                        "caller ABI: {:?}, args: {:#?}",
                        caller_abi,
                        args.iter()
                            .map(|arg| (arg.layout.ty, format!("{:?}", **arg)))
                            .collect::<Vec<_>>()
                    );
                    trace!(
                        "spread_arg: {:?}, locals: {:#?}",
310 311
                        body.spread_arg,
                        body.args_iter()
312
                            .map(|local|
313
                                (local, self.layout_of_local(self.frame(), local, None).unwrap().ty)
314
                            )
315 316 317 318
                            .collect::<Vec<_>>()
                    );

                    // Figure out how to pass which arguments.
319
                    // The Rust ABI is special: ZST get skipped.
320
                    let rust_abi = match caller_abi {
321 322
                        Abi::Rust | Abi::RustCall => true,
                        _ => false
323
                    };
324 325
                    // We have two iterators: Where the arguments come from,
                    // and where they go to.
R
Ralf Jung 已提交
326

327 328 329 330
                    // For where they come from: If the ABI is RustCall, we untuple the
                    // last incoming argument.  These two iterators do not have the same type,
                    // so to keep the code paths uniform we accept an allocation
                    // (for RustCall ABI only).
T
Taiki Endo 已提交
331
                    let caller_args : Cow<'_, [OpTy<'tcx, M::PointerTag>]> =
332 333 334 335 336 337 338 339
                        if caller_abi == Abi::RustCall && !args.is_empty() {
                            // Untuple
                            let (&untuple_arg, args) = args.split_last().unwrap();
                            trace!("eval_fn_call: Will pass last argument by untupling");
                            Cow::from(args.iter().map(|&a| Ok(a))
                                .chain((0..untuple_arg.layout.fields.count()).into_iter()
                                    .map(|i| self.operand_field(untuple_arg, i as u64))
                                )
340
                                .collect::<InterpResult<'_, Vec<OpTy<'tcx, M::PointerTag>>>>()?)
341 342 343 344 345 346
                        } else {
                            // Plain arg passing
                            Cow::from(args)
                        };
                    // Skip ZSTs
                    let mut caller_iter = caller_args.iter()
347
                        .filter(|op| !rust_abi || !op.layout.is_zst())
348 349 350 351 352 353 354
                        .map(|op| *op);

                    // Now we have to spread them out across the callee's locals,
                    // taking into account the `spread_arg`.  If we could write
                    // this is a single iterator (that handles `spread_arg`), then
                    // `pass_argument` would be the loop body. It takes care to
                    // not advance `caller_iter` for ZSTs.
355
                    let mut locals_iter = body.args_iter();
356
                    while let Some(local) = locals_iter.next() {
357 358 359
                        let dest = self.eval_place(
                            &mir::Place::Base(mir::PlaceBase::Local(local))
                        )?;
360
                        if Some(local) == body.spread_arg {
361 362 363
                            // Must be a tuple
                            for i in 0..dest.layout.fields.count() {
                                let dest = self.place_field(dest, i as u64)?;
364
                                self.pass_argument(rust_abi, &mut caller_iter, dest)?;
365 366 367
                            }
                        } else {
                            // Normal argument
368
                            self.pass_argument(rust_abi, &mut caller_iter, dest)?;
R
Ralf Jung 已提交
369
                        }
O
Oliver Schneider 已提交
370
                    }
371 372
                    // Now we should have no more caller args
                    if caller_iter.next().is_some() {
373
                        trace!("Caller has passed too many args");
374 375
                        return err!(FunctionArgCountMismatch);
                    }
376 377
                    // Don't forget to check the return type!
                    if let Some(caller_ret) = dest {
378 379 380
                        let callee_ret = self.eval_place(
                            &mir::Place::RETURN_PLACE
                        )?;
381 382 383 384 385
                        if !Self::check_argument_compat(
                            rust_abi,
                            caller_ret.layout,
                            callee_ret.layout,
                        ) {
386 387 388 389 390
                            return err!(FunctionRetMismatch(
                                caller_ret.layout.ty, callee_ret.layout.ty
                            ));
                        }
                    } else {
V
varkor 已提交
391 392 393 394
                        let local = mir::RETURN_PLACE;
                        let ty = self.frame().body.local_decls[local].ty;
                        if !self.tcx.is_ty_uninhabited_from_any_module(ty) {
                            return err!(FunctionRetMismatch(self.tcx.types.never, ty));
395
                        }
396
                    }
397 398 399 400 401 402 403 404
                    Ok(())
                })();
                match res {
                    Err(err) => {
                        self.stack.pop();
                        Err(err)
                    }
                    Ok(v) => Ok(v)
O
Oliver Schneider 已提交
405
                }
R
rustfmt  
Ralf Jung 已提交
406
            }
407
            // cannot use the shim here, because that will only result in infinite recursion
O
Oliver Schneider 已提交
408
            ty::InstanceDef::Virtual(_, idx) => {
R
Ralf Jung 已提交
409
                let mut args = args.to_vec();
410
                let ptr_size = self.pointer_size();
R
Ralf Jung 已提交
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
                // We have to implement all "object safe receivers".  Currently we
                // support built-in pointers (&, &mut, Box) as well as unsized-self.  We do
                // not yet support custom self types.
                // Also see librustc_codegen_llvm/abi.rs and librustc_codegen_llvm/mir/block.rs.
                let receiver_place = match args[0].layout.ty.builtin_deref(true) {
                    Some(_) => {
                        // Built-in pointer.
                        self.deref_operand(args[0])?
                    }
                    None => {
                        // Unsized self.
                        args[0].to_mem_place()
                    }
                };
                // Find and consult vtable
426 427 428 429 430 431 432 433 434
                let vtable = receiver_place.vtable();
                let vtable_slot = vtable.ptr_offset(ptr_size * (idx as u64 + 3), self)?;
                let vtable_slot = self.memory.check_ptr_access(
                    vtable_slot,
                    ptr_size,
                    self.tcx.data_layout.pointer_align.abi,
                )?.expect("cannot be a ZST");
                let fn_ptr = self.memory.get(vtable_slot.alloc_id)?
                    .read_ptr_sized(self, vtable_slot)?.to_ptr()?;
435
                let instance = self.memory.get_fn(fn_ptr)?;
436

R
Ralf Jung 已提交
437 438 439 440 441 442 443 444 445 446
                // `*mut receiver_place.layout.ty` is almost the layout that we
                // want for args[0]: We have to project to field 0 because we want
                // a thin pointer.
                assert!(receiver_place.layout.is_unsized());
                let receiver_ptr_ty = self.tcx.mk_mut_ptr(receiver_place.layout.ty);
                let this_receiver_ptr = self.layout_of(receiver_ptr_ty)?.field(self, 0)?;
                // Adjust receiver argument.
                args[0] = OpTy::from(ImmTy {
                    layout: this_receiver_ptr,
                    imm: Immediate::Scalar(receiver_place.ptr.into())
447
                });
448
                trace!("Patched self operand to {:#?}", args[0]);
O
Oliver Schneider 已提交
449
                // recurse with concrete function
450
                self.eval_fn_call(instance, span, caller_abi, &args, dest, ret)
R
rustfmt  
Ralf Jung 已提交
451
            }
452 453
        }
    }
454 455 456

    fn drop_in_place(
        &mut self,
457
        place: PlaceTy<'tcx, M::PointerTag>,
458 459 460
        instance: ty::Instance<'tcx>,
        span: Span,
        target: mir::BasicBlock,
461
    ) -> InterpResult<'tcx> {
462 463 464 465 466 467 468 469 470
        trace!("drop_in_place: {:?},\n  {:?}, {:?}", *place, place.layout.ty, instance);
        // We take the address of the object.  This may well be unaligned, which is fine
        // for us here.  However, unaligned accesses will probably make the actual drop
        // implementation fail -- a problem shared by rustc.
        let place = self.force_allocation(place)?;

        let (instance, place) = match place.layout.ty.sty {
            ty::Dynamic(..) => {
                // Dropping a trait object.
471
                self.unpack_dyn_trait(place)?
472 473 474 475
            }
            _ => (instance, place),
        };

476 477
        let arg = ImmTy {
            imm: place.to_ref(),
478 479 480
            layout: self.layout_of(self.tcx.mk_mut_ptr(place.layout.ty))?,
        };

K
kenta7777 已提交
481
        let ty = self.tcx.mk_unit(); // return type is ()
482
        let dest = MPlaceTy::dangling(self.layout_of(ty)?, self);
483 484 485

        self.eval_fn_call(
            instance,
486 487
            span,
            Abi::Rust,
488
            &[arg.into()],
R
Ralf Jung 已提交
489
            Some(dest.into()),
490 491 492
            Some(target),
        )
    }
O
Oliver Schneider 已提交
493
}