diff --git a/Cargo.lock b/Cargo.lock index 7e03474565d85..6c56631bb2e4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,6 +18,7 @@ dependencies = [ "compiler_builtins 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1334,7 +1335,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "minifier" -version = "0.0.20" +version = "0.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "macro-utils 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2686,7 +2687,7 @@ dependencies = [ name = "rustdoc" version = "0.0.0" dependencies = [ - "minifier 0.0.20 (registry+https://github.com/rust-lang/crates.io-index)", + "minifier 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3502,7 +3503,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0a3eb002f0535929f1199681417029ebea04aadc0c7a4224b46be99c7f5d6a16" "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" -"checksum minifier 0.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "96c269bb45c39b333392b2b18ad71760b34ac65666591386b0e959ed58b3f474" +"checksum minifier 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "9707d0ff1b828cba09c4bb27d5c3dceb6f49bd46f700042343bea350a131bf4f" "checksum miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0300eafb20369952951699b68243ab4334f4b10a88f411c221d444b36c40e649" "checksum miniz_oxide 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ad30a47319c16cde58d0314f5d98202a80c9083b5f61178457403dfb14e509c" "checksum miniz_oxide_c_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "28edaef377517fd9fe3e085c37d892ce7acd1fbeab9239c5a36eec352d8a8b7e" diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index d143dffb24be5..09c87fdd1a84c 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -678,10 +678,10 @@ def update_submodule(self, module, checked_out, recorded_submodules): print("Updating submodule", module) - run(["git", "submodule", "-q", "sync", module], + run(["git", "submodule", "-q", "sync", "--progress", module], cwd=self.rust_root, verbose=self.verbose) run(["git", "submodule", "update", - "--init", "--recursive", module], + "--init", "--recursive", "--progress", module], cwd=self.rust_root, verbose=self.verbose) run(["git", "reset", "-q", "--hard"], cwd=module_path, verbose=self.verbose) diff --git a/src/ci/docker/dist-x86_64-linux/build-clang.sh b/src/ci/docker/dist-x86_64-linux/build-clang.sh index 2762f0bf7ec74..a7a8719b5357e 100755 --- a/src/ci/docker/dist-x86_64-linux/build-clang.sh +++ b/src/ci/docker/dist-x86_64-linux/build-clang.sh @@ -13,31 +13,28 @@ set -ex source shared.sh -LLVM=7.0.0 +# Currently these commits are all tip-of-tree as of 2018-12-16, used to pick up +# a fix for rust-lang/rust#56849 +LLVM=032b00a5404865765cda7db3039f39d54964d8b0 +LLD=3e4aa4e8671523321af51449e0569f455ef3ad43 +CLANG=a6b9739069763243020f4ea6fe586bc135fde1f9 mkdir clang cd clang -curl https://releases.llvm.org/$LLVM/llvm-$LLVM.src.tar.xz | \ - xz -d | \ - tar xf - - -cd llvm-$LLVM.src +curl -L https://github.com/llvm-mirror/llvm/archive/$LLVM.tar.gz | \ + tar xzf - --strip-components=1 mkdir -p tools/clang - -curl https://releases.llvm.org/$LLVM/cfe-$LLVM.src.tar.xz | \ - xz -d | \ - tar xf - -C tools/clang --strip-components=1 +curl -L https://github.com/llvm-mirror/clang/archive/$CLANG.tar.gz | \ + tar xzf - --strip-components=1 -C tools/clang mkdir -p tools/lld +curl -L https://github.com/llvm-mirror/lld/archive/$LLD.tar.gz | \ + tar zxf - --strip-components=1 -C tools/lld -curl https://releases.llvm.org/$LLVM/lld-$LLVM.src.tar.xz | \ - xz -d | \ - tar xf - -C tools/lld --strip-components=1 - -mkdir ../clang-build -cd ../clang-build +mkdir clang-build +cd clang-build # For whatever reason the default set of include paths for clang is different # than that of gcc. As a result we need to manually include our sysroot's @@ -55,7 +52,7 @@ INC="$INC:/rustroot/lib/gcc/x86_64-unknown-linux-gnu/4.8.5/include-fixed" INC="$INC:/usr/include" hide_output \ - cmake ../llvm-$LLVM.src \ + cmake .. \ -DCMAKE_C_COMPILER=/rustroot/bin/gcc \ -DCMAKE_CXX_COMPILER=/rustroot/bin/g++ \ -DCMAKE_BUILD_TYPE=Release \ diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 43cdab27e9dae..905b06465340a 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -402,3 +402,18 @@ Using `index-page` option enables `enable-index-page` option as well. ### `--enable-index-page`: generate a default index page for docs This feature allows the generation of a default index-page which lists the generated crates. + +### `--static-root-path`: control how static files are loaded in HTML output + +Using this flag looks like this: + +```bash +$ rustdoc src/lib.rs -Z unstable-options --static-root-path '/cache/' +``` + +This flag controls how rustdoc links to its static files on HTML pages. If you're hosting a lot of +crates' docs generated by the same version of rustdoc, you can use this flag to cache rustdoc's CSS, +JavaScript, and font files in a single location, rather than duplicating it once per "doc root" +(grouping of crate docs generated into the same output directory, like with `cargo doc`). Per-crate +files like the search index will still load from the documentation root, but anything that gets +renamed with `--resource-suffix` will load from the given path. diff --git a/src/doc/unstable-book/src/language-features/repr-packed.md b/src/doc/unstable-book/src/language-features/repr-packed.md deleted file mode 100644 index 2dd763d04b0ab..0000000000000 --- a/src/doc/unstable-book/src/language-features/repr-packed.md +++ /dev/null @@ -1,8 +0,0 @@ -# `repr_packed` - -The tracking issue for this feature is [#33158] - -[#33158]: https://github.com/rust-lang/rust/issues/33158 - ------------------------- - diff --git a/src/liballoc/Cargo.toml b/src/liballoc/Cargo.toml index b2eb3566c04a7..861c7cecb8879 100644 --- a/src/liballoc/Cargo.toml +++ b/src/liballoc/Cargo.toml @@ -15,6 +15,7 @@ compiler_builtins = { version = "0.1.0", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = "0.6" +rand_xorshift = "0.1" [[test]] name = "collectionstests" diff --git a/src/liballoc/benches/btree/map.rs b/src/liballoc/benches/btree/map.rs index 20b9091a07bfc..6e2b5e06b7a91 100644 --- a/src/liballoc/benches/btree/map.rs +++ b/src/liballoc/benches/btree/map.rs @@ -12,7 +12,7 @@ use std::iter::Iterator; use std::vec::Vec; use std::collections::BTreeMap; -use rand::{Rng, thread_rng}; +use rand::{Rng, seq::SliceRandom, thread_rng}; use test::{Bencher, black_box}; macro_rules! map_insert_rand_bench { @@ -78,7 +78,7 @@ macro_rules! map_find_rand_bench { map.insert(k, k); } - rng.shuffle(&mut keys); + keys.shuffle(&mut rng); // measure let mut i = 0; diff --git a/src/liballoc/benches/lib.rs b/src/liballoc/benches/lib.rs index b4f4fd74f3a39..9502a7dc3c075 100644 --- a/src/liballoc/benches/lib.rs +++ b/src/liballoc/benches/lib.rs @@ -13,6 +13,7 @@ #![feature(test)] extern crate rand; +extern crate rand_xorshift; extern crate test; mod btree; diff --git a/src/liballoc/benches/slice.rs b/src/liballoc/benches/slice.rs index 490320f57cbf7..fc58899406332 100644 --- a/src/liballoc/benches/slice.rs +++ b/src/liballoc/benches/slice.rs @@ -12,8 +12,9 @@ use rand::{thread_rng}; use std::mem; use std::ptr; -use rand::{Rng, SeedableRng, XorShiftRng}; +use rand::{Rng, SeedableRng}; use rand::distributions::{Standard, Alphanumeric}; +use rand_xorshift::XorShiftRng; use test::{Bencher, black_box}; #[bench] diff --git a/src/liballoc/benches/str.rs b/src/liballoc/benches/str.rs index 38c94d4d8b5f3..c5e1576d24e26 100644 --- a/src/liballoc/benches/str.rs +++ b/src/liballoc/benches/str.rs @@ -274,11 +274,11 @@ make_test!(split_a_str, s, s.split("a").count()); make_test!(trim_ascii_char, s, { s.trim_matches(|c: char| c.is_ascii()) }); -make_test!(trim_left_ascii_char, s, { - s.trim_left_matches(|c: char| c.is_ascii()) +make_test!(trim_start_ascii_char, s, { + s.trim_start_matches(|c: char| c.is_ascii()) }); -make_test!(trim_right_ascii_char, s, { - s.trim_right_matches(|c: char| c.is_ascii()) +make_test!(trim_end_ascii_char, s, { + s.trim_end_matches(|c: char| c.is_ascii()) }); make_test!(find_underscore_char, s, s.find('_')); diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 83adcce5c742c..a51bd9aa4c7b8 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -109,9 +109,11 @@ impl Box { box x } - #[unstable(feature = "pin", issue = "49150")] + /// Constructs a new `Pin>`. If `T` does not implement `Unpin`, then + /// `x` will be pinned in memory and unable to be moved. + #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn pinned(x: T) -> Pin> { + pub fn pin(x: T) -> Pin> { (box x).into() } } @@ -444,7 +446,7 @@ impl From for Box { } } -#[unstable(feature = "pin", issue = "49150")] +#[stable(feature = "pin", since = "1.33.0")] impl From> for Pin> { fn from(boxed: Box) -> Self { // It's not possible to move or replace the insides of a `Pin>` @@ -808,7 +810,7 @@ impl AsMut for Box { * implementation of `Unpin` (where `T: Unpin`) would be valid/safe, and * could have a method to project a Pin from it. */ -#[unstable(feature = "pin", issue = "49150")] +#[stable(feature = "pin", since = "1.33.0")] impl Unpin for Box { } #[unstable(feature = "generator_trait", issue = "43122")] diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 0c5926fbaf1dc..553c6d7291a9d 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -1897,8 +1897,6 @@ impl VecDeque { /// # Examples /// /// ``` - /// #![feature(vec_resize_with)] - /// /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); @@ -1917,7 +1915,7 @@ impl VecDeque { /// buf.resize_with(5, || { state += 1; state }); /// assert_eq!(buf, [5, 10, 101, 102, 103]); /// ``` - #[unstable(feature = "vec_resize_with", issue = "41758")] + #[stable(feature = "vec_resize_with", since = "1.33.0")] pub fn resize_with(&mut self, new_len: usize, generator: impl FnMut()->T) { let len = self.len(); @@ -1927,6 +1925,118 @@ impl VecDeque { self.truncate(new_len); } } + + /// Rotates the double-ended queue `mid` places to the left. + /// + /// Equivalently, + /// - Rotates item `mid` into the first position. + /// - Pops the first `mid` items and pushes them to the end. + /// - Rotates `len() - mid` places to the right. + /// + /// # Panics + /// + /// If `mid` is greater than `len()`. Note that `mid == len()` + /// does _not_ panic and is a no-op rotation. + /// + /// # Complexity + /// + /// Takes `O(min(mid, len() - mid))` time and no extra space. + /// + /// # Examples + /// + /// ``` + /// #![feature(vecdeque_rotate)] + /// + /// use std::collections::VecDeque; + /// + /// let mut buf: VecDeque<_> = (0..10).collect(); + /// + /// buf.rotate_left(3); + /// assert_eq!(buf, [3, 4, 5, 6, 7, 8, 9, 0, 1, 2]); + /// + /// for i in 1..10 { + /// assert_eq!(i * 3 % 10, buf[0]); + /// buf.rotate_left(3); + /// } + /// assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + /// ``` + #[unstable(feature = "vecdeque_rotate", issue = "56686")] + pub fn rotate_left(&mut self, mid: usize) { + assert!(mid <= self.len()); + let k = self.len() - mid; + if mid <= k { + unsafe { self.rotate_left_inner(mid) } + } else { + unsafe { self.rotate_right_inner(k) } + } + } + + /// Rotates the double-ended queue `k` places to the right. + /// + /// Equivalently, + /// - Rotates the first item into position `k`. + /// - Pops the last `k` items and pushes them to the front. + /// - Rotates `len() - k` places to the left. + /// + /// # Panics + /// + /// If `k` is greater than `len()`. Note that `k == len()` + /// does _not_ panic and is a no-op rotation. + /// + /// # Complexity + /// + /// Takes `O(min(k, len() - k))` time and no extra space. + /// + /// # Examples + /// + /// ``` + /// #![feature(vecdeque_rotate)] + /// + /// use std::collections::VecDeque; + /// + /// let mut buf: VecDeque<_> = (0..10).collect(); + /// + /// buf.rotate_right(3); + /// assert_eq!(buf, [7, 8, 9, 0, 1, 2, 3, 4, 5, 6]); + /// + /// for i in 1..10 { + /// assert_eq!(0, buf[i * 3 % 10]); + /// buf.rotate_right(3); + /// } + /// assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + /// ``` + #[unstable(feature = "vecdeque_rotate", issue = "56686")] + pub fn rotate_right(&mut self, k: usize) { + assert!(k <= self.len()); + let mid = self.len() - k; + if k <= mid { + unsafe { self.rotate_right_inner(k) } + } else { + unsafe { self.rotate_left_inner(mid) } + } + } + + // Safety: the following two methods require that the rotation amount + // be less than half the length of the deque. + // + // `wrap_copy` requres that `min(x, cap() - x) + copy_len <= cap()`, + // but than `min` is never more than half the capacity, regardless of x, + // so it's sound to call here because we're calling with something + // less than half the length, which is never above half the capacity. + + unsafe fn rotate_left_inner(&mut self, mid: usize) { + debug_assert!(mid * 2 <= self.len()); + self.wrap_copy(self.head, self.tail, mid); + self.head = self.wrap_add(self.head, mid); + self.tail = self.wrap_add(self.tail, mid); + } + + unsafe fn rotate_right_inner(&mut self, k: usize) { + debug_assert!(k * 2 <= self.len()); + self.head = self.wrap_sub(self.head, k); + self.tail = self.wrap_sub(self.tail, k); + self.wrap_copy(self.tail, self.head, k); + } } impl VecDeque { diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index abacc62c8562b..03661495b7843 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -72,6 +72,8 @@ test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))] #![no_std] #![needs_allocator] + +#![deny(intra_doc_link_resolution_failure)] #![deny(missing_debug_implementations)] #![cfg_attr(not(test), feature(fn_traits))] @@ -100,7 +102,6 @@ #![feature(nll)] #![feature(optin_builtin_traits)] #![feature(pattern)] -#![feature(pin)] #![feature(ptr_internals)] #![feature(ptr_offset_from)] #![feature(rustc_attrs)] diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 6769a70ddbe0a..225fc9d927c41 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -325,8 +325,10 @@ impl Rc { } } - #[unstable(feature = "pin", issue = "49150")] - pub fn pinned(value: T) -> Pin> { + /// Constructs a new `Pin>`. If `T` does not implement `Unpin`, then + /// `value` will be pinned in memory and unable to be moved. + #[stable(feature = "pin", since = "1.33.0")] + pub fn pin(value: T) -> Pin> { unsafe { Pin::new_unchecked(Rc::new(value)) } } @@ -840,6 +842,8 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { /// drop(foo); // Doesn't print anything /// drop(foo2); // Prints "dropped!" /// ``` + /// + /// [`Weak`]: ../../std/rc/struct.Weak.html fn drop(&mut self) { unsafe { self.dec_strong(); @@ -1419,9 +1423,10 @@ impl fmt::Debug for Weak { #[stable(feature = "downgraded_weak", since = "1.10.0")] impl Default for Weak { /// Constructs a new `Weak`, allocating memory for `T` without initializing - /// it. Calling [`upgrade`][Weak::upgrade] on the return value always gives [`None`]. + /// it. Calling [`upgrade`] on the return value always gives [`None`]. /// /// [`None`]: ../../std/option/enum.Option.html + /// [`upgrade`]: ../../std/rc/struct.Weak.html#method.upgrade /// /// # Examples /// @@ -1928,5 +1933,5 @@ impl AsRef for Rc { } } -#[unstable(feature = "pin", issue = "49150")] +#[stable(feature = "pin", since = "1.33.0")] impl Unpin for Rc { } diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index e596694fb9d4b..b8fb56e77109f 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -303,8 +303,10 @@ impl Arc { Arc { ptr: Box::into_raw_non_null(x), phantom: PhantomData } } - #[unstable(feature = "pin", issue = "49150")] - pub fn pinned(data: T) -> Pin> { + /// Constructs a new `Pin>`. If `T` does not implement `Unpin`, then + /// `data` will be pinned in memory and unable to be moved. + #[stable(feature = "pin", since = "1.33.0")] + pub fn pin(data: T) -> Pin> { unsafe { Pin::new_unchecked(Arc::new(data)) } } @@ -952,6 +954,8 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Arc { /// drop(foo); // Doesn't print anything /// drop(foo2); // Prints "dropped!" /// ``` + /// + /// [`Weak`]: ../../std/sync/struct.Weak.html #[inline] fn drop(&mut self) { // Because `fetch_sub` is already atomic, we do not need to synchronize @@ -1219,10 +1223,11 @@ impl Clone for Weak { #[stable(feature = "downgraded_weak", since = "1.10.0")] impl Default for Weak { /// Constructs a new `Weak`, without allocating memory. - /// Calling [`upgrade`][Weak::upgrade] on the return value always + /// Calling [`upgrade`] on the return value always /// gives [`None`]. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`upgrade`]: ../../std/sync/struct.Weak.html#method.upgrade /// /// # Examples /// @@ -2044,5 +2049,5 @@ impl AsRef for Arc { } } -#[unstable(feature = "pin", issue = "49150")] +#[stable(feature = "pin", since = "1.33.0")] impl Unpin for Arc { } diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index e514a8a69c020..146abd1b7508a 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -13,11 +13,12 @@ #![feature(drain_filter)] #![feature(exact_size_is_empty)] #![feature(pattern)] +#![feature(repeat_generic_slice)] #![feature(slice_sort_by_cached_key)] #![feature(str_escape)] #![feature(try_reserve)] #![feature(unboxed_closures)] -#![feature(repeat_generic_slice)] +#![feature(vecdeque_rotate)] extern crate core; extern crate rand; diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs index 1f2a7211c657b..c8a6d86413ad6 100644 --- a/src/liballoc/tests/vec_deque.rs +++ b/src/liballoc/tests/vec_deque.rs @@ -1309,3 +1309,137 @@ fn test_try_reserve_exact() { } } + +#[test] +fn test_rotate_nop() { + let mut v: VecDeque<_> = (0..10).collect(); + assert_unchanged(&v); + + v.rotate_left(0); + assert_unchanged(&v); + + v.rotate_left(10); + assert_unchanged(&v); + + v.rotate_right(0); + assert_unchanged(&v); + + v.rotate_right(10); + assert_unchanged(&v); + + v.rotate_left(3); + v.rotate_right(3); + assert_unchanged(&v); + + v.rotate_right(3); + v.rotate_left(3); + assert_unchanged(&v); + + v.rotate_left(6); + v.rotate_right(6); + assert_unchanged(&v); + + v.rotate_right(6); + v.rotate_left(6); + assert_unchanged(&v); + + v.rotate_left(3); + v.rotate_left(7); + assert_unchanged(&v); + + v.rotate_right(4); + v.rotate_right(6); + assert_unchanged(&v); + + v.rotate_left(1); + v.rotate_left(2); + v.rotate_left(3); + v.rotate_left(4); + assert_unchanged(&v); + + v.rotate_right(1); + v.rotate_right(2); + v.rotate_right(3); + v.rotate_right(4); + assert_unchanged(&v); + + fn assert_unchanged(v: &VecDeque) { + assert_eq!(v, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + } +} + +#[test] +fn test_rotate_left_parts() { + let mut v: VecDeque<_> = (1..=7).collect(); + v.rotate_left(2); + assert_eq!(v.as_slices(), (&[3, 4, 5, 6, 7, 1][..], &[2][..])); + v.rotate_left(2); + assert_eq!(v.as_slices(), (&[5, 6, 7, 1][..], &[2, 3, 4][..])); + v.rotate_left(2); + assert_eq!(v.as_slices(), (&[7, 1][..], &[2, 3, 4, 5, 6][..])); + v.rotate_left(2); + assert_eq!(v.as_slices(), (&[2, 3, 4, 5, 6, 7, 1][..], &[][..])); + v.rotate_left(2); + assert_eq!(v.as_slices(), (&[4, 5, 6, 7, 1, 2][..], &[3][..])); + v.rotate_left(2); + assert_eq!(v.as_slices(), (&[6, 7, 1, 2][..], &[3, 4, 5][..])); + v.rotate_left(2); + assert_eq!(v.as_slices(), (&[1, 2][..], &[3, 4, 5, 6, 7][..])); +} + +#[test] +fn test_rotate_right_parts() { + let mut v: VecDeque<_> = (1..=7).collect(); + v.rotate_right(2); + assert_eq!(v.as_slices(), (&[6, 7][..], &[1, 2, 3, 4, 5][..])); + v.rotate_right(2); + assert_eq!(v.as_slices(), (&[4, 5, 6, 7][..], &[1, 2, 3][..])); + v.rotate_right(2); + assert_eq!(v.as_slices(), (&[2, 3, 4, 5, 6, 7][..], &[1][..])); + v.rotate_right(2); + assert_eq!(v.as_slices(), (&[7, 1, 2, 3, 4, 5, 6][..], &[][..])); + v.rotate_right(2); + assert_eq!(v.as_slices(), (&[5, 6][..], &[7, 1, 2, 3, 4][..])); + v.rotate_right(2); + assert_eq!(v.as_slices(), (&[3, 4, 5, 6][..], &[7, 1, 2][..])); + v.rotate_right(2); + assert_eq!(v.as_slices(), (&[1, 2, 3, 4, 5, 6][..], &[7][..])); +} + +#[test] +fn test_rotate_left_random() { + let shifts = [ + 6, 1, 0, 11, 12, 1, 11, 7, 9, 3, 6, 1, + 4, 0, 5, 1, 3, 1, 12, 8, 3, 1, 11, 11, + 9, 4, 12, 3, 12, 9, 11, 1, 7, 9, 7, 2, + ]; + let n = 12; + let mut v: VecDeque<_> = (0..n).collect(); + let mut total_shift = 0; + for shift in shifts.iter().cloned() { + v.rotate_left(shift); + total_shift += shift; + for i in 0..n { + assert_eq!(v[i], (i + total_shift) % n); + } + } +} + +#[test] +fn test_rotate_right_random() { + let shifts = [ + 6, 1, 0, 11, 12, 1, 11, 7, 9, 3, 6, 1, + 4, 0, 5, 1, 3, 1, 12, 8, 3, 1, 11, 11, + 9, 4, 12, 3, 12, 9, 11, 1, 7, 9, 7, 2, + ]; + let n = 12; + let mut v: VecDeque<_> = (0..n).collect(); + let mut total_shift = 0; + for shift in shifts.iter().cloned() { + v.rotate_right(shift); + total_shift += shift; + for i in 0..n { + assert_eq!(v[(i + total_shift) % n], i); + } + } +} diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 63af69dda1dce..b78e71331a97f 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -1241,8 +1241,6 @@ impl Vec { /// # Examples /// /// ``` - /// #![feature(vec_resize_with)] - /// /// let mut vec = vec![1, 2, 3]; /// vec.resize_with(5, Default::default); /// assert_eq!(vec, [1, 2, 3, 0, 0]); @@ -1255,7 +1253,7 @@ impl Vec { /// /// [`resize`]: #method.resize /// [`Clone`]: ../../std/clone/trait.Clone.html - #[unstable(feature = "vec_resize_with", issue = "41758")] + #[stable(feature = "vec_resize_with", since = "1.33.0")] pub fn resize_with(&mut self, new_len: usize, f: F) where F: FnMut() -> T { diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs index 5dee1d6dd3a39..da3aa8449bafb 100644 --- a/src/libcore/future/future.rs +++ b/src/libcore/future/future.rs @@ -120,7 +120,7 @@ impl<'a, F: ?Sized + Future + Unpin> Future for &'a mut F { impl

Future for Pin

where - P: ops::DerefMut, + P: Unpin + ops::DerefMut, P::Target: Future, { type Output = <

::Target as Future>::Output; diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index aa23d49672a0b..e493a3804376f 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -429,6 +429,9 @@ impl Iterator for Rev where I: DoubleEndedIterator { #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + #[inline] + fn nth(&mut self, n: usize) -> Option<::Item> { self.iter.nth_back(n) } + fn try_fold(&mut self, init: B, f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try { @@ -461,6 +464,9 @@ impl DoubleEndedIterator for Rev where I: DoubleEndedIterator { #[inline] fn next_back(&mut self) -> Option<::Item> { self.iter.next() } + #[inline] + fn nth_back(&mut self, n: usize) -> Option<::Item> { self.iter.nth(n) } + fn try_rfold(&mut self, init: B, f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try { diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 45e5b614db3e0..727a60e359694 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -427,6 +427,62 @@ pub trait DoubleEndedIterator: Iterator { #[stable(feature = "rust1", since = "1.0.0")] fn next_back(&mut self) -> Option; + /// Returns the `n`th element from the end of the iterator. + /// + /// This is essentially the reversed version of [`nth`]. Although like most indexing + /// operations, the count starts from zero, so `nth_back(0)` returns the first value fro + /// the end, `nth_back(1)` the second, and so on. + /// + /// Note that all elements between the end and the returned element will be + /// consumed, including the returned element. This also means that calling + /// `nth_back(0)` multiple times on the same iterator will return different + /// elements. + /// + /// `nth_back()` will return [`None`] if `n` is greater than or equal to the length of the + /// iterator. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`nth`]: ../../std/iter/trait.Iterator.html#method.nth + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(iter_nth_back)] + /// let a = [1, 2, 3]; + /// assert_eq!(a.iter().nth_back(2), Some(&1)); + /// ``` + /// + /// Calling `nth_back()` multiple times doesn't rewind the iterator: + /// + /// ``` + /// #![feature(iter_nth_back)] + /// let a = [1, 2, 3]; + /// + /// let mut iter = a.iter(); + /// + /// assert_eq!(iter.nth_back(1), Some(&2)); + /// assert_eq!(iter.nth_back(1), None); + /// ``` + /// + /// Returning `None` if there are less than `n + 1` elements: + /// + /// ``` + /// #![feature(iter_nth_back)] + /// let a = [1, 2, 3]; + /// assert_eq!(a.iter().nth_back(10), None); + /// ``` + #[inline] + #[unstable(feature = "iter_nth_back", issue = "56995")] + fn nth_back(&mut self, mut n: usize) -> Option { + for x in self.rev() { + if n == 0 { return Some(x) } + n -= 1; + } + None + } + /// This is the reverse version of [`try_fold()`]: it takes elements /// starting from the back of the iterator. /// @@ -461,8 +517,11 @@ pub trait DoubleEndedIterator: Iterator { /// ``` #[inline] #[stable(feature = "iterator_try_fold", since = "1.27.0")] - fn try_rfold(&mut self, init: B, mut f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try + fn try_rfold(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try { let mut accum = init; while let Some(x) = self.next_back() { @@ -524,8 +583,10 @@ pub trait DoubleEndedIterator: Iterator { /// ``` #[inline] #[stable(feature = "iter_rfold", since = "1.27.0")] - fn rfold(mut self, accum: B, mut f: F) -> B where - Self: Sized, F: FnMut(B, Self::Item) -> B, + fn rfold(mut self, accum: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, { self.try_rfold(accum, move |acc, x| Ok::(f(acc, x))).unwrap() } @@ -574,7 +635,8 @@ pub trait DoubleEndedIterator: Iterator { /// ``` #[inline] #[stable(feature = "iter_rfind", since = "1.27.0")] - fn rfind

(&mut self, mut predicate: P) -> Option where + fn rfind

(&mut self, mut predicate: P) -> Option + where Self: Sized, P: FnMut(&Self::Item) -> bool { @@ -587,7 +649,12 @@ pub trait DoubleEndedIterator: Iterator { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I { - fn next_back(&mut self) -> Option { (**self).next_back() } + fn next_back(&mut self) -> Option { + (**self).next_back() + } + fn nth_back(&mut self, n: usize) -> Option { + (**self).nth_back(n) + } } /// An iterator that knows its exact length. diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index c8ad38c52dbe9..2124458dc5597 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -71,6 +71,7 @@ #![no_core] #![deny(missing_docs)] +#![deny(intra_doc_link_resolution_failure)] #![deny(missing_debug_implementations)] #![feature(allow_internal_unstable)] diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index d3d16127ed5fe..74055a4f8a9b0 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -621,7 +621,6 @@ unsafe impl Freeze for &mut T {} /// So this, for example, can only be done on types implementing `Unpin`: /// /// ```rust -/// #![feature(pin)] /// use std::mem::replace; /// use std::pin::Pin; /// @@ -637,23 +636,23 @@ unsafe impl Freeze for &mut T {} /// [`replace`]: ../../std/mem/fn.replace.html /// [`Pin`]: ../pin/struct.Pin.html /// [`pin module`]: ../../std/pin/index.html -#[unstable(feature = "pin", issue = "49150")] +#[stable(feature = "pin", since = "1.33.0")] pub auto trait Unpin {} /// A marker type which does not implement `Unpin`. /// /// If a type contains a `PhantomPinned`, it will not implement `Unpin` by default. -#[unstable(feature = "pin", issue = "49150")] +#[stable(feature = "pin", since = "1.33.0")] #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct PhantomPinned; -#[unstable(feature = "pin", issue = "49150")] +#[stable(feature = "pin", since = "1.33.0")] impl !Unpin for PhantomPinned {} -#[unstable(feature = "pin", issue = "49150")] +#[stable(feature = "pin", since = "1.33.0")] impl<'a, T: ?Sized + 'a> Unpin for &'a T {} -#[unstable(feature = "pin", issue = "49150")] +#[stable(feature = "pin", since = "1.33.0")] impl<'a, T: ?Sized + 'a> Unpin for &'a mut T {} /// Implementations of `Copy` for primitive types. diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index afd9fcb1fba84..87dde9066019c 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -530,6 +530,12 @@ pub unsafe fn zeroed() -> T { /// it goes out of scope (and therefore would be dropped). Note that this /// includes a `panic` occurring and unwinding the stack suddenly. /// +/// If you partially initialize an array, you may need to use +/// [`ptr::drop_in_place`][drop_in_place] to remove the elements you have fully +/// initialized followed by [`mem::forget`][mem_forget] to prevent drop running +/// on the array. If a partially allocated array is dropped this will lead to +/// undefined behaviour. +/// /// # Examples /// /// Here's how to safely initialize an array of [`Vec`]s. @@ -583,11 +589,44 @@ pub unsafe fn zeroed() -> T { /// println!("{:?}", &data[0]); /// ``` /// +/// This example shows how to handle partially initialized arrays, which could +/// be found in low-level datastructures. +/// +/// ``` +/// use std::mem; +/// use std::ptr; +/// +/// // Count the number of elements we have assigned. +/// let mut data_len: usize = 0; +/// let mut data: [String; 1000]; +/// +/// unsafe { +/// data = mem::uninitialized(); +/// +/// for elem in &mut data[0..500] { +/// ptr::write(elem, String::from("hello")); +/// data_len += 1; +/// } +/// +/// // For each item in the array, drop if we allocated it. +/// for i in &mut data[0..data_len] { +/// ptr::drop_in_place(i); +/// } +/// } +/// // Forget the data. If this is allowed to drop, you may see a crash such as: +/// // 'mem_uninit_test(2457,0x7fffb55dd380) malloc: *** error for object +/// // 0x7ff3b8402920: pointer being freed was not allocated' +/// mem::forget(data); +/// ``` +/// /// [`Vec`]: ../../std/vec/struct.Vec.html /// [`vec!`]: ../../std/macro.vec.html /// [`Clone`]: ../../std/clone/trait.Clone.html /// [ub]: ../../reference/behavior-considered-undefined.html /// [write]: ../ptr/fn.write.html +/// [drop_in_place]: ../ptr/fn.drop_in_place.html +/// [mem_zeroed]: fn.zeroed.html +/// [mem_forget]: fn.forget.html /// [copy]: ../intrinsics/fn.copy.html /// [copy_no]: ../intrinsics/fn.copy_nonoverlapping.html /// [`Drop`]: ../ops/trait.Drop.html @@ -984,6 +1023,9 @@ impl ManuallyDrop { /// /// This function semantically moves out the contained value without preventing further usage. /// It is up to the user of this method to ensure that this container is not used again. + /// + /// [`ManuallyDrop::drop`]: #method.drop + /// [`ManuallyDrop::into_inner`]: #method.into_inner #[must_use = "if you don't need the value, you can use `ManuallyDrop::drop` instead"] #[unstable(feature = "manually_drop_take", issue = "55422")] #[inline] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index f1df1f2856ed6..7ffb81901c619 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -673,7 +673,7 @@ $EndFeature, " } doc_comment! { - concat!("Checked Euclidean division. Computes `self.div_euc(rhs)`, + concat!("Checked Euclidean division. Computes `self.div_euclid(rhs)`, returning `None` if `rhs == 0` or the division results in overflow. # Examples @@ -683,17 +683,17 @@ Basic usage: ``` #![feature(euclidean_division)] assert_eq!((", stringify!($SelfT), -"::min_value() + 1).checked_div_euc(-1), Some(", stringify!($Max), ")); -assert_eq!(", stringify!($SelfT), "::min_value().checked_div_euc(-1), None); -assert_eq!((1", stringify!($SelfT), ").checked_div_euc(0), None); +"::min_value() + 1).checked_div_euclid(-1), Some(", stringify!($Max), ")); +assert_eq!(", stringify!($SelfT), "::min_value().checked_div_euclid(-1), None); +assert_eq!((1", stringify!($SelfT), ").checked_div_euclid(0), None); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] - pub fn checked_div_euc(self, rhs: Self) -> Option { + pub fn checked_div_euclid(self, rhs: Self) -> Option { if rhs == 0 || (self == Self::min_value() && rhs == -1) { None } else { - Some(self.div_euc(rhs)) + Some(self.div_euclid(rhs)) } } } @@ -726,8 +726,8 @@ $EndFeature, " } doc_comment! { - concat!("Checked Euclidean modulo. Computes `self.mod_euc(rhs)`, returning `None` if -`rhs == 0` or the division results in overflow. + concat!("Checked Euclidean remainder. Computes `self.rem_euclid(rhs)`, returning `None` +if `rhs == 0` or the division results in overflow. # Examples @@ -737,17 +737,17 @@ Basic usage: #![feature(euclidean_division)] use std::", stringify!($SelfT), "; -assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(2), Some(1)); -assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(0), None); -assert_eq!(", stringify!($SelfT), "::MIN.checked_mod_euc(-1), None); +assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None); +assert_eq!(", stringify!($SelfT), "::MIN.checked_rem_euclid(-1), None); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] - pub fn checked_mod_euc(self, rhs: Self) -> Option { + pub fn checked_rem_euclid(self, rhs: Self) -> Option { if rhs == 0 || (self == Self::min_value() && rhs == -1) { None } else { - Some(self.mod_euc(rhs)) + Some(self.rem_euclid(rhs)) } } } @@ -1089,7 +1089,7 @@ $EndFeature, " } doc_comment! { - concat!("Wrapping Euclidean division. Computes `self.div_euc(rhs)`, + concat!("Wrapping Euclidean division. Computes `self.div_euclid(rhs)`, wrapping around at the boundary of the type. Wrapping will only occur in `MIN / -1` on a signed type (where `MIN` is the negative minimal value @@ -1106,13 +1106,13 @@ Basic usage: ``` #![feature(euclidean_division)] -assert_eq!(100", stringify!($SelfT), ".wrapping_div_euc(10), 10); -assert_eq!((-128i8).wrapping_div_euc(-1), -128); +assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10); +assert_eq!((-128i8).wrapping_div_euclid(-1), -128); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] - pub fn wrapping_div_euc(self, rhs: Self) -> Self { - self.overflowing_div_euc(rhs).0 + pub fn wrapping_div_euclid(self, rhs: Self) -> Self { + self.overflowing_div_euclid(rhs).0 } } @@ -1145,8 +1145,8 @@ $EndFeature, " } doc_comment! { - concat!("Wrapping Euclidean modulo. Computes `self.mod_euc(rhs)`, wrapping around at the -boundary of the type. + concat!("Wrapping Euclidean remainder. Computes `self.rem_euclid(rhs)`, wrapping around +at the boundary of the type. Wrapping will only occur in `MIN % -1` on a signed type (where `MIN` is the negative minimal value for the type). In this case, this method returns 0. @@ -1161,13 +1161,13 @@ Basic usage: ``` #![feature(euclidean_division)] -assert_eq!(100", stringify!($SelfT), ".wrapping_mod_euc(10), 0); -assert_eq!((-128i8).wrapping_mod_euc(-1), 0); +assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0); +assert_eq!((-128i8).wrapping_rem_euclid(-1), 0); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] - pub fn wrapping_mod_euc(self, rhs: Self) -> Self { - self.overflowing_mod_euc(rhs).0 + pub fn wrapping_rem_euclid(self, rhs: Self) -> Self { + self.overflowing_rem_euclid(rhs).0 } } @@ -1442,7 +1442,7 @@ $EndFeature, " } doc_comment! { - concat!("Calculates the quotient of Euclidean division `self.div_euc(rhs)`. + concat!("Calculates the quotient of Euclidean division `self.div_euclid(rhs)`. Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would occur. If an overflow would occur then `self` is returned. @@ -1459,17 +1459,17 @@ Basic usage: #![feature(euclidean_division)] use std::", stringify!($SelfT), "; -assert_eq!(5", stringify!($SelfT), ".overflowing_div_euc(2), (2, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euc(-1), (", stringify!($SelfT), +assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euclid(-1), (", stringify!($SelfT), "::MIN, true)); ```"), #[inline] #[unstable(feature = "euclidean_division", issue = "49048")] - pub fn overflowing_div_euc(self, rhs: Self) -> (Self, bool) { + pub fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { if self == Self::min_value() && rhs == -1 { (self, true) } else { - (self.div_euc(rhs), false) + (self.div_euclid(rhs), false) } } } @@ -1508,7 +1508,7 @@ $EndFeature, " doc_comment! { - concat!("Calculates the remainder `self.mod_euc(rhs)` by Euclidean division. + concat!("Overflowing Euclidean remainder. Calculates `self.rem_euclid(rhs)`. Returns a tuple of the remainder after dividing along with a boolean indicating whether an arithmetic overflow would occur. If an overflow would occur then 0 is returned. @@ -1525,16 +1525,16 @@ Basic usage: #![feature(euclidean_division)] use std::", stringify!($SelfT), "; -assert_eq!(5", stringify!($SelfT), ".overflowing_mod_euc(2), (1, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_mod_euc(-1), (0, true)); +assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem_euclid(-1), (0, true)); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] - pub fn overflowing_mod_euc(self, rhs: Self) -> (Self, bool) { + pub fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { if self == Self::min_value() && rhs == -1 { (0, true) } else { - (self.mod_euc(rhs), false) + (self.rem_euclid(rhs), false) } } } @@ -1739,9 +1739,13 @@ $EndFeature, " doc_comment! { concat!("Calculates the quotient of Euclidean division of `self` by `rhs`. -This computes the integer `n` such that `self = n * rhs + self.mod_euc(rhs)`. +This computes the integer `n` such that `self = n * rhs + self.rem_euclid(rhs)`, +with `0 <= self.rem_euclid(rhs) < rhs`. + In other words, the result is `self / rhs` rounded to the integer `n` such that `self >= n * rhs`. +If `self > 0`, this is equal to round towards zero (the default in Rust); +if `self < 0`, this is equal to round towards +/- infinity. # Panics @@ -1756,15 +1760,15 @@ Basic usage: let a: ", stringify!($SelfT), " = 7; // or any other integer type let b = 4; -assert_eq!(a.div_euc(b), 1); // 7 >= 4 * 1 -assert_eq!(a.div_euc(-b), -1); // 7 >= -4 * -1 -assert_eq!((-a).div_euc(b), -2); // -7 >= 4 * -2 -assert_eq!((-a).div_euc(-b), 2); // -7 >= -4 * 2 +assert_eq!(a.div_euclid(b), 1); // 7 >= 4 * 1 +assert_eq!(a.div_euclid(-b), -1); // 7 >= -4 * -1 +assert_eq!((-a).div_euclid(b), -2); // -7 >= 4 * -2 +assert_eq!((-a).div_euclid(-b), 2); // -7 >= -4 * 2 ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] #[rustc_inherit_overflow_checks] - pub fn div_euc(self, rhs: Self) -> Self { + pub fn div_euclid(self, rhs: Self) -> Self { let q = self / rhs; if self % rhs < 0 { return if rhs > 0 { q - 1 } else { q + 1 } @@ -1775,9 +1779,11 @@ assert_eq!((-a).div_euc(-b), 2); // -7 >= -4 * 2 doc_comment! { - concat!("Calculates the remainder `self mod rhs` by Euclidean division. + concat!("Calculates the least nonnegative remainder of `self (mod rhs)`. -In particular, the result `n` satisfies `0 <= n < rhs.abs()`. +This is done as if by the Euclidean division algorithm -- given +`r = self.rem_euclid(rhs)`, `self = rhs * self.div_euclid(rhs) + r`, and +`0 <= r < abs(rhs)`. # Panics @@ -1792,15 +1798,15 @@ Basic usage: let a: ", stringify!($SelfT), " = 7; // or any other integer type let b = 4; -assert_eq!(a.mod_euc(b), 3); -assert_eq!((-a).mod_euc(b), 1); -assert_eq!(a.mod_euc(-b), 3); -assert_eq!((-a).mod_euc(-b), 1); +assert_eq!(a.rem_euclid(b), 3); +assert_eq!((-a).rem_euclid(b), 1); +assert_eq!(a.rem_euclid(-b), 3); +assert_eq!((-a).rem_euclid(-b), 1); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] #[rustc_inherit_overflow_checks] - pub fn mod_euc(self, rhs: Self) -> Self { + pub fn rem_euclid(self, rhs: Self) -> Self { let r = self % rhs; if r < 0 { if rhs < 0 { @@ -2611,7 +2617,7 @@ assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);", $EndFeature, " } doc_comment! { - concat!("Checked Euclidean division. Computes `self.div_euc(rhs)`, returning `None` + concat!("Checked Euclidean division. Computes `self.div_euclid(rhs)`, returning `None` if `rhs == 0`. # Examples @@ -2620,16 +2626,16 @@ Basic usage: ``` #![feature(euclidean_division)] -assert_eq!(128", stringify!($SelfT), ".checked_div(2), Some(64)); -assert_eq!(1", stringify!($SelfT), ".checked_div_euc(0), None); +assert_eq!(128", stringify!($SelfT), ".checked_div_euclid(2), Some(64)); +assert_eq!(1", stringify!($SelfT), ".checked_div_euclid(0), None); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] - pub fn checked_div_euc(self, rhs: Self) -> Option { + pub fn checked_div_euclid(self, rhs: Self) -> Option { if rhs == 0 { None } else { - Some(self.div_euc(rhs)) + Some(self.div_euclid(rhs)) } } } @@ -2659,7 +2665,7 @@ assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);", $EndFeature, " } doc_comment! { - concat!("Checked Euclidean modulo. Computes `self.mod_euc(rhs)`, returning `None` + concat!("Checked Euclidean modulo. Computes `self.rem_euclid(rhs)`, returning `None` if `rhs == 0`. # Examples @@ -2668,16 +2674,16 @@ Basic usage: ``` #![feature(euclidean_division)] -assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(2), Some(1)); -assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(0), None); +assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] - pub fn checked_mod_euc(self, rhs: Self) -> Option { + pub fn checked_rem_euclid(self, rhs: Self) -> Option { if rhs == 0 { None } else { - Some(self.mod_euc(rhs)) + Some(self.rem_euclid(rhs)) } } } @@ -2965,11 +2971,14 @@ Basic usage: } doc_comment! { - concat!("Wrapping Euclidean division. Computes `self.div_euc(rhs)`. + concat!("Wrapping Euclidean division. Computes `self.div_euclid(rhs)`. Wrapped division on unsigned types is just normal division. There's no way wrapping could ever happen. This function exists, so that all operations are accounted for in the wrapping operations. +Since, for the positive integers, all common +definitions of division are equal, this +is exactly equal to `self.wrapping_div(rhs)`. # Examples @@ -2977,11 +2986,11 @@ Basic usage: ``` #![feature(euclidean_division)] -assert_eq!(100", stringify!($SelfT), ".wrapping_div_euc(10), 10); +assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] - pub fn wrapping_div_euc(self, rhs: Self) -> Self { + pub fn wrapping_div_euclid(self, rhs: Self) -> Self { self / rhs } } @@ -3009,12 +3018,15 @@ Basic usage: } doc_comment! { - concat!("Wrapping Euclidean modulo. Computes `self.mod_euc(rhs)`. + concat!("Wrapping Euclidean modulo. Computes `self.rem_euclid(rhs)`. Wrapped modulo calculation on unsigned types is just the regular remainder calculation. There's no way wrapping could ever happen. This function exists, so that all operations are accounted for in the wrapping operations. +Since, for the positive integers, all common +definitions of division are equal, this +is exactly equal to `self.wrapping_rem(rhs)`. # Examples @@ -3022,11 +3034,11 @@ Basic usage: ``` #![feature(euclidean_division)] -assert_eq!(100", stringify!($SelfT), ".wrapping_mod_euc(10), 0); +assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] - pub fn wrapping_mod_euc(self, rhs: Self) -> Self { + pub fn wrapping_rem_euclid(self, rhs: Self) -> Self { self % rhs } } @@ -3270,12 +3282,15 @@ Basic usage } doc_comment! { - concat!("Calculates the quotient of Euclidean division `self.div_euc(rhs)`. + concat!("Calculates the quotient of Euclidean division `self.div_euclid(rhs)`. Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would occur. Note that for unsigned integers overflow never occurs, so the second value is always `false`. +Since, for the positive integers, all common +definitions of division are equal, this +is exactly equal to `self.overflowing_div(rhs)`. # Panics @@ -3287,11 +3302,11 @@ Basic usage ``` #![feature(euclidean_division)] -assert_eq!(5", stringify!($SelfT), ".overflowing_div_euc(2), (2, false)); +assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false)); ```"), #[inline] #[unstable(feature = "euclidean_division", issue = "49048")] - pub fn overflowing_div_euc(self, rhs: Self) -> (Self, bool) { + pub fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { (self / rhs, false) } } @@ -3323,12 +3338,15 @@ Basic usage } doc_comment! { - concat!("Calculates the remainder `self.mod_euc(rhs)` by Euclidean division. + concat!("Calculates the remainder `self.rem_euclid(rhs)` as if by Euclidean division. Returns a tuple of the modulo after dividing along with a boolean indicating whether an arithmetic overflow would occur. Note that for unsigned integers overflow never occurs, so the second value is always `false`. +Since, for the positive integers, all common +definitions of division are equal, this operation +is exactly equal to `self.overflowing_rem(rhs)`. # Panics @@ -3340,11 +3358,11 @@ Basic usage ``` #![feature(euclidean_division)] -assert_eq!(5", stringify!($SelfT), ".overflowing_mod_euc(2), (1, false)); +assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false)); ```"), #[inline] #[unstable(feature = "euclidean_division", issue = "49048")] - pub fn overflowing_mod_euc(self, rhs: Self) -> (Self, bool) { + pub fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { (self % rhs, false) } } @@ -3511,7 +3529,9 @@ Basic usage: doc_comment! { concat!("Performs Euclidean division. -For unsigned types, this is just the same as `self / rhs`. +Since, for the positive integers, all common +definitions of division are equal, this +is exactly equal to `self / rhs`. # Examples @@ -3519,21 +3539,23 @@ Basic usage: ``` #![feature(euclidean_division)] -assert_eq!(7", stringify!($SelfT), ".div_euc(4), 1); // or any other integer type +assert_eq!(7", stringify!($SelfT), ".div_euclid(4), 1); // or any other integer type ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] #[rustc_inherit_overflow_checks] - pub fn div_euc(self, rhs: Self) -> Self { + pub fn div_euclid(self, rhs: Self) -> Self { self / rhs } } doc_comment! { - concat!("Calculates the remainder `self mod rhs` by Euclidean division. + concat!("Calculates the least remainder of `self (mod rhs)`. -For unsigned types, this is just the same as `self % rhs`. +Since, for the positive integers, all common +definitions of division are equal, this +is exactly equal to `self % rhs`. # Examples @@ -3541,12 +3563,12 @@ Basic usage: ``` #![feature(euclidean_division)] -assert_eq!(7", stringify!($SelfT), ".mod_euc(4), 3); // or any other integer type +assert_eq!(7", stringify!($SelfT), ".rem_euclid(4), 3); // or any other integer type ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] #[rustc_inherit_overflow_checks] - pub fn mod_euc(self, rhs: Self) -> Self { + pub fn rem_euclid(self, rhs: Self) -> Self { self % rhs } } diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 44d632ece055c..2f248d5276c77 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -273,7 +273,7 @@ impl Option { /// Converts from `Pin<&Option>` to `Option>` #[inline] - #[unstable(feature = "pin", issue = "49150")] + #[stable(feature = "pin", since = "1.33.0")] pub fn as_pin_ref<'a>(self: Pin<&'a Option>) -> Option> { unsafe { Pin::get_ref(self).as_ref().map(|x| Pin::new_unchecked(x)) @@ -282,10 +282,10 @@ impl Option { /// Converts from `Pin<&mut Option>` to `Option>` #[inline] - #[unstable(feature = "pin", issue = "49150")] + #[stable(feature = "pin", since = "1.33.0")] pub fn as_pin_mut<'a>(self: Pin<&'a mut Option>) -> Option> { unsafe { - Pin::get_mut_unchecked(self).as_mut().map(|x| Pin::new_unchecked(x)) + Pin::get_unchecked_mut(self).as_mut().map(|x| Pin::new_unchecked(x)) } } diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 0ad6e8c7c1c7d..930e51ce41ed6 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -36,15 +36,13 @@ //! are always freely movable, even if the data they point to isn't. //! //! [`Pin`]: struct.Pin.html -//! [`Unpin`]: trait.Unpin.html +//! [`Unpin`]: ../../std/marker/trait.Unpin.html //! [`swap`]: ../../std/mem/fn.swap.html //! [`Box`]: ../../std/boxed/struct.Box.html //! //! # Examples //! //! ```rust -//! #![feature(pin)] -//! //! use std::pin::Pin; //! use std::marker::PhantomPinned; //! use std::ptr::NonNull; @@ -72,13 +70,13 @@ //! slice: NonNull::dangling(), //! _pin: PhantomPinned, //! }; -//! let mut boxed = Box::pinned(res); +//! let mut boxed = Box::pin(res); //! //! let slice = NonNull::from(&boxed.data); //! // we know this is safe because modifying a field doesn't move the whole struct //! unsafe { //! let mut_ref: Pin<&mut Self> = Pin::as_mut(&mut boxed); -//! Pin::get_mut_unchecked(mut_ref).slice = slice; +//! Pin::get_unchecked_mut(mut_ref).slice = slice; //! } //! boxed //! } @@ -97,15 +95,12 @@ //! // std::mem::swap(&mut *still_unmoved, &mut *new_unmoved); //! ``` -#![unstable(feature = "pin", issue = "49150")] +#![stable(feature = "pin", since = "1.33.0")] use fmt; -use marker::Sized; +use marker::{Sized, Unpin}; use ops::{Deref, DerefMut, CoerceUnsized, DispatchFromDyn}; -#[doc(inline)] -pub use marker::Unpin; - /// A pinned pointer. /// /// This is a wrapper around a kind of pointer which makes that pointer "pin" its @@ -119,8 +114,9 @@ pub use marker::Unpin; // // Note: the derives below are allowed because they all only use `&P`, so they // cannot move the value behind `pointer`. -#[unstable(feature = "pin", issue = "49150")] +#[stable(feature = "pin", since = "1.33.0")] #[fundamental] +#[repr(transparent)] #[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)] pub struct Pin

{ pointer: P, @@ -132,7 +128,7 @@ where { /// Construct a new `Pin` around a pointer to some data of a type that /// implements `Unpin`. - #[unstable(feature = "pin", issue = "49150")] + #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub fn new(pointer: P) -> Pin

{ // Safety: the value pointed to is `Unpin`, and so has no requirements @@ -154,14 +150,14 @@ impl Pin

{ /// /// If `pointer` dereferences to an `Unpin` type, `Pin::new` should be used /// instead. - #[unstable(feature = "pin", issue = "49150")] + #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub unsafe fn new_unchecked(pointer: P) -> Pin

{ Pin { pointer } } /// Get a pinned shared reference from this pinned pointer. - #[unstable(feature = "pin", issue = "49150")] + #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub fn as_ref(self: &Pin

) -> Pin<&P::Target> { unsafe { Pin::new_unchecked(&*self.pointer) } @@ -170,14 +166,14 @@ impl Pin

{ impl Pin

{ /// Get a pinned mutable reference from this pinned pointer. - #[unstable(feature = "pin", issue = "49150")] + #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub fn as_mut(self: &mut Pin

) -> Pin<&mut P::Target> { unsafe { Pin::new_unchecked(&mut *self.pointer) } } /// Assign a new value to the memory behind the pinned reference. - #[unstable(feature = "pin", issue = "49150")] + #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub fn set(mut self: Pin

, value: P::Target) where @@ -199,11 +195,11 @@ impl<'a, T: ?Sized> Pin<&'a T> { /// will not move so long as the argument value does not move (for example, /// because it is one of the fields of that value), and also that you do /// not move out of the argument you receive to the interior function. - #[unstable(feature = "pin", issue = "49150")] - pub unsafe fn map_unchecked(this: Pin<&'a T>, func: F) -> Pin<&'a U> where + #[stable(feature = "pin", since = "1.33.0")] + pub unsafe fn map_unchecked(self: Pin<&'a T>, func: F) -> Pin<&'a U> where F: FnOnce(&T) -> &U, { - let pointer = &*this.pointer; + let pointer = &*self.pointer; let new_pointer = func(pointer); Pin::new_unchecked(new_pointer) } @@ -215,19 +211,19 @@ impl<'a, T: ?Sized> Pin<&'a T> { /// that lives for as long as the borrow of the `Pin`, not the lifetime of /// the `Pin` itself. This method allows turning the `Pin` into a reference /// with the same lifetime as the original `Pin`. - #[unstable(feature = "pin", issue = "49150")] + #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn get_ref(this: Pin<&'a T>) -> &'a T { - this.pointer + pub fn get_ref(self: Pin<&'a T>) -> &'a T { + self.pointer } } impl<'a, T: ?Sized> Pin<&'a mut T> { /// Convert this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime. - #[unstable(feature = "pin", issue = "49150")] + #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn into_ref(this: Pin<&'a mut T>) -> Pin<&'a T> { - Pin { pointer: this.pointer } + pub fn into_ref(self: Pin<&'a mut T>) -> Pin<&'a T> { + Pin { pointer: self.pointer } } /// Get a mutable reference to the data inside of this `Pin`. @@ -239,12 +235,12 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// that lives for as long as the borrow of the `Pin`, not the lifetime of /// the `Pin` itself. This method allows turning the `Pin` into a reference /// with the same lifetime as the original `Pin`. - #[unstable(feature = "pin", issue = "49150")] + #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn get_mut(this: Pin<&'a mut T>) -> &'a mut T + pub fn get_mut(self: Pin<&'a mut T>) -> &'a mut T where T: Unpin, { - this.pointer + self.pointer } /// Get a mutable reference to the data inside of this `Pin`. @@ -257,10 +253,10 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// /// If the underlying data is `Unpin`, `Pin::get_mut` should be used /// instead. - #[unstable(feature = "pin", issue = "49150")] + #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub unsafe fn get_mut_unchecked(this: Pin<&'a mut T>) -> &'a mut T { - this.pointer + pub unsafe fn get_unchecked_mut(self: Pin<&'a mut T>) -> &'a mut T { + self.pointer } /// Construct a new pin by mapping the interior value. @@ -274,17 +270,17 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// will not move so long as the argument value does not move (for example, /// because it is one of the fields of that value), and also that you do /// not move out of the argument you receive to the interior function. - #[unstable(feature = "pin", issue = "49150")] - pub unsafe fn map_unchecked_mut(this: Pin<&'a mut T>, func: F) -> Pin<&'a mut U> where + #[stable(feature = "pin", since = "1.33.0")] + pub unsafe fn map_unchecked_mut(self: Pin<&'a mut T>, func: F) -> Pin<&'a mut U> where F: FnOnce(&mut T) -> &mut U, { - let pointer = Pin::get_mut_unchecked(this); + let pointer = Pin::get_unchecked_mut(self); let new_pointer = func(pointer); Pin::new_unchecked(new_pointer) } } -#[unstable(feature = "pin", issue = "49150")] +#[stable(feature = "pin", since = "1.33.0")] impl Deref for Pin

{ type Target = P::Target; fn deref(&self) -> &P::Target { @@ -292,7 +288,7 @@ impl Deref for Pin

{ } } -#[unstable(feature = "pin", issue = "49150")] +#[stable(feature = "pin", since = "1.33.0")] impl DerefMut for Pin

where P::Target: Unpin @@ -302,21 +298,21 @@ where } } -#[unstable(feature = "pin", issue = "49150")] +#[stable(feature = "pin", since = "1.33.0")] impl fmt::Debug for Pin

{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&self.pointer, f) } } -#[unstable(feature = "pin", issue = "49150")] +#[stable(feature = "pin", since = "1.33.0")] impl fmt::Display for Pin

{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.pointer, f) } } -#[unstable(feature = "pin", issue = "49150")] +#[stable(feature = "pin", since = "1.33.0")] impl fmt::Pointer for Pin

{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Pointer::fmt(&self.pointer, f) @@ -328,17 +324,14 @@ impl fmt::Pointer for Pin

{ // `Deref` is unsound. Any such impl would probably be unsound // for other reasons, though, so we just need to take care not to allow such // impls to land in std. -#[unstable(feature = "pin", issue = "49150")] +#[stable(feature = "pin", since = "1.33.0")] impl CoerceUnsized> for Pin

where P: CoerceUnsized, {} -#[unstable(feature = "pin", issue = "49150")] +#[stable(feature = "pin", since = "1.33.0")] impl<'a, P, U> DispatchFromDyn> for Pin

where P: DispatchFromDyn, {} - -#[unstable(feature = "pin", issue = "49150")] -impl

Unpin for Pin

{} diff --git a/src/libcore/prelude/v1.rs b/src/libcore/prelude/v1.rs index 45f629a64424c..a1e6034b20821 100644 --- a/src/libcore/prelude/v1.rs +++ b/src/libcore/prelude/v1.rs @@ -19,7 +19,7 @@ // Re-exported core operators #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] -pub use marker::{Copy, Send, Sized, Sync}; +pub use marker::{Copy, Send, Sized, Sync, Unpin}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] pub use ops::{Drop, Fn, FnMut, FnOnce}; diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 59c11b273293f..193061457b5cd 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -877,6 +877,7 @@ impl [T] { /// assert_eq!(iter.remainder(), &['l']); /// ``` /// + /// [`chunks`]: #method.chunks /// [`rchunks`]: #method.rchunks /// [`chunks_exact`]: #method.chunks_exact #[stable(feature = "rchunks", since = "1.31.0")] @@ -921,6 +922,7 @@ impl [T] { /// assert_eq!(v, &[0, 2, 2, 1, 1]); /// ``` /// + /// [`chunks_mut`]: #method.chunks_mut /// [`rchunks_mut`]: #method.rchunks_mut /// [`chunks_exact_mut`]: #method.chunks_exact_mut #[stable(feature = "rchunks", since = "1.31.0")] diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 00b4aa4fa2d7a..b5633333d0170 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1016,6 +1016,33 @@ fn test_iterator_nth() { assert_eq!(v.iter().nth(v.len()), None); } +#[test] +fn test_iterator_nth_back() { + let v: &[_] = &[0, 1, 2, 3, 4]; + for i in 0..v.len() { + assert_eq!(v.iter().nth_back(i).unwrap(), &v[v.len() - 1 - i]); + } + assert_eq!(v.iter().nth_back(v.len()), None); +} + +#[test] +fn test_iterator_rev_nth_back() { + let v: &[_] = &[0, 1, 2, 3, 4]; + for i in 0..v.len() { + assert_eq!(v.iter().rev().nth_back(i).unwrap(), &v[i]); + } + assert_eq!(v.iter().rev().nth_back(v.len()), None); +} + +#[test] +fn test_iterator_rev_nth() { + let v: &[_] = &[0, 1, 2, 3, 4]; + for i in 0..v.len() { + assert_eq!(v.iter().rev().nth(i).unwrap(), &v[v.len() - 1 - i]); + } + assert_eq!(v.iter().rev().nth(v.len()), None); +} + #[test] fn test_iterator_last() { let v: &[_] = &[0, 1, 2, 3, 4]; diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 7d62b4fa90f20..2377a4733678d 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -19,6 +19,7 @@ #![feature(flt2dec)] #![feature(fmt_internals)] #![feature(hashmap_internals)] +#![feature(iter_nth_back)] #![feature(iter_unfold)] #![feature(pattern)] #![feature(range_is_empty)] diff --git a/src/libcore/tests/num/int_macros.rs b/src/libcore/tests/num/int_macros.rs index 71d2e7945389b..8b04f84007fa7 100644 --- a/src/libcore/tests/num/int_macros.rs +++ b/src/libcore/tests/num/int_macros.rs @@ -31,8 +31,8 @@ mod tests { } #[test] - fn test_mod_euc() { - assert!((-1 as $T).mod_euc(MIN) == MAX); + fn test_rem_euclid() { + assert!((-1 as $T).rem_euclid(MIN) == MAX); } #[test] diff --git a/src/libcore/tests/num/mod.rs b/src/libcore/tests/num/mod.rs index 0928f7560e175..e1648db5e8ed2 100644 --- a/src/libcore/tests/num/mod.rs +++ b/src/libcore/tests/num/mod.rs @@ -694,23 +694,23 @@ macro_rules! test_float { assert!(($nan as $fty).max($nan).is_nan()); } #[test] - fn mod_euc() { + fn rem_euclid() { let a: $fty = 42.0; - assert!($inf.mod_euc(a).is_nan()); - assert_eq!(a.mod_euc($inf), a); - assert!(a.mod_euc($nan).is_nan()); - assert!($inf.mod_euc($inf).is_nan()); - assert!($inf.mod_euc($nan).is_nan()); - assert!($nan.mod_euc($inf).is_nan()); + assert!($inf.rem_euclid(a).is_nan()); + assert_eq!(a.rem_euclid($inf), a); + assert!(a.rem_euclid($nan).is_nan()); + assert!($inf.rem_euclid($inf).is_nan()); + assert!($inf.rem_euclid($nan).is_nan()); + assert!($nan.rem_euclid($inf).is_nan()); } #[test] - fn div_euc() { + fn div_euclid() { let a: $fty = 42.0; - assert_eq!(a.div_euc($inf), 0.0); - assert!(a.div_euc($nan).is_nan()); - assert!($inf.div_euc($inf).is_nan()); - assert!($inf.div_euc($nan).is_nan()); - assert!($nan.div_euc($inf).is_nan()); + assert_eq!(a.div_euclid($inf), 0.0); + assert!(a.div_euclid($nan).is_nan()); + assert!($inf.div_euclid($inf).is_nan()); + assert!($inf.div_euclid($nan).is_nan()); + assert!($nan.div_euclid($inf).is_nan()); } } } } diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index 49f8a429126b7..cfe671c626bcf 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -62,7 +62,7 @@ cfg_if! { if #[cfg(target_os = "emscripten")] { #[path = "emcc.rs"] mod imp; - } else if #[cfg(any(target_arch = "wasm32", target_env = "sgx"))] { + } else if #[cfg(target_arch = "wasm32")] { #[path = "dummy.rs"] mod imp; } else if #[cfg(all(target_env = "msvc", target_arch = "aarch64"))] { diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 4881f10fac25e..80dcdde4424c1 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -402,7 +402,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { hir::ExprKind::Closure(..) | hir::ExprKind::Lit(..) | - hir::ExprKind::Path(_) => { + hir::ExprKind::Path(_) | + hir::ExprKind::Err => { self.straightline(expr, pred, None::.iter()) } } diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index f7e2c7036f6f8..db94a48b9b1d7 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -1109,6 +1109,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { ExprKind::Yield(ref subexpression) => { visitor.visit_expr(subexpression); } + ExprKind::Err => {} } } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 6958801d865bf..83e56b56c6c61 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2719,7 +2719,6 @@ impl<'a> LoweringContext<'a> { rules: self.lower_block_check_mode(&b.rules), span: b.span, targeted_by_break, - recovered: b.recovered, }) } @@ -3791,7 +3790,6 @@ impl<'a> LoweringContext<'a> { rules: hir::DefaultBlock, span, targeted_by_break: false, - recovered: blk.recovered, }); P(self.expr_block(blk, ThinVec::new())) } @@ -4127,6 +4125,8 @@ impl<'a> LoweringContext<'a> { hir::ExprKind::Yield(P(expr)) } + ExprKind::Err => hir::ExprKind::Err, + // Desugar `ExprIfLet` // from: `if let = []` ExprKind::IfLet(ref pats, ref sub_expr, ref body, ref else_opt) => { @@ -4831,7 +4831,6 @@ impl<'a> LoweringContext<'a> { rules: hir::DefaultBlock, span, targeted_by_break: false, - recovered: false, } } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 156d55b9e2fe6..a544b6dba89d6 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -817,11 +817,6 @@ pub struct Block { /// break out of this block early. /// Used by `'label: {}` blocks and by `catch` statements. pub targeted_by_break: bool, - /// If true, don't emit return value type errors as the parser had - /// to recover from a parse error so this block will not have an - /// appropriate type. A parse error will have been emitted so the - /// compilation will never succeed if this is true. - pub recovered: bool, } #[derive(Clone, RustcEncodable, RustcDecodable)] @@ -1372,6 +1367,7 @@ impl Expr { ExprKind::Struct(..) => ExprPrecedence::Struct, ExprKind::Repeat(..) => ExprPrecedence::Repeat, ExprKind::Yield(..) => ExprPrecedence::Yield, + ExprKind::Err => ExprPrecedence::Err, } } @@ -1422,7 +1418,8 @@ impl Expr { ExprKind::AddrOf(..) | ExprKind::Binary(..) | ExprKind::Yield(..) | - ExprKind::Cast(..) => { + ExprKind::Cast(..) | + ExprKind::Err => { false } } @@ -1535,6 +1532,9 @@ pub enum ExprKind { /// A suspension point for generators. This is `yield ` in Rust. Yield(P), + + /// Placeholder for an expression that wasn't syntactically well formed in some way. + Err, } /// Optionally `Self`-qualified value/type path or associated extension. @@ -2119,7 +2119,7 @@ impl StructField { /// Id of the whole enum lives in `Item`. /// /// For structs: `NodeId` represents an Id of the structure's constructor, so it is not actually -/// used for `Struct`-structs (but still presents). Structures don't have an analogue of "Id of +/// used for `Struct`-structs (but still present). Structures don't have an analogue of "Id of /// the variant itself" from enum variants. /// Id of the whole struct lives in `Item`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 5c6845181afd1..93194870a4a1e 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -440,7 +440,9 @@ impl<'a> State<'a> { self.s.word("_")?; } hir::TyKind::Err => { - self.s.word("?")?; + self.popen()?; + self.s.word("/*ERROR*/")?; + self.pclose()?; } } self.end() @@ -1550,6 +1552,11 @@ impl<'a> State<'a> { self.word_space("yield")?; self.print_expr_maybe_paren(&expr, parser::PREC_JUMP)?; } + hir::ExprKind::Err => { + self.popen()?; + self.s.word("/*ERROR*/")?; + self.pclose()?; + } } self.ann.post(self, AnnNode::Expr(expr))?; self.end() diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index ae0d78d2958ad..cd8360678b50c 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -420,7 +420,6 @@ impl_stable_hash_for!(struct hir::Block { rules, span, targeted_by_break, - recovered, }); impl_stable_hash_for!(struct hir::Pat { @@ -602,7 +601,8 @@ impl_stable_hash_for!(enum hir::ExprKind { InlineAsm(asm, inputs, outputs), Struct(path, fields, base), Repeat(val, times), - Yield(val) + Yield(val), + Err }); impl_stable_hash_for!(enum hir::LocalSource { diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 449f8e0a2db67..131dedb988832 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -42,11 +42,12 @@ use util::nodemap::FxHashMap; use std::default::Default as StdDefault; use syntax::ast; use syntax::edition; -use syntax_pos::{MultiSpan, Span, symbol::LocalInternedString}; +use syntax_pos::{MultiSpan, Span, symbol::{LocalInternedString, Symbol}}; use errors::DiagnosticBuilder; use hir; use hir::def_id::LOCAL_CRATE; use hir::intravisit as hir_visit; +use syntax::util::lev_distance::find_best_match_for_name; use syntax::visit as ast_visit; /// Information about the registered lints. @@ -139,8 +140,8 @@ struct LintGroup { pub enum CheckLintNameResult<'a> { Ok(&'a [LintId]), - /// Lint doesn't exist - NoLint, + /// Lint doesn't exist. Potentially contains a suggestion for a correct lint name. + NoLint(Option), /// The lint is either renamed or removed. This is the warning /// message, and an optional new name (`None` if removed). Warning(String, Option), @@ -359,8 +360,14 @@ impl LintStore { CheckLintNameResult::Warning(ref msg, _) => { Some(sess.struct_warn(msg)) }, - CheckLintNameResult::NoLint => { - Some(struct_err!(sess, E0602, "unknown lint: `{}`", lint_name)) + CheckLintNameResult::NoLint(suggestion) => { + let mut err = struct_err!(sess, E0602, "unknown lint: `{}`", lint_name); + + if let Some(suggestion) = suggestion { + err.help(&format!("did you mean: `{}`", suggestion)); + } + + Some(err) } CheckLintNameResult::Tool(result) => match result { Err((Some(_), new_name)) => Some(sess.struct_warn(&format!( @@ -464,7 +471,16 @@ impl LintStore { match self.by_name.get(&complete_name) { None => match self.lint_groups.get(&*complete_name) { // Now we are sure, that this lint exists nowhere - None => CheckLintNameResult::NoLint, + None => { + let symbols = self.by_name.keys() + .map(|name| Symbol::intern(&name)) + .collect::>(); + + let suggestion = + find_best_match_for_name(symbols.iter(), &lint_name.to_lowercase(), None); + + CheckLintNameResult::NoLint(suggestion) + } Some(LintGroup { lint_ids, depr, .. }) => { // Reaching this would be weird, but let's cover this case anyway if let Some(LintAlias { name, silent }) = depr { @@ -484,7 +500,7 @@ impl LintStore { Some(&Id(ref id)) => { CheckLintNameResult::Tool(Err((Some(slice::from_ref(id)), complete_name))) } - _ => CheckLintNameResult::NoLint, + _ => CheckLintNameResult::NoLint(None), } } } diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index 06e3e0bab4f10..219429d4cbc0c 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -232,14 +232,13 @@ impl<'a> LintLevelsBuilder<'a> { match item.node { ast::MetaItemKind::Word => {} // actual lint names handled later ast::MetaItemKind::NameValue(ref name_value) => { - let gate_reasons = !self.sess.features_untracked().lint_reasons; if item.ident == "reason" { // found reason, reslice meta list to exclude it metas = &metas[0..metas.len()-1]; // FIXME (#55112): issue unused-attributes lint if we thereby // don't have any lint names (`#[level(reason = "foo")]`) if let ast::LitKind::Str(rationale, _) = name_value.node { - if gate_reasons { + if !self.sess.features_untracked().lint_reasons { feature_gate::emit_feature_err( &self.sess.parse_sess, "lint_reasons", @@ -247,9 +246,8 @@ impl<'a> LintLevelsBuilder<'a> { feature_gate::GateIssue::Language, "lint reasons are experimental" ); - } else { - reason = Some(rationale); } + reason = Some(rationale); } else { let mut err = bad_attr(name_value.span); err.help("reason must be a string literal"); @@ -385,7 +383,7 @@ impl<'a> LintLevelsBuilder<'a> { } err.emit(); } - CheckLintNameResult::NoLint => { + CheckLintNameResult::NoLint(suggestion) => { let lint = builtin::UNKNOWN_LINTS; let (level, src) = self.sets.get_lint_level(lint, self.cur, @@ -398,22 +396,17 @@ impl<'a> LintLevelsBuilder<'a> { src, Some(li.span.into()), &msg); - if name.as_str().chars().any(|c| c.is_uppercase()) { - let name_lower = name.as_str().to_lowercase().to_string(); - if let CheckLintNameResult::NoLint = - store.check_lint_name(&name_lower, tool_name) { - db.emit(); - } else { - db.span_suggestion_with_applicability( - li.span, - "lowercase the lint name", - name_lower, - Applicability::MachineApplicable - ).emit(); - } - } else { - db.emit(); + + if let Some(suggestion) = suggestion { + db.span_suggestion_with_applicability( + li.span, + "did you mean", + suggestion.to_string(), + Applicability::MachineApplicable, + ); } + + db.emit(); } } } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 934d7c12be552..d2175c28309b1 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -25,6 +25,8 @@ use middle::privacy; use ty::{self, TyCtxt}; use util::nodemap::FxHashSet; +use rustc_data_structures::fx::FxHashMap; + use syntax::{ast, source_map}; use syntax::attr; use syntax_pos; @@ -55,12 +57,15 @@ struct MarkSymbolVisitor<'a, 'tcx: 'a> { in_pat: bool, inherited_pub_visibility: bool, ignore_variant_stack: Vec, + // maps from tuple struct constructors to tuple struct items + struct_constructors: FxHashMap, } impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn check_def_id(&mut self, def_id: DefId) { if let Some(node_id) = self.tcx.hir().as_local_node_id(def_id) { - if should_explore(self.tcx, node_id) { + if should_explore(self.tcx, node_id) || + self.struct_constructors.contains_key(&node_id) { self.worklist.push(node_id); } self.live_symbols.insert(node_id); @@ -137,19 +142,23 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { continue } - if let Some(ref node) = self.tcx.hir().find(id) { + // in the case of tuple struct constructors we want to check the item, not the generated + // tuple struct constructor function + let id = self.struct_constructors.get(&id).cloned().unwrap_or(id); + + if let Some(node) = self.tcx.hir().find(id) { self.live_symbols.insert(id); self.visit_node(node); } } } - fn visit_node(&mut self, node: &Node<'tcx>) { + fn visit_node(&mut self, node: Node<'tcx>) { let had_repr_c = self.repr_has_repr_c; self.repr_has_repr_c = false; let had_inherited_pub_visibility = self.inherited_pub_visibility; self.inherited_pub_visibility = false; - match *node { + match node { Node::Item(item) => { match item.node { hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => { @@ -337,6 +346,8 @@ struct LifeSeeder<'k, 'tcx: 'k> { worklist: Vec, krate: &'k hir::Crate, tcx: TyCtxt<'k, 'tcx, 'tcx>, + // see `MarkSymbolVisitor::struct_constructors` + struct_constructors: FxHashMap, } impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { @@ -379,6 +390,9 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { } } } + hir::ItemKind::Struct(ref variant_data, _) => { + self.struct_constructors.insert(variant_data.id(), item.id); + } _ => () } } @@ -392,11 +406,11 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { } } -fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - access_levels: &privacy::AccessLevels, - krate: &hir::Crate) - -> Vec -{ +fn create_and_seed_worklist<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + access_levels: &privacy::AccessLevels, + krate: &hir::Crate, +) -> (Vec, FxHashMap) { let worklist = access_levels.map.iter().filter_map(|(&id, level)| { if level >= &privacy::AccessLevel::Reachable { Some(id) @@ -413,17 +427,18 @@ fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, worklist, krate, tcx, + struct_constructors: Default::default(), }; krate.visit_all_item_likes(&mut life_seeder); - return life_seeder.worklist; + (life_seeder.worklist, life_seeder.struct_constructors) } fn find_live<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, access_levels: &privacy::AccessLevels, krate: &hir::Crate) -> FxHashSet { - let worklist = create_and_seed_worklist(tcx, access_levels, krate); + let (worklist, struct_constructors) = create_and_seed_worklist(tcx, access_levels, krate); let mut symbol_visitor = MarkSymbolVisitor { worklist, tcx, @@ -433,20 +448,12 @@ fn find_live<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, in_pat: false, inherited_pub_visibility: false, ignore_variant_stack: vec![], + struct_constructors, }; symbol_visitor.mark_live_symbols(); symbol_visitor.live_symbols } -fn get_struct_ctor_id(item: &hir::Item) -> Option { - match item.node { - hir::ItemKind::Struct(ref struct_def, _) if !struct_def.is_struct() => { - Some(struct_def.id()) - } - _ => None - } -} - struct DeadVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, live_symbols: FxHashSet, @@ -464,46 +471,35 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { | hir::ItemKind::Union(..) => true, _ => false }; - let ctor_id = get_struct_ctor_id(item); - should_warn && !self.symbol_is_live(item.id, ctor_id) + should_warn && !self.symbol_is_live(item.id) } fn should_warn_about_field(&mut self, field: &hir::StructField) -> bool { let field_type = self.tcx.type_of(self.tcx.hir().local_def_id(field.id)); !field.is_positional() - && !self.symbol_is_live(field.id, None) + && !self.symbol_is_live(field.id) && !field_type.is_phantom_data() && !has_allow_dead_code_or_lang_attr(self.tcx, field.id, &field.attrs) } fn should_warn_about_variant(&mut self, variant: &hir::VariantKind) -> bool { - !self.symbol_is_live(variant.data.id(), None) + !self.symbol_is_live(variant.data.id()) && !has_allow_dead_code_or_lang_attr(self.tcx, variant.data.id(), &variant.attrs) } fn should_warn_about_foreign_item(&mut self, fi: &hir::ForeignItem) -> bool { - !self.symbol_is_live(fi.id, None) + !self.symbol_is_live(fi.id) && !has_allow_dead_code_or_lang_attr(self.tcx, fi.id, &fi.attrs) } // id := node id of an item's definition. - // ctor_id := `Some` if the item is a struct_ctor (tuple struct), - // `None` otherwise. - // If the item is a struct_ctor, then either its `id` or - // `ctor_id` (unwrapped) is in the live_symbols set. More specifically, - // DefMap maps the ExprKind::Path of a struct_ctor to the node referred by - // `ctor_id`. On the other hand, in a statement like - // `type = ;` where refers to a struct_ctor, - // DefMap maps to `id` instead. - fn symbol_is_live(&mut self, - id: ast::NodeId, - ctor_id: Option) - -> bool { - if self.live_symbols.contains(&id) - || ctor_id.map_or(false, |ctor| self.live_symbols.contains(&ctor)) - { + fn symbol_is_live( + &mut self, + id: ast::NodeId, + ) -> bool { + if self.live_symbols.contains(&id) { return true; } // If it's a type whose items are live, then it's live, too. @@ -611,7 +607,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> { fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { match impl_item.node { hir::ImplItemKind::Const(_, body_id) => { - if !self.symbol_is_live(impl_item.id, None) { + if !self.symbol_is_live(impl_item.id) { self.warn_dead_code(impl_item.id, impl_item.span, impl_item.ident.name, @@ -621,7 +617,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> { self.visit_nested_body(body_id) } hir::ImplItemKind::Method(_, body_id) => { - if !self.symbol_is_live(impl_item.id, None) { + if !self.symbol_is_live(impl_item.id) { let span = self.tcx.sess.source_map().def_span(impl_item.span); self.warn_dead_code(impl_item.id, span, impl_item.ident.name, "method", "used"); } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index f1bc37d03e5a1..02ae4737eaacb 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -489,7 +489,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } hir::ExprKind::Continue(..) | - hir::ExprKind::Lit(..) => {} + hir::ExprKind::Lit(..) | + hir::ExprKind::Err => {} hir::ExprKind::Loop(ref blk, _, _) => { self.walk_block(&blk); diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index d1d2fa298a6ca..b5937697c5183 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -525,6 +525,7 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) { hir::ExprKind::Box(..) | hir::ExprKind::Yield(..) | hir::ExprKind::Type(..) | + hir::ExprKind::Err | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => { intravisit::walk_expr(ir, expr); } @@ -1264,7 +1265,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_exprs(inputs, succ) } - hir::ExprKind::Lit(..) | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => { + hir::ExprKind::Lit(..) | hir::ExprKind::Err | + hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => { succ } @@ -1531,7 +1533,7 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) { hir::ExprKind::Block(..) | hir::ExprKind::AddrOf(..) | hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) | hir::ExprKind::Closure(..) | hir::ExprKind::Path(_) | hir::ExprKind::Yield(..) | - hir::ExprKind::Box(..) | hir::ExprKind::Type(..) => { + hir::ExprKind::Box(..) | hir::ExprKind::Type(..) | hir::ExprKind::Err => { intravisit::walk_expr(this, expr); } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index a04914e977493..bd1817fff5399 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -697,7 +697,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { hir::ExprKind::Block(..) | hir::ExprKind::Loop(..) | hir::ExprKind::Match(..) | hir::ExprKind::Lit(..) | hir::ExprKind::Break(..) | hir::ExprKind::Continue(..) | hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) | - hir::ExprKind::InlineAsm(..) | hir::ExprKind::Box(..) => { + hir::ExprKind::InlineAsm(..) | hir::ExprKind::Box(..) | hir::ExprKind::Err => { Ok(self.cat_rvalue_node(expr.hir_id, expr.span, expr_ty)) } } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index b58d80e24857d..8bb3fc1295205 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1271,8 +1271,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "set the MIR optimization level (0-3, default: 1)"), mutable_noalias: Option = (None, parse_opt_bool, [TRACKED], "emit noalias metadata for mutable references (default: yes on LLVM >= 6)"), - arg_align_attributes: bool = (false, parse_bool, [TRACKED], - "emit align metadata for reference arguments"), dump_mir: Option = (None, parse_opt_string, [UNTRACKED], "dump MIR state to file. `val` is used to select which passes and functions to dump. For example: diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index af338cd3868fa..853b54df2b92f 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -397,7 +397,7 @@ fn uncovered_tys<'tcx>(tcx: TyCtxt<'_, '_, '_>, ty: Ty<'tcx>, in_crate: InCrate) -> Vec> { if ty_is_local_constructor(ty, in_crate) { vec![] - } else if fundamental_ty(tcx, ty) { + } else if fundamental_ty(ty) { ty.walk_shallow() .flat_map(|t| uncovered_tys(tcx, t, in_crate)) .collect() @@ -415,14 +415,13 @@ fn is_possibly_remote_type(ty: Ty<'_>, _in_crate: InCrate) -> bool { fn ty_is_local(tcx: TyCtxt<'_, '_, '_>, ty: Ty<'_>, in_crate: InCrate) -> bool { ty_is_local_constructor(ty, in_crate) || - fundamental_ty(tcx, ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, in_crate)) + fundamental_ty(ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, in_crate)) } -fn fundamental_ty(tcx: TyCtxt<'_, '_, '_>, ty: Ty<'_>) -> bool { +fn fundamental_ty(ty: Ty<'_>) -> bool { match ty.sty { ty::Ref(..) => true, ty::Adt(def, _) => def.is_fundamental(), - ty::Dynamic(ref data, ..) => tcx.has_attr(data.principal().def_id(), "fundamental"), _ => false } } diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs index b8bf0fcc15307..f506c47371c92 100644 --- a/src/librustc/traits/query/dropck_outlives.rs +++ b/src/librustc/traits/query/dropck_outlives.rs @@ -55,8 +55,8 @@ impl<'cx, 'gcx, 'tcx> At<'cx, 'gcx, 'tcx> { let c_ty = self.infcx.canonicalize_query(&self.param_env.and(ty), &mut orig_values); let span = self.cause.span; debug!("c_ty = {:?}", c_ty); - match &gcx.dropck_outlives(c_ty) { - Ok(result) if result.is_proven() => { + if let Ok(result) = &gcx.dropck_outlives(c_ty) { + if result.is_proven() { if let Ok(InferOk { value, obligations }) = self.infcx.instantiate_query_response_and_region_obligations( self.cause, @@ -72,8 +72,6 @@ impl<'cx, 'gcx, 'tcx> At<'cx, 'gcx, 'tcx> { }; } } - - _ => { /* fallthrough to error-handling code below */ } } // Errors and ambiuity in dropck occur in two cases: @@ -82,10 +80,11 @@ impl<'cx, 'gcx, 'tcx> At<'cx, 'gcx, 'tcx> { // Either of these should have created an error before. tcx.sess .delay_span_bug(span, "dtorck encountered internal error"); - return InferOk { + + InferOk { value: vec![], obligations: vec![], - }; + } } } @@ -102,7 +101,7 @@ impl<'tcx> DropckOutlivesResult<'tcx> { span: Span, ty: Ty<'tcx>, ) { - for overflow_ty in self.overflows.iter().take(1) { + if let Some(overflow_ty) = self.overflows.iter().next() { let mut err = struct_span_err!( tcx.sess, span, @@ -228,7 +227,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> // (T1..Tn) and closures have same properties as T1..Tn -- // check if *any* of those are trivial. - ty::Tuple(ref tys) => tys.iter().cloned().all(|t| trivial_dropck_outlives(tcx, t)), + ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t)), ty::Closure(def_id, ref substs) => substs .upvar_tys(def_id, tcx) .all(|t| trivial_dropck_outlives(tcx, t)), diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 04d96e362a465..9883752da0b69 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1926,6 +1926,7 @@ pub mod tls { /// to `value` during the call to `f`. It is restored to its previous value after. /// This is used to set the pointer to the new ImplicitCtxt. #[cfg(parallel_queries)] + #[inline] fn set_tlv R, R>(value: usize, f: F) -> R { rayon_core::tlv::with(value, f) } @@ -1933,6 +1934,7 @@ pub mod tls { /// Gets Rayon's thread local variable which is preserved for Rayon jobs. /// This is used to get the pointer to the current ImplicitCtxt. #[cfg(parallel_queries)] + #[inline] fn get_tlv() -> usize { rayon_core::tlv::get() } @@ -1945,6 +1947,7 @@ pub mod tls { /// It is restored to its previous value after. /// This is used to set the pointer to the new ImplicitCtxt. #[cfg(not(parallel_queries))] + #[inline] fn set_tlv R, R>(value: usize, f: F) -> R { let old = get_tlv(); let _reset = OnDrop(move || TLV.with(|tlv| tlv.set(old))); @@ -2009,6 +2012,7 @@ pub mod tls { } /// Sets `context` as the new current ImplicitCtxt for the duration of the function `f` + #[inline] pub fn enter_context<'a, 'gcx: 'tcx, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'gcx, 'tcx>, f: F) -> R where F: FnOnce(&ImplicitCtxt<'a, 'gcx, 'tcx>) -> R @@ -2080,6 +2084,7 @@ pub mod tls { } /// Allows access to the current ImplicitCtxt in a closure if one is available + #[inline] pub fn with_context_opt(f: F) -> R where F: for<'a, 'gcx, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'gcx, 'tcx>>) -> R { @@ -2097,6 +2102,7 @@ pub mod tls { /// Allows access to the current ImplicitCtxt. /// Panics if there is no ImplicitCtxt available + #[inline] pub fn with_context(f: F) -> R where F: for<'a, 'gcx, 'tcx> FnOnce(&ImplicitCtxt<'a, 'gcx, 'tcx>) -> R { @@ -2108,6 +2114,7 @@ pub mod tls { /// with the same 'gcx lifetime as the TyCtxt passed in. /// This will panic if you pass it a TyCtxt which has a different global interner from /// the current ImplicitCtxt's tcx field. + #[inline] pub fn with_related_context<'a, 'gcx, 'tcx1, F, R>(tcx: TyCtxt<'a, 'gcx, 'tcx1>, f: F) -> R where F: for<'b, 'tcx2> FnOnce(&ImplicitCtxt<'b, 'gcx, 'tcx2>) -> R { @@ -2126,6 +2133,7 @@ pub mod tls { /// is given an ImplicitCtxt with the same 'tcx and 'gcx lifetimes as the TyCtxt passed in. /// This will panic if you pass it a TyCtxt which has a different global interner or /// a different local interner from the current ImplicitCtxt's tcx field. + #[inline] pub fn with_fully_related_context<'a, 'gcx, 'tcx, F, R>(tcx: TyCtxt<'a, 'gcx, 'tcx>, f: F) -> R where F: for<'b> FnOnce(&ImplicitCtxt<'b, 'gcx, 'tcx>) -> R { @@ -2143,6 +2151,7 @@ pub mod tls { /// Allows access to the TyCtxt in the current ImplicitCtxt. /// Panics if there is no ImplicitCtxt available + #[inline] pub fn with(f: F) -> R where F: for<'a, 'gcx, 'tcx> FnOnce(TyCtxt<'a, 'gcx, 'tcx>) -> R { @@ -2151,6 +2160,7 @@ pub mod tls { /// Allows access to the TyCtxt in the current ImplicitCtxt. /// The closure is passed None if there is no ImplicitCtxt available + #[inline] pub fn with_opt(f: F) -> R where F: for<'a, 'gcx, 'tcx> FnOnce(Option>) -> R { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 7daaf016c2a66..e1bf43c3782e8 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2061,9 +2061,10 @@ impl ReprOptions { } /// Returns `true` if this `#[repr()]` should inhibit struct field reordering - /// optimizations, such as with repr(C) or repr(packed(1)). + /// optimizations, such as with repr(C), repr(packed(1)), or repr(). pub fn inhibit_struct_field_reordering_opt(&self) -> bool { - !(self.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty() || (self.pack == 1) + self.flags.intersects(ReprFlags::IS_UNOPTIMISABLE) || self.pack == 1 || + self.int.is_some() } /// Returns true if this `#[repr()]` should inhibit union abi optimisations diff --git a/src/librustc/ty/query/job.rs b/src/librustc/ty/query/job.rs index 6e513d68f60f5..0faf6b5a58fa1 100644 --- a/src/librustc/ty/query/job.rs +++ b/src/librustc/ty/query/job.rs @@ -40,15 +40,6 @@ use { rustc_data_structures::stable_hasher::{StableHasherResult, StableHasher, HashStable}, }; -/// Indicates the state of a query for a given key in a query map -pub(super) enum QueryResult<'tcx> { - /// An already executing query. The query job can be used to await for its completion - Started(Lrc>), - - /// The query panicked. Queries trying to wait on this will raise a fatal error / silently panic - Poisoned, -} - /// A span and a query key #[derive(Clone, Debug)] pub struct QueryInfo<'tcx> { diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index a73b92ed713ec..1bae4d8b2de2c 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -16,12 +16,11 @@ use dep_graph::{DepNodeIndex, DepNode, DepKind, DepNodeColor}; use errors::DiagnosticBuilder; use errors::Level; use errors::Diagnostic; -use errors::FatalError; use ty::tls; use ty::{TyCtxt}; use ty::query::Query; use ty::query::config::{QueryConfig, QueryDescription}; -use ty::query::job::{QueryJob, QueryResult, QueryInfo}; +use ty::query::job::{QueryJob, QueryInfo}; use ty::item_path; use util::common::{profq_msg, ProfileQueriesMsg, QueryMsg}; @@ -35,8 +34,12 @@ use syntax_pos::Span; use syntax::source_map::DUMMY_SP; pub struct QueryCache<'tcx, D: QueryConfig<'tcx> + ?Sized> { + /// Completed queries have their result stored here pub(super) results: FxHashMap>, - pub(super) active: FxHashMap>, + + /// Queries under execution will have an entry in this map. + /// The query job inside can be used to await for completion of queries. + pub(super) active: FxHashMap>>, } pub(super) struct QueryValue { @@ -127,26 +130,24 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { return TryGetJob::JobCompleted(result); } let job = match lock.active.entry((*key).clone()) { - Entry::Occupied(entry) => { - match *entry.get() { - QueryResult::Started(ref job) => job.clone(), - QueryResult::Poisoned => FatalError.raise(), - } - } + Entry::Occupied(entry) => entry.get().clone(), Entry::Vacant(entry) => { // No job entry for this query. Return a new one to be started later return tls::with_related_context(tcx, |icx| { + // Create the `parent` variable before `info`. This allows LLVM + // to elide the move of `info` + let parent = icx.query.clone(); let info = QueryInfo { span, query: Q::query(key.clone()), }; - let job = Lrc::new(QueryJob::new(info, icx.query.clone())); + let job = Lrc::new(QueryJob::new(info, parent)); let owner = JobOwner { cache, job: job.clone(), key: (*key).clone(), }; - entry.insert(QueryResult::Started(job)); + entry.insert(job); TryGetJob::NotYetStarted(owner) }) } @@ -171,6 +172,7 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { /// Completes the query by updating the query cache with the `result`, /// signals the waiter and forgets the JobOwner, so it won't poison the query + #[inline(always)] pub(super) fn complete(self, result: &Q::Value, dep_node_index: DepNodeIndex) { // We can move out of `self` here because we `mem::forget` it below let key = unsafe { ptr::read(&self.key) }; @@ -227,11 +229,14 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { } impl<'a, 'tcx, Q: QueryDescription<'tcx>> Drop for JobOwner<'a, 'tcx, Q> { + #[inline(never)] + #[cold] fn drop(&mut self) { - // Poison the query so jobs waiting on it panic - self.cache.borrow_mut().active.insert(self.key.clone(), QueryResult::Poisoned); - // Also signal the completion of the job, so waiters - // will continue execution + // This job failed to execute due to a panic. + // Remove it from the list of active queries + self.cache.borrow_mut().active.remove(&self.key); + // Signal that the job not longer executes, so the waiters will continue execution. + // The waiters will try to execute the query which may result in them panicking too. self.job.signal_complete(); } } @@ -706,8 +711,6 @@ macro_rules! define_queries_inner { [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)*) => { use std::mem; - #[cfg(parallel_queries)] - use ty::query::job::QueryResult; use rustc_data_structures::sync::Lock; use { rustc_data_structures::stable_hasher::HashStable, @@ -744,13 +747,7 @@ macro_rules! define_queries_inner { // deadlock handler, and this shouldn't be locked $( jobs.extend( - self.$name.try_lock().unwrap().active.values().filter_map(|v| - if let QueryResult::Started(ref job) = *v { - Some(job.clone()) - } else { - None - } - ) + self.$name.try_lock().unwrap().active.values().cloned() ); )* diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index b8954dee794f7..71b75525a5aa1 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -489,12 +489,6 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { attrs.pointee_size = pointee.size; attrs.pointee_align = Some(pointee.align); - // HACK(eddyb) LLVM inserts `llvm.assume` calls when inlining functions - // with align attributes, and those calls later block optimizations. - if !is_return && !cx.tcx.sess.opts.debugging_opts.arg_align_attributes { - attrs.pointee_align = None; - } - // `Box` pointer parameters never alias because ownership is transferred // `&mut` pointer parameters never alias other parameters, // or mutable global data diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index 4732db88ec1cb..5c59439fdfb6f 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -1601,15 +1601,12 @@ extern "C" { -> &'a Value; pub fn LLVMRustDIBuilderCreateOpDeref() -> i64; pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> i64; -} -#[allow(improper_ctypes)] // FIXME(#52456) needed for RustString. -extern "C" { + #[allow(improper_ctypes)] pub fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString); + #[allow(improper_ctypes)] pub fn LLVMRustWriteValueToString(value_ref: &Value, s: &RustString); -} -extern "C" { pub fn LLVMIsAConstantInt(value_ref: &Value) -> Option<&Value>; pub fn LLVMIsAConstantFP(value_ref: &Value) -> Option<&Value>; @@ -1687,21 +1684,15 @@ extern "C" { pub fn LLVMRustDestroyArchive(AR: &'static mut Archive); pub fn LLVMRustGetSectionName(SI: &SectionIterator, data: &mut *const c_char) -> size_t; -} -#[allow(improper_ctypes)] // FIXME(#52456) needed for RustString. -extern "C" { + #[allow(improper_ctypes)] pub fn LLVMRustWriteTwineToString(T: &Twine, s: &RustString); -} -extern "C" { pub fn LLVMContextSetDiagnosticHandler(C: &Context, Handler: DiagnosticHandler, DiagnosticContext: *mut c_void); -} -#[allow(improper_ctypes)] // FIXME(#52456) needed for RustString. -extern "C" { + #[allow(improper_ctypes)] pub fn LLVMRustUnpackOptimizationDiagnostic(DI: &'a DiagnosticInfo, pass_name_out: &RustString, function_out: &mut Option<&'a Value>, @@ -1709,34 +1700,23 @@ extern "C" { loc_column_out: &mut c_uint, loc_filename_out: &RustString, message_out: &RustString); -} -extern "C" { pub fn LLVMRustUnpackInlineAsmDiagnostic(DI: &'a DiagnosticInfo, cookie_out: &mut c_uint, message_out: &mut Option<&'a Twine>, instruction_out: &mut Option<&'a Value>); -} -#[allow(improper_ctypes)] // FIXME(#52456) needed for RustString. -extern "C" { + #[allow(improper_ctypes)] pub fn LLVMRustWriteDiagnosticInfoToString(DI: &DiagnosticInfo, s: &RustString); -} - -extern "C" { pub fn LLVMRustGetDiagInfoKind(DI: &DiagnosticInfo) -> DiagnosticKind; pub fn LLVMRustSetInlineAsmDiagnosticHandler(C: &Context, H: InlineAsmDiagHandler, CX: *mut c_void); -} -#[allow(improper_ctypes)] // FIXME(#52456) needed for RustString. -extern "C" { + #[allow(improper_ctypes)] pub fn LLVMRustWriteSMDiagnosticToString(d: &SMDiagnostic, s: &RustString); -} -extern "C" { pub fn LLVMRustWriteArchive(Dst: *const c_char, NumMembers: size_t, Members: *const &RustArchiveMember, diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs index 82b1d7e8b40e4..090ff83ecc1a8 100644 --- a/src/librustc_codegen_llvm/llvm_util.rs +++ b/src/librustc_codegen_llvm/llvm_util.rs @@ -74,6 +74,10 @@ unsafe fn configure_llvm(sess: &Session) { add("-mergefunc-use-aliases"); } + // HACK(eddyb) LLVM inserts `llvm.assume` calls to preserve align attributes + // during inlining. Unfortunately these may block other optimizations. + add("-preserve-alignment-assumptions-during-inlining=false"); + for arg in &sess.opts.cg.llvm_args { add(&(*arg)); } diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index 90aa9f6cbc763..5fad4a24b262e 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -335,11 +335,20 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> { bx: &mut Bx, llindex: V ) -> Self { + // Statically compute the offset if we can, otherwise just use the element size, + // as this will yield the lowest alignment. + let layout = self.layout.field(bx, 0); + let offset = if bx.is_const_integral(llindex) { + layout.size.checked_mul(bx.const_to_uint(llindex), bx).unwrap_or(layout.size) + } else { + layout.size + }; + PlaceRef { llval: bx.inbounds_gep(self.llval, &[bx.cx().const_usize(0), llindex]), llextra: None, - layout: self.layout.field(bx.cx(), 0), - align: self.align + layout, + align: self.align.restrict_for_offset(offset), } } diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index c932ffd1c1bda..052342dd7597b 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -131,8 +131,9 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let keep_going = header_bx.icmp(IntPredicate::IntNE, current, end); header_bx.cond_br(keep_going, body_bx.llbb(), next_bx.llbb()); + let align = dest.align.restrict_for_offset(dest.layout.field(bx.cx(), 0).size); cg_elem.val.store(&mut body_bx, - PlaceRef::new_sized(current, cg_elem.layout, dest.align)); + PlaceRef::new_sized(current, cg_elem.layout, align)); let next = body_bx.inbounds_gep(current, &[bx.cx().const_usize(1)]); body_bx.br(header_bx.llbb()); diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index bc2b8f1d6523e..066e1739841d6 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -28,7 +28,6 @@ #![feature(optin_builtin_traits)] #![feature(nll)] #![feature(allow_internal_unstable)] -#![feature(vec_resize_with)] #![feature(hash_raw_entry)] #![feature(stmt_expr_attributes)] #![feature(core_intrinsics)] @@ -113,12 +112,14 @@ pub struct OnDrop(pub F); impl OnDrop { /// Forgets the function which prevents it from running. /// Ensure that the function owns no memory, otherwise it will be leaked. + #[inline] pub fn disable(self) { std::mem::forget(self); } } impl Drop for OnDrop { + #[inline] fn drop(&mut self) { (self.0)(); } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 55e052882ea5b..43fc91ea4827f 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -997,7 +997,6 @@ where }; let mut ecx = ExtCtxt::new(&sess.parse_sess, cfg, &mut resolver); - let err_count = ecx.parse_sess.span_diagnostic.err_count(); // Expand macros now! let krate = time(sess, "expand crate", || { @@ -1023,9 +1022,6 @@ where let msg = "missing fragment specifier"; sess.buffer_lint(lint, ast::CRATE_NODE_ID, span, msg); } - if ecx.parse_sess.span_diagnostic.err_count() - ecx.resolve_err_count > err_count { - ecx.parse_sess.span_diagnostic.abort_if_errors(); - } if cfg!(windows) { env::set_var("PATH", &old_path); } @@ -1129,12 +1125,6 @@ where }) })?; - // Unresolved macros might be due to mistyped `#[macro_use]`, - // so abort after checking for unknown attributes. (#49074) - if resolver.found_unresolved_macro { - sess.diagnostic().abort_if_errors(); - } - // Lower ast -> hir. // First, we need to collect the dep_graph. let dep_graph = match future_dep_graph { diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index bc991016bbee5..551244f7fe227 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -751,7 +751,6 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> { fn fold_block(&mut self, b: P) -> P { fn stmt_to_block(rules: ast::BlockCheckMode, - recovered: bool, s: Option, sess: &Session) -> ast::Block { ast::Block { @@ -759,7 +758,6 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> { rules, id: sess.next_node_id(), span: syntax_pos::DUMMY_SP, - recovered, } } @@ -778,7 +776,7 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> { } } - let empty_block = stmt_to_block(BlockCheckMode::Default, false, None, self.sess); + let empty_block = stmt_to_block(BlockCheckMode::Default, None, self.sess); let loop_expr = P(ast::Expr { node: ast::ExprKind::Loop(P(empty_block), None), id: self.sess.next_node_id(), @@ -819,7 +817,7 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> { old_blocks.push(new_block); } - stmt_to_block(b.rules, b.recovered, Some(loop_stmt), self.sess) + stmt_to_block(b.rules, Some(loop_stmt), self.sess) } else { //push `loop {}` onto the end of our fresh block and yield that new_block.stmts.push(loop_stmt); diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 598c2f810beb7..9826b4dbe5f86 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -191,38 +191,36 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ); } - if let Some(ty) = self.retrieve_type_for_place(used_place) { - let needs_note = match ty.sty { - ty::Closure(id, _) => { - let tables = self.infcx.tcx.typeck_tables_of(id); - let node_id = self.infcx.tcx.hir().as_local_node_id(id).unwrap(); - let hir_id = self.infcx.tcx.hir().node_to_hir_id(node_id); - - tables.closure_kind_origins().get(hir_id).is_none() - } - _ => true, - }; + let ty = used_place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let needs_note = match ty.sty { + ty::Closure(id, _) => { + let tables = self.infcx.tcx.typeck_tables_of(id); + let node_id = self.infcx.tcx.hir().as_local_node_id(id).unwrap(); + let hir_id = self.infcx.tcx.hir().node_to_hir_id(node_id); - if needs_note { - let mpi = self.move_data.moves[move_out_indices[0]].path; - let place = &self.move_data.move_paths[mpi].place; - - if let Some(ty) = self.retrieve_type_for_place(place) { - let note_msg = match self.describe_place_with_options( - place, - IncludingDowncast(true), - ) { - Some(name) => format!("`{}`", name), - None => "value".to_owned(), - }; - - err.note(&format!( - "move occurs because {} has type `{}`, \ - which does not implement the `Copy` trait", - note_msg, ty - )); - } + tables.closure_kind_origins().get(hir_id).is_none() } + _ => true, + }; + + if needs_note { + let mpi = self.move_data.moves[move_out_indices[0]].path; + let place = &self.move_data.move_paths[mpi].place; + + let ty = place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let note_msg = match self.describe_place_with_options( + place, + IncludingDowncast(true), + ) { + Some(name) => format!("`{}`", name), + None => "value".to_owned(), + }; + + err.note(&format!( + "move occurs because {} has type `{}`, \ + which does not implement the `Copy` trait", + note_msg, ty + )); } if let Some((_, mut old_err)) = self.move_error_reported @@ -1568,7 +1566,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { )?; buf.push_str("["); if self.append_local_to_string(index, buf).is_err() { - buf.push_str(".."); + buf.push_str("_"); } buf.push_str("]"); } @@ -1673,22 +1671,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } - /// Retrieve type of a place for the current MIR representation - fn retrieve_type_for_place(&self, place: &Place<'tcx>) -> Option { - match place { - Place::Local(local) => { - let local = &self.mir.local_decls[*local]; - Some(local.ty) - } - Place::Promoted(ref prom) => Some(prom.1), - Place::Static(ref st) => Some(st.ty), - Place::Projection(ref proj) => match proj.elem { - ProjectionElem::Field(_, ty) => Some(ty), - _ => None, - }, - } - } - /// Check if a place is a thread-local static. pub fn is_place_thread_local(&self, place: &Place<'tcx>) -> bool { if let Place::Static(statik) = place { diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 146bf53830656..64defaf78a487 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -126,18 +126,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::LogicalOp { op, lhs, rhs } => { // And: // - // [block: If(lhs)] -true-> [else_block: If(rhs)] -true-> [true_block] - // | | (false) - // +----------false-----------+------------------> [false_block] + // [block: If(lhs)] -true-> [else_block: dest = (rhs)] + // | (false) + // [shortcurcuit_block: dest = false] // // Or: // - // [block: If(lhs)] -false-> [else_block: If(rhs)] -true-> [true_block] - // | (true) | (false) - // [true_block] [false_block] + // [block: If(lhs)] -false-> [else_block: dest = (rhs)] + // | (true) + // [shortcurcuit_block: dest = true] - let (true_block, false_block, mut else_block, join_block) = ( - this.cfg.start_new_block(), + let (shortcircuit_block, mut else_block, join_block) = ( this.cfg.start_new_block(), this.cfg.start_new_block(), this.cfg.start_new_block(), @@ -145,47 +144,41 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let lhs = unpack!(block = this.as_local_operand(block, lhs)); let blocks = match op { - LogicalOp::And => (else_block, false_block), - LogicalOp::Or => (true_block, else_block), + LogicalOp::And => (else_block, shortcircuit_block), + LogicalOp::Or => (shortcircuit_block, else_block), }; let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1); this.cfg.terminate(block, source_info, term); - let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs)); - let term = TerminatorKind::if_(this.hir.tcx(), rhs, true_block, false_block); - this.cfg.terminate(else_block, source_info, term); - this.cfg.push_assign_constant( - true_block, + shortcircuit_block, source_info, destination, Constant { span: expr_span, ty: this.hir.bool_ty(), user_ty: None, - literal: this.hir.true_literal(), + literal: match op { + LogicalOp::And => this.hir.false_literal(), + LogicalOp::Or => this.hir.true_literal(), + }, }, ); - - this.cfg.push_assign_constant( - false_block, + this.cfg.terminate( + shortcircuit_block, source_info, - destination, - Constant { - span: expr_span, - ty: this.hir.bool_ty(), - user_ty: None, - literal: this.hir.false_literal(), - }, + TerminatorKind::Goto { target: join_block }, ); - this.cfg.terminate( - true_block, + let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs)); + this.cfg.push_assign( + else_block, source_info, - TerminatorKind::Goto { target: join_block }, + destination, + Rvalue::Use(rhs), ); this.cfg.terminate( - false_block, + else_block, source_info, TerminatorKind::Goto { target: join_block }, ); diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index c8dec6d0b9764..69706924dc966 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -347,7 +347,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { span: test.span, ty: mty, - // FIXME(#47184): This constant comes from user + // FIXME(#54571): This constant comes from user // input (a constant in a pattern). Are // there forms where users can add type // annotations here? For example, an diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 248c5d2db4917..4c183d59a637c 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -187,7 +187,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( } let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; assert!(!layout.is_unsized()); - let ret = ecx.allocate(layout, MemoryKind::Stack)?; + let ret = ecx.allocate(layout, MemoryKind::Stack); let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id())); let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); @@ -490,8 +490,8 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, ptr: Pointer, _kind: MemoryKind, - ) -> EvalResult<'tcx, Pointer> { - Ok(ptr) + ) -> Pointer { + ptr } #[inline(always)] @@ -692,12 +692,16 @@ pub fn const_eval_raw_provider<'a, 'tcx>( let err = error_to_const_error(&ecx, error); // errors in statics are always emitted as fatal errors if tcx.is_static(def_id).is_some() { - let err = err.report_as_error(ecx.tcx, "could not evaluate static initializer"); - // check that a static never produces `TooGeneric` + let reported_err = err.report_as_error(ecx.tcx, + "could not evaluate static initializer"); + // Ensure that if the above error was either `TooGeneric` or `Reported` + // an error must be reported. if tcx.sess.err_count() == 0 { - span_bug!(ecx.tcx.span, "static eval failure didn't emit an error: {:#?}", err); + tcx.sess.delay_span_bug(err.span, + &format!("static eval failure did not emit an error: {:#?}", + reported_err)); } - err + reported_err } else if def_id.is_local() { // constant defined in this crate, we can figure out a lint level! match tcx.describe_def(def_id) { diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index f93dbce97b54a..5a8ffb8059840 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -790,6 +790,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprKind::Tup(ref fields) => ExprKind::Tuple { fields: fields.to_ref() }, hir::ExprKind::Yield(ref v) => ExprKind::Yield { value: v.to_ref() }, + hir::ExprKind::Err => unreachable!(), }; Expr { diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index f78a70f6a25f4..0324bfb892e45 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -83,7 +83,7 @@ impl<'tcx> PatternTypeProjections<'tcx> { } pub(crate) fn ref_binding(&self) -> Self { - // FIXME(#47184): ignore for now + // FIXME(#55401): ignore for now PatternTypeProjections { contents: vec![] } } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index d36d530fe78b2..8ae0345e07a34 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -422,7 +422,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc return_to_block: StackPopCleanup, ) -> EvalResult<'tcx> { if self.stack.len() > 1 { // FIXME should be "> 0", printing topmost frame crashes rustc... - debug!("PAUSING({}) {}", self.cur_frame(), self.frame().instance); + info!("PAUSING({}) {}", self.cur_frame(), self.frame().instance); } ::log_settings::settings().indentation += 1; @@ -491,7 +491,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc } if self.stack.len() > 1 { // FIXME no check should be needed, but some instances ICE - debug!("ENTERING({}) {}", self.cur_frame(), self.frame().instance); + info!("ENTERING({}) {}", self.cur_frame(), self.frame().instance); } if self.stack.len() > self.tcx.sess.const_eval_stack_frame_limit { @@ -503,7 +503,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> { if self.stack.len() > 1 { // FIXME no check should be needed, but some instances ICE - debug!("LEAVING({}) {}", self.cur_frame(), self.frame().instance); + info!("LEAVING({}) {}", self.cur_frame(), self.frame().instance); } ::log_settings::settings().indentation -= 1; let frame = self.stack.pop().expect( @@ -557,7 +557,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc } if self.stack.len() > 1 { // FIXME should be "> 0", printing topmost frame crashes rustc... - debug!("CONTINUING({}) {}", self.cur_frame(), self.frame().instance); + info!("CONTINUING({}) {}", self.cur_frame(), self.frame().instance); } Ok(()) diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index e6f3b664c007b..144d79f236ce8 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -185,7 +185,7 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized { ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, ptr: Pointer, kind: MemoryKind, - ) -> EvalResult<'tcx, Pointer>; + ) -> Pointer; /// Executed when evaluating the `*` operator: Following a reference. /// This has the chance to adjust the tag. It should not change anything else! diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 420fe26426321..f1c7b2be6fb86 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -131,10 +131,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { &mut self, alloc: Allocation, kind: MemoryKind, - ) -> EvalResult<'tcx, AllocId> { + ) -> AllocId { let id = self.tcx.alloc_map.lock().reserve(); self.alloc_map.insert(id, (kind, alloc)); - Ok(id) + id } pub fn allocate( @@ -142,9 +142,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { size: Size, align: Align, kind: MemoryKind, - ) -> EvalResult<'tcx, Pointer> { + ) -> Pointer { let extra = AllocationExtra::memory_allocated(size, &self.extra); - Ok(Pointer::from(self.allocate_with(Allocation::undef(size, align, extra), kind)?)) + Pointer::from(self.allocate_with(Allocation::undef(size, align, extra), kind)) } pub fn reallocate( @@ -162,7 +162,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { // For simplicities' sake, we implement reallocate as "alloc, copy, dealloc". // This happens so rarely, the perf advantage is outweighed by the maintenance cost. - let new_ptr = self.allocate(new_size, new_align, kind)?; + let new_ptr = self.allocate(new_size, new_align, kind); self.copy( ptr.into(), old_align, @@ -708,8 +708,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { relocations .iter() .map(|&(offset, reloc)| { - (offset + dest.offset - src.offset + (i * size * relocations.len() as u64), - reloc) + // compute offset for current repetition + let dest_offset = dest.offset + (i * size); + ( + // shift offsets from source allocation to destination allocation + offset + dest_offset - src.offset, + reloc, + ) }) ); } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 83ceadada65ce..7143d66ad9246 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -382,7 +382,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> _ => { trace!("Forcing allocation for local of type {:?}", layout.ty); Operand::Indirect( - *self.allocate(layout, MemoryKind::Stack)? + *self.allocate(layout, MemoryKind::Stack) ) } }) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index bae670bf2b4b3..e316b54f8ca7d 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -911,7 +911,7 @@ where // that might e.g., be an inner field of a struct with `Scalar` layout, // that has different alignment than the outer field. let local_layout = self.layout_of_local(&self.stack[frame], local)?; - let ptr = self.allocate(local_layout, MemoryKind::Stack)?; + let ptr = self.allocate(local_layout, MemoryKind::Stack); // We don't have to validate as we can assume the local // was already valid for its type. self.write_immediate_to_mplace_no_validate(value, ptr)?; @@ -933,15 +933,15 @@ where &mut self, layout: TyLayout<'tcx>, kind: MemoryKind, - ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + ) -> MPlaceTy<'tcx, M::PointerTag> { if layout.is_unsized() { assert!(self.tcx.features().unsized_locals, "cannot alloc memory for unsized type"); // FIXME: What should we do here? We should definitely also tag! - Ok(MPlaceTy::dangling(layout, self)) + MPlaceTy::dangling(layout, self) } else { - let ptr = self.memory.allocate(layout.size, layout.align.abi, kind)?; - let ptr = M::tag_new_allocation(self, ptr, kind)?; - Ok(MPlaceTy::from_aligned_ptr(ptr, layout)) + let ptr = self.memory.allocate(layout.size, layout.align.abi, kind); + let ptr = M::tag_new_allocation(self, ptr, kind); + MPlaceTy::from_aligned_ptr(ptr, layout) } } diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 596dba5760646..308abdbbb90f0 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -81,7 +81,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> } fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<'tcx> { - debug!("{:?}", stmt); + info!("{:?}", stmt); use rustc::mir::StatementKind::*; @@ -289,7 +289,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> } fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<'tcx> { - debug!("{:?}", terminator.kind); + info!("{:?}", terminator.kind); self.tcx.span = terminator.source_info.span; self.memory.tcx.span = terminator.source_info.span; @@ -299,7 +299,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> if !self.stack.is_empty() { // This should change *something* debug_assert!(self.cur_frame() != old_stack || self.frame().block != old_bb); - debug!("// {:?}", self.frame().block); + info!("// {:?}", self.frame().block); } Ok(()) } diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index bda585b8eda34..22936a9b0a0cf 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -54,7 +54,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> ptr_size * (3 + methods.len() as u64), ptr_align, MemoryKind::Vtable, - )?.with_default_tag(); + ).with_default_tag(); let tcx = &*self.tcx; let drop = ::monomorphize::resolve_drop_in_place(*tcx, ty); diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index acae03f7f94f5..cfa899eb5a62a 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -346,7 +346,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { Rvalue::Cast(kind, ref operand, _) => { let (op, span) = self.eval_operand(operand, source_info)?; self.use_ecx(source_info, |this| { - let dest = this.ecx.allocate(place_layout, MemoryKind::Stack)?; + let dest = this.ecx.allocate(place_layout, MemoryKind::Stack); this.ecx.cast(op, kind, dest.into())?; Ok((dest.into(), span)) }) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index b854f029e5106..646a671d4a2ce 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -518,7 +518,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { // Only allow statics (not consts) to refer to other statics. if self.mode == Mode::Static || self.mode == Mode::StaticMut { - if context.is_mutating_use() { + if self.mode == Mode::Static && context.is_mutating_use() { // this is not strictly necessary as miri will also bail out // For interior mutability we can't really catch this statically as that // goes through raw pointers and intermediate temporaries, so miri has diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 9a35721e3e1c4..259888412a98d 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -288,25 +288,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { visit::walk_ty(self, ty) } - fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) { - // Check if the path in this `use` is not generic, such as `use foo::bar;` While this - // can't happen normally thanks to the parser, a generic might sneak in if the `use` is - // built using a macro. - // - // macro_use foo { - // ($p:path) => { use $p; } - // } - // foo!(bar::baz); - use_tree.prefix.segments.iter().find(|segment| { - segment.args.is_some() - }).map(|segment| { - self.err_handler().span_err(segment.args.as_ref().unwrap().span(), - "generic arguments in import path"); - }); - - visit::walk_use_tree(self, use_tree, id); - } - fn visit_label(&mut self, label: &'a Label) { self.check_label(label.ident); visit::walk_label(self, label); @@ -443,17 +424,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { visit::walk_foreign_item(self, fi) } - fn visit_vis(&mut self, vis: &'a Visibility) { - if let VisibilityKind::Restricted { ref path, .. } = vis.node { - path.segments.iter().find(|segment| segment.args.is_some()).map(|segment| { - self.err_handler().span_err(segment.args.as_ref().unwrap().span(), - "generic arguments in visibility path"); - }); - } - - visit::walk_vis(self, vis) - } - fn visit_generics(&mut self, generics: &'a Generics) { let mut seen_non_lifetime_param = false; let mut seen_default = None; diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index bfe8b677a5e80..2f0fbe477754f 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -459,7 +459,8 @@ fn check_expr_kind<'a, 'tcx>( struct_result } - hir::ExprKind::Lit(_) => Promotable, + hir::ExprKind::Lit(_) | + hir::ExprKind::Err => Promotable, hir::ExprKind::AddrOf(_, ref expr) | hir::ExprKind::Repeat(ref expr, _) => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 794e5741d62ca..c1d4ea281809b 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1584,7 +1584,6 @@ pub struct Resolver<'a> { macro_map: FxHashMap>, macro_defs: FxHashMap, local_macro_def_scopes: FxHashMap>, - pub found_unresolved_macro: bool, /// List of crate local macros that we need to warn about as being unused. /// Right now this only includes macro_rules! macros, and macros 2.0. @@ -1919,7 +1918,6 @@ impl<'a> Resolver<'a> { name_already_seen: FxHashMap::default(), potentially_unused_imports: Vec::new(), struct_constructors: Default::default(), - found_unresolved_macro: false, unused_macros: FxHashSet::default(), current_type_ascription: Vec::new(), injected_crate: None, @@ -2032,8 +2030,10 @@ impl<'a> Resolver<'a> { record_used_id: Option, path_span: Span) -> Option> { - let record_used = record_used_id.is_some(); assert!(ns == TypeNS || ns == ValueNS); + if ident.name == keywords::Invalid.name() { + return Some(LexicalScopeBinding::Def(Def::Err)); + } if ns == TypeNS { ident.span = if ident.name == keywords::SelfUpper.name() { // FIXME(jseyfried) improve `Self` hygiene @@ -2046,6 +2046,7 @@ impl<'a> Resolver<'a> { } // Walk backwards up the ribs in scope. + let record_used = record_used_id.is_some(); let mut module = self.graph_root; for i in (0 .. self.ribs[ns].len()).rev() { if let Some(def) = self.ribs[ns][i].bindings.get(&ident).cloned() { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 81633c8f57f9e..64a5f1e3b6fb4 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -192,7 +192,14 @@ impl<'a> base::Resolver for Resolver<'a> { }; let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope); - let (def, ext) = self.resolve_macro_to_def(path, kind, &parent_scope, true, force)?; + let (def, ext) = match self.resolve_macro_to_def(path, kind, &parent_scope, true, force) { + Ok((def, ext)) => (def, ext), + Err(Determinacy::Determined) if kind == MacroKind::Attr => { + // Replace unresolved attributes with used inert attributes for better recovery. + return Ok(Some(Lrc::new(SyntaxExtension::NonMacroAttr { mark_used: true }))); + } + Err(determinacy) => return Err(determinacy), + }; if let Def::Macro(def_id, _) = def { if after_derive { @@ -347,7 +354,6 @@ impl<'a> Resolver<'a> { } PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined), PathResult::NonModule(..) | PathResult::Indeterminate | PathResult::Failed(..) => { - self.found_unresolved_macro = true; Err(Determinacy::Determined) } PathResult::Module(..) => unreachable!(), @@ -363,10 +369,8 @@ impl<'a> Resolver<'a> { let binding = self.early_resolve_ident_in_lexical_scope( path[0].ident, ScopeSet::Macro(kind), parent_scope, false, force, path_span ); - match binding { - Ok(..) => {} - Err(Determinacy::Determined) => self.found_unresolved_macro = true, - Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined), + if let Err(Determinacy::Undetermined) = binding { + return Err(Determinacy::Undetermined); } if trace { @@ -868,14 +872,23 @@ impl<'a> Resolver<'a> { pub fn finalize_current_module_macro_resolutions(&mut self) { let module = self.current_module; - let check_consistency = |this: &mut Self, path: &[Segment], span, - kind: MacroKind, initial_def, def| { + let check_consistency = |this: &mut Self, path: &[Segment], span, kind: MacroKind, + initial_def: Option, def: Def| { if let Some(initial_def) = initial_def { if def != initial_def && def != Def::Err && this.ambiguity_errors.is_empty() { // Make sure compilation does not succeed if preferred macro resolution // has changed after the macro had been expanded. In theory all such // situations should be reported as ambiguity errors, so this is a bug. - span_bug!(span, "inconsistent resolution for a macro"); + if initial_def == Def::NonMacroAttr(NonMacroAttrKind::Custom) { + // Yeah, legacy custom attributes are implemented using forced resolution + // (which is a best effort error recovery tool, basically), so we can't + // promise their resolution won't change later. + let msg = format!("inconsistent resolution for a macro: first {}, then {}", + initial_def.kind_name(), def.kind_name()); + this.session.span_err(span, &msg); + } else { + span_bug!(span, "inconsistent resolution for a macro"); + } } } else { // It's possible that the macro was unresolved (indeterminate) and silently diff --git a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs b/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs index 5b6d8abc5ef3e..6a6aab2bea366 100644 --- a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs +++ b/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs @@ -10,28 +10,29 @@ use std::iter; -use super::{LinkerFlavor, Target, TargetOptions, PanicStrategy}; +use super::{LinkerFlavor, PanicStrategy, Target, TargetOptions}; pub fn target() -> Result { const PRE_LINK_ARGS: &[&str] = &[ "-Wl,--as-needed", "-Wl,-z,noexecstack", "-m64", - "-fuse-ld=gold", - "-nostdlib", - "-shared", - "-Wl,-e,sgx_entry", - "-Wl,-Bstatic", - "-Wl,--gc-sections", - "-Wl,-z,text", - "-Wl,-z,norelro", - "-Wl,--rosegment", - "-Wl,--no-undefined", - "-Wl,--error-unresolved-symbols", - "-Wl,--no-undefined-version", - "-Wl,-Bsymbolic", - "-Wl,--export-dynamic", + "-fuse-ld=gold", + "-nostdlib", + "-shared", + "-Wl,-e,sgx_entry", + "-Wl,-Bstatic", + "-Wl,--gc-sections", + "-Wl,-z,text", + "-Wl,-z,norelro", + "-Wl,--rosegment", + "-Wl,--no-undefined", + "-Wl,--error-unresolved-symbols", + "-Wl,--no-undefined-version", + "-Wl,-Bsymbolic", + "-Wl,--export-dynamic", ]; + const EXPORT_SYMBOLS: &[&str] = &[ "sgx_entry", "HEAP_BASE", @@ -41,19 +42,26 @@ pub fn target() -> Result { "ENCLAVE_SIZE", "CFGDATA_BASE", "DEBUG", + "EH_FRM_HDR_BASE", + "EH_FRM_HDR_SIZE", + "TEXT_BASE", + "TEXT_SIZE", ]; let opts = TargetOptions { dynamic_linking: false, executables: true, linker_is_gnu: true, max_atomic_width: Some(64), - panic_strategy: PanicStrategy::Abort, + panic_strategy: PanicStrategy::Unwind, cpu: "x86-64".into(), features: "+rdrnd,+rdseed".into(), position_independent_executables: true, - pre_link_args: iter::once( - (LinkerFlavor::Gcc, PRE_LINK_ARGS.iter().cloned().map(String::from).collect()) - ).collect(), + pre_link_args: iter::once(( + LinkerFlavor::Gcc, + PRE_LINK_ARGS.iter().cloned().map(String::from).collect(), + )) + .collect(), + post_link_objects: vec!["libunwind.a".into()], override_export_symbols: Some(EXPORT_SYMBOLS.iter().cloned().map(String::from).collect()), ..Default::default() }; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d45f8fd6de8d9..22efa2381b145 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4498,6 +4498,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } tcx.mk_unit() } + hir::ExprKind::Err => { + tcx.types.err + } } } @@ -4754,12 +4757,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // // #41425 -- label the implicit `()` as being the // "found type" here, rather than the "expected type". - // - // #44579 -- if the block was recovered during parsing, - // the type would be nonsensical and it is not worth it - // to perform the type check, so we avoid generating the - // diagnostic output. - if !self.diverges.get().always() && !blk.recovered { + if !self.diverges.get().always() { coerce.coerce_forced_unit(self, &self.misc(blk.span), &mut |err| { if let Some(expected_ty) = expected.only_has_type(self) { self.consider_hint_about_removing_semicolon(blk, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index a4eafee36d1a1..5e70c7be1fef1 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2220,7 +2220,6 @@ fn from_target_feature( feature_gate::GateIssue::Language, &format!("the target feature `{}` is currently unstable", feature), ); - return None; } Some(Symbol::intern(feature)) })); diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 8bac007b748ac..bc6447d74f1b2 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -9,6 +9,6 @@ path = "lib.rs" [dependencies] pulldown-cmark = { version = "0.1.2", default-features = false } -minifier = "0.0.20" +minifier = "0.0.21" tempfile = "3" parking_lot = "0.6.4" diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 847786d123efc..e70284e4948ec 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -10,7 +10,8 @@ //! Representation of a `#[doc(cfg(...))]` attribute. -// FIXME: Once RFC #1868 is implemented, switch to use those structures instead. +// FIXME: Once the portability lint RFC is implemented (see tracking issue #41619), +// switch to use those structures instead. use std::mem; use std::fmt::{self, Write}; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f42b19ed13914..01ead05999b21 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -478,7 +478,7 @@ impl Item { classes.push("unstable"); } - if !s.deprecated_since.is_empty() { + if s.deprecation.is_some() { classes.push("deprecated"); } @@ -503,6 +503,15 @@ impl Item { pub fn type_(&self) -> ItemType { ItemType::from(self) } + + /// Returns the info in the item's `#[deprecated]` or `#[rustc_deprecated]` attributes. + /// + /// If the item is not deprecated, returns `None`. + pub fn deprecation(&self) -> Option<&Deprecation> { + self.deprecation + .as_ref() + .or_else(|| self.stability.as_ref().and_then(|s| s.deprecation.as_ref())) + } } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] @@ -3844,40 +3853,37 @@ impl Clean for doctree::ProcMacro { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Stability { pub level: stability::StabilityLevel, - pub feature: String, + pub feature: Option, pub since: String, - pub deprecated_since: String, - pub deprecated_reason: String, - pub unstable_reason: String, - pub issue: Option + pub deprecation: Option, + pub unstable_reason: Option, + pub issue: Option, } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Deprecation { - pub since: String, - pub note: String, + pub since: Option, + pub note: Option, } impl Clean for attr::Stability { fn clean(&self, _: &DocContext) -> Stability { Stability { level: stability::StabilityLevel::from_attr_level(&self.level), - feature: self.feature.to_string(), + feature: Some(self.feature.to_string()).filter(|f| !f.is_empty()), since: match self.level { attr::Stable {ref since} => since.to_string(), _ => String::new(), }, - deprecated_since: match self.rustc_depr { - Some(attr::RustcDeprecation {ref since, ..}) => since.to_string(), - _=> String::new(), - }, - deprecated_reason: match self.rustc_depr { - Some(ref depr) => depr.reason.to_string(), - _ => String::new(), - }, + deprecation: self.rustc_depr.as_ref().map(|d| { + Deprecation { + note: Some(d.reason.to_string()).filter(|r| !r.is_empty()), + since: Some(d.since.to_string()).filter(|d| !d.is_empty()), + } + }), unstable_reason: match self.level { - attr::Unstable { reason: Some(ref reason), .. } => reason.to_string(), - _ => String::new(), + attr::Unstable { reason: Some(ref reason), .. } => Some(reason.to_string()), + _ => None, }, issue: match self.level { attr::Unstable {issue, ..} => Some(issue), @@ -3896,8 +3902,8 @@ impl<'a> Clean for &'a attr::Stability { impl Clean for attr::Deprecation { fn clean(&self, _: &DocContext) -> Deprecation { Deprecation { - since: self.since.as_ref().map_or(String::new(), |s| s.to_string()), - note: self.note.as_ref().map_or(String::new(), |s| s.to_string()), + since: self.since.map(|s| s.to_string()).filter(|s| !s.is_empty()), + note: self.note.map(|n| n.to_string()).filter(|n| !n.is_empty()), } } } diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index b421f07ddafa2..f9a46fe362e3c 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -181,6 +181,9 @@ pub struct RenderOptions { /// A file to use as the index page at the root of the output directory. Overrides /// `enable_index_page` to be true if set. pub index_page: Option, + /// An optional path to use as the location of static files. If not set, uses combinations of + /// `../` to reach the documentation root. + pub static_root_path: Option, // Options specific to reading standalone Markdown files @@ -433,6 +436,7 @@ impl Options { let markdown_playground_url = matches.opt_str("markdown-playground-url"); let crate_version = matches.opt_str("crate-version"); let enable_index_page = matches.opt_present("enable-index-page") || index_page.is_some(); + let static_root_path = matches.opt_str("static-root-path"); let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); @@ -471,6 +475,7 @@ impl Options { enable_minification, enable_index_page, index_page, + static_root_path, markdown_no_toc, markdown_css, markdown_playground_url, diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 37ff693bdf167..d8a57bc93fd6c 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -26,16 +26,20 @@ pub struct Page<'a> { pub title: &'a str, pub css_class: &'a str, pub root_path: &'a str, + pub static_root_path: Option<&'a str>, pub description: &'a str, pub keywords: &'a str, pub resource_suffix: &'a str, + pub extra_scripts: &'a [&'a str], + pub static_extra_scripts: &'a [&'a str], } pub fn render( dst: &mut dyn io::Write, layout: &Layout, page: &Page, sidebar: &S, t: &T, - css_file_extension: bool, themes: &[PathBuf], extra_scripts: &[&str]) + css_file_extension: bool, themes: &[PathBuf]) -> io::Result<()> { + let static_root_path = page.static_root_path.unwrap_or(page.root_path); write!(dst, "\ \ @@ -46,20 +50,20 @@ pub fn render( \ \ {title}\ - \ - \ + \ {themes}\ - \ - \ + \ - \ - \ + \ + \ {css_extension}\ {favicon}\ {in_header}\ \ \ \ @@ -77,11 +81,13 @@ pub fn render( \

\ \
\
\ - \ + \