Skip to content

Commit f2c7917

Browse files
committed
translate drop glue using MIR
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.
1 parent 26df816 commit f2c7917

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+721
-1141
lines changed

src/libcore/intrinsics.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,13 @@
4646
issue = "0")]
4747
#![allow(missing_docs)]
4848

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

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

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

630+
#[cfg(stage0)]
625631
/// Executes the destructor (if any) of the pointed-to value.
626632
///
627633
/// This has two use cases:

src/libcore/ptr.rs

+29
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,38 @@ pub use intrinsics::copy;
3737
#[stable(feature = "rust1", since = "1.0.0")]
3838
pub use intrinsics::write_bytes;
3939

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

44+
#[cfg(not(stage0))]
45+
/// Executes the destructor (if any) of the pointed-to value.
46+
///
47+
/// This has two use cases:
48+
///
49+
/// * It is *required* to use `drop_in_place` to drop unsized types like
50+
/// trait objects, because they can't be read out onto the stack and
51+
/// dropped normally.
52+
///
53+
/// * It is friendlier to the optimizer to do this over `ptr::read` when
54+
/// dropping manually allocated memory (e.g. when writing Box/Rc/Vec),
55+
/// as the compiler doesn't need to prove that it's sound to elide the
56+
/// copy.
57+
///
58+
/// # Undefined Behavior
59+
///
60+
/// This has all the same safety problems as `ptr::read` with respect to
61+
/// invalid pointers, types, and double drops.
62+
#[stable(feature = "drop_in_place", since = "1.8.0")]
63+
#[lang="drop_in_place"]
64+
#[inline]
65+
#[allow(unconditional_recursion)]
66+
pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
67+
// Code here does not matter - this is replaced by the
68+
// real drop glue by the compiler.
69+
drop_in_place(to_drop);
70+
}
71+
4372
/// Creates a null raw pointer.
4473
///
4574
/// # Examples

src/librustc/middle/lang_items.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ language_item_table! {
335335

336336
ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn;
337337
BoxFreeFnLangItem, "box_free", box_free_fn;
338-
StrDupUniqFnLangItem, "strdup_uniq", strdup_uniq_fn;
338+
DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn;
339339

340340
StartFnLangItem, "start", start_fn;
341341

@@ -355,8 +355,6 @@ language_item_table! {
355355
ContravariantLifetimeItem, "contravariant_lifetime", contravariant_lifetime;
356356
InvariantLifetimeItem, "invariant_lifetime", invariant_lifetime;
357357

358-
NoCopyItem, "no_copy_bound", no_copy_bound;
359-
360358
NonZeroItem, "non_zero", non_zero;
361359

362360
DebugTraitLangItem, "debug_trait", debug_trait;

src/librustc/mir/mod.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_data_structures::control_flow_graph::{GraphPredecessors, GraphSuccesso
1717
use rustc_data_structures::control_flow_graph::ControlFlowGraph;
1818
use hir::def::CtorKind;
1919
use hir::def_id::DefId;
20-
use ty::subst::Substs;
20+
use ty::subst::{Subst, Substs};
2121
use ty::{self, AdtDef, ClosureSubsts, Region, Ty};
2222
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
2323
use util::ppaux;
@@ -982,6 +982,22 @@ impl<'tcx> Debug for Operand<'tcx> {
982982
}
983983
}
984984

985+
impl<'tcx> Operand<'tcx> {
986+
pub fn item<'a>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
987+
def_id: DefId,
988+
substs: &'tcx Substs<'tcx>,
989+
span: Span)
990+
-> Self
991+
{
992+
Operand::Constant(Constant {
993+
span: span,
994+
ty: tcx.item_type(def_id).subst(tcx, substs),
995+
literal: Literal::Item { def_id, substs }
996+
})
997+
}
998+
999+
}
1000+
9851001
///////////////////////////////////////////////////////////////////////////
9861002
/// Rvalues
9871003

src/librustc/ty/instance.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ pub enum InstanceDef<'tcx> {
3535
Virtual(DefId, usize),
3636
// <[mut closure] as FnOnce>::call_once
3737
ClosureOnceShim { call_once: DefId },
38+
// drop_in_place::<T>; None for empty drop glue.
39+
DropGlue(DefId, Option<Ty<'tcx>>),
3840
}
3941

4042
impl<'tcx> InstanceDef<'tcx> {
@@ -46,7 +48,8 @@ impl<'tcx> InstanceDef<'tcx> {
4648
InstanceDef::Virtual(def_id, _) |
4749
InstanceDef::Intrinsic(def_id, ) |
4850
InstanceDef::ClosureOnceShim { call_once: def_id }
49-
=> def_id
51+
=> def_id,
52+
InstanceDef::DropGlue(def_id, _) => def_id
5053
}
5154
}
5255

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

@@ -97,6 +101,9 @@ impl<'tcx> fmt::Display for Instance<'tcx> {
97101
InstanceDef::ClosureOnceShim { .. } => {
98102
write!(f, " - shim")
99103
}
104+
InstanceDef::DropGlue(_, ty) => {
105+
write!(f, " - shim({:?})", ty)
106+
}
100107
}
101108
}
102109
}

