mod.rs 18.2 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 rustc::mir;
use rustc::ty::{self, Ty};
R
Ralf Jung 已提交
13
use rustc::ty::layout::LayoutOf;
D
Donato Sciarra 已提交
14
use syntax::source_map::Span;
15
use rustc_target::spec::abi::Abi;
16

R
Ralf Jung 已提交
17 18
use rustc::mir::interpret::{EvalResult, Scalar};
use super::{EvalContext, Machine, Value, OpTy, PlaceTy, ValTy, Operand};
19

O
Oliver Schneider 已提交
20
use rustc_data_structures::indexed_vec::Idx;
21

22
mod drop;
O
Oliver Schneider 已提交
23

O
Oliver Schneider 已提交
24
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
25
    pub fn goto_block(&mut self, target: mir::BasicBlock) {
26 27 28 29
        self.frame_mut().block = target;
        self.frame_mut().stmt = 0;
    }

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

41
            Goto { target } => self.goto_block(target),
42

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

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

O
Oliver Schneider 已提交
56
                for (index, &const_int) in values.iter().enumerate() {
57
                    // Compare using binary_op
B
Bernardo Meurer 已提交
58 59 60 61
                    let const_int = Scalar::Bits {
                        bits: const_int,
                        size: discr.layout.size.bytes() as u8
                    };
R
Ralf Jung 已提交
62 63 64
                    let (res, _) = self.binary_op(mir::BinOp::Eq,
                        discr,
                        ValTy { value: Value::Scalar(const_int.into()), layout: discr.layout }
65
                    )?;
R
Ralf Jung 已提交
66
                    if res.to_bool()? {
67 68 69 70 71
                        target_block = targets[index];
                        break;
                    }
                }

72
                self.goto_block(target_block);
73 74
            }

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

86
                let func = self.eval_operand(func, None)?;
R
Ralf Jung 已提交
87
                let (fn_def, sig) = match func.layout.ty.sty {
V
varkor 已提交
88
                    ty::FnPtr(sig) => {
R
Ralf Jung 已提交
89
                        let fn_ptr = self.read_scalar(func)?.to_ptr()?;
90
                        let instance = self.memory.get_fn(fn_ptr)?;
91
                        let instance_ty = instance.ty(*self.tcx);
92
                        match instance_ty.sty {
V
varkor 已提交
93
                            ty::FnDef(..) => {
94
                                let real_sig = instance_ty.fn_sig(*self.tcx);
95 96 97 98 99 100 101 102
                                let sig = self.tcx.normalize_erasing_late_bound_regions(
                                    ty::ParamEnv::reveal_all(),
                                    &sig,
                                );
                                let real_sig = self.tcx.normalize_erasing_late_bound_regions(
                                    ty::ParamEnv::reveal_all(),
                                    &real_sig,
                                );
103
                                if !self.check_sig_compat(sig, real_sig)? {
104
                                    return err!(FunctionPointerTyMismatch(real_sig, sig));
105
                                }
R
rustfmt  
Ralf Jung 已提交
106
                            }
107 108 109
                            ref other => bug!("instance def ty: {:?}", other),
                        }
                        (instance, sig)
R
rustfmt  
Ralf Jung 已提交
110
                    }
V
varkor 已提交
111
                    ty::FnDef(def_id, substs) => (
O
Oliver Schneider 已提交
112
                        self.resolve(def_id, substs)?,
R
Ralf Jung 已提交
113
                        func.layout.ty.fn_sig(*self.tcx),
R
rustfmt  
Ralf Jung 已提交
114
                    ),
115
                    _ => {
R
Ralf Jung 已提交
116
                        let msg = format!("can't handle callee of type {:?}", func.layout.ty);
117
                        return err!(Unimplemented(msg));
118
                    }
119
                };
R
Ralf Jung 已提交
120
                let args = self.eval_operands(args)?;
121 122 123 124
                let sig = self.tcx.normalize_erasing_late_bound_regions(
                    ty::ParamEnv::reveal_all(),
                    &sig,
                );
R
rustfmt  
Ralf Jung 已提交
125 126 127
                self.eval_fn_call(
                    fn_def,
                    destination,
R
Ralf Jung 已提交
128
                    &args[..],
R
rustfmt  
Ralf Jung 已提交
129 130 131
                    terminator.source_info.span,
                    sig,
                )?;
