From: kennytm Date: Fri, 19 Oct 2018 08:48:36 +0000 (+0800) Subject: Rollup merge of #55013 - matthewjasper:propagate-generator-bounds, r=nikomatsakis X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=0724efd9a1aac9cf4620795786fb8e896fbb17b3;hp=ef1a40d5fec8678c4ae51cf2dcbed96934182b8c;p=rust.git Rollup merge of #55013 - matthewjasper:propagate-generator-bounds, r=nikomatsakis [NLL] Propagate bounds from generators This used to only be done for closures. --- diff --git a/RELEASES.md b/RELEASES.md index 9bc750ddef5..b40897a7509 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,124 @@ +Version 1.30.0 (2018-10-25) +========================== + +Language +-------- +- [Procedural macros are now available.][52081] These kinds of macros allow for + more powerful code generation, there is a [new chapter available][proc-macros] + in Rust Programming Language book that goes further in depth. +- [You can now use keywords as identifiers using the raw identifiers + syntax (`r#`).][53236] e.g. `let r#bool = true;` +- [Using anonymous parameters in traits is now deprecated with a warning and + will be a hard error in the 2018 edition.][53272] +- [You can now use `crate` in paths.][54404] This allows you to refer to the + crate root in the path. e.g. `use crate::foo;` refers to `foo` in `src/lib.rs`. +- [Using a external crate now no longer requires being prefixed with `::`.][54404] + e.g. previously using a external crate in a module without a use statement + required `let json = ::serde_json::from_str(foo);` can now be written + as `let json = serde_json::from_str(foo);`. +- [You can now apply the `#[used]` attribute to static items to prevent the + compiler from optimising them away even if they appear to be unused.][51363] + e.g. `#[used] static FOO: u32 = 1;` +- [You can now import and reexport macros from other crates with the `use` + syntax.][50911] Macros exported with `#[macro_export]` are now placed into + the root module of the crate. If your macro relies on calling other local + macros it is recommended to export with the + `#[macro_export(local_inner_macros)]` attribute so that users won't have to + import those macros. +- [`mod.rs` files are now optional.][54146] Previously if you had a `foo` module + with a `bar` submodule, you would have `src/foo/mod.rs` and `src/foo/bar.rs`. + Now you can have `src/foo.rs` and `src/foo/bar.rs` to achieve the same effect. +- [You can now catch visibility keywords (e.g. `pub`, `pub(crate)`) in macros + using the `vis` specifier.][53370] +- [Non-macro attributes now allow all forms of literals not just + strings.][53044] e.g. Previously you would write `#[attr("true")]` you can now + write `#[attr(true)]`. +- [You can now specify a function to handle a panic in the Rust runtime with the + `#[panic_handler]` attribute.][51366] + +Compiler +-------- +- [Added the `riscv32imc-unknown-none-elf` target.][53822] +- [Added the `aarch64-unknown-netbsd` target][53165] + +Libraries +--------- +- [`ManuallyDrop` now allows the inner type to be unsized.][53033] + +Stabilized APIs +--------------- +- [`Ipv4Addr::BROADCAST`] +- [`Ipv4Addr::LOCALHOST`] +- [`Ipv4Addr::UNSPECIFIED`] +- [`Ipv6Addr::LOCALHOST`] +- [`Ipv6Addr::UNSPECIFIED`] +- [`Iterator::find_map`] + + The following methods are a replacement methods for `trim_left`, `trim_right`, + `trim_left_matches`, and `trim_right_matches`. Which will be deprecated + in 1.33.0. +- [`str::trim_end_matches`] +- [`str::trim_end`] +- [`str::trim_start_matches`] +- [`str::trim_start`] + +Cargo +---- +- [`cargo run` doesn't require specifying a package in workspaces.][cargo/5877] +- [`cargo doc` now supports `--message-format=json`.][cargo/5878] This is + equivalent to calling `rustdoc --error-format=json`. +- [You can specify which edition to create a project in cargo + with `cargo new --edition`.][cargo/5984] Currently only `2015` is a + valid option. +- [Cargo will now provide a progress bar for builds.][cargo/5995] + +Misc +---- +- [`rustdoc` allows you to specify what edition to treat your code as with the + `--edition` option.][54057] +- [`rustdoc` now has the `--color` (Specify whether to output color) and + `--error-format` (Specify error format e.g. `json`) options.][53003] +- [We now distribute a `rust-gdbgui` script that invokes `gdbgui` with Rust + debug symbols.][53774] +- [Attributes from Rust tools such as `rustfmt` or `clippy` are now + available.][53459] e.g. `#[rustfmt::skip]` will skip formatting the next item. + +[50911]: https://github.com/rust-lang/rust/pull/50911/ +[51363]: https://github.com/rust-lang/rust/pull/51363/ +[51366]: https://github.com/rust-lang/rust/pull/51366/ +[52081]: https://github.com/rust-lang/rust/pull/52081/ +[53003]: https://github.com/rust-lang/rust/pull/53003/ +[53033]: https://github.com/rust-lang/rust/pull/53033/ +[53044]: https://github.com/rust-lang/rust/pull/53044/ +[53165]: https://github.com/rust-lang/rust/pull/53165/ +[53213]: https://github.com/rust-lang/rust/pull/53213/ +[53236]: https://github.com/rust-lang/rust/pull/53236/ +[53272]: https://github.com/rust-lang/rust/pull/53272/ +[53370]: https://github.com/rust-lang/rust/pull/53370/ +[53459]: https://github.com/rust-lang/rust/pull/53459/ +[53774]: https://github.com/rust-lang/rust/pull/53774/ +[53822]: https://github.com/rust-lang/rust/pull/53822/ +[54057]: https://github.com/rust-lang/rust/pull/54057/ +[54146]: https://github.com/rust-lang/rust/pull/54146/ +[54404]: https://github.com/rust-lang/rust/pull/54404/ +[cargo/5877]: https://github.com/rust-lang/cargo/pull/5877/ +[cargo/5878]: https://github.com/rust-lang/cargo/pull/5878/ +[cargo/5984]: https://github.com/rust-lang/cargo/pull/5984/ +[cargo/5995]: https://github.com/rust-lang/cargo/pull/5995/ +[proc-macros]: https://doc.rust-lang.org/book/2018-edition/ch19-06-macros.html + +[`Ipv4Addr::BROADCAST`]: https://doc.rust-lang.org/nightly/std/net/struct.Ipv4Addr.html#associatedconstant.BROADCAST +[`Ipv4Addr::LOCALHOST`]: https://doc.rust-lang.org/nightly/std/net/struct.Ipv4Addr.html#associatedconstant.LOCALHOST +[`Ipv4Addr::UNSPECIFIED`]: https://doc.rust-lang.org/nightly/std/net/struct.Ipv4Addr.html#associatedconstant.UNSPECIFIED +[`Ipv6Addr::LOCALHOST`]: https://doc.rust-lang.org/nightly/std/net/struct.Ipv6Addr.html#associatedconstant.LOCALHOST +[`Ipv6Addr::UNSPECIFIED`]: https://doc.rust-lang.org/nightly/std/net/struct.Ipv6Addr.html#associatedconstant.UNSPECIFIED +[`Iterator::find_map`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.find_map +[`str::trim_end_matches`]: https://doc.rust-lang.org/nightly/std/primitive.str.html#method.trim_end_matches +[`str::trim_end`]: https://doc.rust-lang.org/nightly/std/primitive.str.html#method.trim_end +[`str::trim_start_matches`]: https://doc.rust-lang.org/nightly/std/primitive.str.html#method.trim_start_matches +[`str::trim_start`]: https://doc.rust-lang.org/nightly/std/primitive.str.html#method.trim_start + + Version 1.29.2 (2018-10-11) =========================== @@ -6,6 +127,7 @@ Version 1.29.2 (2018-10-11) [54639]: https://github.com/rust-lang/rust/pull/54639 + Version 1.29.1 (2018-09-25) =========================== @@ -19,6 +141,7 @@ Security Notes Thank you to Scott McMurray for responsibily disclosing this vulnerability to us. + Version 1.29.0 (2018-09-13) ========================== @@ -73,7 +196,10 @@ Compatibility Notes Consider using the `home_dir` function from https://crates.io/crates/dirs instead. - [`rustc` will no longer silently ignore invalid data in target spec.][52330] +- [`cfg` attributes and `--cfg` command line flags are now more + strictly validated.][53893] +[53893]: https://github.com/rust-lang/rust/pull/53893/ [52861]: https://github.com/rust-lang/rust/pull/52861/ [52656]: https://github.com/rust-lang/rust/pull/52656/ [52239]: https://github.com/rust-lang/rust/pull/52239/ diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 0cad471d9a1..84ca7c4fec9 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -115,12 +115,10 @@ #![feature(unsize)] #![feature(allocator_internals)] #![feature(on_unimplemented)] -#![feature(chunks_exact)] #![feature(rustc_const_unstable)] #![feature(const_vec_new)] #![feature(slice_partition_dedup)] #![feature(maybe_uninit)] -#![feature(rchunks)] // Allow testing this library diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 2628757b503..1eaff7410ea 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -123,9 +123,9 @@ pub use core::slice::{from_ref, from_mut}; #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use core::slice::SliceIndex; -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] pub use core::slice::{ChunksExact, ChunksExactMut}; -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] pub use core::slice::{RChunks, RChunksMut, RChunksExact, RChunksExactMut}; //////////////////////////////////////////////////////////////////////////////// diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 62c84c9e086..6d1cfb10859 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -19,8 +19,6 @@ #![feature(str_escape)] #![feature(try_reserve)] #![feature(unboxed_closures)] -#![feature(chunks_exact)] -#![feature(rchunks)] #![feature(repeat_generic_slice)] extern crate alloc_system; diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 266c6913747..662a8ddd968 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -92,6 +92,7 @@ impl !Send for *mut T { } #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sized"] #[rustc_on_unimplemented( + on(parent_trait="std::path::Path", label="borrow the `Path` instead"), message="the size for values of type `{Self}` cannot be known at compilation time", label="doesn't have a size known at compile-time", note="to learn more, visit ChunksMut { /// # Examples /// /// ``` - /// #![feature(chunks_exact)] - /// /// let slice = ['l', 'o', 'r', 'e', 'm']; /// let mut iter = slice.chunks_exact(2); /// assert_eq!(iter.next().unwrap(), &['l', 'o']); @@ -725,7 +723,7 @@ pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut { /// /// [`chunks`]: #method.chunks /// [`rchunks_exact`]: #method.rchunks_exact - #[unstable(feature = "chunks_exact", issue = "47115")] + #[stable(feature = "chunks_exact", since = "1.31.0")] #[inline] pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact { assert!(chunk_size != 0); @@ -756,8 +754,6 @@ pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact { /// # Examples /// /// ``` - /// #![feature(chunks_exact)] - /// /// let v = &mut [0, 0, 0, 0, 0]; /// let mut count = 1; /// @@ -772,7 +768,7 @@ pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact { /// /// [`chunks_mut`]: #method.chunks_mut /// [`rchunks_exact_mut`]: #method.rchunks_exact_mut - #[unstable(feature = "chunks_exact", issue = "47115")] + #[stable(feature = "chunks_exact", since = "1.31.0")] #[inline] pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut { assert!(chunk_size != 0); @@ -799,8 +795,6 @@ pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut { /// # Examples /// /// ``` - /// #![feature(rchunks)] - /// /// let slice = ['l', 'o', 'r', 'e', 'm']; /// let mut iter = slice.rchunks(2); /// assert_eq!(iter.next().unwrap(), &['e', 'm']); @@ -811,7 +805,7 @@ pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut { /// /// [`rchunks_exact`]: #method.rchunks_exact /// [`chunks`]: #method.chunks - #[unstable(feature = "rchunks", issue = "55177")] + #[stable(feature = "rchunks", since = "1.31.0")] #[inline] pub fn rchunks(&self, chunk_size: usize) -> RChunks { assert!(chunk_size != 0); @@ -835,8 +829,6 @@ pub fn rchunks(&self, chunk_size: usize) -> RChunks { /// # Examples /// /// ``` - /// #![feature(rchunks)] - /// /// let v = &mut [0, 0, 0, 0, 0]; /// let mut count = 1; /// @@ -851,7 +843,7 @@ pub fn rchunks(&self, chunk_size: usize) -> RChunks { /// /// [`rchunks_exact_mut`]: #method.rchunks_exact_mut /// [`chunks_mut`]: #method.chunks_mut - #[unstable(feature = "rchunks", issue = "55177")] + #[stable(feature = "rchunks", since = "1.31.0")] #[inline] pub fn rchunks_mut(&mut self, chunk_size: usize) -> RChunksMut { assert!(chunk_size != 0); @@ -879,8 +871,6 @@ pub fn rchunks_mut(&mut self, chunk_size: usize) -> RChunksMut { /// # Examples /// /// ``` - /// #![feature(rchunks)] - /// /// let slice = ['l', 'o', 'r', 'e', 'm']; /// let mut iter = slice.rchunks_exact(2); /// assert_eq!(iter.next().unwrap(), &['e', 'm']); @@ -891,7 +881,7 @@ pub fn rchunks_mut(&mut self, chunk_size: usize) -> RChunksMut { /// /// [`rchunks`]: #method.rchunks /// [`chunks_exact`]: #method.chunks_exact - #[unstable(feature = "rchunks", issue = "55177")] + #[stable(feature = "rchunks", since = "1.31.0")] #[inline] pub fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact { assert!(chunk_size != 0); @@ -921,8 +911,6 @@ pub fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact { /// # Examples /// /// ``` - /// #![feature(rchunks)] - /// /// let v = &mut [0, 0, 0, 0, 0]; /// let mut count = 1; /// @@ -937,7 +925,7 @@ pub fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact { /// /// [`rchunks_mut`]: #method.rchunks_mut /// [`chunks_exact_mut`]: #method.chunks_exact_mut - #[unstable(feature = "rchunks", issue = "55177")] + #[stable(feature = "rchunks", since = "1.31.0")] #[inline] pub fn rchunks_exact_mut(&mut self, chunk_size: usize) -> RChunksExactMut { assert!(chunk_size != 0); @@ -4022,25 +4010,25 @@ fn may_have_side_effect() -> bool { false } /// [`remainder`]: ../../std/slice/struct.ChunksExact.html#method.remainder /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] pub struct ChunksExact<'a, T:'a> { v: &'a [T], rem: &'a [T], chunk_size: usize } -#[unstable(feature = "chunks_exact", issue = "47115")] impl<'a, T> ChunksExact<'a, T> { /// Return the remainder of the original slice that is not going to be /// returned by the iterator. The returned slice has at most `chunk_size-1` /// elements. + #[stable(feature = "chunks_exact", since = "1.31.0")] pub fn remainder(&self) -> &'a [T] { self.rem } } // FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] impl Clone for ChunksExact<'_, T> { fn clone(&self) -> Self { ChunksExact { @@ -4051,7 +4039,7 @@ fn clone(&self) -> Self { } } -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] impl<'a, T> Iterator for ChunksExact<'a, T> { type Item = &'a [T]; @@ -4096,7 +4084,7 @@ fn last(mut self) -> Option { } } -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] impl<'a, T> DoubleEndedIterator for ChunksExact<'a, T> { #[inline] fn next_back(&mut self) -> Option<&'a [T]> { @@ -4110,7 +4098,7 @@ fn next_back(&mut self) -> Option<&'a [T]> { } } -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] impl ExactSizeIterator for ChunksExact<'_, T> { fn is_empty(&self) -> bool { self.v.is_empty() @@ -4120,11 +4108,11 @@ fn is_empty(&self) -> bool { #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for ChunksExact<'_, T> {} -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] impl FusedIterator for ChunksExact<'_, T> {} #[doc(hidden)] -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] { let start = i * self.chunk_size; @@ -4146,24 +4134,24 @@ fn may_have_side_effect() -> bool { false } /// [`into_remainder`]: ../../std/slice/struct.ChunksExactMut.html#method.into_remainder /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] pub struct ChunksExactMut<'a, T:'a> { v: &'a mut [T], rem: &'a mut [T], chunk_size: usize } -#[unstable(feature = "chunks_exact", issue = "47115")] impl<'a, T> ChunksExactMut<'a, T> { /// Return the remainder of the original slice that is not going to be /// returned by the iterator. The returned slice has at most `chunk_size-1` /// elements. + #[stable(feature = "chunks_exact", since = "1.31.0")] pub fn into_remainder(self) -> &'a mut [T] { self.rem } } -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] impl<'a, T> Iterator for ChunksExactMut<'a, T> { type Item = &'a mut [T]; @@ -4210,7 +4198,7 @@ fn last(mut self) -> Option { } } -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> { #[inline] fn next_back(&mut self) -> Option<&'a mut [T]> { @@ -4226,7 +4214,7 @@ fn next_back(&mut self) -> Option<&'a mut [T]> { } } -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] impl ExactSizeIterator for ChunksExactMut<'_, T> { fn is_empty(&self) -> bool { self.v.is_empty() @@ -4236,11 +4224,11 @@ fn is_empty(&self) -> bool { #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for ChunksExactMut<'_, T> {} -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] impl FusedIterator for ChunksExactMut<'_, T> {} #[doc(hidden)] -#[unstable(feature = "chunks_exact", issue = "47115")] +#[stable(feature = "chunks_exact", since = "1.31.0")] unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T] { let start = i * self.chunk_size; @@ -4260,14 +4248,14 @@ fn may_have_side_effect() -> bool { false } /// [`rchunks`]: ../../std/primitive.slice.html#method.rchunks /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] pub struct RChunks<'a, T:'a> { v: &'a [T], chunk_size: usize } // FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> Clone for RChunks<'a, T> { fn clone(&self) -> RChunks<'a, T> { RChunks { @@ -4277,7 +4265,7 @@ fn clone(&self) -> RChunks<'a, T> { } } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> Iterator for RChunks<'a, T> { type Item = &'a [T]; @@ -4341,7 +4329,7 @@ fn last(self) -> Option { } } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> DoubleEndedIterator for RChunks<'a, T> { #[inline] fn next_back(&mut self) -> Option<&'a [T]> { @@ -4357,17 +4345,17 @@ fn next_back(&mut self) -> Option<&'a [T]> { } } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> ExactSizeIterator for RChunks<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<'a, T> TrustedLen for RChunks<'a, T> {} -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> FusedIterator for RChunks<'a, T> {} #[doc(hidden)] -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] { let end = self.v.len() - i * self.chunk_size; @@ -4391,13 +4379,13 @@ fn may_have_side_effect() -> bool { false } /// [`rchunks_mut`]: ../../std/primitive.slice.html#method.rchunks_mut /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] pub struct RChunksMut<'a, T:'a> { v: &'a mut [T], chunk_size: usize } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> Iterator for RChunksMut<'a, T> { type Item = &'a mut [T]; @@ -4465,7 +4453,7 @@ fn last(self) -> Option { } } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> { #[inline] fn next_back(&mut self) -> Option<&'a mut [T]> { @@ -4482,17 +4470,17 @@ fn next_back(&mut self) -> Option<&'a mut [T]> { } } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> ExactSizeIterator for RChunksMut<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<'a, T> TrustedLen for RChunksMut<'a, T> {} -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> FusedIterator for RChunksMut<'a, T> {} #[doc(hidden)] -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T] { let end = self.v.len() - i * self.chunk_size; @@ -4518,25 +4506,25 @@ fn may_have_side_effect() -> bool { false } /// [`remainder`]: ../../std/slice/struct.ChunksExact.html#method.remainder /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] pub struct RChunksExact<'a, T:'a> { v: &'a [T], rem: &'a [T], chunk_size: usize } -#[unstable(feature = "rchunks", issue = "55177")] impl<'a, T> RChunksExact<'a, T> { /// Return the remainder of the original slice that is not going to be /// returned by the iterator. The returned slice has at most `chunk_size-1` /// elements. + #[stable(feature = "rchunks", since = "1.31.0")] pub fn remainder(&self) -> &'a [T] { self.rem } } // FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> Clone for RChunksExact<'a, T> { fn clone(&self) -> RChunksExact<'a, T> { RChunksExact { @@ -4547,7 +4535,7 @@ fn clone(&self) -> RChunksExact<'a, T> { } } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> Iterator for RChunksExact<'a, T> { type Item = &'a [T]; @@ -4592,7 +4580,7 @@ fn last(mut self) -> Option { } } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> DoubleEndedIterator for RChunksExact<'a, T> { #[inline] fn next_back(&mut self) -> Option<&'a [T]> { @@ -4606,7 +4594,7 @@ fn next_back(&mut self) -> Option<&'a [T]> { } } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> ExactSizeIterator for RChunksExact<'a, T> { fn is_empty(&self) -> bool { self.v.is_empty() @@ -4616,11 +4604,11 @@ fn is_empty(&self) -> bool { #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<'a, T> TrustedLen for RChunksExact<'a, T> {} -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> FusedIterator for RChunksExact<'a, T> {} #[doc(hidden)] -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] { let end = self.v.len() - i * self.chunk_size; @@ -4643,24 +4631,24 @@ fn may_have_side_effect() -> bool { false } /// [`into_remainder`]: ../../std/slice/struct.ChunksExactMut.html#method.into_remainder /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] pub struct RChunksExactMut<'a, T:'a> { v: &'a mut [T], rem: &'a mut [T], chunk_size: usize } -#[unstable(feature = "rchunks", issue = "55177")] impl<'a, T> RChunksExactMut<'a, T> { /// Return the remainder of the original slice that is not going to be /// returned by the iterator. The returned slice has at most `chunk_size-1` /// elements. + #[stable(feature = "rchunks", since = "1.31.0")] pub fn into_remainder(self) -> &'a mut [T] { self.rem } } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> Iterator for RChunksExactMut<'a, T> { type Item = &'a mut [T]; @@ -4709,7 +4697,7 @@ fn last(mut self) -> Option { } } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> { #[inline] fn next_back(&mut self) -> Option<&'a mut [T]> { @@ -4724,7 +4712,7 @@ fn next_back(&mut self) -> Option<&'a mut [T]> { } } -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> ExactSizeIterator for RChunksExactMut<'a, T> { fn is_empty(&self) -> bool { self.v.is_empty() @@ -4734,11 +4722,11 @@ fn is_empty(&self) -> bool { #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<'a, T> TrustedLen for RChunksExactMut<'a, T> {} -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] impl<'a, T> FusedIterator for RChunksExactMut<'a, T> {} #[doc(hidden)] -#[unstable(feature = "rchunks", issue = "55177")] +#[stable(feature = "rchunks", since = "1.31.0")] unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T] { let end = self.v.len() - i * self.chunk_size; diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index e889d484353..965bd545eed 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -34,8 +34,6 @@ #![feature(trusted_len)] #![feature(try_from)] #![feature(try_trait)] -#![feature(chunks_exact)] -#![feature(rchunks)] #![feature(align_offset)] #![feature(reverse_bits)] #![feature(inner_deref)] diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index fc34a71f392..db775beae4f 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -378,6 +378,9 @@ fn on_unimplemented_note( flags.push(("from_method".to_owned(), Some(method.to_string()))); } } + if let Some(t) = self.get_parent_trait_ref(&obligation.cause.code) { + flags.push(("parent_trait".to_owned(), Some(t.to_string()))); + } if let Some(k) = obligation.cause.span.compiler_desugaring_kind() { flags.push(("from_desugaring".to_owned(), None)); diff --git a/src/librustc/ty/cast.rs b/src/librustc/ty/cast.rs index c0861abb774..ab82f28c8bf 100644 --- a/src/librustc/ty/cast.rs +++ b/src/librustc/ty/cast.rs @@ -58,6 +58,8 @@ pub enum CastKind { } impl<'tcx> CastTy<'tcx> { + /// Returns `Some` for integral/pointer casts. + /// casts like unsizing casts will return `None` pub fn from_ty(t: Ty<'tcx>) -> Option> { match t.sty { ty::Bool => Some(CastTy::Int(IntTy::Bool)), diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 34ee03b895f..d9b64527700 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -609,12 +609,12 @@ pub fn report_error_if_loan_conflicts_with_restriction(&self, new_loan.span, &nl, old_loan.span, previous_end_span, Origin::Ast), (ty::UniqueImmBorrow, _) => self.bccx.cannot_uniquely_borrow_by_one_closure( - new_loan.span, &nl, &new_loan_msg, + new_loan.span, "closure", &nl, &new_loan_msg, old_loan.span, &ol_pronoun, &old_loan_msg, previous_end_span, Origin::Ast), (_, ty::UniqueImmBorrow) => { let new_loan_str = &new_loan.kind.to_user_str(); self.bccx.cannot_reborrow_already_uniquely_borrowed( - new_loan.span, &nl, &new_loan_msg, new_loan_str, + new_loan.span, "closure", &nl, &new_loan_msg, new_loan_str, old_loan.span, &old_loan_msg, previous_end_span, Origin::Ast) } (..) => diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 76717548521..4cf2072e792 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -276,10 +276,13 @@ fn check_unused_parens_expr(&self, cx: &EarlyContext, value: &ast::Expr, msg: &str, - struct_lit_needs_parens: bool) { + followed_by_block: bool) { if let ast::ExprKind::Paren(ref inner) = value.node { - let necessary = struct_lit_needs_parens && - parser::contains_exterior_struct_lit(&inner); + let necessary = followed_by_block && if let ast::ExprKind::Ret(_) = inner.node { + true + } else { + parser::contains_exterior_struct_lit(&inner) + }; if !necessary { let pattern = pprust::expr_to_string(value); Self::remove_outer_parens(cx, value.span, &pattern, msg); @@ -343,7 +346,7 @@ fn get_lints(&self) -> LintArray { impl EarlyLintPass for UnusedParens { fn check_expr(&mut self, cx: &EarlyContext, e: &ast::Expr) { use syntax::ast::ExprKind::*; - let (value, msg, struct_lit_needs_parens) = match e.node { + let (value, msg, followed_by_block) = match e.node { If(ref cond, ..) => (cond, "`if` condition", true), While(ref cond, ..) => (cond, "`while` condition", true), IfLet(_, ref cond, ..) => (cond, "`if let` head expression", true), @@ -380,7 +383,7 @@ fn check_expr(&mut self, cx: &EarlyContext, e: &ast::Expr) { return; } }; - self.check_unused_parens_expr(cx, &value, msg, struct_lit_needs_parens); + self.check_unused_parens_expr(cx, &value, msg, followed_by_block); } fn check_pat(&mut self, cx: &EarlyContext, p: &ast::Pat) { diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 759b842e9df..baf9e032270 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -15,11 +15,11 @@ use rustc::hir::def_id::DefId; use rustc::middle::region::ScopeTree; use rustc::mir::{ - self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, Field, Local, + self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, Constant, Field, Local, LocalDecl, LocalKind, Location, Operand, Place, PlaceProjection, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm, }; -use rustc::ty; +use rustc::ty::{self, DefIdTree}; use rustc::util::ppaux::with_highlight_region_for_bound_region; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; @@ -103,7 +103,7 @@ pub(super) fn report_use_of_moved_or_uninitialized( use_spans.var_span_label( &mut err, - format!("{} occurs due to use in closure", desired_action.as_noun()), + format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()), ); err.buffer(&mut self.errors_buffer); @@ -131,6 +131,12 @@ pub(super) fn report_use_of_moved_or_uninitialized( Origin::Mir, ); + self.add_closure_invoked_twice_with_moved_variable_suggestion( + context.loc, + used_place, + &mut err, + ); + let mut is_loop_move = false; for move_site in &move_site_vec { let move_out = self.move_data.moves[(*move_site).moi]; @@ -161,13 +167,16 @@ pub(super) fn report_use_of_moved_or_uninitialized( ); } else { err.span_label(move_span, format!("value moved{} here", move_msg)); - move_spans.var_span_label(&mut err, "variable moved due to use in closure"); + move_spans.var_span_label( + &mut err, + format!("variable moved due to use{}", move_spans.describe()), + ); }; } use_spans.var_span_label( &mut err, - format!("{} occurs due to use in closure", desired_action.as_noun()), + format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()), ); if !is_loop_move { @@ -226,9 +235,13 @@ pub(super) fn report_use_of_moved_or_uninitialized( pub(super) fn report_move_out_while_borrowed( &mut self, context: Context, - (place, _span): (&Place<'tcx>, Span), + (place, span): (&Place<'tcx>, Span), borrow: &BorrowData<'tcx>, ) { + debug!( + "report_move_out_while_borrowed: context={:?} place={:?} span={:?} borrow={:?}", + context, place, span, borrow + ); let tcx = self.infcx.tcx; let value_msg = match self.describe_place(place) { Some(name) => format!("`{}`", name), @@ -253,9 +266,15 @@ pub(super) fn report_move_out_while_borrowed( err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg)); err.span_label(span, format!("move out of {} occurs here", value_msg)); - borrow_spans.var_span_label(&mut err, "borrow occurs due to use in closure"); + borrow_spans.var_span_label( + &mut err, + format!("borrow occurs due to use{}", borrow_spans.describe()) + ); - move_spans.var_span_label(&mut err, "move occurs due to use in closure"); + move_spans.var_span_label( + &mut err, + format!("move occurs due to use{}", move_spans.describe()) + ); self.explain_why_borrow_contains_point(context, borrow, None) .add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, ""); @@ -291,7 +310,7 @@ pub(super) fn report_use_while_mutably_borrowed( let place = &borrow.borrowed_place; let desc_place = self.describe_place(place).unwrap_or("_".to_owned()); - format!("borrow occurs due to use of `{}` in closure", desc_place) + format!("borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe()) }); self.explain_why_borrow_contains_point(context, borrow, None) @@ -312,6 +331,12 @@ pub(super) fn report_conflicting_borrow( let borrow_spans = self.borrow_spans(span, context.loc); let span = borrow_spans.args_or_use(); + let container_name = if issued_spans.for_generator() || borrow_spans.for_generator() { + "generator" + } else { + "closure" + }; + let desc_place = self.describe_place(place).unwrap_or("_".to_owned()); let tcx = self.infcx.tcx; @@ -392,7 +417,9 @@ pub(super) fn report_conflicting_borrow( ); borrow_spans.var_span_label( &mut err, - format!("borrow occurs due to use of `{}` in closure", desc_place), + format!( + "borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe() + ), ); err.buffer(&mut self.errors_buffer); @@ -403,6 +430,7 @@ pub(super) fn report_conflicting_borrow( first_borrow_desc = "first "; tcx.cannot_uniquely_borrow_by_one_closure( span, + container_name, &desc_place, "", issued_span, @@ -417,6 +445,7 @@ pub(super) fn report_conflicting_borrow( first_borrow_desc = "first "; tcx.cannot_reborrow_already_uniquely_borrowed( span, + container_name, &desc_place, "", lft, @@ -431,6 +460,7 @@ pub(super) fn report_conflicting_borrow( first_borrow_desc = "first "; tcx.cannot_reborrow_already_uniquely_borrowed( span, + container_name, &desc_place, "", lft, @@ -456,7 +486,7 @@ pub(super) fn report_conflicting_borrow( if issued_spans == borrow_spans { borrow_spans.var_span_label( &mut err, - format!("borrows occur due to use of `{}` in closure", desc_place), + format!("borrows occur due to use of `{}`{}", desc_place, borrow_spans.describe()), ); } else { let borrow_place = &issued_borrow.borrowed_place; @@ -464,16 +494,18 @@ pub(super) fn report_conflicting_borrow( issued_spans.var_span_label( &mut err, format!( - "first borrow occurs due to use of `{}` in closure", - borrow_place_desc + "first borrow occurs due to use of `{}`{}", + borrow_place_desc, + issued_spans.describe(), ), ); borrow_spans.var_span_label( &mut err, format!( - "second borrow occurs due to use of `{}` in closure", - desc_place + "second borrow occurs due to use of `{}`{}", + desc_place, + borrow_spans.describe(), ), ); } @@ -643,7 +675,16 @@ fn report_local_value_does_not_live_long_enough( format!("`{}` dropped here while still borrowed", name), ); - borrow_spans.args_span_label(&mut err, "value captured here"); + let within = if borrow_spans.for_generator() { + " by generator" + } else { + "" + }; + + borrow_spans.args_span_label( + &mut err, + format!("value captured here{}", within), + ); explanation.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, ""); } @@ -774,7 +815,16 @@ fn report_temporary_value_does_not_live_long_enough( } explanation.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, ""); - borrow_spans.args_span_label(&mut err, "value captured here"); + let within = if borrow_spans.for_generator() { + " by generator" + } else { + "" + }; + + borrow_spans.args_span_label( + &mut err, + format!("value captured here{}", within), + ); err } @@ -906,7 +956,10 @@ pub(super) fn report_illegal_mutation_of_borrowed( ) }; - loan_spans.var_span_label(&mut err, "borrow occurs due to use in closure"); + loan_spans.var_span_label( + &mut err, + format!("borrow occurs due to use{}", loan_spans.describe()), + ); self.explain_why_borrow_contains_point(context, loan, None) .add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, ""); @@ -1009,16 +1062,111 @@ enum StorageDeadOrDrop<'tcx> { } impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { - // End-user visible description of `place` if one can be found. If the - // place is a temporary for instance, None will be returned. + + /// Adds a suggestion when a closure is invoked twice with a moved variable. + /// + /// ```text + /// note: closure cannot be invoked more than once because it moves the variable `dict` out of + /// its environment + /// --> $DIR/issue-42065.rs:16:29 + /// | + /// LL | for (key, value) in dict { + /// | ^^^^ + /// ``` + pub(super) fn add_closure_invoked_twice_with_moved_variable_suggestion( + &self, + location: Location, + place: &Place<'tcx>, + diag: &mut DiagnosticBuilder<'_>, + ) { + let mut target = place.local(); + debug!( + "add_closure_invoked_twice_with_moved_variable_suggestion: location={:?} place={:?} \ + target={:?}", + location, place, target, + ); + for stmt in &self.mir[location.block].statements[location.statement_index..] { + debug!( + "add_closure_invoked_twice_with_moved_variable_suggestion: stmt={:?} \ + target={:?}", + stmt, target, + ); + if let StatementKind::Assign(into, box Rvalue::Use(from)) = &stmt.kind { + debug!( + "add_closure_invoked_twice_with_moved_variable_suggestion: into={:?} \ + from={:?}", + into, from, + ); + match from { + Operand::Copy(ref place) | + Operand::Move(ref place) if target == place.local() => + target = into.local(), + _ => {}, + } + } + } + + + let terminator = self.mir[location.block].terminator(); + debug!( + "add_closure_invoked_twice_with_moved_variable_suggestion: terminator={:?}", + terminator, + ); + if let TerminatorKind::Call { + func: Operand::Constant(box Constant { + literal: ty::Const { ty: &ty::TyS { sty: ty::TyKind::FnDef(id, _), .. }, .. }, + .. + }), + args, + .. + } = &terminator.kind { + debug!("add_closure_invoked_twice_with_moved_variable_suggestion: id={:?}", id); + if self.infcx.tcx.parent(id) == self.infcx.tcx.lang_items().fn_once_trait() { + let closure = match args.first() { + Some(Operand::Copy(ref place)) | + Some(Operand::Move(ref place)) if target == place.local() => + place.local().unwrap(), + _ => return, + }; + debug!( + "add_closure_invoked_twice_with_moved_variable_suggestion: closure={:?}", + closure, + ); + + if let ty::TyKind::Closure(did, _substs) = self.mir.local_decls[closure].ty.sty { + let node_id = match self.infcx.tcx.hir.as_local_node_id(did) { + Some(node_id) => node_id, + _ => return, + }; + let hir_id = self.infcx.tcx.hir.node_to_hir_id(node_id); + + if let Some(( + span, name + )) = self.infcx.tcx.typeck_tables_of(did).closure_kind_origins().get(hir_id) { + diag.span_note( + *span, + &format!( + "closure cannot be invoked more than once because it \ + moves the variable `{}` out of its environment", + name, + ), + ); + } + } + } + } + } + + /// End-user visible description of `place` if one can be found. If the + /// place is a temporary for instance, None will be returned. pub(super) fn describe_place(&self, place: &Place<'tcx>) -> Option { self.describe_place_with_options(place, IncludingDowncast(false)) } - // End-user visible description of `place` if one can be found. If the - // place is a temporary for instance, None will be returned. - // `IncludingDowncast` parameter makes the function return `Err` if `ProjectionElem` is - // `Downcast` and `IncludingDowncast` is true + /// End-user visible description of `place` if one can be found. If the + /// place is a temporary for instance, None will be returned. + /// `IncludingDowncast` parameter makes the function return `Err` if `ProjectionElem` is + /// `Downcast` and `IncludingDowncast` is true pub(super) fn describe_place_with_options( &self, place: &Place<'tcx>, @@ -1031,7 +1179,7 @@ pub(super) fn describe_place_with_options( } } - // Appends end-user visible description of `place` to `buf`. + /// Appends end-user visible description of `place` to `buf`. fn append_place_to_string( &self, place: &Place<'tcx>, @@ -1166,8 +1314,8 @@ fn append_place_to_string( Ok(()) } - // Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have - // a name, then `Err` is returned + /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have + /// a name, then `Err` is returned fn append_local_to_string(&self, local_index: Local, buf: &mut String) -> Result<(), ()> { let local = &self.mir.local_decls[local_index]; match local.name { @@ -1179,7 +1327,7 @@ fn append_local_to_string(&self, local_index: Local, buf: &mut String) -> Result } } - // End-user visible description of the `field`nth field of `base` + /// End-user visible description of the `field`nth field of `base` fn describe_field(&self, base: &Place, field: Field) -> String { match *base { Place::Local(local) => { @@ -1204,7 +1352,7 @@ fn describe_field(&self, base: &Place, field: Field) -> String { } } - // End-user visible description of the `field_index`nth field of `ty` + /// End-user visible description of the `field_index`nth field of `ty` fn describe_field_from_ty(&self, ty: &ty::Ty, field: Field) -> String { if ty.is_box() { // If the type is a box, the field is described from the boxed type @@ -1247,7 +1395,7 @@ fn describe_field_from_ty(&self, ty: &ty::Ty, field: Field) -> String { } } - // Retrieve type of a place for the current MIR representation + /// 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) => { @@ -1805,6 +1953,8 @@ fn get_region_name_for_ty(&self, ty: ty::Ty<'tcx>, counter: usize) -> String { pub(super) enum UseSpans { // The access is caused by capturing a variable for a closure. ClosureUse { + // This is true if the captured variable was from a generator. + is_generator: bool, // The span of the args of the closure, including the `move` keyword if // it's present. args_span: Span, @@ -1845,10 +1995,31 @@ pub(super) fn var_span_label(self, err: &mut DiagnosticBuilder, message: impl In } } - pub(super) fn for_closure(self) -> bool { - match self { - UseSpans::ClosureUse { .. } => true, - UseSpans::OtherUse(_) => false, + /// Return `false` if this place is not used in a closure. + fn for_closure(&self) -> bool { + match *self { + UseSpans::ClosureUse { is_generator, .. } => !is_generator, + _ => false, + } + } + + /// Return `false` if this place is not used in a generator. + fn for_generator(&self) -> bool { + match *self { + UseSpans::ClosureUse { is_generator, .. } => is_generator, + _ => false, + } + } + + /// Describe the span associated with a use of a place. + fn describe(&self) -> String { + match *self { + UseSpans::ClosureUse { is_generator, .. } => if is_generator { + " in generator".to_string() + } else { + " in closure".to_string() + }, + _ => "".to_string(), } } @@ -1871,53 +2042,37 @@ pub(super) fn move_spans( location: Location, ) -> UseSpans { use self::UseSpans::*; - use rustc::hir::ExprKind::Closure; - use rustc::mir::AggregateKind; - let stmt = match self.mir[location.block] - .statements - .get(location.statement_index) - { + let stmt = match self.mir[location.block].statements.get(location.statement_index) { Some(stmt) => stmt, None => return OtherUse(self.mir.source_info(location).span), }; - if let StatementKind::Assign(_, box Rvalue::Aggregate(ref kind, ref places)) = stmt.kind { - if let AggregateKind::Closure(def_id, _) = **kind { - debug!("find_closure_move_span: found closure {:?}", places); + debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt); + if let StatementKind::Assign( + _, + box Rvalue::Aggregate(ref kind, ref places) + ) = stmt.kind { + let (def_id, is_generator) = match kind { + box AggregateKind::Closure(def_id, _) => (def_id, false), + box AggregateKind::Generator(def_id, _, _) => (def_id, true), + _ => return OtherUse(stmt.source_info.span), + }; - if let Some(node_id) = self.infcx.tcx.hir.as_local_node_id(def_id) { - if let Closure(_, _, _, args_span, _) = - self.infcx.tcx.hir.expect_expr(node_id).node - { - if let Some(var_span) = self.infcx.tcx.with_freevars(node_id, |freevars| { - for (v, place) in freevars.iter().zip(places) { - match place { - Operand::Copy(place) | Operand::Move(place) - if moved_place == place => - { - debug!( - "find_closure_move_span: found captured local {:?}", - place - ); - return Some(v.span); - } - _ => {} - } - } - None - }) { - return ClosureUse { - args_span, - var_span, - }; - } - } - } + debug!( + "move_spans: def_id={:?} is_generator={:?} places={:?}", + def_id, is_generator, places + ); + if let Some((args_span, var_span)) = self.closure_span(*def_id, moved_place, places) { + return ClosureUse { + is_generator, + args_span, + var_span, + }; } } - return OtherUse(stmt.source_info.span); + OtherUse(stmt.source_info.span) } /// Finds the span of arguments of a closure (within `maybe_closure_span`) @@ -1926,9 +2081,9 @@ pub(super) fn move_spans( /// and originating from `maybe_closure_span`. pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans { use self::UseSpans::*; - use rustc::hir::ExprKind::Closure; + debug!("borrow_spans: use_span={:?} location={:?}", use_span, location); - let local = match self.mir[location.block] + let target = match self.mir[location.block] .statements .get(location.statement_index) { @@ -1939,54 +2094,35 @@ pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpan _ => return OtherUse(use_span), }; - if self.mir.local_kind(local) != LocalKind::Temp { + if self.mir.local_kind(target) != LocalKind::Temp { // operands are always temporaries. return OtherUse(use_span); } for stmt in &self.mir[location.block].statements[location.statement_index + 1..] { - if let StatementKind::Assign(_, box Rvalue::Aggregate(ref kind, ref places)) = stmt.kind - { - if let AggregateKind::Closure(def_id, _) = **kind { - debug!("find_closure_borrow_span: found closure {:?}", places); - - return if let Some(node_id) = self.infcx.tcx.hir.as_local_node_id(def_id) { - let args_span = if let Closure(_, _, _, span, _) = - self.infcx.tcx.hir.expect_expr(node_id).node - { - span - } else { - return OtherUse(use_span); - }; + if let StatementKind::Assign( + _, box Rvalue::Aggregate(ref kind, ref places) + ) = stmt.kind { + let (def_id, is_generator) = match kind { + box AggregateKind::Closure(def_id, _) => (def_id, false), + box AggregateKind::Generator(def_id, _, _) => (def_id, true), + _ => continue, + }; - self.infcx - .tcx - .with_freevars(node_id, |freevars| { - for (v, place) in freevars.iter().zip(places) { - match *place { - Operand::Copy(Place::Local(l)) - | Operand::Move(Place::Local(l)) if local == l => - { - debug!( - "find_closure_borrow_span: found captured local \ - {:?}", - l - ); - return Some(v.span); - } - _ => {} - } - } - None - }) - .map(|var_span| ClosureUse { - args_span, - var_span, - }) - .unwrap_or(OtherUse(use_span)) - } else { - OtherUse(use_span) + debug!( + "borrow_spans: def_id={:?} is_generator={:?} places={:?}", + def_id, is_generator, places + ); + if let Some((args_span, var_span)) = self.closure_span( + *def_id, &Place::Local(target), places + ) { + return ClosureUse { + is_generator, + args_span, + var_span, }; + } else { + return OtherUse(use_span); } } @@ -1998,6 +2134,47 @@ pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpan OtherUse(use_span) } + /// Finds the span of a captured variable within a closure or generator. + fn closure_span( + &self, + def_id: DefId, + target_place: &Place<'tcx>, + places: &Vec>, + ) -> Option<(Span, Span)> { + debug!( + "closure_span: def_id={:?} target_place={:?} places={:?}", + def_id, target_place, places + ); + let node_id = self.infcx.tcx.hir.as_local_node_id(def_id)?; + let expr = &self.infcx.tcx.hir.expect_expr(node_id).node; + debug!("closure_span: node_id={:?} expr={:?}", node_id, expr); + if let hir::ExprKind::Closure( + .., args_span, _ + ) = expr { + let var_span = self.infcx.tcx.with_freevars( + node_id, + |freevars| { + for (v, place) in freevars.iter().zip(places) { + match place { + Operand::Copy(place) | + Operand::Move(place) if target_place == place => { + debug!("closure_span: found captured local {:?}", place); + return Some(v.span); + }, + _ => {} + } + } + + None + }, + )?; + + Some((*args_span, var_span)) + } else { + None + } + } + /// Helper to retrieve span(s) of given borrow from the current MIR /// representation pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData) -> UseSpans { diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index aa559c96ec6..52c557b83d5 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -148,7 +148,7 @@ fn check_rvalue( Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) => { check_place(tcx, mir, place, span, PlaceMode::Read) } - Rvalue::Cast(_, operand, cast_ty) => { + Rvalue::Cast(CastKind::Misc, operand, cast_ty) => { use rustc::ty::cast::CastTy; let cast_in = CastTy::from_ty(operand.ty(mir, tcx)).expect("bad input type for cast"); let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); @@ -163,6 +163,16 @@ fn check_rvalue( _ => check_operand(tcx, mir, operand, span), } } + Rvalue::Cast(CastKind::UnsafeFnPointer, _, _) | + Rvalue::Cast(CastKind::ClosureFnPointer, _, _) | + Rvalue::Cast(CastKind::ReifyFnPointer, _, _) => Err(( + span, + "function pointer casts are not allowed in const fn".into(), + )), + Rvalue::Cast(CastKind::Unsize, _, _) => Err(( + span, + "unsizing casts are not allowed in const fn".into(), + )), // binops are fine on integers Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => { check_operand(tcx, mir, lhs, span)?; @@ -177,8 +187,11 @@ fn check_rvalue( )) } } - // checked by regular const fn checks - Rvalue::NullaryOp(..) => Ok(()), + Rvalue::NullaryOp(NullOp::SizeOf, _) => Ok(()), + Rvalue::NullaryOp(NullOp::Box, _) => Err(( + span, + "heap allocations are not allowed in const fn".into(), + )), Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(mir, tcx); if ty.is_integral() || ty.is_bool() { diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs index 2616d0cd964..d5c655a3de4 100644 --- a/src/librustc_mir/util/borrowck_errors.rs +++ b/src/librustc_mir/util/borrowck_errors.rs @@ -221,6 +221,7 @@ fn cannot_uniquely_borrow_by_two_closures( fn cannot_uniquely_borrow_by_one_closure( self, new_loan_span: Span, + container_name: &str, desc_new: &str, opt_via: &str, old_loan_span: Span, @@ -241,7 +242,7 @@ fn cannot_uniquely_borrow_by_one_closure( ); err.span_label( new_loan_span, - format!("closure construction occurs here{}", opt_via), + format!("{} construction occurs here{}", container_name, opt_via), ); err.span_label(old_loan_span, format!("borrow occurs here{}", old_opt_via)); if let Some(previous_end_span) = previous_end_span { @@ -253,6 +254,7 @@ fn cannot_uniquely_borrow_by_one_closure( fn cannot_reborrow_already_uniquely_borrowed( self, new_loan_span: Span, + container_name: &str, desc_new: &str, opt_via: &str, kind_new: &str, @@ -275,7 +277,7 @@ fn cannot_reborrow_already_uniquely_borrowed( err.span_label(new_loan_span, format!("borrow occurs here{}", opt_via)); err.span_label( old_loan_span, - format!("closure construction occurs here{}", old_opt_via), + format!("{} construction occurs here{}", container_name, old_opt_via), ); if let Some(previous_end_span) = previous_end_span { err.span_label(previous_end_span, "borrow from closure ends here"); diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 25a7ff9cd3f..e2f5829d14f 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -139,7 +139,7 @@ fn build_reduced_graph_for_use_tree( let prefix_iter = || parent_prefix.iter().cloned() .chain(use_tree.prefix.segments.iter().map(|seg| seg.ident)); - let prefix_start = prefix_iter().nth(0); + let prefix_start = prefix_iter().next(); let starts_with_non_keyword = prefix_start.map_or(false, |ident| { !ident.is_path_segment_keyword() }); @@ -1048,13 +1048,10 @@ fn visit_trait_item(&mut self, item: &'a TraitItem) { fn visit_token(&mut self, t: Token) { if let Token::Interpolated(nt) = t { - match nt.0 { - token::NtExpr(ref expr) => { - if let ast::ExprKind::Mac(..) = expr.node { - self.visit_invoc(expr.id); - } + if let token::NtExpr(ref expr) = nt.0 { + if let ast::ExprKind::Mac(..) = expr.node { + self.visit_invoc(expr.id); } - _ => {} } } } diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index de9481579e2..6f3135b37cf 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -109,7 +109,7 @@ fn visit_use_tree(&mut self, use_tree: &'a ast::UseTree, id: ast::NodeId, nested self.item_span }; - if items.len() == 0 { + if items.is_empty() { self.unused_imports .entry(self.base_id) .or_default() @@ -170,7 +170,7 @@ pub fn check_crate(resolver: &mut Resolver, krate: &ast::Crate) { for (id, spans) in &visitor.unused_imports { let len = spans.len(); - let mut spans = spans.values().map(|s| *s).collect::>(); + let mut spans = spans.values().cloned().collect::>(); spans.sort(); let ms = MultiSpan::from_spans(spans.clone()); let mut span_snippets = spans.iter() @@ -183,7 +183,7 @@ pub fn check_crate(resolver: &mut Resolver, krate: &ast::Crate) { span_snippets.sort(); let msg = format!("unused import{}{}", if len > 1 { "s" } else { "" }, - if span_snippets.len() > 0 { + if !span_snippets.is_empty() { format!(": {}", span_snippets.join(", ")) } else { String::new() diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index ac0616e50b0..bf3fbdc2c5a 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1633,19 +1633,17 @@ fn resolve_hir_path_cb(&mut self, path: &mut hir::Path, is_value: bool, error *def = module.def().unwrap(), PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => *def = path_res.base_def(), - PathResult::NonModule(..) => match self.resolve_path( - None, - &path, - None, - true, - span, - CrateLint::No, - ) { - PathResult::Failed(span, msg, _) => { + PathResult::NonModule(..) => + if let PathResult::Failed(span, msg, _) = self.resolve_path( + None, + &path, + None, + true, + span, + CrateLint::No, + ) { error_callback(self, span, ResolutionError::FailedToResolve(&msg)); - } - _ => {} - }, + }, PathResult::Module(ModuleOrUniformRoot::UniformRoot(_)) | PathResult::Indeterminate => unreachable!(), PathResult::Failed(span, msg, _) => { @@ -2357,7 +2355,7 @@ fn resolve_use_tree( span: prefix.span.to(use_tree.prefix.span), }; - if items.len() == 0 { + if items.is_empty() { // Resolve prefix of an import with empty braces (issue #28388). self.smart_resolve_path_with_crate_lint( id, @@ -2696,7 +2694,7 @@ fn check_consistent_bindings(&mut self, pats: &[P]) { let map_j = self.binding_mode_map(&q); for (&key, &binding_i) in &map_i { - if map_j.len() == 0 { // Account for missing bindings when + if map_j.is_empty() { // Account for missing bindings when let binding_error = missing_vars // map_j has none. .entry(key.name) .or_insert(BindingError { @@ -2757,9 +2755,8 @@ fn resolve_arm(&mut self, arm: &Arm) { // This has to happen *after* we determine which pat_idents are variants self.check_consistent_bindings(&arm.pats); - match arm.guard { - Some(ast::Guard::If(ref expr)) => self.visit_expr(expr), - _ => {} + if let Some(ast::Guard::If(ref expr)) = arm.guard { + self.visit_expr(expr) } self.visit_expr(&arm.body); @@ -3000,14 +2997,14 @@ fn smart_resolve_path_fragment(&mut self, // Make the base error. let expected = source.descr_expected(); let path_str = names_to_string(path); - let item_str = path[path.len() - 1]; + let item_str = path.last().unwrap(); let code = source.error_code(def.is_some()); let (base_msg, fallback_label, base_span) = if let Some(def) = def { (format!("expected {}, found {} `{}`", expected, def.kind_name(), path_str), format!("not a {}", expected), span) } else { - let item_span = path[path.len() - 1].span; + let item_span = path.last().unwrap().span; let (mod_prefix, mod_str) = if path.len() == 1 { (String::new(), "this scope".to_string()) } else if path.len() == 2 && path[0].name == keywords::CrateRoot.name() { @@ -3030,10 +3027,7 @@ fn smart_resolve_path_fragment(&mut self, let mut err = this.session.struct_span_err_with_code(base_span, &base_msg, code); // Emit help message for fake-self from other languages like `this`(javascript) - let fake_self: Vec = ["this", "my"].iter().map( - |s| Ident::from_str(*s) - ).collect(); - if fake_self.contains(&item_str) + if ["this", "my"].contains(&&*item_str.as_str()) && this.self_value_is_available(path[0].span, span) { err.span_suggestion_with_applicability( span, @@ -3374,7 +3368,7 @@ fn type_ascription_suggestion(&self, ); } break; - } else if snippet.trim().len() != 0 { + } else if !snippet.trim().is_empty() { debug!("tried to find type ascription `:` token, couldn't find it"); break; } @@ -3936,7 +3930,7 @@ fn adjust_local_def(&mut self, } _ => {} } - return def; + def } fn lookup_assoc_candidate(&mut self, @@ -4386,10 +4380,9 @@ fn lookup_import_candidates_from_module(&mut self, where FilterFn: Fn(Def) -> bool { let mut candidates = Vec::new(); - let mut worklist = Vec::new(); let mut seen_modules = FxHashSet(); let not_local_module = crate_name != keywords::Crate.ident(); - worklist.push((start_module, Vec::::new(), not_local_module)); + let mut worklist = vec![(start_module, Vec::::new(), not_local_module)]; while let Some((in_module, path_segments, @@ -4476,33 +4469,24 @@ fn lookup_import_candidates(&mut self, -> Vec where FilterFn: Fn(Def) -> bool { - let mut suggestions = vec![]; - - suggestions.extend( - self.lookup_import_candidates_from_module( - lookup_name, namespace, self.graph_root, keywords::Crate.ident(), &filter_fn - ) - ); + let mut suggestions = self.lookup_import_candidates_from_module( + lookup_name, namespace, self.graph_root, keywords::Crate.ident(), &filter_fn); if self.session.rust_2018() { let extern_prelude_names = self.extern_prelude.clone(); for &name in extern_prelude_names.iter() { let ident = Ident::with_empty_ctxt(name); - match self.crate_loader.maybe_process_path_extern(name, ident.span) { - Some(crate_id) => { - let crate_root = self.get_module(DefId { - krate: crate_id, - index: CRATE_DEF_INDEX, - }); - self.populate_module_if_necessary(&crate_root); + if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(name, + ident.span) + { + let crate_root = self.get_module(DefId { + krate: crate_id, + index: CRATE_DEF_INDEX, + }); + self.populate_module_if_necessary(&crate_root); - suggestions.extend( - self.lookup_import_candidates_from_module( - lookup_name, namespace, crate_root, ident, &filter_fn - ) - ); - } - None => {} + suggestions.extend(self.lookup_import_candidates_from_module( + lookup_name, namespace, crate_root, ident, &filter_fn)); } } } @@ -4515,9 +4499,8 @@ fn find_module(&mut self, -> Option<(Module<'a>, ImportSuggestion)> { let mut result = None; - let mut worklist = Vec::new(); let mut seen_modules = FxHashSet(); - worklist.push((self.graph_root, Vec::new())); + let mut worklist = vec![(self.graph_root, Vec::new())]; while let Some((in_module, path_segments)) = worklist.pop() { // abort if the module is already found diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 6c57e6c88ab..28284a45bcd 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -203,9 +203,7 @@ fn visit_ast_fragment_with_placeholders(&mut self, mark: Mark, fragment: &AstFra self.current_module = invocation.module.get(); self.current_module.unresolved_invocations.borrow_mut().remove(&mark); self.current_module.unresolved_invocations.borrow_mut().extend(derives); - for &derive in derives { - self.invocations.insert(derive, invocation); - } + self.invocations.extend(derives.iter().map(|&derive| (derive, invocation))); let mut visitor = BuildReducedGraphVisitor { resolver: self, current_legacy_scope: invocation.parent_legacy_scope.get(), @@ -277,11 +275,12 @@ fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec, allow_deri if traits.is_empty() { attrs.remove(i); } else { - let mut tokens = Vec::new(); + let mut tokens = Vec::with_capacity(traits.len() - 1); for (j, path) in traits.iter().enumerate() { if j > 0 { tokens.push(TokenTree::Token(attrs[i].span, Token::Comma).into()); } + tokens.reserve((path.segments.len() * 2).saturating_sub(1)); for (k, segment) in path.segments.iter().enumerate() { if k > 0 { tokens.push(TokenTree::Token(path.span, Token::ModSep).into()); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 48f312ce9f2..d5d772e1359 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -672,7 +672,7 @@ struct UniformPathsCanaryResults<'a> { }; let has_explicit_self = - import.module_path.len() > 0 && + !import.module_path.is_empty() && import.module_path[0].name == keywords::SelfValue.name(); self.per_ns(|_, ns| { @@ -703,9 +703,8 @@ struct UniformPathsCanaryResults<'a> { if let SingleImport { source, ref result, .. } = import.subclass { if source.name == "self" { // Silence `unresolved import` error if E0429 is already emitted - match result.value_ns.get() { - Err(Determined) => continue, - _ => {}, + if let Err(Determined) = result.value_ns.get() { + continue; } } } @@ -822,20 +821,19 @@ struct UniformPathsCanaryResults<'a> { fn throw_unresolved_import_error(&self, error_vec: Vec<(Span, String, String)>, span: Option) { let max_span_label_msg_count = 10; // upper limit on number of span_label message. - let (span,msg) = match error_vec.is_empty() { - true => (span.unwrap(), "unresolved import".to_string()), - false => { - let span = MultiSpan::from_spans(error_vec.clone().into_iter() - .map(|elem: (Span, String, String)| { elem.0 } - ).collect()); - let path_vec: Vec = error_vec.clone().into_iter() - .map(|elem: (Span, String, String)| { format!("`{}`", elem.1) } - ).collect(); - let path = path_vec.join(", "); - let msg = format!("unresolved import{} {}", - if path_vec.len() > 1 { "s" } else { "" }, path); - (span, msg) - } + let (span, msg) = if error_vec.is_empty() { + (span.unwrap(), "unresolved import".to_string()) + } else { + let span = MultiSpan::from_spans(error_vec.clone().into_iter() + .map(|elem: (Span, String, String)| { elem.0 }) + .collect()); + let path_vec: Vec = error_vec.clone().into_iter() + .map(|elem: (Span, String, String)| { format!("`{}`", elem.1) }) + .collect(); + let path = path_vec.join(", "); + let msg = format!("unresolved import{} {}", + if path_vec.len() > 1 { "s" } else { "" }, path); + (span, msg) }; let mut err = struct_span_err!(self.resolver.session, span, E0432, "{}", &msg); for span_error in error_vec.into_iter().take(max_span_label_msg_count) { @@ -1026,9 +1024,8 @@ fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Spa if all_ns_err { let mut all_ns_failed = true; self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS { - match this.resolve_ident_in_module(module, ident, ns, record_used, span) { - Ok(_) => all_ns_failed = false, - _ => {} + if this.resolve_ident_in_module(module, ident, ns, record_used, span).is_ok() { + all_ns_failed = false; } }); @@ -1247,65 +1244,62 @@ fn finalize_resolutions_in(&mut self, module: Module<'b>) { } } - match binding.kind { - NameBindingKind::Import { binding: orig_binding, directive, .. } => { - if ns == TypeNS && orig_binding.is_variant() && - !orig_binding.vis.is_at_least(binding.vis, &*self) { - let msg = match directive.subclass { - ImportDirectiveSubclass::SingleImport { .. } => { - format!("variant `{}` is private and cannot be re-exported", - ident) - }, - ImportDirectiveSubclass::GlobImport { .. } => { - let msg = "enum is private and its variants \ - cannot be re-exported".to_owned(); - let error_id = (DiagnosticMessageId::ErrorId(0), // no code?! - Some(binding.span), - msg.clone()); - let fresh = self.session.one_time_diagnostics - .borrow_mut().insert(error_id); - if !fresh { - continue; - } - msg - }, - ref s @ _ => bug!("unexpected import subclass {:?}", s) - }; - let mut err = self.session.struct_span_err(binding.span, &msg); - - let imported_module = match directive.imported_module.get() { - Some(ModuleOrUniformRoot::Module(module)) => module, - _ => bug!("module should exist"), - }; - let resolutions = imported_module.parent.expect("parent should exist") - .resolutions.borrow(); - let enum_path_segment_index = directive.module_path.len() - 1; - let enum_ident = directive.module_path[enum_path_segment_index]; - - let enum_resolution = resolutions.get(&(enum_ident, TypeNS)) - .expect("resolution should exist"); - let enum_span = enum_resolution.borrow() - .binding.expect("binding should exist") - .span; - let enum_def_span = self.session.source_map().def_span(enum_span); - let enum_def_snippet = self.session.source_map() - .span_to_snippet(enum_def_span).expect("snippet should exist"); - // potentially need to strip extant `crate`/`pub(path)` for suggestion - let after_vis_index = enum_def_snippet.find("enum") - .expect("`enum` keyword should exist in snippet"); - let suggestion = format!("pub {}", - &enum_def_snippet[after_vis_index..]); - - self.session - .diag_span_suggestion_once(&mut err, - DiagnosticMessageId::ErrorId(0), - enum_def_span, - "consider making the enum public", - suggestion); - err.emit(); - } + if let NameBindingKind::Import { binding: orig_binding, directive, .. } = binding.kind { + if ns == TypeNS && orig_binding.is_variant() && + !orig_binding.vis.is_at_least(binding.vis, &*self) { + let msg = match directive.subclass { + ImportDirectiveSubclass::SingleImport { .. } => { + format!("variant `{}` is private and cannot be re-exported", + ident) + }, + ImportDirectiveSubclass::GlobImport { .. } => { + let msg = "enum is private and its variants \ + cannot be re-exported".to_owned(); + let error_id = (DiagnosticMessageId::ErrorId(0), // no code?! + Some(binding.span), + msg.clone()); + let fresh = self.session.one_time_diagnostics + .borrow_mut().insert(error_id); + if !fresh { + continue; + } + msg + }, + ref s @ _ => bug!("unexpected import subclass {:?}", s) + }; + let mut err = self.session.struct_span_err(binding.span, &msg); + + let imported_module = match directive.imported_module.get() { + Some(ModuleOrUniformRoot::Module(module)) => module, + _ => bug!("module should exist"), + }; + let resolutions = imported_module.parent.expect("parent should exist") + .resolutions.borrow(); + let enum_path_segment_index = directive.module_path.len() - 1; + let enum_ident = directive.module_path[enum_path_segment_index]; + + let enum_resolution = resolutions.get(&(enum_ident, TypeNS)) + .expect("resolution should exist"); + let enum_span = enum_resolution.borrow() + .binding.expect("binding should exist") + .span; + let enum_def_span = self.session.source_map().def_span(enum_span); + let enum_def_snippet = self.session.source_map() + .span_to_snippet(enum_def_span).expect("snippet should exist"); + // potentially need to strip extant `crate`/`pub(path)` for suggestion + let after_vis_index = enum_def_snippet.find("enum") + .expect("`enum` keyword should exist in snippet"); + let suggestion = format!("pub {}", + &enum_def_snippet[after_vis_index..]); + + self.session + .diag_span_suggestion_once(&mut err, + DiagnosticMessageId::ErrorId(0), + enum_def_span, + "consider making the enum public", + suggestion); + err.emit(); } - _ => {} } } diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 8e8340b3ed9..c3f225d1eb0 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -198,6 +198,35 @@ pub fn signum(self) -> f32 { } } + /// Returns a number composed of the magnitude of one number and the sign of + /// another. + /// + /// Equal to `self` if the sign of `self` and `y` are the same, otherwise + /// equal to `-y`. If `self` is a `NAN`, then a `NAN` with the sign of `y` + /// is returned. + /// + /// # Examples + /// + /// ``` + /// #![feature(copysign)] + /// use std::f32; + /// + /// let f = 3.5_f32; + /// + /// assert_eq!(f.copysign(0.42), 3.5_f32); + /// assert_eq!(f.copysign(-0.42), -3.5_f32); + /// assert_eq!((-f).copysign(0.42), 3.5_f32); + /// assert_eq!((-f).copysign(-0.42), -3.5_f32); + /// + /// assert!(f32::NAN.copysign(1.0).is_nan()); + /// ``` + #[inline] + #[must_use] + #[unstable(feature="copysign", issue="55169")] + pub fn copysign(self, y: f32) -> f32 { + unsafe { intrinsics::copysignf32(self, y) } + } + /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error, yielding a more accurate result than an unfused multiply-add. /// diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 6880294afca..da062dda77a 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -176,6 +176,35 @@ pub fn signum(self) -> f64 { } } + /// Returns a number composed of the magnitude of one number and the sign of + /// another. + /// + /// Equal to `self` if the sign of `self` and `y` are the same, otherwise + /// equal to `-y`. If `self` is a `NAN`, then a `NAN` with the sign of `y` + /// is returned. + /// + /// # Examples + /// + /// ``` + /// #![feature(copysign)] + /// use std::f64; + /// + /// let f = 3.5_f64; + /// + /// assert_eq!(f.copysign(0.42), 3.5_f64); + /// assert_eq!(f.copysign(-0.42), -3.5_f64); + /// assert_eq!((-f).copysign(0.42), 3.5_f64); + /// assert_eq!((-f).copysign(-0.42), -3.5_f64); + /// + /// assert!(f64::NAN.copysign(1.0).is_nan()); + /// ``` + #[inline] + #[must_use] + #[unstable(feature="copysign", issue="55169")] + pub fn copysign(self, y: f64) -> f64 { + unsafe { intrinsics::copysignf64(self, y) } + } + /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error, yielding a more accurate result than an unfused multiply-add. /// diff --git a/src/test/ui/closure_context/issue-42065.nll.stderr b/src/test/ui/closure_context/issue-42065.nll.stderr deleted file mode 100644 index bda8a3b85f7..00000000000 --- a/src/test/ui/closure_context/issue-42065.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0382]: use of moved value: `debug_dump_dict` - --> $DIR/issue-42065.rs:21:5 - | -LL | debug_dump_dict(); - | --------------- value moved here -LL | debug_dump_dict(); - | ^^^^^^^^^^^^^^^ value used here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs new file mode 100644 index 00000000000..3e42cb8c1b0 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs @@ -0,0 +1,5 @@ +const fn foo(a: i32) -> Vec { + vec![1, 2, 3] //~ ERROR heap allocations are not allowed in const fn +} + +fn main() {} diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr new file mode 100644 index 00000000000..f6b704370b6 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr @@ -0,0 +1,10 @@ +error: heap allocations are not allowed in const fn + --> $DIR/bad_const_fn_body_ice.rs:2:5 + | +LL | vec![1, 2, 3] //~ ERROR heap allocations are not allowed in const fn + | ^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/src/test/ui/consts/min_const_fn/cast_errors.rs b/src/test/ui/consts/min_const_fn/cast_errors.rs new file mode 100644 index 00000000000..8648cd35387 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/cast_errors.rs @@ -0,0 +1,14 @@ +fn main() {} + +const fn unsize(x: &[u8; 3]) -> &[u8] { x } +//~^ ERROR unsizing casts are not allowed in const fn +const fn closure() -> fn() { || {} } +//~^ ERROR function pointers in const fn are unstable +const fn closure2() { + (|| {}) as fn(); +//~^ ERROR function pointers in const fn are unstable +} +const fn reify(f: fn()) -> unsafe fn() { f } +//~^ ERROR function pointers in const fn are unstable +const fn reify2() { main as unsafe fn(); } +//~^ ERROR function pointers in const fn are unstable diff --git a/src/test/ui/consts/min_const_fn/cast_errors.stderr b/src/test/ui/consts/min_const_fn/cast_errors.stderr new file mode 100644 index 00000000000..ba980b7aacb --- /dev/null +++ b/src/test/ui/consts/min_const_fn/cast_errors.stderr @@ -0,0 +1,32 @@ +error: unsizing casts are not allowed in const fn + --> $DIR/cast_errors.rs:3:41 + | +LL | const fn unsize(x: &[u8; 3]) -> &[u8] { x } + | ^ + +error: function pointers in const fn are unstable + --> $DIR/cast_errors.rs:5:23 + | +LL | const fn closure() -> fn() { || {} } + | ^^^^ + +error: function pointers in const fn are unstable + --> $DIR/cast_errors.rs:8:5 + | +LL | (|| {}) as fn(); + | ^^^^^^^^^^^^^^^ + +error: function pointers in const fn are unstable + --> $DIR/cast_errors.rs:11:28 + | +LL | const fn reify(f: fn()) -> unsafe fn() { f } + | ^^^^^^^^^^^ + +error: function pointers in const fn are unstable + --> $DIR/cast_errors.rs:13:21 + | +LL | const fn reify2() { main as unsafe fn(); } + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/error-codes/E0277.stderr b/src/test/ui/error-codes/E0277.stderr index ab9020222ea..d0c089fa0f3 100644 --- a/src/test/ui/error-codes/E0277.stderr +++ b/src/test/ui/error-codes/E0277.stderr @@ -2,7 +2,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> $DIR/E0277.rs:23:6 | LL | fn f(p: Path) { } - | ^ doesn't have a size known at compile-time + | ^ borrow the `Path` instead | = help: within `std::path::Path`, the trait `std::marker::Sized` is not implemented for `[u8]` = note: to learn more, visit diff --git a/src/test/ui/generator/borrowing.nll.stderr b/src/test/ui/generator/borrowing.nll.stderr index 9d1a52a8335..52b5c9d891b 100644 --- a/src/test/ui/generator/borrowing.nll.stderr +++ b/src/test/ui/generator/borrowing.nll.stderr @@ -1,10 +1,11 @@ error[E0597]: `a` does not live long enough - --> $DIR/borrowing.rs:18:18 + --> $DIR/borrowing.rs:18:29 | LL | unsafe { (|| yield &a).resume() } - | ^^^^^^^^^^^^^ - | | - | borrowed value does not live long enough + | -----------^- + | || | + | || borrowed value does not live long enough + | |value captured here by generator | a temporary with access to the borrow is created here ... LL | //~^ ERROR: `a` does not live long enough LL | }; @@ -15,18 +16,18 @@ LL | }; = note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block. error[E0597]: `a` does not live long enough - --> $DIR/borrowing.rs:24:9 + --> $DIR/borrowing.rs:25:20 | -LL | let _b = { - | -- borrow later stored here -LL | let a = 3; -LL | / || { -LL | | yield &a -LL | | //~^ ERROR: `a` does not live long enough -LL | | } - | |_________^ borrowed value does not live long enough -LL | }; - | - `a` dropped here while still borrowed +LL | let _b = { + | -- borrow later stored here +LL | let a = 3; +LL | || { + | -- value captured here by generator +LL | yield &a + | ^ borrowed value does not live long enough +... +LL | }; + | - `a` dropped here while still borrowed error: aborting due to 2 previous errors diff --git a/src/test/ui/generator/dropck.nll.stderr b/src/test/ui/generator/dropck.nll.stderr index 2b95a5caf6d..078aaf6176a 100644 --- a/src/test/ui/generator/dropck.nll.stderr +++ b/src/test/ui/generator/dropck.nll.stderr @@ -13,21 +13,19 @@ LL | } = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `ref_` does not live long enough - --> $DIR/dropck.rs:22:11 + --> $DIR/dropck.rs:24:18 | -LL | gen = || { - | ___________^ -LL | | // but the generator can use it to drop a `Ref<'a, i32>`. -LL | | let _d = ref_.take(); //~ ERROR `ref_` does not live long enough -LL | | yield; -LL | | }; - | |_____^ borrowed value does not live long enough +LL | gen = || { + | -- value captured here by generator +LL | // but the generator can use it to drop a `Ref<'a, i32>`. +LL | let _d = ref_.take(); //~ ERROR `ref_` does not live long enough + | ^^^^ borrowed value does not live long enough ... -LL | } - | - - | | - | `ref_` dropped here while still borrowed - | borrow might be used here, when `gen` is dropped and runs the destructor for generator +LL | } + | - + | | + | `ref_` dropped here while still borrowed + | borrow might be used here, when `gen` is dropped and runs the destructor for generator | = note: values in a scope are dropped in the opposite order they are defined diff --git a/src/test/ui/generator/yield-while-iterating.nll.stderr b/src/test/ui/generator/yield-while-iterating.nll.stderr index d332df6e4ba..2f0a0589844 100644 --- a/src/test/ui/generator/yield-while-iterating.nll.stderr +++ b/src/test/ui/generator/yield-while-iterating.nll.stderr @@ -9,17 +9,15 @@ LL | yield(); error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable --> $DIR/yield-while-iterating.rs:67:20 | -LL | let mut b = || { - | _________________- -LL | | for p in &mut x { -LL | | yield p; -LL | | } -LL | | }; - | |_____- mutable borrow occurs here -LL | println!("{}", x[0]); //~ ERROR - | ^ immutable borrow occurs here -LL | b.resume(); - | - mutable borrow later used here +LL | let mut b = || { + | -- mutable borrow occurs here +LL | for p in &mut x { + | - first borrow occurs due to use of `x` in generator +... +LL | println!("{}", x[0]); //~ ERROR + | ^ immutable borrow occurs here +LL | b.resume(); + | - mutable borrow later used here error: aborting due to 2 previous errors diff --git a/src/test/ui/generator/yield-while-ref-reborrowed.nll.stderr b/src/test/ui/generator/yield-while-ref-reborrowed.nll.stderr index b5c392c51ec..8dabb3c2505 100644 --- a/src/test/ui/generator/yield-while-ref-reborrowed.nll.stderr +++ b/src/test/ui/generator/yield-while-ref-reborrowed.nll.stderr @@ -1,17 +1,15 @@ error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access --> $DIR/yield-while-ref-reborrowed.rs:45:20 | -LL | let mut b = || { - | _________________- -LL | | let a = &mut *x; -LL | | yield(); -LL | | println!("{}", a); -LL | | }; - | |_____- closure construction occurs here -LL | println!("{}", x); //~ ERROR - | ^ borrow occurs here -LL | b.resume(); - | - first borrow later used here +LL | let mut b = || { + | -- generator construction occurs here +LL | let a = &mut *x; + | - first borrow occurs due to use of `x` in generator +... +LL | println!("{}", x); //~ ERROR + | ^ borrow occurs here +LL | b.resume(); + | - first borrow later used here error: aborting due to previous error diff --git a/src/test/ui/lint/no-unused-parens-return-block.rs b/src/test/ui/lint/no-unused-parens-return-block.rs new file mode 100644 index 00000000000..37dc519a204 --- /dev/null +++ b/src/test/ui/lint/no-unused-parens-return-block.rs @@ -0,0 +1,9 @@ +// run-pass + +#![deny(unused_parens)] +#![allow(unreachable_code)] + +fn main() { + match (return) {} // ok + if (return) {} // ok +} diff --git a/src/test/ui/suggestions/path-by-value.rs b/src/test/ui/suggestions/path-by-value.rs new file mode 100644 index 00000000000..c875ca674ae --- /dev/null +++ b/src/test/ui/suggestions/path-by-value.rs @@ -0,0 +1,6 @@ +use std::path::Path; + +fn f(p: Path) { } +//~^ ERROR E0277 + +fn main() {} diff --git a/src/test/ui/suggestions/path-by-value.stderr b/src/test/ui/suggestions/path-by-value.stderr new file mode 100644 index 00000000000..338cfc990dc --- /dev/null +++ b/src/test/ui/suggestions/path-by-value.stderr @@ -0,0 +1,15 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/path-by-value.rs:3:6 + | +LL | fn f(p: Path) { } + | ^ borrow the `Path` instead + | + = help: within `std::path::Path`, the trait `std::marker::Sized` is not implemented for `[u8]` + = note: to learn more, visit + = note: required because it appears within the type `std::path::Path` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.nll.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.nll.stderr deleted file mode 100644 index f4756696b6b..00000000000 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0382]: use of moved value: `tick` - --> $DIR/unboxed-closures-infer-fnonce-call-twice.rs:20:5 - | -LL | tick(); - | ---- value moved here -LL | tick(); //~ ERROR use of moved value: `tick` - | ^^^^ value used here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.nll.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.nll.stderr deleted file mode 100644 index 95ed6736278..00000000000 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0382]: use of moved value: `tick` - --> $DIR/unboxed-closures-infer-fnonce-move-call-twice.rs:20:5 - | -LL | tick(); - | ---- value moved here -LL | tick(); //~ ERROR use of moved value: `tick` - | ^^^^ value used here after move - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`.