about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan MacKenzie <ecstaticmorse@gmail.com>2019-09-25 12:53:28 -0700
committerDylan MacKenzie <ecstaticmorse@gmail.com>2019-09-28 07:06:52 -0700
commita302055caac70f51641cdad1dfa87f134090496a (patch)
tree0fb0a2f6c59f7b80041cd51670804f94e17838c2
parentff6faabda7840db86b90663f239bac909bae3a18 (diff)
downloadrust-a302055caac70f51641cdad1dfa87f134090496a.tar.gz
rust-a302055caac70f51641cdad1dfa87f134090496a.zip
Mask results from flow-sensitive resolver with `in_any_value_of_ty`
We relied previously on the caller (e.g. `Q::in_operand`) to ignore
`Local`s that were indirectly mutable (and thus assumed to be
qualified). However, it's much clearer (and more efficient) to do this
in the resolver itself.

This does not yet remove the masking done in `Q::in_operand` and others
for safety's sake, although I believe that should now be possible.
-rw-r--r--src/librustc_mir/transform/check_consts/resolver.rs20
1 files changed, 19 insertions, 1 deletions
diff --git a/src/librustc_mir/transform/check_consts/resolver.rs b/src/librustc_mir/transform/check_consts/resolver.rs
index c23a7e98efc..2789693ecb6 100644
--- a/src/librustc_mir/transform/check_consts/resolver.rs
+++ b/src/librustc_mir/transform/check_consts/resolver.rs
@@ -188,6 +188,9 @@ where
     indirectly_mutable_locals: &'a RefCell<IndirectlyMutableResults<'mir, 'tcx>>,
     cursor: dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q>>,
     qualifs_per_local: BitSet<Local>,
+
+    /// The value of `Q::in_any_value_of_ty` for each local.
+    qualifs_in_any_value_of_ty: BitSet<Local>,
 }
 
 impl<Q> FlowSensitiveResolver<'a, 'mir, 'tcx, Q>
@@ -208,10 +211,18 @@ where
             dataflow::Engine::new(item.body, dead_unwinds, analysis).iterate_to_fixpoint();
         let cursor = dataflow::ResultsCursor::new(item.body, results);
 
+        let mut qualifs_in_any_value_of_ty = BitSet::new_empty(item.body.local_decls.len());
+        for (local, decl) in item.body.local_decls.iter_enumerated() {
+            if Q::in_any_value_of_ty(item, decl.ty) {
+                qualifs_in_any_value_of_ty.insert(local);
+            }
+        }
+
         FlowSensitiveResolver {
             cursor,
             indirectly_mutable_locals,
             qualifs_per_local: BitSet::new_empty(item.body.local_decls.len()),
+            qualifs_in_any_value_of_ty,
             location: Location { block: mir::START_BLOCK, statement_index: 0 },
         }
     }
@@ -242,16 +253,23 @@ where
 
         self.qualifs_per_local.overwrite(indirectly_mutable_locals.get());
         self.qualifs_per_local.union(self.cursor.get());
+        self.qualifs_per_local.intersect(&self.qualifs_in_any_value_of_ty);
         &self.qualifs_per_local
     }
 
     fn contains(&mut self, local: Local) -> bool {
+        // No need to update the cursor if we know that `Local` cannot possibly be qualified.
+        if !self.qualifs_in_any_value_of_ty.contains(local) {
+            return false;
+        }
+
+        // Otherwise, return `true` if this local is qualified or was indirectly mutable at any
+        // point before this statement.
         self.cursor.seek_before(self.location);
         if self.cursor.get().contains(local) {
             return true;
         }
 
-
         let mut indirectly_mutable_locals = self.indirectly_mutable_locals.borrow_mut();
         indirectly_mutable_locals.seek(self.location);
         indirectly_mutable_locals.get().contains(local)