Skip to content

Commit 5043534

Browse files
committed
rustc: support arbitrary Box definitions in box_free.
1 parent f63e30a commit 5043534

File tree

6 files changed

+45
-154
lines changed

6 files changed

+45
-154
lines changed

src/liballoc/arc.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,8 @@ impl<T: ?Sized> Arc<T> {
568568

569569
fn from_box(v: Box<T>) -> Arc<T> {
570570
unsafe {
571-
let bptr = Box::into_raw(v);
571+
let box_unique = Box::into_unique(v);
572+
let bptr = box_unique.as_ptr();
572573

573574
let value_size = size_of_val(&*bptr);
574575
let ptr = Self::allocate_for_ptr(bptr);
@@ -580,7 +581,7 @@ impl<T: ?Sized> Arc<T> {
580581
value_size);
581582

582583
// Free the allocation without dropping its contents
583-
box_free(bptr);
584+
box_free(box_unique);
584585

585586
Arc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData }
586587
}

src/liballoc/heap.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
use core::intrinsics::{min_align_of_val, size_of_val};
1919
use core::mem::{self, ManuallyDrop};
20+
use core::ptr::Unique;
2021
use core::usize;
2122

2223
pub use allocator::*;
@@ -252,9 +253,21 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
252253
}
253254
}
254255

255-
#[cfg_attr(not(test), lang = "box_free")]
256+
#[cfg(stage0)]
257+
#[lang = "box_free"]
256258
#[inline]
257-
pub(crate) unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
259+
pub(crate) unsafe fn old_box_free<T: ?Sized>(ptr: *mut T) {
260+
box_free(Unique::new_unchecked(ptr))
261+
}
262+
263+
#[cfg_attr(not(any(test, stage0)), lang = "box_free")]
264+
#[inline]
265+
// Invoked by the compiler to deallocate the storage of `Box<T>`,
266+
// after the owned `T` value on the heap has already been dropped.
267+
// NB: the generics should be the same as for `Box`, and the
268+
// argument types should match the fields in `struct Box`.
269+
pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
270+
let ptr = ptr.as_ptr();
258271
let size = size_of_val(&*ptr);
259272
let align = min_align_of_val(&*ptr);
260273
// We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary.

src/liballoc/rc.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,8 @@ impl<T: ?Sized> Rc<T> {
681681

682682
fn from_box(v: Box<T>) -> Rc<T> {
683683
unsafe {
684-
let bptr = Box::into_raw(v);
684+
let box_unique = Box::into_unique(v);
685+
let bptr = box_unique.as_ptr();
685686

686687
let value_size = size_of_val(&*bptr);
687688
let ptr = Self::allocate_for_ptr(bptr);
@@ -693,7 +694,7 @@ impl<T: ?Sized> Rc<T> {
693694
value_size);
694695

695696
// Free the allocation without dropping its contents
696-
box_free(bptr);
697+
box_free(box_unique);
697698

698699
Rc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData }
699700
}

src/librustc_mir/borrow_check/nll/type_check/mod.rs

+1-75
Original file line numberDiff line numberDiff line change
@@ -892,11 +892,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
892892
));
893893
}
894894

895-
if self.is_box_free(func) {
896-
self.check_box_free_inputs(mir, term, &sig, args, term_location);
897-
} else {
898-
self.check_call_inputs(mir, term, &sig, args, term_location);
899-
}
895+
self.check_call_inputs(mir, term, &sig, args, term_location);
900896
}
901897
TerminatorKind::Assert {
902898
ref cond, ref msg, ..
@@ -1000,76 +996,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
1000996
}
1001997
}
1002998

