terminator.rs 19.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

11 12
use std::borrow::Cow;

13 14
use rustc::{mir, ty};
use rustc::ty::layout::{self, TyLayout, LayoutOf};
D
Donato Sciarra 已提交
15
use syntax::source_map::Span;
16
use rustc_target::spec::abi::Abi;
17

18
use rustc::mir::interpret::{EvalResult, PointerArithmetic, EvalErrorKind, Scalar};
R
Ralf Jung 已提交
19
use super::{
20
    EvalContext, Machine, Value, OpTy, Place, PlaceTy, Operand, StackPopCleanup
R
Ralf Jung 已提交
21
};
22

23
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
R
Ralf Jung 已提交
24 25 26 27 28 29 30 31 32
    #[inline]
    pub fn goto_block(&mut self, target: Option<mir::BasicBlock>) -> EvalResult<'tcx> {
        if let Some(target) = target {
            self.frame_mut().block = target;
            self.frame_mut().stmt = 0;
            Ok(())
        } else {
            err!(Unreachable)
        }
33 34
    }

35 36 37
    pub(super) fn eval_terminator(
        &mut self,
        terminator: &mir::Terminator<'tcx>,
38
    ) -> EvalResult<'tcx> {
39
        use rustc::mir::TerminatorKind::*;
40
        match terminator.kind {
S
Scott Olson 已提交
41
            Return => {
R
Ralf Jung 已提交
42
                self.dump_place(self.frame().return_place);
S
Scott Olson 已提交
43 44
                self.pop_stack_frame()?
            }
45

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

R
rustfmt  
Ralf Jung 已提交
48 49 50 51 52 53
            SwitchInt {
                ref discr,
                ref values,
                ref targets,
                ..
            } => {
54
                let discr = self.read_value(self.eval_operand(discr, None)?)?;
R
Ralf Jung 已提交
55
                trace!("SwitchInt({:?})", *discr);
56 57 58 59

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

O
Oliver Schneider 已提交
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);
R
Ralf Jung 已提交
63
                    let (res, _) = self.binary_op(mir::BinOp::Eq,
64 65
                        discr.to_scalar()?, discr.layout,
                        const_int, discr.layout,
66
                    )?;
R
Ralf Jung 已提交
67
                    if res.to_bool()? {
68 69 70 71 72
                        target_block = targets[index];
                        break;
                    }
                }

R
Ralf Jung 已提交
73
                self.goto_block(Some(target_block))?;
74 75
            }

R
rustfmt  
Ralf Jung 已提交
76 77 78 79 80 81
            Call {
                ref func,
                ref args,
                ref destination,
                ..
            } => {
R
Ralf Jung 已提交
82 83 84
                let (dest, ret) = match *destination {
                    Some((ref lv, target)) => (Some(self.eval_place(lv)?), Some(target)),
                    None => (None, None),
85
                };
86

87
                let func = self.eval_operand(func, None)?;
88
                let (fn_def, abi) = match func.layout.ty.sty {
V
varkor 已提交
89
                    ty::FnPtr(sig) => {
90
                        let caller_abi = sig.abi();
R
Ralf Jung 已提交
91
                        let fn_ptr = self.read_scalar(func)?.to_ptr()?;
92
                        let instance = self.memory.get_fn(fn_ptr)?;
93
                        (instance, caller_abi)
R
rustfmt  
Ralf Jung 已提交
94
                    }
R
Ralf Jung 已提交
95 96
                    ty::FnDef(def_id, substs) => {
                        let sig = func.layout.ty.fn_sig(*self.tcx);
97
                        (self.resolve(def_id, substs)?, sig.abi())
R
Ralf Jung 已提交
98
                    },
99
                    _ => {
R
Ralf Jung 已提交
100
                        let msg = format!("can't handle callee of type {:?}", func.layout.ty);
101
                        return err!(Unimplemented(msg));
102
                    }
103
                };
R
Ralf Jung 已提交
104
                let args = self.eval_operands(args)?;
R
rustfmt  
Ralf Jung 已提交
105 106
                self.eval_fn_call(
                    fn_def,
107 108
                    terminator.source_info.span,
                    abi,
R
Ralf Jung 已提交
109
                    &args[..],
R
Ralf Jung 已提交
110 111
                    dest,
                    ret,
R
rustfmt  
Ralf Jung 已提交
112
                )?;
113 114
            }

