terminator.rs 19.4 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
    /// Pass a single argument, checking the types for compatibility.
    fn pass_argument(
        &mut self,
        skip_zst: bool,
208 209
        caller_arg: &mut impl Iterator<Item=OpTy<'tcx, M::PointerTag>>,
        callee_arg: PlaceTy<'tcx, M::PointerTag>,
210 211 212 213 214
    ) -> 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,
234 235
        args: &[OpTy<'tcx, M::PointerTag>],
        dest: Option<PlaceTy<'tcx, M::PointerTag>>,
R
Ralf Jung 已提交
236
        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
                    // 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).
333
                    let caller_args : Cow<[OpTy<'tcx, M::PointerTag>]> =
334 335 336 337 338 339 340 341
                        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))
                                )
342
                                .collect::<EvalResult<Vec<OpTy<'tcx, M::PointerTag>>>>()?)
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
                        } 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
                    // 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?
R
Ralf Jung 已提交
387
                        // On the plus side, the the callee ever writes to its return place,
388 389
                        // 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

    fn drop_in_place(
        &mut self,
429
        place: PlaceTy<'tcx, M::PointerTag>,
430 431 432 433 434 435 436 437 438 439 440 441 442
        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
}