]> git.lizzy.rs Git - rust.git/commitdiff
mir: Add TerminatorKind::FalseUnwind
authorbobtwinkles <srkoser+GitHub@gmail.com>
Thu, 25 Jan 2018 06:45:45 +0000 (01:45 -0500)
committerbobtwinkles <srkoser+GitHub@gmail.com>
Mon, 5 Feb 2018 20:00:40 +0000 (15:00 -0500)
Sometimes a simple goto misses the cleanup/unwind edges. Specifically, in the
case of infinite loops such as those introduced by a loop statement without any
other out edges. Analogous to TerminatorKind::FalseEdges; this new terminator
kind is used when we want borrowck to consider an unwind path, but real control
flow should never actually take it.

19 files changed:
src/librustc/ich/impls_mir.rs
src/librustc/mir/mod.rs
src/librustc/mir/visit.rs
src/librustc_mir/borrow_check/mod.rs
src/librustc_mir/borrow_check/nll/type_check/mod.rs
src/librustc_mir/build/matches/mod.rs
src/librustc_mir/dataflow/impls/borrows.rs
src/librustc_mir/dataflow/mod.rs
src/librustc_mir/dataflow/move_paths/builder.rs
src/librustc_mir/interpret/terminator/mod.rs
src/librustc_mir/monomorphize/collector.rs
src/librustc_mir/transform/check_unsafety.rs
src/librustc_mir/transform/inline.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_mir/transform/remove_noop_landing_pads.rs
src/librustc_mir/transform/simplify_branches.rs
src/librustc_passes/mir_stats.rs
src/librustc_trans/mir/analyze.rs
src/librustc_trans/mir/block.rs

index f46b590d2dc59d0490e17c3950ae103d3526b894..e78c2ad7c88b74ebc6a29125a688126768b24ad1 100644 (file)
@@ -201,6 +201,10 @@ fn hash_stable<W: StableHasherResult>(&self,
                     target.hash_stable(hcx, hasher);
                 }
             }
+            mir::TerminatorKind::FalseUnwind { ref real_target, ref unwind } => {
+                real_target.hash_stable(hcx, hasher);
+                unwind.hash_stable(hcx, hasher);
+            }
         }
     }
 }
index d82691f882c7348b7ad2e1cc01cc13963c1eb945..e7284a2716fd112ea8704e46180f995051ff9fd3 100644 (file)
@@ -803,9 +803,28 @@ pub enum TerminatorKind<'tcx> {
     /// Indicates the end of the dropping of a generator
     GeneratorDrop,
 
+    /// A block where control flow only ever takes one real path, but borrowck
+    /// needs to be more conservative.
     FalseEdges {
+        /// The target normal control flow will take
         real_target: BasicBlock,
-        imaginary_targets: Vec<BasicBlock>
+        /// The list of blocks control flow could conceptually take, but won't
+        /// in practice
+        imaginary_targets: Vec<BasicBlock>,
+    },
+    /// A terminator for blocks that only take one path in reality, but where we
+    /// reserve the right to unwind in borrowck, even if it won't happen in practice.
+    /// This can arise in infinite loops with no function calls for example.
+    FalseUnwind {
+        /// The target normal control flow will take
+        real_target: BasicBlock,
+        /// The imaginary cleanup block link. This particular path will never be taken
+        /// in practice, but in order to avoid fragility we want to always
+        /// consider it in borrowck. We don't want to accept programs which
+        /// pass borrowck only when panic=abort or some assertions are disabled
+        /// due to release vs. debug mode builds. This needs to be an Option because
+        /// of the remove_noop_landing_pads and no_landing_pads passes
+        unwind: Option<BasicBlock>,
     },
 }
 
@@ -865,6 +884,8 @@ pub fn successors(&self) -> Cow<[BasicBlock]> {
                 s.extend_from_slice(imaginary_targets);
                 s.into_cow()
             }
+            FalseUnwind { real_target: t, unwind: Some(u) } => vec![t, u].into_cow(),
+            FalseUnwind { real_target: ref t, unwind: None } => slice::from_ref(t).into_cow(),
         }
     }
 
@@ -897,6 +918,8 @@ pub fn successors_mut(&mut self) -> Vec<&mut BasicBlock> {
                 s.extend(imaginary_targets.iter_mut());
                 s
             }
+            FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => vec![t, u],
+            FalseUnwind { ref mut real_target, unwind: None } => vec![real_target],
         }
     }
 
@@ -916,7 +939,8 @@ pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> {
             TerminatorKind::Call { cleanup: ref mut unwind, .. } |
             TerminatorKind::Assert { cleanup: ref mut unwind, .. } |
             TerminatorKind::DropAndReplace { ref mut unwind, .. } |
-            TerminatorKind::Drop { ref mut unwind, .. } => {
+            TerminatorKind::Drop { ref mut unwind, .. } |
+            TerminatorKind::FalseUnwind { ref mut unwind, .. } => {
                 Some(unwind)
             }
         }
@@ -1045,7 +1069,8 @@ pub fn fmt_head<W: Write>(&self, fmt: &mut W) -> fmt::Result {
 
                 write!(fmt, ")")
             },
-            FalseEdges { .. } => write!(fmt, "falseEdges")
+            FalseEdges { .. } => write!(fmt, "falseEdges"),
+            FalseUnwind { .. } => write!(fmt, "falseUnwind"),
         }
     }
 
@@ -1087,6 +1112,8 @@ pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
                 l.resize(imaginary_targets.len() + 1, "imaginary".into());
                 l
             }
+            FalseUnwind { unwind: Some(_), .. } => vec!["real".into(), "cleanup".into()],
+            FalseUnwind { unwind: None, .. } => vec!["real".into()],
         }
     }
 }
@@ -2189,7 +2216,8 @@ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
             Return => Return,
             Unreachable => Unreachable,
             FalseEdges { real_target, ref imaginary_targets } =>
-                FalseEdges { real_target, imaginary_targets: imaginary_targets.clone() }
+                FalseEdges { real_target, imaginary_targets: imaginary_targets.clone() },
+            FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind },
         };
         Terminator {
             source_info: self.source_info,
@@ -2231,7 +2259,8 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
             Return |
             GeneratorDrop |
             Unreachable |
-            FalseEdges { .. } => false
+            FalseEdges { .. } |
+            FalseUnwind { .. } => false
         }
     }
 }
index 57ed41f2f06e63c7ef6968409e55754ef44f3dbc..b26e1854d97fddf9a71909ef8c35848f21cc821b 100644 (file)
@@ -495,15 +495,21 @@ fn super_terminator_kind(&mut self,
                         self.visit_operand(value, source_location);
                         self.visit_branch(block, resume);
                         drop.map(|t| self.visit_branch(block, t));
-
                     }
 
-                    TerminatorKind::FalseEdges { real_target, ref imaginary_targets } => {
+                    TerminatorKind::FalseEdges { real_target, ref imaginary_targets} => {
                         self.visit_branch(block, real_target);
                         for target in imaginary_targets {
                             self.visit_branch(block, *target);
                         }
                     }
+
+                    TerminatorKind::FalseUnwind { real_target, unwind } => {
+                        self.visit_branch(block, real_target);
+                        if let Some(unwind) = unwind {
+                            self.visit_branch(block, unwind);
+                        }
+                    }
                 }
             }
 
index 9a6d83b8eb75904c81d2b45a128992cf328c4dde..6a19392a6e88b5c0f5a6d74e5f34668c4f2e7be0 100644 (file)
@@ -576,7 +576,8 @@ fn visit_terminator_entry(
             TerminatorKind::Goto { target: _ }
             | TerminatorKind::Abort
             | TerminatorKind::Unreachable
-            | TerminatorKind::FalseEdges { .. } => {
+            | TerminatorKind::FalseEdges { real_target: _, imaginary_targets: _ }
+            | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => {
                 // no data used, thus irrelevant to borrowck
             }
         }
index c0c680a4ddcbceae0b361f7af3ffb86800a1e3e5..7ca8d0bdd500bb841a8dc849ce5b5ed4909d900d 100644 (file)
@@ -796,7 +796,8 @@ fn check_terminator(
             | TerminatorKind::GeneratorDrop
             | TerminatorKind::Unreachable
             | TerminatorKind::Drop { .. }
-            | TerminatorKind::FalseEdges { .. } => {
+            | TerminatorKind::FalseEdges { .. }
+            | TerminatorKind::FalseUnwind { .. } => {
                 // no checks needed for these
             }
 
@@ -1152,6 +1153,18 @@ fn check_iscleanup(&mut self, mir: &Mir<'tcx>, block_data: &BasicBlockData<'tcx>
                     self.assert_iscleanup(mir, block_data, *target, is_cleanup);
                 }
             }
+            TerminatorKind::FalseUnwind {
+                real_target,
+                unwind
+            } => {
+                self.assert_iscleanup(mir, block_data, real_target, is_cleanup);
+                if let Some(unwind) = unwind {
+                    if is_cleanup {
+                        span_mirbug!(self, block_data, "cleanup in cleanup block via false unwind");
+                    }
+                    self.assert_iscleanup(mir, block_data, unwind, true);
+                }
+            }
         }
     }
 
