about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <dylan.dpc@gmail.com>2020-05-18 19:04:04 +0200
committerGitHub <noreply@github.com>2020-05-18 19:04:04 +0200
commit4adb9a85c32e56ee4e9bcd48c96b791150b469ad (patch)
treeb69c3eeaf81f58e416c8ac3e6c28a2237409da6d
parentc6030c957a2bb4ddb36c9a06df5fcf9c5f626029 (diff)
parent1e4b66300551149fd49ce499aaae5c231cefde7f (diff)
downloadrust-4adb9a85c32e56ee4e9bcd48c96b791150b469ad.tar.gz
rust-4adb9a85c32e56ee4e9bcd48c96b791150b469ad.zip
Rollup merge of #72283 - jonas-schievink:elaborate-drop-elaboration, r=cramertj
Drop Elaboration Elaboration

As in, adding more documentation to it.
-rw-r--r--src/librustc_mir/shim.rs13
-rw-r--r--src/librustc_mir/util/elaborate_drops.rs95
2 files changed, 99 insertions, 9 deletions
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index d025468d28b..e3982c654d5 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -277,7 +277,18 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
     }
 
     fn drop_style(&self, _path: Self::Path, mode: DropFlagMode) -> DropStyle {
-        if let DropFlagMode::Shallow = mode { DropStyle::Static } else { DropStyle::Open }
+        match mode {
+            DropFlagMode::Shallow => {
+                // Drops for the contained fields are "shallow" and "static" - they will simply call
+                // the field's own drop glue.
+                DropStyle::Static
+            }
+            DropFlagMode::Deep => {
+                // The top-level drop is "deep" and "open" - it will be elaborated to a drop ladder
+                // dropping each field contained in the value.
+                DropStyle::Open
+            }
+        }
     }
 
     fn get_drop_flag(&mut self, _path: Self::Path) -> Option<Operand<'tcx>> {
diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs
index af7c88b178d..ed999c6871b 100644
--- a/src/librustc_mir/util/elaborate_drops.rs
+++ b/src/librustc_mir/util/elaborate_drops.rs
@@ -12,10 +12,15 @@ use std::fmt;
 
 use std::convert::TryInto;
 
+/// The value of an inserted drop flag.
 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
 pub enum DropFlagState {
-    Present, // i.e., initialized
-    Absent,  // i.e., deinitialized or "moved"
+    /// The tracked value is initialized and needs to be dropped when leaving its scope.
+    Present,
+
+    /// The tracked value is uninitialized or was moved out of and does not need to be dropped when
+    /// leaving its scope.
+    Absent,
 }
 
 impl DropFlagState {
@@ -27,23 +32,42 @@ impl DropFlagState {
     }
 }
 
+/// Describes how/if a value should be dropped.
 #[derive(Debug)]
 pub enum DropStyle {
+    /// The value is already dead at the drop location, no drop will be executed.
     Dead,
+
+    /// The value is known to always be initialized at the drop location, drop will always be
+    /// executed.
     Static,
+
+    /// Whether the value needs to be dropped depends on its drop flag.
     Conditional,
+
+    /// An "open" drop is one where only the fields of a value are dropped.
+    ///
+    /// For example, this happens when moving out of a struct field: The rest of the struct will be
+    /// dropped in such an "open" drop. It is also used to generate drop glue for the individual
+    /// components of a value, for example for dropping array elements.
     Open,
 }
 
+/// Which drop flags to affect/check with an operation.
 #[derive(Debug)]
 pub enum DropFlagMode {
+    /// Only affect the top-level drop flag, not that of any contained fields.
     Shallow,
+    /// Affect all nested drop flags in addition to the top-level one.
     Deep,
 }
 
+/// Describes if unwinding is necessary and where to unwind to if a panic occurs.
 #[derive(Copy, Clone, Debug)]
 pub enum Unwind {
+    /// Unwind to this block.
     To(BasicBlock),
+    /// Already in an unwind path, any panic will cause an abort.
     InCleanup,
 }
 
