Implement drop support (fixes #11)
This commit is contained in:
parent
770461f57d
commit
59518987ed
4 changed files with 142 additions and 20 deletions
|
@ -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() -> !;
|
||||
|
|
|
@ -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<T: Termination + 'static>(
|
||||
main: fn() -> T,
|
||||
|
@ -91,4 +114,9 @@ fn main() {
|
|||
panic(&("", "", 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
let _ = NoisyDrop {
|
||||
text: "Outer got dropped!\0",
|
||||
inner: NoisyDropInner,
|
||||
};
|
||||
}
|
||||
|
|
48
src/abi.rs
48
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));
|
||||
.map(|&(ref place, bb)| (trans_place(fx, place), bb));
|
||||
|
||||
if codegen_intrinsic_call(fx, fn_ty, sig, &args, destination) {
|
||||
return;
|
||||
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<CValue<'tcx>>,
|
||||
ret_place: Option<CPlace<'tcx>>,
|
||||
) {
|
||||
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<impl Backend>) {
|
||||
|
@ -565,11 +582,12 @@ pub fn codegen_return(fx: &mut FunctionCx<impl Backend>) {
|
|||
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[..];
|
||||
|
|
81
src/base.rs
81
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, &[]);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue