Skip to content

Commit 4adb9a8

Browse files
authored
Rollup merge of #72283 - jonas-schievink:elaborate-drop-elaboration, r=cramertj
Drop Elaboration Elaboration As in, adding more documentation to it.
2 parents c6030c9 + 1e4b663 commit 4adb9a8

File tree

2 files changed

+99
-9
lines changed

2 files changed

+99
-9
lines changed

src/librustc_mir/shim.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,18 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
277277
}
278278

279279
fn drop_style(&self, _path: Self::Path, mode: DropFlagMode) -> DropStyle {
280-
if let DropFlagMode::Shallow = mode { DropStyle::Static } else { DropStyle::Open }
280+
match mode {
281+
DropFlagMode::Shallow => {
282+
// Drops for the contained fields are "shallow" and "static" - they will simply call
283+
// the field's own drop glue.
284+
DropStyle::Static
285+
}
286+
DropFlagMode::Deep => {
287+
// The top-level drop is "deep" and "open" - it will be elaborated to a drop ladder
288+
// dropping each field contained in the value.
289+
DropStyle::Open
290+
}
291+
}
281292
}
282293

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

src/librustc_mir/util/elaborate_drops.rs

+87-8
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,15 @@ use std::fmt;
1212

1313
use std::convert::TryInto;
1414

15+
/// The value of an inserted drop flag.
1516
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
1617
pub enum DropFlagState {
17-
Present, // i.e., initialized
18-
Absent, // i.e., deinitialized or "moved"
18+
/// The tracked value is initialized and needs to be dropped when leaving its scope.
19+
Present,
20+
21+
/// The tracked value is uninitialized or was moved out of and does not need to be dropped when
22+
/// leaving its scope.
23+
Absent,
1924
}
2025

2126
impl DropFlagState {
@@ -27,23 +32,42 @@ impl DropFlagState {
2732
}
2833
}
2934

35+
/// Describes how/if a value should be dropped.
3036
#[derive(Debug)]
3137
pub enum DropStyle {
38+
/// The value is already dead at the drop location, no drop will be executed.
3239
Dead,
40+
41+
/// The value is known to always be initialized at the drop location, drop will always be
42+
/// executed.
3343
Static,
44+
45+
/// Whether the value needs to be dropped depends on its drop flag.
3446
Conditional,
47+
48+
/// An "open" drop is one where only the fields of a value are dropped.
49+
///
50+
/// For example, this happens when moving out of a struct field: The rest of the struct will be
51+
/// dropped in such an "open" drop. It is also used to generate drop glue for the individual
52+
/// components of a value, for example for dropping array elements.
3553
Open,
3654
}
3755

56+
/// Which drop flags to affect/check with an operation.
3857
#[derive(Debug)]
3958
pub enum DropFlagMode {
59+
/// Only affect the top-level drop flag, not that of any contained fields.
4060
Shallow,
61+
/// Affect all nested drop flags in addition to the top-level one.
4162
Deep,
4263
}
4364

65+
/// Describes if unwinding is necessary and where to unwind to if a panic occurs.
4466
#[derive(Copy, Clone, Debug)]
4567
pub enum Unwind {
68+
/// Unwind to this block.
4669
To(BasicBlock),
70+
/// Already in an unwind path, any panic will cause an abort.
4771
InCleanup,
4872
}
4973

@@ -74,20 +98,58 @@ impl Unwind {
7498
}
7599

