]> git.lizzy.rs Git - rust.git/commitdiff
Basic loop support
authorEric Holk <ericholk@microsoft.com>
Thu, 4 Nov 2021 17:56:07 +0000 (10:56 -0700)
committerEric Holk <ericholk@microsoft.com>
Tue, 18 Jan 2022 22:25:25 +0000 (14:25 -0800)
compiler/rustc_typeck/src/check/generator_interior.rs
src/test/ui/generator/drop-control-flow.rs

index 65644a54c4fa11c6c27b0d153233c3ae1f80e30f..d7ad84684d1f1fc286cc1763f8480995da52f867 100644 (file)
@@ -726,15 +726,19 @@ fn intersect_drop_ranges(&mut self, drops: HirIdMap<DropRange>) {
         })
     }
 
-    fn merge_drop_ranges(&mut self, drops: HirIdMap<DropRange>) {
+    fn merge_drop_ranges_at(&mut self, drops: HirIdMap<DropRange>, join_point: usize) {
         drops.into_iter().for_each(|(k, v)| {
             if !self.drop_ranges.contains_key(&k) {
                 self.drop_ranges.insert(k, DropRange { events: vec![] });
             }
-            self.drop_ranges.get_mut(&k).unwrap().merge_with(&v, self.expr_count);
+            self.drop_ranges.get_mut(&k).unwrap().merge_with(&v, join_point);
         });
     }
 
+    fn merge_drop_ranges(&mut self, drops: HirIdMap<DropRange>) {
+        self.merge_drop_ranges_at(drops, self.expr_count);
+    }
+
     /// ExprUseVisitor's consume callback doesn't go deep enough for our purposes in all
     /// expressions. This method consumes a little deeper into the expression when needed.
     fn consume_expr(&mut self, expr: &hir::Expr<'_>) {
@@ -893,6 +897,17 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
 
                 reinit = Some(lhs);
             }
+            ExprKind::Loop(body, ..) => {
+                let body_drop_ranges = self.fork_drop_ranges();
+                let old_drop_ranges = self.swap_drop_ranges(body_drop_ranges);
+
+                let join_point = self.expr_count;
+
+                self.visit_block(body);
+
+                let body_drop_ranges = self.swap_drop_ranges(old_drop_ranges);
+                self.merge_drop_ranges_at(body_drop_ranges, join_point);
+            }
             _ => intravisit::walk_expr(self, expr),
         }
 
@@ -1007,11 +1022,20 @@ fn reinit(&mut self, location: usize) {
     ///
     /// After merging, the value will be dead at the end of the range only if it was dead
     /// at the end of both self and other.
-    ///
-    /// Assumes that all locations in each range are less than joinpoint
     fn merge_with(&mut self, other: &DropRange, join_point: usize) {
-        let mut events: Vec<_> =
-            self.events.iter().merge(other.events.iter()).dedup().cloned().collect();
+        let join_event = if self.is_dropped_at(join_point) && other.is_dropped_at(join_point) {
+            Event::Drop(join_point)
+        } else {
+            Event::Reinit(join_point)
+        };
+        let mut events: Vec<_> = self
+            .events
+            .iter()
+            .merge([join_event].iter())
+            .merge(other.events.iter())
+            .dedup()
+            .cloned()
+            .collect();
 
         events.push(if self.is_dropped_at(join_point) && other.is_dropped_at(join_point) {
             Event::Drop(join_point)
index b180a61b104100616765b5a5fdefd8819a898500..6587e54df60831b58c164c874da10ff02c54b819 100644 (file)
@@ -77,5 +77,5 @@ fn main() {
     one_armed_if(true);
     if_let(Some(41));
     reinit();
-    // loop_uninit();
+    loop_uninit();
 }