src/librustc_borrowck/borrowck/mir/gather_moves.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
437437
}
438438
Rvalue::Ref(..) |
439439
Rvalue::Discriminant(..) |
440-
Rvalue::Len(..) => {}
440+
Rvalue::Len(..) |
441441
Rvalue::Box(..) => {
442442
// This returns an rvalue with uninitialized contents. We can't
443443
// move out of it here because it is an rvalue - assignments always

src/librustc_mir/shim.rs

+130-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc::middle::region::ROOT_CODE_EXTENT;
1515
use rustc::mir::*;
1616
use rustc::mir::transform::MirSource;
1717
use rustc::ty::{self, Ty};
18-
use rustc::ty::subst::Subst;
18+
use rustc::ty::subst::{Kind, Subst};
1919
use rustc::ty::maps::Providers;
2020

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

2727
use std::cell::RefCell;
28+
use std::fmt;
2829
use std::iter;
2930
use std::mem;
3031

3132
use transform::{add_call_guards, no_landing_pads, simplify};
33+
use util::elaborate_drops::{self, DropElaborator, DropStyle, DropFlagMode};
34+
use util::patch::MirPatch;
3235

3336
pub fn provide(providers: &mut Providers) {
3437
providers.mir_shims = make_shim;
@@ -101,6 +104,9 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
101104
None
102105
)
103106
}
107+
ty::InstanceDef::DropGlue(def_id, ty) => {
108+
build_drop_shim(tcx, &param_env, def_id, ty)
109+
}
104110
ty::InstanceDef::Intrinsic(_) => {
105111
bug!("creating shims from intrinsics ({:?}) is unsupported", instance)
106112
}
@@ -143,6 +149,129 @@ fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>)
143149
.collect()
144150
}
145151