@@ -74,20 +98,58 @@ impl Unwind {
 }
 
 pub trait DropElaborator<'a, 'tcx>: fmt::Debug {
+    /// The type representing paths that can be moved out of.
+    ///
+    /// Users can move out of individual fields of a struct, such as `a.b.c`. This type is used to
+    /// represent such move paths. Sometimes tracking individual move paths is not necessary, in
+    /// which case this may be set to (for example) `()`.
     type Path: Copy + fmt::Debug;
 
+    // Accessors
+
     fn patch(&mut self) -> &mut MirPatch<'tcx>;
     fn body(&self) -> &'a Body<'tcx>;
     fn tcx(&self) -> TyCtxt<'tcx>;
     fn param_env(&self) -> ty::ParamEnv<'tcx>;
 
+    // Drop logic
+
+    /// Returns how `path` should be dropped, given `mode`.
     fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle;
+
+    /// Returns the drop flag of `path` as a MIR `Operand` (or `None` if `path` has no drop flag).
     fn get_drop_flag(&mut self, path: Self::Path) -> Option<Operand<'tcx>>;
+
+    /// Modifies the MIR patch so that the drop flag of `path` (if any) is cleared at `location`.
+    ///
+    /// If `mode` is deep, drop flags of all child paths should also be cleared by inserting
+    /// additional statements.
     fn clear_drop_flag(&mut self, location: Location, path: Self::Path, mode: DropFlagMode);
 
+    // Subpaths
+
+    /// Returns the subpath of a field of `path` (or `None` if there is no dedicated subpath).
+    ///
+    /// If this returns `None`, `field` will not get a dedicated drop flag.
     fn field_subpath(&self, path: Self::Path, field: Field) -> Option<Self::Path>;
+
+    /// Returns the subpath of a dereference of `path` (or `None` if there is no dedicated subpath).
+    ///
+    /// If this returns `None`, `*path` will not get a dedicated drop flag.
+    ///
+    /// This is only relevant for `Box<T>`, where the contained `T` can be moved out of the box.
     fn deref_subpath(&self, path: Self::Path) -> Option<Self::Path>;
+
+    /// Returns the subpath of downcasting `path` to one of its variants.
+    ///
+    /// If this returns `None`, the downcast of `path` will not get a dedicated drop flag.
     fn downcast_subpath(&self, path: Self::Path, variant: VariantIdx) -> Option<Self::Path>;
+
+    /// Returns the subpath of indexing a fixed-size array `path`.
+    ///
+    /// If this returns `None`, elements of `path` will not get a dedicated drop flag.
+    ///
+    /// This is only relevant for array patterns, which can move out of individual array elements.
     fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option<Self::Path>;
 }
 
@@ -106,6 +168,14 @@ where
     unwind: Unwind,
 }
 
+/// "Elaborates" a drop of `place`/`path` and patches `bb`'s terminator to execute it.
+///
+/// The passed `elaborator` is used to determine what should happen at the drop terminator. It
+/// decides whether the drop can be statically determined or whether it needs a dynamic drop flag,
+/// and whether the drop is "open", ie. should be expanded to drop all subfields of the dropped
+/// value.
+///
+/// When this returns, the MIR patch in the `elaborator` contains the necessary changes.
 pub fn elaborate_drop<'b, 'tcx, D>(
     elaborator: &mut D,
     source_info: SourceInfo,
@@ -346,9 +416,7 @@ where
         let interior = self.tcx().mk_place_deref(self.place);
         let interior_path = self.elaborator.deref_subpath(self.path);
 
-        let succ = self.succ; // FIXME(#43234)
-        let unwind = self.unwind;
-        let succ = self.box_free_block(adt, substs, succ, unwind);
+        let succ = self.box_free_block(adt, substs, self.succ, self.unwind);
         let unwind_succ =
             self.unwind.map(|unwind| self.box_free_block(adt, substs, unwind, Unwind::InCleanup));
 
@@ -829,6 +897,8 @@ where
         self.drop_flag_test_block(drop_block, succ, unwind)
     }
 
+    /// Creates a block that resets the drop flag. If `mode` is deep, all children drop flags will
+    /// also be cleared.
     fn drop_flag_reset_block(
         &mut self,
         mode: DropFlagMode,
@@ -850,13 +920,15 @@ where
 
     fn elaborated_drop_block(&mut self) -> BasicBlock {
         debug!("elaborated_drop_block({:?})", self);
-        let unwind = self.unwind; // FIXME(#43234)
-        let succ = self.succ;
-        let blk = self.drop_block(succ, unwind);
+        let blk = self.drop_block(self.succ, self.unwind);
         self.elaborate_drop(blk);
         blk
     }
 
+    /// Creates a block that frees the backing memory of a `Box` if its drop is required (either
+    /// statically or by checking its drop flag).
+    ///
+    /// The contained value will not be dropped.
     fn box_free_block(
         &mut self,
         adt: &'tcx ty::AdtDef,
@@ -868,6 +940,8 @@ where
         self.drop_flag_test_block(block, target, unwind)
     }
 
+    /// Creates a block that frees the backing memory of a `Box` (without dropping the contained
+    /// value).
     fn unelaborated_free_block(
         &mut self,
         adt: &'tcx ty::AdtDef,
@@ -914,6 +988,11 @@ where
         self.new_block(unwind, block)
     }
 
+    /// Returns the block to jump to in order to test the drop flag and execute the drop.
+    ///
+    /// Depending on the required `DropStyle`, this might be a generated block with an `if`
+    /// terminator (for dynamic/open drops), or it might be `on_set` or `on_unset` itself, in case
+    /// the drop can be statically determined.
     fn drop_flag_test_block(
         &mut self,
         on_set: BasicBlock,