From d6fc3e176eb0a015e9911a60fc1a5e0b6103416a Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 18 May 2018 15:16:57 +0200 Subject: [PATCH 1/2] Make `[T]::len` and `str::len` const fn --- src/libcore/lib.rs | 3 +++ src/libcore/slice/mod.rs | 32 +++++++++++++++++++++----------- src/libcore/str/mod.rs | 20 +++++++++++++++----- src/test/ui/const-eval/strlen.rs | 26 ++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 16 deletions(-) create mode 100644 src/test/ui/const-eval/strlen.rs diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 77b5488084d99..d37629ced11db 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 3b19a401859ee..b453edcb4e193 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 { - pub data: *const T, - pub len: usize, +union Repr<'a, T: 'a> { + rust: &'a [T], + rust_mut: &'a mut [T], + raw: FatPtr, +} + +#[repr(C)] +struct FatPtr { + data: *const T, + len: usize, } // @@ -119,9 +126,10 @@ impl [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>(self).len + Repr { rust: self }.raw.len } } @@ -135,7 +143,8 @@ impl [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] { /// ``` #[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 82bead0ab4676..70aaf10f4213e 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 0000000000000..bdadf5dd5e14a --- /dev/null +++ b/src/test/ui/const-eval/strlen.rs @@ -0,0 +1,26 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass + +#![feature(const_str_len, const_str_as_bytes)] + +#![crate_type = "lib"] + +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 +} From 2788f66ab079e76ee5c73ba1651103c557be7a61 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 20 May 2018 20:25:28 +0200 Subject: [PATCH 2/2] Add some runtime sanity checks --- src/test/ui/const-eval/strlen.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/test/ui/const-eval/strlen.rs b/src/test/ui/const-eval/strlen.rs index bdadf5dd5e14a..dfa41c491fa89 100644 --- a/src/test/ui/const-eval/strlen.rs +++ b/src/test/ui/const-eval/strlen.rs @@ -8,12 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-pass +// run-pass #![feature(const_str_len, const_str_as_bytes)] -#![crate_type = "lib"] - const S: &str = "foo"; pub const B: &[u8] = S.as_bytes(); @@ -24,3 +22,12 @@ pub fn foo() -> [u8; S.len()] { } 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"); +}