R
rustfmt  
Ralf Jung 已提交
115 116 117 118 119
            Drop {
                ref location,
                target,
                ..
            } => {
120
                // FIXME(CTFE): forbid drop in const eval
O
Oliver Schneider 已提交
121
                let place = self.eval_place(location)?;
R
Ralf Jung 已提交
122
                let ty = place.layout.ty;
123
                trace!("TerminatorKind::drop: {:?}, type {}", location, ty);
O
Oliver Schneider 已提交
124

125
                let instance = ::monomorphize::resolve_drop_in_place(*self.tcx, ty);
126
                self.drop_in_place(
O
Oliver Schneider 已提交
127
                    place,
R
rustfmt  
Ralf Jung 已提交
128 129
                    instance,
                    terminator.source_info.span,
130
                    target,
R
rustfmt  
Ralf Jung 已提交
131
                )?;
O
Oliver Schneider 已提交
132
            }
133

R
rustfmt  
Ralf Jung 已提交
134 135 136 137 138 139 140
            Assert {
                ref cond,
                expected,
                ref msg,
                target,
                ..
            } => {
141 142
                let cond_val = self.read_value(self.eval_operand(cond, None)?)?
                    .to_scalar()?.to_bool()?;
143
                if expected == cond_val {
R
Ralf Jung 已提交
144
                    self.goto_block(Some(target))?;
145
                } else {
146
                    // Compute error message
147
                    use rustc::mir::interpret::EvalErrorKind::*;
148
                    return match *msg {
O
Oliver Schneider 已提交
149
                        BoundsCheck { ref len, ref index } => {
150
                            let len = self.read_value(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_value(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 })
R
rustfmt  
Ralf Jung 已提交
157
                        }
158 159
                        Overflow(op) => Err(Overflow(op).into()),
                        OverflowNeg => Err(OverflowNeg.into()),
160 161
                        DivisionByZero => Err(DivisionByZero.into()),
                        RemainderByZero => Err(RemainderByZero.into()),
O
Oliver Schneider 已提交
162 163
                        GeneratorResumedAfterReturn |
                        GeneratorResumedAfterPanic => unimplemented!(),
164
                        _ => bug!(),
R
rustfmt  
Ralf Jung 已提交
165
                    };
166
                }
R
rustfmt  
Ralf Jung 已提交
167
            }
168

169 170 171 172 173
            Yield { .. } |
            GeneratorDrop |
            DropAndReplace { .. } |
            Resume |
            Abort => unimplemented!("{:#?}", terminator.kind),
B
Bernardo Meurer 已提交
174 175 176 177
            FalseEdges { .. } => bug!("should have been eliminated by\
                                      `simplify_branches` mir pass"),
            FalseUnwind { .. } => bug!("should have been eliminated by\
                                       `simplify_branches` mir pass"),
178
            Unreachable => return err!(Unreachable),
179 180 181 182 183
        }

        Ok(())
    }

184 185 186 187 188 189 190
    fn check_argument_compat(
        caller: TyLayout<'tcx>,
        callee: TyLayout<'tcx>,
    ) -> bool {
        if caller.ty == callee.ty {
            // No question
            return true;
191
        }
192 193 194 195 196 197 198 199 200
        // Compare layout
        match (&caller.abi, &callee.abi) {
            (layout::Abi::Scalar(ref caller), layout::Abi::Scalar(ref callee)) =>
                // 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).
                caller.value == callee.value,
            // Be conservative
            _ => false
201
        }
202
    }
203

