From ba4c4988161abbe58e973b792c7e271785b4bc4d Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sat, 29 Aug 2020 18:25:17 +0800 Subject: [PATCH 01/39] 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/39] 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/39] 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/39] 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/39] 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/39] 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/39] 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/39] 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/39] 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/39] 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/39] 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/39] 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/39] 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 2e7ca7329966b9a86b4d35689cb719883dcda4e8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 12 Sep 2020 14:30:27 +0200 Subject: [PATCH 14/39] Don't emit an error on private doc tests when they're ignored --- src/librustdoc/passes/doc_test_lints.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs index cbbe86dc433f3..78af9f9b8561a 100644 --- a/src/librustdoc/passes/doc_test_lints.rs +++ b/src/librustdoc/passes/doc_test_lints.rs @@ -8,7 +8,7 @@ use crate::clean; use crate::clean::*; use crate::core::DocContext; use crate::fold::DocFolder; -use crate::html::markdown::{find_testable_code, ErrorCodes, LangString}; +use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString}; use rustc_session::lint; pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass { @@ -48,15 +48,11 @@ pub(crate) struct Tests { pub(crate) found_tests: usize, } -impl Tests { - pub(crate) fn new() -> Tests { - Tests { found_tests: 0 } - } -} - impl crate::doctest::Tester for Tests { - fn add_test(&mut self, _: String, _: LangString, _: usize) { - self.found_tests += 1; + fn add_test(&mut self, _: String, config: LangString, _: usize) { + if config.rust && config.ignore == Ignore::None { + self.found_tests += 1; + } } } @@ -85,7 +81,7 @@ pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { } }; - let mut tests = Tests::new(); + let mut tests = Tests { found_tests: 0 }; find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None); From 15d25a8a7272708cd841c90884f7d3626af9b6a9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 12 Sep 2020 14:30:40 +0200 Subject: [PATCH 15/39] Add test for ignored private doc test --- src/test/rustdoc-ui/coverage/doc-examples.stdout | 4 ++-- src/test/rustdoc-ui/private-doc-test.rs | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 src/test/rustdoc-ui/private-doc-test.rs diff --git a/src/test/rustdoc-ui/coverage/doc-examples.stdout b/src/test/rustdoc-ui/coverage/doc-examples.stdout index 10ed13c9ff566..8188740f8739b 100644 --- a/src/test/rustdoc-ui/coverage/doc-examples.stdout +++ b/src/test/rustdoc-ui/coverage/doc-examples.stdout @@ -1,7 +1,7 @@ +-------------------------------------+------------+------------+------------+------------+ | File | Documented | Percentage | Examples | Percentage | +-------------------------------------+------------+------------+------------+------------+ -| ...tdoc-ui/coverage/doc-examples.rs | 4 | 100.0% | 2 | 50.0% | +| ...tdoc-ui/coverage/doc-examples.rs | 4 | 100.0% | 1 | 25.0% | +-------------------------------------+------------+------------+------------+------------+ -| Total | 4 | 100.0% | 2 | 50.0% | +| Total | 4 | 100.0% | 1 | 25.0% | +-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/private-doc-test.rs b/src/test/rustdoc-ui/private-doc-test.rs new file mode 100644 index 0000000000000..379fa45f9fa3e --- /dev/null +++ b/src/test/rustdoc-ui/private-doc-test.rs @@ -0,0 +1,12 @@ +// check-pass + +#![deny(private_doc_tests)] + +mod foo { + /// private doc test + /// + /// ```ignore (used for testing ignored doc tests) + /// assert!(false); + /// ``` + fn bar() {} +} From b7ce5b44dd2e0fa8d6f7131a246ecad77328921e Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Sun, 13 Sep 2020 22:06:06 +0200 Subject: [PATCH 16/39] remove orphaned files Should been part of https://github.com/rust-lang/rust/pull/74163 --- .../dist-x86_64-linux/build-git.sh | 15 ------------- .../dist-x86_64-linux/build-headers.sh | 16 -------------- .../dist-x86_64-linux/build-perl.sh | 21 ------------------- 3 files changed, 52 deletions(-) delete mode 100755 src/ci/docker/host-x86_64/dist-x86_64-linux/build-git.sh delete mode 100755 src/ci/docker/host-x86_64/dist-x86_64-linux/build-headers.sh delete mode 100755 src/ci/docker/host-x86_64/dist-x86_64-linux/build-perl.sh diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-git.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-git.sh deleted file mode 100755 index 38fea2a8094b9..0000000000000 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-git.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - -set -ex -source shared.sh - -curl -L https://www.kernel.org/pub/software/scm/git/git-2.10.0.tar.gz | tar xzf - - -cd git-2.10.0 -make configure -hide_output ./configure --prefix=/rustroot -hide_output make -j10 -hide_output make install - -cd .. -rm -rf git-2.10.0 diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-headers.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-headers.sh deleted file mode 100755 index b623e53583b5e..0000000000000 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-headers.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -set -ex -source shared.sh - -curl https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.2.84.tar.xz | unxz | tar x - -cd linux-3.2.84 -hide_output make mrproper -hide_output make INSTALL_HDR_PATH=dest headers_install - -find dest/include \( -name .install -o -name ..install.cmd \) -delete -yes | cp -fr dest/include/* /usr/include - -cd .. -rm -rf linux-3.2.84 diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-perl.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-perl.sh deleted file mode 100755 index a678d353d52f5..0000000000000 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-perl.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash - -set -ex -source shared.sh - -curl https://www.cpan.org/src/5.0/perl-5.28.0.tar.gz | \ - tar xzf - - -cd perl-5.28.0 - -# Gotta do some hackery to tell python about our custom OpenSSL build, but other -# than that fairly normal. -CC=gcc \ -CFLAGS='-I /rustroot/include -fgnu89-inline' \ -LDFLAGS='-L /rustroot/lib -L /rustroot/lib64' \ - hide_output ./configure.gnu -hide_output make -j10 -hide_output make install - -cd .. -rm -rf perl-5.28.0 From c9686cb31ad9dd9428825dbb3b362f5df72ab719 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sun, 26 Jul 2020 08:53:39 -0400 Subject: [PATCH 17/39] Introduce a PartitioningCx struct --- .../src/monomorphize/partitioning/default.rs | 32 +++++++++---------- .../src/monomorphize/partitioning/merging.rs | 15 ++++----- .../src/monomorphize/partitioning/mod.rs | 25 +++++++++------ 3 files changed, 38 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs index b48bae8378779..827d037f31988 100644 --- a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs @@ -11,6 +11,7 @@ use rustc_middle::ty::print::characteristic_def_id_of_type; use rustc_middle::ty::{self, DefIdTree, InstanceDef, TyCtxt}; use rustc_span::symbol::Symbol; +use super::PartitioningCx; use crate::monomorphize::collector::InliningMap; use crate::monomorphize::partitioning::merging; use crate::monomorphize::partitioning::{ @@ -22,35 +23,36 @@ pub struct DefaultPartitioning; impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { fn place_root_mono_items( &mut self, - tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, mono_items: &mut dyn Iterator>, ) -> PreInliningPartitioning<'tcx> { let mut roots = FxHashSet::default(); let mut codegen_units = FxHashMap::default(); - let is_incremental_build = tcx.sess.opts.incremental.is_some(); + let is_incremental_build = cx.tcx.sess.opts.incremental.is_some(); let mut internalization_candidates = FxHashSet::default(); // Determine if monomorphizations instantiated in this crate will be made // available to downstream crates. This depends on whether we are in // share-generics mode and whether the current crate can even have // downstream crates. - let export_generics = tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics(); + let export_generics = + cx.tcx.sess.opts.share_generics() && cx.tcx.local_crate_exports_generics(); - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); + let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); let cgu_name_cache = &mut FxHashMap::default(); for mono_item in mono_items { - match mono_item.instantiation_mode(tcx) { + match mono_item.instantiation_mode(cx.tcx) { InstantiationMode::GloballyShared { .. } => {} InstantiationMode::LocalCopy => continue, } - let characteristic_def_id = characteristic_def_id_of_mono_item(tcx, mono_item); + let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item); let is_volatile = is_incremental_build && mono_item.is_generic_fn(); let codegen_unit_name = match characteristic_def_id { Some(def_id) => compute_codegen_unit_name( - tcx, + cx.tcx, cgu_name_builder, def_id, is_volatile, @@ -65,7 +67,7 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { let mut can_be_internalized = true; let (linkage, visibility) = mono_item_linkage_and_visibility( - tcx, + cx.tcx, &mono_item, &mut can_be_internalized, export_generics, @@ -97,17 +99,16 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { fn merge_codegen_units( &mut self, - tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, initial_partitioning: &mut PreInliningPartitioning<'tcx>, - target_cgu_count: usize, ) { - merging::merge_codegen_units(tcx, initial_partitioning, target_cgu_count); + merging::merge_codegen_units(cx, initial_partitioning); } fn place_inlined_mono_items( &mut self, + cx: &PartitioningCx<'_, 'tcx>, initial_partitioning: PreInliningPartitioning<'tcx>, - inlining_map: &InliningMap<'tcx>, ) -> PostInliningPartitioning<'tcx> { let mut new_partitioning = Vec::new(); let mut mono_item_placements = FxHashMap::default(); @@ -124,7 +125,7 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { // Collect all items that need to be available in this codegen unit. let mut reachable = FxHashSet::default(); for root in old_codegen_unit.items().keys() { - follow_inlining(*root, inlining_map, &mut reachable); + follow_inlining(*root, cx.inlining_map, &mut reachable); } let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name()); @@ -198,9 +199,8 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { fn internalize_symbols( &mut self, - _tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, partitioning: &mut PostInliningPartitioning<'tcx>, - inlining_map: &InliningMap<'tcx>, ) { if partitioning.codegen_units.len() == 1 { // Fast path for when there is only one codegen unit. In this case we @@ -218,7 +218,7 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { // Build a map from every monomorphization to all the monomorphizations that // reference it. let mut accessor_map: FxHashMap, Vec>> = Default::default(); - inlining_map.iter_accesses(|accessor, accessees| { + cx.inlining_map.iter_accesses(|accessor, accessees| { for accessee in accessees { accessor_map.entry(*accessee).or_default().push(accessor); } diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs b/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs index 1787e6df1b9c7..3f3aaa2f63ca3 100644 --- a/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs @@ -3,17 +3,16 @@ use std::cmp; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder}; -use rustc_middle::ty::TyCtxt; use rustc_span::symbol::{Symbol, SymbolStr}; +use super::PartitioningCx; use crate::monomorphize::partitioning::PreInliningPartitioning; pub fn merge_codegen_units<'tcx>( - tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, initial_partitioning: &mut PreInliningPartitioning<'tcx>, - target_cgu_count: usize, ) { - assert!(target_cgu_count >= 1); + assert!(cx.target_cgu_count >= 1); let codegen_units = &mut initial_partitioning.codegen_units; // Note that at this point in time the `codegen_units` here may not be in a @@ -32,7 +31,7 @@ pub fn merge_codegen_units<'tcx>( codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name().as_str()])).collect(); // Merge the two smallest codegen units until the target size is reached. - while codegen_units.len() > target_cgu_count { + while codegen_units.len() > cx.target_cgu_count { // Sort small cgus to the back codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate())); let mut smallest = codegen_units.pop().unwrap(); @@ -56,9 +55,9 @@ pub fn merge_codegen_units<'tcx>( ); } - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); + let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); - if tcx.sess.opts.incremental.is_some() { + if cx.tcx.sess.opts.incremental.is_some() { // If we are doing incremental compilation, we want CGU names to // reflect the path of the source level module they correspond to. // For CGUs that contain the code of multiple modules because of the @@ -82,7 +81,7 @@ pub fn merge_codegen_units<'tcx>( for cgu in codegen_units.iter_mut() { if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) { - if tcx.sess.opts.debugging_opts.human_readable_cgu_names { + if cx.tcx.sess.opts.debugging_opts.human_readable_cgu_names { cgu.set_name(Symbol::intern(&new_cgu_name)); } else { // If we don't require CGU names to be human-readable, we diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs index b45fe0ee010f9..f66fec37b25de 100644 --- a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs @@ -107,31 +107,35 @@ use rustc_span::symbol::Symbol; use crate::monomorphize::collector::InliningMap; use crate::monomorphize::collector::{self, MonoItemCollectionMode}; +pub struct PartitioningCx<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + target_cgu_count: usize, + inlining_map: &'a InliningMap<'tcx>, +} + trait Partitioner<'tcx> { fn place_root_mono_items( &mut self, - tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, mono_items: &mut dyn Iterator>, ) -> PreInliningPartitioning<'tcx>; fn merge_codegen_units( &mut self, - tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, initial_partitioning: &mut PreInliningPartitioning<'tcx>, - target_cgu_count: usize, ); fn place_inlined_mono_items( &mut self, + cx: &PartitioningCx<'_, 'tcx>, initial_partitioning: PreInliningPartitioning<'tcx>, - inlining_map: &InliningMap<'tcx>, ) -> PostInliningPartitioning<'tcx>; fn internalize_symbols( &mut self, - tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, partitioning: &mut PostInliningPartitioning<'tcx>, - inlining_map: &InliningMap<'tcx>, ); } @@ -156,12 +160,13 @@ pub fn partition<'tcx>( let _prof_timer = tcx.prof.generic_activity("cgu_partitioning"); let mut partitioner = get_partitioner(tcx); + let cx = &PartitioningCx { tcx, target_cgu_count: max_cgu_count, inlining_map }; // In the first step, we place all regular monomorphizations into their // respective 'home' codegen unit. Regular monomorphizations are all // functions and statics defined in the local crate. let mut initial_partitioning = { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots"); - partitioner.place_root_mono_items(tcx, mono_items) + partitioner.place_root_mono_items(cx, mono_items) }; initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); @@ -171,7 +176,7 @@ pub fn partition<'tcx>( // Merge until we have at most `max_cgu_count` codegen units. { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus"); - partitioner.merge_codegen_units(tcx, &mut initial_partitioning, max_cgu_count); + partitioner.merge_codegen_units(cx, &mut initial_partitioning); debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter()); } @@ -181,7 +186,7 @@ pub fn partition<'tcx>( // local functions the definition of which is marked with `#[inline]`. let mut post_inlining = { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items"); - partitioner.place_inlined_mono_items(initial_partitioning, inlining_map) + partitioner.place_inlined_mono_items(cx, initial_partitioning) }; post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); @@ -192,7 +197,7 @@ pub fn partition<'tcx>( // more freedom to optimize. if !tcx.sess.link_dead_code() { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols"); - partitioner.internalize_symbols(tcx, &mut post_inlining, inlining_map); + partitioner.internalize_symbols(cx, &mut post_inlining); } // Finally, sort by codegen unit name, so that we get deterministic results. From 0eac38b7a65c29734f4b2d34f35ee0aa9cb00a74 Mon Sep 17 00:00:00 2001 From: iximeow Date: Sun, 13 Sep 2020 20:55:06 -0700 Subject: [PATCH 18/39] fix syntax error in suggesting generic constraint in trait parameter suggest `where T: Foo` for the first bound on a trait, then suggest `, T: Foo` when the suggested bound would add to an existing set of `where` clauses. `where T: Foo` may be the first bound if `T` has a default, because we'd rather suggest ``` trait A where T: Copy ``` than ``` trait A ``` for legibility reasons. --- compiler/rustc_middle/src/ty/diagnostics.rs | 66 +++++++++++++------ .../ui/trait-impl-bound-suggestions.fixed | 20 ++++++ src/test/ui/trait-impl-bound-suggestions.rs | 20 ++++++ .../ui/trait-impl-bound-suggestions.stderr | 17 +++++ src/test/ui/type/type-check-defaults.stderr | 4 +- 5 files changed, 105 insertions(+), 22 deletions(-) create mode 100644 src/test/ui/trait-impl-bound-suggestions.fixed create mode 100644 src/test/ui/trait-impl-bound-suggestions.rs create mode 100644 src/test/ui/trait-impl-bound-suggestions.stderr diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index bc51c8b6cd41c..0416ef9e64387 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -202,33 +202,59 @@ pub fn suggest_constraining_type_param( // Suggestion: // fn foo(t: T) where T: Foo, T: Bar {... } // - insert: `, T: Zar` + // + // Additionally, there may be no `where` clause whatsoever in the case that this was + // reached becauase the generic parameter has a default: + // + // Message: + // trait Foo {... } + // - help: consider further restricting this type parameter with `where T: Zar` + // + // Suggestion: + // trait Foo where T: Zar {... } + // - insert: `where T: Zar` - let mut param_spans = Vec::new(); + if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) + && generics.where_clause.predicates.len() == 0 + { + // Suggest a bound, but there are no existing where clauses for this ``, so + // suggest adding one. + err.span_suggestion_verbose( + generics.where_clause.tail_span_for_suggestion(), + &msg_restrict_type_further, + format!(" where {}: {}", param_name, constraint), + Applicability::MachineApplicable, + ); + } else { + let mut param_spans = Vec::new(); - for predicate in generics.where_clause.predicates { - if let WherePredicate::BoundPredicate(WhereBoundPredicate { - span, bounded_ty, .. - }) = predicate - { - if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind { - if let Some(segment) = path.segments.first() { - if segment.ident.to_string() == param_name { - param_spans.push(span); + for predicate in generics.where_clause.predicates { + if let WherePredicate::BoundPredicate(WhereBoundPredicate { + span, + bounded_ty, + .. + }) = predicate + { + if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind { + if let Some(segment) = path.segments.first() { + if segment.ident.to_string() == param_name { + param_spans.push(span); + } } } } } - } - match ¶m_spans[..] { - &[¶m_span] => suggest_restrict(param_span.shrink_to_hi()), - _ => { - err.span_suggestion_verbose( - generics.where_clause.tail_span_for_suggestion(), - &msg_restrict_type_further, - format!(", {}: {}", param_name, constraint), - Applicability::MachineApplicable, - ); + match ¶m_spans[..] { + &[¶m_span] => suggest_restrict(param_span.shrink_to_hi()), + _ => { + err.span_suggestion_verbose( + generics.where_clause.tail_span_for_suggestion(), + &msg_restrict_type_further, + format!(", {}: {}", param_name, constraint), + Applicability::MachineApplicable, + ); + } } } diff --git a/src/test/ui/trait-impl-bound-suggestions.fixed b/src/test/ui/trait-impl-bound-suggestions.fixed new file mode 100644 index 0000000000000..db3a95f5c4f61 --- /dev/null +++ b/src/test/ui/trait-impl-bound-suggestions.fixed @@ -0,0 +1,20 @@ +// run-rustfix + +#[allow(unused)] +use std::fmt::Debug; +// Rustfix should add this, or use `std::fmt::Debug` instead. + +#[allow(dead_code)] +struct ConstrainedStruct { + x: X +} + +#[allow(dead_code)] +trait InsufficientlyConstrainedGeneric where X: Copy { + fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct { + //~^ ERROR the trait bound `X: Copy` is not satisfied + ConstrainedStruct { x } + } +} + +pub fn main() { } diff --git a/src/test/ui/trait-impl-bound-suggestions.rs b/src/test/ui/trait-impl-bound-suggestions.rs new file mode 100644 index 0000000000000..bf75175179efd --- /dev/null +++ b/src/test/ui/trait-impl-bound-suggestions.rs @@ -0,0 +1,20 @@ +// run-rustfix + +#[allow(unused)] +use std::fmt::Debug; +// Rustfix should add this, or use `std::fmt::Debug` instead. + +#[allow(dead_code)] +struct ConstrainedStruct { + x: X +} + +#[allow(dead_code)] +trait InsufficientlyConstrainedGeneric { + fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct { + //~^ ERROR the trait bound `X: Copy` is not satisfied + ConstrainedStruct { x } + } +} + +pub fn main() { } diff --git a/src/test/ui/trait-impl-bound-suggestions.stderr b/src/test/ui/trait-impl-bound-suggestions.stderr new file mode 100644 index 0000000000000..3a21e9c6b2ad4 --- /dev/null +++ b/src/test/ui/trait-impl-bound-suggestions.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `X: Copy` is not satisfied + --> $DIR/trait-impl-bound-suggestions.rs:14:52 + | +LL | struct ConstrainedStruct { + | ---- required by this bound in `ConstrainedStruct` +... +LL | fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct { + | ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `X` + | +help: consider further restricting type parameter `X` + | +LL | trait InsufficientlyConstrainedGeneric where X: Copy { + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type/type-check-defaults.stderr b/src/test/ui/type/type-check-defaults.stderr index fa6f342241025..d8c7f595e62ef 100644 --- a/src/test/ui/type/type-check-defaults.stderr +++ b/src/test/ui/type/type-check-defaults.stderr @@ -56,8 +56,8 @@ LL | trait Base: Super { } | help: consider further restricting type parameter `T` | -LL | trait Base: Super, T: Copy { } - | ^^^^^^^^^ +LL | trait Base: Super where T: Copy { } + | ^^^^^^^^^^^^^ error[E0277]: cannot add `u8` to `i32` --> $DIR/type-check-defaults.rs:24:66 From dd57275c3e4d52b443090d0d75a9a3443bc5ce5c Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 14 Sep 2020 09:45:02 +0200 Subject: [PATCH 19/39] shrink const infer error --- .../infer/error_reporting/need_type_info.rs | 15 ++++++++----- .../cannot-infer-const-args.full.stderr | 0 .../cannot-infer-const-args.min.stderr | 0 .../{ => infer}/cannot-infer-const-args.rs | 0 .../infer/method-chain.full.stderr | 11 ++++++++++ .../infer/method-chain.min.stderr | 11 ++++++++++ .../ui/const-generics/infer/method-chain.rs | 22 +++++++++++++++++++ .../{ => infer}/uninferred-consts.full.stderr | 4 ++-- .../{ => infer}/uninferred-consts.min.stderr | 4 ++-- .../{ => infer}/uninferred-consts.rs | 0 10 files changed, 57 insertions(+), 10 deletions(-) rename src/test/ui/const-generics/{ => infer}/cannot-infer-const-args.full.stderr (100%) rename src/test/ui/const-generics/{ => infer}/cannot-infer-const-args.min.stderr (100%) rename src/test/ui/const-generics/{ => infer}/cannot-infer-const-args.rs (100%) create mode 100644 src/test/ui/const-generics/infer/method-chain.full.stderr create mode 100644 src/test/ui/const-generics/infer/method-chain.min.stderr create mode 100644 src/test/ui/const-generics/infer/method-chain.rs rename src/test/ui/const-generics/{ => infer}/uninferred-consts.full.stderr (80%) rename src/test/ui/const-generics/{ => infer}/uninferred-consts.min.stderr (80%) rename src/test/ui/const-generics/{ => infer}/uninferred-consts.rs (100%) diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 4de84e5ba399c..9be234a7bb8bd 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -8,7 +8,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat}; use rustc_middle::hir::map::Map; use rustc_middle::ty::print::Print; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; -use rustc_middle::ty::{self, DefIdTree, Ty}; +use rustc_middle::ty::{self, DefIdTree, InferConst, Ty}; use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::kw; use rustc_span::Span; @@ -569,12 +569,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { local_visitor.visit_expr(expr); } + let span = if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val { + self.inner.borrow_mut().const_unification_table().probe_value(vid).origin.span + } else { + local_visitor.target_span + }; + let error_code = error_code.into(); - let mut err = self.tcx.sess.struct_span_err_with_code( - local_visitor.target_span, - "type annotations needed", - error_code, - ); + let mut err = + self.tcx.sess.struct_span_err_with_code(span, "type annotations needed", error_code); err.note("unable to infer the value of a const parameter"); diff --git a/src/test/ui/const-generics/cannot-infer-const-args.full.stderr b/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr similarity index 100% rename from src/test/ui/const-generics/cannot-infer-const-args.full.stderr rename to src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr diff --git a/src/test/ui/const-generics/cannot-infer-const-args.min.stderr b/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr similarity index 100% rename from src/test/ui/const-generics/cannot-infer-const-args.min.stderr rename to src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr diff --git a/src/test/ui/const-generics/cannot-infer-const-args.rs b/src/test/ui/const-generics/infer/cannot-infer-const-args.rs similarity index 100% rename from src/test/ui/const-generics/cannot-infer-const-args.rs rename to src/test/ui/const-generics/infer/cannot-infer-const-args.rs diff --git a/src/test/ui/const-generics/infer/method-chain.full.stderr b/src/test/ui/const-generics/infer/method-chain.full.stderr new file mode 100644 index 0000000000000..06e4c2e7bc6bc --- /dev/null +++ b/src/test/ui/const-generics/infer/method-chain.full.stderr @@ -0,0 +1,11 @@ +error[E0282]: type annotations needed + --> $DIR/method-chain.rs:21:33 + | +LL | Foo.bar().bar().bar().bar().baz(); + | ^^^ + | + = note: unable to infer the value of a const parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/const-generics/infer/method-chain.min.stderr b/src/test/ui/const-generics/infer/method-chain.min.stderr new file mode 100644 index 0000000000000..06e4c2e7bc6bc --- /dev/null +++ b/src/test/ui/const-generics/infer/method-chain.min.stderr @@ -0,0 +1,11 @@ +error[E0282]: type annotations needed + --> $DIR/method-chain.rs:21:33 + | +LL | Foo.bar().bar().bar().bar().baz(); + | ^^^ + | + = note: unable to infer the value of a const parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/const-generics/infer/method-chain.rs b/src/test/ui/const-generics/infer/method-chain.rs new file mode 100644 index 0000000000000..b3184642f36b4 --- /dev/null +++ b/src/test/ui/const-generics/infer/method-chain.rs @@ -0,0 +1,22 @@ +// revisions: full min + +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] + +struct Foo; + +impl Foo { + fn bar(self) -> Foo { + Foo + } + + fn baz(self) -> Foo { + println!("baz: {}", N); + Foo + } +} + +fn main() { + Foo.bar().bar().bar().bar().baz(); //~ ERROR type annotations needed +} \ No newline at end of file diff --git a/src/test/ui/const-generics/uninferred-consts.full.stderr b/src/test/ui/const-generics/infer/uninferred-consts.full.stderr similarity index 80% rename from src/test/ui/const-generics/uninferred-consts.full.stderr rename to src/test/ui/const-generics/infer/uninferred-consts.full.stderr index 2c5af9e65f827..6af49ba64523b 100644 --- a/src/test/ui/const-generics/uninferred-consts.full.stderr +++ b/src/test/ui/const-generics/infer/uninferred-consts.full.stderr @@ -1,8 +1,8 @@ error[E0282]: type annotations needed - --> $DIR/uninferred-consts.rs:14:5 + --> $DIR/uninferred-consts.rs:14:9 | LL | Foo.foo(); - | ^^^^^^^^^ + | ^^^ | = note: unable to infer the value of a const parameter diff --git a/src/test/ui/const-generics/uninferred-consts.min.stderr b/src/test/ui/const-generics/infer/uninferred-consts.min.stderr similarity index 80% rename from src/test/ui/const-generics/uninferred-consts.min.stderr rename to src/test/ui/const-generics/infer/uninferred-consts.min.stderr index 2c5af9e65f827..6af49ba64523b 100644 --- a/src/test/ui/const-generics/uninferred-consts.min.stderr +++ b/src/test/ui/const-generics/infer/uninferred-consts.min.stderr @@ -1,8 +1,8 @@ error[E0282]: type annotations needed - --> $DIR/uninferred-consts.rs:14:5 + --> $DIR/uninferred-consts.rs:14:9 | LL | Foo.foo(); - | ^^^^^^^^^ + | ^^^ | = note: unable to infer the value of a const parameter diff --git a/src/test/ui/const-generics/uninferred-consts.rs b/src/test/ui/const-generics/infer/uninferred-consts.rs similarity index 100% rename from src/test/ui/const-generics/uninferred-consts.rs rename to src/test/ui/const-generics/infer/uninferred-consts.rs From 035f8791668406bc49fc315253835cbdec247549 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 14 Sep 2020 10:08:32 +0200 Subject: [PATCH 20/39] improve const infer err --- .../src/infer/error_reporting/need_type_info.rs | 14 ++++++++++++-- compiler/rustc_middle/src/infer/unify_key.rs | 1 + .../infer/cannot-infer-const-args.full.stderr | 2 +- .../infer/cannot-infer-const-args.min.stderr | 2 +- .../const-generics/infer/method-chain.full.stderr | 2 +- .../const-generics/infer/method-chain.min.stderr | 2 +- src/test/ui/const-generics/infer/method-chain.rs | 2 +- .../infer/uninferred-consts.full.stderr | 2 +- .../infer/uninferred-consts.min.stderr | 2 +- 9 files changed, 20 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 9be234a7bb8bd..f87406c2ce469 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -6,6 +6,7 @@ use rustc_hir::def::{DefKind, Namespace}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat}; use rustc_middle::hir::map::Map; +use rustc_middle::infer::unify_key::ConstVariableOriginKind; use rustc_middle::ty::print::Print; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; use rustc_middle::ty::{self, DefIdTree, InferConst, Ty}; @@ -569,8 +570,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { local_visitor.visit_expr(expr); } + let mut param_name = None; let span = if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val { - self.inner.borrow_mut().const_unification_table().probe_value(vid).origin.span + let origin = self.inner.borrow_mut().const_unification_table().probe_value(vid).origin; + if let ConstVariableOriginKind::ConstParameterDefinition(param) = origin.kind { + param_name = Some(param); + } + origin.span } else { local_visitor.target_span }; @@ -579,7 +585,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let mut err = self.tcx.sess.struct_span_err_with_code(span, "type annotations needed", error_code); - err.note("unable to infer the value of a const parameter"); + if let Some(param_name) = param_name { + err.note(&format!("cannot infer the value of the const parameter `{}`", param_name)); + } else { + err.note("unable to infer the value of a const parameter"); + } err } diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index 2580ac6bebd86..a60a17befeffd 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -124,6 +124,7 @@ pub struct ConstVariableOrigin { pub enum ConstVariableOriginKind { MiscVariable, ConstInference, + // FIXME(const_generics): Consider storing the `DefId` of the param here. ConstParameterDefinition(Symbol), SubstitutionPlaceholder, } diff --git a/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr b/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr index 053139787edf9..84e75cc376416 100644 --- a/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr +++ b/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | foo(); | ^^^ | - = note: unable to infer the value of a const parameter + = note: cannot infer the value of the const parameter `X` error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr b/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr index 053139787edf9..84e75cc376416 100644 --- a/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr +++ b/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | foo(); | ^^^ | - = note: unable to infer the value of a const parameter + = note: cannot infer the value of the const parameter `X` error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/method-chain.full.stderr b/src/test/ui/const-generics/infer/method-chain.full.stderr index 06e4c2e7bc6bc..e65bc3f109681 100644 --- a/src/test/ui/const-generics/infer/method-chain.full.stderr +++ b/src/test/ui/const-generics/infer/method-chain.full.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | Foo.bar().bar().bar().bar().baz(); | ^^^ | - = note: unable to infer the value of a const parameter + = note: cannot infer the value of the const parameter `N` error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/method-chain.min.stderr b/src/test/ui/const-generics/infer/method-chain.min.stderr index 06e4c2e7bc6bc..e65bc3f109681 100644 --- a/src/test/ui/const-generics/infer/method-chain.min.stderr +++ b/src/test/ui/const-generics/infer/method-chain.min.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | Foo.bar().bar().bar().bar().baz(); | ^^^ | - = note: unable to infer the value of a const parameter + = note: cannot infer the value of the const parameter `N` error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/method-chain.rs b/src/test/ui/const-generics/infer/method-chain.rs index b3184642f36b4..9389ca20d106f 100644 --- a/src/test/ui/const-generics/infer/method-chain.rs +++ b/src/test/ui/const-generics/infer/method-chain.rs @@ -19,4 +19,4 @@ impl Foo { fn main() { Foo.bar().bar().bar().bar().baz(); //~ ERROR type annotations needed -} \ No newline at end of file +} diff --git a/src/test/ui/const-generics/infer/uninferred-consts.full.stderr b/src/test/ui/const-generics/infer/uninferred-consts.full.stderr index 6af49ba64523b..e47b6bd5dc691 100644 --- a/src/test/ui/const-generics/infer/uninferred-consts.full.stderr +++ b/src/test/ui/const-generics/infer/uninferred-consts.full.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | Foo.foo(); | ^^^ | - = note: unable to infer the value of a const parameter + = note: cannot infer the value of the const parameter `N` error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/uninferred-consts.min.stderr b/src/test/ui/const-generics/infer/uninferred-consts.min.stderr index 6af49ba64523b..e47b6bd5dc691 100644 --- a/src/test/ui/const-generics/infer/uninferred-consts.min.stderr +++ b/src/test/ui/const-generics/infer/uninferred-consts.min.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | Foo.foo(); | ^^^ | - = note: unable to infer the value of a const parameter + = note: cannot infer the value of the const parameter `N` error: aborting due to previous error From b88155160cf4abc07a5b8da98385ac343a5eeca0 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Mon, 14 Sep 2020 21:08:08 +0800 Subject: [PATCH 21/39] Simplify iter flatten struct doc --- library/core/src/iter/adapters/flatten.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 4202e52448dcf..4b19c451a993b 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -7,8 +7,8 @@ use super::Map; /// An iterator that maps each element to an iterator, and yields the elements /// of the produced iterators. /// -/// This `struct` is created by the [`flat_map`] method on [`Iterator`]. See its -/// documentation for more. +/// This `struct` is created by [`Iterator::flat_map`]. See its documentation +/// for more. /// /// [`flat_map`]: trait.Iterator.html#method.flat_map /// [`Iterator`]: trait.Iterator.html From 43709f7111b37a473dc779b12c755ed4df5beaf5 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 14 Sep 2020 16:11:06 +0200 Subject: [PATCH 22/39] :arrow_up: rust-analyzer --- src/tools/rust-analyzer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer index 0275b08d15216..0d03fe6ef57d3 160000 --- a/src/tools/rust-analyzer +++ b/src/tools/rust-analyzer @@ -1 +1 @@ -Subproject commit 0275b08d1521606fa733f76fe5d5707717456fb4 +Subproject commit 0d03fe6ef57d3956e92382e0e1f1a916015191cb From 5112f879ff3c106dadc9d5699f471b06473cf7e0 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Tue, 15 Sep 2020 00:35:48 +0800 Subject: [PATCH 23/39] Remove flatten doc intra-doc links --- library/core/src/iter/adapters/flatten.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 4b19c451a993b..ddb1aaebc1f3e 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -9,9 +9,6 @@ use super::Map; /// /// This `struct` is created by [`Iterator::flat_map`]. See its documentation /// for more. -/// -/// [`flat_map`]: trait.Iterator.html#method.flat_map -/// [`Iterator`]: trait.Iterator.html #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] pub struct FlatMap { From 1f26a189551ea037e769d27c433b4eaf8c3091b2 Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Mon, 14 Sep 2020 10:32:42 -0700 Subject: [PATCH 24/39] Use intra-doc links for `DelaySpanBugEmitted` Also improve the docs for it a bit. --- compiler/rustc_middle/src/ty/context.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index aacf61e5b425a..56746666e2f1f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -66,8 +66,8 @@ use std::mem; use std::ops::{Bound, Deref}; use std::sync::Arc; -/// A type that is not publicly constructable. This prevents people from making `TyKind::Error` -/// except through `tcx.err*()`, which are in this module. +/// A type that is not publicly constructable. This prevents people from making [`TyKind::Error`]s +/// except through the error-reporting functions on a [`tcx`][TyCtxt]. #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] #[derive(TyEncodable, TyDecodable, HashStable)] pub struct DelaySpanBugEmitted(()); From 15349ef5fad7778c872ce0f7d887e581819183f4 Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Mon, 14 Sep 2020 10:39:07 -0700 Subject: [PATCH 25/39] Minor improvements to `mir::Constant` docs --- compiler/rustc_middle/src/mir/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index d32a7a4062e27..29daf7e9309aa 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2285,8 +2285,8 @@ impl<'tcx> Debug for Rvalue<'tcx> { /// Constants /// /// Two constants are equal if they are the same constant. Note that -/// this does not necessarily mean that they are "==" in Rust -- in -/// particular one must be wary of `NaN`! +/// this does not necessarily mean that they are `==` in Rust -- in +/// particular, one must be wary of `NaN`! #[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, HashStable)] pub struct Constant<'tcx> { From 5c1043a7507245098d9ba1a90e034487654dd961 Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Mon, 14 Sep 2020 10:42:06 -0700 Subject: [PATCH 26/39] Fix diagram for `DebruijnIndex` --- compiler/rustc_middle/src/ty/sty.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 9f5fc5a2d3fbc..1f6c0121ae2eb 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1233,13 +1233,13 @@ rustc_index::newtype_index! { /// particular, imagine a type like this: /// /// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char) - /// ^ ^ | | | - /// | | | | | - /// | +------------+ 0 | | - /// | | | - /// +--------------------------------+ 1 | - /// | | - /// +------------------------------------------+ 0 + /// ^ ^ | | | + /// | | | | | + /// | +------------+ 0 | | + /// | | | + /// +----------------------------------+ 1 | + /// | | + /// +----------------------------------------------+ 0 /// /// In this type, there are two binders (the outer fn and the inner /// fn). We need to be able to determine, for any given region, which From e1607c87f0bb96c1c59d84a2789b7f7d2b69e182 Mon Sep 17 00:00:00 2001 From: iximeow Date: Mon, 14 Sep 2020 13:13:02 -0700 Subject: [PATCH 27/39] clean up comment text a bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Esteban Küber --- compiler/rustc_middle/src/ty/diagnostics.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 0416ef9e64387..715319747e390 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -204,7 +204,7 @@ pub fn suggest_constraining_type_param( // - insert: `, T: Zar` // // Additionally, there may be no `where` clause whatsoever in the case that this was - // reached becauase the generic parameter has a default: + // reached because the generic parameter has a default: // // Message: // trait Foo {... } @@ -217,8 +217,8 @@ pub fn suggest_constraining_type_param( if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) && generics.where_clause.predicates.len() == 0 { - // Suggest a bound, but there are no existing where clauses for this ``, so - // suggest adding one. + // Suggest a bound, but there is no existing `where` clause *and* the type param has a + // default (``), so we suggest adding `where T: Bar`. err.span_suggestion_verbose( generics.where_clause.tail_span_for_suggestion(), &msg_restrict_type_further, From 32efcfca2fece73a69efcedd1c78f45b0bbcb39c Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 14 Sep 2020 14:42:37 -0700 Subject: [PATCH 28/39] Include non-JSON output in error display for lint-doc failure. Some errors, like if rustc is broken, or dylib search path is wrong, will only display non-JSON errors. Show those, too, to make it easier to debug a problem. --- src/tools/lint-docs/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index 5323bc357c09d..92b3d186fa141 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -402,9 +402,12 @@ fn generate_lint_output( None => { let rendered: Vec<&str> = msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect(); + let non_json: Vec<&str> = + stderr.lines().filter(|line| !line.starts_with('{')).collect(); Err(format!( - "did not find lint `{}` in output of example, got:\n{}", + "did not find lint `{}` in output of example, got:\n{}\n{}", name, + non_json.join("\n"), rendered.join("\n") ) .into()) From 9dad90814543bdd10b1989020edad70939b0e869 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 14 Sep 2020 14:42:56 -0700 Subject: [PATCH 29/39] Fix generating rustc docs with non-default lib directory. --- src/bootstrap/builder.rs | 8 ++++++-- src/bootstrap/doc.rs | 4 ++++ src/bootstrap/test.rs | 8 ++++---- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 0f18660c0e109..53560c9deb6c2 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -710,7 +710,7 @@ impl<'a> Builder<'a> { /// Adds the compiler's directory of dynamic libraries to `cmd`'s dynamic /// library lookup path. - pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Cargo) { + pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Command) { // Windows doesn't need dylib path munging because the dlls for the // compiler live next to the compiler and the system will find them // automatically. @@ -718,7 +718,7 @@ impl<'a> Builder<'a> { return; } - add_dylib_path(vec![self.rustc_libdir(compiler)], &mut cmd.command); + add_dylib_path(vec![self.rustc_libdir(compiler)], cmd); } /// Gets a path to the compiler specified. @@ -1515,6 +1515,10 @@ impl Cargo { self.command.env(key.as_ref(), value.as_ref()); self } + + pub fn add_rustc_lib_path(&mut self, builder: &Builder<'_>, compiler: Compiler) { + builder.add_rustc_lib_path(compiler, &mut self.command); + } } impl From for Command { diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 98a0119e4df12..f90e76a4f4ea6 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -766,6 +766,10 @@ impl Step for RustcBook { if builder.config.verbose() { cmd.arg("--verbose"); } + // If the lib directories are in an unusual location (changed in + // config.toml), then this needs to explicitly update the dylib search + // path. + builder.add_rustc_lib_path(self.compiler, &mut cmd); builder.run(&mut cmd); // Run rustbook/mdbook to generate the HTML pages. builder.ensure(RustbookSrc { diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 045dda2d4cb4c..ba5f75c49ac77 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -270,7 +270,7 @@ impl Step for Rls { &[], ); - builder.add_rustc_lib_path(compiler, &mut cargo); + cargo.add_rustc_lib_path(builder, compiler); cargo.arg("--").args(builder.config.cmd.test_args()); if try_run(builder, &mut cargo.into()) { @@ -328,7 +328,7 @@ impl Step for Rustfmt { t!(fs::create_dir_all(&dir)); cargo.env("RUSTFMT_TEST_DIR", dir); - builder.add_rustc_lib_path(compiler, &mut cargo); + cargo.add_rustc_lib_path(builder, compiler); if try_run(builder, &mut cargo.into()) { builder.save_toolstate("rustfmt", ToolState::TestPass); @@ -449,7 +449,7 @@ impl Step for Miri { cargo.arg("--").args(builder.config.cmd.test_args()); - builder.add_rustc_lib_path(compiler, &mut cargo); + cargo.add_rustc_lib_path(builder, compiler); if !try_run(builder, &mut cargo.into()) { return; @@ -554,7 +554,7 @@ impl Step for Clippy { cargo.arg("--").args(builder.config.cmd.test_args()); - builder.add_rustc_lib_path(compiler, &mut cargo); + cargo.add_rustc_lib_path(builder, compiler); builder.run(&mut cargo.into()); } From 58310ce94bc9bde54fdbf97ec4fee18201d69221 Mon Sep 17 00:00:00 2001 From: Camelid Date: Mon, 14 Sep 2020 15:14:21 -0700 Subject: [PATCH 30/39] Use intra-doc links in `core::mem` --- library/core/src/mem/mod.rs | 57 +++++++++++-------------------------- 1 file changed, 17 insertions(+), 40 deletions(-) diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 6d8ed2f4ffb1a..aa1b5529df222 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -31,10 +31,10 @@ pub use crate::intrinsics::transmute; /// forever in an unreachable state. However, it does not guarantee that pointers /// to this memory will remain valid. /// -/// * If you want to leak memory, see [`Box::leak`][leak]. -/// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`][into_raw]. +/// * If you want to leak memory, see [`Box::leak`]. +/// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`]. /// * If you want to dispose of a value properly, running its destructor, see -/// [`mem::drop`][drop]. +/// [`mem::drop`]. /// /// # Safety /// @@ -132,15 +132,11 @@ pub use crate::intrinsics::transmute; /// ownership to `s` — the final step of interacting with `v` to dispose of it without /// running its destructor is entirely avoided. /// -/// [drop]: fn.drop.html -/// [uninit]: fn.uninitialized.html -/// [clone]: ../clone/trait.Clone.html -/// [swap]: fn.swap.html -/// [box]: ../../std/boxed/struct.Box.html -/// [leak]: ../../std/boxed/struct.Box.html#method.leak -/// [into_raw]: ../../std/boxed/struct.Box.html#method.into_raw +/// [`Box`]: ../../std/boxed/struct.Box.html +/// [`Box::leak`]: ../../std/boxed/struct.Box.html#method.leak +/// [`Box::into_raw`]: ../../std/boxed/struct.Box.html#method.into_raw +/// [`mem::drop`]: drop /// [ub]: ../../reference/behavior-considered-undefined.html -/// [`ManuallyDrop`]: struct.ManuallyDrop.html #[inline] #[rustc_const_stable(feature = "const_forget", since = "1.46.0")] #[stable(feature = "rust1", since = "1.0.0")] @@ -152,8 +148,6 @@ pub const fn forget(t: T) { /// /// This function is just a shim intended to be removed when the `unsized_locals` feature gets /// stabilized. -/// -/// [`forget`]: fn.forget.html #[inline] #[unstable(feature = "forget_unsized", issue = "none")] pub fn forget_unsized(t: T) { @@ -301,7 +295,7 @@ pub fn forget_unsized(t: T) { /// assert_eq!(2, mem::size_of::()); /// ``` /// -/// [alignment]: ./fn.align_of.html +/// [alignment]: align_of #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_promotable] @@ -365,7 +359,6 @@ pub const fn size_of_val(val: &T) -> usize { /// [slice]: ../../std/primitive.slice.html /// [trait object]: ../../book/ch17-02-trait-objects.html /// [extern type]: ../../unstable-book/language-features/extern-types.html -/// [`size_of_val`]: ../../core/mem/fn.size_of_val.html /// /// # Examples /// @@ -501,7 +494,6 @@ pub const fn align_of_val(val: &T) -> usize { /// [slice]: ../../std/primitive.slice.html /// [trait object]: ../../book/ch17-02-trait-objects.html /// [extern type]: ../../unstable-book/language-features/extern-types.html -/// [`align_of_val`]: ../../core/mem/fn.align_of_val.html /// /// # Examples /// @@ -540,7 +532,7 @@ pub unsafe fn align_of_val_raw(val: *const T) -> usize { /// `needs_drop` explicitly. Types like [`HashMap`], on the other hand, have to drop /// values one at a time and should use this API. /// -/// [`drop_in_place`]: ../ptr/fn.drop_in_place.html +/// [`drop_in_place`]: crate::ptr::drop_in_place /// [`HashMap`]: ../../std/collections/struct.HashMap.html /// /// # Examples @@ -595,9 +587,9 @@ pub const fn needs_drop() -> bool { /// This has the same effect as [`MaybeUninit::zeroed().assume_init()`][zeroed]. /// It is useful for FFI sometimes, but should generally be avoided. /// -/// [zeroed]: union.MaybeUninit.html#method.zeroed +/// [zeroed]: MaybeUninit::zeroed /// [ub]: ../../reference/behavior-considered-undefined.html -/// [inv]: union.MaybeUninit.html#initialization-invariant +/// [inv]: MaybeUninit#initialization-invariant /// /// # Examples /// @@ -650,10 +642,10 @@ pub unsafe fn zeroed() -> T { /// (Notice that the rules around uninitialized integers are not finalized yet, but /// until they are, it is advisable to avoid them.) /// -/// [`MaybeUninit`]: union.MaybeUninit.html -/// [uninit]: union.MaybeUninit.html#method.uninit -/// [assume_init]: union.MaybeUninit.html#method.assume_init -/// [inv]: union.MaybeUninit.html#initialization-invariant +/// [`MaybeUninit`]: MaybeUninit +/// [uninit]: MaybeUninit::uninit +/// [assume_init]: MaybeUninit::assume_init +/// [inv]: MaybeUninit#initialization-invariant #[inline(always)] #[rustc_deprecated(since = "1.39.0", reason = "use `mem::MaybeUninit` instead")] #[stable(feature = "rust1", since = "1.0.0")] @@ -686,9 +678,6 @@ pub unsafe fn uninitialized() -> T { /// assert_eq!(42, x); /// assert_eq!(5, y); /// ``` -/// -/// [`replace`]: fn.replace.html -/// [`take`]: fn.take.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn swap(x: &mut T, y: &mut T) { @@ -754,10 +743,6 @@ pub fn swap(x: &mut T, y: &mut T) { /// assert_eq!(buffer.get_and_reset(), vec![0, 1]); /// assert_eq!(buffer.buf.len(), 0); /// ``` -/// -/// [`Clone`]: ../../std/clone/trait.Clone.html -/// [`replace`]: fn.replace.html -/// [`swap`]: fn.swap.html #[inline] #[stable(feature = "mem_take", since = "1.40.0")] pub fn take(dest: &mut T) -> T { @@ -822,10 +807,6 @@ pub fn take(dest: &mut T) -> T { /// assert_eq!(buffer.replace_index(0, 2), 0); /// assert_eq!(buffer.buf[0], 2); /// ``` -/// -/// [`Clone`]: ../../std/clone/trait.Clone.html -/// [`swap`]: fn.swap.html -/// [`take`]: fn.take.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "if you don't need the old value, you can just assign the new value directly"] @@ -851,7 +832,7 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// Because `_x` is moved into the function, it is automatically dropped before /// the function returns. /// -/// [drop]: ../ops/trait.Drop.html +/// [drop]: Drop /// /// # Examples /// @@ -894,8 +875,7 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// println!("x: {}, y: {}", x, y.0); // still available /// ``` /// -/// [`RefCell`]: ../../std/cell/struct.RefCell.html -/// [`Copy`]: ../../std/marker/trait.Copy.html +/// [`RefCell`]: crate::cell::RefCell #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn drop(_x: T) {} @@ -914,7 +894,6 @@ pub fn drop(_x: T) {} /// `T`. /// /// [ub]: ../../reference/behavior-considered-undefined.html -/// [size_of]: fn.size_of.html /// /// # Examples /// @@ -960,8 +939,6 @@ pub unsafe fn transmute_copy(src: &T) -> U { /// Opaque type representing the discriminant of an enum. /// /// See the [`discriminant`] function in this module for more information. -/// -/// [`discriminant`]: fn.discriminant.html #[stable(feature = "discriminant_value", since = "1.21.0")] pub struct Discriminant(::Discriminant); From f7f9a6c1356dbc79394fbf93d485d6d8b44db380 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 14 Sep 2020 22:03:54 -0400 Subject: [PATCH 31/39] Add a comment why `extern crate` is necessary for rustdoc --- src/librustdoc/lib.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 73a783d54060c..94e51d91b542a 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -16,6 +16,12 @@ #[macro_use] extern crate lazy_static; +#[macro_use] +extern crate tracing; + +// N.B. these need `extern crate` even in 2018 edition +// because they're loaded implicitly from the sysroot. +// Dependencies listed in Cargo.toml do not need extern crate. extern crate rustc_ast; extern crate rustc_ast_pretty; extern crate rustc_attr; @@ -42,8 +48,6 @@ extern crate rustc_target; extern crate rustc_trait_selection; extern crate rustc_typeck; extern crate test as testing; -#[macro_use] -extern crate tracing; use std::default::Default; use std::env; From 1c7204f870ab1a654ffd0252b6097afc4dbfd48d Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 14 Sep 2020 04:22:43 +0000 Subject: [PATCH 32/39] Prefer asm! over llvm_asm! in core --- library/core/src/hint.rs | 28 +++++++++++++++++++++-- library/core/src/num/dec2flt/algorithm.rs | 20 +++++++++++++--- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index d40a380286762..5b00de4578e02 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -111,7 +111,7 @@ pub fn spin_loop() { #[inline] #[unstable(feature = "test", issue = "50297")] #[allow(unreachable_code)] // this makes #[cfg] a bit easier below. -pub fn black_box(dummy: T) -> T { +pub fn black_box(mut dummy: T) -> T { // We need to "use" the argument in some way LLVM can't introspect, and on // targets that support it we can typically leverage inline assembly to do // this. LLVM's interpretation of inline assembly is that it's, well, a black @@ -121,7 +121,31 @@ pub fn black_box(dummy: T) -> T { #[cfg(not(miri))] // This is just a hint, so it is fine to skip in Miri. // SAFETY: the inline assembly is a no-op. unsafe { - llvm_asm!("" : : "r"(&dummy)); + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + { + asm!( + "/* {0} */", + in(reg) &mut dummy, + // FIXME: We are using ATT syntax to support LLVM 8 and LLVM 9. + options(att_syntax, nostack, preserves_flags), + ); + } + #[cfg(target_arch = "nvptx64")] + { + asm!( + "/* {0} */", + in(reg64) &mut dummy, + options(nostack, preserves_flags), + ); + } + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "nvptx64")))] + { + asm!( + "/* {0} */", + in(reg) &mut dummy, + options(nostack, preserves_flags), + ); + } } dummy diff --git a/library/core/src/num/dec2flt/algorithm.rs b/library/core/src/num/dec2flt/algorithm.rs index aaeb4d8a22c29..a5fbdc6ee2d48 100644 --- a/library/core/src/num/dec2flt/algorithm.rs +++ b/library/core/src/num/dec2flt/algorithm.rs @@ -60,12 +60,19 @@ mod fpu_precision { fn set_cw(cw: u16) { // SAFETY: the `fldcw` instruction has been audited to be able to work correctly with // any `u16` - unsafe { llvm_asm!("fldcw $0" :: "m" (cw) :: "volatile") } + unsafe { + asm!( + "fldcw ({})", + in(reg) &cw, + // FIXME: We are using ATT syntax to support LLVM 8 and LLVM 9. + options(att_syntax, nostack), + ) + } } /// Sets the precision field of the FPU to `T` and returns a `FPUControlWord`. pub fn set_precision() -> FPUControlWord { - let cw = 0u16; + let mut cw = 0_u16; // Compute the value for the Precision Control field that is appropriate for `T`. let cw_precision = match size_of::() { @@ -78,7 +85,14 @@ mod fpu_precision { // `FPUControlWord` structure is dropped // SAFETY: the `fnstcw` instruction has been audited to be able to work correctly with // any `u16` - unsafe { llvm_asm!("fnstcw $0" : "=*m" (&cw) ::: "volatile") } + unsafe { + asm!( + "fnstcw ({})", + in(reg) &mut cw, + // FIXME: We are using ATT syntax to support LLVM 8 and LLVM 9. + options(att_syntax, nostack), + ) + } // Set the control word to the desired precision. This is achieved by masking away the old // precision (bits 8 and 9, 0x300) and replacing it with the precision flag computed above. From 1f572b03492e7d3ce7156d00f9b44ccedf47bb50 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Tue, 15 Sep 2020 14:41:43 +0800 Subject: [PATCH 33/39] 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 176956c115c2b797471a3f59eef3e17789229007 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Tue, 15 Sep 2020 00:02:48 +0200 Subject: [PATCH 34/39] Test and fix Sync & Send traits of BTreeMap artefacts --- library/alloc/src/collections/btree/borrow.rs | 3 + .../alloc/src/collections/btree/map/tests.rs | 140 ++++++++++++++++++ 2 files changed, 143 insertions(+) diff --git a/library/alloc/src/collections/btree/borrow.rs b/library/alloc/src/collections/btree/borrow.rs index 5c95acfbe9c20..016f139a501a0 100644 --- a/library/alloc/src/collections/btree/borrow.rs +++ b/library/alloc/src/collections/btree/borrow.rs @@ -16,6 +16,9 @@ pub struct DormantMutRef<'a, T> { _marker: PhantomData<&'a mut T>, } +unsafe impl<'a, T> Sync for DormantMutRef<'a, T> where &'a mut T: Sync {} +unsafe impl<'a, T> Send for DormantMutRef<'a, T> where &'a mut T: Send {} + impl<'a, T> DormantMutRef<'a, T> { /// Capture a unique borrow, and immediately reborrow it. For the compiler, /// the lifetime of the new reference is the same as the lifetime of the diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index af5cf7d7d875c..d2cd6b8e5241a 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -1418,6 +1418,146 @@ fn test_variance() { } } +#[test] +#[allow(dead_code)] +fn test_sync() { + fn map(v: &BTreeMap) -> impl Sync + '_ { + v + } + + fn into_iter(v: BTreeMap) -> impl Sync { + v.into_iter() + } + + fn into_keys(v: BTreeMap) -> impl Sync { + v.into_keys() + } + + fn into_values(v: BTreeMap) -> impl Sync { + v.into_values() + } + + fn drain_filter(v: &mut BTreeMap) -> impl Sync + '_ { + v.drain_filter(|_, _| false) + } + + fn iter(v: &BTreeMap) -> impl Sync + '_ { + v.iter() + } + + fn iter_mut(v: &mut BTreeMap) -> impl Sync + '_ { + v.iter_mut() + } + + fn keys(v: &BTreeMap) -> impl Sync + '_ { + v.keys() + } + + fn values(v: &BTreeMap) -> impl Sync + '_ { + v.values() + } + + fn values_mut(v: &mut BTreeMap) -> impl Sync + '_ { + v.values_mut() + } + + fn range(v: &BTreeMap) -> impl Sync + '_ { + v.range(..) + } + + fn range_mut(v: &mut BTreeMap) -> impl Sync + '_ { + v.range_mut(..) + } + + fn entry(v: &mut BTreeMap) -> impl Sync + '_ { + v.entry(Default::default()) + } + + fn occupied_entry(v: &mut BTreeMap) -> impl Sync + '_ { + match v.entry(Default::default()) { + Occupied(entry) => entry, + _ => unreachable!(), + } + } + + fn vacant_entry(v: &mut BTreeMap) -> impl Sync + '_ { + match v.entry(Default::default()) { + Vacant(entry) => entry, + _ => unreachable!(), + } + } +} + +#[test] +#[allow(dead_code)] +fn test_send() { + fn map(v: BTreeMap) -> impl Send { + v + } + + fn into_iter(v: BTreeMap) -> impl Send { + v.into_iter() + } + + fn into_keys(v: BTreeMap) -> impl Send { + v.into_keys() + } + + fn into_values(v: BTreeMap) -> impl Send { + v.into_values() + } + + fn drain_filter(v: &mut BTreeMap) -> impl Send + '_ { + v.drain_filter(|_, _| false) + } + + fn iter(v: &BTreeMap) -> impl Send + '_ { + v.iter() + } + + fn iter_mut(v: &mut BTreeMap) -> impl Send + '_ { + v.iter_mut() + } + + fn keys(v: &BTreeMap) -> impl Send + '_ { + v.keys() + } + + fn values(v: &BTreeMap) -> impl Send + '_ { + v.values() + } + + fn values_mut(v: &mut BTreeMap) -> impl Send + '_ { + v.values_mut() + } + + fn range(v: &BTreeMap) -> impl Send + '_ { + v.range(..) + } + + fn range_mut(v: &mut BTreeMap) -> impl Send + '_ { + v.range_mut(..) + } + + fn entry(v: &mut BTreeMap) -> impl Send + '_ { + v.entry(Default::default()) + } + + fn occupied_entry(v: &mut BTreeMap) -> impl Send + '_ { + match v.entry(Default::default()) { + Occupied(entry) => entry, + _ => unreachable!(), + } + } + + fn vacant_entry(v: &mut BTreeMap) -> impl Send + '_ { + match v.entry(Default::default()) { + Vacant(entry) => entry, + _ => unreachable!(), + } + } +} + #[test] fn test_occupied_entry_key() { let mut a = BTreeMap::new(); From b93a8315f2fcff479a99e0694309fe12dbe095d5 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 15 Sep 2020 08:40:10 -0400 Subject: [PATCH 35/39] Add a comment why rustdoc loads crates from the sysroot --- src/librustdoc/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 94e51d91b542a..7762e8f8d4fb1 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -21,7 +21,11 @@ extern crate tracing; // N.B. these need `extern crate` even in 2018 edition // because they're loaded implicitly from the sysroot. -// Dependencies listed in Cargo.toml do not need extern crate. +// The reason they're loaded from the sysroot is because +// the rustdoc artifacts aren't stored in rustc's cargo target directory. +// So if `rustc` was specified in Cargo.toml, this would spuriously rebuild crates. +// +// Dependencies listed in Cargo.toml do not need `extern crate`. extern crate rustc_ast; extern crate rustc_ast_pretty; extern crate rustc_attr; From 5f3145febd4e0e8ff28bfeec0418ece7f832428a Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 15 Sep 2020 08:59:34 -0400 Subject: [PATCH 36/39] Avoid printing dry run timings --- src/bootstrap/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 0f18660c0e109..dc027661c8320 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -1421,7 +1421,7 @@ impl<'a> Builder<'a> { (out, dur - deps) }; - if self.config.print_step_timings { + if self.config.print_step_timings && !self.config.dry_run { println!("[TIMING] {:?} -- {}.{:03}", step, dur.as_secs(), dur.subsec_millis()); } From 328c61c15711ae8a741b2aa56af1c450f54d1796 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 11 Sep 2020 22:17:16 -0400 Subject: [PATCH 37/39] Make the default stage for x.py configurable This allows configuring the default stage for each sub-command individually. - Normalize the stage as early as possible, so there's no confusion about which to use. - Don't add an explicit `stage` option in config.toml This offers no more flexibility than `*_stage` and makes it confusing which takes precedence. - Always give `--stage N` precedence over config.toml - Fix bootstrap tests This changes the tests to go through `Config::parse` so that they test the actual defaults, not the dummy ones provided by `default_opts`. To make this workable (and independent of the environment), it does not read `config.toml` for tests. --- config.toml.example | 17 ++++++++++ src/bootstrap/builder.rs | 31 ++---------------- src/bootstrap/builder/tests.rs | 14 ++++---- src/bootstrap/config.rs | 59 ++++++++++++++++++++++++++++++---- 4 files changed, 79 insertions(+), 42 deletions(-) diff --git a/config.toml.example b/config.toml.example index 2d5b3136450b9..f10d1a7b44e5e 100644 --- a/config.toml.example +++ b/config.toml.example @@ -111,6 +111,23 @@ # General build configuration options # ============================================================================= [build] +# The default stage to use for the `doc` subcommand +#doc-stage = 0 + +# The default stage to use for the `build` subcommand +#build-stage = 1 + +# The default stage to use for the `test` subcommand +#test-stage = 1 + +# The default stage to use for the `dist` subcommand +#dist-stage = 2 + +# The default stage to use for the `install` subcommand +#install-stage = 2 + +# The default stage to use for the `bench` subcommand +#bench-stage = 2 # Build triple for the original snapshot compiler. This must be a compiler that # nightlies are already produced for. The current platform must be able to run diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 31d4f1f28a86d..034b01a502cc5 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -526,23 +526,9 @@ impl<'a> Builder<'a> { } fn new_internal(build: &Build, kind: Kind, paths: Vec) -> Builder<'_> { - let top_stage = if let Some(explicit_stage) = build.config.stage { - explicit_stage - } else { - // See https://github.com/rust-lang/compiler-team/issues/326 - match kind { - Kind::Doc => 0, - Kind::Build | Kind::Test => 1, - Kind::Bench | Kind::Dist | Kind::Install => 2, - // These are all bootstrap tools, which don't depend on the compiler. - // The stage we pass shouldn't matter, but use 0 just in case. - Kind::Check | Kind::Clippy | Kind::Fix | Kind::Run | Kind::Format => 0, - } - }; - Builder { build, - top_stage, + top_stage: build.config.stage, kind, cache: Cache::new(), stack: RefCell::new(Vec::new()), @@ -566,20 +552,7 @@ impl<'a> Builder<'a> { Subcommand::Format { .. } | Subcommand::Clean { .. } => panic!(), }; - let this = Self::new_internal(build, kind, paths.to_owned()); - - // CI should always run stage 2 builds, unless it specifically states otherwise - #[cfg(not(test))] - if build.config.stage.is_none() && build.ci_env != crate::CiEnv::None { - match kind { - Kind::Test | Kind::Doc | Kind::Build | Kind::Bench | Kind::Dist | Kind::Install => { - assert_eq!(this.top_stage, 2) - } - Kind::Check | Kind::Clippy | Kind::Fix | Kind::Run | Kind::Format => {} - } - } - - this + Self::new_internal(build, kind, paths.to_owned()) } pub fn execute_cli(&self) { diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index c6eac95c34507..f96925f927086 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -2,8 +2,8 @@ use super::*; use crate::config::{Config, TargetSelection}; use std::thread; -fn configure(host: &[&str], target: &[&str]) -> Config { - let mut config = Config::default_opts(); +fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config { + let mut config = Config::parse(&[cmd.to_owned()]); // don't save toolstates config.save_toolstates = None; config.skip_only_host_steps = false; @@ -42,7 +42,7 @@ mod defaults { #[test] fn build_default() { - let build = Build::new(configure(&[], &[])); + let build = Build::new(configure("build", &[], &[])); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); @@ -70,7 +70,7 @@ mod defaults { #[test] fn build_stage_0() { - let config = Config { stage: Some(0), ..configure(&[], &[]) }; + let config = Config { stage: 0, ..configure("build", &[], &[]) }; let build = Build::new(config); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); @@ -92,7 +92,7 @@ mod defaults { #[test] fn doc_default() { - let mut config = configure(&[], &[]); + let mut config = configure("doc", &[], &[]); config.compiler_docs = true; config.cmd = Subcommand::Doc { paths: Vec::new(), open: false }; let build = Build::new(config); @@ -126,7 +126,7 @@ mod dist { use pretty_assertions::assert_eq; fn configure(host: &[&str], target: &[&str]) -> Config { - Config { stage: Some(2), ..super::configure(host, target) } + Config { stage: 2, ..super::configure("dist", host, target) } } #[test] @@ -455,7 +455,7 @@ mod dist { #[test] fn test_with_no_doc_stage0() { let mut config = configure(&[], &[]); - config.stage = Some(0); + config.stage = 0; config.cmd = Subcommand::Test { paths: vec!["library/std".into()], test_args: vec![], diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 5a79d3db5c905..cc0a534314a52 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -10,7 +10,6 @@ use std::ffi::OsString; use std::fmt; use std::fs; use std::path::{Path, PathBuf}; -use std::process; use crate::cache::{Interned, INTERNER}; use crate::flags::Flags; @@ -57,7 +56,7 @@ pub struct Config { pub skip_only_host_steps: bool, pub on_fail: Option, - pub stage: Option, + pub stage: u32, pub keep_stage: Vec, pub src: PathBuf, pub jobs: Option, @@ -300,6 +299,12 @@ struct Build { configure_args: Option>, local_rebuild: Option, print_step_timings: Option, + doc_stage: Option, + build_stage: Option, + test_stage: Option, + install_stage: Option, + dist_stage: Option, + bench_stage: Option, } /// TOML representation of various global install decisions. @@ -480,13 +485,11 @@ impl Config { pub fn parse(args: &[String]) -> Config { let flags = Flags::parse(&args); - let file = flags.config.clone(); let mut config = Config::default_opts(); config.exclude = flags.exclude; config.rustc_error_format = flags.rustc_error_format; config.json_output = flags.json_output; config.on_fail = flags.on_fail; - config.stage = flags.stage; config.jobs = flags.jobs.map(threads_from_config); config.cmd = flags.cmd; config.incremental = flags.incremental; @@ -503,8 +506,14 @@ impl Config { config.out = dir; } - let toml = file + #[cfg(test)] + let toml = TomlConfig::default(); + #[cfg(not(test))] + let toml = flags + .config .map(|file| { + use std::process; + let contents = t!(fs::read_to_string(&file)); match toml::from_str(&contents) { Ok(table) => table, @@ -520,7 +529,7 @@ impl Config { }) .unwrap_or_else(TomlConfig::default); - let build = toml.build.clone().unwrap_or_default(); + let build = toml.build.unwrap_or_default(); // If --target was specified but --host wasn't specified, don't run any host-only tests. let has_hosts = build.host.is_some() || flags.host.is_some(); @@ -564,6 +573,44 @@ impl Config { set(&mut config.configure_args, build.configure_args); set(&mut config.local_rebuild, build.local_rebuild); set(&mut config.print_step_timings, build.print_step_timings); + + // See https://github.com/rust-lang/compiler-team/issues/326 + config.stage = match config.cmd { + Subcommand::Doc { .. } => flags.stage.or(build.doc_stage).unwrap_or(0), + Subcommand::Build { .. } => flags.stage.or(build.build_stage).unwrap_or(1), + Subcommand::Test { .. } => flags.stage.or(build.test_stage).unwrap_or(1), + Subcommand::Bench { .. } => flags.stage.or(build.bench_stage).unwrap_or(2), + Subcommand::Dist { .. } => flags.stage.or(build.dist_stage).unwrap_or(2), + Subcommand::Install { .. } => flags.stage.or(build.install_stage).unwrap_or(2), + // These are all bootstrap tools, which don't depend on the compiler. + // The stage we pass shouldn't matter, but use 0 just in case. + Subcommand::Clean { .. } + | Subcommand::Check { .. } + | Subcommand::Clippy { .. } + | Subcommand::Fix { .. } + | Subcommand::Run { .. } + | Subcommand::Format { .. } => flags.stage.unwrap_or(0), + }; + + // CI should always run stage 2 builds, unless it specifically states otherwise + #[cfg(not(test))] + if flags.stage.is_none() && crate::CiEnv::current() != crate::CiEnv::None { + match config.cmd { + Subcommand::Test { .. } + | Subcommand::Doc { .. } + | Subcommand::Build { .. } + | Subcommand::Bench { .. } + | Subcommand::Dist { .. } + | Subcommand::Install { .. } => assert_eq!(config.stage, 2), + Subcommand::Clean { .. } + | Subcommand::Check { .. } + | Subcommand::Clippy { .. } + | Subcommand::Fix { .. } + | Subcommand::Run { .. } + | Subcommand::Format { .. } => {} + } + } + config.verbose = cmp::max(config.verbose, flags.verbose); if let Some(ref install) = toml.install { From 21b0c1286a1f01cb8a21bda0973833ca11889364 Mon Sep 17 00:00:00 2001 From: khyperia Date: Tue, 15 Sep 2020 23:35:31 +0200 Subject: [PATCH 38/39] Extract some intrinsics out of rustc_codegen_llvm A significant amount of intrinsics do not actually need backend-specific behaviors to be implemented, instead relying on methods already in rustc_codegen_ssa. So, extract those methods out to rustc_codegen_ssa, so that each backend doesn't need to reimplement the same code. --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 527 +--------------- compiler/rustc_codegen_ssa/src/mir/block.rs | 3 +- .../rustc_codegen_ssa/src/mir/intrinsic.rs | 596 ++++++++++++++++++ compiler/rustc_codegen_ssa/src/mir/mod.rs | 1 + 4 files changed, 606 insertions(+), 521 deletions(-) create mode 100644 compiler/rustc_codegen_ssa/src/mir/intrinsic.rs diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 2208ceca00c83..7f5b09eac4f9e 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -7,15 +7,12 @@ use crate::type_of::LayoutLlvmExt; use crate::va_arg::emit_va_arg; use crate::value::Value; -use rustc_ast as ast; use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh}; use rustc_codegen_ssa::common::span_invalid_monomorphization_error; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; -use rustc_codegen_ssa::glue; -use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; +use rustc_codegen_ssa::mir::operand::OperandRef; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::*; -use rustc_codegen_ssa::MemFlags; use rustc_hir as hir; use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt}; use rustc_middle::ty::{self, Ty}; @@ -71,8 +68,6 @@ fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: Symbol) -> Option<&'ll Va sym::nearbyintf64 => "llvm.nearbyint.f64", sym::roundf32 => "llvm.round.f32", sym::roundf64 => "llvm.round.f64", - sym::assume => "llvm.assume", - sym::abort => "llvm.trap", _ => return None, }; Some(cx.get_intrinsic(&llvm_name)) @@ -112,9 +107,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { &args.iter().map(|arg| arg.immediate()).collect::>(), None, ), - sym::unreachable => { - return; - } sym::likely => { let expect = self.get_intrinsic(&("llvm.expect.i1")); self.call(expect, &[args[0].immediate(), self.const_bool(true)], None) @@ -137,8 +129,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { let llfn = self.get_intrinsic(&("llvm.debugtrap")); self.call(llfn, &[], None) } - sym::va_start => self.va_start(args[0].immediate()), - sym::va_end => self.va_end(args[0].immediate()), sym::va_copy => { let intrinsic = self.cx().get_intrinsic(&("llvm.va_copy")); self.call(intrinsic, &[args[0].immediate(), args[1].immediate()], None) @@ -169,123 +159,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { _ => bug!("the va_arg intrinsic does not work with non-scalar types"), } } - sym::size_of_val => { - let tp_ty = substs.type_at(0); - if let OperandValue::Pair(_, meta) = args[0].val { - let (llsize, _) = glue::size_and_align_of_dst(self, tp_ty, Some(meta)); - llsize - } else { - self.const_usize(self.size_of(tp_ty).bytes()) - } - } - sym::min_align_of_val => { - let tp_ty = substs.type_at(0); - if let OperandValue::Pair(_, meta) = args[0].val { - let (_, llalign) = glue::size_and_align_of_dst(self, tp_ty, Some(meta)); - llalign - } else { - self.const_usize(self.align_of(tp_ty).bytes()) - } - } - sym::size_of - | sym::pref_align_of - | sym::min_align_of - | sym::needs_drop - | sym::type_id - | sym::type_name - | sym::variant_count => { - let value = self - .tcx - .const_eval_instance(ty::ParamEnv::reveal_all(), instance, None) - .unwrap(); - OperandRef::from_const(self, value, ret_ty).immediate_or_packed_pair(self) - } - // Effectively no-op - sym::forget => { - return; - } - sym::offset => { - let ptr = args[0].immediate(); - let offset = args[1].immediate(); - self.inbounds_gep(ptr, &[offset]) - } - sym::arith_offset => { - let ptr = args[0].immediate(); - let offset = args[1].immediate(); - self.gep(ptr, &[offset]) - } - - sym::copy_nonoverlapping => { - copy_intrinsic( - self, - false, - false, - substs.type_at(0), - args[1].immediate(), - args[0].immediate(), - args[2].immediate(), - ); - return; - } - sym::copy => { - copy_intrinsic( - self, - true, - false, - substs.type_at(0), - args[1].immediate(), - args[0].immediate(), - args[2].immediate(), - ); - return; - } - sym::write_bytes => { - memset_intrinsic( - self, - false, - substs.type_at(0), - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - ); - return; - } - sym::volatile_copy_nonoverlapping_memory => { - copy_intrinsic( - self, - false, - true, - substs.type_at(0), - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - ); - return; - } - sym::volatile_copy_memory => { - copy_intrinsic( - self, - true, - true, - substs.type_at(0), - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - ); - return; - } - sym::volatile_set_memory => { - memset_intrinsic( - self, - true, - substs.type_at(0), - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - ); - return; - } sym::volatile_load | sym::unaligned_volatile_load => { let tp_ty = substs.type_at(0); let mut ptr = args[0].immediate(); @@ -343,20 +217,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { | sym::ctpop | sym::bswap | sym::bitreverse - | sym::add_with_overflow - | sym::sub_with_overflow - | sym::mul_with_overflow - | sym::wrapping_add - | sym::wrapping_sub - | sym::wrapping_mul - | sym::unchecked_div - | sym::unchecked_rem - | sym::unchecked_shl - | sym::unchecked_shr - | sym::unchecked_add - | sym::unchecked_sub - | sym::unchecked_mul - | sym::exact_div | sym::rotate_left | sym::rotate_right | sym::saturating_add @@ -396,84 +256,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { &[args[0].immediate()], None, ), - sym::add_with_overflow - | sym::sub_with_overflow - | sym::mul_with_overflow => { - let intrinsic = format!( - "llvm.{}{}.with.overflow.i{}", - if signed { 's' } else { 'u' }, - &name_str[..3], - width - ); - let llfn = self.get_intrinsic(&intrinsic); - - // Convert `i1` to a `bool`, and write it to the out parameter - let pair = - self.call(llfn, &[args[0].immediate(), args[1].immediate()], None); - let val = self.extract_value(pair, 0); - let overflow = self.extract_value(pair, 1); - let overflow = self.zext(overflow, self.type_bool()); - - let dest = result.project_field(self, 0); - self.store(val, dest.llval, dest.align); - let dest = result.project_field(self, 1); - self.store(overflow, dest.llval, dest.align); - - return; - } - sym::wrapping_add => self.add(args[0].immediate(), args[1].immediate()), - sym::wrapping_sub => self.sub(args[0].immediate(), args[1].immediate()), - sym::wrapping_mul => self.mul(args[0].immediate(), args[1].immediate()), - sym::exact_div => { - if signed { - self.exactsdiv(args[0].immediate(), args[1].immediate()) - } else { - self.exactudiv(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_div => { - if signed { - self.sdiv(args[0].immediate(), args[1].immediate()) - } else { - self.udiv(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_rem => { - if signed { - self.srem(args[0].immediate(), args[1].immediate()) - } else { - self.urem(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_shl => self.shl(args[0].immediate(), args[1].immediate()), - sym::unchecked_shr => { - if signed { - self.ashr(args[0].immediate(), args[1].immediate()) - } else { - self.lshr(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_add => { - if signed { - self.unchecked_sadd(args[0].immediate(), args[1].immediate()) - } else { - self.unchecked_uadd(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_sub => { - if signed { - self.unchecked_ssub(args[0].immediate(), args[1].immediate()) - } else { - self.unchecked_usub(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_mul => { - if signed { - self.unchecked_smul(args[0].immediate(), args[1].immediate()) - } else { - self.unchecked_umul(args[0].immediate(), args[1].immediate()) - } - } sym::rotate_left | sym::rotate_right => { let is_left = name == sym::rotate_left; let val = args[0].immediate(); @@ -513,75 +295,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { } } } - sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => { - match float_type_width(arg_tys[0]) { - Some(_width) => match name { - sym::fadd_fast => self.fadd_fast(args[0].immediate(), args[1].immediate()), - sym::fsub_fast => self.fsub_fast(args[0].immediate(), args[1].immediate()), - sym::fmul_fast => self.fmul_fast(args[0].immediate(), args[1].immediate()), - sym::fdiv_fast => self.fdiv_fast(args[0].immediate(), args[1].immediate()), - sym::frem_fast => self.frem_fast(args[0].immediate(), args[1].immediate()), - _ => bug!(), - }, - None => { - span_invalid_monomorphization_error( - tcx.sess, - span, - &format!( - "invalid monomorphization of `{}` intrinsic: \ - expected basic float type, found `{}`", - name, arg_tys[0] - ), - ); - return; - } - } - } - - sym::float_to_int_unchecked => { - if float_type_width(arg_tys[0]).is_none() { - span_invalid_monomorphization_error( - tcx.sess, - span, - &format!( - "invalid monomorphization of `float_to_int_unchecked` \ - intrinsic: expected basic float type, \ - found `{}`", - arg_tys[0] - ), - ); - return; - } - let (width, signed) = match int_type_width_signed(ret_ty, self.cx) { - Some(pair) => pair, - None => { - span_invalid_monomorphization_error( - tcx.sess, - span, - &format!( - "invalid monomorphization of `float_to_int_unchecked` \ - intrinsic: expected basic integer type, \ - found `{}`", - ret_ty - ), - ); - return; - } - }; - if signed { - self.fptosi(args[0].immediate(), self.cx.type_ix(width)) - } else { - self.fptoui(args[0].immediate(), self.cx.type_ix(width)) - } - } - - sym::discriminant_value => { - if ret_ty.is_integral() { - args[0].deref(self.cx()).codegen_get_discr(self, ret_ty) - } else { - span_bug!(span, "Invalid discriminant type for `{:?}`", arg_tys[0]) - } - } _ if name_str.starts_with("simd_") => { match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) { @@ -589,174 +302,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { Err(()) => return, } } - // This requires that atomic intrinsics follow a specific naming pattern: - // "atomic_[_]", and no ordering means SeqCst - name if name_str.starts_with("atomic_") => { - use rustc_codegen_ssa::common::AtomicOrdering::*; - use rustc_codegen_ssa::common::{AtomicRmwBinOp, SynchronizationScope}; - - let split: Vec<&str> = name_str.split('_').collect(); - - let is_cxchg = split[1] == "cxchg" || split[1] == "cxchgweak"; - let (order, failorder) = match split.len() { - 2 => (SequentiallyConsistent, SequentiallyConsistent), - 3 => match split[2] { - "unordered" => (Unordered, Unordered), - "relaxed" => (Monotonic, Monotonic), - "acq" => (Acquire, Acquire), - "rel" => (Release, Monotonic), - "acqrel" => (AcquireRelease, Acquire), - "failrelaxed" if is_cxchg => (SequentiallyConsistent, Monotonic), - "failacq" if is_cxchg => (SequentiallyConsistent, Acquire), - _ => self.sess().fatal("unknown ordering in atomic intrinsic"), - }, - 4 => match (split[2], split[3]) { - ("acq", "failrelaxed") if is_cxchg => (Acquire, Monotonic), - ("acqrel", "failrelaxed") if is_cxchg => (AcquireRelease, Monotonic), - _ => self.sess().fatal("unknown ordering in atomic intrinsic"), - }, - _ => self.sess().fatal("Atomic intrinsic not in correct format"), - }; - - let invalid_monomorphization = |ty| { - span_invalid_monomorphization_error( - tcx.sess, - span, - &format!( - "invalid monomorphization of `{}` intrinsic: \ - expected basic integer type, found `{}`", - name, ty - ), - ); - }; - - match split[1] { - "cxchg" | "cxchgweak" => { - let ty = substs.type_at(0); - if int_type_width_signed(ty, self).is_some() { - let weak = split[1] == "cxchgweak"; - let pair = self.atomic_cmpxchg( - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - order, - failorder, - weak, - ); - let val = self.extract_value(pair, 0); - let success = self.extract_value(pair, 1); - let success = self.zext(success, self.type_bool()); - - let dest = result.project_field(self, 0); - self.store(val, dest.llval, dest.align); - let dest = result.project_field(self, 1); - self.store(success, dest.llval, dest.align); - return; - } else { - return invalid_monomorphization(ty); - } - } - - "load" => { - let ty = substs.type_at(0); - if int_type_width_signed(ty, self).is_some() { - let size = self.size_of(ty); - self.atomic_load(args[0].immediate(), order, size) - } else { - return invalid_monomorphization(ty); - } - } - - "store" => { - let ty = substs.type_at(0); - if int_type_width_signed(ty, self).is_some() { - let size = self.size_of(ty); - self.atomic_store( - args[1].immediate(), - args[0].immediate(), - order, - size, - ); - return; - } else { - return invalid_monomorphization(ty); - } - } - - "fence" => { - self.atomic_fence(order, SynchronizationScope::CrossThread); - return; - } - - "singlethreadfence" => { - self.atomic_fence(order, SynchronizationScope::SingleThread); - return; - } - - // These are all AtomicRMW ops - op => { - let atom_op = match op { - "xchg" => AtomicRmwBinOp::AtomicXchg, - "xadd" => AtomicRmwBinOp::AtomicAdd, - "xsub" => AtomicRmwBinOp::AtomicSub, - "and" => AtomicRmwBinOp::AtomicAnd, - "nand" => AtomicRmwBinOp::AtomicNand, - "or" => AtomicRmwBinOp::AtomicOr, - "xor" => AtomicRmwBinOp::AtomicXor, - "max" => AtomicRmwBinOp::AtomicMax, - "min" => AtomicRmwBinOp::AtomicMin, - "umax" => AtomicRmwBinOp::AtomicUMax, - "umin" => AtomicRmwBinOp::AtomicUMin, - _ => self.sess().fatal("unknown atomic operation"), - }; - - let ty = substs.type_at(0); - if int_type_width_signed(ty, self).is_some() { - self.atomic_rmw( - atom_op, - args[0].immediate(), - args[1].immediate(), - order, - ) - } else { - return invalid_monomorphization(ty); - } - } - } - } - - sym::nontemporal_store => { - let dst = args[0].deref(self.cx()); - args[1].val.nontemporal_store(self, dst); - return; - } - - sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => { - let a = args[0].immediate(); - let b = args[1].immediate(); - if name == sym::ptr_guaranteed_eq { - self.icmp(IntPredicate::IntEQ, a, b) - } else { - self.icmp(IntPredicate::IntNE, a, b) - } - } - - sym::ptr_offset_from => { - let ty = substs.type_at(0); - let pointee_size = self.size_of(ty); - - // This is the same sequence that Clang emits for pointer subtraction. - // It can be neither `nsw` nor `nuw` because the input is treated as - // unsigned but then the output is treated as signed, so neither works. - let a = args[0].immediate(); - let b = args[1].immediate(); - let a = self.ptrtoint(a, self.type_isize()); - let b = self.ptrtoint(b, self.type_isize()); - let d = self.sub(a, b); - let pointee_size = self.const_usize(pointee_size.bytes()); - // this is where the signed magic happens (notice the `s` in `exactsdiv`) - self.exactsdiv(d, pointee_size) - } _ => bug!("unknown intrinsic '{}'", name), }; @@ -807,39 +352,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { } } -fn copy_intrinsic( - bx: &mut Builder<'a, 'll, 'tcx>, - allow_overlap: bool, - volatile: bool, - ty: Ty<'tcx>, - dst: &'ll Value, - src: &'ll Value, - count: &'ll Value, -) { - let (size, align) = bx.size_and_align_of(ty); - let size = bx.mul(bx.const_usize(size.bytes()), count); - let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() }; - if allow_overlap { - bx.memmove(dst, align, src, align, size, flags); - } else { - bx.memcpy(dst, align, src, align, size, flags); - } -} - -fn memset_intrinsic( - bx: &mut Builder<'a, 'll, 'tcx>, - volatile: bool, - ty: Ty<'tcx>, - dst: &'ll Value, - val: &'ll Value, - count: &'ll Value, -) { - let (size, align) = bx.size_and_align_of(ty); - let size = bx.mul(bx.const_usize(size.bytes()), count); - let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() }; - bx.memset(dst, val, size, align, flags); -} - fn try_intrinsic( bx: &mut Builder<'a, 'll, 'tcx>, try_func: &'ll Value, @@ -2205,37 +1717,12 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, // stuffs. fn int_type_width_signed(ty: Ty<'_>, cx: &CodegenCx<'_, '_>) -> Option<(u64, bool)> { match ty.kind() { - ty::Int(t) => Some(( - match t { - ast::IntTy::Isize => u64::from(cx.tcx.sess.target.ptr_width), - ast::IntTy::I8 => 8, - ast::IntTy::I16 => 16, - ast::IntTy::I32 => 32, - ast::IntTy::I64 => 64, - ast::IntTy::I128 => 128, - }, - true, - )), - ty::Uint(t) => Some(( - match t { - ast::UintTy::Usize => u64::from(cx.tcx.sess.target.ptr_width), - ast::UintTy::U8 => 8, - ast::UintTy::U16 => 16, - ast::UintTy::U32 => 32, - ast::UintTy::U64 => 64, - ast::UintTy::U128 => 128, - }, - false, - )), - _ => None, - } -} - -// Returns the width of a float Ty -// Returns None if the type is not a float -fn float_type_width(ty: Ty<'_>) -> Option { - match ty.kind() { - ty::Float(t) => Some(t.bit_width()), + ty::Int(t) => { + Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.ptr_width)), true)) + } + ty::Uint(t) => { + Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.ptr_width)), false)) + } _ => None, } } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 4639ce4a5ab5b..4f85d232caa68 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -687,7 +687,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }) .collect(); - bx.codegen_intrinsic_call( + Self::codegen_intrinsic_call( + &mut bx, *instance.as_ref().unwrap(), &fn_abi, &args, diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs new file mode 100644 index 0000000000000..14f1ed59a67c5 --- /dev/null +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -0,0 +1,596 @@ +use super::operand::{OperandRef, OperandValue}; +use super::place::PlaceRef; +use super::FunctionCx; +use crate::common::{span_invalid_monomorphization_error, IntPredicate}; +use crate::glue; +use crate::traits::*; +use crate::MemFlags; + +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::{sym, Span}; +use rustc_target::abi::call::{FnAbi, PassMode}; + +fn copy_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + bx: &mut Bx, + allow_overlap: bool, + volatile: bool, + ty: Ty<'tcx>, + dst: Bx::Value, + src: Bx::Value, + count: Bx::Value, +) { + let layout = bx.layout_of(ty); + let size = layout.size; + let align = layout.align.abi; + let size = bx.mul(bx.const_usize(size.bytes()), count); + let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() }; + if allow_overlap { + bx.memmove(dst, align, src, align, size, flags); + } else { + bx.memcpy(dst, align, src, align, size, flags); + } +} + +fn memset_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + bx: &mut Bx, + volatile: bool, + ty: Ty<'tcx>, + dst: Bx::Value, + val: Bx::Value, + count: Bx::Value, +) { + let layout = bx.layout_of(ty); + let size = layout.size; + let align = layout.align.abi; + let size = bx.mul(bx.const_usize(size.bytes()), count); + let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() }; + bx.memset(dst, val, size, align, flags); +} + +impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { + pub fn codegen_intrinsic_call( + bx: &mut Bx, + instance: ty::Instance<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + args: &[OperandRef<'tcx, Bx::Value>], + llresult: Bx::Value, + span: Span, + ) { + let callee_ty = instance.ty(bx.tcx(), ty::ParamEnv::reveal_all()); + + let (def_id, substs) = match *callee_ty.kind() { + ty::FnDef(def_id, substs) => (def_id, substs), + _ => bug!("expected fn item type, found {}", callee_ty), + }; + + let sig = callee_ty.fn_sig(bx.tcx()); + let sig = bx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + let arg_tys = sig.inputs(); + let ret_ty = sig.output(); + let name = bx.tcx().item_name(def_id); + let name_str = &*name.as_str(); + + let llret_ty = bx.backend_type(bx.layout_of(ret_ty)); + let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); + + let llval = match name { + sym::assume => { + bx.assume(args[0].immediate()); + return; + } + sym::abort => { + bx.abort(); + return; + } + + sym::unreachable => { + return; + } + sym::va_start => bx.va_start(args[0].immediate()), + sym::va_end => bx.va_end(args[0].immediate()), + sym::size_of_val => { + let tp_ty = substs.type_at(0); + if let OperandValue::Pair(_, meta) = args[0].val { + let (llsize, _) = glue::size_and_align_of_dst(bx, tp_ty, Some(meta)); + llsize + } else { + bx.const_usize(bx.layout_of(tp_ty).size.bytes()) + } + } + sym::min_align_of_val => { + let tp_ty = substs.type_at(0); + if let OperandValue::Pair(_, meta) = args[0].val { + let (_, llalign) = glue::size_and_align_of_dst(bx, tp_ty, Some(meta)); + llalign + } else { + bx.const_usize(bx.layout_of(tp_ty).align.abi.bytes()) + } + } + sym::size_of + | sym::pref_align_of + | sym::min_align_of + | sym::needs_drop + | sym::type_id + | sym::type_name + | sym::variant_count => { + let value = bx + .tcx() + .const_eval_instance(ty::ParamEnv::reveal_all(), instance, None) + .unwrap(); + OperandRef::from_const(bx, value, ret_ty).immediate_or_packed_pair(bx) + } + // Effectively no-op + sym::forget => { + return; + } + sym::offset => { + let ptr = args[0].immediate(); + let offset = args[1].immediate(); + bx.inbounds_gep(ptr, &[offset]) + } + sym::arith_offset => { + let ptr = args[0].immediate(); + let offset = args[1].immediate(); + bx.gep(ptr, &[offset]) + } + + sym::copy_nonoverlapping => { + copy_intrinsic( + bx, + false, + false, + substs.type_at(0), + args[1].immediate(), + args[0].immediate(), + args[2].immediate(), + ); + return; + } + sym::copy => { + copy_intrinsic( + bx, + true, + false, + substs.type_at(0), + args[1].immediate(), + args[0].immediate(), + args[2].immediate(), + ); + return; + } + sym::write_bytes => { + memset_intrinsic( + bx, + false, + substs.type_at(0), + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + ); + return; + } + + sym::volatile_copy_nonoverlapping_memory => { + copy_intrinsic( + bx, + false, + true, + substs.type_at(0), + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + ); + return; + } + sym::volatile_copy_memory => { + copy_intrinsic( + bx, + true, + true, + substs.type_at(0), + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + ); + return; + } + sym::volatile_set_memory => { + memset_intrinsic( + bx, + true, + substs.type_at(0), + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + ); + return; + } + sym::volatile_store => { + let dst = args[0].deref(bx.cx()); + args[1].val.volatile_store(bx, dst); + return; + } + sym::unaligned_volatile_store => { + let dst = args[0].deref(bx.cx()); + args[1].val.unaligned_volatile_store(bx, dst); + return; + } + sym::add_with_overflow + | sym::sub_with_overflow + | sym::mul_with_overflow + | sym::wrapping_add + | sym::wrapping_sub + | sym::wrapping_mul + | sym::unchecked_div + | sym::unchecked_rem + | sym::unchecked_shl + | sym::unchecked_shr + | sym::unchecked_add + | sym::unchecked_sub + | sym::unchecked_mul + | sym::exact_div => { + let ty = arg_tys[0]; + match int_type_width_signed(ty, bx.tcx()) { + Some((_width, signed)) => match name { + sym::add_with_overflow + | sym::sub_with_overflow + | sym::mul_with_overflow => { + let op = match name { + sym::add_with_overflow => OverflowOp::Add, + sym::sub_with_overflow => OverflowOp::Sub, + sym::mul_with_overflow => OverflowOp::Mul, + _ => bug!(), + }; + let (val, overflow) = + bx.checked_binop(op, ty, args[0].immediate(), args[1].immediate()); + // Convert `i1` to a `bool`, and write it to the out parameter + let val = bx.from_immediate(val); + let overflow = bx.from_immediate(overflow); + + let dest = result.project_field(bx, 0); + bx.store(val, dest.llval, dest.align); + let dest = result.project_field(bx, 1); + bx.store(overflow, dest.llval, dest.align); + + return; + } + sym::wrapping_add => bx.add(args[0].immediate(), args[1].immediate()), + sym::wrapping_sub => bx.sub(args[0].immediate(), args[1].immediate()), + sym::wrapping_mul => bx.mul(args[0].immediate(), args[1].immediate()), + sym::exact_div => { + if signed { + bx.exactsdiv(args[0].immediate(), args[1].immediate()) + } else { + bx.exactudiv(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_div => { + if signed { + bx.sdiv(args[0].immediate(), args[1].immediate()) + } else { + bx.udiv(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_rem => { + if signed { + bx.srem(args[0].immediate(), args[1].immediate()) + } else { + bx.urem(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_shl => bx.shl(args[0].immediate(), args[1].immediate()), + sym::unchecked_shr => { + if signed { + bx.ashr(args[0].immediate(), args[1].immediate()) + } else { + bx.lshr(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_add => { + if signed { + bx.unchecked_sadd(args[0].immediate(), args[1].immediate()) + } else { + bx.unchecked_uadd(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_sub => { + if signed { + bx.unchecked_ssub(args[0].immediate(), args[1].immediate()) + } else { + bx.unchecked_usub(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_mul => { + if signed { + bx.unchecked_smul(args[0].immediate(), args[1].immediate()) + } else { + bx.unchecked_umul(args[0].immediate(), args[1].immediate()) + } + } + _ => bug!(), + }, + None => { + span_invalid_monomorphization_error( + bx.tcx().sess, + span, + &format!( + "invalid monomorphization of `{}` intrinsic: \ + expected basic integer type, found `{}`", + name, ty + ), + ); + return; + } + } + } + sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => { + match float_type_width(arg_tys[0]) { + Some(_width) => match name { + sym::fadd_fast => bx.fadd_fast(args[0].immediate(), args[1].immediate()), + sym::fsub_fast => bx.fsub_fast(args[0].immediate(), args[1].immediate()), + sym::fmul_fast => bx.fmul_fast(args[0].immediate(), args[1].immediate()), + sym::fdiv_fast => bx.fdiv_fast(args[0].immediate(), args[1].immediate()), + sym::frem_fast => bx.frem_fast(args[0].immediate(), args[1].immediate()), + _ => bug!(), + }, + None => { + span_invalid_monomorphization_error( + bx.tcx().sess, + span, + &format!( + "invalid monomorphization of `{}` intrinsic: \ + expected basic float type, found `{}`", + name, arg_tys[0] + ), + ); + return; + } + } + } + + sym::float_to_int_unchecked => { + if float_type_width(arg_tys[0]).is_none() { + span_invalid_monomorphization_error( + bx.tcx().sess, + span, + &format!( + "invalid monomorphization of `float_to_int_unchecked` \ + intrinsic: expected basic float type, \ + found `{}`", + arg_tys[0] + ), + ); + return; + } + let (_width, signed) = match int_type_width_signed(ret_ty, bx.tcx()) { + Some(pair) => pair, + None => { + span_invalid_monomorphization_error( + bx.tcx().sess, + span, + &format!( + "invalid monomorphization of `float_to_int_unchecked` \ + intrinsic: expected basic integer type, \ + found `{}`", + ret_ty + ), + ); + return; + } + }; + if signed { + bx.fptosi(args[0].immediate(), llret_ty) + } else { + bx.fptoui(args[0].immediate(), llret_ty) + } + } + + sym::discriminant_value => { + if ret_ty.is_integral() { + args[0].deref(bx.cx()).codegen_get_discr(bx, ret_ty) + } else { + span_bug!(span, "Invalid discriminant type for `{:?}`", arg_tys[0]) + } + } + + // This requires that atomic intrinsics follow a specific naming pattern: + // "atomic_[_]", and no ordering means SeqCst + name if name_str.starts_with("atomic_") => { + use crate::common::AtomicOrdering::*; + use crate::common::{AtomicRmwBinOp, SynchronizationScope}; + + let split: Vec<&str> = name_str.split('_').collect(); + + let is_cxchg = split[1] == "cxchg" || split[1] == "cxchgweak"; + let (order, failorder) = match split.len() { + 2 => (SequentiallyConsistent, SequentiallyConsistent), + 3 => match split[2] { + "unordered" => (Unordered, Unordered), + "relaxed" => (Monotonic, Monotonic), + "acq" => (Acquire, Acquire), + "rel" => (Release, Monotonic), + "acqrel" => (AcquireRelease, Acquire), + "failrelaxed" if is_cxchg => (SequentiallyConsistent, Monotonic), + "failacq" if is_cxchg => (SequentiallyConsistent, Acquire), + _ => bx.sess().fatal("unknown ordering in atomic intrinsic"), + }, + 4 => match (split[2], split[3]) { + ("acq", "failrelaxed") if is_cxchg => (Acquire, Monotonic), + ("acqrel", "failrelaxed") if is_cxchg => (AcquireRelease, Monotonic), + _ => bx.sess().fatal("unknown ordering in atomic intrinsic"), + }, + _ => bx.sess().fatal("Atomic intrinsic not in correct format"), + }; + + let invalid_monomorphization = |ty| { + span_invalid_monomorphization_error( + bx.tcx().sess, + span, + &format!( + "invalid monomorphization of `{}` intrinsic: \ + expected basic integer type, found `{}`", + name, ty + ), + ); + }; + + match split[1] { + "cxchg" | "cxchgweak" => { + let ty = substs.type_at(0); + if int_type_width_signed(ty, bx.tcx()).is_some() { + let weak = split[1] == "cxchgweak"; + let pair = bx.atomic_cmpxchg( + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + order, + failorder, + weak, + ); + let val = bx.extract_value(pair, 0); + let success = bx.extract_value(pair, 1); + let val = bx.from_immediate(val); + let success = bx.from_immediate(success); + + let dest = result.project_field(bx, 0); + bx.store(val, dest.llval, dest.align); + let dest = result.project_field(bx, 1); + bx.store(success, dest.llval, dest.align); + return; + } else { + return invalid_monomorphization(ty); + } + } + + "load" => { + let ty = substs.type_at(0); + if int_type_width_signed(ty, bx.tcx()).is_some() { + let size = bx.layout_of(ty).size; + bx.atomic_load(args[0].immediate(), order, size) + } else { + return invalid_monomorphization(ty); + } + } + + "store" => { + let ty = substs.type_at(0); + if int_type_width_signed(ty, bx.tcx()).is_some() { + let size = bx.layout_of(ty).size; + bx.atomic_store(args[1].immediate(), args[0].immediate(), order, size); + return; + } else { + return invalid_monomorphization(ty); + } + } + + "fence" => { + bx.atomic_fence(order, SynchronizationScope::CrossThread); + return; + } + + "singlethreadfence" => { + bx.atomic_fence(order, SynchronizationScope::SingleThread); + return; + } + + // These are all AtomicRMW ops + op => { + let atom_op = match op { + "xchg" => AtomicRmwBinOp::AtomicXchg, + "xadd" => AtomicRmwBinOp::AtomicAdd, + "xsub" => AtomicRmwBinOp::AtomicSub, + "and" => AtomicRmwBinOp::AtomicAnd, + "nand" => AtomicRmwBinOp::AtomicNand, + "or" => AtomicRmwBinOp::AtomicOr, + "xor" => AtomicRmwBinOp::AtomicXor, + "max" => AtomicRmwBinOp::AtomicMax, + "min" => AtomicRmwBinOp::AtomicMin, + "umax" => AtomicRmwBinOp::AtomicUMax, + "umin" => AtomicRmwBinOp::AtomicUMin, + _ => bx.sess().fatal("unknown atomic operation"), + }; + + let ty = substs.type_at(0); + if int_type_width_signed(ty, bx.tcx()).is_some() { + bx.atomic_rmw(atom_op, args[0].immediate(), args[1].immediate(), order) + } else { + return invalid_monomorphization(ty); + } + } + } + } + + sym::nontemporal_store => { + let dst = args[0].deref(bx.cx()); + args[1].val.nontemporal_store(bx, dst); + return; + } + + sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => { + let a = args[0].immediate(); + let b = args[1].immediate(); + if name == sym::ptr_guaranteed_eq { + bx.icmp(IntPredicate::IntEQ, a, b) + } else { + bx.icmp(IntPredicate::IntNE, a, b) + } + } + + sym::ptr_offset_from => { + let ty = substs.type_at(0); + let pointee_size = bx.layout_of(ty).size; + + // This is the same sequence that Clang emits for pointer subtraction. + // It can be neither `nsw` nor `nuw` because the input is treated as + // unsigned but then the output is treated as signed, so neither works. + let a = args[0].immediate(); + let b = args[1].immediate(); + let a = bx.ptrtoint(a, bx.type_isize()); + let b = bx.ptrtoint(b, bx.type_isize()); + let d = bx.sub(a, b); + let pointee_size = bx.const_usize(pointee_size.bytes()); + // this is where the signed magic happens (notice the `s` in `exactsdiv`) + bx.exactsdiv(d, pointee_size) + } + + _ => { + // Need to use backend-specific things in the implementation. + bx.codegen_intrinsic_call(instance, fn_abi, args, llresult, span); + return; + } + }; + + if !fn_abi.ret.is_ignore() { + if let PassMode::Cast(ty) = fn_abi.ret.mode { + let ptr_llty = bx.type_ptr_to(bx.cast_backend_type(&ty)); + let ptr = bx.pointercast(result.llval, ptr_llty); + bx.store(llval, ptr, result.align); + } else { + OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout) + .val + .store(bx, result); + } + } + } +} + +// Returns the width of an int Ty, and if it's signed or not +// Returns None if the type is not an integer +// FIXME: there’s multiple of this functions, investigate using some of the already existing +// stuffs. +fn int_type_width_signed(ty: Ty<'_>, tcx: TyCtxt<'_>) -> Option<(u64, bool)> { + match ty.kind() { + ty::Int(t) => Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.ptr_width)), true)), + ty::Uint(t) => Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.ptr_width)), false)), + _ => None, + } +} + +// Returns the width of a float Ty +// Returns None if the type is not a float +fn float_type_width(ty: Ty<'_>) -> Option { + match ty.kind() { + ty::Float(t) => Some(t.bit_width()), + _ => None, + } +} diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index c1e7cfd80ef10..64d456fb7aa67 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -486,6 +486,7 @@ mod block; pub mod constant; pub mod coverageinfo; pub mod debuginfo; +mod intrinsic; pub mod operand; pub mod place; mod rvalue; From e0c1621a3f687f30a372be5308cda4c8e261c768 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 15 Sep 2020 14:55:50 -0700 Subject: [PATCH 39/39] Update books --- src/doc/book | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/book b/src/doc/book index e5ed97128302d..cb28dee95e5e5 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit e5ed97128302d5fa45dbac0e64426bc7649a558c +Subproject commit cb28dee95e5e50b793e6ba9291c5d1568d3ad72e diff --git a/src/doc/nomicon b/src/doc/nomicon index 25854752549d4..6e57e64501f61 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 25854752549d44d76fbd7650e17cb4f167a0b8fb +Subproject commit 6e57e64501f61873ab80cb78a07180a22751a5d6 diff --git a/src/doc/reference b/src/doc/reference index 25391dba46262..56a13c082ee90 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 25391dba46262f882fa846beefaff54a966a8fa5 +Subproject commit 56a13c082ee90736c08d6abdcd90462517b703d3