]> git.lizzy.rs Git - rust.git/blobdiff - src/shims/panic.rs
Auto merge of #2189 - RalfJung:clippy, r=RalfJung
[rust.git] / src / shims / panic.rs
index 2f61ab6c39583aea101089d58fd3867c0cb822e1..ed6e72591dd002e331b3ab45193573854486dfc4 100644 (file)
 //!   gets popped *during unwinding*, we take the panic payload and store it according to the extra
 //!   metadata we remembered when pushing said frame.
 
-use rustc::mir;
-use rustc::ty::{self, layout::LayoutOf};
+use log::trace;
+
+use rustc_ast::Mutability;
+use rustc_middle::{mir, ty};
+use rustc_span::Symbol;
+use rustc_target::spec::abi::Abi;
 use rustc_target::spec::PanicStrategy;
 
 use crate::*;
+use helpers::check_arg_count;
 
 /// Holds all of the relevant data for when unwinding hits a `try` frame.
 #[derive(Debug)]
@@ -30,37 +35,38 @@ pub struct CatchUnwindData<'tcx> {
     ret: mir::BasicBlock,
 }
 
-impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
+impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
     /// Handles the special `miri_start_panic` intrinsic, which is called
     /// by libpanic_unwind to delegate the actual unwinding process to Miri.
     fn handle_miri_start_panic(
         &mut self,
+        abi: Abi,
+        link_name: Symbol,
         args: &[OpTy<'tcx, Tag>],
-        unwind: Option<mir::BasicBlock>,
+        unwind: StackPopUnwind,
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
-        trace!("miri_start_panic: {:?}", this.frame().span);
+        trace!("miri_start_panic: {:?}", this.frame().instance);
 
         // Get the raw pointer stored in arg[0] (the panic payload).
-        let payload = this.read_scalar(args[0])?.not_undef()?;
-        assert!(
-            this.machine.panic_payload.is_none(),
-            "the panic runtime should avoid double-panics"
-        );
-        this.machine.panic_payload = Some(payload);
+        let [payload] = this.check_shim(abi, Abi::Rust, link_name, args)?;
+        let payload = this.read_scalar(payload)?.check_init()?;
+        let thread = this.active_thread_mut();
+        assert!(thread.panic_payload.is_none(), "the panic runtime should avoid double-panics");
+        thread.panic_payload = Some(payload);
 
         // Jump to the unwind block to begin unwinding.
-        this.unwind_to_block(unwind);
-        return Ok(());
+        this.unwind_to_block(unwind)?;
+        Ok(())
     }
 
     /// Handles the `try` intrinsic, the underlying implementation of `std::panicking::try`.
     fn handle_try(
         &mut self,
         args: &[OpTy<'tcx, Tag>],
-        dest: PlaceTy<'tcx, Tag>,
+        dest: &PlaceTy<'tcx, Tag>,
         ret: mir::BasicBlock,
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
@@ -77,20 +83,22 @@ fn handle_try(
         // a pointer to `Box<dyn Any + Send + 'static>`.
 
         // Get all the arguments.
-        let try_fn = this.read_scalar(args[0])?.not_undef()?;
-        let data = this.read_scalar(args[1])?.not_undef()?;
-        let catch_fn = this.read_scalar(args[2])?.not_undef()?;
+        let [try_fn, data, catch_fn] = check_arg_count(args)?;
+        let try_fn = this.read_pointer(try_fn)?;
+        let data = this.read_scalar(data)?.check_init()?;
+        let catch_fn = this.read_scalar(catch_fn)?.check_init()?;
 
         // Now we make a function call, and pass `data` as first and only argument.
-        let f_instance = this.memory.get_fn(try_fn)?.as_instance()?;
+        let f_instance = this.get_ptr_fn(try_fn)?.as_instance()?;
         trace!("try_fn: {:?}", f_instance);
-        let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into();
+        let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into();
         this.call_function(
             f_instance,
+            Abi::Rust,
             &[data.into()],
-            Some(ret_place),
+            &ret_place,
             // Directly return to caller.
-            StackPopCleanup::Goto { ret: Some(ret), unwind: None },
+            StackPopCleanup::Goto { ret: Some(ret), unwind: StackPopUnwind::Skip },
         )?;
 
         // We ourselves will return `0`, eventually (will be overwritten if we catch a panic).
@@ -100,10 +108,11 @@ fn handle_try(
         // This lets `handle_stack_pop` (below) know that we should stop unwinding
         // when we pop this frame.
         if this.tcx.sess.panic_strategy() == PanicStrategy::Unwind {
-            this.frame_mut().extra.catch_unwind = Some(CatchUnwindData { catch_fn, data, dest, ret });
+            this.frame_mut().extra.catch_unwind =
+                Some(CatchUnwindData { catch_fn, data, dest: *dest, ret });
         }
 
-        return Ok(());
+        Ok(())
     }
 
     fn handle_stack_pop(
@@ -114,7 +123,7 @@ fn handle_stack_pop(
         let this = self.eval_context_mut();
 
         trace!("handle_stack_pop(extra = {:?}, unwinding = {})", extra, unwinding);
-        if let Some(stacked_borrows) = this.memory.extra.stacked_borrows.as_ref() {
+        if let Some(stacked_borrows) = &this.machine.stacked_borrows {
             stacked_borrows.borrow_mut().end_call(extra.call_id);
         }
 
@@ -123,25 +132,30 @@ fn handle_stack_pop(
         if let (true, Some(catch_unwind)) = (unwinding, extra.catch_unwind.take()) {
             // We've just popped a frame that was pushed by `try`,
             // and we are unwinding, so we should catch that.
-            trace!("unwinding: found catch_panic frame during unwinding: {:?}", this.frame().span);
+            trace!(
+                "unwinding: found catch_panic frame during unwinding: {:?}",
+                this.frame().instance
+            );
 
             // We set the return value of `try` to 1, since there was a panic.
-            this.write_scalar(Scalar::from_i32(1), catch_unwind.dest)?;
+            this.write_scalar(Scalar::from_i32(1), &catch_unwind.dest)?;
 
-            // `panic_payload` holds what was passed to `miri_start_panic`.
+            // The Thread's `panic_payload` holds what was passed to `miri_start_panic`.
             // This is exactly the second argument we need to pass to `catch_fn`.
-            let payload = this.machine.panic_payload.take().unwrap();
+            let payload = this.active_thread_mut().panic_payload.take().unwrap();
 
             // Push the `catch_fn` stackframe.
-            let f_instance = this.memory.get_fn(catch_unwind.catch_fn)?.as_instance()?;
+            let f_instance =
+                this.get_ptr_fn(this.scalar_to_ptr(catch_unwind.catch_fn)?)?.as_instance()?;
             trace!("catch_fn: {:?}", f_instance);
-            let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into();
+            let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into();
             this.call_function(
                 f_instance,
+                Abi::Rust,
                 &[catch_unwind.data.into(), payload.into()],
-                Some(ret_place),
+                &ret_place,
                 // Directly return to caller of `try`.
-                StackPopCleanup::Goto { ret: Some(catch_unwind.ret), unwind: None },
+                StackPopCleanup::Goto { ret: Some(catch_unwind.ret), unwind: StackPopUnwind::Skip },
             )?;
 
             // We pushed a new stack frame, the engine should not do any jumping now!
@@ -151,24 +165,21 @@ fn handle_stack_pop(
         }
     }
 
-    /// Starta a panic in the interpreter with the given message as payload.
-    fn start_panic(
-        &mut self,
-        msg: &str,
-        unwind: Option<mir::BasicBlock>,
-    ) -> InterpResult<'tcx> {
+    /// Start a panic in the interpreter with the given message as payload.
+    fn start_panic(&mut self, msg: &str, unwind: StackPopUnwind) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
         // First arg: message.
-        let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into());
+        let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into(), Mutability::Not);
 
         // Call the lang item.
         let panic = this.tcx.lang_items().panic_fn().unwrap();
         let panic = ty::Instance::mono(this.tcx.tcx, panic);
         this.call_function(
             panic,
-            &[msg.to_ref()],
-            None,
+            Abi::Rust,
+            &[msg.to_ref(this)],
+            &MPlaceTy::dangling(this.machine.layouts.unit).into(),
             StackPopCleanup::Goto { ret: None, unwind },
         )
     }
@@ -178,31 +189,44 @@ fn assert_panic(
         msg: &mir::AssertMessage<'tcx>,
         unwind: Option<mir::BasicBlock>,
     ) -> InterpResult<'tcx> {
-        use rustc::mir::AssertKind::*;
+        use rustc_middle::mir::AssertKind::*;
         let this = self.eval_context_mut();
 
         match msg {
-            BoundsCheck { ref index, ref len } => {
+            BoundsCheck { index, len } => {
                 // Forward to `panic_bounds_check` lang item.
 
                 // First arg: index.
-                let index = this.read_scalar(this.eval_operand(index, None)?)?;
+                let index = this.read_scalar(&this.eval_operand(index, None)?)?;
                 // Second arg: len.
-                let len = this.read_scalar(this.eval_operand(len, None)?)?;
+                let len = this.read_scalar(&this.eval_operand(len, None)?)?;
 
                 // Call the lang item.
                 let panic_bounds_check = this.tcx.lang_items().panic_bounds_check_fn().unwrap();
                 let panic_bounds_check = ty::Instance::mono(this.tcx.tcx, panic_bounds_check);
                 this.call_function(
                     panic_bounds_check,
+                    Abi::Rust,
                     &[index.into(), len.into()],
-                    None,
-                    StackPopCleanup::Goto { ret: None, unwind },
+                    &MPlaceTy::dangling(this.machine.layouts.unit).into(),
+                    StackPopCleanup::Goto {
+                        ret: None,
+                        unwind: match unwind {
+                            Some(cleanup) => StackPopUnwind::Cleanup(cleanup),
+                            None => StackPopUnwind::Skip,
+                        },
+                    },
                 )?;
             }
             _ => {
                 // Forward everything else to `panic` lang item.
-                this.start_panic(msg.description(), unwind)?;
+                this.start_panic(
+                    msg.description(),
+                    match unwind {
+                        Some(cleanup) => StackPopUnwind::Cleanup(cleanup),
+                        None => StackPopUnwind::Skip,
+                    },
+                )?;
             }
         }
         Ok(())