about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr/copy.rs30
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs61
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr/drop.rs30
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr/drop/tests.rs101
4 files changed, 222 insertions, 0 deletions
diff --git a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
index 90500b2de89..aebf24ebbde 100644
--- a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
+++ b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
@@ -203,3 +203,33 @@ where
         self.tag().hash_stable(hcx, hasher);
     }
 }
+
+/// Test that `new` does not compile if there is not enough alignment for the
+/// tag in the pointer.
+///
+/// ```compile_fail,E0080
+/// use rustc_data_structures::tagged_ptr::{CopyTaggedPtr, Tag};
+///
+/// #[derive(Copy, Clone, Debug, PartialEq, Eq)]
+/// enum Tag2 { B00 = 0b00, B01 = 0b01, B10 = 0b10, B11 = 0b11 };
+///
+/// unsafe impl Tag for Tag2 {
+///     const BITS: usize = 2;
+///
+///     fn into_usize(self) -> usize { todo!() }
+///     unsafe fn from_usize(tag: usize) -> Self { todo!() }
+/// }
+///
+/// let value = 12u16;
+/// let reference = &value;
+/// let tag = Tag2::B01;
+///
+/// let _ptr = CopyTaggedPtr::<_, _, true>::new(reference, tag);
+/// ```
+// For some reason miri does not get the compile error
+// probably it `check`s instead of `build`ing?
+#[cfg(not(miri))]
+const _: () = ();
+
+#[cfg(test)]
+mod tests;
diff --git a/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs
new file mode 100644
index 00000000000..77544f9c032
--- /dev/null
+++ b/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs
@@ -0,0 +1,61 @@
+use std::ptr;
+
+use crate::tagged_ptr::{CopyTaggedPtr, Pointer, Tag};
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum Tag2 {
+    B00 = 0b00,
+    B01 = 0b01,
+    B10 = 0b10,
+    B11 = 0b11,
+}
+
+unsafe impl Tag for Tag2 {
+    const BITS: usize = 2;
+
+    fn into_usize(self) -> usize {
+        self as _
+    }
+
+    unsafe fn from_usize(tag: usize) -> Self {
+        const B00: usize = Tag2::B00 as _;
+        const B01: usize = Tag2::B01 as _;
+        const B10: usize = Tag2::B10 as _;
+        const B11: usize = Tag2::B11 as _;
+        match tag {
+            B00 => Tag2::B00,
+            B01 => Tag2::B01,
+            B10 => Tag2::B10,
+            B11 => Tag2::B11,
+            _ => unreachable!(),
+        }
+    }
+}
+
+#[test]
+fn smoke() {
+    let value = 12u32;
+    let reference = &value;
+    let tag = Tag2::B01;
+
+    let ptr = tag_ptr(reference, tag);
+
+    assert_eq!(ptr.tag(), tag);
+    assert_eq!(*ptr, 12);
+    assert!(ptr::eq(ptr.pointer(), reference));
+
+    let copy = ptr;
+
+    let mut ptr = ptr;
+    ptr.set_tag(Tag2::B00);
+    assert_eq!(ptr.tag(), Tag2::B00);
+
+    assert_eq!(copy.tag(), tag);
+    assert_eq!(*copy, 12);
+    assert!(ptr::eq(copy.pointer(), reference));
+}
+
+/// Helper to create tagged pointers without specifying `COMPARE_PACKED` if it does not matter.
+fn tag_ptr<P: Pointer, T: Tag>(ptr: P, tag: T) -> CopyTaggedPtr<P, T, true> {
+    CopyTaggedPtr::new(ptr, tag)
+}
diff --git a/compiler/rustc_data_structures/src/tagged_ptr/drop.rs b/compiler/rustc_data_structures/src/tagged_ptr/drop.rs
index de253a0b255..286951ce0e9 100644
--- a/compiler/rustc_data_structures/src/tagged_ptr/drop.rs
+++ b/compiler/rustc_data_structures/src/tagged_ptr/drop.rs
@@ -134,3 +134,33 @@ where
         self.raw.hash_stable(hcx, hasher);
     }
 }
