diff --git a/examples/mini_core.rs b/examples/mini_core.rs index 318cfe49da184..ea0a8c08ef53b 100644 --- a/examples/mini_core.rs +++ b/examples/mini_core.rs @@ -197,6 +197,11 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { &mut MY_TINY_HEAP as *mut [u8; 16] as *mut u8 } +#[lang = "drop"] +pub trait Drop { + fn drop(&mut self); +} + pub mod intrinsics { extern "rust-intrinsic" { pub fn abort() -> !; diff --git a/examples/mini_core_hello_world.rs b/examples/mini_core_hello_world.rs index ba05e5befc9a7..661fa3cd7f153 100644 --- a/examples/mini_core_hello_world.rs +++ b/examples/mini_core_hello_world.rs @@ -49,6 +49,29 @@ impl SomeTrait for &'static str { } } +struct NoisyDrop { + text: &'static str, + inner: NoisyDropInner, +} + +struct NoisyDropInner; + +impl Drop for NoisyDrop { + fn drop(&mut self) { + unsafe { + puts(self.text as *const str as *const u8); + } + } +} + +impl Drop for NoisyDropInner { + fn drop(&mut self) { + unsafe { + puts("Inner got dropped!\0" as *const str as *const u8); + } + } +} + #[lang = "start"] fn start( main: fn() -> T, @@ -91,4 +114,9 @@ fn main() { panic(&("", "", 0, 0)); } } + + let _ = NoisyDrop { + text: "Outer got dropped!\0", + inner: NoisyDropInner, + }; } diff --git a/src/abi.rs b/src/abi.rs index 3d020087e4760..c1eefa430e01d 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -433,7 +433,7 @@ pub fn codegen_fn_prelude<'a, 'tcx: 'a>( .jump(*fx.ebb_map.get(&START_BLOCK).unwrap(), &[]); } -pub fn codegen_call<'a, 'tcx: 'a>( +pub fn codegen_terminator_call<'a, 'tcx: 'a>( fx: &mut FunctionCx<'a, 'tcx, impl Backend>, func: &Operand<'tcx>, args: &[Operand<'tcx>], @@ -466,19 +466,42 @@ pub fn codegen_call<'a, 'tcx: 'a>( let destination = destination .as_ref() - .map(|(place, bb)| (trans_place(fx, place), *bb)); - - if codegen_intrinsic_call(fx, fn_ty, sig, &args, destination) { - return; + .map(|&(ref place, bb)| (trans_place(fx, place), bb)); + + if !codegen_intrinsic_call(fx, fn_ty, &args, destination) { + codegen_call_inner( + fx, + Some(func), + fn_ty, + args, + destination.map(|(place, _)| place), + ); + + if let Some((_, dest)) = destination { + let ret_ebb = fx.get_ebb(dest); + fx.bcx.ins().jump(ret_ebb, &[]); + } else { + fx.bcx.ins().trap(TrapCode::User(!0)); + } } +} + +pub fn codegen_call_inner<'a, 'tcx: 'a>( + fx: &mut FunctionCx<'a, 'tcx, impl Backend>, + func: Option<&Operand<'tcx>>, + fn_ty: Ty<'tcx>, + args: Vec>, + ret_place: Option>, +) { + let sig = ty_fn_sig(fx.tcx, fn_ty); let ret_layout = fx.layout_of(sig.output()); let output_pass_mode = get_pass_mode(fx.tcx, sig.abi, sig.output(), true); let return_ptr = match output_pass_mode { PassMode::NoPass => None, - PassMode::ByRef => match destination { - Some((place, _)) => Some(place.expect_addr()), + PassMode::ByRef => match ret_place { + Some(ret_place) => Some(ret_place.expect_addr()), None => Some(fx.bcx.ins().iconst(fx.module.pointer_type(), 0)), }, PassMode::ByVal(_) => None, @@ -504,7 +527,7 @@ pub fn codegen_call<'a, 'tcx: 'a>( Some(ptr) } else { func_ref = if instance.is_none() { - let func = trans_operand(fx, func); + let func = trans_operand(fx, func.expect("indirect call without func Operand")); Some(func.load_value(fx)) } else { None @@ -534,19 +557,13 @@ pub fn codegen_call<'a, 'tcx: 'a>( match output_pass_mode { PassMode::NoPass => {} PassMode::ByVal(_) => { - if let Some((ret_place, _)) = destination { + if let Some(ret_place) = ret_place { let results = fx.bcx.inst_results(call_inst); ret_place.write_cvalue(fx, CValue::ByVal(results[0], ret_layout)); } } PassMode::ByRef => {} } - if let Some((_, dest)) = destination { - let ret_ebb = fx.get_ebb(dest); - fx.bcx.ins().jump(ret_ebb, &[]); - } else { - fx.bcx.ins().trap(TrapCode::User(!0)); - } } pub fn codegen_return(fx: &mut FunctionCx) { @@ -565,11 +582,12 @@ pub fn codegen_return(fx: &mut FunctionCx) { fn codegen_intrinsic_call<'a, 'tcx: 'a>( fx: &mut FunctionCx<'a, 'tcx, impl Backend>, fn_ty: Ty<'tcx>, - sig: FnSig<'tcx>, args: &[CValue<'tcx>], destination: Option<(CPlace<'tcx>, BasicBlock)>, ) -> bool { if let ty::FnDef(def_id, substs) = fn_ty.sty { + let sig = ty_fn_sig(fx.tcx, fn_ty); + if sig.abi == Abi::RustIntrinsic { let intrinsic = fx.tcx.item_name(def_id).as_str(); let intrinsic = &intrinsic[..]; diff --git a/src/base.rs b/src/base.rs index 0dd7e1382c0b9..e2422fe115788 100644 --- a/src/base.rs +++ b/src/base.rs @@ -224,19 +224,90 @@ fn codegen_fn_content<'a, 'tcx: 'a>(fx: &mut FunctionCx<'a, 'tcx, impl Backend>) destination, cleanup: _, } => { - crate::abi::codegen_call(fx, func, args, destination); + crate::abi::codegen_terminator_call(fx, func, args, destination); } TerminatorKind::Resume | TerminatorKind::Abort | TerminatorKind::Unreachable => { fx.bcx.ins().trap(TrapCode::User(!0)); } TerminatorKind::Yield { .. } | TerminatorKind::FalseEdges { .. } - | TerminatorKind::FalseUnwind { .. } => { + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::DropAndReplace { .. } => { bug!("shouldn't exist at trans {:?}", bb_data.terminator()); } - TerminatorKind::Drop { target, .. } | TerminatorKind::DropAndReplace { target, .. } => { - // TODO call drop impl - // unimplemented!("terminator {:?}", bb_data.terminator()); + TerminatorKind::Drop { + location, + target, + unwind: _, + } => { + let ty = location.ty(fx.mir, fx.tcx).to_ty(fx.tcx); + let ty = fx.monomorphize(&ty); + let drop_fn = ::rustc_mir::monomorphize::resolve_drop_in_place(fx.tcx, ty); + + if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def { + // we don't actually need to drop anything + } else { + let drop_place = trans_place(fx, location); + let arg_place = CPlace::temp( + fx, + fx.tcx.mk_ref( + &ty::RegionKind::ReErased, + TypeAndMut { + ty, + mutbl: ::rustc::hir::Mutability::MutMutable, + }, + ), + ); + drop_place.write_place_ref(fx, arg_place); + match ty.sty { + ty::Dynamic(..) => { + unimplemented!("Drop for trait object"); + } + _ => { + let drop_fn_ty = drop_fn.ty(fx.tcx); + let arg_value = arg_place.to_cvalue(fx); + crate::abi::codegen_call_inner( + fx, + None, + drop_fn_ty, + vec![arg_value], + None, + ); + } + } + /* + let (args1, args2); + /*let mut args = if let Some(llextra) = place.llextra { + args2 = [place.llval, llextra]; + &args2[..] + } else { + args1 = [place.llval]; + &args1[..] + };*/ + let (drop_fn, fn_ty) = match ty.sty { + ty::Dynamic(..) => { + let fn_ty = drop_fn.ty(bx.cx.tcx); + let sig = common::ty_fn_sig(bx.cx, fn_ty); + let sig = bx.tcx().normalize_erasing_late_bound_regions( + ty::ParamEnv::reveal_all(), + &sig, + ); + let fn_ty = FnType::new_vtable(bx.cx, sig, &[]); + let vtable = args[1]; + args = &args[..1]; + (meth::DESTRUCTOR.get_fn(&bx, vtable, &fn_ty), fn_ty) + } + _ => { + let value = place.to_cvalue(fx); + (callee::get_fn(bx.cx, drop_fn), + FnType::of_instance(bx.cx, &drop_fn)) + } + }; + do_call(self, bx, fn_ty, drop_fn, args, + Some((ReturnDest::Nothing, target)), + unwind);*/ + } + let target_ebb = fx.get_ebb(*target); fx.bcx.ins().jump(target_ebb, &[]); }