204 205 206 207 208 209 210 211 212 213 214
    /// Pass a single argument, checking the types for compatibility.
    fn pass_argument(
        &mut self,
        skip_zst: bool,
        caller_arg: &mut impl Iterator<Item=OpTy<'tcx>>,
        callee_arg: PlaceTy<'tcx>,
    ) -> EvalResult<'tcx> {
        if skip_zst && callee_arg.layout.is_zst() {
            // Nothing to do.
            trace!("Skipping callee ZST");
            return Ok(());
215
        }
216 217 218 219 220 221 222 223 224 225
        let caller_arg = caller_arg.next()
            .ok_or_else(|| EvalErrorKind::FunctionArgCountMismatch)?;
        if skip_zst {
            debug_assert!(!caller_arg.layout.is_zst(), "ZSTs must have been already filtered out");
        }
        // Now, check
        if !Self::check_argument_compat(caller_arg.layout, callee_arg.layout) {
            return err!(FunctionArgMismatch(caller_arg.layout.ty, callee_arg.layout.ty));
        }
        self.copy_op(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,
R
Ralf Jung 已提交
234
        args: &[OpTy<'tcx>],
R
Ralf Jung 已提交
235 236
        dest: Option<PlaceTy<'tcx>>,
        ret: Option<mir::BasicBlock>,
237
    ) -> EvalResult<'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 246 247
                // The intrinsic itself cannot diverge, so if we got here without a return
                // place... (can happen e.g. for transmute returning `!`)
                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
            }
R
Ralf Jung 已提交
258
            ty::InstanceDef::ClosureOnceShim { .. } |
259 260
            ty::InstanceDef::FnPtrShim(..) |
            ty::InstanceDef::DropGlue(..) |
261
            ty::InstanceDef::CloneShim(..) |
O
Oliver Schneider 已提交
262
            ty::InstanceDef::Item(_) => {
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
                // 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
R
Ralf Jung 已提交
283 284 285 286 287 288 289
                let mir = match M::find_fn(self, instance, args, dest, ret)? {
                    Some(mir) => mir,
                    None => return Ok(()),
                };

                let return_place = match dest {
                    Some(place) => *place,
290
                    None => Place::null(&self), // any access will error. good!
R
Ralf Jung 已提交
291 292 293 294 295 296 297 298
                };
                self.push_stack_frame(
                    instance,
                    span,
                    mir,
                    return_place,
                    StackPopCleanup::Goto(ret),
                )?;
O
Oliver Schneider 已提交
299

300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
                // 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: {:#?}",
                        mir.spread_arg,
                        mir.args_iter()
                            .map(|local|
                                (local, self.layout_of_local(self.cur_frame(), local).unwrap().ty)
317
                            )
318 319 320 321 322 323 324 325 326
                            .collect::<Vec<_>>()
                    );

                    // Figure out how to pass which arguments.
                    // We have two iterators: Where the arguments come from,
                    // and where they go to.
                    let skip_zst = match caller_abi {
                        Abi::Rust | Abi::RustCall => true,
                        _ => false
327
                    };
R
Ralf Jung 已提交
328

329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
                    // 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).
                    let caller_args : Cow<[OpTy<'tcx>]> =
                        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))
                                )
                                .collect::<EvalResult<Vec<OpTy<'tcx>>>>()?)
                        } else {
                            // Plain arg passing
                            Cow::from(args)
                        };
                    // Skip ZSTs
                    let mut caller_iter = caller_args.iter()
                        .filter(|op| !skip_zst || !op.layout.is_zst())
                        .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.
                    let mut locals_iter = mir.args_iter();
                    while let Some(local) = locals_iter.next() {
359
                        let dest = self.eval_place(&mir::Place::Local(local))?;
360 361 362 363 364 365 366 367 368
                        if Some(local) == mir.spread_arg {
                            // Must be a tuple
                            for i in 0..dest.layout.fields.count() {
                                let dest = self.place_field(dest, i as u64)?;
                                self.pass_argument(skip_zst, &mut caller_iter, dest)?;
                            }
                        } else {
                            // Normal argument
                            self.pass_argument(skip_zst, &mut caller_iter, dest)?;
R
Ralf Jung 已提交
369
                        }
O
Oliver Schneider 已提交
370
                    }
