Skip to content

Commit

Permalink
translate drop glue using MIR
Browse files Browse the repository at this point in the history
Drop of arrays is now translated in trans::block in an ugly way that I
should clean up in a later PR, and does not handle panics in the middle
of an array drop, but this commit & PR are growing too big.
  • Loading branch information
arielb1 committed Mar 18, 2017
1 parent 26df816 commit f2c7917
Show file tree
Hide file tree
Showing 53 changed files with 721 additions and 1,141 deletions.
8 changes: 7 additions & 1 deletion src/libcore/intrinsics.rs
Expand Up @@ -46,8 +46,13 @@
issue = "0")]
#![allow(missing_docs)]

extern "rust-intrinsic" {
#[cfg(not(stage0))]
#[stable(feature = "drop_in_place", since = "1.8.0")]
#[rustc_deprecated(reason = "no longer an intrinsic - use `ptr::drop_in_place` directly",
since = "1.18.0")]
pub use ptr::drop_in_place;

extern "rust-intrinsic" {
// NB: These intrinsics take raw pointers because they mutate aliased
// memory, which is not valid for either `&` or `&mut`.

Expand Down Expand Up @@ -622,6 +627,7 @@ extern "rust-intrinsic" {
pub fn size_of_val<T: ?Sized>(_: &T) -> usize;
pub fn min_align_of_val<T: ?Sized>(_: &T) -> usize;

#[cfg(stage0)]
/// Executes the destructor (if any) of the pointed-to value.
///
/// This has two use cases:
Expand Down
29 changes: 29 additions & 0 deletions src/libcore/ptr.rs
Expand Up @@ -37,9 +37,38 @@ pub use intrinsics::copy;
#[stable(feature = "rust1", since = "1.0.0")]
pub use intrinsics::write_bytes;

#[cfg(stage0)]
#[stable(feature = "drop_in_place", since = "1.8.0")]
pub use intrinsics::drop_in_place;

#[cfg(not(stage0))]
/// Executes the destructor (if any) of the pointed-to value.
///
/// This has two use cases:
///
/// * It is *required* to use `drop_in_place` to drop unsized types like
/// trait objects, because they can't be read out onto the stack and
/// dropped normally.
///
/// * It is friendlier to the optimizer to do this over `ptr::read` when
/// dropping manually allocated memory (e.g. when writing Box/Rc/Vec),
/// as the compiler doesn't need to prove that it's sound to elide the
/// copy.
///
/// # Undefined Behavior
///
/// This has all the same safety problems as `ptr::read` with respect to
/// invalid pointers, types, and double drops.
#[stable(feature = "drop_in_place", since = "1.8.0")]
#[lang="drop_in_place"]
#[inline]
#[allow(unconditional_recursion)]
pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
// Code here does not matter - this is replaced by the
// real drop glue by the compiler.
drop_in_place(to_drop);
}

/// Creates a null raw pointer.
///
/// # Examples
Expand Down
4 changes: 1 addition & 3 deletions src/librustc/middle/lang_items.rs
Expand Up @@ -335,7 +335,7 @@ language_item_table! {

ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn;
BoxFreeFnLangItem, "box_free", box_free_fn;
StrDupUniqFnLangItem, "strdup_uniq", strdup_uniq_fn;
DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn;

StartFnLangItem, "start", start_fn;

Expand All @@ -355,8 +355,6 @@ language_item_table! {
ContravariantLifetimeItem, "contravariant_lifetime", contravariant_lifetime;
InvariantLifetimeItem, "invariant_lifetime", invariant_lifetime;

NoCopyItem, "no_copy_bound", no_copy_bound;

NonZeroItem, "non_zero", non_zero;

DebugTraitLangItem, "debug_trait", debug_trait;
Expand Down
18 changes: 17 additions & 1 deletion src/librustc/mir/mod.rs
Expand Up @@ -17,7 +17,7 @@ use rustc_data_structures::control_flow_graph::{GraphPredecessors, GraphSuccesso
use rustc_data_structures::control_flow_graph::ControlFlowGraph;
use hir::def::CtorKind;
use hir::def_id::DefId;
use ty::subst::Substs;
use ty::subst::{Subst, Substs};
use ty::{self, AdtDef, ClosureSubsts, Region, Ty};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use util::ppaux;
Expand Down Expand Up @@ -982,6 +982,22 @@ impl<'tcx> Debug for Operand<'tcx> {
}
}

impl<'tcx> Operand<'tcx> {
pub fn item<'a>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
substs: &'tcx Substs<'tcx>,
span: Span)
-> Self
{
Operand::Constant(Constant {
span: span,
ty: tcx.item_type(def_id).subst(tcx, substs),
literal: Literal::Item { def_id, substs }
})
}

}

///////////////////////////////////////////////////////////////////////////
/// Rvalues

Expand Down
9 changes: 8 additions & 1 deletion src/librustc/ty/instance.rs
Expand Up @@ -35,6 +35,8 @@ pub enum InstanceDef<'tcx> {
Virtual(DefId, usize),
// <[mut closure] as FnOnce>::call_once
ClosureOnceShim { call_once: DefId },
// drop_in_place::<T>; None for empty drop glue.
DropGlue(DefId, Option<Ty<'tcx>>),
}

impl<'tcx> InstanceDef<'tcx> {
Expand All @@ -46,7 +48,8 @@ impl<'tcx> InstanceDef<'tcx> {
InstanceDef::Virtual(def_id, _) |
InstanceDef::Intrinsic(def_id, ) |
InstanceDef::ClosureOnceShim { call_once: def_id }
=> def_id
=> def_id,
InstanceDef::DropGlue(def_id, _) => def_id
}
}

Expand All @@ -65,6 +68,7 @@ impl<'tcx> InstanceDef<'tcx> {
// real on-demand.
let ty = match self {
&InstanceDef::FnPtrShim(_, ty) => Some(ty),
&InstanceDef::DropGlue(_, ty) => ty,
_ => None
}.into_iter();

Expand Down Expand Up @@ -97,6 +101,9 @@ impl<'tcx> fmt::Display for Instance<'tcx> {
InstanceDef::ClosureOnceShim { .. } => {
write!(f, " - shim")
}
InstanceDef::DropGlue(_, ty) => {
write!(f, " - shim({:?})", ty)
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_borrowck/borrowck/mir/gather_moves.rs
Expand Up @@ -437,7 +437,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
}
Rvalue::Ref(..) |
Rvalue::Discriminant(..) |
Rvalue::Len(..) => {}
Rvalue::Len(..) |
Rvalue::Box(..) => {
// This returns an rvalue with uninitialized contents. We can't
// move out of it here because it is an rvalue - assignments always
Expand Down
132 changes: 130 additions & 2 deletions src/librustc_mir/shim.rs
Expand Up @@ -15,7 +15,7 @@ use rustc::middle::region::ROOT_CODE_EXTENT;
use rustc::mir::*;
use rustc::mir::transform::MirSource;
use rustc::ty::{self, Ty};
use rustc::ty::subst::Subst;
use rustc::ty::subst::{Kind, Subst};
use rustc::ty::maps::Providers;

use rustc_data_structures::indexed_vec::{IndexVec, Idx};
Expand All @@ -25,10 +25,13 @@ use syntax::ast;
use syntax_pos::Span;

use std::cell::RefCell;
use std::fmt;
use std::iter;
use std::mem;

use transform::{add_call_guards, no_landing_pads, simplify};
use util::elaborate_drops::{self, DropElaborator, DropStyle, DropFlagMode};
use util::patch::MirPatch;

pub fn provide(providers: &mut Providers) {
providers.mir_shims = make_shim;
Expand Down Expand Up @@ -101,6 +104,9 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
None
)
}
ty::InstanceDef::DropGlue(def_id, ty) => {
build_drop_shim(tcx, &param_env, def_id, ty)
}
ty::InstanceDef::Intrinsic(_) => {
bug!("creating shims from intrinsics ({:?}) is unsupported", instance)
}
Expand Down Expand Up @@ -143,6 +149,129 @@ fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>)
.collect()
}

fn build_drop_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
param_env: &ty::ParameterEnvironment<'tcx>,
def_id: DefId,
ty: Option<Ty<'tcx>>)
-> Mir<'tcx>
{
debug!("build_drop_shim(def_id={:?}, ty={:?})", def_id, ty);

let substs = if let Some(ty) = ty {
tcx.mk_substs(iter::once(Kind::from(ty)))
} else {
param_env.free_substs
};
let fn_ty = tcx.item_type(def_id).subst(tcx, substs);
let sig = tcx.erase_late_bound_regions(&fn_ty.fn_sig());
let span = tcx.def_span(def_id);

let source_info = SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE };

let return_block = BasicBlock::new(1);
let mut blocks = IndexVec::new();
let block = |blocks: &mut IndexVec<_, _>, kind| {
blocks.push(BasicBlockData {
statements: vec![],
terminator: Some(Terminator { source_info, kind }),
is_cleanup: false
})
};
block(&mut blocks, TerminatorKind::Goto { target: return_block });
block(&mut blocks, TerminatorKind::Return);

let mut mir = Mir::new(
blocks,
IndexVec::from_elem_n(
VisibilityScopeData { span: span, parent_scope: None }, 1
),
IndexVec::new(),
sig.output(),
local_decls_for_sig(&sig),
sig.inputs().len(),
vec![],
span
);

if let Some(..) = ty {
let patch = {
let mut elaborator = DropShimElaborator {
mir: &mir,
patch: MirPatch::new(&mir),
tcx, param_env
};
let dropee = Lvalue::Projection(
box Projection {
base: Lvalue::Local(Local::new(1+0)),
elem: ProjectionElem::Deref
}
);
let resume_block = elaborator.patch.resume_block();
elaborate_drops::elaborate_drop(
&mut elaborator,
source_info,
false,
&dropee,
(),
return_block,
Some(resume_block),
START_BLOCK
);
elaborator.patch
};
patch.apply(&mut mir);
}

mir
}

pub struct DropShimElaborator<'a, 'tcx: 'a> {
mir: &'a Mir<'tcx>,
patch: MirPatch<'tcx>,
tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
param_env: &'a ty::ParameterEnvironment<'tcx>,
}

