Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Future-proof the compiler for Box<T, A>. #47043

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/liballoc/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,8 @@ impl<T: ?Sized> Arc<T> {

fn from_box(v: Box<T>) -> Arc<T> {
unsafe {
let bptr = Box::into_raw(v);
let box_unique = Box::into_unique(v);
let bptr = box_unique.as_ptr();

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

// Free the allocation without dropping its contents
box_free(bptr);
box_free(box_unique);

Arc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData }
}
Expand Down
17 changes: 15 additions & 2 deletions src/liballoc/heap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

use core::intrinsics::{min_align_of_val, size_of_val};
use core::mem::{self, ManuallyDrop};
use core::ptr::Unique;
use core::usize;

pub use allocator::*;
Expand Down Expand Up @@ -252,9 +253,21 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
}
}

#[cfg_attr(not(test), lang = "box_free")]
#[cfg(stage0)]
#[lang = "box_free"]
#[inline]
pub(crate) unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
pub(crate) unsafe fn old_box_free<T: ?Sized>(ptr: *mut T) {
box_free(Unique::new_unchecked(ptr))
}

#[cfg_attr(not(any(test, stage0)), lang = "box_free")]
#[inline]
// Invoked by the compiler to deallocate the storage of `Box<T>`,
// after the owned `T` value on the heap has already been dropped.
// NB: the generics should be the same as for `Box`, and the
// argument types should match the fields in `struct Box`.
pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
let ptr = ptr.as_ptr();
let size = size_of_val(&*ptr);
let align = min_align_of_val(&*ptr);
// We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary.
Expand Down
5 changes: 3 additions & 2 deletions src/liballoc/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,8 @@ impl<T: ?Sized> Rc<T> {

fn from_box(v: Box<T>) -> Rc<T> {
unsafe {
let bptr = Box::into_raw(v);
let box_unique = Box::into_unique(v);
let bptr = box_unique.as_ptr();

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

// Free the allocation without dropping its contents
box_free(bptr);
box_free(box_unique);

Rc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData }
}
Expand Down
11 changes: 9 additions & 2 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use middle::lang_items;
use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
use middle::stability;
use mir::{Mir, interpret};
use ty::subst::{Kind, Substs};
use ty::subst::{Kind, Substs, Subst};
use ty::ReprOptions;
use ty::Instance;
use traits;
Expand Down Expand Up @@ -1959,7 +1959,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> {
let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem);
let adt_def = self.adt_def(def_id);
let substs = self.mk_substs(iter::once(Kind::from(ty)));
let substs = Substs::for_item(self, def_id, |_, _| bug!(), |def, substs| {
if def.index == 0 {
ty
} else {
assert!(def.has_default);
self.type_of(def.def_id).subst(self, substs)
}
});
self.mk_ty(TyAdt(adt_def, substs))
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc_const_eval/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -853,7 +853,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
ty::TyAdt(adt, substs) => {
if adt.is_box() {
// Use T as the sub pattern type of Box<T>.
vec![substs[0].as_type().unwrap()]
vec![ty.boxed_ty()]
} else {
adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| {
let is_visible = adt.is_enum()
Expand Down
76 changes: 1 addition & 75 deletions src/librustc_mir/borrow_check/nll/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -892,11 +892,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
));
}

if self.is_box_free(func) {
self.check_box_free_inputs(mir, term, &sig, args, term_location);
} else {
self.check_call_inputs(mir, term, &sig, args, term_location);
}
self.check_call_inputs(mir, term, &sig, args, term_location);
}
TerminatorKind::Assert {
ref cond, ref msg, ..
Expand Down Expand Up @@ -1000,76 +996,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
}
}

fn is_box_free(&self, operand: &Operand<'tcx>) -> bool {
match operand {
&Operand::Constant(box Constant {
literal:
Literal::Value {
value:
&ty::Const {
val: ConstVal::Function(def_id, _),
..
},
..
},
..
}) => Some(def_id) == self.tcx().lang_items().box_free_fn(),
_ => false,
}
}

