Skip to content

Commit 6f9b15c

Browse files
committed
Add tests for tagged pointers
1 parent 5e4577e commit 6f9b15c

File tree

4 files changed

+222
-0
lines changed

4 files changed

+222
-0
lines changed

compiler/rustc_data_structures/src/tagged_ptr/copy.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,3 +203,33 @@ where
203203
self.tag().hash_stable(hcx, hasher);
204204
}
205205
}
206+
207+
/// Test that `new` does not compile if there is not enough alignment for the
208+
/// tag in the pointer.
209+
///
210+
/// ```compile_fail,E0080
211+
/// use rustc_data_structures::tagged_ptr::{CopyTaggedPtr, Tag};
212+
///
213+
/// #[derive(Copy, Clone, Debug, PartialEq, Eq)]
214+
/// enum Tag2 { B00 = 0b00, B01 = 0b01, B10 = 0b10, B11 = 0b11 };
215+
///
216+
/// unsafe impl Tag for Tag2 {
217+
/// const BITS: usize = 2;
218+
///
219+
/// fn into_usize(self) -> usize { todo!() }
220+
/// unsafe fn from_usize(tag: usize) -> Self { todo!() }
221+
/// }
222+
///
223+
/// let value = 12u16;
224+
/// let reference = &value;
225+
/// let tag = Tag2::B01;
226+
///
227+
/// let _ptr = CopyTaggedPtr::<_, _, true>::new(reference, tag);
228+
/// ```
229+
// For some reason miri does not get the compile error
230+
// probably it `check`s instead of `build`ing?
231+
#[cfg(not(miri))]
232+
const _: () = ();
233+
234+
#[cfg(test)]
235+
mod tests;
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
use std::ptr;
2+
3+
use crate::tagged_ptr::{CopyTaggedPtr, Pointer, Tag};
4+
5+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
6+
enum Tag2 {
7+
B00 = 0b00,
8+
B01 = 0b01,
9+
B10 = 0b10,
10+
B11 = 0b11,
11+
}
12+
13+
unsafe impl Tag for Tag2 {
14+
const BITS: usize = 2;
15+
16+
fn into_usize(self) -> usize {
17+
self as _
18+
}
19+
20+
unsafe fn from_usize(tag: usize) -> Self {
21+
const B00: usize = Tag2::B00 as _;
22+
const B01: usize = Tag2::B01 as _;
23+
const B10: usize = Tag2::B10 as _;
24+
const B11: usize = Tag2::B11 as _;
25+
match tag {
26+
B00 => Tag2::B00,
27+
B01 => Tag2::B01,
28+
B10 => Tag2::B10,
29+
B11 => Tag2::B11,
30+
_ => unreachable!(),
31+
}
32+
}
33+
}
34+
35+
#[test]
36+
fn smoke() {
37+
let value = 12u32;
38+
let reference = &value;
39+
let tag = Tag2::B01;
40+
41+
let ptr = tag_ptr(reference, tag);
42+
43+
assert_eq!(ptr.tag(), tag);
44+
assert_eq!(*ptr, 12);
45+
assert!(ptr::eq(ptr.pointer(), reference));
46+
47+
let copy = ptr;
48+
49+
let mut ptr = ptr;
50+
ptr.set_tag(Tag2::B00);
51+
assert_eq!(ptr.tag(), Tag2::B00);
52+
53+
assert_eq!(copy.tag(), tag);
54+
assert_eq!(*copy, 12);
55+
assert!(ptr::eq(copy.pointer(), reference));
56+
}
57+
58+
/// Helper to create tagged pointers without specifying `COMPARE_PACKED` if it does not matter.
59+
fn tag_ptr<P: Pointer, T: Tag>(ptr: P, tag: T) -> CopyTaggedPtr<P, T, true> {
60+
CopyTaggedPtr::new(ptr, tag)
61+
}

