about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_mir/util/elaborate_drops.rs68
1 files changed, 44 insertions, 24 deletions
diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs
index 1564db1ee2a..cc91bbf9061 100644
--- a/src/librustc_mir/util/elaborate_drops.rs
+++ b/src/librustc_mir/util/elaborate_drops.rs
@@ -337,18 +337,19 @@ 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, adt: &'tcx ty::AdtDef, substs: &'tcx Substs<'tcx>)
+                             -> BasicBlock
     {
-        debug!("open_drop_for_box({:?}, {:?})", self, ty);
+        debug!("open_drop_for_box({:?}, {:?}, {:?})", self, adt, substs);
 
         let interior = self.place.clone().deref();
         let interior_path = self.elaborator.deref_subpath(self.path);
 
         let succ = self.succ; // FIXME(#43234)
         let unwind = self.unwind;
-        let succ = self.box_free_block(ty, succ, unwind);
+        let succ = self.box_free_block(adt, substs, succ, unwind);
         let unwind_succ = self.unwind.map(|unwind| {
-            self.box_free_block(ty, unwind, Unwind::InCleanup)
+            self.box_free_block(adt, substs, unwind, Unwind::InCleanup)
         });
 
         self.drop_subpath(&interior, interior_path, succ, unwind_succ)
@@ -791,11 +792,12 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
             ty::TyTuple(tys) => {
                 self.open_drop_for_tuple(tys)
             }
-            ty::TyAdt(def, _) if def.is_box() => {
-                self.open_drop_for_box(ty.boxed_ty())
-            }
             ty::TyAdt(def, substs) => {
-                self.open_drop_for_adt(def, substs)
+                if def.is_box() {
+                    self.open_drop_for_box(def, substs)
+                } else {
+                    self.open_drop_for_adt(def, substs)
+                }
             }
             ty::TyDynamic(..) => {
                 let unwind = self.unwind; // FIXME(#43234)
@@ -858,34 +860,40 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
 
     fn box_free_block<'a>(
         &mut self,
-        ty: Ty<'tcx>,
+        adt: &'tcx ty::AdtDef,
+        substs: &'tcx Substs<'tcx>,
         target: BasicBlock,
         unwind: Unwind,
     ) -> BasicBlock {
-        let block = self.unelaborated_free_block(ty, target, unwind);
+        let block = self.unelaborated_free_block(adt, substs, target, unwind);
         self.drop_flag_test_block(block, target, unwind)
     }
 
     fn unelaborated_free_block<'a>(
         &mut self,
-        ty: Ty<'tcx>,
+        adt: &'tcx ty::AdtDef,
+        substs: &'tcx Substs<'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)));
-        let ref_ty = tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut {
-            ty: ty,
-            mutbl: hir::Mutability::MutMutable
-        });
-        let ptr_ty = tcx.mk_mut_ptr(ty);
-        let ref_tmp = Place::Local(self.new_temp(ref_ty));
-        let ptr_tmp = Place::Local(self.new_temp(ptr_ty));
-
-        let free_block = BasicBlockData {
-            statements: vec![
+        let free_sig = tcx.fn_sig(free_func).skip_binder().clone();
+        let free_inputs = free_sig.inputs();
+        // If the box_free function takes a *mut T, transform the Box into
+        // such a pointer before calling box_free. Otherwise, pass it all
+        // the fields in the Box as individual arguments.
+        let (stmts, args) = if free_inputs.len() == 1 && free_inputs[0].is_mutable_pointer() {
+            let ty = substs.type_at(0);
+            let ref_ty = tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut {
+                ty: ty,
+                mutbl: hir::Mutability::MutMutable
+            });
+            let ptr_ty = tcx.mk_mut_ptr(ty);
+            let ref_tmp = Place::Local(self.new_temp(ref_ty));
+            let ptr_tmp = Place::Local(self.new_temp(ptr_ty));
+            let stmts = vec![
                 self.assign(&ref_tmp, Rvalue::Ref(
                     tcx.types.re_erased,
                     BorrowKind::Mut { allow_two_phase_borrow: false },
@@ -896,11 +904,23 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
                     Operand::Move(ref_tmp),
                     ptr_ty,
                 )),
-            ],
+            ];
+            (stmts, vec![Operand::Move(ptr_tmp)])
+        } else {
+            let args = adt.variants[0].fields.iter().enumerate().map(|(i, f)| {
+                let field = Field::new(i);
+                let field_ty = f.ty(self.tcx(), substs);
+                Operand::Move(self.place.clone().field(field, field_ty))
+            }).collect();
+            (vec![], args)
+        };
+
+        let free_block = BasicBlockData {
+            statements: stmts,
             terminator: Some(Terminator {
                 kind: TerminatorKind::Call {
                     func: Operand::function_handle(tcx, free_func, substs, self.source_info.span),
-                    args: vec![Operand::Move(ptr_tmp)],
+                    args: args,
                     destination: Some((unit_temp, target)),
                     cleanup: None
                 }, // FIXME(#43234)