From d433da4567b4a7b9c9b92a5b25629fa20952e95c Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 28 Dec 2017 07:56:21 +0200 Subject: [PATCH 1/4] rustc: remove an assortment of Box special-cases. --- src/librustc_const_eval/_match.rs | 2 +- src/librustc_mir/monomorphize/collector.rs | 3 -- src/librustc_trans/base.rs | 42 +++++++------------ src/librustc_trans/debuginfo/metadata.rs | 1 + src/librustc_trans/debuginfo/mod.rs | 1 + src/librustc_typeck/check/regionck.rs | 5 --- .../regions-close-object-into-object-5.rs | 1 - .../regions-close-over-type-parameter-1.rs | 2 - 8 files changed, 18 insertions(+), 39 deletions(-) diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index 33d9bfa6e6b9c..0bc2dff51b3f6 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -853,7 +853,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, ty::TyAdt(adt, substs) => { if adt.is_box() { // Use T as the sub pattern type of Box. - vec![substs[0].as_type().unwrap()] + vec![ty.boxed_ty()] } else { adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| { let is_visible = adt.is_enum() diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index e9a8c2427b373..168d25b0a776e 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -823,9 +823,6 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) => { ptr_vtable(a, b) } - (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) if def_a.is_box() && def_b.is_box() => { - ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty()) - } (&ty::TyAdt(source_adt_def, source_substs), &ty::TyAdt(target_adt_def, target_substs)) => { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 7bb81e9da34c2..44e2dd0a9c3cd 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -236,12 +236,6 @@ pub fn unsize_thin_ptr<'a, 'tcx>( let ptr_ty = bcx.ccx.layout_of(b).llvm_type(bcx.ccx).ptr_to(); (bcx.pointercast(src, ptr_ty), unsized_info(bcx.ccx, a, b, None)) } - (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) if def_a.is_box() && def_b.is_box() => { - let (a, b) = (src_ty.boxed_ty(), dst_ty.boxed_ty()); - assert!(bcx.ccx.shared().type_is_sized(a)); - let ptr_ty = bcx.ccx.layout_of(b).llvm_type(bcx.ccx).ptr_to(); - (bcx.pointercast(src, ptr_ty), unsized_info(bcx.ccx, a, b, None)) - } (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) => { assert_eq!(def_a, def_b); @@ -278,31 +272,25 @@ pub fn coerce_unsized_into<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, dst: PlaceRef<'tcx>) { let src_ty = src.layout.ty; let dst_ty = dst.layout.ty; - let coerce_ptr = || { - let (base, info) = match src.load(bcx).val { - OperandValue::Pair(base, info) => { - // fat-ptr to fat-ptr unsize preserves the vtable - // i.e. &'a fmt::Debug+Send => &'a fmt::Debug - // So we need to pointercast the base to ensure - // the types match up. - let thin_ptr = dst.layout.field(bcx.ccx, abi::FAT_PTR_ADDR); - (bcx.pointercast(base, thin_ptr.llvm_type(bcx.ccx)), info) - } - OperandValue::Immediate(base) => { - unsize_thin_ptr(bcx, base, src_ty, dst_ty) - } - OperandValue::Ref(..) => bug!() - }; - OperandValue::Pair(base, info).store(bcx, dst); - }; match (&src_ty.sty, &dst_ty.sty) { (&ty::TyRef(..), &ty::TyRef(..)) | (&ty::TyRef(..), &ty::TyRawPtr(..)) | (&ty::TyRawPtr(..), &ty::TyRawPtr(..)) => { - coerce_ptr() - } - (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) if def_a.is_box() && def_b.is_box() => { - coerce_ptr() + let (base, info) = match src.load(bcx).val { + OperandValue::Pair(base, info) => { + // fat-ptr to fat-ptr unsize preserves the vtable + // i.e. &'a fmt::Debug+Send => &'a fmt::Debug + // So we need to pointercast the base to ensure + // the types match up. + let thin_ptr = dst.layout.field(bcx.ccx, abi::FAT_PTR_ADDR); + (bcx.pointercast(base, thin_ptr.llvm_type(bcx.ccx)), info) + } + OperandValue::Immediate(base) => { + unsize_thin_ptr(bcx, base, src_ty, dst_ty) + } + OperandValue::Ref(..) => bug!() + }; + OperandValue::Pair(base, info).store(bcx, dst); } (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) => { diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 871f255951483..9687805a52abc 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -558,6 +558,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, Err(metadata) => return metadata, } } + // FIXME(eddyb) remove this Box special-case. ty::TyAdt(def, _) if def.is_box() => { match ptr_metadata(t.boxed_ty()) { Ok(res) => res, diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 3f9ace151a389..bd55380d91e2f 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -431,6 +431,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Only "class" methods are generally understood by LLVM, // so avoid methods on other types (e.g. `<*mut T>::null`). match impl_self_ty.sty { + // FIXME(eddyb) remove this Box special-case. ty::TyAdt(def, ..) if !def.is_box() => { Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP)) } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 64063ec5beda9..4d7ca764b4fd4 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -713,11 +713,6 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { self.type_must_outlive(infer::RelateObjectBound(cast_expr.span), from_ty, r); } - /*From:*/ (&ty::TyAdt(from_def, _), - /*To: */ &ty::TyAdt(to_def, _)) if from_def.is_box() && to_def.is_box() => { - self.walk_cast(cast_expr, from_ty.boxed_ty(), to_ty.boxed_ty()); - } - _ => { } } } diff --git a/src/test/compile-fail/regions-close-object-into-object-5.rs b/src/test/compile-fail/regions-close-object-into-object-5.rs index 6cbe5234ce0e8..d743c411ccac2 100644 --- a/src/test/compile-fail/regions-close-object-into-object-5.rs +++ b/src/test/compile-fail/regions-close-object-into-object-5.rs @@ -30,7 +30,6 @@ fn f<'a, T, U>(v: Box+'static>) -> Box { //~| ERROR the parameter type `T` may not live long enough //~| ERROR the parameter type `T` may not live long enough //~| ERROR the parameter type `T` may not live long enough - //~| ERROR the parameter type `T` may not live long enough } fn main() {} diff --git a/src/test/compile-fail/regions-close-over-type-parameter-1.rs b/src/test/compile-fail/regions-close-over-type-parameter-1.rs index b70ec59420db1..fc18095fc8336 100644 --- a/src/test/compile-fail/regions-close-over-type-parameter-1.rs +++ b/src/test/compile-fail/regions-close-over-type-parameter-1.rs @@ -19,7 +19,6 @@ trait SomeTrait { fn get(&self) -> isize; } fn make_object1(v: A) -> Box { box v as Box //~^ ERROR the parameter type `A` may not live long enough - //~| ERROR the parameter type `A` may not live long enough } fn make_object2<'a,A:SomeTrait+'a>(v: A) -> Box { @@ -29,7 +28,6 @@ fn make_object2<'a,A:SomeTrait+'a>(v: A) -> Box { fn make_object3<'a,'b,A:SomeTrait+'a>(v: A) -> Box { box v as Box //~^ ERROR the parameter type `A` may not live long enough - //~| ERROR the parameter type `A` may not live long enough } fn main() { } From 9e1a903a767bd781e5bea035e938d092fbffc8e3 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 28 Dec 2017 07:57:13 +0200 Subject: [PATCH 2/4] rustc_trans: don't special-case Box to have T* LLVM types. --- src/librustc_trans/intrinsic.rs | 6 ++--- src/librustc_trans/mir/block.rs | 32 +++++--------------------- src/librustc_trans/mir/operand.rs | 19 +++++++++++++-- src/librustc_trans/mir/place.rs | 2 +- src/librustc_trans/type_of.rs | 5 +--- src/test/codegen/function-arguments.rs | 2 +- 6 files changed, 29 insertions(+), 37 deletions(-) diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 3cd60e7f1bc7f..01cfa22c89b8f 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -248,7 +248,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, }, "volatile_store" => { let tp_ty = substs.type_at(0); - let dst = args[0].deref(bcx.ccx); + let dst = args[0].deref(bcx); if let OperandValue::Pair(a, b) = args[1].val { bcx.volatile_store(a, dst.project_field(bcx, 0).llval); bcx.volatile_store(b, dst.project_field(bcx, 1).llval); @@ -394,7 +394,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, }, "discriminant_value" => { - args[0].deref(bcx.ccx).trans_get_discr(bcx, ret_ty) + args[0].deref(bcx).trans_get_discr(bcx, ret_ty) } "align_offset" => { @@ -542,7 +542,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, "nontemporal_store" => { let tp_ty = substs.type_at(0); - let dst = args[0].deref(bcx.ccx); + let dst = args[0].deref(bcx); let val = if let OperandValue::Ref(ptr, align) = args[1].val { bcx.load(ptr, align) } else { diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 422b8210b3544..8362c6fbde0b2 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -592,9 +592,12 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { self.trans_argument(&bcx, op, &mut llargs, &fn_ty.args[i]); } - if let Some(tup) = untuple { - self.trans_arguments_untupled(&bcx, tup, &mut llargs, - &fn_ty.args[first_args.len()..]) + if let Some(tuple) = untuple { + let tuple = self.trans_operand(&bcx, tuple); + for (i, arg) in fn_ty.args[first_args.len()..].iter().enumerate() { + let op = tuple.extract_field(&bcx, i); + self.trans_argument(&bcx, op, &mut llargs, arg); + } } let fn_ptr = match (llfn, instance) { @@ -692,29 +695,6 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { llargs.push(llval); } - fn trans_arguments_untupled(&mut self, - bcx: &Builder<'a, 'tcx>, - operand: &mir::Operand<'tcx>, - llargs: &mut Vec, - args: &[ArgType<'tcx>]) { - let tuple = self.trans_operand(bcx, operand); - - // Handle both by-ref and immediate tuples. - if let Ref(llval, align) = tuple.val { - let tuple_ptr = PlaceRef::new_sized(llval, tuple.layout, align); - for i in 0..tuple.layout.fields.count() { - let field_ptr = tuple_ptr.project_field(bcx, i); - self.trans_argument(bcx, field_ptr.load(bcx), llargs, &args[i]); - } - } else { - // If the tuple is immediate, the elements are as well. - for i in 0..tuple.layout.fields.count() { - let op = tuple.extract_field(bcx, i); - self.trans_argument(bcx, op, llargs, &args[i]); - } - } - } - fn get_personality_slot(&mut self, bcx: &Builder<'a, 'tcx>) -> PlaceRef<'tcx> { let ccx = bcx.ccx; if let Some(slot) = self.personality_slot { diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index 05af48761a167..9157c8addbfdb 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -99,7 +99,16 @@ impl<'a, 'tcx> OperandRef<'tcx> { } } - pub fn deref(self, ccx: &CrateContext<'a, 'tcx>) -> PlaceRef<'tcx> { + pub fn deref(mut self, bcx: &Builder<'a, 'tcx>) -> PlaceRef<'tcx> { + if let ty::TyAdt(def, _) = self.layout.ty.sty { + if def.is_box() { + // HACK(eddyb) Get the raw pointer, assuming it's always + // the first field of the first field of ... of `struct Box`. + while !self.layout.ty.is_unsafe_ptr() { + self = self.extract_field(bcx, 0); + } + } + } let projected_ty = self.layout.ty.builtin_deref(true, ty::NoPreference) .unwrap_or_else(|| bug!("deref of non-pointer {:?}", self)).ty; let (llptr, llextra) = match self.val { @@ -107,7 +116,7 @@ impl<'a, 'tcx> OperandRef<'tcx> { OperandValue::Pair(llptr, llextra) => (llptr, llextra), OperandValue::Ref(..) => bug!("Deref of by-Ref operand {:?}", self) }; - let layout = ccx.layout_of(projected_ty); + let layout = bcx.ccx.layout_of(projected_ty); PlaceRef { llval: llptr, llextra, @@ -152,6 +161,12 @@ impl<'a, 'tcx> OperandRef<'tcx> { } pub fn extract_field(&self, bcx: &Builder<'a, 'tcx>, i: usize) -> OperandRef<'tcx> { + // For indirect values, we can just go through `PlaceRef::project_field`. + if let OperandValue::Ref(ptr, align) = self.val { + let place = PlaceRef::new_sized(ptr, self.layout, align); + return place.project_field(bcx, i).load(bcx); + } + let field = self.layout.field(bcx.ccx, i); let offset = self.layout.fields.offset(i); diff --git a/src/librustc_trans/mir/place.rs b/src/librustc_trans/mir/place.rs index b556b6a132312..08661ac657147 100644 --- a/src/librustc_trans/mir/place.rs +++ b/src/librustc_trans/mir/place.rs @@ -431,7 +431,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { elem: mir::ProjectionElem::Deref }) => { // Load the pointer from its location. - self.trans_consume(bcx, base).deref(bcx.ccx) + self.trans_consume(bcx, base).deref(bcx) } mir::Place::Projection(ref projection) => { let tr_base = self.trans_place(bcx, &projection.base); diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 8d9bc07fe5630..e2d15d1e0b3bf 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -252,6 +252,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { ty::TyRawPtr(ty::TypeAndMut { ty, .. }) => { ccx.layout_of(ty).llvm_type(ccx).ptr_to() } + // FIXME(eddyb) remove this Box special-case. ty::TyAdt(def, _) if def.is_box() => { ccx.layout_of(self.ty.boxed_ty()).llvm_type(ccx).ptr_to() } @@ -341,10 +342,6 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { ty::TyRawPtr(_) => { return self.field(ccx, index).llvm_type(ccx); } - ty::TyAdt(def, _) if def.is_box() => { - let ptr_ty = ccx.tcx().mk_mut_ptr(self.ty.boxed_ty()); - return ccx.layout_of(ptr_ty).scalar_pair_element_llvm_type(ccx, index); - } _ => {} } diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs index f8945a6ee8d93..7946e5bccc4bb 100644 --- a/src/test/codegen/function-arguments.rs +++ b/src/test/codegen/function-arguments.rs @@ -128,7 +128,7 @@ pub fn str(_: &[u8]) { pub fn trait_borrow(_: &Drop) { } -// CHECK: @trait_box(%"core::ops::drop::Drop"* noalias nonnull, {}* noalias nonnull readonly) +// CHECK: @trait_box(i8* noalias nonnull, i8* noalias nonnull readonly) #[no_mangle] pub fn trait_box(_: Box) { } From f63e30a5f63d5278e00ab44901431480a159128f Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 28 Dec 2017 08:13:21 +0200 Subject: [PATCH 3/4] rustc: support `owned_box` lang items with more (defaulted) type parameters. --- src/librustc/ty/context.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e21eb8bbf8ad2..dc9f37a728c57 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -31,7 +31,7 @@ use middle::lang_items; use middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use middle::stability; use mir::{Mir, interpret}; -use ty::subst::{Kind, Substs}; +use ty::subst::{Kind, Substs, Subst}; use ty::ReprOptions; use ty::Instance; use traits; @@ -1959,7 +1959,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> { let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem); let adt_def = self.adt_def(def_id); - let substs = self.mk_substs(iter::once(Kind::from(ty))); + let substs = Substs::for_item(self, def_id, |_, _| bug!(), |def, substs| { + if def.index == 0 { + ty + } else { + assert!(def.has_default); + self.type_of(def.def_id).subst(self, substs) + } + }); self.mk_ty(TyAdt(adt_def, substs)) } From 50435345509883e332f21a5cb15c5c5f53368179 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 29 Dec 2017 02:59:23 +0200 Subject: [PATCH 4/4] rustc: support arbitrary `Box` definitions in `box_free`. --- src/liballoc/arc.rs | 5 +- src/liballoc/heap.rs | 17 ++++- src/liballoc/rc.rs | 5 +- .../borrow_check/nll/type_check/mod.rs | 76 +------------------ src/librustc_mir/transform/inline.rs | 65 +--------------- src/librustc_mir/util/elaborate_drops.rs | 31 +++++--- 6 files changed, 45 insertions(+), 154 deletions(-) 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)