fn check_box_free_inputs(
&mut self,
mir: &Mir<'tcx>,
term: &Terminator<'tcx>,
sig: &ty::FnSig<'tcx>,
args: &[Operand<'tcx>],
term_location: Location,
) {
debug!("check_box_free_inputs");

// box_free takes a Box as a pointer. Allow for that.

if sig.inputs().len() != 1 {
span_mirbug!(self, term, "box_free should take 1 argument");
return;
}

let pointee_ty = match sig.inputs()[0].sty {
ty::TyRawPtr(mt) => mt.ty,
_ => {
span_mirbug!(self, term, "box_free should take a raw ptr");
return;
}
};

if args.len() != 1 {
span_mirbug!(self, term, "box_free called with wrong # of args");
return;
}

let ty = args[0].ty(mir, self.tcx());
let arg_ty = match ty.sty {
ty::TyRawPtr(mt) => mt.ty,
ty::TyAdt(def, _) if def.is_box() => ty.boxed_ty(),
_ => {
span_mirbug!(self, term, "box_free called with bad arg ty");
return;
}
};

if let Err(terr) = self.sub_types(arg_ty, pointee_ty, term_location.at_self()) {
span_mirbug!(
self,
term,
"bad box_free arg ({:?} <- {:?}): {:?}",
pointee_ty,
arg_ty,
terr
);
}
}

fn check_iscleanup(&mut self, mir: &Mir<'tcx>, block_data: &BasicBlockData<'tcx>) {
let is_cleanup = block_data.is_cleanup;
self.last_span = block_data.terminator().source_info.span;
Expand Down
3 changes: 0 additions & 3 deletions src/librustc_mir/monomorphize/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -823,9 +823,6 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
&ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) => {
ptr_vtable(a, b)
}
(&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) if def_a.is_box() && def_b.is_box() => {
ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty())
}

