about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorDylan DPC <dylan.dpc@gmail.com>2020-04-26 21:02:32 +0200
committerGitHub <noreply@github.com>2020-04-26 21:02:32 +0200
commit398d3eeca1f6cb84f91275826d66548c75e8fac0 (patch)
tree73b5d8aa93f4b3fc06ae7fd9b22b7fc02f3ac7d2 /src
parent7f3b3df9e2f2efe3434b4f6fc76462d2c8ad332f (diff)
parent0228ca0c7d07f92d449209fa2eeda9eb72e68f63 (diff)
downloadrust-398d3eeca1f6cb84f91275826d66548c75e8fac0.tar.gz
rust-398d3eeca1f6cb84f91275826d66548c75e8fac0.zip
Rollup merge of #71421 - elichai:2020-04-boxed-slice, r=sfackler
Add a function to turn Box<T> into Box<[T]>

Hi,
I think this is very useful, as currently it's not possible in safe rust to do this without re-allocating.
an alternative implementation of the same function can be:
```rust
pub fn into_boxed_slice<T>(boxed: Box<T>) -> Box<[T]> {
    unsafe {
        let slice = slice::from_raw_parts_mut(Box::into_raw(boxed), 1);
        Box::from_raw(slice)
    }
}
```

The only thing that makes me a little uncomfortable is this line :
> The alignment of array types is greater or equal to the alignment of its element type

from https://rust-lang.github.io/unsafe-code-guidelines/layout/arrays-and-slices.html

But then I see:
> The alignment of &T, &mut T, *const T and *mut T are the same, and are at least the word size.
> The alignment of &[T] is the word size.

from https://rust-lang.github.io/unsafe-code-guidelines/layout/pointers.html#representation

So I do believe this is valid(FWIW it also passes in miri https://play.rust-lang.org/?gist=c002b99364ee6b29862aeb3565a91c19)
Diffstat (limited to 'src')
-rw-r--r--src/liballoc/boxed.rs10
-rw-r--r--src/test/ui/box-into-boxed-slice-fail.rs15
-rw-r--r--src/test/ui/box-into-boxed-slice-fail.stderr43
-rw-r--r--src/test/ui/box-into-boxed-slice.rs11
4 files changed, 79 insertions, 0 deletions
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs
index 3d657396a9f..b3a771a721d 100644
--- a/src/liballoc/boxed.rs
+++ b/src/liballoc/boxed.rs
@@ -239,6 +239,16 @@ impl<T> Box<T> {
     pub fn pin(x: T) -> Pin<Box<T>> {
         (box x).into()
     }
+
+    /// Converts a `Box<T>` into a `Box<[T]>`
+    ///
+    /// This conversion does not allocate on the heap and happens in place.
+    ///
+    #[unstable(feature = "box_into_boxed_slice", issue = "71582")]
+    pub fn into_boxed_slice(boxed: Box<T>) -> Box<[T]> {
+        // *mut T and *mut [T; 1] have the same size and alignment
+        unsafe { Box::from_raw(Box::into_raw(boxed) as *mut [T; 1] as *mut [T]) }
+    }
 }
 
 impl<T> Box<[T]> {
diff --git a/src/test/ui/box-into-boxed-slice-fail.rs b/src/test/ui/box-into-boxed-slice-fail.rs
new file mode 100644
index 00000000000..5f8a3fd9d6a
--- /dev/null
+++ b/src/test/ui/box-into-boxed-slice-fail.rs
@@ -0,0 +1,15 @@
+// ignore-tidy-linelength
+#![feature(box_into_boxed_slice)]
+
+use std::boxed::Box;
+use std::fmt::Debug;
+fn main() {
+    let boxed_slice = Box::new([1,2,3]) as Box<[u8]>;
+    let _ = Box::into_boxed_slice(boxed_slice);
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    //~^^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    let boxed_trait: Box<dyn Debug> = Box::new(5u8);
+    let _ = Box::into_boxed_slice(boxed_trait);
+    //~^ ERROR the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time
+    //~^^ ERROR the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time
+}
diff --git a/src/test/ui/box-into-boxed-slice-fail.stderr b/src/test/ui/box-into-boxed-slice-fail.stderr
new file mode 100644
index 00000000000..dfc4999958a
--- /dev/null
+++ b/src/test/ui/box-into-boxed-slice-fail.stderr
@@ -0,0 +1,43 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/box-into-boxed-slice-fail.rs:8:35
+   |
+LL |     let _ = Box::into_boxed_slice(boxed_slice);
+   |                                   ^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `[u8]`
+   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+   = note: required by `std::boxed::Box::<T>::into_boxed_slice`
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/box-into-boxed-slice-fail.rs:8:13
+   |
+LL |     let _ = Box::into_boxed_slice(boxed_slice);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `[u8]`
+   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+   = note: slice and array elements must have `Sized` type
+
+error[E0277]: the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time
+  --> $DIR/box-into-boxed-slice-fail.rs:12:35
+   |
+LL |     let _ = Box::into_boxed_slice(boxed_trait);
+   |                                   ^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `dyn std::fmt::Debug`
+   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+   = note: required by `std::boxed::Box::<T>::into_boxed_slice`
+
+error[E0277]: the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time
+  --> $DIR/box-into-boxed-slice-fail.rs:12:13
+   |
+LL |     let _ = Box::into_boxed_slice(boxed_trait);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `dyn std::fmt::Debug`
+   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+   = note: slice and array elements must have `Sized` type
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/box-into-boxed-slice.rs b/src/test/ui/box-into-boxed-slice.rs
new file mode 100644
index 00000000000..61b3d915253
--- /dev/null
+++ b/src/test/ui/box-into-boxed-slice.rs
@@ -0,0 +1,11 @@
+// run-pass
+#![feature(box_into_boxed_slice)]
+
+use std::boxed::Box;
+fn main() {
+    assert_eq!(Box::into_boxed_slice(Box::new(5u8)), Box::new([5u8]) as Box<[u8]>);
+    assert_eq!(Box::into_boxed_slice(Box::new([25u8])), Box::new([[25u8]]) as Box<[[u8; 1]]>);
+    let a: Box<[Box<[u8; 1]>]> = Box::into_boxed_slice(Box::new(Box::new([5u8])));
+    let b: Box<[Box<[u8; 1]>]> = Box::new([Box::new([5u8])]);
+    assert_eq!(a, b);
+}