diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 185af8835d1e4..6dba53d7ebd3b 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -568,7 +568,8 @@ impl Arc { fn from_box(v: Box) -> Arc { unsafe { - let bptr = Box::into_raw(v); + let box_unique = Box::into_unique(v); + let bptr = box_unique.as_ptr(); let value_size = size_of_val(&*bptr); let ptr = Self::allocate_for_ptr(bptr); @@ -580,7 +581,7 @@ impl Arc { value_size); // Free the allocation without dropping its contents - box_free(bptr); + box_free(box_unique); Arc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData } } diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index b2bd9d7d8fafa..c1862fd509ca9 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -17,6 +17,7 @@ use core::intrinsics::{min_align_of_val, size_of_val}; use core::mem::{self, ManuallyDrop}; +use core::ptr::Unique; use core::usize; pub use allocator::*; @@ -252,9 +253,21 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { } } -#[cfg_attr(not(test), lang = "box_free")] +#[cfg(stage0)] +#[lang = "box_free"] #[inline] -pub(crate) unsafe fn box_free(ptr: *mut T) { +pub(crate) unsafe fn old_box_free(ptr: *mut T) { + box_free(Unique::new_unchecked(ptr)) +} + +#[cfg_attr(not(any(test, stage0)), lang = "box_free")] +#[inline] +// Invoked by the compiler to deallocate the storage of `Box`, +// after the owned `T` value on the heap has already been dropped. +// NB: the generics should be the same as for `Box`, and the +// argument types should match the fields in `struct Box`. +pub(crate) unsafe fn box_free(ptr: Unique) { + let ptr = ptr.as_ptr(); let size = size_of_val(&*ptr); let align = min_align_of_val(&*ptr); // We do not allocate for Box when T is ZST, so deallocation is also not necessary. diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 59079f9ba76bc..3cce32d4569ab 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -681,7 +681,8 @@ impl Rc { fn from_box(v: Box) -> Rc { unsafe { - let bptr = Box::into_raw(v); + let box_unique = Box::into_unique(v); + let bptr = box_unique.as_ptr(); let value_size = size_of_val(&*bptr); let ptr = Self::allocate_for_ptr(bptr); @@ -693,7 +694,7 @@ impl Rc { value_size); // Free the allocation without dropping its contents - box_free(bptr); + box_free(box_unique); Rc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 901b73c610e3b..554a644c4b887 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -892,11 +892,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { )); } - if self.is_box_free(func) { - self.check_box_free_inputs(mir, term, &sig, args, term_location); - } else { - self.check_call_inputs(mir, term, &sig, args, term_location); - } + self.check_call_inputs(mir, term, &sig, args, term_location); } TerminatorKind::Assert { ref cond, ref msg, .. @@ -1000,76 +996,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn is_box_free(&self, operand: &Operand<'tcx>) -> bool { - match operand { - &Operand::Constant(box Constant { - literal: - Literal::Value { - value: - &ty::Const { - val: ConstVal::Function(def_id, _), - .. - }, - .. - }, - .. - }) => Some(def_id) == self.tcx().lang_items().box_free_fn(), - _ => false, - } - } - - fn check_box_free_inputs( - &mut self, - mir: &Mir<'tcx>, - term: &Terminator<'tcx>, - sig: &ty::FnSig<'tcx>, - args: &[Operand<'tcx>], - term_location: Location, - ) { - debug!("check_box_free_inputs"); - - // box_free takes a Box as a pointer. Allow for that. - - if sig.inputs().len() != 1 { - span_mirbug!(self, term, "box_free should take 1 argument"); - return; - } - - let pointee_ty = match sig.inputs()[0].sty { - ty::TyRawPtr(mt) => mt.ty, - _ => { - span_mirbug!(self, term, "box_free should take a raw ptr"); - return; - } - }; - - if args.len() != 1 { - span_mirbug!(self, term, "box_free called with wrong # of args"); - return; - } - - let ty = args[0].ty(mir, self.tcx()); - let arg_ty = match ty.sty { - ty::TyRawPtr(mt) => mt.ty, - ty::TyAdt(def, _) if def.is_box() => ty.boxed_ty(), - _ => { - span_mirbug!(self, term, "box_free called with bad arg ty"); - return; - } - }; - - if let Err(terr) = self.sub_types(arg_ty, pointee_ty, term_location.at_self()) { - span_mirbug!( - self, - term, - "bad box_free arg ({:?} <- {:?}): {:?}", - pointee_ty, - arg_ty, - terr - ); - } - } - fn check_iscleanup(&mut self, mir: &Mir<'tcx>, block_data: &BasicBlockData<'tcx>) { let is_cleanup = block_data.is_cleanup; self.last_span = block_data.terminator().source_info.span; diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 43ee75d1e2ba2..36daaffc47406 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -369,8 +369,6 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { TerminatorKind::Call { args, destination: Some(destination), cleanup, .. } => { debug!("Inlined {:?} into {:?}", callsite.callee, self.source); - let is_box_free = Some(callsite.callee) == self.tcx.lang_items().box_free_fn(); - let mut local_map = IndexVec::with_capacity(callee_mir.local_decls.len()); let mut scope_map = IndexVec::with_capacity(callee_mir.visibility_scopes.len()); let mut promoted_map = IndexVec::with_capacity(callee_mir.promoted.len()); @@ -450,24 +448,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let return_block = destination.1; - let args : Vec<_> = if is_box_free { - assert!(args.len() == 1); - // box_free takes a Box, but is defined with a *mut T, inlining - // needs to generate the cast. - // FIXME: we should probably just generate correct MIR in the first place... - - let arg = if let Operand::Move(ref place) = args[0] { - place.clone() - } else { - bug!("Constant arg to \"box_free\""); - }; - - let ptr_ty = args[0].ty(caller_mir, self.tcx); - vec![self.cast_box_free_arg(arg, ptr_ty, &callsite, caller_mir)] - } else { - // Copy the arguments if needed. - self.make_call_args(args, &callsite, caller_mir) - }; + // Copy the arguments if needed. + let args: Vec<_> = self.make_call_args(args, &callsite, caller_mir); let bb_len = caller_mir.basic_blocks().len(); let mut integrator = Integrator { @@ -508,49 +490,6 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { } } - fn cast_box_free_arg(&self, arg: Place<'tcx>, ptr_ty: Ty<'tcx>, - callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>) -> Local { - let arg = Rvalue::Ref( - self.tcx.types.re_erased, - BorrowKind::Mut, - arg.deref()); - - let ty = arg.ty(caller_mir, self.tcx); - let ref_tmp = LocalDecl::new_temp(ty, callsite.location.span); - let ref_tmp = caller_mir.local_decls.push(ref_tmp); - let ref_tmp = Place::Local(ref_tmp); - - let ref_stmt = Statement { - source_info: callsite.location, - kind: StatementKind::Assign(ref_tmp.clone(), arg) - }; - - caller_mir[callsite.bb] - .statements.push(ref_stmt); - - let pointee_ty = match ptr_ty.sty { - ty::TyRawPtr(tm) | ty::TyRef(_, tm) => tm.ty, - _ if ptr_ty.is_box() => ptr_ty.boxed_ty(), - _ => bug!("Invalid type `{:?}` for call to box_free", ptr_ty) - }; - let ptr_ty = self.tcx.mk_mut_ptr(pointee_ty); - - let raw_ptr = Rvalue::Cast(CastKind::Misc, Operand::Move(ref_tmp), ptr_ty); - - let cast_tmp = LocalDecl::new_temp(ptr_ty, callsite.location.span); - let cast_tmp = caller_mir.local_decls.push(cast_tmp); - - let cast_stmt = Statement { - source_info: callsite.location, - kind: StatementKind::Assign(Place::Local(cast_tmp), raw_ptr) - }; - - caller_mir[callsite.bb] - .statements.push(cast_stmt); - - cast_tmp - } - fn make_call_args( &self, args: Vec>, diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 3331bc9e59e0b..cd2e0874cafae 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -337,18 +337,18 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> self.drop_ladder(fields, succ, unwind).0 } - fn open_drop_for_box<'a>(&mut self, ty: Ty<'tcx>) -> BasicBlock + fn open_drop_for_box<'a>(&mut self, box_ty: Ty<'tcx>) -> BasicBlock { - debug!("open_drop_for_box({:?}, {:?})", self, ty); + debug!("open_drop_for_box({:?}, {:?})", self, box_ty); let interior = self.place.clone().deref(); let interior_path = self.elaborator.deref_subpath(self.path); let succ = self.succ; // FIXME(#6393) let unwind = self.unwind; - let succ = self.box_free_block(ty, succ, unwind); + let succ = self.box_free_block(box_ty, succ, unwind); let unwind_succ = self.unwind.map(|unwind| { - self.box_free_block(ty, unwind, Unwind::InCleanup) + self.box_free_block(box_ty, unwind, Unwind::InCleanup) }); self.drop_subpath(&interior, interior_path, succ, unwind_succ) @@ -788,7 +788,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> self.open_drop_for_tuple(tys) } ty::TyAdt(def, _) if def.is_box() => { - self.open_drop_for_box(ty.boxed_ty()) + self.open_drop_for_box(ty) } ty::TyAdt(def, substs) => { self.open_drop_for_adt(def, substs) @@ -854,28 +854,39 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> fn box_free_block<'a>( &mut self, - ty: Ty<'tcx>, + box_ty: Ty<'tcx>, target: BasicBlock, unwind: Unwind, ) -> BasicBlock { - let block = self.unelaborated_free_block(ty, target, unwind); + let block = self.unelaborated_free_block(box_ty, target, unwind); self.drop_flag_test_block(block, target, unwind) } fn unelaborated_free_block<'a>( &mut self, - ty: Ty<'tcx>, + box_ty: Ty<'tcx>, target: BasicBlock, unwind: Unwind ) -> BasicBlock { let tcx = self.tcx(); let unit_temp = Place::Local(self.new_temp(tcx.mk_nil())); let free_func = tcx.require_lang_item(lang_items::BoxFreeFnLangItem); - let substs = tcx.mk_substs(iter::once(Kind::from(ty))); + + // Use the generic parameters of `Box` for `box_free`, and the + // fields of `Box` as arguments. Their types should always match. + let (substs, args) = match box_ty.sty { + ty::TyAdt(def, substs) => { + (substs, def.struct_variant().fields.iter().enumerate().map(|(i, f)| { + let box_place = self.place.clone(); + Operand::Move(box_place.field(Field::new(i), f.ty(tcx, substs))) + }).collect()) + } + _ => bug!("expected Box to be a struct, found `{:?}`", box_ty) + }; let call = TerminatorKind::Call { func: Operand::function_handle(tcx, free_func, substs, self.source_info.span), - args: vec![Operand::Move(self.place.clone())], + args, destination: Some((unit_temp, target)), cleanup: None }; // FIXME(#6393)