Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 9051331

Browse files
committed
Lift Pointer's requirement for the pointer to be thin
fat pointers rule!
1 parent 26232f1 commit 9051331

File tree

5 files changed

+58
-33
lines changed

5 files changed

+58
-33
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use std::mem;
2+
3+
/// Returns the ABI-required minimum alignment of a type in bytes.
4+
///
5+
/// This is equivalent to [`mem::align_of`], but also works for some unsized
6+
/// types (e.g. slices or rustc's `List`s).
7+
pub const fn align_of<T: ?Sized + Aligned>() -> usize {
8+
T::ALIGN
9+
}
10+
11+
/// A type with a statically known alignment.
12+
///
13+
/// # Safety
14+
///
15+
/// `Self::ALIGN` must be equal to the alignment of `Self`. For sized types it
16+
/// is [`mem::align_of<Self>()`], for unsized types it depends on the type, for
17+
/// example `[T]` has alignment of `T`.
18+
///
19+
/// [`mem::align_of<Self>()`]: mem::align_of
20+
pub unsafe trait Aligned {
21+
/// Alignment of `Self`.
22+
const ALIGN: usize;
23+
}
24+
25+
unsafe impl<T> Aligned for T {
26+
const ALIGN: usize = mem::align_of::<Self>();
27+
}
28+
29+
unsafe impl<T> Aligned for [T] {
30+
const ALIGN: usize = mem::align_of::<T>();
31+
}

compiler/rustc_data_structures/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ pub mod transitive_relation;
8383
pub mod vec_linked_list;
8484
pub mod work_queue;
8585
pub use atomic_ref::AtomicRef;
86+
pub mod aligned;
8687
pub mod frozen;
8788
pub mod owned_slice;
8889
pub mod sso;

compiler/rustc_data_structures/src/tagged_ptr.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313
//! The tag must implement the `Tag` trait. We assert that the tag and `Pointer`
1414
//! are compatible at compile time.
1515
16-
use std::mem::{self, ManuallyDrop};
16+
use std::mem::ManuallyDrop;
1717
use std::ops::Deref;
1818
use std::ptr::NonNull;
1919
use std::rc::Rc;
2020
use std::sync::Arc;
2121

22+
use crate::aligned::Aligned;
23+
2224
mod copy;
2325
mod drop;
2426

@@ -31,8 +33,7 @@ pub use drop::TaggedPtr;
3133
/// # Safety
3234
///
3335
/// The pointer returned from [`into_ptr`] must be a [valid], pointer to
34-
/// [`<Self as Deref>::Target`]. Note that pointers to [`Self::Target`] must be
35-
/// thin, even though [`Self::Target`] may not be `Sized`.
36+
/// [`<Self as Deref>::Target`].
3637
///
3738
/// Note that if `Self` implements [`DerefMut`] the pointer returned from
3839
/// [`into_ptr`] must be valid for writes (and thus calling [`NonNull::as_mut`]
@@ -110,7 +111,7 @@ pub unsafe trait Tag: Copy {
110111
unsafe fn from_usize(tag: usize) -> Self;
111112
}
112113