1003-
fn is_box_free(&self, operand: &Operand<'tcx>) -> bool {
1004-
match operand {
1005-
&Operand::Constant(box Constant {
1006-
literal:
1007-
Literal::Value {
1008-
value:
1009-
&ty::Const {
1010-
val: ConstVal::Function(def_id, _),
1011-
..
1012-
},
1013-
..
1014-
},
1015-
..
1016-
}) => Some(def_id) == self.tcx().lang_items().box_free_fn(),
1017-
_ => false,
1018-
}
1019-
}
1020-
1021-
fn check_box_free_inputs(
1022-
&mut self,
1023-
mir: &Mir<'tcx>,
1024-
term: &Terminator<'tcx>,
1025-
sig: &ty::FnSig<'tcx>,
1026-
args: &[Operand<'tcx>],
1027-
term_location: Location,
1028-
) {
1029-
debug!("check_box_free_inputs");
1030-
1031-
// box_free takes a Box as a pointer. Allow for that.
1032-
1033-
if sig.inputs().len() != 1 {
1034-
span_mirbug!(self, term, "box_free should take 1 argument");
1035-
return;
1036-
}
1037-
1038-
let pointee_ty = match sig.inputs()[0].sty {
1039-
ty::TyRawPtr(mt) => mt.ty,
1040-
_ => {
1041-
span_mirbug!(self, term, "box_free should take a raw ptr");
1042-
return;
1043-
}
1044-
};
1045-
1046-
if args.len() != 1 {
1047-
span_mirbug!(self, term, "box_free called with wrong # of args");
1048-
return;
1049-
}
1050-
1051-
let ty = args[0].ty(mir, self.tcx());
1052-
let arg_ty = match ty.sty {
1053-
ty::TyRawPtr(mt) => mt.ty,
1054-
ty::TyAdt(def, _) if def.is_box() => ty.boxed_ty(),
1055-
_ => {
1056-
span_mirbug!(self, term, "box_free called with bad arg ty");
1057-
return;
1058-
}
1059-
};
1060-
1061-
if let Err(terr) = self.sub_types(arg_ty, pointee_ty, term_location.at_self()) {
1062-
span_mirbug!(
1063-
self,
1064-
term,
1065-
"bad box_free arg ({:?} <- {:?}): {:?}",
1066-
pointee_ty,
1067-
arg_ty,
1068-
terr
1069-
);
1070-
}
1071-
}
1072-
1073999
fn check_iscleanup(&mut self, mir: &Mir<'tcx>, block_data: &BasicBlockData<'tcx>) {
10741000
let is_cleanup = block_data.is_cleanup;
10751001
self.last_span = block_data.terminator().source_info.span;

src/librustc_mir/transform/inline.rs

+2-63
Original file line numberDiff line numberDiff line change
@@ -369,8 +369,6 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
369369
TerminatorKind::Call { args, destination: Some(destination), cleanup, .. } => {
370370
debug!("Inlined {:?} into {:?}", callsite.callee, self.source);
371371

372-
let is_box_free = Some(callsite.callee) == self.tcx.lang_items().box_free_fn();
373-
374372
let mut local_map = IndexVec::with_capacity(callee_mir.local_decls.len());
375373
let mut scope_map = IndexVec::with_capacity(callee_mir.visibility_scopes.len());
376374
let mut promoted_map = IndexVec::with_capacity(callee_mir.promoted.len());
@@ -450,24 +448,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
450448

451449
let return_block = destination.1;
452450

453-
let args : Vec<_> = if is_box_free {
454-
assert!(args.len() == 1);
455-
// box_free takes a Box, but is defined with a *mut T, inlining
456-
// needs to generate the cast.
457-
// FIXME: we should probably just generate correct MIR in the first place...
458-
459-
let arg = if let Operand::Move(ref place) = args[0] {
460-
place.clone()
461-
} else {
462-
bug!("Constant arg to \"box_free\"");
463-
};
464-
465-
let ptr_ty = args[0].ty(caller_mir, self.tcx);
466-
vec![self.cast_box_free_arg(arg, ptr_ty, &callsite, caller_mir)]
467-
} else {
468-
// Copy the arguments if needed.
469-
self.make_call_args(args, &callsite, caller_mir)
470-
};
451+
// Copy the arguments if needed.
452+
let args: Vec<_> = self.make_call_args(args, &callsite, caller_mir);
471453

472454
let bb_len = caller_mir.basic_blocks().len();
473455
let mut integrator = Integrator {
@@ -508,49 +490,6 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
508490
}
509491
}
510492

511-
fn cast_box_free_arg(&self, arg: Place<'tcx>, ptr_ty: Ty<'tcx>,
512-
callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>) -> Local {
513-
let arg = Rvalue::Ref(
514-
self.tcx.types.re_erased,
515-
BorrowKind::Mut,
516-
arg.deref());
517-
518-
let ty = arg.ty(caller_mir, self.tcx);
519-
let ref_tmp = LocalDecl::new_temp(ty, callsite.location.span);
520-
let ref_tmp = caller_mir.local_decls.push(ref_tmp);
521-
let ref_tmp = Place::Local(ref_tmp);
522-
523-
let ref_stmt = Statement {
524-
source_info: callsite.location,
525-
kind: StatementKind::Assign(ref_tmp.clone(), arg)
526-
};
527-
528-
caller_mir[callsite.bb]
529-
.statements.push(ref_stmt);
530-
531-
let pointee_ty = match ptr_ty.sty {
532-
ty::TyRawPtr(tm) | ty::TyRef(_, tm) => tm.ty,
533-
_ if ptr_ty.is_box() => ptr_ty.boxed_ty(),
534-
_ => bug!("Invalid type `{:?}` for call to box_free", ptr_ty)
535-
};
536-
let ptr_ty = self.tcx.mk_mut_ptr(pointee_ty);
537-
538-
let raw_ptr = Rvalue::Cast(CastKind::Misc, Operand::Move(ref_tmp), ptr_ty);
539-
540-
let cast_tmp = LocalDecl::new_temp(ptr_ty, callsite.location.span);
541-
let cast_tmp = caller_mir.local_decls.push(cast_tmp);
542-
543-
let cast_stmt = Statement {
544-
source_info: callsite.location,
545-
kind: StatementKind::Assign(Place::Local(cast_tmp), raw_ptr)
546-
};
547-
548-
caller_mir[callsite.bb]
549-
.statements.push(cast_stmt);
550-
551-
cast_tmp
552-
}
553-
554493
fn make_call_args(
555494
&self,
556495
args: Vec<Operand<'tcx>>,

src/librustc_mir/util/elaborate_drops.rs

+21-10
Original file line numberDiff line numberDiff line change
@@ -337,18 +337,18 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
337337
self.drop_ladder(fields, succ, unwind).0
338338
}
339339

340-
fn open_drop_for_box<'a>(&mut self, ty: Ty<'tcx>) -> BasicBlock
340+
fn open_drop_for_box<'a>(&mut self, box_ty: Ty<'tcx>) -> BasicBlock
341341
{
342-
debug!("open_drop_for_box({:?}, {:?})", self, ty);
342+
debug!("open_drop_for_box({:?}, {:?})", self, box_ty);
343343

344344
let interior = self.place.clone().deref();
345345
let interior_path = self.elaborator.deref_subpath(self.path);
346346

347347
let succ = self.succ; // FIXME(#6393)
348348
let unwind = self.unwind;
349-
let succ = self.box_free_block(ty, succ, unwind);
349+
let succ = self.box_free_block(box_ty, succ, unwind);
350350
let unwind_succ = self.unwind.map(|unwind| {
351-
self.box_free_block(ty, unwind, Unwind::InCleanup)
351+
self.box_free_block(box_ty, unwind, Unwind::InCleanup)
352352
});
353353

354354
self.drop_subpath(&interior, interior_path, succ, unwind_succ)
@@ -788,7 +788,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
788788
self.open_drop_for_tuple(tys)
789789
}
790790
ty::TyAdt(def, _) if def.is_box() => {
791-
self.open_drop_for_box(ty.boxed_ty())
791+
self.open_drop_for_box(ty)
792792
}
793793
ty::TyAdt(def, substs) => {
794794
self.open_drop_for_adt(def, substs)
@@ -854,28 +854,39 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
854854

855855
fn box_free_block<'a>(
856856
&mut self,
857-
ty: Ty<'tcx>,
857+
box_ty: Ty<'tcx>,
858858
target: BasicBlock,
859859
unwind: Unwind,
860860
) -> BasicBlock {
861-
let block = self.unelaborated_free_block(ty, target, unwind);
861+
let block = self.unelaborated_free_block(box_ty, target, unwind);
862862
self.drop_flag_test_block(block, target, unwind)
863863
}
864864