371 372 373 374 375
                    // Now we should have no more caller args
                    if caller_iter.next().is_some() {
                        trace!("Caller has too many args over");
                        return err!(FunctionArgCountMismatch);
                    }
376 377 378 379 380 381 382 383 384 385 386 387 388 389
                    // Don't forget to check the return type!
                    if let Some(caller_ret) = dest {
                        let callee_ret = self.eval_place(&mir::Place::Local(mir::RETURN_PLACE))?;
                        if !Self::check_argument_compat(caller_ret.layout, callee_ret.layout) {
                            return err!(FunctionRetMismatch(
                                caller_ret.layout.ty, callee_ret.layout.ty
                            ));
                        }
                    } else {
                        // FIXME: The caller thinks this function cannot return. How do
                        // we verify that the callee agrees?
                        // On the plus side, the the callee every writes to its return place,
                        // that will be detected as UB (because we set that to NULL above).
                    }
390 391 392 393 394 395 396 397
                    Ok(())
                })();
                match res {
                    Err(err) => {
                        self.stack.pop();
                        Err(err)
                    }
                    Ok(v) => Ok(v)
O
Oliver Schneider 已提交
398
                }
R
rustfmt  
Ralf Jung 已提交
399
            }
400
            // cannot use the shim here, because that will only result in infinite recursion
O
Oliver Schneider 已提交
401
            ty::InstanceDef::Virtual(_, idx) => {
402
                let ptr_size = self.pointer_size();
403
                let ptr_align = self.tcx.data_layout.pointer_align;
404 405
                let ptr = self.ref_to_mplace(self.read_value(args[0])?)?;
                let vtable = ptr.vtable()?;
O
Oliver Schneider 已提交
406
                let fn_ptr = self.memory.read_ptr_sized(
407 408
                    vtable.offset(ptr_size * (idx as u64 + 3), &self)?,
                    ptr_align
R
Ralf Jung 已提交
409
                )?.to_ptr()?;
410
                let instance = self.memory.get_fn(fn_ptr)?;
411 412 413 414

                // We have to patch the self argument, in particular get the layout
                // expected by the actual function. Cannot just use "field 0" due to
                // Box<self>.
415
                let mut args = args.to_vec();
416 417 418
                let pointee = args[0].layout.ty.builtin_deref(true).unwrap().ty;
                let fake_fat_ptr_ty = self.tcx.mk_mut_ptr(pointee);
                args[0].layout = self.layout_of(fake_fat_ptr_ty)?.field(&self, 0)?;
419
                args[0].op = Operand::Immediate(Value::Scalar(ptr.ptr.into())); // strip vtable
420
                trace!("Patched self operand to {:#?}", args[0]);
O
Oliver Schneider 已提交
421
                // recurse with concrete function
422
                self.eval_fn_call(instance, span, caller_abi, &args, dest, ret)
R
rustfmt  
Ralf Jung 已提交
423
            }
424 425
        }
    }
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442

    fn drop_in_place(
        &mut self,
        place: PlaceTy<'tcx>,
        instance: ty::Instance<'tcx>,
        span: Span,
        target: mir::BasicBlock,
    ) -> EvalResult<'tcx> {
        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.
443
                self.unpack_dyn_trait(place)?
444 445 446 447 448
            }
            _ => (instance, place),
        };

        let arg = OpTy {
449
            op: Operand::Immediate(place.to_ref()),
450 451 452
            layout: self.layout_of(self.tcx.mk_mut_ptr(place.layout.ty))?,
        };

K
kenta7777 已提交
453
        let ty = self.tcx.mk_unit(); // return type is ()
454 455 456 457
        let dest = PlaceTy::null(&self, self.layout_of(ty)?);

        self.eval_fn_call(
            instance,
458 459
            span,
            Abi::Rust,
460 461 462 463 464
            &[arg],
            Some(dest),
            Some(target),
        )
    }
O
Oliver Schneider 已提交
465
}