index 6cb9217776648194aedafb1ee649be440239524c..e2096bf5356c15ff748fe90a3a0c88582ee80d81 100644 (file)
@@ -728,7 +728,8 @@ fn bind_and_guard_matched_candidate<'pat>(&mut self,
                                TerminatorKind::FalseEdges {
                                    real_target: block,
                                    imaginary_targets:
-                                       vec![candidate.next_candidate_pre_binding_block]});
+                                       vec![candidate.next_candidate_pre_binding_block],
+                               });
 
         self.bind_matched_candidate(block, candidate.bindings);
 
@@ -749,7 +750,8 @@ fn bind_and_guard_matched_candidate<'pat>(&mut self,
                                TerminatorKind::FalseEdges {
                                    real_target: otherwise,
                                    imaginary_targets:
-                                       vec![candidate.next_candidate_pre_binding_block] });
+                                       vec![candidate.next_candidate_pre_binding_block],
+                               });
             Some(otherwise)
         } else {
             self.cfg.terminate(block, candidate_source_info,
index 80990bcc080891ef93478a602019248137560710..ad6ac6876ce669b241a1e881bac1c5124fe09d10 100644 (file)
@@ -517,6 +517,7 @@ fn terminator_effect_on_borrows(&self,
             mir::TerminatorKind::Yield {..} |
             mir::TerminatorKind::Goto {..} |
             mir::TerminatorKind::FalseEdges {..} |
+            mir::TerminatorKind::FalseUnwind {..} |
             mir::TerminatorKind::Unreachable => {}
         }
     }
index 291c22b5e1ed0f0aa32081534a97ff24f396cd21..9c7d9b398cc566561d27e7fccbf8f1e6350923d1 100644 (file)
@@ -864,6 +864,14 @@ fn propagate_bits_into_graph_successors_of(
                     self.propagate_bits_into_entry_set_for(in_out, changed, target);
                 }
             }
+            mir::TerminatorKind::FalseUnwind { ref real_target, unwind } => {
+                self.propagate_bits_into_entry_set_for(in_out, changed, real_target);
+                if let Some(ref unwind) = unwind {
+                    if !self.dead_unwinds.contains(&bb) {
+                        self.propagate_bits_into_entry_set_for(in_out, changed, unwind);
+                    }
+                }
+            }
         }
     }
 
