From 432460a6fc92e8baecbc4fa175345e78232fe2ed Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 28 Jan 2016 23:59:00 +0200 Subject: [PATCH] Synthesize calls to box_free language item This gets rid of Drop(Free, _) MIR construct by synthesizing a call to language item which takes care of dropping instead. --- src/doc/book/lang-items.md | 6 ++ src/liballoc/heap.rs | 13 ++++ src/librustc/middle/dead.rs | 2 +- src/librustc/middle/lang_items.rs | 8 +- src/librustc/middle/reachable.rs | 2 +- src/librustc/mir/repr.rs | 12 +-- src/librustc/mir/visit.rs | 2 +- src/librustc_metadata/encoder.rs | 2 +- src/librustc_mir/build/cfg.rs | 11 ++- src/librustc_mir/build/expr/as_rvalue.rs | 25 +++---- src/librustc_mir/build/expr/as_temp.rs | 2 +- src/librustc_mir/build/expr/into.rs | 2 +- src/librustc_mir/build/matches/mod.rs | 2 +- src/librustc_mir/build/scope.rs | 82 +++++++++++++++++---- src/librustc_mir/build/stmt.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 5 +- src/librustc_mir/hair/mod.rs | 1 + src/librustc_mir/transform/erase_regions.rs | 2 +- src/librustc_trans/trans/mir/constant.rs | 4 +- src/librustc_trans/trans/mir/statement.rs | 11 +-- 20 files changed, 127 insertions(+), 69 deletions(-) diff --git a/src/doc/book/lang-items.md b/src/doc/book/lang-items.md index e492bd3e782..b948567ac5b 100644 --- a/src/doc/book/lang-items.md +++ b/src/doc/book/lang-items.md @@ -39,11 +39,17 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { p } + #[lang = "exchange_free"] unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) { libc::free(ptr as *mut libc::c_void) } +#[lang = "box_free"] +unsafe fn box_free(ptr: *mut T) { + deallocate(ptr as *mut u8, ::core::mem::size_of::(), ::core::mem::align_of::()); +} + #[start] fn main(argc: isize, argv: *const *const u8) -> isize { let x = box 1; diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index 7e7e3c619cb..08b403a60f3 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -16,6 +16,8 @@ issue = "27700")] use core::{isize, usize}; +#[cfg(not(test))] +use core::intrinsics::{size_of, min_align_of}; #[allow(improper_ctypes)] extern "C" { @@ -147,6 +149,17 @@ unsafe fn exchange_free(ptr: *mut u8, old_size: usize, align: usize) { deallocate(ptr, old_size, align); } +#[cfg(not(test))] +#[lang = "box_free"] +#[inline] +unsafe fn box_free(ptr: *mut T) { + let size = size_of::(); + // We do not allocate for Box when T is ZST, so deallocation is also not necessary. + if size != 0 { + deallocate(ptr as *mut u8, size, min_align_of::()); + } +} + #[cfg(test)] mod tests { extern crate test; diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 1fa4093853b..7ed931265f2 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -435,7 +435,7 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { let is_named = node.name().is_some(); let field_type = self.tcx.node_id_to_type(node.id); let is_marker_field = match field_type.ty_to_def_id() { - Some(def_id) => self.tcx.lang_items.items().any(|(_, item)| *item == Some(def_id)), + Some(def_id) => self.tcx.lang_items.items().iter().any(|item| *item == Some(def_id)), _ => false }; is_named diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 6e57d5dd1ba..b445f549ba2 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -36,9 +36,6 @@ use syntax::parse::token::InternedString; use rustc_front::intravisit::Visitor; use rustc_front::hir; -use std::iter::Enumerate; -use std::slice; - // The actual lang items defined come at the end of this file in one handy table. // So you probably just want to nip down to the end. macro_rules! lets_do_this { @@ -69,8 +66,8 @@ impl LanguageItems { } } - pub fn items<'a>(&'a self) -> Enumerate>> { - self.items.iter().enumerate() + pub fn items(&self) -> &[Option] { + &*self.items } pub fn item_name(index: usize) -> &'static str { @@ -334,6 +331,7 @@ lets_do_this! { ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn; ExchangeFreeFnLangItem, "exchange_free", exchange_free_fn; + BoxFreeFnLangItem, "box_free", box_free_fn; StrDupUniqFnLangItem, "strdup_uniq", strdup_uniq_fn; StartFnLangItem, "start", start_fn; diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 6373bfbc55e..6dd447e3b68 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -362,7 +362,7 @@ pub fn find_reachable(tcx: &ty::ctxt, for (id, _) in &access_levels.map { reachable_context.worklist.push(*id); } - for (_, item) in tcx.lang_items.items() { + for item in tcx.lang_items.items().iter() { if let Some(did) = *item { if let Some(node_id) = tcx.map.as_local_node_id(did) { reachable_context.worklist.push(node_id); diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index 988bf2c76a8..b9a94ad0068 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -490,14 +490,7 @@ pub struct Statement<'tcx> { #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub enum StatementKind<'tcx> { Assign(Lvalue<'tcx>, Rvalue<'tcx>), - Drop(DropKind, Lvalue<'tcx>), -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] -pub enum DropKind { - /// free a partially constructed box, should go away eventually - Free, - Deep + Drop(Lvalue<'tcx>), } impl<'tcx> Debug for Statement<'tcx> { @@ -505,8 +498,7 @@ impl<'tcx> Debug for Statement<'tcx> { use self::StatementKind::*; match self.kind { Assign(ref lv, ref rv) => write!(fmt, "{:?} = {:?}", lv, rv), - Drop(DropKind::Free, ref lv) => write!(fmt, "free {:?}", lv), - Drop(DropKind::Deep, ref lv) => write!(fmt, "drop {:?}", lv), + Drop(ref lv) => write!(fmt, "drop {:?}", lv), } } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index a38ef078c6f..494eac44b1a 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -124,7 +124,7 @@ macro_rules! make_mir_visitor { ref $($mutability)* rvalue) => { self.visit_assign(block, lvalue, rvalue); } - StatementKind::Drop(_, ref $($mutability)* lvalue) => { + StatementKind::Drop(ref $($mutability)* lvalue) => { self.visit_lvalue(lvalue, LvalueContext::Drop); } } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 1e50868f664..8df72016078 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1649,7 +1649,7 @@ fn encode_crate_deps(rbml_w: &mut Encoder, cstore: &cstore::CStore) { fn encode_lang_items(ecx: &EncodeContext, rbml_w: &mut Encoder) { rbml_w.start_tag(tag_lang_items); - for (i, &opt_def_id) in ecx.tcx.lang_items.items() { + for (i, &opt_def_id) in ecx.tcx.lang_items.items().iter().enumerate() { if let Some(def_id) = opt_def_id { if def_id.is_local() { rbml_w.start_tag(tag_lang_items_item); diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index 523ac85cdc5..5be2b8394ee 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -32,16 +32,21 @@ impl<'tcx> CFG<'tcx> { BasicBlock::new(node_index) } + pub fn start_new_cleanup_block(&mut self) -> BasicBlock { + let bb = self.start_new_block(); + self.block_data_mut(bb).is_cleanup = true; + bb + } + pub fn push(&mut self, block: BasicBlock, statement: Statement<'tcx>) { debug!("push({:?}, {:?})", block, statement); self.block_data_mut(block).statements.push(statement); } - pub fn push_drop(&mut self, block: BasicBlock, span: Span, - kind: DropKind, lvalue: &Lvalue<'tcx>) { + pub fn push_drop(&mut self, block: BasicBlock, span: Span, lvalue: &Lvalue<'tcx>) { self.push(block, Statement { span: span, - kind: StatementKind::Drop(kind, lvalue.clone()) + kind: StatementKind::Drop(lvalue.clone()) }); } diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index e556d707a2d..dea2d750b98 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -59,25 +59,18 @@ impl<'a,'tcx> Builder<'a,'tcx> { let arg = unpack!(block = this.as_operand(block, arg)); block.and(Rvalue::UnaryOp(op, arg)) } - ExprKind::Box { value } => { + ExprKind::Box { value, value_extents } => { let value = this.hir.mirror(value); let result = this.temp(expr.ty); - // to start, malloc some memory of suitable type (thus far, uninitialized): - let rvalue = Rvalue::Box(value.ty); - this.cfg.push_assign(block, expr_span, &result, rvalue); - - // schedule a shallow free of that memory, lest we unwind: - let extent = this.extent_of_innermost_scope(); - this.schedule_drop(expr_span, extent, DropKind::Free, &result, value.ty); - - // initialize the box contents: - let contents = result.clone().deref(); - unpack!(block = this.into(&contents, block, value)); - - // now that the result is fully initialized, cancel the drop - // by "using" the result (which is linear): - block.and(Rvalue::Use(Operand::Consume(result))) + this.cfg.push_assign(block, expr_span, &result, Rvalue::Box(value.ty)); + this.in_scope(value_extents, block, |this| { + // schedule a shallow free of that memory, lest we unwind: + this.schedule_box_free(expr_span, value_extents, &result, value.ty); + // initialize the box contents: + unpack!(block = this.into(&result.clone().deref(), block, value)); + block.and(Rvalue::Use(Operand::Consume(result))) + }) } ExprKind::Cast { source } => { let source = unpack!(block = this.as_operand(block, source)); diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index 53f8090ad0f..27c374e1ac2 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -41,7 +41,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { this.hir.span_bug(expr.span, "no temp_lifetime for expr"); } }; - this.schedule_drop(expr.span, temp_lifetime, DropKind::Deep, &temp, expr_ty); + this.schedule_drop(expr.span, temp_lifetime, &temp, expr_ty); // Careful here not to cause an infinite cycle. If we always // called `into`, then for lvalues like `x.f`, it would diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 4261efe8215..7ecd8a26507 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -188,7 +188,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { // operators like x[j] = x[i]. let rhs = unpack!(block = this.as_operand(block, rhs)); let lhs = unpack!(block = this.as_lvalue(block, lhs)); - this.cfg.push_drop(block, expr_span, DropKind::Deep, &lhs); + this.cfg.push_drop(block, expr_span, &lhs); this.cfg.push_assign(block, expr_span, &lhs, Rvalue::Use(rhs)); block.unit() } diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index c2c87fcbd20..e6430b7d634 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -601,7 +601,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { ty: var_ty.clone(), }); let index = index as u32; - self.schedule_drop(span, var_extent, DropKind::Deep, &Lvalue::Var(index), var_ty); + self.schedule_drop(span, var_extent, &Lvalue::Var(index), var_ty); self.var_indices.insert(var_id, index); debug!("declare_binding: index={:?}", index); diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index dae525c84d0..35153bc8a90 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -89,7 +89,7 @@ should go to. use build::{BlockAnd, BlockAndExtension, Builder}; use rustc::middle::region::CodeExtent; use rustc::middle::lang_items; -use rustc::middle::subst::Substs; +use rustc::middle::subst::{Substs, VecPerParamSpace}; use rustc::middle::ty::{self, Ty}; use rustc::mir::repr::*; use syntax::codemap::{Span, DUMMY_SP}; @@ -97,7 +97,8 @@ use syntax::parse::token::intern_and_get_ident; pub struct Scope<'tcx> { extent: CodeExtent, - drops: Vec<(DropKind, Span, Lvalue<'tcx>)>, + drops: Vec<(Span, Lvalue<'tcx>)>, + frees: Vec<(Span, Lvalue<'tcx>, Ty<'tcx>)>, cached_block: Option, } @@ -164,6 +165,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { self.scopes.push(Scope { extent: extent.clone(), drops: vec![], + frees: vec![], cached_block: None, }); } @@ -180,8 +182,8 @@ impl<'a,'tcx> Builder<'a,'tcx> { // add in any drops needed on the fallthrough path (any other // exiting paths, such as those that arise from `break`, will // have drops already) - for (kind, span, lvalue) in scope.drops { - self.cfg.push_drop(block, span, kind, &lvalue); + for (span, lvalue) in scope.drops { + self.cfg.push_drop(block, span, &lvalue); } } @@ -225,8 +227,8 @@ impl<'a,'tcx> Builder<'a,'tcx> { }); for scope in scopes.iter_mut().rev().take(scope_count) { - for &(kind, drop_span, ref lvalue) in &scope.drops { - cfg.push_drop(block, drop_span, kind, lvalue); + for &(drop_span, ref lvalue) in &scope.drops { + cfg.push_drop(block, drop_span, lvalue); } } cfg.terminate(block, Terminator::Goto { target: target }); @@ -242,23 +244,55 @@ impl<'a,'tcx> Builder<'a,'tcx> { return None; } + let tcx = self.hir.tcx(); + let unit_tmp = self.get_unit_temp(); let mut terminator = Terminator::Resume; // Given an array of scopes, we generate these from the outermost scope to the innermost // one. Thus for array [S0, S1, S2] with corresponding cleanup blocks [B0, B1, B2], we will // generate B0 <- B1 <- B2 in left-to-right order. The outermost scope (B0) will always // terminate with a Resume terminator. - for scope in self.scopes.iter_mut().filter(|s| !s.drops.is_empty()) { + for scope in self.scopes.iter_mut().filter(|s| !s.drops.is_empty() || !s.frees.is_empty()) { if let Some(b) = scope.cached_block { terminator = Terminator::Goto { target: b }; continue; } else { - let new_block = self.cfg.start_new_block(); - self.cfg.block_data_mut(new_block).is_cleanup = true; + let mut new_block = self.cfg.start_new_cleanup_block(); self.cfg.terminate(new_block, terminator); terminator = Terminator::Goto { target: new_block }; - for &(kind, span, ref lvalue) in scope.drops.iter().rev() { - self.cfg.push_drop(new_block, span, kind, lvalue); + + for &(span, ref lvalue) in scope.drops.iter().rev() { + self.cfg.push_drop(new_block, span, lvalue); } + + for &(_, ref lvalue, ref item_ty) in scope.frees.iter().rev() { + let item = lang_items::SpannedLangItems::box_free_fn(&tcx.lang_items) + .expect("box_free language item required"); + let substs = tcx.mk_substs(Substs::new( + VecPerParamSpace::new(vec![], vec![], vec![item_ty]), + VecPerParamSpace::new(vec![], vec![], vec![]) + )); + let func = Constant { + span: item.1, + ty: tcx.lookup_item_type(item.0).ty.subst(substs), + literal: Literal::Item { + def_id: item.0, + kind: ItemKind::Function, + substs: substs + } + }; + let old_block = new_block; + new_block = self.cfg.start_new_cleanup_block(); + self.cfg.terminate(new_block, Terminator::Call { + func: Operand::Constant(func), + args: vec![Operand::Consume(lvalue.clone())], + kind: CallKind::Converging { + target: old_block, + destination: unit_tmp.clone() + } + }); + terminator = Terminator::Goto { target: new_block }; + } + scope.cached_block = Some(new_block); } } @@ -272,7 +306,6 @@ impl<'a,'tcx> Builder<'a,'tcx> { pub fn schedule_drop(&mut self, span: Span, extent: CodeExtent, - kind: DropKind, lvalue: &Lvalue<'tcx>, lvalue_ty: Ty<'tcx>) { if self.hir.needs_drop(lvalue_ty) { @@ -282,7 +315,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { // incorrect (i.e. they still are pointing at old cached_block). scope.cached_block = None; if scope.extent == extent { - scope.drops.push((kind, span, lvalue.clone())); + scope.drops.push((span, lvalue.clone())); return; } } @@ -291,6 +324,27 @@ impl<'a,'tcx> Builder<'a,'tcx> { } } + /// Schedule dropping of a not yet fully initialised box. This cleanup will (and should) only + /// be translated into unwind branch. The extent should be for the `EXPR` inside `box EXPR`. + pub fn schedule_box_free(&mut self, + span: Span, + extent: CodeExtent, + lvalue: &Lvalue<'tcx>, + item_ty: Ty<'tcx>) { + for scope in self.scopes.iter_mut().rev() { + // We must invalidate all the cached_blocks leading up to the scope we’re looking + // for, because otherwise some/most of the blocks in the chain might become + // incorrect (i.e. they still are pointing at old cached_block). + scope.cached_block = None; + if scope.extent == extent { + scope.frees.push((span, lvalue.clone(), item_ty)); + return; + } + } + self.hir.span_bug(span, + &format!("extent {:?} not in scope to drop {:?}", extent, lvalue)); + } + pub fn extent_of_innermost_scope(&self) -> CodeExtent { self.scopes.last().map(|scope| scope.extent).unwrap() } @@ -299,6 +353,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { self.scopes.first().map(|scope| scope.extent).unwrap() } + pub fn panic_bounds_check(&mut self, block: BasicBlock, index: Operand<'tcx>, @@ -405,4 +460,5 @@ impl<'a,'tcx> Builder<'a,'tcx> { literal: self.hir.usize_literal(span_lines.line) }) } + } diff --git a/src/librustc_mir/build/stmt.rs b/src/librustc_mir/build/stmt.rs index c70b22893ae..3a50acec94f 100644 --- a/src/librustc_mir/build/stmt.rs +++ b/src/librustc_mir/build/stmt.rs @@ -72,7 +72,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { let expr = this.hir.mirror(expr); let temp = this.temp(expr.ty.clone()); unpack!(block = this.into(&temp, block, expr)); - this.cfg.push_drop(block, span, DropKind::Deep, &temp); + this.cfg.push_drop(block, span, &temp); block.unit() })); } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index d8a1930fd5c..f9a9c99f63d 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -375,7 +375,10 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { hir::ExprType(ref source, _) => return source.make_mirror(cx), hir::ExprBox(ref value) => - ExprKind::Box { value: value.to_ref() }, + ExprKind::Box { + value: value.to_ref(), + value_extents: cx.tcx.region_maps.node_extent(value.id) + }, hir::ExprVec(ref fields) => ExprKind::Vec { fields: fields.to_ref() }, hir::ExprTup(ref fields) => diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index b356e3886d1..0891c2845b0 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -123,6 +123,7 @@ pub enum ExprKind<'tcx> { }, Box { value: ExprRef<'tcx>, + value_extents: CodeExtent, }, Call { ty: ty::Ty<'tcx>, diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 66604786d46..3cd1bd76c54 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -69,7 +69,7 @@ impl<'a, 'tcx> EraseRegions<'a, 'tcx> { self.erase_regions_lvalue(lvalue); self.erase_regions_rvalue(rvalue); } - StatementKind::Drop(_, ref mut lvalue) => { + StatementKind::Drop(ref mut lvalue) => { self.erase_regions_lvalue(lvalue); } } diff --git a/src/librustc_trans/trans/mir/constant.rs b/src/librustc_trans/trans/mir/constant.rs index 84cc87e9b13..3b763599f77 100644 --- a/src/librustc_trans/trans/mir/constant.rs +++ b/src/librustc_trans/trans/mir/constant.rs @@ -82,13 +82,13 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { constant: &mir::Constant<'tcx>) -> OperandRef<'tcx> { - let ty = bcx.monomorphize(&constant.ty); match constant.literal { mir::Literal::Item { def_id, kind, substs } => { let substs = bcx.tcx().mk_substs(bcx.monomorphize(&substs)); - self.trans_item_ref(bcx, ty, kind, substs, def_id) + self.trans_item_ref(bcx, constant.ty, kind, substs, def_id) } mir::Literal::Value { ref value } => { + let ty = bcx.monomorphize(&constant.ty); self.trans_constval(bcx, value, ty) } } diff --git a/src/librustc_trans/trans/mir/statement.rs b/src/librustc_trans/trans/mir/statement.rs index dae0d3b55c0..cd186de7ca0 100644 --- a/src/librustc_trans/trans/mir/statement.rs +++ b/src/librustc_trans/trans/mir/statement.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::middle::ty::LvaluePreference; use rustc::mir::repr as mir; use trans::common::Block; use trans::debuginfo::DebugLoc; @@ -52,19 +51,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } } - mir::StatementKind::Drop(mir::DropKind::Deep, ref lvalue) => { + mir::StatementKind::Drop(ref lvalue) => { let tr_lvalue = self.trans_lvalue(bcx, lvalue); let ty = tr_lvalue.ty.to_ty(bcx.tcx()); glue::drop_ty(bcx, tr_lvalue.llval, ty, DebugLoc::None) } - - mir::StatementKind::Drop(mir::DropKind::Free, ref lvalue) => { - let tr_lvalue = self.trans_lvalue(bcx, lvalue); - let ty = tr_lvalue.ty.to_ty(bcx.tcx()); - let content_ty = ty.builtin_deref(true, LvaluePreference::NoPreference); - let content_ty = content_ty.unwrap().ty; - glue::trans_exchange_free_ty(bcx, tr_lvalue.llval, content_ty, DebugLoc::None) - } } } }