76100
pub trait DropElaborator<'a, 'tcx>: fmt::Debug {
101+
/// The type representing paths that can be moved out of.
102+
///
103+
/// Users can move out of individual fields of a struct, such as `a.b.c`. This type is used to
104+
/// represent such move paths. Sometimes tracking individual move paths is not necessary, in
105+
/// which case this may be set to (for example) `()`.
77106
type Path: Copy + fmt::Debug;
78107

108+
// Accessors
109+
79110
fn patch(&mut self) -> &mut MirPatch<'tcx>;
80111
fn body(&self) -> &'a Body<'tcx>;
81112
fn tcx(&self) -> TyCtxt<'tcx>;
82113
fn param_env(&self) -> ty::ParamEnv<'tcx>;
83114

115+
// Drop logic
116+
117+
/// Returns how `path` should be dropped, given `mode`.
84118
fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle;
119+
120+
/// Returns the drop flag of `path` as a MIR `Operand` (or `None` if `path` has no drop flag).
85121
fn get_drop_flag(&mut self, path: Self::Path) -> Option<Operand<'tcx>>;
122+
123+
/// Modifies the MIR patch so that the drop flag of `path` (if any) is cleared at `location`.
124+
///
125+
/// If `mode` is deep, drop flags of all child paths should also be cleared by inserting
126+
/// additional statements.
86127
fn clear_drop_flag(&mut self, location: Location, path: Self::Path, mode: DropFlagMode);
87128

129+
// Subpaths
130+
131+
/// Returns the subpath of a field of `path` (or `None` if there is no dedicated subpath).
132+
///
133+
/// If this returns `None`, `field` will not get a dedicated drop flag.
88134
fn field_subpath(&self, path: Self::Path, field: Field) -> Option<Self::Path>;
135+
136+
/// Returns the subpath of a dereference of `path` (or `None` if there is no dedicated subpath).
137+
///
138+
/// If this returns `None`, `*path` will not get a dedicated drop flag.
139+
///
140+
/// This is only relevant for `Box<T>`, where the contained `T` can be moved out of the box.
89141
fn deref_subpath(&self, path: Self::Path) -> Option<Self::Path>;
142+
143+
/// Returns the subpath of downcasting `path` to one of its variants.
144+
///
145+
/// If this returns `None`, the downcast of `path` will not get a dedicated drop flag.
90146
fn downcast_subpath(&self, path: Self::Path, variant: VariantIdx) -> Option<Self::Path>;
147+
148+
/// Returns the subpath of indexing a fixed-size array `path`.
149+
///
150+
/// If this returns `None`, elements of `path` will not get a dedicated drop flag.
151+
///
152+
/// This is only relevant for array patterns, which can move out of individual array elements.
91153
fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option<Self::Path>;
92154
}
93155

@@ -106,6 +168,14 @@ where
106168
unwind: Unwind,
107169
}
108170

171+
/// "Elaborates" a drop of `place`/`path` and patches `bb`'s terminator to execute it.
172+
///
173+
/// The passed `elaborator` is used to determine what should happen at the drop terminator. It
174+
/// decides whether the drop can be statically determined or whether it needs a dynamic drop flag,
175+
/// and whether the drop is "open", ie. should be expanded to drop all subfields of the dropped
176+
/// value.
177+
///
178+
/// When this returns, the MIR patch in the `elaborator` contains the necessary changes.
109179
pub fn elaborate_drop<'b, 'tcx, D>(
110180
elaborator: &mut D,
111181
source_info: SourceInfo,
@@ -346,9 +416,7 @@ where
346416
let interior = self.tcx().mk_place_deref(self.place);
347417
let interior_path = self.elaborator.deref_subpath(self.path);
348418

349-
let succ = self.succ; // FIXME(#43234)
350-
let unwind = self.unwind;
351-
let succ = self.box_free_block(adt, substs, succ, unwind);
419+
let succ = self.box_free_block(adt, substs, self.succ, self.unwind);
352420
let unwind_succ =
353421
self.unwind.map(|unwind| self.box_free_block(adt, substs, unwind, Unwind::InCleanup));
354422

@@ -829,6 +897,8 @@ where
829897
self.drop_flag_test_block(drop_block, succ, unwind)
830898
}
831899

900+
/// Creates a block that resets the drop flag. If `mode` is deep, all children drop flags will
901+
/// also be cleared.
832902
fn drop_flag_reset_block(
833903
&mut self,
834904
mode: DropFlagMode,
@@ -850,13 +920,15 @@ where
850920

851921
fn elaborated_drop_block(&mut self) -> BasicBlock {
852922
debug!("elaborated_drop_block({:?})", self);
853-
let unwind = self.unwind; // FIXME(#43234)
854-
let succ = self.succ;
855-
let blk = self.drop_block(succ, unwind);
923+
let blk = self.drop_block(self.succ, self.unwind);
856924
self.elaborate_drop(blk);
857925
blk
858926
}
859927

928+
/// Creates a block that frees the backing memory of a `Box` if its drop is required (either
929+
/// statically or by checking its drop flag).
930+
///
931+
/// The contained value will not be dropped.
860932
fn box_free_block(
861933
&mut self,
862934
adt: &'tcx ty::AdtDef,
@@ -868,6 +940,8 @@ where
868940
self.drop_flag_test_block(block, target, unwind)
869941
}
870942

943+
/// Creates a block that frees the backing memory of a `Box` (without dropping the contained
944+
/// value).
871945
fn unelaborated_free_block(
872946
&mut self,
873947
adt: &'tcx ty::AdtDef,
@@ -914,6 +988,11 @@ where
914988
self.new_block(unwind, block)
915989
}
916990

991+
/// Returns the block to jump to in order to test the drop flag and execute the drop.
992+
///
993+
/// Depending on the required `DropStyle`, this might be a generated block with an `if`
994+
/// terminator (for dynamic/open drops), or it might be `on_set` or `on_unset` itself, in case
995+
/// the drop can be statically determined.
917996
fn drop_flag_test_block(
918997
&mut self,
919998
on_set: BasicBlock,

0 commit comments

Comments
 (0)