diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 6b48c6ae26dac..3073b1dbfaeeb 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -296,6 +296,7 @@ fn trans_custom_dtor<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, sized_args = [v0]; &sized_args } else { + // FIXME(#36457) -- we should pass unsized values to drop glue as two arguments unsized_args = [ Load(bcx, get_dataptr(bcx, v0)), Load(bcx, get_meta(bcx, v0)) @@ -440,7 +441,9 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>, } } -fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueKind<'tcx>) +fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + v0: ValueRef, + g: DropGlueKind<'tcx>) -> Block<'blk, 'tcx> { let t = g.ty(); @@ -463,6 +466,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK let llval = get_dataptr(bcx, v0); let llbox = Load(bcx, llval); let bcx = drop_ty(bcx, v0, content_ty, DebugLoc::None); + // FIXME(#36457) -- we should pass unsized values to drop glue as two arguments let info = get_meta(bcx, v0); let info = Load(bcx, info); let (llsize, llalign) = @@ -488,6 +492,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK // No support in vtable for distinguishing destroying with // versus without calling Drop::drop. Assert caller is // okay with always calling the Drop impl, if any. + // FIXME(#36457) -- we should pass unsized values to drop glue as two arguments assert!(!skip_dtor); let data_ptr = get_dataptr(bcx, v0); let vtable_ptr = Load(bcx, get_meta(bcx, v0)); @@ -543,6 +548,7 @@ fn drop_structural_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, let value = if type_is_sized(cx.tcx(), t) { adt::MaybeSizedValue::sized(av) } else { + // FIXME(#36457) -- we should pass unsized values as two arguments let data = Load(cx, get_dataptr(cx, av)); let info = Load(cx, get_meta(cx, av)); adt::MaybeSizedValue::unsized_(data, info) @@ -586,6 +592,7 @@ fn drop_structural_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, let val = if type_is_sized(cx.tcx(), field_ty) { llfld_a } else { + // FIXME(#36457) -- we should pass unsized values as two arguments let scratch = alloc_ty(cx, field_ty, "__fat_ptr_iter"); Store(cx, llfld_a, get_dataptr(cx, scratch)); Store(cx, value.meta, get_meta(cx, scratch)); diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 2049696ee4f71..fbade107ecfda 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -186,6 +186,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let ptr = if is_sized { llargs[0] } else { + // FIXME(#36457) -- we should pass unsized values as two arguments let scratch = alloc_ty(bcx, tp_ty, "drop"); call_lifetime_start(bcx, scratch); Store(bcx, llargs[0], get_dataptr(bcx, scratch)); diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index fbd04d7b38029..baeafbe3e346f 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -242,10 +242,28 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let lvalue = self.trans_lvalue(&bcx, location); let drop_fn = glue::get_drop_glue(bcx.ccx(), ty); let drop_ty = glue::get_drop_glue_type(bcx.tcx(), ty); - let llvalue = if drop_ty != ty { - bcx.pointercast(lvalue.llval, type_of::type_of(bcx.ccx(), drop_ty).ptr_to()) + let is_sized = common::type_is_sized(bcx.tcx(), ty); + let llvalue = if is_sized { + if drop_ty != ty { + bcx.pointercast(lvalue.llval, type_of::type_of(bcx.ccx(), drop_ty).ptr_to()) + } else { + lvalue.llval + } } else { - lvalue.llval + // FIXME(#36457) Currently drop glue takes sized + // values as a `*(data, meta)`, but elsewhere in + // MIR we pass `(data, meta)` as two separate + // arguments. It would be better to fix drop glue, + // but I am shooting for a quick fix to #35546 + // here that can be cleanly backported to beta, so + // I want to avoid touching all of trans. + bcx.with_block(|bcx| { + let scratch = base::alloc_ty(bcx, ty, "drop"); + base::call_lifetime_start(bcx, scratch); + build::Store(bcx, lvalue.llval, base::get_dataptr(bcx, scratch)); + build::Store(bcx, lvalue.llextra, base::get_meta(bcx, scratch)); + scratch + }) }; if let Some(unwind) = unwind { bcx.invoke(drop_fn, diff --git a/src/test/run-pass/issue-35546.rs b/src/test/run-pass/issue-35546.rs new file mode 100644 index 0000000000000..e8d14f1d42146 --- /dev/null +++ b/src/test/run-pass/issue-35546.rs @@ -0,0 +1,28 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for #35546. Check that we are able to codegen +// this. Before we had problems because of the drop glue signature +// around dropping a trait object (specifically, when dropping the +// `value` field of `Node`). + +struct Node { + next: Option>>, + value: T, +} + +fn clear(head: &mut Option>>) { + match head.take() { + Some(node) => *head = node.next, + None => (), + } +} + +fn main() {}