132 133
            }

R
rustfmt  
Ralf Jung 已提交
134 135 136 137 138
            Drop {
                ref location,
                target,
                ..
            } => {
139
                // FIXME(CTFE): forbid drop in const eval
O
Oliver Schneider 已提交
140
                let place = self.eval_place(location)?;
R
Ralf Jung 已提交
141
                let ty = place.layout.ty;
142
                trace!("TerminatorKind::drop: {:?}, type {}", location, ty);
O
Oliver Schneider 已提交
143

144
                let instance = ::monomorphize::resolve_drop_in_place(*self.tcx, ty);
145
                self.drop_in_place(
O
Oliver Schneider 已提交
146
                    place,
R
rustfmt  
Ralf Jung 已提交
147 148
                    instance,
                    terminator.source_info.span,
149
                    target,
R
rustfmt  
Ralf Jung 已提交
150
                )?;
O
Oliver Schneider 已提交
151
            }
152

R
rustfmt  
Ralf Jung 已提交
153 154 155 156 157 158 159
            Assert {
                ref cond,
                expected,
                ref msg,
                target,
                ..
            } => {
B
Bernardo Meurer 已提交
160 161 162
                let cond_val = self.eval_operand_and_read_value(cond, None)?
                    .to_scalar()?
                    .to_bool()?;
163
                if expected == cond_val {
164
                    self.goto_block(target);
165
                } else {
166
                    use rustc::mir::interpret::EvalErrorKind::*;
167
                    return match *msg {
O
Oliver Schneider 已提交
168
                        BoundsCheck { ref len, ref index } => {
169 170
                            let len = self.eval_operand_and_read_value(len, None)
                                .expect("can't eval len").to_scalar()?
171
                                .to_bits(self.memory().pointer_size())? as u64;
172 173
                            let index = self.eval_operand_and_read_value(index, None)
                                .expect("can't eval index").to_scalar()?
174
                                .to_bits(self.memory().pointer_size())? as u64;
175
                            err!(BoundsCheck { len, index })
R
rustfmt  
Ralf Jung 已提交
176
                        }
177 178
                        Overflow(op) => Err(Overflow(op).into()),
                        OverflowNeg => Err(OverflowNeg.into()),
179 180
                        DivisionByZero => Err(DivisionByZero.into()),
                        RemainderByZero => Err(RemainderByZero.into()),
O
Oliver Schneider 已提交
181 182
                        GeneratorResumedAfterReturn |
                        GeneratorResumedAfterPanic => unimplemented!(),
183
                        _ => bug!(),
R
rustfmt  
Ralf Jung 已提交
184
                    };
185
                }
R
rustfmt  
Ralf Jung 已提交
186
            }
187

O
Oliver Schneider 已提交
188 189
            Yield { .. } => unimplemented!("{:#?}", terminator.kind),
            GeneratorDrop => unimplemented!(),
190 191
            DropAndReplace { .. } => unimplemented!(),
            Resume => unimplemented!(),
D
David Henningsson 已提交
192
            Abort => unimplemented!(),
B
Bernardo Meurer 已提交
193 194 195 196
            FalseEdges { .. } => bug!("should have been eliminated by\
                                      `simplify_branches` mir pass"),
            FalseUnwind { .. } => bug!("should have been eliminated by\
                                       `simplify_branches` mir pass"),
197
            Unreachable => return err!(Unreachable),
198 199 200 201 202
        }

        Ok(())
    }

B
Bernardo Meurer 已提交
203 204
    /// Decides whether it is okay to call the method with signature `real_sig`
    /// using signature `sig`.
R
Ralf Jung 已提交
205
    /// FIXME: This should take into account the platform-dependent ABI description.
206 207 208 209 210
    fn check_sig_compat(
        &mut self,
        sig: ty::FnSig<'tcx>,
        real_sig: ty::FnSig<'tcx>,
    ) -> EvalResult<'tcx, bool> {
211
        fn check_ty_compat<'tcx>(ty: Ty<'tcx>, real_ty: Ty<'tcx>) -> bool {
R
rustfmt  
Ralf Jung 已提交
212 213 214
            if ty == real_ty {
                return true;
            } // This is actually a fast pointer comparison
215 216 217
            return match (&ty.sty, &real_ty.sty) {
                // Permit changing the pointer type of raw pointers and references as well as
                // mutability of raw pointers.
B
Bernardo Meurer 已提交
218
                // FIXME: Should not be allowed when fat pointers are involved.
V
varkor 已提交
219 220
                (&ty::RawPtr(_), &ty::RawPtr(_)) => true,
                (&ty::Ref(_, _, _), &ty::Ref(_, _, _)) => {
R
rustfmt  
Ralf Jung 已提交
221 222
                    ty.is_mutable_pointer() == real_ty.is_mutable_pointer()
                }
223
                // rule out everything else
R
rustfmt  
Ralf Jung 已提交
224 225
                _ => false,
            };
226 227
        }

R
rustfmt  
Ralf Jung 已提交
228
        if sig.abi == real_sig.abi && sig.variadic == real_sig.variadic &&
229
            sig.inputs_and_output.len() == real_sig.inputs_and_output.len() &&
R
rustfmt  
Ralf Jung 已提交
230 231 232 233 234
            sig.inputs_and_output
                .iter()
                .zip(real_sig.inputs_and_output)
                .all(|(ty, real_ty)| check_ty_compat(ty, real_ty))
        {
235 236 237 238 239 240 241 242 243 244 245 246
            // Definitely good.
            return Ok(true);
        }

        if sig.variadic || real_sig.variadic {
            // We're not touching this
            return Ok(false);
        }

        // We need to allow what comes up when a non-capturing closure is cast to a fn().
        match (sig.abi, real_sig.abi) {
            (Abi::Rust, Abi::RustCall) // check the ABIs.  This makes the test here non-symmetric.
B
Bernardo Meurer 已提交
247 248
                if check_ty_compat(sig.output(), real_sig.output())
                    && real_sig.inputs_and_output.len() == 3 => {
249 250
                // First argument of real_sig must be a ZST
                let fst_ty = real_sig.inputs_and_output[0];
251
                if self.layout_of(fst_ty)?.is_zst() {
252 253 254
                    // Second argument must be a tuple matching the argument list of sig
                    let snd_ty = real_sig.inputs_and_output[1];
                    match snd_ty.sty {
B
Bernardo Meurer 已提交
255
<<<<<<< HEAD
V
varkor 已提交
256
                        ty::Tuple(tys) if sig.inputs().len() == tys.len() =>
257
                            if sig.inputs().iter().zip(tys).all(|(ty, real_ty)| check_ty_compat(ty, real_ty)) {
B
Bernardo Meurer 已提交
258 259 260 261 262 263 264
=======
                        ty::TyTuple(tys) if sig.inputs().len() == tys.len() =>
                            if sig.inputs()
                                  .iter()
                                  .zip(tys)
                                  .all(|(ty, real_ty)| check_ty_compat(ty, real_ty)) {
>>>>>>> 7d30ba9... Fixup long code lines
265 266 267 268 269 270 271 272 273 274 275 276 277
                                return Ok(true)
                            },
                        _ => {}
                    }
                }
            }
            _ => {}
        };

        // Nope, this doesn't work.
        return Ok(false);
    }

