diff --git a/src/interpreter/terminator/intrinsics.rs b/src/interpreter/terminator/intrinsics.rs index f6dc8778a5f3..9161f6e35b4e 100644 --- a/src/interpreter/terminator/intrinsics.rs +++ b/src/interpreter/terminator/intrinsics.rs @@ -18,6 +18,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { dest: Lvalue<'tcx>, dest_ty: Ty<'tcx>, dest_layout: &'tcx Layout, + target: mir::BasicBlock, ) -> EvalResult<'tcx, ()> { let arg_vals: EvalResult> = args.iter() .map(|arg| self.eval_operand(arg)) @@ -137,7 +138,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { }; let mut drops = Vec::new(); self.drop(lvalue, ty, &mut drops)?; - self.eval_drop_impls(drops)?; + // need to change the block before pushing the drop impl stack frames + // we could do this for all intrinsics before evaluating the intrinsics, but if + // the evaluation fails, we should not have moved forward + self.goto_block(target); + return self.eval_drop_impls(drops); } "fabsf32" => { @@ -341,6 +346,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { name => return Err(EvalError::Unimplemented(format!("unimplemented intrinsic: {}", name))), } + self.goto_block(target); + // Since we pushed no stack frame, the main loop will act // as if the call just completed and it's returning to the // current frame. diff --git a/src/interpreter/terminator/mod.rs b/src/interpreter/terminator/mod.rs index dab0aed4acbe..dcca791f6665 100644 --- a/src/interpreter/terminator/mod.rs +++ b/src/interpreter/terminator/mod.rs @@ -187,8 +187,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let ty = fn_ty.sig.0.output; let layout = self.type_layout(ty); let (ret, target) = destination.unwrap(); - self.call_intrinsic(def_id, substs, arg_operands, ret, ty, layout)?; - self.goto_block(target); + self.call_intrinsic(def_id, substs, arg_operands, ret, ty, layout, target)?; Ok(()) } diff --git a/tests/run-pass/call_drop_through_trait_object_rc.rs b/tests/run-pass/call_drop_through_trait_object_rc.rs new file mode 100644 index 000000000000..ce56ca6a1caf --- /dev/null +++ b/tests/run-pass/call_drop_through_trait_object_rc.rs @@ -0,0 +1,22 @@ +trait Foo {} + +struct Bar; + +static mut DROP_CALLED: bool = false; + +impl Drop for Bar { + fn drop(&mut self) { + unsafe { DROP_CALLED = true; } + } +} + +impl Foo for Bar {} + +use std::rc::Rc; + +fn main() { + let b: Rc = Rc::new(Bar); + assert!(unsafe { !DROP_CALLED }); + drop(b); + assert!(unsafe { DROP_CALLED }); +}