865865
fn unelaborated_free_block<'a>(
866866
&mut self,
867-
ty: Ty<'tcx>,
867+
box_ty: Ty<'tcx>,
868868
target: BasicBlock,
869869
unwind: Unwind
870870
) -> BasicBlock {
871871
let tcx = self.tcx();
872872
let unit_temp = Place::Local(self.new_temp(tcx.mk_nil()));
873873
let free_func = tcx.require_lang_item(lang_items::BoxFreeFnLangItem);
874-
let substs = tcx.mk_substs(iter::once(Kind::from(ty)));
874+
875+
// Use the generic parameters of `Box` for `box_free`, and the
876+
// fields of `Box` as arguments. Their types should always match.
877+
let (substs, args) = match box_ty.sty {
878+
ty::TyAdt(def, substs) => {
879+
(substs, def.struct_variant().fields.iter().enumerate().map(|(i, f)| {
880+
let box_place = self.place.clone();
881+
Operand::Move(box_place.field(Field::new(i), f.ty(tcx, substs)))
882+
}).collect())
883+
}
884+
_ => bug!("expected Box<T> to be a struct, found `{:?}`", box_ty)
885+
};
875886

876887
let call = TerminatorKind::Call {
877888
func: Operand::function_handle(tcx, free_func, substs, self.source_info.span),
878-
args: vec![Operand::Move(self.place.clone())],
889+
args,
879890
destination: Some((unit_temp, target)),
880891
cleanup: None
881892
}; // FIXME(#6393)

0 commit comments

Comments
 (0)