impl<'a, 'tcx> fmt::Debug for DropShimElaborator<'a, 'tcx> {
fn fmt(&self, _f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
Ok(())
}
}

impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
type Path = ();

fn patch(&mut self) -> &mut MirPatch<'tcx> { &mut self.patch }
fn mir(&self) -> &'a Mir<'tcx> { self.mir }
fn tcx(&self) -> ty::TyCtxt<'a, 'tcx, 'tcx> { self.tcx }
fn param_env(&self) -> &'a ty::ParameterEnvironment<'tcx> { self.param_env }

fn drop_style(&self, _path: Self::Path, mode: DropFlagMode) -> DropStyle {
if let DropFlagMode::Shallow = mode {
DropStyle::Static
} else {
DropStyle::Open
}
}

fn get_drop_flag(&mut self, _path: Self::Path) -> Option<Operand<'tcx>> {
None
}

fn clear_drop_flag(&mut self, _location: Location, _path: Self::Path, _mode: DropFlagMode) {
}

fn field_subpath(&self, _path: Self::Path, _field: Field) -> Option<Self::Path> {
None
}
fn deref_subpath(&self, _path: Self::Path) -> Option<Self::Path> {
None
}
fn downcast_subpath(&self, _path: Self::Path, _variant: usize) -> Option<Self::Path> {
Some(())
}
}

/// Build a "call" shim for `def_id`. The shim calls the
/// function specified by `call_kind`, first adjusting its first
/// argument according to `rcvr_adjustment`.
Expand All @@ -162,7 +291,6 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
def_id, rcvr_adjustment, call_kind, untuple_args);

let fn_ty = tcx.item_type(def_id).subst(tcx, param_env.free_substs);
// Not normalizing here without a param env.
let sig = tcx.erase_late_bound_regions(&fn_ty.fn_sig());
let span = tcx.def_span(def_id);

Expand Down

0 comments on commit f2c7917

Please sign in to comment.