about summary refs log tree commit diff
path: root/compiler/rustc_data_structures/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-11-15 13:19:05 +0000
committerbors <bors@rust-lang.org>2020-11-15 13:19:05 +0000
commit5fab31e5ddf5f2613bf57a0a7286dc6f5887e1cb (patch)
treebf2540f955bf3e3adb49330b1fd06ee628d9fc35 /compiler/rustc_data_structures/src
parent04688459242356c0f6b9fdad3ba76c9ec4dcc354 (diff)
parent568354f01f22148709e51fe1130826addb455e18 (diff)
downloadrust-5fab31e5ddf5f2613bf57a0a7286dc6f5887e1cb.tar.gz
rust-5fab31e5ddf5f2613bf57a0a7286dc6f5887e1cb.zip
Auto merge of #79070 - jonas-schievink:rollup-wacn2b8, r=jonas-schievink
Rollup of 13 pull requests

Successful merges:

 - #77802 (Allow making `RUSTC_BOOTSTRAP` conditional on the crate name)
 - #79004 (Add `--color` support to bootstrap)
 - #79005 (cleanup: Remove `ParseSess::injected_crate_name`)
 - #79016 (Make `_` an expression, to discard values in destructuring assignments)
 - #79019 (astconv: extract closures into a separate trait)
 - #79026 (Implement BTreeMap::retain and BTreeSet::retain)
 - #79031 (Validate that locals have a corresponding `LocalDecl`)
 - #79034 (rustc_resolve: Make `macro_rules` scope chain compression lazy)
 - #79036 (Move Steal to rustc_data_structures.)
 - #79041 (Rename clean::{ItemEnum -> ItemKind}, clean::Item::{inner -> kind})
 - #79058 (Move likely/unlikely argument outside of invisible unsafe block)
 - #79059 (Print 'checking cranelift artifacts' to easily separate it from other artifacts)
 - #79063 (Update rustfmt to v1.4.26)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler/rustc_data_structures/src')
-rw-r--r--compiler/rustc_data_structures/src/lib.rs13
-rw-r--r--compiler/rustc_data_structures/src/steal.rs51
2 files changed, 58 insertions, 6 deletions
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 7669b78834c..322c7a71160 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -47,9 +47,9 @@ pub fn cold_path<F: FnOnce() -> R, R>(f: F) -> R {
 #[macro_export]
 macro_rules! likely {
     ($e:expr) => {
-        #[allow(unused_unsafe)]
-        {
-            unsafe { std::intrinsics::likely($e) }
+        match $e {
+            #[allow(unused_unsafe)]
+            e => unsafe { std::intrinsics::likely(e) },
         }
     };
 }
@@ -57,9 +57,9 @@ macro_rules! likely {
 #[macro_export]
 macro_rules! unlikely {
     ($e:expr) => {
-        #[allow(unused_unsafe)]
-        {
-            unsafe { std::intrinsics::unlikely($e) }
+        match $e {
+            #[allow(unused_unsafe)]
+            e => unsafe { std::intrinsics::unlikely(e) },
         }
     };
 }
@@ -102,6 +102,7 @@ pub mod work_queue;
 pub use atomic_ref::AtomicRef;
 pub mod frozen;
 pub mod sso;
+pub mod steal;
 pub mod tagged_ptr;
 pub mod temp_dir;
 pub mod unhash;
diff --git a/compiler/rustc_data_structures/src/steal.rs b/compiler/rustc_data_structures/src/steal.rs
new file mode 100644
index 00000000000..e532a84cea3
--- /dev/null
+++ b/compiler/rustc_data_structures/src/steal.rs
@@ -0,0 +1,51 @@
+use crate::stable_hasher::{HashStable, StableHasher};
+use crate::sync::{MappedReadGuard, ReadGuard, RwLock};
+
+/// The `Steal` struct is intended to used as the value for a query.
+/// Specifically, we sometimes have queries (*cough* MIR *cough*)
+/// where we create a large, complex value that we want to iteratively
+/// update (e.g., optimize). We could clone the value for each
+/// optimization, but that'd be expensive. And yet we don't just want
+/// to mutate it in place, because that would spoil the idea that
+/// queries are these pure functions that produce an immutable value
+/// (since if you did the query twice, you could observe the mutations).
+/// So instead we have the query produce a `&'tcx Steal<mir::Body<'tcx>>`
+/// (to be very specific). Now we can read from this
+/// as much as we want (using `borrow()`), but you can also
+/// `steal()`. Once you steal, any further attempt to read will panic.
+/// Therefore, we know that -- assuming no ICE -- nobody is observing
+/// the fact that the MIR was updated.
+///
+/// Obviously, whenever you have a query that yields a `Steal` value,
+/// you must treat it with caution, and make sure that you know that
+/// -- once the value is stolen -- it will never be read from again.
+//
+// FIXME(#41710): what is the best way to model linear queries?
+pub struct Steal<T> {
+    value: RwLock<Option<T>>,
+}
+
+impl<T> Steal<T> {
+    pub fn new(value: T) -> Self {
+        Steal { value: RwLock::new(Some(value)) }
+    }
+
+    pub fn borrow(&self) -> MappedReadGuard<'_, T> {
+        ReadGuard::map(self.value.borrow(), |opt| match *opt {
+            None => panic!("attempted to read from stolen value"),
+            Some(ref v) => v,
+        })
+    }
+
+    pub fn steal(&self) -> T {
+        let value_ref = &mut *self.value.try_write().expect("stealing value which is locked");
+        let value = value_ref.take();
+        value.expect("attempt to read from stolen value")
+    }
+}
+
+impl<CTX, T: HashStable<CTX>> HashStable<CTX> for Steal<T> {
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+        self.borrow().hash_stable(hcx, hasher);
+    }
+}