+
+/// Test that `new` does not compile if there is not enough alignment for the
+/// tag in the pointer.
+///
+/// ```compile_fail,E0080
+/// use rustc_data_structures::tagged_ptr::{TaggedPtr, Tag};
+///
+/// #[derive(Copy, Clone, Debug, PartialEq, Eq)]
+/// enum Tag2 { B00 = 0b00, B01 = 0b01, B10 = 0b10, B11 = 0b11 };
+///
+/// unsafe impl Tag for Tag2 {
+///     const BITS: usize = 2;
+///
+///     fn into_usize(self) -> usize { todo!() }
+///     unsafe fn from_usize(tag: usize) -> Self { todo!() }
+/// }
+///
+/// let value = 12u16;
+/// let reference = &value;
+/// let tag = Tag2::B01;
+///
+/// let _ptr = TaggedPtr::<_, _, true>::new(reference, tag);
+/// ```
+// For some reason miri does not get the compile error
+// probably it `check`s instead of `build`ing?
+#[cfg(not(miri))]
+const _: () = ();
+
+#[cfg(test)]
+mod tests;
diff --git a/compiler/rustc_data_structures/src/tagged_ptr/drop/tests.rs b/compiler/rustc_data_structures/src/tagged_ptr/drop/tests.rs
new file mode 100644
index 00000000000..0c61cebaf7e
--- /dev/null
+++ b/compiler/rustc_data_structures/src/tagged_ptr/drop/tests.rs
@@ -0,0 +1,101 @@
+use std::{ptr, sync::Arc};
+
+use crate::tagged_ptr::{Pointer, Tag, TaggedPtr};
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum Tag2 {
+    B00 = 0b00,
+    B01 = 0b01,
+    B10 = 0b10,
+    B11 = 0b11,
+}
+
+unsafe impl Tag for Tag2 {
+    const BITS: usize = 2;
+
+    fn into_usize(self) -> usize {
+        self as _
+    }
+
+    unsafe fn from_usize(tag: usize) -> Self {
+        const B00: usize = Tag2::B00 as _;
+        const B01: usize = Tag2::B01 as _;
+        const B10: usize = Tag2::B10 as _;
+        const B11: usize = Tag2::B11 as _;
+        match tag {
+            B00 => Tag2::B00,
+            B01 => Tag2::B01,
+            B10 => Tag2::B10,
+            B11 => Tag2::B11,
+            _ => unreachable!(),
+        }
+    }
+}
+
+#[test]
+fn smoke() {
+    let value = 12u32;
+    let reference = &value;
+    let tag = Tag2::B01;
+
+    let ptr = tag_ptr(reference, tag);
+
+    assert_eq!(ptr.tag(), tag);
+    assert_eq!(*ptr, 12);
+
+    let clone = ptr.clone();
+    assert_eq!(clone.tag(), tag);
+    assert_eq!(*clone, 12);
+
+    let mut ptr = ptr;
+    ptr.set_tag(Tag2::B00);
+    assert_eq!(ptr.tag(), Tag2::B00);
+
+    assert_eq!(clone.tag(), tag);
+    assert_eq!(*clone, 12);
+    assert!(ptr::eq(&*ptr, &*clone))
+}
+
+#[test]
+fn boxed() {
+    let value = 12u32;
+    let boxed = Box::new(value);
+    let tag = Tag2::B01;
+
+    let ptr = tag_ptr(boxed, tag);
+
+    assert_eq!(ptr.tag(), tag);
+    assert_eq!(*ptr, 12);
+
+    let clone = ptr.clone();
+    assert_eq!(clone.tag(), tag);
+    assert_eq!(*clone, 12);
+
+    let mut ptr = ptr;
+    ptr.set_tag(Tag2::B00);
+    assert_eq!(ptr.tag(), Tag2::B00);
+
+    assert_eq!(clone.tag(), tag);
+    assert_eq!(*clone, 12);
+    assert!(!ptr::eq(&*ptr, &*clone))
+}
+
+#[test]
+fn arclones() {
+    let value = 12u32;
+    let arc = Arc::new(value);
+    let tag = Tag2::B01;
+
+    let ptr = tag_ptr(arc, tag);
+
+    assert_eq!(ptr.tag(), tag);
+    assert_eq!(*ptr, 12);
+
+    let clone = ptr.clone();
+    assert!(ptr::eq(&*ptr, &*clone))
+}
+
+/// Helper to create tagged pointers without specifying `COMPARE_PACKED` if it does not matter.
+fn tag_ptr<P: Pointer, T: Tag>(ptr: P, tag: T) -> TaggedPtr<P, T, true> {
+    TaggedPtr::new(ptr, tag)
+}