compiler/rustc_data_structures/src/tagged_ptr/drop.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,33 @@ where
134134
self.raw.hash_stable(hcx, hasher);
135135
}
136136
}
137+
138+
/// Test that `new` does not compile if there is not enough alignment for the
139+
/// tag in the pointer.
140+
///
141+
/// ```compile_fail,E0080
142+
/// use rustc_data_structures::tagged_ptr::{TaggedPtr, Tag};
143+
///
144+
/// #[derive(Copy, Clone, Debug, PartialEq, Eq)]
145+
/// enum Tag2 { B00 = 0b00, B01 = 0b01, B10 = 0b10, B11 = 0b11 };
146+
///
147+
/// unsafe impl Tag for Tag2 {
148+
/// const BITS: usize = 2;
149+
///
150+
/// fn into_usize(self) -> usize { todo!() }
151+
/// unsafe fn from_usize(tag: usize) -> Self { todo!() }
152+
/// }
153+
///
154+
/// let value = 12u16;
155+
/// let reference = &value;
156+
/// let tag = Tag2::B01;
157+
///
158+
/// let _ptr = TaggedPtr::<_, _, true>::new(reference, tag);
159+
/// ```
160+
// For some reason miri does not get the compile error
161+
// probably it `check`s instead of `build`ing?
162+
#[cfg(not(miri))]
163+
const _: () = ();
164+
165+
#[cfg(test)]
166+
mod tests;
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
use std::{ptr, sync::Arc};
2+
3+
use crate::tagged_ptr::{Pointer, Tag, TaggedPtr};
4+
5+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
6+
enum Tag2 {
7+
B00 = 0b00,
8+
B01 = 0b01,
9+
B10 = 0b10,
10+
B11 = 0b11,
11+
}
12+
13+
unsafe impl Tag for Tag2 {
14+
const BITS: usize = 2;
15+
16+
fn into_usize(self) -> usize {
17+
self as _
18+
}
19+
20+
unsafe fn from_usize(tag: usize) -> Self {
21+
const B00: usize = Tag2::B00 as _;
22+
const B01: usize = Tag2::B01 as _;
23+
const B10: usize = Tag2::B10 as _;
24+
const B11: usize = Tag2::B11 as _;
25+
match tag {
26+
B00 => Tag2::B00,
27+
B01 => Tag2::B01,
28+
B10 => Tag2::B10,
29+
B11 => Tag2::B11,
30+
_ => unreachable!(),
31+
}
32+
}
33+
}
34+
35+
#[test]
36+
fn smoke() {
37+
let value = 12u32;
38+
let reference = &value;
39+
let tag = Tag2::B01;
40+
41+
let ptr = tag_ptr(reference, tag);
42+
43+
assert_eq!(ptr.tag(), tag);
44+
assert_eq!(*ptr, 12);
45+
46+
let clone = ptr.clone();
47+
assert_eq!(clone.tag(), tag);
48+
assert_eq!(*clone, 12);
49+
50+
let mut ptr = ptr;
51+
ptr.set_tag(Tag2::B00);
52+
assert_eq!(ptr.tag(), Tag2::B00);
53+
54+
assert_eq!(clone.tag(), tag);
55+
assert_eq!(*clone, 12);
56+
assert!(ptr::eq(&*ptr, &*clone))
57+
}
58+
59+
#[test]
60+
fn boxed() {
61+
let value = 12u32;
62+
let boxed = Box::new(value);
63+
let tag = Tag2::B01;
64+
65+
let ptr = tag_ptr(boxed, tag);
66+
67+
assert_eq!(ptr.tag(), tag);
68+
assert_eq!(*ptr, 12);
69+
70+
let clone = ptr.clone();
71+
assert_eq!(clone.tag(), tag);
72+
assert_eq!(*clone, 12);
73+
74+
let mut ptr = ptr;
75+
ptr.set_tag(Tag2::B00);
76+
assert_eq!(ptr.tag(), Tag2::B00);
77+
78+
assert_eq!(clone.tag(), tag);
79+
assert_eq!(*clone, 12);
80+
assert!(!ptr::eq(&*ptr, &*clone))
81+
}
82+
83+
#[test]
84+
fn arclones() {
85+
let value = 12u32;
86+
let arc = Arc::new(value);
87+
let tag = Tag2::B01;
88+
89+
let ptr = tag_ptr(arc, tag);
90+
91+
assert_eq!(ptr.tag(), tag);
92+
assert_eq!(*ptr, 12);
93+
94+
let clone = ptr.clone();
95+
assert!(ptr::eq(&*ptr, &*clone))
96+
}
97+
98+
/// Helper to create tagged pointers without specifying `COMPARE_PACKED` if it does not matter.
99+
fn tag_ptr<P: Pointer, T: Tag>(ptr: P, tag: T) -> TaggedPtr<P, T, true> {
100+
TaggedPtr::new(ptr, tag)
101+
}

0 commit comments

Comments
 (0)