113-
unsafe impl<T> Pointer for Box<T> {
114+
unsafe impl<T: ?Sized + Aligned> Pointer for Box<T> {
114115
const BITS: usize = bits_for::<Self::Target>();
115116

116117
#[inline]
@@ -130,7 +131,7 @@ unsafe impl<T> Pointer for Box<T> {
130131
}
131132
}
132133

133-
unsafe impl<T> Pointer for Rc<T> {
134+
unsafe impl<T: ?Sized + Aligned> Pointer for Rc<T> {
134135
const BITS: usize = bits_for::<Self::Target>();
135136

136137
#[inline]
@@ -149,7 +150,7 @@ unsafe impl<T> Pointer for Rc<T> {
149150
}
150151
}
151152

152-
unsafe impl<T> Pointer for Arc<T> {
153+
unsafe impl<T: ?Sized + Aligned> Pointer for Arc<T> {
153154
const BITS: usize = bits_for::<Self::Target>();
154155

155156
#[inline]
@@ -168,7 +169,7 @@ unsafe impl<T> Pointer for Arc<T> {
168169
}
169170
}
170171

171-
unsafe impl<'a, T: 'a> Pointer for &'a T {
172+
unsafe impl<'a, T: 'a + ?Sized + Aligned> Pointer for &'a T {
172173
const BITS: usize = bits_for::<Self::Target>();
173174

174175
#[inline]
@@ -186,7 +187,7 @@ unsafe impl<'a, T: 'a> Pointer for &'a T {
186187
}
187188
}
188189

189-
unsafe impl<'a, T: 'a> Pointer for &'a mut T {
190+
unsafe impl<'a, T: 'a + ?Sized + Aligned> Pointer for &'a mut T {
190191
const BITS: usize = bits_for::<Self::Target>();
191192

192193
#[inline]
@@ -206,8 +207,8 @@ unsafe impl<'a, T: 'a> Pointer for &'a mut T {
206207

207208
/// Returns the number of bits available for use for tags in a pointer to `T`
208209
/// (this is based on `T`'s alignment).
209-
pub const fn bits_for<T>() -> usize {
210-
let bits = mem::align_of::<T>().trailing_zeros();
210+
pub const fn bits_for<T: ?Sized + Aligned>() -> usize {
211+
let bits = crate::aligned::align_of::<T>().trailing_zeros();
211212

212213
// This is a replacement for `.try_into().unwrap()` unavailable in `const`
213214
// (it's fine to make an assert here, since this is only called in compile time)

compiler/rustc_data_structures/src/tagged_ptr/copy.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,7 @@ where
5555
}
5656

5757
const TAG_BIT_SHIFT: usize = usize::BITS as usize - T::BITS;
58-
const ASSERTION: () = {
59-
assert!(T::BITS <= P::BITS);
60-
// Used for the transmute_copy's below
61-
// TODO(waffle): do we need this assert anymore?
62-
assert!(std::mem::size_of::<&P::Target>() == std::mem::size_of::<usize>());
63-
};
58+
const ASSERTION: () = { assert!(T::BITS <= P::BITS) };
6459

6560
/// Pack pointer `ptr` that comes from [`P::into_ptr`] with a `tag`.
6661
///

compiler/rustc_middle/src/ty/list.rs

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::arena::Arena;
2-
use rustc_data_structures::tagged_ptr::bits_for;
2+
use rustc_data_structures::aligned::Aligned;
33
use rustc_serialize::{Encodable, Encoder};
44
use std::alloc::Layout;
55
use std::cmp::Ordering;
@@ -8,7 +8,7 @@ use std::hash::{Hash, Hasher};
88
use std::iter;
99
use std::mem;
1010
use std::ops::Deref;
11-
use std::ptr::{self, NonNull};
11+
use std::ptr;
1212
use std::slice;
1313

1414
/// `List<T>` is a bit like `&[T]`, but with some critical differences.
@@ -199,20 +199,17 @@ impl<'a, T: Copy> IntoIterator for &'a List<T> {
199199

200200
unsafe impl<T: Sync> Sync for List<T> {}
201201

202-
unsafe impl<'a, T: 'a> rustc_data_structures::tagged_ptr::Pointer for &'a List<T> {
203-
const BITS: usize = bits_for::<usize>();
204-
205-
#[inline]
206-
fn into_ptr(self) -> NonNull<List<T>> {
207-
NonNull::from(self)
208-
}
209-
210-
#[inline]
211-
unsafe fn from_ptr(ptr: NonNull<List<T>>) -> &'a List<T> {
212-
ptr.as_ref()
213-
}
202+
// Safety:
203+
// Layouts of `Equivalent<T>` and `List<T>` are the same, modulo opaque tail,
204+
// thus aligns of `Equivalent<T>` and `List<T>` must be the same.
205+
unsafe impl<T> Aligned for List<T> {
206+
const ALIGN: usize = {
207+
#[repr(C)]
208+
struct Equivalent<T> {
209+
_len: usize,
210+
_data: [T; 0],
211+
}
214212

215-
unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: NonNull<List<T>>, f: F) -> R {
216-
f(&ptr.as_ref())
217-
}
213+
mem::align_of::<Equivalent<T>>()
214+
};
218215
}

0 commit comments

Comments
 (0)