278 279
    fn eval_fn_call(
        &mut self,
O
Oliver Schneider 已提交
280
        instance: ty::Instance<'tcx>,
R
Ralf Jung 已提交
281 282
        destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
        args: &[OpTy<'tcx>],
283
        span: Span,
O
Oliver Schneider 已提交
284
        sig: ty::FnSig<'tcx>,
285
    ) -> EvalResult<'tcx> {
O
Oliver Schneider 已提交
286
        trace!("eval_fn_call: {:#?}", instance);
R
Ralf Jung 已提交
287 288 289
        if let Some((place, _)) = destination {
            assert_eq!(place.layout.ty, sig.output());
        }
O
Oliver Schneider 已提交
290 291
        match instance.def {
            ty::InstanceDef::Intrinsic(..) => {
292
                let (ret, target) = match destination {
O
Oliver Schneider 已提交
293
                    Some(dest) => dest,
294
                    _ => return err!(Unreachable),
295
                };
R
Ralf Jung 已提交
296 297
                M::call_intrinsic(self, instance, args, ret, target)?;
                self.dump_place(*ret);
O
Oliver Schneider 已提交
298
                Ok(())
R
rustfmt  
Ralf Jung 已提交
299
            }
300
            // FIXME: figure out why we can't just go through the shim
R
rustfmt  
Ralf Jung 已提交
301
            ty::InstanceDef::ClosureOnceShim { .. } => {
R
Ralf Jung 已提交
302
                if M::eval_fn_call(self, instance, destination, args, span)? {
303 304
                    return Ok(());
                }
O
Oliver Schneider 已提交
305 306 307 308
                let mut arg_locals = self.frame().mir.args_iter();
                match sig.abi {
                    // closure as closure once
                    Abi::RustCall => {
R
Ralf Jung 已提交
309
                        for (arg_local, &op) in arg_locals.zip(args) {
O
Oliver Schneider 已提交
310
                            let dest = self.eval_place(&mir::Place::Local(arg_local))?;
R
Ralf Jung 已提交
311
                            self.copy_op(op, dest)?;
O
Oliver Schneider 已提交
312
                        }
R
rustfmt  
Ralf Jung 已提交
313
                    }
O
Oliver Schneider 已提交
314 315 316 317
                    // non capture closure as fn ptr
                    // need to inject zst ptr for closure object (aka do nothing)
                    // and need to pack arguments
                    Abi::Rust => {
R
rustfmt  
Ralf Jung 已提交
318
                        trace!(
R
Ralf Jung 已提交
319 320
                            "args: {:#?}",
                            self.frame().mir.args_iter().zip(args.iter())
B
Bernardo Meurer 已提交
321 322
                                .map(|(local, arg)| (local, **arg, arg.layout.ty))
                                .collect::<Vec<_>>()
R
rustfmt  
Ralf Jung 已提交
323
                        );
O
Oliver Schneider 已提交
324
                        let local = arg_locals.nth(1).unwrap();
R
Ralf Jung 已提交
325
                        for (i, &op) in args.into_iter().enumerate() {
O
Oliver Schneider 已提交
326
                            let dest = self.eval_place(&mir::Place::Local(local).field(
R
rustfmt  
Ralf Jung 已提交
327
                                mir::Field::new(i),
R
Ralf Jung 已提交
328
                                op.layout.ty,
R
rustfmt  
Ralf Jung 已提交
329
                            ))?;
R
Ralf Jung 已提交
330
                            self.copy_op(op, dest)?;
O
Oliver Schneider 已提交
331
                        }
R
rustfmt  
Ralf Jung 已提交
332
                    }
O
Oliver Schneider 已提交
333 334 335
                    _ => bug!("bad ABI for ClosureOnceShim: {:?}", sig.abi),
                }
                Ok(())
O
Oliver Schneider 已提交
336
            }
337 338
            ty::InstanceDef::FnPtrShim(..) |
            ty::InstanceDef::DropGlue(..) |
339
            ty::InstanceDef::CloneShim(..) |
O
Oliver Schneider 已提交
340
            ty::InstanceDef::Item(_) => {
R
Ralf Jung 已提交
341
                // Push the stack frame, and potentially be entirely done if the call got hooked
R
Ralf Jung 已提交
342
                if M::eval_fn_call(self, instance, destination, args, span)? {
B
Bernardo Meurer 已提交
343
                    // FIXME: Can we make it return the frame to push, instead
R
Ralf Jung 已提交
344 345
                    // of the hook doing half of the work and us doing the argument
                    // initialization?
346 347
                    return Ok(());
                }
O
Oliver Schneider 已提交
348

R
Ralf Jung 已提交
349
                // Pass the arguments
O
Oliver Schneider 已提交
350
                let mut arg_locals = self.frame().mir.args_iter();
351
                trace!("ABI: {:?}", sig.abi);
R
rustfmt  
Ralf Jung 已提交
352
                trace!(
R
Ralf Jung 已提交
353 354 355
                    "args: {:#?}",
                    self.frame().mir.args_iter().zip(args.iter())
                        .map(|(local, arg)| (local, **arg, arg.layout.ty)).collect::<Vec<_>>()
R
rustfmt  
Ralf Jung 已提交
356
                );
O
Oliver Schneider 已提交
357 358 359 360
                match sig.abi {
                    Abi::RustCall => {
                        assert_eq!(args.len(), 2);

R
rustfmt  
Ralf Jung 已提交
361 362
                        {
                            // write first argument
O
Oliver Schneider 已提交
363
                            let first_local = arg_locals.next().unwrap();
O
Oliver Schneider 已提交
364
                            let dest = self.eval_place(&mir::Place::Local(first_local))?;
R
Ralf Jung 已提交
365
                            self.copy_op(args[0], dest)?;
O
Oliver Schneider 已提交
366 367 368
                        }

                        // unpack and write all other args
R
Ralf Jung 已提交
369
                        let layout = args[1].layout;
V
varkor 已提交
370
                        if let ty::Tuple(_) = layout.ty.sty {
371 372 373 374
                            if layout.is_zst() {
                                // Nothing to do, no need to unpack zsts
                                return Ok(());
                            }
O
Oliver Schneider 已提交
375
                            if self.frame().mir.args_iter().count() == layout.fields.count() + 1 {
376
                                for (i, arg_local) in arg_locals.enumerate() {
R
Ralf Jung 已提交
377
                                    let arg = self.operand_field(args[1], i as u64)?;
O
Oliver Schneider 已提交
378
                                    let dest = self.eval_place(&mir::Place::Local(arg_local))?;
R
Ralf Jung 已提交
379
                                    self.copy_op(arg, dest)?;
O
Oliver Schneider 已提交
380
                                }
O
Oliver Schneider 已提交
381
                            } else {
382
                                trace!("manual impl of rust-call ABI");
O
Oliver Schneider 已提交
383
                                // called a manual impl of a rust-call function
O
Oliver Schneider 已提交
384 385
                                let dest = self.eval_place(
                                    &mir::Place::Local(arg_locals.next().unwrap()),
R
rustfmt  
Ralf Jung 已提交
386
                                )?;
R
Ralf Jung 已提交
387
                                self.copy_op(args[1], dest)?;
O
Oliver Schneider 已提交
388 389
                            }
                        } else {
R
rustfmt  
Ralf Jung 已提交
390
                            bug!(
R
Ralf Jung 已提交
391
                                "rust-call ABI tuple argument was {:#?}",
R
rustfmt  
Ralf Jung 已提交
392 393
                                layout
                            );
O
Oliver Schneider 已提交
394
                        }
R
rustfmt  
Ralf Jung 已提交
395
                    }
R
Ralf Jung 已提交
396
                    _ => {
R
Ralf Jung 已提交
397
                        for (arg_local, &op) in arg_locals.zip(args) {
O
Oliver Schneider 已提交
398
                            let dest = self.eval_place(&mir::Place::Local(arg_local))?;
R
Ralf Jung 已提交
399
                            self.copy_op(op, dest)?;
R
Ralf Jung 已提交
400
                        }
O
Oliver Schneider 已提交
401 402 403
                    }
                }
                Ok(())
R
rustfmt  
Ralf Jung 已提交
404
            }
405
            // cannot use the shim here, because that will only result in infinite recursion
O
Oliver Schneider 已提交
406 407
            ty::InstanceDef::Virtual(_, idx) => {
                let ptr_size = self.memory.pointer_size();
408
                let ptr_align = self.tcx.data_layout.pointer_align;
R
Ralf Jung 已提交
409
                let (ptr, vtable) = self.read_value(args[0])?.to_scalar_dyn_trait()?;
O
Oliver Schneider 已提交
410
                let fn_ptr = self.memory.read_ptr_sized(
411 412
                    vtable.offset(ptr_size * (idx as u64 + 3), &self)?,
                    ptr_align
R
Ralf Jung 已提交
413
                )?.to_ptr()?;
414
                let instance = self.memory.get_fn(fn_ptr)?;
415 416 417 418

                // 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>.
419
                let mut args = args.to_vec();
420 421 422 423 424
                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)?;
                args[0].op = Operand::Immediate(Value::Scalar(ptr.into())); // strip vtable
                trace!("Patched self operand to {:#?}", args[0]);
O
Oliver Schneider 已提交
425
                // recurse with concrete function
426
                self.eval_fn_call(instance, destination, &args, span, sig)
R
rustfmt  
Ralf Jung 已提交
427
            }
428 429
        }
    }
O
Oliver Schneider 已提交
430
}