diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
commit | 698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch) | |
tree | 173a775858bd501c378080a10dca74132f05bc50 /compiler/rustc_data_structures/src/steal.rs | |
parent | Initial commit. (diff) | |
download | rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip |
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_data_structures/src/steal.rs')
-rw-r--r-- | compiler/rustc_data_structures/src/steal.rs | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/compiler/rustc_data_structures/src/steal.rs b/compiler/rustc_data_structures/src/steal.rs new file mode 100644 index 000000000..a3ece6550 --- /dev/null +++ b/compiler/rustc_data_structures/src/steal.rs @@ -0,0 +1,55 @@ +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? +#[derive(Debug)] +pub struct Steal<T> { + value: RwLock<Option<T>>, +} + +impl<T> Steal<T> { + pub fn new(value: T) -> Self { + Steal { value: RwLock::new(Some(value)) } + } + + #[track_caller] + pub fn borrow(&self) -> MappedReadGuard<'_, T> { + let borrow = self.value.borrow(); + if borrow.is_none() { + panic!("attempted to read from stolen value: {}", std::any::type_name::<T>()); + } + ReadGuard::map(borrow, |opt| opt.as_ref().unwrap()) + } + + #[track_caller] + 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 steal 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); + } +} |