Skip to content

Commit fe98885

Browse files
authored
Rollup merge of rust-lang#109971 - WaffleLapkin:yeet_ownership, r=Nilstrieb
Yeet `owning_ref` Based on the discussions from rust-lang#109948 This replaces `owning_ref` with a far simpler & safer abstraction. Fixes rust-lang#109974
2 parents 8b8994c + fbe0591 commit fe98885

File tree

13 files changed

+227
-2012
lines changed

13 files changed

+227
-2012
lines changed

Diff for: compiler/rustc_codegen_ssa/src/back/metadata.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ use object::{
1313
use snap::write::FrameEncoder;
1414

1515
use rustc_data_structures::memmap::Mmap;
16-
use rustc_data_structures::owning_ref::OwningRef;
17-
use rustc_data_structures::rustc_erase_owner;
16+
use rustc_data_structures::owned_slice::try_slice_owned;
1817
use rustc_data_structures::sync::MetadataRef;
1918
use rustc_metadata::fs::METADATA_FILENAME;
2019
use rustc_metadata::EncodedMetadata;
@@ -42,10 +41,10 @@ fn load_metadata_with(
4241
) -> Result<MetadataRef, String> {
4342
let file =
4443
File::open(path).map_err(|e| format!("failed to open file '{}': {}", path.display(), e))?;
45-
let data = unsafe { Mmap::map(file) }
46-
.map_err(|e| format!("failed to mmap file '{}': {}", path.display(), e))?;
47-
let metadata = OwningRef::new(data).try_map(f)?;
48-
return Ok(rustc_erase_owner!(metadata.map_owner_box()));
44+
45+
unsafe { Mmap::map(file) }
46+
.map_err(|e| format!("failed to mmap file '{}': {}", path.display(), e))
47+
.and_then(|mmap| try_slice_owned(mmap, |mmap| f(mmap)))
4948
}
5049

5150
impl MetadataLoader for DefaultMetadataLoader {

Diff for: compiler/rustc_data_structures/src/lib.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//! Various data structures used by the Rust compiler. The intention
2-
//! is that code in here should be not be *specific* to rustc, so that
2+
//! is that code in here should not be *specific* to rustc, so that
33
//! it can be easily unit tested and so forth.
44
//!
55
//! # Note
@@ -27,6 +27,8 @@
2727
#![feature(thread_id_value)]
2828
#![feature(vec_into_raw_parts)]
2929
#![feature(get_mut_unchecked)]
30+
#![feature(lint_reasons)]
31+
#![feature(unwrap_infallible)]
3032
#![allow(rustc::default_hash_types)]
3133
#![allow(rustc::potential_query_instability)]
3234
#![deny(rustc::untranslatable_diagnostic)]
@@ -59,7 +61,6 @@ pub mod intern;
5961
pub mod jobserver;
6062
pub mod macros;
6163
pub mod obligation_forest;
62-
pub mod owning_ref;
6364
pub mod sip128;
6465
pub mod small_c_str;
6566
pub mod small_str;
@@ -82,6 +83,7 @@ pub mod vec_linked_list;
8283
pub mod work_queue;
8384
pub use atomic_ref::AtomicRef;
8485
pub mod frozen;
86+
pub mod owned_slice;
8587
pub mod sso;
8688
pub mod steal;
8789
pub mod tagged_ptr;

Diff for: compiler/rustc_data_structures/src/memmap.rs

+1-9
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ use std::fs::File;
22
use std::io;
33
use std::ops::{Deref, DerefMut};
44

5-
use crate::owning_ref::StableAddress;
6-
7-
/// A trivial wrapper for [`memmap2::Mmap`] that implements [`StableAddress`].
5+
/// A trivial wrapper for [`memmap2::Mmap`] (or `Vec<u8>` on WASM).
86
#[cfg(not(target_arch = "wasm32"))]
97
pub struct Mmap(memmap2::Mmap);
108

@@ -46,12 +44,6 @@ impl AsRef<[u8]> for Mmap {
4644
}
4745
}
4846

49-
// SAFETY: On architectures other than WASM, mmap is used as backing storage. The address of this
50-
// memory map is stable. On WASM, `Vec<u8>` is used as backing storage. The `Mmap` type doesn't
51-
// export any function that can cause the `Vec` to be re-allocated. As such the address of the
52-
// bytes inside this `Vec` is stable.
53-
unsafe impl StableAddress for Mmap {}
54-
5547
#[cfg(not(target_arch = "wasm32"))]
5648
pub struct MmapMut(memmap2::MmapMut);
5749

Diff for: compiler/rustc_data_structures/src/owned_slice.rs

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
use std::{borrow::Borrow, ops::Deref};
2+
3+
// Use our fake Send/Sync traits when on not parallel compiler,
4+
// so that `OwnedSlice` only implements/requires Send/Sync
5+
// for parallel compiler builds.
6+
use crate::sync::{Send, Sync};
7+
8+
/// An owned slice.
9+
///
10+
/// This is similar to `Box<[u8]>` but allows slicing and using anything as the
11+
/// backing buffer.
12+
///
13+
/// See [`slice_owned`] for `OwnedSlice` construction and examples.
14+
///
15+
/// ---------------------------------------------------------------------------
16+
///
17+
/// This is essentially a replacement for `owning_ref` which is a lot simpler
18+
/// and even sound! 🌸
19+
pub struct OwnedSlice {
20+
/// This is conceptually a `&'self.owner [u8]`.
21+
bytes: *const [u8],
22+
23+
// +---------------------------------------+
24+
// | We expect `dead_code` lint here, |
25+
// | because we don't want to accidentally |
26+
// | touch the owner — otherwise the owner |
27+
// | could invalidate out `bytes` pointer |
28+
// | |
29+
// | so be quiet |
30+
// +----+ +-------------------------------+
31+
// \/
32+
// ⊂(´・◡・⊂ )∘˚˳° (I am the phantom remnant of #97770)
33+
#[expect(dead_code)]
34+
owner: Box<dyn Send + Sync>,
35+
}
36+
37+
/// Makes an [`OwnedSlice`] out of an `owner` and a `slicer` function.
38+
///
39+
/// ## Examples
40+
///
41+
/// ```rust
42+
/// # use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned};
43+
/// let vec = vec![1, 2, 3, 4];
44+
///
45+
/// // Identical to slicing via `&v[1..3]` but produces an owned slice
46+
/// let slice: OwnedSlice = slice_owned(vec, |v| &v[1..3]);
47+
/// assert_eq!(&*slice, [2, 3]);
48+
/// ```
49+
///
50+
/// ```rust
51+
/// # use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned};
52+
/// # use std::ops::Deref;
53+
/// let vec = vec![1, 2, 3, 4];
54+
///
55+
/// // Identical to slicing via `&v[..]` but produces an owned slice
56+
/// let slice: OwnedSlice = slice_owned(vec, Deref::deref);
57+
/// assert_eq!(&*slice, [1, 2, 3, 4]);
58+
/// ```
59+
pub fn slice_owned<O, F>(owner: O, slicer: F) -> OwnedSlice
60+
where
61+
O: Send + Sync + 'static,
62+
F: FnOnce(&O) -> &[u8],
63+
{
64+
try_slice_owned(owner, |x| Ok::<_, !>(slicer(x))).into_ok()
65+
}
66+
67+
/// Makes an [`OwnedSlice`] out of an `owner` and a `slicer` function that can fail.
68+
///
69+
/// See [`slice_owned`] for the infallible version.
70+
pub fn try_slice_owned<O, F, E>(owner: O, slicer: F) -> Result<OwnedSlice, E>
71+
where
72+
O: Send + Sync + 'static,
73+
F: FnOnce(&O) -> Result<&[u8], E>,
74+
{
75+
// We box the owner of the bytes, so it doesn't move.
76+
//
77+
// Since the owner does not move and we don't access it in any way
78+
// before drop, there is nothing that can invalidate the bytes pointer.
79+
//
80+
// Thus, "extending" the lifetime of the reference returned from `F` is fine.
81+
// We pretend that we pass it a reference that lives as long as the returned slice.
82+
//
83+
// N.B. the HRTB on the `slicer` is important — without it the caller could provide
84+
// a short lived slice, unrelated to the owner.
85+
86+
let owner = Box::new(owner);
87+
let bytes = slicer(&*owner)?;
88+
89+
Ok(OwnedSlice { bytes, owner })
90+
}
91+
92+
impl Deref for OwnedSlice {
93+
type Target = [u8];
94+
95+
#[inline]
96+
fn deref(&self) -> &[u8] {
97+
// Safety:
98+
// `self.bytes` is valid per the construction in `slice_owned`
99+
// (which is the only constructor)
100+
unsafe { &*self.bytes }
101+
}
102+
}
103+
104+
impl Borrow<[u8]> for OwnedSlice {
105+
#[inline]
106+
fn borrow(&self) -> &[u8] {
107+
self
108+
}
109+
}
110+
111+
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Send`
112+
unsafe impl Send for OwnedSlice {}
113+
114+
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Sync`
115+
unsafe impl Sync for OwnedSlice {}
116+
117+
#[cfg(test)]
118+
mod tests;
+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
use std::{
2+
ops::Deref,
3+
sync::{
4+
atomic::{self, AtomicBool},
5+
Arc,
6+
},
7+
};
8+
9+
use crate::{
10+
owned_slice::{slice_owned, try_slice_owned, OwnedSlice},
11+
OnDrop,
12+
};
13+
14+
#[test]
15+
fn smoke() {
16+
let slice = slice_owned(vec![1, 2, 3, 4, 5, 6], Vec::as_slice);
17+
18+
assert_eq!(&*slice, [1, 2, 3, 4, 5, 6]);
19+
}
20+
21+
#[test]
22+
fn static_storage() {
23+
let slice = slice_owned(Box::new(String::from("what")), |_| b"bytes boo");
24+
25+
assert_eq!(&*slice, b"bytes boo");
26+
}
27+
28+
#[test]
29+
fn slice_the_slice() {
30+
let slice = slice_owned(vec![1, 2, 3, 4, 5, 6], Vec::as_slice);
31+
let slice = slice_owned(slice, |s| &s[1..][..4]);
32+
let slice = slice_owned(slice, |s| s);
33+
let slice = slice_owned(slice, |s| &s[1..]);
34+
35+
assert_eq!(&*slice, &[1, 2, 3, 4, 5, 6][1..][..4][1..]);
36+
}
37+
38+
#[test]
39+
fn try_and_fail() {
40+
let res = try_slice_owned(vec![0], |v| v.get(12..).ok_or(()));
41+
42+
assert!(res.is_err());
43+
}
44+
45+
#[test]
46+
fn boxed() {
47+
// It's important that we don't cause UB because of `Box`'es uniqueness
48+
49+
let boxed: Box<[u8]> = vec![1, 1, 2, 3, 5, 8, 13, 21].into_boxed_slice();
50+
let slice = slice_owned(boxed, Deref::deref);
51+
52+
assert_eq!(&*slice, [1, 1, 2, 3, 5, 8, 13, 21]);
53+
}
54+
55+
#[test]
56+
fn drop_drops() {
57+
let flag = Arc::new(AtomicBool::new(false));
58+
let flag_prime = Arc::clone(&flag);
59+
let d = OnDrop(move || flag_prime.store(true, atomic::Ordering::Relaxed));
60+
61+
let slice = slice_owned(d, |_| &[]);
62+
63+
assert_eq!(flag.load(atomic::Ordering::Relaxed), false);
64+
65+
drop(slice);
66+
67+
assert_eq!(flag.load(atomic::Ordering::Relaxed), true);
68+
}
69+
70+
#[test]
71+
fn send_sync() {
72+
crate::sync::assert_send::<OwnedSlice>();
73+
crate::sync::assert_sync::<OwnedSlice>();
74+
}

Diff for: compiler/rustc_data_structures/src/owning_ref/LICENSE

-21
This file was deleted.

0 commit comments

Comments
 (0)