index cd36282eca0a65408f5a773f7a448adbcb1d7340..635d99e7737a97467025175374c2b11837bea2d9 100644 (file)
@@ -346,6 +346,7 @@ fn gather_terminator(&mut self, term: &Terminator<'tcx>) {
             TerminatorKind::Abort |
             TerminatorKind::GeneratorDrop |
             TerminatorKind::FalseEdges { .. } |
+            TerminatorKind::FalseUnwind { .. } |
             TerminatorKind::Unreachable => { }
 
             TerminatorKind::Return => {
index c8a0dbdd9030896549427ef41f9c392cfe318701..606bda51edb1fdfe304a01c4eada0f125c0b7abe 100644 (file)
@@ -165,6 +165,7 @@ pub(super) fn eval_terminator(
             Resume => unimplemented!(),
             Abort => unimplemented!(),
             FalseEdges { .. } => bug!("should have been eliminated by `simplify_branches` mir pass"),
+            FalseUnwind { .. } => bug!("should have been eliminated by `simplify_branches` mir pass"),
             Unreachable => return err!(Unreachable),
         }
 
index f16187797d4e5127d2f6544683207a8cc244cb5c..a80dfaef0dab1b276ff74892f80facd2c3d879b9 100644 (file)
@@ -636,7 +636,8 @@ fn visit_terminator_kind(&mut self,
             mir::TerminatorKind::Assert { .. } => {}
             mir::TerminatorKind::GeneratorDrop |
             mir::TerminatorKind::Yield { .. } |
-            mir::TerminatorKind::FalseEdges { .. } => bug!(),
+            mir::TerminatorKind::FalseEdges { .. } |
+            mir::TerminatorKind::FalseUnwind { .. } => bug!(),
         }
 
         self.super_terminator_kind(block, kind, location);
index ae27f54e618a1822c4edaaa5cb397152385db3fa..bbc7803b84d8e1a87e68b52102533d4a32ed3134 100644 (file)
@@ -76,7 +76,8 @@ fn visit_terminator(&mut self,
             TerminatorKind::Abort |
             TerminatorKind::Return |
             TerminatorKind::Unreachable |
-            TerminatorKind::FalseEdges { .. } => {
+            TerminatorKind::FalseEdges { .. } |
+            TerminatorKind::FalseUnwind { .. } => {
                 // safe (at least as emitted during MIR construction)
             }
 
index ceea97e3ed3b0f1276757873ff053c99e2b295bf..2d861921c9c8d6d7ee91c86045c64eb7dfc6f8d1 100644 (file)
@@ -813,6 +813,9 @@ fn visit_terminator_kind(&mut self, block: BasicBlock,
                     *target = self.update_target(*target);
                 }
             }
+            TerminatorKind::FalseUnwind { real_target: _ , unwind: _ } =>
+                // see the ordering of passes in the optimized_mir query.
+                bug!("False unwinds should have been removed before inlining")
         }
     }
 
index da76adfd48f3ffd4306317d4579c7fc120c2c63f..741e39fe068800a9e770cb58417e56b2be3696a7 100644 (file)
@@ -327,7 +327,8 @@ fn qualify_const(&mut self) -> (Qualif, Rc<IdxSetBuf<Local>>) {
                 TerminatorKind::GeneratorDrop |
                 TerminatorKind::Yield { .. } |
                 TerminatorKind::Unreachable |
-                TerminatorKind::FalseEdges { .. } => None,
+                TerminatorKind::FalseEdges { .. } |
+                TerminatorKind::FalseUnwind { .. } => None,
 
                 TerminatorKind::Return => {
                     // Check for unused values. This usually means
index e7cab469bc222e0691e671857f5109cad11c81c5..cd80d25c410f1fc9e906406a9bd35b26f1a2a948 100644 (file)
@@ -75,7 +75,8 @@ fn is_nop_landing_pad(&self, bb: BasicBlock, mir: &Mir, nop_landing_pads: &BitVe
             TerminatorKind::Goto { .. } |
             TerminatorKind::Resume |
             TerminatorKind::SwitchInt { .. } |
-            TerminatorKind::FalseEdges { .. } => {
+            TerminatorKind::FalseEdges { .. } |
+            TerminatorKind::FalseUnwind { .. } => {
                 terminator.successors().iter().all(|succ| {
                     nop_landing_pads.contains(succ.index())
                 })
index 20c33bab1aacb2b5ebae5e75fc6be120e34e56da..41089f567bd710c65d99219109fc428c2615bec5 100644 (file)
@@ -64,6 +64,9 @@ fn run_pass<'a, 'tcx>(&self,
                 TerminatorKind::FalseEdges { real_target, .. } => {
                     TerminatorKind::Goto { target: real_target }
                 },
+                TerminatorKind::FalseUnwind { real_target, .. } => {
+                    TerminatorKind::Goto { target: real_target }
+                },
                 _ => continue
             };
         }
index b379a174b23f61aba881f09c1861a369441bd5cb..e4705674e229233eb817f87db48a4459e758abee 100644 (file)
@@ -123,6 +123,7 @@ fn visit_terminator_kind(&mut self,
             TerminatorKind::GeneratorDrop => "TerminatorKind::GeneratorDrop",
             TerminatorKind::Yield { .. } => "TerminatorKind::Yield",
             TerminatorKind::FalseEdges { .. } => "TerminatorKind::FalseEdges",
+            TerminatorKind::FalseUnwind { .. } => "TerminatorKind::FalseUnwind",
         }, kind);
         self.super_terminator_kind(block, kind, location);
     }
index bf82e1d50c47387884bb1f46c24e3c4b7a4296cc..f683703ce6d53403851dcb5567bd0fda34871dba 100644 (file)
@@ -242,7 +242,8 @@ fn discover_masters<'tcx>(result: &mut IndexVec<mir::BasicBlock, CleanupKind>,
                 TerminatorKind::Unreachable |
                 TerminatorKind::SwitchInt { .. } |
                 TerminatorKind::Yield { .. } |
-                TerminatorKind::FalseEdges { .. } => {
+                TerminatorKind::FalseEdges { .. } |
+                TerminatorKind::FalseUnwind { .. } => {
                     /* nothing to do */
                 }
                 TerminatorKind::Call { cleanup: unwind, .. } |
index af1e30a4b19a6c2f5485c92d26988981f64839b7..bb2a7840faee76e38b57d152e84991fd835948a9 100644 (file)
@@ -608,8 +608,9 @@ fn trans_terminator(&mut self,
                         cleanup);
             }
             mir::TerminatorKind::GeneratorDrop |
-            mir::TerminatorKind::Yield { .. } |
-            mir::TerminatorKind::FalseEdges { .. } => bug!("generator ops in trans"),
+            mir::TerminatorKind::Yield { .. } => bug!("generator ops in trans"),
+            mir::TerminatorKind::FalseEdges { .. } |
+            mir::TerminatorKind::FalseUnwind { .. } => bug!("borrowck false edges in trans"),
         }
     }