152+
fn build_drop_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
153+
param_env: &ty::ParameterEnvironment<'tcx>,
154+
def_id: DefId,
155+
ty: Option<Ty<'tcx>>)
156+
-> Mir<'tcx>
157+
{
158+
debug!("build_drop_shim(def_id={:?}, ty={:?})", def_id, ty);
159+
160+
let substs = if let Some(ty) = ty {
161+
tcx.mk_substs(iter::once(Kind::from(ty)))
162+
} else {
163+
param_env.free_substs
164+
};
165+
let fn_ty = tcx.item_type(def_id).subst(tcx, substs);
166+
let sig = tcx.erase_late_bound_regions(&fn_ty.fn_sig());
167+
let span = tcx.def_span(def_id);
168+
169+
let source_info = SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE };
170+
171+
let return_block = BasicBlock::new(1);
172+
let mut blocks = IndexVec::new();
173+
let block = |blocks: &mut IndexVec<_, _>, kind| {
174+
blocks.push(BasicBlockData {
175+
statements: vec![],
176+
terminator: Some(Terminator { source_info, kind }),
177+
is_cleanup: false
178+
})
179+
};
180+
block(&mut blocks, TerminatorKind::Goto { target: return_block });
181+
block(&mut blocks, TerminatorKind::Return);
182+
183+
let mut mir = Mir::new(
184+
blocks,
185+
IndexVec::from_elem_n(
186+
VisibilityScopeData { span: span, parent_scope: None }, 1
187+
),
188+
IndexVec::new(),
189+
sig.output(),
190+
local_decls_for_sig(&sig),
191+
sig.inputs().len(),
192+
vec![],
193+
span
194+
);
195+
196+
if let Some(..) = ty {
197+
let patch = {
198+
let mut elaborator = DropShimElaborator {
199+
mir: &mir,
200+
patch: MirPatch::new(&mir),
201+
tcx, param_env
202+
};
203+
let dropee = Lvalue::Projection(
204+
box Projection {
205+
base: Lvalue::Local(Local::new(1+0)),
206+
elem: ProjectionElem::Deref
207+
}
208+
);
209+
let resume_block = elaborator.patch.resume_block();
210+
elaborate_drops::elaborate_drop(
211+
&mut elaborator,
212+
source_info,
213+
false,
214+
&dropee,
215+
(),
216+
return_block,
217+
Some(resume_block),
218+
START_BLOCK
219+
);
220+
elaborator.patch
221+
};
222+
patch.apply(&mut mir);
223+
}
224+
225+
mir
226+
}
227+
228+
pub struct DropShimElaborator<'a, 'tcx: 'a> {
229+
mir: &'a Mir<'tcx>,
230+
patch: MirPatch<'tcx>,
231+
tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
232+
param_env: &'a ty::ParameterEnvironment<'tcx>,
233+
}
234+
235+
impl<'a, 'tcx> fmt::Debug for DropShimElaborator<'a, 'tcx> {
236+
fn fmt(&self, _f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
237+
Ok(())
238+
}
239+
}
240+
241+
impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
242+
type Path = ();
243+
244+
fn patch(&mut self) -> &mut MirPatch<'tcx> { &mut self.patch }
245+
fn mir(&self) -> &'a Mir<'tcx> { self.mir }
246+
fn tcx(&self) -> ty::TyCtxt<'a, 'tcx, 'tcx> { self.tcx }
247+
fn param_env(&self) -> &'a ty::ParameterEnvironment<'tcx> { self.param_env }
248+
249+
fn drop_style(&self, _path: Self::Path, mode: DropFlagMode) -> DropStyle {
250+
if let DropFlagMode::Shallow = mode {
251+
DropStyle::Static
252+
} else {
253+
DropStyle::Open
254+
}
255+
}
256+
257+
fn get_drop_flag(&mut self, _path: Self::Path) -> Option<Operand<'tcx>> {
258+
None
259+
}
260+
261+
fn clear_drop_flag(&mut self, _location: Location, _path: Self::Path, _mode: DropFlagMode) {
262+
}
263+
264+
fn field_subpath(&self, _path: Self::Path, _field: Field) -> Option<Self::Path> {
265+
None
266+
}
267+
fn deref_subpath(&self, _path: Self::Path) -> Option<Self::Path> {
268+
None
269+
}
270+
fn downcast_subpath(&self, _path: Self::Path, _variant: usize) -> Option<Self::Path> {
271+
Some(())
272+
}
273+
}
274+
146275
/// Build a "call" shim for `def_id`. The shim calls the
147276
/// function specified by `call_kind`, first adjusting its first
148277
/// argument according to `rcvr_adjustment`.
@@ -162,7 +291,6 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
162291
def_id, rcvr_adjustment, call_kind, untuple_args);
163292

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

0 commit comments

Comments
 (0)