(&ty::TyAdt(source_adt_def, source_substs),
&ty::TyAdt(target_adt_def, target_substs)) => {
Expand Down
65 changes: 2 additions & 63 deletions src/librustc_mir/transform/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,6 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
TerminatorKind::Call { args, destination: Some(destination), cleanup, .. } => {
debug!("Inlined {:?} into {:?}", callsite.callee, self.source);

let is_box_free = Some(callsite.callee) == self.tcx.lang_items().box_free_fn();

let mut local_map = IndexVec::with_capacity(callee_mir.local_decls.len());
let mut scope_map = IndexVec::with_capacity(callee_mir.visibility_scopes.len());
let mut promoted_map = IndexVec::with_capacity(callee_mir.promoted.len());
Expand Down Expand Up @@ -450,24 +448,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {

let return_block = destination.1;

let args : Vec<_> = if is_box_free {
assert!(args.len() == 1);
// box_free takes a Box, but is defined with a *mut T, inlining
// needs to generate the cast.
// FIXME: we should probably just generate correct MIR in the first place...

let arg = if let Operand::Move(ref place) = args[0] {
place.clone()
} else {
bug!("Constant arg to \"box_free\"");
};

let ptr_ty = args[0].ty(caller_mir, self.tcx);
vec![self.cast_box_free_arg(arg, ptr_ty, &callsite, caller_mir)]
} else {
// Copy the arguments if needed.
self.make_call_args(args, &callsite, caller_mir)
};
// Copy the arguments if needed.
let args: Vec<_> = self.make_call_args(args, &callsite, caller_mir);

let bb_len = caller_mir.basic_blocks().len();
let mut integrator = Integrator {
Expand Down Expand Up @@ -508,49 +490,6 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
}
}

fn cast_box_free_arg(&self, arg: Place<'tcx>, ptr_ty: Ty<'tcx>,
callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>) -> Local {
let arg = Rvalue::Ref(
self.tcx.types.re_erased,
BorrowKind::Mut,
arg.deref());

let ty = arg.ty(caller_mir, self.tcx);
let ref_tmp = LocalDecl::new_temp(ty, callsite.location.span);
let ref_tmp = caller_mir.local_decls.push(ref_tmp);
let ref_tmp = Place::Local(ref_tmp);

let ref_stmt = Statement {
source_info: callsite.location,
kind: StatementKind::Assign(ref_tmp.clone(), arg)
};

caller_mir[callsite.bb]
.statements.push(ref_stmt);

let pointee_ty = match ptr_ty.sty {
ty::TyRawPtr(tm) | ty::TyRef(_, tm) => tm.ty,
_ if ptr_ty.is_box() => ptr_ty.boxed_ty(),
_ => bug!("Invalid type `{:?}` for call to box_free", ptr_ty)
};
let ptr_ty = self.tcx.mk_mut_ptr(pointee_ty);

let raw_ptr = Rvalue::Cast(CastKind::Misc, Operand::Move(ref_tmp), ptr_ty);

let cast_tmp = LocalDecl::new_temp(ptr_ty, callsite.location.span);
let cast_tmp = caller_mir.local_decls.push(cast_tmp);

let cast_stmt = Statement {
source_info: callsite.location,
kind: StatementKind::Assign(Place::Local(cast_tmp), raw_ptr)
};

caller_mir[callsite.bb]
.statements.push(cast_stmt);

cast_tmp
}

fn make_call_args(
&self,
args: Vec<Operand<'tcx>>,
Expand Down
31 changes: 21 additions & 10 deletions src/librustc_mir/util/elaborate_drops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,18 +337,18 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
self.drop_ladder(fields, succ, unwind).0
}

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

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

let succ = self.succ; // FIXME(#6393)
let unwind = self.unwind;
let succ = self.box_free_block(ty, succ, unwind);
let succ = self.box_free_block(box_ty, succ, unwind);
let unwind_succ = self.unwind.map(|unwind| {
self.box_free_block(ty, unwind, Unwind::InCleanup)
self.box_free_block(box_ty, unwind, Unwind::InCleanup)
});

self.drop_subpath(&interior, interior_path, succ, unwind_succ)
Expand Down Expand Up @@ -788,7 +788,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
self.open_drop_for_tuple(tys)
}
ty::TyAdt(def, _) if def.is_box() => {
self.open_drop_for_box(ty.boxed_ty())
self.open_drop_for_box(ty)
}
ty::TyAdt(def, substs) => {
self.open_drop_for_adt(def, substs)
Expand Down Expand Up @@ -854,28 +854,39 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>

fn box_free_block<'a>(
&mut self,
ty: Ty<'tcx>,
box_ty: Ty<'tcx>,
target: BasicBlock,
unwind: Unwind,
) -> BasicBlock {
let block = self.unelaborated_free_block(ty, target, unwind);
let block = self.unelaborated_free_block(box_ty, target, unwind);
self.drop_flag_test_block(block, target, unwind)
}

fn unelaborated_free_block<'a>(
&mut self,
ty: Ty<'tcx>,
box_ty: Ty<'tcx>,
target: BasicBlock,
unwind: Unwind
) -> BasicBlock {
let tcx = self.tcx();
let unit_temp = Place::Local(self.new_temp(tcx.mk_nil()));
let free_func = tcx.require_lang_item(lang_items::BoxFreeFnLangItem);
let substs = tcx.mk_substs(iter::once(Kind::from(ty)));

// Use the generic parameters of `Box` for `box_free`, and the
// fields of `Box` as arguments. Their types should always match.
let (substs, args) = match box_ty.sty {
ty::TyAdt(def, substs) => {
(substs, def.struct_variant().fields.iter().enumerate().map(|(i, f)| {
let box_place = self.place.clone();
Operand::Move(box_place.field(Field::new(i), f.ty(tcx, substs)))
}).collect())
}
_ => bug!("expected Box<T> to be a struct, found `{:?}`", box_ty)
};

let call = TerminatorKind::Call {
func: Operand::function_handle(tcx, free_func, substs, self.source_info.span),
args: vec![Operand::Move(self.place.clone())],
args,
destination: Some((unit_temp, target)),
cleanup: None
}; // FIXME(#6393)
Expand Down
Loading