about summary refs log tree commit diff
diff options
context:
space:
mode:
authorkennytm <kennytm@gmail.com>2018-05-23 00:26:10 +0800
committerGitHub <noreply@github.com>2018-05-23 00:26:10 +0800
commite7e3261121c2a600da27d89906c8734d8a346852 (patch)
treed3b50b473b01e1a2361828d530d8ca805237fa71
parenteb92280287ff15e6683a7a32cd1c52f4a0493501 (diff)
parent2788f66ab079e76ee5c73ba1651103c557be7a61 (diff)
downloadrust-e7e3261121c2a600da27d89906c8734d8a346852.tar.gz
rust-e7e3261121c2a600da27d89906c8734d8a346852.zip
Rollup merge of #50863 - oli-obk:const_len, r=SimonSapin,Gankro
Make `[T]::len` and `str::len` const fn

r? @Gankro
-rw-r--r--src/libcore/lib.rs3
-rw-r--r--src/libcore/slice/mod.rs32
-rw-r--r--src/libcore/str/mod.rs20
-rw-r--r--src/test/ui/const-eval/strlen.rs33
4 files changed, 72 insertions, 16 deletions
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 77b5488084d..d37629ced11 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -119,6 +119,9 @@
 #![feature(powerpc_target_feature)]
 #![feature(mips_target_feature)]
 #![feature(aarch64_target_feature)]
+#![feature(const_slice_len)]
+#![feature(const_str_as_bytes)]
+#![feature(const_str_len)]
 
 #[prelude_import]
 #[allow(unused)]
diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
index 3b19a401859..b453edcb4e1 100644
--- a/src/libcore/slice/mod.rs
+++ b/src/libcore/slice/mod.rs
@@ -59,9 +59,16 @@ mod rotate;
 mod sort;
 
 #[repr(C)]
-struct Repr<T> {
-    pub data: *const T,
-    pub len: usize,
+union Repr<'a, T: 'a> {
+    rust: &'a [T],
+    rust_mut: &'a mut [T],
+    raw: FatPtr<T>,
+}
+
+#[repr(C)]
+struct FatPtr<T> {
+    data: *const T,
+    len: usize,
 }
 
 //
@@ -119,9 +126,10 @@ impl<T> [T] {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn len(&self) -> usize {
+    #[rustc_const_unstable(feature = "const_slice_len")]
+    pub const fn len(&self) -> usize {
         unsafe {
-            mem::transmute::<&[T], Repr<T>>(self).len
+            Repr { rust: self }.raw.len
         }
     }
 
@@ -135,7 +143,8 @@ impl<T> [T] {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn is_empty(&self) -> bool {
+    #[rustc_const_unstable(feature = "const_slice_len")]
+    pub const fn is_empty(&self) -> bool {
         self.len() == 0
     }
 
@@ -418,7 +427,8 @@ impl<T> [T] {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn as_ptr(&self) -> *const T {
+    #[rustc_const_unstable(feature = "const_slice_as_ptr")]
+    pub const fn as_ptr(&self) -> *const T {
         self as *const [T] as *const T
     }
 
@@ -3856,8 +3866,8 @@ unsafe impl<'a, T> TrustedRandomAccess for ExactChunksMut<'a, T> {
 /// ```
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
-pub unsafe fn from_raw_parts<'a, T>(p: *const T, len: usize) -> &'a [T] {
-    mem::transmute(Repr { data: p, len: len })
+pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
+    Repr { raw: FatPtr { data, len } }.rust
 }
 
 /// Performs the same functionality as `from_raw_parts`, except that a mutable
@@ -3869,8 +3879,8 @@ pub unsafe fn from_raw_parts<'a, T>(p: *const T, len: usize) -> &'a [T] {
 /// `from_raw_parts`.
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
-pub unsafe fn from_raw_parts_mut<'a, T>(p: *mut T, len: usize) -> &'a mut [T] {
-    mem::transmute(Repr { data: p, len: len })
+pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
+    Repr { raw: FatPtr { data, len} }.rust_mut
 }
 
 /// Converts a reference to T into a slice of length 1 (without copying).
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index 82bead0ab46..70aaf10f421 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -2166,7 +2166,8 @@ impl str {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn len(&self) -> usize {
+    #[rustc_const_unstable(feature = "const_str_len")]
+    pub const fn len(&self) -> usize {
         self.as_bytes().len()
     }
 
@@ -2185,7 +2186,8 @@ impl str {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn is_empty(&self) -> bool {
+    #[rustc_const_unstable(feature = "const_str_len")]
+    pub const fn is_empty(&self) -> bool {
         self.len() == 0
     }
 
@@ -2242,8 +2244,15 @@ impl str {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline(always)]
-    pub fn as_bytes(&self) -> &[u8] {
-        unsafe { &*(self as *const str as *const [u8]) }
+    #[rustc_const_unstable(feature="const_str_as_bytes")]
+    pub const fn as_bytes(&self) -> &[u8] {
+        unsafe {
+            union Slices<'a> {
+                str: &'a str,
+                slice: &'a [u8],
+            }
+            Slices { str: self }.slice
+        }
     }
 
     /// Converts a mutable string slice to a mutable byte slice. To convert the
@@ -2303,7 +2312,8 @@ impl str {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn as_ptr(&self) -> *const u8 {
+    #[rustc_const_unstable(feature = "const_str_as_ptr")]
+    pub const fn as_ptr(&self) -> *const u8 {
         self as *const str as *const u8
     }
 
diff --git a/src/test/ui/const-eval/strlen.rs b/src/test/ui/const-eval/strlen.rs
new file mode 100644
index 00000000000..dfa41c491fa
--- /dev/null
+++ b/src/test/ui/const-eval/strlen.rs
@@ -0,0 +1,33 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-pass
+
+#![feature(const_str_len, const_str_as_bytes)]
+
+const S: &str = "foo";
+pub const B: &[u8] = S.as_bytes();
+
+pub fn foo() -> [u8; S.len()] {
+    let mut buf = [0; S.len()];
+    for (i, &c) in S.as_bytes().iter().enumerate() {
+        buf[i] = c;
+    }
+    buf
+}
+
+fn main() {
+    assert_eq!(&foo()[..], b"foo");
+    assert_eq!(foo().len(), S.len());
+    const LEN: usize = S.len();
+    assert_eq!(LEN, S.len());
+    assert_eq!(B, foo());
+    assert_eq!(B, b"foo");
+}