From ba4c4988161abbe58e973b792c7e271785b4bc4d Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sat, 29 Aug 2020 18:25:17 +0800 Subject: [PATCH 01/17] Add more info for Vec Drain doc See its documentation for more --- library/alloc/src/vec.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index b4ad238680f79..f6b2b3f1d23ce 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -2785,6 +2785,7 @@ unsafe impl<#[may_dangle] T> Drop for IntoIter { /// A draining iterator for `Vec`. /// /// This `struct` is created by [`Vec::drain`]. +/// See its documentation for more. #[stable(feature = "drain", since = "1.6.0")] pub struct Drain<'a, T: 'a> { /// Index of tail to preserve From 71484121001b69aefdc41fd7192b7095250517a7 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sat, 29 Aug 2020 18:57:49 +0800 Subject: [PATCH 02/17] Vec slice example fix style and show type elision --- library/alloc/src/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index b4ad238680f79..d39b6b701e6d8 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -171,7 +171,7 @@ use crate::raw_vec::RawVec; /// /// // ... and that's all! /// // you can also do it like this: -/// let x : &[usize] = &v; +/// let u: &[usize] = &v; // or &[_] /// ``` /// /// In Rust, it's more common to pass slices as arguments rather than vectors From a80d39041e2d5cd58a846c9ef9e01ee9d691a7ed Mon Sep 17 00:00:00 2001 From: Howard Su Date: Thu, 3 Sep 2020 06:31:21 +0800 Subject: [PATCH 03/17] Use inline(never) instead of cold inline(never) is better way to avoid optimizer to inline the function instead of cold. --- library/std/src/thread/local.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 9d8c6f1815eeb..60a05dc5d545b 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -424,10 +424,9 @@ pub mod fast { // thread_local's, or it is being recursively initialized. // // Macos: Inlining this function can cause two `tlv_get_addr` calls to - // be performed for every call to `Key::get`. The #[cold] hint makes - // that less likely. + // be performed for every call to `Key::get`. // LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722 - #[cold] + #[inline(never)] unsafe fn try_initialize T>(&self, init: F) -> Option<&'static T> { if !mem::needs_drop::() || self.try_register_dtor() { Some(self.inner.initialize(init)) From 941dca8ed238a04a55741127165e9ad80671ed8a Mon Sep 17 00:00:00 2001 From: Ayush Kumar Mishra Date: Sat, 5 Sep 2020 16:52:52 +0530 Subject: [PATCH 04/17] Add Arith Tests in Library --- library/core/tests/num/i32.rs | 27 +++++++++++++++++++++++ src/test/ui/numbers-arithmetic/arith-0.rs | 8 ------- src/test/ui/numbers-arithmetic/arith-1.rs | 24 -------------------- src/test/ui/numbers-arithmetic/arith-2.rs | 9 -------- 4 files changed, 27 insertions(+), 41 deletions(-) delete mode 100644 src/test/ui/numbers-arithmetic/arith-0.rs delete mode 100644 src/test/ui/numbers-arithmetic/arith-1.rs delete mode 100644 src/test/ui/numbers-arithmetic/arith-2.rs diff --git a/library/core/tests/num/i32.rs b/library/core/tests/num/i32.rs index 39250ee84bce6..71a40e14ebceb 100644 --- a/library/core/tests/num/i32.rs +++ b/library/core/tests/num/i32.rs @@ -1 +1,28 @@ int_module!(i32, i32); + +#[test] +fn test_arith_operation() { + let a: isize = 10; + assert_eq!(a * (a - 1), 90); + let i32_a: isize = 10; + assert_eq!(i32_a, 10); + assert_eq!(i32_a - 10, 0); + assert_eq!(i32_a / 10, 1); + assert_eq!(i32_a - 20, -10); + assert_eq!(i32_a << 10, 10240); + assert_eq!(i32_a << 16, 655360); + assert_eq!(i32_a * 16, 160); + assert_eq!(i32_a * i32_a * i32_a, 1000); + assert_eq!(i32_a * i32_a * i32_a * i32_a, 10000); + assert_eq!(i32_a * i32_a / i32_a * i32_a, 100); + assert_eq!(i32_a * (i32_a - 1) << (2 + i32_a as usize), 368640); + let i32_b: isize = 0x10101010; + assert_eq!(i32_b + 1 - 1, i32_b); + assert_eq!(i32_b << 1, i32_b << 1); + assert_eq!(i32_b >> 1, i32_b >> 1); + assert_eq!(i32_b & i32_b << 1, 0); + assert_eq!(i32_b | i32_b << 1, 0x30303030); + let i32_c: isize = 0x10101010; + assert_eq!(i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3), + i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3)); +} diff --git a/src/test/ui/numbers-arithmetic/arith-0.rs b/src/test/ui/numbers-arithmetic/arith-0.rs deleted file mode 100644 index 7943cb908d1f1..0000000000000 --- a/src/test/ui/numbers-arithmetic/arith-0.rs +++ /dev/null @@ -1,8 +0,0 @@ -// run-pass - - -pub fn main() { - let a: isize = 10; - println!("{}", a); - assert_eq!(a * (a - 1), 90); -} diff --git a/src/test/ui/numbers-arithmetic/arith-1.rs b/src/test/ui/numbers-arithmetic/arith-1.rs deleted file mode 100644 index c13c8d8b7659d..0000000000000 --- a/src/test/ui/numbers-arithmetic/arith-1.rs +++ /dev/null @@ -1,24 +0,0 @@ -// run-pass - - -pub fn main() { - let i32_a: isize = 10; - assert_eq!(i32_a, 10); - assert_eq!(i32_a - 10, 0); - assert_eq!(i32_a / 10, 1); - assert_eq!(i32_a - 20, -10); - assert_eq!(i32_a << 10, 10240); - assert_eq!(i32_a << 16, 655360); - assert_eq!(i32_a * 16, 160); - assert_eq!(i32_a * i32_a * i32_a, 1000); - assert_eq!(i32_a * i32_a * i32_a * i32_a, 10000); - assert_eq!(i32_a * i32_a / i32_a * i32_a, 100); - assert_eq!(i32_a * (i32_a - 1) << (2 + i32_a as usize), 368640); - let i32_b: isize = 0x10101010; - assert_eq!(i32_b + 1 - 1, i32_b); - assert_eq!(i32_b << 1, i32_b << 1); - assert_eq!(i32_b >> 1, i32_b >> 1); - assert_eq!(i32_b & i32_b << 1, 0); - println!("{}", i32_b | i32_b << 1); - assert_eq!(i32_b | i32_b << 1, 0x30303030); -} diff --git a/src/test/ui/numbers-arithmetic/arith-2.rs b/src/test/ui/numbers-arithmetic/arith-2.rs deleted file mode 100644 index 46c280677ce84..0000000000000 --- a/src/test/ui/numbers-arithmetic/arith-2.rs +++ /dev/null @@ -1,9 +0,0 @@ -// run-pass - - - -pub fn main() { - let i32_c: isize = 0x10101010; - assert_eq!(i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3), - i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3)); -} From dc37b553accd4fb2f8d0c59f69c701b524361cc2 Mon Sep 17 00:00:00 2001 From: Ayush Kumar Mishra Date: Sat, 5 Sep 2020 17:07:53 +0530 Subject: [PATCH 05/17] Minor refactoring --- library/core/tests/num/i32.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/core/tests/num/i32.rs b/library/core/tests/num/i32.rs index 71a40e14ebceb..4acc760ffac99 100644 --- a/library/core/tests/num/i32.rs +++ b/library/core/tests/num/i32.rs @@ -23,6 +23,8 @@ fn test_arith_operation() { assert_eq!(i32_b & i32_b << 1, 0); assert_eq!(i32_b | i32_b << 1, 0x30303030); let i32_c: isize = 0x10101010; - assert_eq!(i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3), - i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3)); + assert_eq!( + i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3), + i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3) + ); } From 7d834c87d2ebb3d8dd4895bc5fabc4d44a1d2b52 Mon Sep 17 00:00:00 2001 From: Ayush Kumar Mishra Date: Sat, 5 Sep 2020 17:24:06 +0530 Subject: [PATCH 06/17] Move Various str tests in library --- library/alloc/tests/str.rs | 21 +++++++++++++++++++++ src/test/ui/str-multiline.rs | 13 ------------- src/test/ui/string-escapes.rs | 7 ------- 3 files changed, 21 insertions(+), 20 deletions(-) delete mode 100644 src/test/ui/str-multiline.rs delete mode 100644 src/test/ui/string-escapes.rs diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index b20cf076aca3c..ed8ee2d8823c0 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1921,3 +1921,24 @@ fn different_str_pattern_forwarding_lifetimes() { foo::<&str>("x"); } + +#[test] +fn test_str_multiline() { + let a: String = "this \ +is a test" + .to_string(); + let b: String = "this \ + is \ + another \ + test" + .to_string(); + assert_eq!(a, "this is a test".to_string()); + assert_eq!(b, "this is another test".to_string()); +} + +#[test] +fn test_str_escapes() { + let x = "\\\\\ + "; + assert_eq!(x, r"\\"); // extraneous whitespace stripped +} diff --git a/src/test/ui/str-multiline.rs b/src/test/ui/str-multiline.rs deleted file mode 100644 index 2b2e001d8bb7f..0000000000000 --- a/src/test/ui/str-multiline.rs +++ /dev/null @@ -1,13 +0,0 @@ -// run-pass - -pub fn main() { - let a: String = "this \ -is a test".to_string(); - let b: String = - "this \ - is \ - another \ - test".to_string(); - assert_eq!(a, "this is a test".to_string()); - assert_eq!(b, "this is another test".to_string()); -} diff --git a/src/test/ui/string-escapes.rs b/src/test/ui/string-escapes.rs deleted file mode 100644 index cee5e27786cae..0000000000000 --- a/src/test/ui/string-escapes.rs +++ /dev/null @@ -1,7 +0,0 @@ -// run-pass - -fn main() { - let x = "\\\\\ - "; - assert_eq!(x, r"\\"); // extraneous whitespace stripped -} From d85db82960db80132a10d25e0fe7dfd5f4736d0f Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 8 Sep 2020 23:38:24 -0700 Subject: [PATCH 07/17] Add documentation for `impl From for Poll` --- library/core/src/task/poll.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 9383e7c45fa55..4e987a53b2cb2 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -112,6 +112,14 @@ impl Poll>> { #[stable(feature = "futures_api", since = "1.36.0")] impl From for Poll { + /// Convert to a `Ready` variant. + /// + /// # Example + /// + /// ``` + /// # use core::task::Poll; + /// assert_eq!(Poll::from(true), Poll::Ready(true)); + /// ``` fn from(t: T) -> Poll { Poll::Ready(t) } From 8b0d0a0cadbaaf0e7f4114e289a71981872c8587 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 9 Sep 2020 11:53:24 -0700 Subject: [PATCH 08/17] Add documentation for `impl From> for Vec` --- library/alloc/src/collections/binary_heap.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 40aa4d850f59d..24d17fdd880ba 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -1343,6 +1343,10 @@ impl From> for BinaryHeap { #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] impl From> for Vec { + /// Converts a `BinaryHeap` into a `Vec`. + /// + /// This conversion requires no data movement or allocation, and has + /// constant time complexity. fn from(heap: BinaryHeap) -> Vec { heap.data } From 85ab152be78ffaf7dd97f60ececceda28f4e4802 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 11 Sep 2020 20:53:52 -0400 Subject: [PATCH 09/17] Update bootstrap readme - Reflect changes in x.py defaults - Remove recommendation to use nightly for incremental; it works fine on beta - Remove note that incremental chooses stage 1 by default; stage 1 is already the default - Update Discord -> Zulip --- src/bootstrap/README.md | 38 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index 975b8be02c898..a69bd1cc3bc53 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -26,10 +26,10 @@ The script accepts commands, flags, and arguments to determine what to do: ``` # build the whole compiler - ./x.py build + ./x.py build --stage 2 # build the stage1 compiler - ./x.py build --stage 1 + ./x.py build # build stage0 libstd ./x.py build --stage 0 library/std @@ -43,8 +43,8 @@ The script accepts commands, flags, and arguments to determine what to do: that belong to stage n or earlier: ``` - # keep old build products for stage 0 and build stage 1 - ./x.py build --keep-stage 0 --stage 1 + # build stage 1, keeping old build products for stage 0 + ./x.py build --keep-stage 0 ``` * `test` - a command for executing unit tests. Like the `build` command this @@ -123,24 +123,8 @@ that (b) leverage Rust as much as possible! ## Incremental builds -You can configure rustbuild to use incremental compilation. Because -incremental is new and evolving rapidly, if you want to use it, it is -recommended that you replace the snapshot with a locally installed -nightly build of rustc. You will want to keep this up to date. - -To follow this course of action, first thing you will want to do is to -install a nightly, presumably using `rustup`. You will then want to -configure your directory to use this build, like so: - -```sh -# configure to use local rust instead of downloading a beta. -# `--local-rust-root` is optional here. If elided, we will -# use whatever rustc we find on your PATH. -$ ./configure --local-rust-root=~/.cargo/ --enable-local-rebuild -``` - -After that, you can use the `--incremental` flag to actually do -incremental builds: +You can configure rustbuild to use incremental compilation with the +`--incremental` flag: ```sh $ ./x.py build --incremental @@ -150,9 +134,7 @@ The `--incremental` flag will store incremental compilation artifacts in `build//stage0-incremental`. Note that we only use incremental compilation for the stage0 -> stage1 compilation -- this is because the stage1 compiler is changing, and we don't try to cache and reuse -incremental artifacts across different versions of the compiler. For -this reason, `--incremental` defaults to `--stage 1` (though you can -manually select a higher stage, if you prefer). +incremental artifacts across different versions of the compiler. You can always drop the `--incremental` to build as normal (but you will still be using the local nightly as your bootstrap). @@ -331,8 +313,8 @@ are: `Config` struct. * Adding a sanity check? Take a look at `bootstrap/sanity.rs`. -If you have any questions feel free to reach out on `#infra` channel in the -[Rust Discord server][rust-discord] or ask on internals.rust-lang.org. When +If you have any questions feel free to reach out on the `#t-infra` channel in +the [Rust Zulip server][rust-zulip] or ask on internals.rust-lang.org. When you encounter bugs, please file issues on the rust-lang/rust issue tracker. -[rust-discord]: https://discord.gg/rust-lang +[rust-zulip]: https://rust-lang.zulipchat.com/#narrow/stream/242791-t-infra From 73e0a56dde24693768d56960023f00ef61f28684 Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Fri, 4 Sep 2020 20:17:06 +0200 Subject: [PATCH 10/17] Make all methods of `Duration` const Make the following methods of `Duration` unstable const under `duration_const_2`: - `from_secs_f64` - `from_secs_f32` - `mul_f64` - `mul_f32` - `div_f64` - `div_f32` This results in all methods of `Duration` being (unstable) const. Also adds tests for these methods in a const context, moved the test to `library` as part of #76268. Possible because of #72449, which made the relevant `f32` and `f64` methods const. Tracking issue: #72440 --- library/core/src/time.rs | 18 +++-- library/core/tests/lib.rs | 3 + library/core/tests/time.rs | 101 ++++++++++++++++++++++++ src/test/ui/consts/duration-consts-2.rs | 67 ---------------- 4 files changed, 116 insertions(+), 73 deletions(-) delete mode 100644 src/test/ui/consts/duration-consts-2.rs diff --git a/library/core/src/time.rs b/library/core/src/time.rs index f39781788d7c0..6dc542dee58e6 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -693,7 +693,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn from_secs_f64(secs: f64) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn from_secs_f64(secs: f64) -> Duration { const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f64; let nanos = secs * (NANOS_PER_SEC as f64); if !nanos.is_finite() { @@ -727,7 +728,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn from_secs_f32(secs: f32) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn from_secs_f32(secs: f32) -> Duration { const MAX_NANOS_F32: f32 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f32; let nanos = secs * (NANOS_PER_SEC as f32); if !nanos.is_finite() { @@ -761,7 +763,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn mul_f64(self, rhs: f64) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn mul_f64(self, rhs: f64) -> Duration { Duration::from_secs_f64(rhs * self.as_secs_f64()) } @@ -782,7 +785,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn mul_f32(self, rhs: f32) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn mul_f32(self, rhs: f32) -> Duration { Duration::from_secs_f32(rhs * self.as_secs_f32()) } @@ -802,7 +806,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn div_f64(self, rhs: f64) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn div_f64(self, rhs: f64) -> Duration { Duration::from_secs_f64(self.as_secs_f64() / rhs) } @@ -824,7 +829,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn div_f32(self, rhs: f32) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn div_f32(self, rhs: f32) -> Duration { Duration::from_secs_f32(self.as_secs_f32() / rhs) } diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index a2e294ace1860..04402117f7da6 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -10,8 +10,11 @@ #![feature(core_private_diy_float)] #![feature(debug_non_exhaustive)] #![feature(dec2flt)] +#![feature(div_duration)] +#![feature(duration_consts_2)] #![feature(duration_constants)] #![feature(duration_saturating_ops)] +#![feature(duration_zero)] #![feature(exact_size_is_empty)] #![feature(fixed_size_array)] #![feature(flt2dec)] diff --git a/library/core/tests/time.rs b/library/core/tests/time.rs index 4f90eb63b0472..7c43885040b3e 100644 --- a/library/core/tests/time.rs +++ b/library/core/tests/time.rs @@ -321,3 +321,104 @@ fn debug_formatting_precision_high() { assert_eq!(format!("{:.10?}", Duration::new(4, 001_000_000)), "4.0010000000s"); assert_eq!(format!("{:.20?}", Duration::new(4, 001_000_000)), "4.00100000000000000000s"); } + +#[test] +fn duration_const() { + // test that the methods of `Duration` are usable in a const context + + const DURATION: Duration = Duration::new(0, 123_456_789); + + const SUB_SEC_MILLIS: u32 = DURATION.subsec_millis(); + assert_eq!(SUB_SEC_MILLIS, 123); + + const SUB_SEC_MICROS: u32 = DURATION.subsec_micros(); + assert_eq!(SUB_SEC_MICROS, 123_456); + + const SUB_SEC_NANOS: u32 = DURATION.subsec_nanos(); + assert_eq!(SUB_SEC_NANOS, 123_456_789); + + const ZERO: Duration = Duration::zero(); + assert_eq!(ZERO, Duration::new(0, 0)); + + const IS_ZERO: bool = ZERO.is_zero(); + assert!(IS_ZERO); + + const ONE: Duration = Duration::new(1, 0); + + const SECONDS: u64 = ONE.as_secs(); + assert_eq!(SECONDS, 1); + + const FROM_SECONDS: Duration = Duration::from_secs(1); + assert_eq!(FROM_SECONDS, ONE); + + const SECONDS_F32: f32 = ONE.as_secs_f32(); + assert_eq!(SECONDS_F32, 1.0); + + const FROM_SECONDS_F32: Duration = Duration::from_secs_f32(1.0); + assert_eq!(FROM_SECONDS_F32, ONE); + + const SECONDS_F64: f64 = ONE.as_secs_f64(); + assert_eq!(SECONDS_F64, 1.0); + + const FROM_SECONDS_F64: Duration = Duration::from_secs_f64(1.0); + assert_eq!(FROM_SECONDS_F64, ONE); + + const MILLIS: u128 = ONE.as_millis(); + assert_eq!(MILLIS, 1_000); + + const FROM_MILLIS: Duration = Duration::from_millis(1_000); + assert_eq!(FROM_MILLIS, ONE); + + const MICROS: u128 = ONE.as_micros(); + assert_eq!(MICROS, 1_000_000); + + const FROM_MICROS: Duration = Duration::from_micros(1_000_000); + assert_eq!(FROM_MICROS, ONE); + + const NANOS: u128 = ONE.as_nanos(); + assert_eq!(NANOS, 1_000_000_000); + + const FROM_NANOS: Duration = Duration::from_nanos(1_000_000_000); + assert_eq!(FROM_NANOS, ONE); + + const MAX: Duration = Duration::new(u64::MAX, 999_999_999); + + const CHECKED_ADD: Option = MAX.checked_add(ONE); + assert_eq!(CHECKED_ADD, None); + + const CHECKED_SUB: Option = ZERO.checked_sub(ONE); + assert_eq!(CHECKED_SUB, None); + + const CHECKED_MUL: Option = ONE.checked_mul(1); + assert_eq!(CHECKED_MUL, Some(ONE)); + + const MUL_F32: Duration = ONE.mul_f32(1.0); + assert_eq!(MUL_F32, ONE); + + const MUL_F64: Duration = ONE.mul_f64(1.0); + assert_eq!(MUL_F64, ONE); + + const CHECKED_DIV: Option = ONE.checked_div(1); + assert_eq!(CHECKED_DIV, Some(ONE)); + + const DIV_F32: Duration = ONE.div_f32(1.0); + assert_eq!(DIV_F32, ONE); + + const DIV_F64: Duration = ONE.div_f64(1.0); + assert_eq!(DIV_F64, ONE); + + const DIV_DURATION_F32: f32 = ONE.div_duration_f32(ONE); + assert_eq!(DIV_DURATION_F32, 1.0); + + const DIV_DURATION_F64: f64 = ONE.div_duration_f64(ONE); + assert_eq!(DIV_DURATION_F64, 1.0); + + const SATURATING_ADD: Duration = MAX.saturating_add(ONE); + assert_eq!(SATURATING_ADD, MAX); + + const SATURATING_SUB: Duration = ZERO.saturating_sub(ONE); + assert_eq!(SATURATING_SUB, ZERO); + + const SATURATING_MUL: Duration = MAX.saturating_mul(2); + assert_eq!(SATURATING_MUL, MAX); +} diff --git a/src/test/ui/consts/duration-consts-2.rs b/src/test/ui/consts/duration-consts-2.rs deleted file mode 100644 index bc0969e4f1fba..0000000000000 --- a/src/test/ui/consts/duration-consts-2.rs +++ /dev/null @@ -1,67 +0,0 @@ -// run-pass - -#![feature(const_panic)] -#![feature(duration_consts_2)] -#![feature(div_duration)] -#![feature(duration_saturating_ops)] - -use std::time::Duration; - -fn duration() { - const ZERO : Duration = Duration::new(0, 0); - assert_eq!(ZERO, Duration::from_secs(0)); - - const ONE : Duration = Duration::new(0, 1); - assert_eq!(ONE, Duration::from_nanos(1)); - - const MAX : Duration = Duration::new(u64::MAX, 1_000_000_000 - 1); - - const MAX_CHECKED_ADD_ZERO : Option = MAX.checked_add(ZERO); - assert_eq!(MAX_CHECKED_ADD_ZERO, Some(MAX)); - - const MAX_CHECKED_ADD_ONE : Option = MAX.checked_add(ONE); - assert_eq!(MAX_CHECKED_ADD_ONE, None); - - const ONE_CHECKED_SUB_ONE : Option = ONE.checked_sub(ONE); - assert_eq!(ONE_CHECKED_SUB_ONE, Some(ZERO)); - - const ZERO_CHECKED_SUB_ONE : Option = ZERO.checked_sub(ONE); - assert_eq!(ZERO_CHECKED_SUB_ONE, None); - - const ONE_CHECKED_MUL_ONE : Option = ONE.checked_mul(1); - assert_eq!(ONE_CHECKED_MUL_ONE, Some(ONE)); - - const MAX_CHECKED_MUL_TWO : Option = MAX.checked_mul(2); - assert_eq!(MAX_CHECKED_MUL_TWO, None); - - const ONE_CHECKED_DIV_ONE : Option = ONE.checked_div(1); - assert_eq!(ONE_CHECKED_DIV_ONE, Some(ONE)); - - const ONE_CHECKED_DIV_ZERO : Option = ONE.checked_div(0); - assert_eq!(ONE_CHECKED_DIV_ZERO, None); - - const MAX_AS_F32 : f32 = MAX.as_secs_f32(); - assert_eq!(MAX_AS_F32, 18446744000000000000.0_f32); - - const MAX_AS_F64 : f64 = MAX.as_secs_f64(); - assert_eq!(MAX_AS_F64, 18446744073709552000.0_f64); - - const ONE_AS_F32 : f32 = ONE.div_duration_f32(ONE); - assert_eq!(ONE_AS_F32, 1.0_f32); - - const ONE_AS_F64 : f64 = ONE.div_duration_f64(ONE); - assert_eq!(ONE_AS_F64, 1.0_f64); - - const MAX_SATURATING_ADD_ONE : Duration = MAX.saturating_add(ONE); - assert_eq!(MAX_SATURATING_ADD_ONE, MAX); - - const ZERO_SATURATING_SUB_ONE : Duration = ZERO.saturating_sub(ONE); - assert_eq!(ZERO_SATURATING_SUB_ONE, ZERO); - - const MAX_SATURATING_MUL_TWO : Duration = MAX.saturating_mul(2); - assert_eq!(MAX_SATURATING_MUL_TWO, MAX); -} - -fn main() { - duration(); -} From 4f0047ed108889ea97ad7656307a8a829dd56636 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 12 Sep 2020 18:35:32 +0200 Subject: [PATCH 11/17] Add a comment on is_trivially_sized about obviously !Sized types --- compiler/rustc_middle/src/ty/sty.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 9f5fc5a2d3fbc..825221c22a8c1 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2280,6 +2280,12 @@ impl<'tcx> TyS<'tcx> { /// /// Returning true means the type is known to be sized. Returning /// `false` means nothing -- could be sized, might not be. + /// + /// Note that we could never rely on the fact that a type such as `[_]` is + /// trivially `!Sized` because we could be in a type environment with a + /// bound such as `[_]: Copy`. A function with such a bound obviously never + /// can be called, but that doesn't mean it shouldn't typecheck. This is why + /// this method doesn't return `Option`. pub fn is_trivially_sized(&self, tcx: TyCtxt<'tcx>) -> bool { match self.kind() { ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) From 75f0f7af3172cedaa01e9bf066c06017bfe9a426 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 12 Sep 2020 13:27:57 +0200 Subject: [PATCH 12/17] Fix a typo --- src/librustdoc/clean/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1bdbad4675556..00f27bb51ed21 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -839,7 +839,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, ty::GenericPredicates<'tcx let mut where_predicates = where_predicates.into_iter().flat_map(|p| p.clean(cx)).collect::>(); - // Type parameters and have a Sized bound by default unless removed with + // Type parameters have a Sized bound by default unless removed with // ?Sized. Scan through the predicates and mark any type parameter with // a Sized bound, removing the bounds as we find them. // From caf6c92d19216d75bf248643a11df77a598293e7 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 12 Sep 2020 13:30:21 +0200 Subject: [PATCH 13/17] Clean up some language trait items comparisons --- .../src/traits/error_reporting/mod.rs | 7 +------ compiler/rustc_traits/src/chalk/db.rs | 20 +++++-------------- 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index dcd8379803319..611280b413dd7 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1507,12 +1507,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { // avoid inundating the user with unnecessary errors, but we now // check upstream for type errors and don't add the obligations to // begin with in those cases. - if self - .tcx - .lang_items() - .sized_trait() - .map_or(false, |sized_id| sized_id == trait_ref.def_id()) - { + if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) { self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0282).emit(); return; } diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 7cc567dabb28f..2fad54013ad5b 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -110,25 +110,15 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t .map(|i| chalk_ir::AssocTypeId(i.def_id)) .collect(); - let well_known = if self - .interner - .tcx - .lang_items() - .sized_trait() - .map(|t| def_id == t) - .unwrap_or(false) - { + let well_known = if self.interner.tcx.lang_items().sized_trait() == Some(def_id) { Some(chalk_solve::rust_ir::WellKnownTrait::Sized) - } else if self.interner.tcx.lang_items().copy_trait().map(|t| def_id == t).unwrap_or(false) - { + } else if self.interner.tcx.lang_items().copy_trait() == Some(def_id) { Some(chalk_solve::rust_ir::WellKnownTrait::Copy) - } else if self.interner.tcx.lang_items().clone_trait().map(|t| def_id == t).unwrap_or(false) - { + } else if self.interner.tcx.lang_items().clone_trait() == Some(def_id) { Some(chalk_solve::rust_ir::WellKnownTrait::Clone) - } else if self.interner.tcx.lang_items().drop_trait().map(|t| def_id == t).unwrap_or(false) - { + } else if self.interner.tcx.lang_items().drop_trait() == Some(def_id) { Some(chalk_solve::rust_ir::WellKnownTrait::Drop) - } else if self.interner.tcx.lang_items().fn_trait().map(|t| def_id == t).unwrap_or(false) { + } else if self.interner.tcx.lang_items().fn_trait() == Some(def_id) { Some(chalk_solve::rust_ir::WellKnownTrait::Fn) } else if self .interner From 1f572b03492e7d3ce7156d00f9b44ccedf47bb50 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Tue, 15 Sep 2020 14:41:43 +0800 Subject: [PATCH 14/17] Vec doc use elision as code rather than comment --- library/alloc/src/vec.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index d39b6b701e6d8..f6807c4c5c3ae 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -171,7 +171,9 @@ use crate::raw_vec::RawVec; /// /// // ... and that's all! /// // you can also do it like this: -/// let u: &[usize] = &v; // or &[_] +/// let u: &[usize] = &v; +/// // or like this: +/// let u: &[_] = &v; /// ``` /// /// In Rust, it's more common to pass slices as arguments rather than vectors From d888725fba70af4139629da0f7a17910aa66d951 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 13 Sep 2020 11:27:21 +0200 Subject: [PATCH 15/17] reduce size of test_from_iter_specialization_with_iterator_adapters test in Miri --- library/alloc/tests/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 608a3c9bdf762..5fdbef7171025 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -894,7 +894,7 @@ fn test_from_iter_partially_drained_in_place_specialization() { #[test] fn test_from_iter_specialization_with_iterator_adapters() { fn assert_in_place_trait(_: &T) {}; - let src: Vec = vec![0usize; 65535]; + let src: Vec = vec![0usize; if cfg!(miri) { 256 } else { 65535 }]; let srcptr = src.as_ptr(); let iter = src .into_iter() From c528d2419672bd4ace322ddbc000813a12c1d4c7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 13 Sep 2020 12:14:59 +0200 Subject: [PATCH 16/17] fix slice::check_range aliasing problems --- library/alloc/src/collections/vec_deque.rs | 6 +- library/alloc/src/slice.rs | 2 + library/alloc/src/string.rs | 3 +- library/alloc/src/vec.rs | 2 +- library/alloc/tests/vec.rs | 2 +- library/core/src/slice/index.rs | 75 +++++++++++++++++++- library/core/src/slice/mod.rs | 81 ++-------------------- 7 files changed, 85 insertions(+), 86 deletions(-) diff --git a/library/alloc/src/collections/vec_deque.rs b/library/alloc/src/collections/vec_deque.rs index 253a3e9f2bea9..65cfe9a9b4996 100644 --- a/library/alloc/src/collections/vec_deque.rs +++ b/library/alloc/src/collections/vec_deque.rs @@ -1089,11 +1089,7 @@ impl VecDeque { where R: RangeBounds, { - // SAFETY: This buffer is only used to check the range. It might be partially - // uninitialized, but `check_range` needs a contiguous slice. - // https://github.com/rust-lang/rust/pull/75207#discussion_r471193682 - let buffer = unsafe { slice::from_raw_parts(self.ptr(), self.len()) }; - let Range { start, end } = buffer.check_range(range); + let Range { start, end } = slice::check_range(self.len(), range); let tail = self.wrap_add(self.tail, start); let head = self.wrap_add(self.tail, end); (tail, head) diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 677bfdd2349ec..55afdd94f4468 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -91,6 +91,8 @@ use crate::borrow::ToOwned; use crate::boxed::Box; use crate::vec::Vec; +#[unstable(feature = "slice_check_range", issue = "76393")] +pub use core::slice::check_range; #[unstable(feature = "array_chunks", issue = "74985")] pub use core::slice::ArrayChunks; #[unstable(feature = "array_chunks", issue = "74985")] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index e1724bf3c9a90..2b0ce5ede5630 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -49,6 +49,7 @@ use core::iter::{FromIterator, FusedIterator}; use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds}; use core::ptr; +use core::slice; use core::str::{lossy, pattern::Pattern}; use crate::borrow::{Cow, ToOwned}; @@ -1506,7 +1507,7 @@ impl String { // of the vector version. The data is just plain bytes. // Because the range removal happens in Drop, if the Drain iterator is leaked, // the removal will not happen. - let Range { start, end } = self.as_bytes().check_range(range); + let Range { start, end } = slice::check_range(self.len(), range); assert!(self.is_char_boundary(start)); assert!(self.is_char_boundary(end)); diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index cb4c1c20abcf6..fdd71a3211afa 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -1310,7 +1310,7 @@ impl Vec { // the hole, and the vector length is restored to the new length. // let len = self.len(); - let Range { start, end } = self.check_range(range); + let Range { start, end } = slice::check_range(len, range); unsafe { // set self.vec length's to start, to be safe in case Drain is leaked diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 5fdbef7171025..9ef5df01565c6 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -894,7 +894,7 @@ fn test_from_iter_partially_drained_in_place_specialization() { #[test] fn test_from_iter_specialization_with_iterator_adapters() { fn assert_in_place_trait(_: &T) {}; - let src: Vec = vec![0usize; if cfg!(miri) { 256 } else { 65535 }]; + let src: Vec = vec![0usize; 256]; let srcptr = src.as_ptr(); let iter = src .into_iter() diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index d67e0ae536d9f..a662d9682c51b 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -1,6 +1,6 @@ //! Indexing implementations for `[T]`. -use crate::ops; +use crate::ops::{self, Bound, Range, RangeBounds}; use crate::ptr; #[stable(feature = "rust1", since = "1.0.0")] @@ -62,6 +62,79 @@ pub(super) fn slice_end_index_overflow_fail() -> ! { panic!("attempted to index slice up to maximum usize"); } +/// Performs bounds-checking of the given range. +/// The returned [`Range`] is safe to pass to [`get_unchecked`] and [`get_unchecked_mut`] +/// for slices of the given length. +/// +/// [`get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked +/// [`get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut +/// +/// # Panics +/// +/// Panics if the range is out of bounds. +/// +/// # Examples +/// +/// ``` +/// #![feature(slice_check_range)] +/// use std::slice; +/// +/// let v = [10, 40, 30]; +/// assert_eq!(1..2, slice::check_range(v.len(), 1..2)); +/// assert_eq!(0..2, slice::check_range(v.len(), ..2)); +/// assert_eq!(1..3, slice::check_range(v.len(), 1..)); +/// ``` +/// +/// Panics when [`Index::index`] would panic: +/// +/// ```should_panic +/// #![feature(slice_check_range)] +/// +/// std::slice::check_range(3, 2..1); +/// ``` +/// +/// ```should_panic +/// #![feature(slice_check_range)] +/// +/// std::slice::check_range(3, 1..4); +/// ``` +/// +/// ```should_panic +/// #![feature(slice_check_range)] +/// +/// std::slice::check_range(3, 1..=usize::MAX); +/// ``` +/// +/// [`Index::index`]: crate::ops::Index::index +#[track_caller] +#[unstable(feature = "slice_check_range", issue = "76393")] +pub fn check_range>(len: usize, range: R) -> Range { + let start = match range.start_bound() { + Bound::Included(&start) => start, + Bound::Excluded(start) => { + start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) + } + Bound::Unbounded => 0, + }; + + let end = match range.end_bound() { + Bound::Included(end) => { + end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) + } + Bound::Excluded(&end) => end, + Bound::Unbounded => len, + }; + + if start > end { + slice_index_order_fail(start, end); + } + if end > len { + slice_end_index_len_fail(end, len); + } + + Range { start, end } +} + mod private_slice_index { use super::ops; #[stable(feature = "slice_get_slice", since = "1.28.0")] diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 64a707c39f076..ba3185433c8d8 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -12,7 +12,7 @@ use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::intrinsics::assume; use crate::marker::{self, Copy}; use crate::mem; -use crate::ops::{Bound, FnMut, Range, RangeBounds}; +use crate::ops::{FnMut, Range, RangeBounds}; use crate::option::Option; use crate::option::Option::{None, Some}; use crate::ptr::{self, NonNull}; @@ -72,8 +72,8 @@ pub use sort::heapsort; #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use index::SliceIndex; -use index::{slice_end_index_len_fail, slice_index_order_fail}; -use index::{slice_end_index_overflow_fail, slice_start_index_overflow_fail}; +#[unstable(feature = "slice_check_range", issue = "76393")] +pub use index::check_range; #[lang = "slice"] #[cfg(not(test))] @@ -378,79 +378,6 @@ impl [T] { unsafe { &mut *index.get_unchecked_mut(self) } } - /// Converts a range over this slice to [`Range`]. - /// - /// The returned range is safe to pass to [`get_unchecked`] and [`get_unchecked_mut`]. - /// - /// [`get_unchecked`]: #method.get_unchecked - /// [`get_unchecked_mut`]: #method.get_unchecked_mut - /// - /// # Panics - /// - /// Panics if the range is out of bounds. - /// - /// # Examples - /// - /// ``` - /// #![feature(slice_check_range)] - /// - /// let v = [10, 40, 30]; - /// assert_eq!(1..2, v.check_range(1..2)); - /// assert_eq!(0..2, v.check_range(..2)); - /// assert_eq!(1..3, v.check_range(1..)); - /// ``` - /// - /// Panics when [`Index::index`] would panic: - /// - /// ```should_panic - /// #![feature(slice_check_range)] - /// - /// [10, 40, 30].check_range(2..1); - /// ``` - /// - /// ```should_panic - /// #![feature(slice_check_range)] - /// - /// [10, 40, 30].check_range(1..4); - /// ``` - /// - /// ```should_panic - /// #![feature(slice_check_range)] - /// - /// [10, 40, 30].check_range(1..=usize::MAX); - /// ``` - /// - /// [`Index::index`]: crate::ops::Index::index - #[track_caller] - #[unstable(feature = "slice_check_range", issue = "76393")] - pub fn check_range>(&self, range: R) -> Range { - let start = match range.start_bound() { - Bound::Included(&start) => start, - Bound::Excluded(start) => { - start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) - } - Bound::Unbounded => 0, - }; - - let len = self.len(); - let end = match range.end_bound() { - Bound::Included(end) => { - end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) - } - Bound::Excluded(&end) => end, - Bound::Unbounded => len, - }; - - if start > end { - slice_index_order_fail(start, end); - } - if end > len { - slice_end_index_len_fail(end, len); - } - - Range { start, end } - } - /// Returns a raw pointer to the slice's buffer. /// /// The caller must ensure that the slice outlives the pointer this @@ -2794,7 +2721,7 @@ impl [T] { where T: Copy, { - let Range { start: src_start, end: src_end } = self.check_range(src); + let Range { start: src_start, end: src_end } = check_range(self.len(), src); let count = src_end - src_start; assert!(dest <= self.len() - count, "dest is out of bounds"); // SAFETY: the conditions for `ptr::copy` have all been checked above, From 7d67546a6ade5c1ade4b8e66266411f7aa4fae69 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 15 Sep 2020 23:46:26 +0200 Subject: [PATCH 17/17] hopefully fix rustdoc links --- library/core/src/slice/index.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index a662d9682c51b..16fcb6231dc09 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -105,7 +105,7 @@ pub(super) fn slice_end_index_overflow_fail() -> ! { /// std::slice::check_range(3, 1..=usize::MAX); /// ``` /// -/// [`Index::index`]: crate::ops::Index::index +/// [`Index::index`]: ops::Index::index #[track_caller] #[unstable(feature = "slice_check_range", issue = "76393")] pub fn check_range>(len: usize, range: R) -> Range {