From e023158145ece18176a2e93420600ccda0d0bc58 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 1 Sep 2020 09:49:40 -0400 Subject: [PATCH 001/446] Permit uninhabited enums to cast into ints This essentially reverts part of #6204. --- compiler/rustc_middle/src/ty/mod.rs | 4 +++- src/test/ui/uninhabited/uninhabited-enum-cast.rs | 4 +++- src/test/ui/uninhabited/uninhabited-enum-cast.stderr | 9 --------- 3 files changed, 6 insertions(+), 11 deletions(-) delete mode 100644 src/test/ui/uninhabited/uninhabited-enum-cast.stderr diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index b6300a40b0d..3e7d370c0af 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2481,8 +2481,10 @@ impl<'tcx> AdtDef { self.variants.iter().flat_map(|v| v.fields.iter()) } + /// Whether the ADT lacks fields. Note that this includes uninhabited enums, + /// e.g., `enum Void {}` is considered payload free as well. pub fn is_payloadfree(&self) -> bool { - !self.variants.is_empty() && self.variants.iter().all(|v| v.fields.is_empty()) + self.variants.iter().all(|v| v.fields.is_empty()) } /// Return a `VariantDef` given a variant id. diff --git a/src/test/ui/uninhabited/uninhabited-enum-cast.rs b/src/test/ui/uninhabited/uninhabited-enum-cast.rs index 7e178e054cc..5a75c94c42f 100644 --- a/src/test/ui/uninhabited/uninhabited-enum-cast.rs +++ b/src/test/ui/uninhabited/uninhabited-enum-cast.rs @@ -1,7 +1,9 @@ +// check-pass + enum E {} fn f(e: E) { - println!("{}", (e as isize).to_string()); //~ ERROR non-primitive cast + println!("{}", (e as isize).to_string()); } fn main() {} diff --git a/src/test/ui/uninhabited/uninhabited-enum-cast.stderr b/src/test/ui/uninhabited/uninhabited-enum-cast.stderr deleted file mode 100644 index a9f10dfec99..00000000000 --- a/src/test/ui/uninhabited/uninhabited-enum-cast.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0605]: non-primitive cast: `E` as `isize` - --> $DIR/uninhabited-enum-cast.rs:4:20 - | -LL | println!("{}", (e as isize).to_string()); - | ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0605`. From 990a39596cf3b33e550f2045f78a62970f8d78f8 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 1 Sep 2020 10:55:49 -0400 Subject: [PATCH 002/446] Prevent ICE on uninhabited MIR interpretation --- compiler/rustc_mir/src/interpret/cast.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/interpret/cast.rs b/compiler/rustc_mir/src/interpret/cast.rs index 501a5bcddb3..cb94994fef2 100644 --- a/compiler/rustc_mir/src/interpret/cast.rs +++ b/compiler/rustc_mir/src/interpret/cast.rs @@ -139,9 +139,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // # First handle non-scalar source values. - // Handle cast from a univariant (ZST) enum. + // Handle cast from a ZST enum (0 or 1 variants). match src.layout.variants { Variants::Single { index } => { + if src.layout.abi.is_uninhabited() { + // This is dead code, because an uninhabited enum is UB to + // instantiate. + throw_ub!(Unreachable); + } if let Some(discr) = src.layout.ty.discriminant_for_variant(*self.tcx, index) { assert!(src.layout.is_zst()); let discr_layout = self.layout_of(discr.ty)?; From 05c9c0ee5dcd935f518db151bee2dc88380fb92f Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 11 Sep 2020 13:10:15 -0400 Subject: [PATCH 003/446] Modify executable checking to be more universal This uses a dummy file to check if the filesystem being used supports the executable bit in general. --- src/bootstrap/test.rs | 1 + src/tools/tidy/src/bins.rs | 54 +++++++++++++++++++++++++++++++------- src/tools/tidy/src/main.rs | 8 +++--- 3 files changed, 51 insertions(+), 12 deletions(-) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 045dda2d4cb..82a4e415b8d 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -737,6 +737,7 @@ impl Step for Tidy { let mut cmd = builder.tool_cmd(Tool::Tidy); cmd.arg(&builder.src); cmd.arg(&builder.initial_cargo); + cmd.arg(&builder.out); if builder.is_verbose() { cmd.arg("--verbose"); } diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs index 589be26dc27..62cfa85577f 100644 --- a/src/tools/tidy/src/bins.rs +++ b/src/tools/tidy/src/bins.rs @@ -9,19 +9,56 @@ use std::path::Path; // All files are executable on Windows, so just check on Unix. #[cfg(windows)] -pub fn check(_path: &Path, _bad: &mut bool) {} +pub fn check(_path: &Path, _output: &Path, _bad: &mut bool) {} #[cfg(unix)] -pub fn check(path: &Path, bad: &mut bool) { +pub fn check(path: &Path, output: &Path, bad: &mut bool) { use std::fs; use std::os::unix::prelude::*; use std::process::{Command, Stdio}; - if let Ok(contents) = fs::read_to_string("/proc/version") { - // Probably on Windows Linux Subsystem or Docker via VirtualBox, - // all files will be marked as executable, so skip checking. - if contents.contains("Microsoft") || contents.contains("boot2docker") { - return; + fn is_executable(path: &Path) -> std::io::Result { + Ok(path.metadata()?.mode() & 0o111 != 0) + } + + // We want to avoid false positives on filesystems that do not support the + // executable bit. This occurs on some versions of Window's linux subsystem, + // for example. + // + // We try to create the temporary file first in the src directory, which is + // the preferred location as it's most likely to be on the same filesystem, + // and then in the output (`build`) directory if that fails. Sometimes we + // see the source directory mounted as read-only which means we can't + // readily create a file there to test. + // + // See #36706 and #74753 for context. + let mut temp_path = path.join("tidy-test-file"); + match fs::File::create(&temp_path).or_else(|_| { + temp_path = output.join("tidy-test-file"); + fs::File::create(&temp_path) + }) { + Ok(file) => { + let exec = is_executable(&temp_path).unwrap_or(false); + std::mem::drop(file); + std::fs::remove_file(&temp_path).expect("Deleted temp file"); + if exec { + // If the file is executable, then we assume that this + // filesystem does not track executability, so skip this check. + return; + } + } + Err(e) => { + // If the directory is read-only or we otherwise don't have rights, + // just don't run this check. + // + // 30 is the "Read-only filesystem" code at least in one CI + // environment. + if e.raw_os_error() == Some(30) { + eprintln!("tidy: Skipping binary file check, read-only filesystem"); + return; + } + + panic!("unable to create temporary file `{:?}`: {:?}", temp_path, e); } } @@ -36,8 +73,7 @@ pub fn check(path: &Path, bad: &mut bool) { return; } - let metadata = t!(entry.metadata(), file); - if metadata.mode() & 0o111 != 0 { + if t!(is_executable(&file), file) { let rel_path = file.strip_prefix(path).unwrap(); let git_friendly_path = rel_path.to_str().unwrap().replace("\\", "/"); let output = Command::new("git") diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 36c9e58eb9a..e1525f8e1bf 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -13,6 +13,8 @@ use std::process; fn main() { let root_path: PathBuf = env::args_os().nth(1).expect("need path to root of repo").into(); let cargo: PathBuf = env::args_os().nth(2).expect("need path to cargo").into(); + let output_directory: PathBuf = + env::args_os().nth(3).expect("need path to output directory").into(); let src_path = root_path.join("src"); let library_path = root_path.join("library"); @@ -36,9 +38,9 @@ fn main() { unit_tests::check(&library_path, &mut bad); // Checks that need to be done for both the compiler and std libraries. - bins::check(&src_path, &mut bad); - bins::check(&compiler_path, &mut bad); - bins::check(&library_path, &mut bad); + bins::check(&src_path, &output_directory, &mut bad); + bins::check(&compiler_path, &output_directory, &mut bad); + bins::check(&library_path, &output_directory, &mut bad); style::check(&src_path, &mut bad); style::check(&compiler_path, &mut bad); From 1ff7da6551a7cdf6ace2a9d00e92bbab550334ee Mon Sep 17 00:00:00 2001 From: dylni <46035563+dylni@users.noreply.github.com> Date: Fri, 18 Sep 2020 12:17:51 -0400 Subject: [PATCH 004/446] Move `slice::check_range` to `RangeBounds` --- library/alloc/src/collections/vec_deque.rs | 2 +- library/alloc/src/lib.rs | 2 +- library/alloc/src/slice.rs | 2 - library/alloc/src/string.rs | 5 +- library/alloc/src/vec.rs | 2 +- library/core/src/ops/range.rs | 82 ++++++++++++++++++ library/core/src/slice/index.rs | 83 ++----------------- library/core/src/slice/mod.rs | 7 +- .../range-bounds-for-length.md | 10 +++ .../src/library-features/slice-check-range.md | 10 --- 10 files changed, 104 insertions(+), 101 deletions(-) create mode 100644 src/doc/unstable-book/src/library-features/range-bounds-for-length.md delete mode 100644 src/doc/unstable-book/src/library-features/slice-check-range.md diff --git a/library/alloc/src/collections/vec_deque.rs b/library/alloc/src/collections/vec_deque.rs index 65cfe9a9b49..0cb8d7a891a 100644 --- a/library/alloc/src/collections/vec_deque.rs +++ b/library/alloc/src/collections/vec_deque.rs @@ -1089,7 +1089,7 @@ impl VecDeque { where R: RangeBounds, { - let Range { start, end } = slice::check_range(self.len(), range); + let Range { start, end } = range.for_length(self.len()); let tail = self.wrap_add(self.tail, start); let head = self.wrap_add(self.tail, end); (tail, head) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 7881c101f9f..002c7702779 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -116,11 +116,11 @@ #![feature(or_patterns)] #![feature(pattern)] #![feature(ptr_internals)] +#![feature(range_bounds_for_length)] #![feature(raw_ref_op)] #![feature(rustc_attrs)] #![feature(receiver_trait)] #![feature(min_specialization)] -#![feature(slice_check_range)] #![feature(slice_ptr_get)] #![feature(slice_ptr_len)] #![feature(staged_api)] diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 79403cf8687..93501ef4085 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -91,8 +91,6 @@ use crate::borrow::ToOwned; use crate::boxed::Box; use crate::vec::Vec; -#[unstable(feature = "slice_check_range", issue = "76393")] -pub use core::slice::check_range; #[unstable(feature = "array_chunks", issue = "74985")] pub use core::slice::ArrayChunks; #[unstable(feature = "array_chunks", issue = "74985")] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 2b0ce5ede56..26124e30111 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -49,7 +49,6 @@ use core::iter::{FromIterator, FusedIterator}; use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds}; use core::ptr; -use core::slice; use core::str::{lossy, pattern::Pattern}; use crate::borrow::{Cow, ToOwned}; @@ -1507,14 +1506,14 @@ impl String { // of the vector version. The data is just plain bytes. // Because the range removal happens in Drop, if the Drain iterator is leaked, // the removal will not happen. - let Range { start, end } = slice::check_range(self.len(), range); + let Range { start, end } = range.for_length(self.len()); assert!(self.is_char_boundary(start)); assert!(self.is_char_boundary(end)); // Take out two simultaneous borrows. The &mut String won't be accessed // until iteration is over, in Drop. let self_ptr = self as *mut _; - // SAFETY: `check_range` and `is_char_boundary` do the appropriate bounds checks. + // SAFETY: `for_length` and `is_char_boundary` do the appropriate bounds checks. let chars_iter = unsafe { self.get_unchecked(start..end) }.chars(); Drain { start, end, iter: chars_iter, string: self_ptr } diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 9dbea0dc9e6..e668b17c46c 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -1312,7 +1312,7 @@ impl Vec { // the hole, and the vector length is restored to the new length. // let len = self.len(); - let Range { start, end } = slice::check_range(len, range); + let Range { start, end } = range.for_length(len); unsafe { // set self.vec length's to start, to be safe in case Drain is leaked diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 2eaf7601e54..6ad55786176 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -1,5 +1,9 @@ use crate::fmt; use crate::hash::Hash; +use crate::slice::index::{ + slice_end_index_len_fail, slice_end_index_overflow_fail, slice_index_order_fail, + slice_start_index_overflow_fail, +}; /// An unbounded range (`..`). /// @@ -729,6 +733,84 @@ pub trait RangeBounds { Unbounded => true, }) } + + /// Performs bounds-checking of this range. + /// + /// The returned [`Range`] is safe to pass to [`slice::get_unchecked`] and + /// [`slice::get_unchecked_mut`] for slices of the given length. + /// + /// [`slice::get_unchecked`]: crate::slice::get_unchecked + /// [`slice::get_unchecked_mut`]: crate::slice::get_unchecked_mut + /// + /// # Panics + /// + /// Panics if the range would be out of bounds. + /// + /// # Examples + /// + /// ``` + /// #![feature(range_bounds_for_length)] + /// + /// let v = [10, 40, 30]; + /// assert_eq!(1..2, (1..2).for_length(v.len())); + /// assert_eq!(0..2, (..2).for_length(v.len())); + /// assert_eq!(1..3, (1..).for_length(v.len())); + /// ``` + /// + /// Panics when [`Index::index`] would panic: + /// + /// ```should_panic + /// #![feature(range_bounds_for_length)] + /// + /// (2..1).for_length(3); + /// ``` + /// + /// ```should_panic + /// #![feature(range_bounds_for_length)] + /// + /// (1..4).for_length(3); + /// ``` + /// + /// ```should_panic + /// #![feature(range_bounds_for_length)] + /// + /// (1..=usize::MAX).for_length(3); + /// ``` + /// + /// [`Index::index`]: crate::ops::Index::index + #[track_caller] + #[unstable(feature = "range_bounds_for_length", issue = "76393")] + fn for_length(self, len: usize) -> Range + where + Self: RangeBounds, + { + let start: Bound<&usize> = self.start_bound(); + let start = match start { + Bound::Included(&start) => start, + Bound::Excluded(start) => { + start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) + } + Bound::Unbounded => 0, + }; + + let end: Bound<&usize> = self.end_bound(); + let end = match end { + Bound::Included(end) => { + end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) + } + Bound::Excluded(&end) => end, + Bound::Unbounded => len, + }; + + if start > end { + slice_index_order_fail(start, end); + } + if end > len { + slice_end_index_len_fail(end, len); + } + + Range { start, end } + } } use self::Bound::{Excluded, Included, Unbounded}; diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 16fcb6231dc..f1f21c1d24b 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -1,6 +1,6 @@ //! Indexing implementations for `[T]`. -use crate::ops::{self, Bound, Range, RangeBounds}; +use crate::ops; use crate::ptr; #[stable(feature = "rust1", since = "1.0.0")] @@ -37,104 +37,31 @@ fn slice_start_index_len_fail(index: usize, len: usize) -> ! { #[inline(never)] #[cold] #[track_caller] -pub(super) fn slice_end_index_len_fail(index: usize, len: usize) -> ! { +pub(crate) fn slice_end_index_len_fail(index: usize, len: usize) -> ! { panic!("range end index {} out of range for slice of length {}", index, len); } #[inline(never)] #[cold] #[track_caller] -pub(super) fn slice_index_order_fail(index: usize, end: usize) -> ! { +pub(crate) fn slice_index_order_fail(index: usize, end: usize) -> ! { panic!("slice index starts at {} but ends at {}", index, end); } #[inline(never)] #[cold] #[track_caller] -pub(super) fn slice_start_index_overflow_fail() -> ! { +pub(crate) fn slice_start_index_overflow_fail() -> ! { panic!("attempted to index slice from after maximum usize"); } #[inline(never)] #[cold] #[track_caller] -pub(super) fn slice_end_index_overflow_fail() -> ! { +pub(crate) fn slice_end_index_overflow_fail() -> ! { panic!("attempted to index slice up to maximum usize"); } -/// Performs bounds-checking of the given range. -/// The returned [`Range`] is safe to pass to [`get_unchecked`] and [`get_unchecked_mut`] -/// for slices of the given length. -/// -/// [`get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked -/// [`get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut -/// -/// # Panics -/// -/// Panics if the range is out of bounds. -/// -/// # Examples -/// -/// ``` -/// #![feature(slice_check_range)] -/// use std::slice; -/// -/// let v = [10, 40, 30]; -/// assert_eq!(1..2, slice::check_range(v.len(), 1..2)); -/// assert_eq!(0..2, slice::check_range(v.len(), ..2)); -/// assert_eq!(1..3, slice::check_range(v.len(), 1..)); -/// ``` -/// -/// Panics when [`Index::index`] would panic: -/// -/// ```should_panic -/// #![feature(slice_check_range)] -/// -/// std::slice::check_range(3, 2..1); -/// ``` -/// -/// ```should_panic -/// #![feature(slice_check_range)] -/// -/// std::slice::check_range(3, 1..4); -/// ``` -/// -/// ```should_panic -/// #![feature(slice_check_range)] -/// -/// std::slice::check_range(3, 1..=usize::MAX); -/// ``` -/// -/// [`Index::index`]: ops::Index::index -#[track_caller] -#[unstable(feature = "slice_check_range", issue = "76393")] -pub fn check_range>(len: usize, range: R) -> Range { - let start = match range.start_bound() { - Bound::Included(&start) => start, - Bound::Excluded(start) => { - start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) - } - Bound::Unbounded => 0, - }; - - let end = match range.end_bound() { - Bound::Included(end) => { - end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) - } - Bound::Excluded(&end) => end, - Bound::Unbounded => len, - }; - - if start > end { - slice_index_order_fail(start, end); - } - if end > len { - slice_end_index_len_fail(end, len); - } - - Range { start, end } -} - mod private_slice_index { use super::ops; #[stable(feature = "slice_get_slice", since = "1.28.0")] diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 8e9d1eb98a8..5ad57b23c4a 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -29,7 +29,7 @@ pub mod memchr; mod ascii; mod cmp; -mod index; +pub(crate) mod index; mod iter; mod raw; mod rotate; @@ -75,9 +75,6 @@ pub use sort::heapsort; #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use index::SliceIndex; -#[unstable(feature = "slice_check_range", issue = "76393")] -pub use index::check_range; - #[lang = "slice"] #[cfg(not(test))] impl [T] { @@ -2758,7 +2755,7 @@ impl [T] { where T: Copy, { - let Range { start: src_start, end: src_end } = check_range(self.len(), src); + let Range { start: src_start, end: src_end } = src.for_length(self.len()); let count = src_end - src_start; assert!(dest <= self.len() - count, "dest is out of bounds"); // SAFETY: the conditions for `ptr::copy` have all been checked above, diff --git a/src/doc/unstable-book/src/library-features/range-bounds-for-length.md b/src/doc/unstable-book/src/library-features/range-bounds-for-length.md new file mode 100644 index 00000000000..47a1bd8dff1 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/range-bounds-for-length.md @@ -0,0 +1,10 @@ +# `range_bounds_for_length` + +The tracking issue for this feature is: [#76393] + +------------------------ + +This adds [`RangeBounds::for_length`]. + +[#76393]: https://github.com/rust-lang/rust/issues/76393 +[`RangeBounds::for_length`]: https://doc.rust-lang.org/nightly/std/ops/trait.RangeBounds.html#method.for_length diff --git a/src/doc/unstable-book/src/library-features/slice-check-range.md b/src/doc/unstable-book/src/library-features/slice-check-range.md deleted file mode 100644 index 83e5738cf54..00000000000 --- a/src/doc/unstable-book/src/library-features/slice-check-range.md +++ /dev/null @@ -1,10 +0,0 @@ -# `slice_check_range` - -The tracking issue for this feature is: [#76393] - ------------------------- - -This adds [`slice::check_range`]. - -[#76393]: https://github.com/rust-lang/rust/issues/76393 -[`slice::check_range`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.check_range From 1095dcab96d524e700b11edf366d45a0fd173fa0 Mon Sep 17 00:00:00 2001 From: dylni <46035563+dylni@users.noreply.github.com> Date: Fri, 18 Sep 2020 12:39:10 -0400 Subject: [PATCH 005/446] Fix links --- library/core/src/ops/range.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 6ad55786176..378aad5cb9e 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -739,8 +739,8 @@ pub trait RangeBounds { /// The returned [`Range`] is safe to pass to [`slice::get_unchecked`] and /// [`slice::get_unchecked_mut`] for slices of the given length. /// - /// [`slice::get_unchecked`]: crate::slice::get_unchecked - /// [`slice::get_unchecked_mut`]: crate::slice::get_unchecked_mut + /// [`slice::get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked + /// [`slice::get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut /// /// # Panics /// From eb63168e007058dad4af758faf1dca449c049777 Mon Sep 17 00:00:00 2001 From: dylni <46035563+dylni@users.noreply.github.com> Date: Fri, 18 Sep 2020 13:05:54 -0400 Subject: [PATCH 006/446] Fix doctests --- library/core/src/ops/range.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 378aad5cb9e..d9420616b4b 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -751,6 +751,8 @@ pub trait RangeBounds { /// ``` /// #![feature(range_bounds_for_length)] /// + /// use std::ops::RangeBounds; + /// /// let v = [10, 40, 30]; /// assert_eq!(1..2, (1..2).for_length(v.len())); /// assert_eq!(0..2, (..2).for_length(v.len())); @@ -762,18 +764,24 @@ pub trait RangeBounds { /// ```should_panic /// #![feature(range_bounds_for_length)] /// + /// use std::ops::RangeBounds; + /// /// (2..1).for_length(3); /// ``` /// /// ```should_panic /// #![feature(range_bounds_for_length)] /// + /// use std::ops::RangeBounds; + /// /// (1..4).for_length(3); /// ``` /// /// ```should_panic /// #![feature(range_bounds_for_length)] /// + /// use std::ops::RangeBounds; + /// /// (1..=usize::MAX).for_length(3); /// ``` /// From f055b0bb0847ecf08fe452a270faae8324b55b05 Mon Sep 17 00:00:00 2001 From: dylni <46035563+dylni@users.noreply.github.com> Date: Fri, 18 Sep 2020 13:55:03 -0400 Subject: [PATCH 007/446] Rename method to `assert_len` --- library/alloc/src/collections/vec_deque.rs | 2 +- library/alloc/src/lib.rs | 2 +- library/alloc/src/string.rs | 4 +- library/alloc/src/vec.rs | 2 +- library/core/src/ops/range.rs | 82 +++++++++---------- library/core/src/slice/mod.rs | 2 +- .../range-bounds-assert-len.md | 10 +++ .../range-bounds-for-length.md | 10 --- 8 files changed, 57 insertions(+), 57 deletions(-) create mode 100644 src/doc/unstable-book/src/library-features/range-bounds-assert-len.md delete mode 100644 src/doc/unstable-book/src/library-features/range-bounds-for-length.md diff --git a/library/alloc/src/collections/vec_deque.rs b/library/alloc/src/collections/vec_deque.rs index 0cb8d7a891a..4d6c681e44c 100644 --- a/library/alloc/src/collections/vec_deque.rs +++ b/library/alloc/src/collections/vec_deque.rs @@ -1089,7 +1089,7 @@ impl VecDeque { where R: RangeBounds, { - let Range { start, end } = range.for_length(self.len()); + let Range { start, end } = range.assert_len(self.len()); let tail = self.wrap_add(self.tail, start); let head = self.wrap_add(self.tail, end); (tail, head) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 002c7702779..512a4a1cc1b 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -116,7 +116,7 @@ #![feature(or_patterns)] #![feature(pattern)] #![feature(ptr_internals)] -#![feature(range_bounds_for_length)] +#![feature(range_bounds_assert_len)] #![feature(raw_ref_op)] #![feature(rustc_attrs)] #![feature(receiver_trait)] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 26124e30111..7b0ec1c43c0 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1506,14 +1506,14 @@ impl String { // of the vector version. The data is just plain bytes. // Because the range removal happens in Drop, if the Drain iterator is leaked, // the removal will not happen. - let Range { start, end } = range.for_length(self.len()); + let Range { start, end } = range.assert_len(self.len()); assert!(self.is_char_boundary(start)); assert!(self.is_char_boundary(end)); // Take out two simultaneous borrows. The &mut String won't be accessed // until iteration is over, in Drop. let self_ptr = self as *mut _; - // SAFETY: `for_length` and `is_char_boundary` do the appropriate bounds checks. + // SAFETY: `assert_len` and `is_char_boundary` do the appropriate bounds checks. let chars_iter = unsafe { self.get_unchecked(start..end) }.chars(); Drain { start, end, iter: chars_iter, string: self_ptr } diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index e668b17c46c..90c2708b9c9 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -1312,7 +1312,7 @@ impl Vec { // the hole, and the vector length is restored to the new length. // let len = self.len(); - let Range { start, end } = range.for_length(len); + let Range { start, end } = range.assert_len(len); unsafe { // set self.vec length's to start, to be safe in case Drain is leaked diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index d9420616b4b..16d86c81978 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -705,35 +705,6 @@ pub trait RangeBounds { #[stable(feature = "collections_range", since = "1.28.0")] fn end_bound(&self) -> Bound<&T>; - /// Returns `true` if `item` is contained in the range. - /// - /// # Examples - /// - /// ``` - /// assert!( (3..5).contains(&4)); - /// assert!(!(3..5).contains(&2)); - /// - /// assert!( (0.0..1.0).contains(&0.5)); - /// assert!(!(0.0..1.0).contains(&f32::NAN)); - /// assert!(!(0.0..f32::NAN).contains(&0.5)); - /// assert!(!(f32::NAN..1.0).contains(&0.5)); - #[stable(feature = "range_contains", since = "1.35.0")] - fn contains(&self, item: &U) -> bool - where - T: PartialOrd, - U: ?Sized + PartialOrd, - { - (match self.start_bound() { - Included(ref start) => *start <= item, - Excluded(ref start) => *start < item, - Unbounded => true, - }) && (match self.end_bound() { - Included(ref end) => item <= *end, - Excluded(ref end) => item < *end, - Unbounded => true, - }) - } - /// Performs bounds-checking of this range. /// /// The returned [`Range`] is safe to pass to [`slice::get_unchecked`] and @@ -749,46 +720,46 @@ pub trait RangeBounds { /// # Examples /// /// ``` - /// #![feature(range_bounds_for_length)] + /// #![feature(range_bounds_assert_len)] /// /// use std::ops::RangeBounds; /// /// let v = [10, 40, 30]; - /// assert_eq!(1..2, (1..2).for_length(v.len())); - /// assert_eq!(0..2, (..2).for_length(v.len())); - /// assert_eq!(1..3, (1..).for_length(v.len())); + /// assert_eq!(1..2, (1..2).assert_len(v.len())); + /// assert_eq!(0..2, (..2).assert_len(v.len())); + /// assert_eq!(1..3, (1..).assert_len(v.len())); /// ``` /// /// Panics when [`Index::index`] would panic: /// /// ```should_panic - /// #![feature(range_bounds_for_length)] + /// #![feature(range_bounds_assert_len)] /// /// use std::ops::RangeBounds; /// - /// (2..1).for_length(3); + /// (2..1).assert_len(3); /// ``` /// /// ```should_panic - /// #![feature(range_bounds_for_length)] + /// #![feature(range_bounds_assert_len)] /// /// use std::ops::RangeBounds; /// - /// (1..4).for_length(3); + /// (1..4).assert_len(3); /// ``` /// /// ```should_panic - /// #![feature(range_bounds_for_length)] + /// #![feature(range_bounds_assert_len)] /// /// use std::ops::RangeBounds; /// - /// (1..=usize::MAX).for_length(3); + /// (1..=usize::MAX).assert_len(3); /// ``` /// /// [`Index::index`]: crate::ops::Index::index #[track_caller] - #[unstable(feature = "range_bounds_for_length", issue = "76393")] - fn for_length(self, len: usize) -> Range + #[unstable(feature = "range_bounds_assert_len", issue = "76393")] + fn assert_len(self, len: usize) -> Range where Self: RangeBounds, { @@ -819,6 +790,35 @@ pub trait RangeBounds { Range { start, end } } + + /// Returns `true` if `item` is contained in the range. + /// + /// # Examples + /// + /// ``` + /// assert!( (3..5).contains(&4)); + /// assert!(!(3..5).contains(&2)); + /// + /// assert!( (0.0..1.0).contains(&0.5)); + /// assert!(!(0.0..1.0).contains(&f32::NAN)); + /// assert!(!(0.0..f32::NAN).contains(&0.5)); + /// assert!(!(f32::NAN..1.0).contains(&0.5)); + #[stable(feature = "range_contains", since = "1.35.0")] + fn contains(&self, item: &U) -> bool + where + T: PartialOrd, + U: ?Sized + PartialOrd, + { + (match self.start_bound() { + Included(ref start) => *start <= item, + Excluded(ref start) => *start < item, + Unbounded => true, + }) && (match self.end_bound() { + Included(ref end) => item <= *end, + Excluded(ref end) => item < *end, + Unbounded => true, + }) + } } use self::Bound::{Excluded, Included, Unbounded}; diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 5ad57b23c4a..43185bae3da 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -2755,7 +2755,7 @@ impl [T] { where T: Copy, { - let Range { start: src_start, end: src_end } = src.for_length(self.len()); + let Range { start: src_start, end: src_end } = src.assert_len(self.len()); let count = src_end - src_start; assert!(dest <= self.len() - count, "dest is out of bounds"); // SAFETY: the conditions for `ptr::copy` have all been checked above, diff --git a/src/doc/unstable-book/src/library-features/range-bounds-assert-len.md b/src/doc/unstable-book/src/library-features/range-bounds-assert-len.md new file mode 100644 index 00000000000..0e95d5ded92 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/range-bounds-assert-len.md @@ -0,0 +1,10 @@ +# `range_bounds_assert_len` + +The tracking issue for this feature is: [#76393] + +------------------------ + +This adds [`RangeBounds::assert_len`]. + +[#76393]: https://github.com/rust-lang/rust/issues/76393 +[`RangeBounds::assert_len`]: https://doc.rust-lang.org/nightly/std/ops/trait.RangeBounds.html#method.assert_len diff --git a/src/doc/unstable-book/src/library-features/range-bounds-for-length.md b/src/doc/unstable-book/src/library-features/range-bounds-for-length.md deleted file mode 100644 index 47a1bd8dff1..00000000000 --- a/src/doc/unstable-book/src/library-features/range-bounds-for-length.md +++ /dev/null @@ -1,10 +0,0 @@ -# `range_bounds_for_length` - -The tracking issue for this feature is: [#76393] - ------------------------- - -This adds [`RangeBounds::for_length`]. - -[#76393]: https://github.com/rust-lang/rust/issues/76393 -[`RangeBounds::for_length`]: https://doc.rust-lang.org/nightly/std/ops/trait.RangeBounds.html#method.for_length From fd22e87afc9082522bc7b52e32d25d43c64594e6 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 18 Sep 2020 22:13:07 +0200 Subject: [PATCH 008/446] fix flag computation for `ExistentialPredicate::Projection` --- compiler/rustc_middle/src/ty/flags.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index c9a4022330a..e116f650c8d 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -160,9 +160,7 @@ impl FlagComputation { match predicate { ty::ExistentialPredicate::Trait(tr) => computation.add_substs(tr.substs), ty::ExistentialPredicate::Projection(p) => { - let mut proj_computation = FlagComputation::new(); - proj_computation.add_existential_projection(&p); - self.add_bound_computation(proj_computation); + computation.add_existential_projection(&p); } ty::ExistentialPredicate::AutoTrait(_) => {} } From 7652b4b1d9cec0ad22f529a4335d05f7d7792521 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 18 Sep 2020 22:24:53 +0200 Subject: [PATCH 009/446] guard against `skip_binder` errors during FlagComputation --- compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_middle/src/ty/flags.rs | 66 ++++++++++++------------- 2 files changed, 33 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 56746666e2f..b66c65f3b64 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -134,7 +134,7 @@ impl<'tcx> CtxtInterners<'tcx> { fn intern_predicate(&self, kind: PredicateKind<'tcx>) -> &'tcx PredicateInner<'tcx> { self.predicate .intern(kind, |kind| { - let flags = super::flags::FlagComputation::for_predicate(&kind); + let flags = super::flags::FlagComputation::for_predicate(kind); let predicate_struct = PredicateInner { kind, diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index e116f650c8d..8b97a87f214 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -22,7 +22,7 @@ impl FlagComputation { result } - pub fn for_predicate(kind: &ty::PredicateKind<'_>) -> FlagComputation { + pub fn for_predicate(kind: ty::PredicateKind<'_>) -> FlagComputation { let mut result = FlagComputation::new(); result.add_predicate_kind(kind); result @@ -53,7 +53,14 @@ impl FlagComputation { /// Adds the flags/depth from a set of types that appear within the current type, but within a /// region binder. - fn add_bound_computation(&mut self, computation: FlagComputation) { + fn bound_computation(&mut self, value: ty::Binder, f: F) + where + F: FnOnce(&mut Self, T), + { + let mut computation = FlagComputation::new(); + + f(&mut computation, value.skip_binder()); + self.add_flags(computation.flags); // The types that contributed to `computation` occurred within @@ -101,9 +108,7 @@ impl FlagComputation { } &ty::GeneratorWitness(ts) => { - let mut computation = FlagComputation::new(); - computation.add_tys(ts.skip_binder()); - self.add_bound_computation(computation); + self.bound_computation(ts, |flags, ts| flags.add_tys(ts)); } &ty::Closure(_, substs) => { @@ -154,18 +159,21 @@ impl FlagComputation { self.add_substs(substs); } - &ty::Dynamic(ref obj, r) => { - let mut computation = FlagComputation::new(); - for predicate in obj.skip_binder().iter() { - match predicate { - ty::ExistentialPredicate::Trait(tr) => computation.add_substs(tr.substs), - ty::ExistentialPredicate::Projection(p) => { - computation.add_existential_projection(&p); + &ty::Dynamic(obj, r) => { + self.bound_computation(obj, |computation, obj| { + for predicate in obj.iter() { + match predicate { + ty::ExistentialPredicate::Trait(tr) => { + computation.add_substs(tr.substs) + } + ty::ExistentialPredicate::Projection(p) => { + computation.add_existential_projection(&p); + } + ty::ExistentialPredicate::AutoTrait(_) => {} } - ty::ExistentialPredicate::AutoTrait(_) => {} } - } - self.add_bound_computation(computation); + }); + self.add_region(r); } @@ -193,22 +201,21 @@ impl FlagComputation { self.add_substs(substs); } - &ty::FnPtr(f) => { - self.add_fn_sig(f); - } + &ty::FnPtr(fn_sig) => self.bound_computation(fn_sig, |computation, fn_sig| { + computation.add_tys(fn_sig.inputs()); + computation.add_ty(fn_sig.output()); + }), } } - fn add_predicate_kind(&mut self, kind: &ty::PredicateKind<'_>) { + fn add_predicate_kind(&mut self, kind: ty::PredicateKind<'_>) { match kind { ty::PredicateKind::ForAll(binder) => { - let mut computation = FlagComputation::new(); - - computation.add_predicate_atom(binder.skip_binder()); - - self.add_bound_computation(computation); + self.bound_computation(binder, |computation, atom| { + computation.add_predicate_atom(atom) + }); } - &ty::PredicateKind::Atom(atom) => self.add_predicate_atom(atom), + ty::PredicateKind::Atom(atom) => self.add_predicate_atom(atom), } } @@ -264,15 +271,6 @@ impl FlagComputation { } } - fn add_fn_sig(&mut self, fn_sig: ty::PolyFnSig<'_>) { - let mut computation = FlagComputation::new(); - - computation.add_tys(fn_sig.skip_binder().inputs()); - computation.add_ty(fn_sig.skip_binder().output()); - - self.add_bound_computation(computation); - } - fn add_region(&mut self, r: ty::Region<'_>) { self.add_flags(r.type_flags()); if let ty::ReLateBound(debruijn, _) = *r { From dc89bb1135afc31fc9ee2272e627192c04354d22 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Wed, 10 Jun 2020 14:21:58 +1200 Subject: [PATCH 010/446] Use if_chain in Increment/InitializeVisitor --- clippy_lints/src/loops.rs | 43 +++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 7f998c63f49..9f3be26e672 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -2162,15 +2162,16 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { match parent.kind { ExprKind::AssignOp(op, ref lhs, ref rhs) => { if lhs.hir_id == expr.hir_id { - if op.node == BinOpKind::Add && is_integer_const(self.cx, rhs, 1) { - *state = match *state { - VarState::Initial if self.depth == 0 => VarState::IncrOnce, - _ => VarState::DontWarn, - }; + *state = if op.node == BinOpKind::Add + && is_integer_const(self.cx, rhs, 1) + && *state == VarState::Initial + && self.depth == 0 + { + VarState::IncrOnce } else { - // Assigned some other value - *state = VarState::DontWarn; - } + // Assigned some other value or assigned multiple times + VarState::DontWarn + }; } }, ExprKind::Assign(ref lhs, _, _) if lhs.hir_id == expr.hir_id => *state = VarState::DontWarn, @@ -2212,18 +2213,20 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) { // Look for declarations of the variable - if let StmtKind::Local(ref local) = stmt.kind { - if local.pat.hir_id == self.var_id { - if let PatKind::Binding(.., ident, _) = local.pat.kind { - self.name = Some(ident.name); - - self.state = local.init.as_ref().map_or(VarState::Declared, |init| { - if is_integer_const(&self.cx, init, 0) { - VarState::Warn - } else { - VarState::Declared - } - }) + if_chain! { + if let StmtKind::Local(ref local) = stmt.kind; + if local.pat.hir_id == self.var_id; + if let PatKind::Binding(.., ident, _) = local.pat.kind; + then { + self.name = Some(ident.name); + self.state = if_chain! { + if let Some(ref init) = local.init; + if is_integer_const(&self.cx, init, 0); + then { + VarState::Warn + } else { + VarState::Declared + } } } } From 116f30dc33d9e3744f257f2f7f5467acfbff178b Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Wed, 10 Jun 2020 14:25:06 +1200 Subject: [PATCH 011/446] Use else blocks instead of return statements in Increment/InitializeVisitor --- clippy_lints/src/loops.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 9f3be26e672..a59d3ef8708 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -2181,16 +2181,17 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { _ => (), } } + + walk_expr(self, expr); } else if is_loop(expr) || is_conditional(expr) { self.depth += 1; walk_expr(self, expr); self.depth -= 1; - return; } else if let ExprKind::Continue(_) = expr.kind { self.done = true; - return; + } else { + walk_expr(self, expr); } - walk_expr(self, expr); } fn nested_visit_map(&mut self) -> NestedVisitorMap { NestedVisitorMap::None @@ -2272,16 +2273,16 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { self.state = VarState::DontWarn; return; } + walk_expr(self, expr); } else if !self.past_loop && is_loop(expr) { self.state = VarState::DontWarn; - return; } else if is_conditional(expr) { self.depth += 1; walk_expr(self, expr); self.depth -= 1; - return; + } else { + walk_expr(self, expr); } - walk_expr(self, expr); } fn nested_visit_map(&mut self) -> NestedVisitorMap { From b2d5b89a1de15df9052fdf44d01b174add82837f Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Wed, 10 Jun 2020 14:41:09 +1200 Subject: [PATCH 012/446] Check if it's after the loop earlier --- clippy_lints/src/loops.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index a59d3ef8708..20e75546d71 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -2250,6 +2250,11 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { // If node is the desired variable, see how it's used if var_def_id(self.cx, expr) == Some(self.var_id) { + if self.past_loop { + self.state = VarState::DontWarn; + return; + } + if let Some(parent) = get_parent_expr(self.cx, expr) { match parent.kind { ExprKind::AssignOp(_, ref lhs, _) if lhs.hir_id == expr.hir_id => { @@ -2269,10 +2274,6 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { } } - if self.past_loop { - self.state = VarState::DontWarn; - return; - } walk_expr(self, expr); } else if !self.past_loop && is_loop(expr) { self.state = VarState::DontWarn; From 31cb1109648bf4242cab47571343578244e7fb9d Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Wed, 10 Jun 2020 14:48:26 +1200 Subject: [PATCH 013/446] add concinient methods to Increment/InitializeVisitor --- clippy_lints/src/loops.rs | 63 +++++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 19 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 20e75546d71..61f0059cca4 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1536,31 +1536,17 @@ fn check_for_loop_explicit_counter<'tcx>( expr: &'tcx Expr<'_>, ) { // Look for variables that are incremented once per loop iteration. - let mut visitor = IncrementVisitor { - cx, - states: FxHashMap::default(), - depth: 0, - done: false, - }; + let mut visitor = IncrementVisitor::new(cx); walk_expr(&mut visitor, body); // For each candidate, check the parent block to see if // it's initialized to zero at the start of the loop. if let Some(block) = get_enclosing_block(&cx, expr.hir_id) { - for (id, _) in visitor.states.iter().filter(|&(_, v)| *v == VarState::IncrOnce) { - let mut visitor2 = InitializeVisitor { - cx, - end_expr: expr, - var_id: *id, - state: VarState::IncrOnce, - name: None, - depth: 0, - past_loop: false, - }; + for id in visitor.into_results() { + let mut visitor2 = InitializeVisitor::new(cx, expr, id); walk_block(&mut visitor2, block); - if visitor2.state == VarState::Warn { - if let Some(name) = visitor2.name { + if let Some(name) = visitor2.get_result() { let mut applicability = Applicability::MachineApplicable; // for some reason this is the only way to get the `Span` @@ -1585,7 +1571,6 @@ fn check_for_loop_explicit_counter<'tcx>( ), applicability, ); - } } } } @@ -2142,6 +2127,24 @@ struct IncrementVisitor<'a, 'tcx> { done: bool, } +impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> { + fn new(cx: &'a LateContext<'a, 'tcx>) -> Self { + Self { + cx, + states: FxHashMap::default(), + depth: 0, + done: false, + } + } + + fn into_results(self) -> impl Iterator { + self.states + .into_iter() + .filter(|(_, state)| *state == VarState::IncrOnce) + .map(|(id, _)| id) + } +} + impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { type Map = Map<'tcx>; @@ -2209,6 +2212,28 @@ struct InitializeVisitor<'a, 'tcx> { past_loop: bool, } +impl<'a, 'tcx> InitializeVisitor<'a, 'tcx> { + fn new(cx: &'a LateContext<'a, 'tcx>, end_expr: &'tcx Expr<'tcx>, var_id: HirId) -> Self { + Self { + cx, + end_expr, + var_id, + state: VarState::IncrOnce, + name: None, + depth: 0, + past_loop: false, + } + } + + fn get_result(&self) -> Option { + if self.state == VarState::Warn { + self.name + } else { + None + } + } +} + impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { type Map = Map<'tcx>; From c599e2fcfaaedb12b560f4136bab3d0b450acf8f Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Wed, 10 Jun 2020 15:05:51 +1200 Subject: [PATCH 014/446] Split VarState --- clippy_lints/src/loops.rs | 87 +++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 39 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 61f0059cca4..2b7830e7cad 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -2107,23 +2107,18 @@ fn is_simple_break_expr(expr: &Expr<'_>) -> bool { } } -// To trigger the EXPLICIT_COUNTER_LOOP lint, a variable must be -// incremented exactly once in the loop body, and initialized to zero -// at the start of the loop. #[derive(Debug, PartialEq)] -enum VarState { +enum IncrementVisitorVarState { Initial, // Not examined yet IncrOnce, // Incremented exactly once, may be a loop counter - Declared, // Declared but not (yet) initialized to zero - Warn, DontWarn, } /// Scan a for loop for variables that are incremented exactly once and not used after that. struct IncrementVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, // context reference - states: FxHashMap, // incremented variables - depth: u32, // depth of conditional expressions + cx: &'a LateContext<'tcx>, // context reference + states: FxHashMap, // incremented variables + depth: u32, // depth of conditional expressions done: bool, } @@ -2140,7 +2135,7 @@ impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> { fn into_results(self) -> impl Iterator { self.states .into_iter() - .filter(|(_, state)| *state == VarState::IncrOnce) + .filter(|(_, state)| *state == IncrementVisitorVarState::IncrOnce) .map(|(id, _)| id) } } @@ -2156,9 +2151,9 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { // If node is a variable if let Some(def_id) = var_def_id(self.cx, expr) { if let Some(parent) = get_parent_expr(self.cx, expr) { - let state = self.states.entry(def_id).or_insert(VarState::Initial); - if *state == VarState::IncrOnce { - *state = VarState::DontWarn; + let state = self.states.entry(def_id).or_insert(IncrementVisitorVarState::Initial); + if *state == IncrementVisitorVarState::IncrOnce { + *state = IncrementVisitorVarState::DontWarn; return; } @@ -2167,19 +2162,21 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { if lhs.hir_id == expr.hir_id { *state = if op.node == BinOpKind::Add && is_integer_const(self.cx, rhs, 1) - && *state == VarState::Initial + && *state == IncrementVisitorVarState::Initial && self.depth == 0 { - VarState::IncrOnce + IncrementVisitorVarState::IncrOnce } else { // Assigned some other value or assigned multiple times - VarState::DontWarn + IncrementVisitorVarState::DontWarn }; } }, - ExprKind::Assign(ref lhs, _, _) if lhs.hir_id == expr.hir_id => *state = VarState::DontWarn, + ExprKind::Assign(ref lhs, _, _) if lhs.hir_id == expr.hir_id => { + *state = IncrementVisitorVarState::DontWarn + }, ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => { - *state = VarState::DontWarn + *state = IncrementVisitorVarState::DontWarn }, _ => (), } @@ -2201,13 +2198,20 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { } } -/// Checks whether a variable is initialized to zero at the start of a loop. +enum InitializeVisitorState { + Initial, // Not examined yet + Declared(Symbol), // Declared but not (yet) initialized + Initialized { name: Symbol }, + DontWarn, +} + +/// Checks whether a variable is initialized to zero at the start of a loop and not modified +/// and used after the loop. struct InitializeVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, // context reference end_expr: &'tcx Expr<'tcx>, // the for loop. Stop scanning here. var_id: HirId, - state: VarState, - name: Option, + state: InitializeVisitorState, depth: u32, // depth of conditional expressions past_loop: bool, } @@ -2218,16 +2222,15 @@ impl<'a, 'tcx> InitializeVisitor<'a, 'tcx> { cx, end_expr, var_id, - state: VarState::IncrOnce, - name: None, + state: InitializeVisitorState::Initial, depth: 0, past_loop: false, } } fn get_result(&self) -> Option { - if self.state == VarState::Warn { - self.name + if let InitializeVisitorState::Initialized { name } = self.state { + Some(name) } else { None } @@ -2244,23 +2247,24 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { if local.pat.hir_id == self.var_id; if let PatKind::Binding(.., ident, _) = local.pat.kind; then { - self.name = Some(ident.name); self.state = if_chain! { if let Some(ref init) = local.init; if is_integer_const(&self.cx, init, 0); then { - VarState::Warn - } else { - VarState::Declared + InitializeVisitorState::Initialized { + name: ident.name } + } else { + InitializeVisitorState::Declared(ident.name) } } } + } walk_stmt(self, stmt); } fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if self.state == VarState::DontWarn { + if matches!(self.state, InitializeVisitorState::DontWarn) { return; } if expr.hir_id == self.end_expr.hir_id { @@ -2269,31 +2273,36 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { } // No need to visit expressions before the variable is // declared - if self.state == VarState::IncrOnce { + if matches!(self.state, InitializeVisitorState::Initial) { return; } // If node is the desired variable, see how it's used if var_def_id(self.cx, expr) == Some(self.var_id) { if self.past_loop { - self.state = VarState::DontWarn; + self.state = InitializeVisitorState::DontWarn; return; } if let Some(parent) = get_parent_expr(self.cx, expr) { match parent.kind { ExprKind::AssignOp(_, ref lhs, _) if lhs.hir_id == expr.hir_id => { - self.state = VarState::DontWarn; + self.state = InitializeVisitorState::DontWarn; }, ExprKind::Assign(ref lhs, ref rhs, _) if lhs.hir_id == expr.hir_id => { - self.state = if is_integer_const(&self.cx, rhs, 0) && self.depth == 0 { - VarState::Warn - } else { - VarState::DontWarn + self.state = if_chain! { + if is_integer_const(&self.cx, rhs, 0) && self.depth == 0; + if let InitializeVisitorState::Declared(name) + | InitializeVisitorState::Initialized { name, ..} = self.state; + then { + InitializeVisitorState::Initialized { name } + } else { + InitializeVisitorState::DontWarn + } } }, ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => { - self.state = VarState::DontWarn + self.state = InitializeVisitorState::DontWarn }, _ => (), } @@ -2301,7 +2310,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { walk_expr(self, expr); } else if !self.past_loop && is_loop(expr) { - self.state = VarState::DontWarn; + self.state = InitializeVisitorState::DontWarn; } else if is_conditional(expr) { self.depth += 1; walk_expr(self, expr); From 13c207d3756754c54a6b20d852087616d5abfbf4 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Wed, 10 Jun 2020 15:14:57 +1200 Subject: [PATCH 015/446] Generalise `InitializeVisitor` --- clippy_lints/src/loops.rs | 36 +++++++++++++++++++---------------- clippy_lints/src/utils/mod.rs | 2 +- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 2b7830e7cad..bf067c70a7e 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1528,6 +1528,9 @@ fn check_arg_type(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) { } } +// To trigger the EXPLICIT_COUNTER_LOOP lint, a variable must be +// incremented exactly once in the loop body, and initialized to zero +// at the start of the loop. fn check_for_loop_explicit_counter<'tcx>( cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, @@ -1546,7 +1549,10 @@ fn check_for_loop_explicit_counter<'tcx>( let mut visitor2 = InitializeVisitor::new(cx, expr, id); walk_block(&mut visitor2, block); - if let Some(name) = visitor2.get_result() { + if_chain! { + if let Some((name, initializer)) = visitor2.get_result(); + if is_integer_const(cx, initializer, 0); + then { let mut applicability = Applicability::MachineApplicable; // for some reason this is the only way to get the `Span` @@ -1571,6 +1577,7 @@ fn check_for_loop_explicit_counter<'tcx>( ), applicability, ); + } } } } @@ -2198,20 +2205,20 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { } } -enum InitializeVisitorState { +enum InitializeVisitorState<'hir> { Initial, // Not examined yet Declared(Symbol), // Declared but not (yet) initialized - Initialized { name: Symbol }, + Initialized { name: Symbol, initializer: &'hir Expr<'hir> }, DontWarn, } -/// Checks whether a variable is initialized to zero at the start of a loop and not modified +/// Checks whether a variable is initialized at the start of a loop and not modified /// and used after the loop. struct InitializeVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, // context reference end_expr: &'tcx Expr<'tcx>, // the for loop. Stop scanning here. var_id: HirId, - state: InitializeVisitorState, + state: InitializeVisitorState<'tcx>, depth: u32, // depth of conditional expressions past_loop: bool, } @@ -2228,9 +2235,9 @@ impl<'a, 'tcx> InitializeVisitor<'a, 'tcx> { } } - fn get_result(&self) -> Option { - if let InitializeVisitorState::Initialized { name } = self.state { - Some(name) + fn get_result(&self) -> Option<(Name, &'tcx Expr<'tcx>)> { + if let InitializeVisitorState::Initialized { name, initializer } = self.state { + Some((name, initializer)) } else { None } @@ -2247,19 +2254,16 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { if local.pat.hir_id == self.var_id; if let PatKind::Binding(.., ident, _) = local.pat.kind; then { - self.state = if_chain! { - if let Some(ref init) = local.init; - if is_integer_const(&self.cx, init, 0); - then { + self.state = if let Some(ref init) = local.init { InitializeVisitorState::Initialized { - name: ident.name + initializer: init, + name: ident.name, } } else { InitializeVisitorState::Declared(ident.name) } } } - } walk_stmt(self, stmt); } @@ -2291,11 +2295,11 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { }, ExprKind::Assign(ref lhs, ref rhs, _) if lhs.hir_id == expr.hir_id => { self.state = if_chain! { - if is_integer_const(&self.cx, rhs, 0) && self.depth == 0; + if self.depth == 0; if let InitializeVisitorState::Declared(name) | InitializeVisitorState::Initialized { name, ..} = self.state; then { - InitializeVisitorState::Initialized { name } + InitializeVisitorState::Initialized { initializer: rhs, name } } else { InitializeVisitorState::DontWarn } diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 92cb31fcf85..a0ddcce111e 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -707,7 +707,7 @@ fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option, } /// Gets the parent expression, if any –- this is useful to constrain a lint. -pub fn get_parent_expr<'c>(cx: &'c LateContext<'_>, e: &Expr<'_>) -> Option<&'c Expr<'c>> { +pub fn get_parent_expr<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> { let map = &cx.tcx.hir(); let hir_id = e.hir_id; let parent_id = map.get_parent_node(hir_id); From 9573a0d378033a81e55ca834a5d305d3cf2be24d Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Wed, 10 Jun 2020 15:15:20 +1200 Subject: [PATCH 016/446] Rename variables --- clippy_lints/src/loops.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index bf067c70a7e..1c316c00f43 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1539,18 +1539,18 @@ fn check_for_loop_explicit_counter<'tcx>( expr: &'tcx Expr<'_>, ) { // Look for variables that are incremented once per loop iteration. - let mut visitor = IncrementVisitor::new(cx); - walk_expr(&mut visitor, body); + let mut increment_visitor = IncrementVisitor::new(cx); + walk_expr(&mut increment_visitor, body); // For each candidate, check the parent block to see if // it's initialized to zero at the start of the loop. if let Some(block) = get_enclosing_block(&cx, expr.hir_id) { - for id in visitor.into_results() { - let mut visitor2 = InitializeVisitor::new(cx, expr, id); - walk_block(&mut visitor2, block); + for id in increment_visitor.into_results() { + let mut initialize_visitor = InitializeVisitor::new(cx, expr, id); + walk_block(&mut initialize_visitor, block); if_chain! { - if let Some((name, initializer)) = visitor2.get_result(); + if let Some((name, initializer)) = initialize_visitor.get_result(); if is_integer_const(cx, initializer, 0); then { let mut applicability = Applicability::MachineApplicable; From 1026b42f0694eb9239b5cebe80be743d5ded0da5 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Wed, 10 Jun 2020 15:32:24 +1200 Subject: [PATCH 017/446] Rename a struct and variables --- clippy_lints/src/loops.rs | 65 ++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 1c316c00f43..d9896f7fd6b 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -820,9 +820,9 @@ impl Offset { } } -struct FixedOffsetVar<'hir> { - var: &'hir Expr<'hir>, - offset: Offset, +struct IndexExpr<'hir> { + base: &'hir Expr<'hir>, + idx_offset: Offset, } fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'_>) -> bool { @@ -845,14 +845,14 @@ fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { } } -fn get_offset<'tcx>(cx: &LateContext<'tcx>, idx: &Expr<'_>, var: HirId) -> Option { - fn extract_offset<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>, var: HirId) -> Option { +fn get_offset<'tcx>(cx: &LateContext<'tcx>, idx: &Expr<'_>, start: HirId) -> Option { + fn extract_offset<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>, start: HirId) -> Option { match &e.kind { ExprKind::Lit(l) => match l.node { ast::LitKind::Int(x, _ty) => Some(x.to_string()), _ => None, }, - ExprKind::Path(..) if !same_var(cx, e, var) => Some(snippet_opt(cx, e.span).unwrap_or_else(|| "??".into())), + ExprKind::Path(..) if !same_var(cx, e, start) => Some(snippet_opt(cx, e.span).unwrap_or_else(|| "??".into())), _ => None, } } @@ -860,20 +860,20 @@ fn get_offset<'tcx>(cx: &LateContext<'tcx>, idx: &Expr<'_>, var: HirId) -> Optio match idx.kind { ExprKind::Binary(op, lhs, rhs) => match op.node { BinOpKind::Add => { - let offset_opt = if same_var(cx, lhs, var) { - extract_offset(cx, rhs, var) - } else if same_var(cx, rhs, var) { - extract_offset(cx, lhs, var) + let offset_opt = if same_var(cx, lhs, start) { + extract_offset(cx, rhs, start) + } else if same_var(cx, rhs, start) { + extract_offset(cx, lhs, start) } else { None }; offset_opt.map(Offset::positive) }, - BinOpKind::Sub if same_var(cx, lhs, var) => extract_offset(cx, rhs, var).map(Offset::negative), + BinOpKind::Sub if same_var(cx, lhs, start) => extract_offset(cx, rhs, start).map(Offset::negative), _ => None, }, - ExprKind::Path(..) if same_var(cx, idx, var) => Some(Offset::positive("0".into())), + ExprKind::Path(..) if same_var(cx, idx, start) => Some(Offset::positive("0".into())), _ => None, } } @@ -916,8 +916,8 @@ fn build_manual_memcpy_suggestion<'tcx>( start: &Expr<'_>, end: &Expr<'_>, limits: ast::RangeLimits, - dst_var: FixedOffsetVar<'_>, - src_var: FixedOffsetVar<'_>, + dst: IndexExpr<'_>, + src: IndexExpr<'_>, ) -> String { fn print_sum(arg1: &str, arg2: &Offset) -> String { match (arg1, &arg2.value[..], arg2.sign) { @@ -944,13 +944,13 @@ fn build_manual_memcpy_suggestion<'tcx>( } } - let print_limit = |end: &Expr<'_>, offset: Offset, var: &Expr<'_>| { + let print_limit = |end: &Expr<'_>, offset: Offset, base: &Expr<'_>| { if_chain! { if let ExprKind::MethodCall(method, _, len_args, _) = end.kind; if method.ident.name == sym!(len); if len_args.len() == 1; if let Some(arg) = len_args.get(0); - if var_def_id(cx, arg) == var_def_id(cx, var); + if var_def_id(cx, arg) == var_def_id(cx, base); then { match offset.sign { OffsetSign::Negative => format!("({} - {})", snippet(cx, end.span, ".len()"), offset.value), @@ -971,25 +971,26 @@ fn build_manual_memcpy_suggestion<'tcx>( }; let start_str = snippet(cx, start.span, "").to_string(); - let dst_offset = print_offset(&start_str, &dst_var.offset); - let dst_limit = print_limit(end, dst_var.offset, dst_var.var); - let src_offset = print_offset(&start_str, &src_var.offset); - let src_limit = print_limit(end, src_var.offset, src_var.var); + let dst_offset = print_offset(&start_str, &dst.idx_offset); + let dst_limit = print_limit(end, dst.idx_offset, dst.base); + let src_offset = print_offset(&start_str, &src.idx_offset); + let src_limit = print_limit(end, src.idx_offset, src.base); - let dst_var_name = snippet_opt(cx, dst_var.var.span).unwrap_or_else(|| "???".into()); - let src_var_name = snippet_opt(cx, src_var.var.span).unwrap_or_else(|| "???".into()); + let dst_base_str = snippet_opt(cx, dst.base.span).unwrap_or_else(|| "???".into()); + let src_base_str = snippet_opt(cx, src.base.span).unwrap_or_else(|| "???".into()); let dst = if dst_offset == "" && dst_limit == "" { - dst_var_name + dst_base_str } else { - format!("{}[{}..{}]", dst_var_name, dst_offset, dst_limit) + format!("{}[{}..{}]", dst_base_str, dst_offset, dst_limit) }; format!( "{}.clone_from_slice(&{}[{}..{}])", - dst, src_var_name, src_offset, src_limit + dst, src_base_str, src_offset, src_limit ) } + /// Checks for for loops that sequentially copy items from one slice-like /// object to another. fn detect_manual_memcpy<'tcx>( @@ -1014,18 +1015,18 @@ fn detect_manual_memcpy<'tcx>( o.and_then(|(lhs, rhs)| { let rhs = fetch_cloned_expr(rhs); if_chain! { - if let ExprKind::Index(seqexpr_left, idx_left) = lhs.kind; - if let ExprKind::Index(seqexpr_right, idx_right) = rhs.kind; - if is_slice_like(cx, cx.typeck_results().expr_ty(seqexpr_left)) - && is_slice_like(cx, cx.typeck_results().expr_ty(seqexpr_right)); + if let ExprKind::Index(base_left, idx_left) = lhs.kind; + if let ExprKind::Index(base_right, idx_right) = rhs.kind; + if is_slice_like(cx, cx.typeck_results().expr_ty(base_left)) + && is_slice_like(cx, cx.typeck_results().expr_ty(base_right)); if let Some(offset_left) = get_offset(cx, &idx_left, canonical_id); if let Some(offset_right) = get_offset(cx, &idx_right, canonical_id); // Source and destination must be different - if var_def_id(cx, seqexpr_left) != var_def_id(cx, seqexpr_right); + if var_def_id(cx, base_left) != var_def_id(cx, base_right); then { - Some((FixedOffsetVar { var: seqexpr_left, offset: offset_left }, - FixedOffsetVar { var: seqexpr_right, offset: offset_right })) + Some((IndexExpr { base: base_left, idx_offset: offset_left }, + IndexExpr { base: base_right, idx_offset: offset_right })) } else { None } From b4b4da162f19e9a4c63854a2b5a6167b83f9d8b9 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Wed, 10 Jun 2020 15:51:23 +1200 Subject: [PATCH 018/446] Introduce Start and StartKind --- clippy_lints/src/loops.rs | 67 +++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 14 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index d9896f7fd6b..157dff59d44 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -818,13 +818,29 @@ impl Offset { sign: OffsetSign::Positive, } } + + fn empty() -> Self { + Self::positive("0".into()) + } +} + +#[derive(Debug, Clone, Copy)] +enum StartKind<'hir> { + Range, + Counter { initializer: &'hir Expr<'hir> }, } struct IndexExpr<'hir> { base: &'hir Expr<'hir>, + idx: StartKind<'hir>, idx_offset: Offset, } +struct Start<'hir> { + id: HirId, + kind: StartKind<'hir>, +} + fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'_>) -> bool { let is_slice = match ty.kind() { ty::Ref(_, subty, _) => is_slice_like(cx, subty), @@ -845,14 +861,32 @@ fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { } } -fn get_offset<'tcx>(cx: &LateContext<'tcx>, idx: &Expr<'_>, start: HirId) -> Option { - fn extract_offset<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>, start: HirId) -> Option { +fn get_offset<'tcx>( + cx: &LateContext<'tcx>, + idx: &Expr<'_>, + starts: &[Start<'tcx>], +) -> Option<(StartKind<'tcx>, Offset)> { + fn extract_start<'tcx>( + cx: &LateContext<'tcx>, + expr: &Expr<'_>, + starts: &[Start<'tcx>], + ) -> Option> { + starts.iter().find(|var| same_var(cx, expr, var.id)).map(|v| v.kind) + } + + fn extract_offset<'tcx>( + cx: &LateContext<'tcx>, + e: &Expr<'_>, + starts: &[Start<'tcx>], + ) -> Option { match &e.kind { ExprKind::Lit(l) => match l.node { ast::LitKind::Int(x, _ty) => Some(x.to_string()), _ => None, }, - ExprKind::Path(..) if !same_var(cx, e, start) => Some(snippet_opt(cx, e.span).unwrap_or_else(|| "??".into())), + ExprKind::Path(..) if extract_start(cx, e, starts).is_none() => { + Some(snippet_opt(cx, e.span).unwrap_or_else(|| "??".into())) + }, _ => None, } } @@ -860,20 +894,21 @@ fn get_offset<'tcx>(cx: &LateContext<'tcx>, idx: &Expr<'_>, start: HirId) -> Opt match idx.kind { ExprKind::Binary(op, lhs, rhs) => match op.node { BinOpKind::Add => { - let offset_opt = if same_var(cx, lhs, start) { - extract_offset(cx, rhs, start) - } else if same_var(cx, rhs, start) { - extract_offset(cx, lhs, start) + let offset_opt = if let Some(s) = extract_start(cx, lhs, starts) { + extract_offset(cx, rhs, starts).map(|o| (s, o)) + } else if let Some(s) = extract_start(cx, rhs, starts) { + extract_offset(cx, lhs, starts).map(|o| (s, o)) } else { None }; - offset_opt.map(Offset::positive) + offset_opt.map(|(s, o)| (s, Offset::positive(o))) }, - BinOpKind::Sub if same_var(cx, lhs, start) => extract_offset(cx, rhs, start).map(Offset::negative), + BinOpKind::Sub => extract_start(cx, lhs, starts) + .and_then(|s| extract_offset(cx, rhs, starts).map(|o| (s, Offset::negative(o)))), _ => None, }, - ExprKind::Path(..) if same_var(cx, idx, start) => Some(Offset::positive("0".into())), + ExprKind::Path(..) => extract_start(cx, idx, starts).map(|s| (s, Offset::empty())), _ => None, } } @@ -1008,6 +1043,10 @@ fn detect_manual_memcpy<'tcx>( { // the var must be a single name if let PatKind::Binding(_, canonical_id, _, _) = pat.kind { + let mut starts = vec![Start { + id: canonical_id, + kind: StartKind::Range, + }]; // The only statements in the for loops can be indexed assignments from // indexed retrievals. let big_sugg = get_assignments(body) @@ -1019,14 +1058,14 @@ fn detect_manual_memcpy<'tcx>( if let ExprKind::Index(base_right, idx_right) = rhs.kind; if is_slice_like(cx, cx.typeck_results().expr_ty(base_left)) && is_slice_like(cx, cx.typeck_results().expr_ty(base_right)); - if let Some(offset_left) = get_offset(cx, &idx_left, canonical_id); - if let Some(offset_right) = get_offset(cx, &idx_right, canonical_id); + if let Some((start_left, offset_left)) = get_offset(cx, &idx_left, &starts); + if let Some((start_right, offset_right)) = get_offset(cx, &idx_right, &starts); // Source and destination must be different if var_def_id(cx, base_left) != var_def_id(cx, base_right); then { - Some((IndexExpr { base: base_left, idx_offset: offset_left }, - IndexExpr { base: base_right, idx_offset: offset_right })) + Some((IndexExpr { base: base_left, idx: start_left, idx_offset: offset_left }, + IndexExpr { base: base_right, idx: start_right, idx_offset: offset_right })) } else { None } From 720f19f2ec4282f636889b35beabf31272e3b1b2 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Wed, 10 Jun 2020 15:58:12 +1200 Subject: [PATCH 019/446] Implement detecting `manual_memcpy` with loop counters --- clippy_lints/src/loops.rs | 90 ++++++++++++++++++++++++++++----------- 1 file changed, 66 insertions(+), 24 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 157dff59d44..c036d63c335 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -913,37 +913,62 @@ fn get_offset<'tcx>( } } -fn get_assignments<'tcx>(body: &'tcx Expr<'tcx>) -> impl Iterator, &'tcx Expr<'tcx>)>> { - fn get_assignment<'tcx>(e: &'tcx Expr<'tcx>) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> { - if let ExprKind::Assign(lhs, rhs, _) = e.kind { - Some((lhs, rhs)) - } else { - None - } +fn get_assignment<'tcx>(e: &'tcx Expr<'tcx>) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> { + if let ExprKind::Assign(lhs, rhs, _) = e.kind { + Some((lhs, rhs)) + } else { + None } +} - // This is one of few ways to return different iterators - // derived from: https://stackoverflow.com/questions/29760668/conditionally-iterate-over-one-of-several-possible-iterators/52064434#52064434 - let mut iter_a = None; - let mut iter_b = None; +fn get_assignments<'a: 'c, 'tcx: 'c, 'c>( + cx: &'a LateContext<'a, 'tcx>, + stmts: &'tcx [Stmt<'tcx>], + expr: Option<&'tcx Expr<'tcx>>, + loop_counters: &'c [Start<'tcx>], +) -> impl Iterator, &'tcx Expr<'tcx>)>> + 'c { + stmts + .iter() + .filter_map(move |stmt| match stmt.kind { + StmtKind::Local(..) | StmtKind::Item(..) => None, + StmtKind::Expr(e) | StmtKind::Semi(e) => if_chain! { + if let ExprKind::AssignOp(_, var, _) = e.kind; + // skip StartKind::Range + if loop_counters.iter().skip(1).any(|counter| Some(counter.id) == var_def_id(cx, var)); + then { None } else { Some(e) } + }, + }) + .chain(expr.into_iter()) + .map(get_assignment) +} - if let ExprKind::Block(b, _) = body.kind { - let Block { stmts, expr, .. } = *b; +fn get_loop_counters<'a, 'tcx>( + cx: &'a LateContext<'a, 'tcx>, + body: &'tcx Block<'tcx>, + expr: &'tcx Expr<'_>, +) -> Option> + 'a> { + // Look for variables that are incremented once per loop iteration. + let mut increment_visitor = IncrementVisitor::new(cx); + walk_block(&mut increment_visitor, body); - iter_a = stmts - .iter() - .filter_map(|stmt| match stmt.kind { - StmtKind::Local(..) | StmtKind::Item(..) => None, - StmtKind::Expr(e) | StmtKind::Semi(e) => Some(e), + // For each candidate, check the parent block to see if + // it's initialized to zero at the start of the loop. + if let Some(block) = get_enclosing_block(&cx, expr.hir_id) { + increment_visitor + .into_results() + .filter_map(move |var_id| { + let mut initialize_visitor = InitializeVisitor::new(cx, expr, var_id); + walk_block(&mut initialize_visitor, block); + + initialize_visitor.get_result().map(|(_, initializer)| Start { + id: var_id, + kind: StartKind::Counter { initializer }, + }) }) - .chain(expr.into_iter()) - .map(get_assignment) .into() } else { - iter_b = Some(get_assignment(body)) + None } - - iter_a.into_iter().flatten().chain(iter_b.into_iter()) } fn build_manual_memcpy_suggestion<'tcx>( @@ -1047,9 +1072,26 @@ fn detect_manual_memcpy<'tcx>( id: canonical_id, kind: StartKind::Range, }]; + + // This is one of few ways to return different iterators + // derived from: https://stackoverflow.com/questions/29760668/conditionally-iterate-over-one-of-several-possible-iterators/52064434#52064434 + let mut iter_a = None; + let mut iter_b = None; + + if let ExprKind::Block(block, _) = body.kind { + if let Some(loop_counters) = get_loop_counters(cx, block, expr) { + starts.extend(loop_counters); + } + iter_a = Some(get_assignments(cx, block.stmts, block.expr, &starts)); + } else { + iter_b = Some(get_assignment(body)); + } + // The only statements in the for loops can be indexed assignments from // indexed retrievals. - let big_sugg = get_assignments(body) + let assignments = iter_a.into_iter().flatten().chain(iter_b.into_iter()); + + let big_sugg = assignments .map(|o| { o.and_then(|(lhs, rhs)| { let rhs = fetch_cloned_expr(rhs); From de56279cd9047832216e1d1c06dc45375bf01b31 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Thu, 11 Jun 2020 11:06:13 +1200 Subject: [PATCH 020/446] Implement building the `manual_memcpy` sugggestion with loop counters --- clippy_lints/src/loops.rs | 185 +++++++++++++++++++++++++-------- clippy_lints/src/utils/sugg.rs | 78 +++++++++++++- 2 files changed, 213 insertions(+), 50 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index c036d63c335..bd2ae47b723 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -800,19 +800,19 @@ enum OffsetSign { } struct Offset { - value: String, + value: MinifyingSugg<'static>, sign: OffsetSign, } impl Offset { - fn negative(value: String) -> Self { + fn negative(value: MinifyingSugg<'static>) -> Self { Self { value, sign: OffsetSign::Negative, } } - fn positive(value: String) -> Self { + fn positive(value: MinifyingSugg<'static>) -> Self { Self { value, sign: OffsetSign::Positive, @@ -820,7 +820,88 @@ impl Offset { } fn empty() -> Self { - Self::positive("0".into()) + Self::positive(MinifyingSugg::non_paren("0")) + } +} + +fn apply_offset(lhs: &MinifyingSugg<'static>, rhs: &Offset) -> MinifyingSugg<'static> { + match rhs.sign { + OffsetSign::Positive => lhs + &rhs.value, + OffsetSign::Negative => lhs - &rhs.value, + } +} + +#[derive(Clone)] +struct MinifyingSugg<'a>(sugg::Sugg<'a>); + +impl std::fmt::Display for MinifyingSugg<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + std::fmt::Display::fmt(&self.0, f) + } +} + +impl<'a> MinifyingSugg<'a> { + fn as_str(&self) -> &str { + let sugg::Sugg::NonParen(s) | sugg::Sugg::MaybeParen(s) | sugg::Sugg::BinOp(_, s) = &self.0; + s.as_ref() + } + + fn hir(cx: &LateContext<'_, '_>, expr: &Expr<'_>, default: &'a str) -> Self { + Self(sugg::Sugg::hir(cx, expr, default)) + } + + fn maybe_par(self) -> Self { + Self(self.0.maybe_par()) + } + + fn non_paren(str: impl Into>) -> Self { + Self(sugg::Sugg::NonParen(str.into())) + } +} + +impl std::ops::Add for &MinifyingSugg<'static> { + type Output = MinifyingSugg<'static>; + fn add(self, rhs: &MinifyingSugg<'static>) -> MinifyingSugg<'static> { + match (self.as_str(), rhs.as_str()) { + ("0", _) => rhs.clone(), + (_, "0") => self.clone(), + (_, _) => MinifyingSugg(&self.0 + &rhs.0), + } + } +} + +impl std::ops::Sub for &MinifyingSugg<'static> { + type Output = MinifyingSugg<'static>; + fn sub(self, rhs: &MinifyingSugg<'static>) -> MinifyingSugg<'static> { + match (self.as_str(), rhs.as_str()) { + (_, "0") => self.clone(), + ("0", _) => MinifyingSugg(sugg::make_unop("-", rhs.0.clone())), + (x, y) if x == y => MinifyingSugg::non_paren("0"), + (_, _) => MinifyingSugg(&self.0 - &rhs.0), + } + } +} + +impl std::ops::Add<&MinifyingSugg<'static>> for MinifyingSugg<'static> { + type Output = MinifyingSugg<'static>; + fn add(self, rhs: &MinifyingSugg<'static>) -> MinifyingSugg<'static> { + match (self.as_str(), rhs.as_str()) { + ("0", _) => rhs.clone(), + (_, "0") => self, + (_, _) => MinifyingSugg(self.0 + &rhs.0), + } + } +} + +impl std::ops::Sub<&MinifyingSugg<'static>> for MinifyingSugg<'static> { + type Output = MinifyingSugg<'static>; + fn sub(self, rhs: &MinifyingSugg<'static>) -> MinifyingSugg<'static> { + match (self.as_str(), rhs.as_str()) { + (_, "0") => self, + ("0", _) => MinifyingSugg(sugg::make_unop("-", rhs.0.clone())), + (x, y) if x == y => MinifyingSugg::non_paren("0"), + (_, _) => MinifyingSugg(self.0 - &rhs.0), + } } } @@ -878,14 +959,15 @@ fn get_offset<'tcx>( cx: &LateContext<'tcx>, e: &Expr<'_>, starts: &[Start<'tcx>], - ) -> Option { + ) -> Option> { match &e.kind { ExprKind::Lit(l) => match l.node { - ast::LitKind::Int(x, _ty) => Some(x.to_string()), + ast::LitKind::Int(x, _ty) => Some(MinifyingSugg::non_paren(x.to_string())), _ => None, }, ExprKind::Path(..) if extract_start(cx, e, starts).is_none() => { - Some(snippet_opt(cx, e.span).unwrap_or_else(|| "??".into())) + // `e` is always non paren as it's a `Path` + Some(MinifyingSugg::non_paren(snippet(cx, e.span, "???"))) }, _ => None, } @@ -979,32 +1061,15 @@ fn build_manual_memcpy_suggestion<'tcx>( dst: IndexExpr<'_>, src: IndexExpr<'_>, ) -> String { - fn print_sum(arg1: &str, arg2: &Offset) -> String { - match (arg1, &arg2.value[..], arg2.sign) { - ("0", "0", _) => "0".into(), - ("0", x, OffsetSign::Positive) | (x, "0", _) => x.into(), - ("0", x, OffsetSign::Negative) => format!("-{}", x), - (x, y, OffsetSign::Positive) => format!("({} + {})", x, y), - (x, y, OffsetSign::Negative) => { - if x == y { - "0".into() - } else { - format!("({} - {})", x, y) - } - }, - } - } - - fn print_offset(start_str: &str, inline_offset: &Offset) -> String { - let offset = print_sum(start_str, inline_offset); + fn print_offset(offset: MinifyingSugg<'static>) -> MinifyingSugg<'static> { if offset.as_str() == "0" { - "".into() + MinifyingSugg::non_paren("") } else { offset } } - let print_limit = |end: &Expr<'_>, offset: Offset, base: &Expr<'_>| { + let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| -> MinifyingSugg<'static> { if_chain! { if let ExprKind::MethodCall(method, _, len_args, _) = end.kind; if method.ident.name == sym!(len); @@ -1012,42 +1077,72 @@ fn build_manual_memcpy_suggestion<'tcx>( if let Some(arg) = len_args.get(0); if var_def_id(cx, arg) == var_def_id(cx, base); then { - match offset.sign { - OffsetSign::Negative => format!("({} - {})", snippet(cx, end.span, ".len()"), offset.value), - OffsetSign::Positive => "".into(), + if sugg.as_str() == end_str { + MinifyingSugg::non_paren("") + } else { + sugg } } else { - let end_str = match limits { + match limits { ast::RangeLimits::Closed => { - let end = sugg::Sugg::hir(cx, end, ""); - format!("{}", end + sugg::ONE) + sugg + &MinifyingSugg::non_paren("1") }, - ast::RangeLimits::HalfOpen => format!("{}", snippet(cx, end.span, "..")), - }; - - print_sum(&end_str, &offset) + ast::RangeLimits::HalfOpen => sugg, + } } } }; - let start_str = snippet(cx, start.span, "").to_string(); - let dst_offset = print_offset(&start_str, &dst.idx_offset); - let dst_limit = print_limit(end, dst.idx_offset, dst.base); - let src_offset = print_offset(&start_str, &src.idx_offset); - let src_limit = print_limit(end, src.idx_offset, src.base); + let start_str = MinifyingSugg::hir(cx, start, ""); + let end_str = MinifyingSugg::hir(cx, end, ""); + + let print_offset_and_limit = |idx_expr: &IndexExpr<'_>| match idx_expr.idx { + StartKind::Range => ( + print_offset(apply_offset(&start_str, &idx_expr.idx_offset)), + print_limit( + end, + end_str.as_str(), + idx_expr.base, + apply_offset(&end_str, &idx_expr.idx_offset), + ), + ), + StartKind::Counter { initializer } => { + let counter_start = MinifyingSugg::hir(cx, initializer, ""); + ( + print_offset(apply_offset(&counter_start, &idx_expr.idx_offset)), + print_limit( + end, + end_str.as_str(), + idx_expr.base, + apply_offset(&end_str, &idx_expr.idx_offset) + &counter_start - &start_str, + ), + ) + }, + }; + + let (dst_offset, dst_limit) = print_offset_and_limit(&dst); + let (src_offset, src_limit) = print_offset_and_limit(&src); let dst_base_str = snippet_opt(cx, dst.base.span).unwrap_or_else(|| "???".into()); let src_base_str = snippet_opt(cx, src.base.span).unwrap_or_else(|| "???".into()); - let dst = if dst_offset == "" && dst_limit == "" { + let dst = if dst_offset.as_str() == "" && dst_limit.as_str() == "" { dst_base_str } else { - format!("{}[{}..{}]", dst_base_str, dst_offset, dst_limit) + format!( + "{}[{}..{}]", + dst_base_str, + dst_offset.maybe_par(), + dst_limit.maybe_par() + ) }; format!( "{}.clone_from_slice(&{}[{}..{}])", - dst, src_base_str, src_offset, src_limit + dst, + src_base_str, + src_offset.maybe_par(), + src_limit.maybe_par() ) } diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index ec8b7e59b59..50d48650a09 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -36,6 +36,46 @@ impl Display for Sugg<'_> { } } +// It's impossible to derive Clone due to the lack of the impl Clone for AssocOp +impl Clone for Sugg<'_> { + fn clone(&self) -> Self { + /// manually cloning AssocOp + fn clone_assoc_op(this: &AssocOp) -> AssocOp { + match this { + AssocOp::Add => AssocOp::Add, + AssocOp::Subtract => AssocOp::Subtract, + AssocOp::Multiply => AssocOp::Multiply, + AssocOp::Divide => AssocOp::Divide, + AssocOp::Modulus => AssocOp::Modulus, + AssocOp::LAnd => AssocOp::LAnd, + AssocOp::LOr => AssocOp::LOr, + AssocOp::BitXor => AssocOp::BitXor, + AssocOp::BitAnd => AssocOp::BitAnd, + AssocOp::BitOr => AssocOp::BitOr, + AssocOp::ShiftLeft => AssocOp::ShiftLeft, + AssocOp::ShiftRight => AssocOp::ShiftRight, + AssocOp::Equal => AssocOp::Equal, + AssocOp::Less => AssocOp::Less, + AssocOp::LessEqual => AssocOp::LessEqual, + AssocOp::NotEqual => AssocOp::NotEqual, + AssocOp::Greater => AssocOp::Greater, + AssocOp::GreaterEqual => AssocOp::GreaterEqual, + AssocOp::Assign => AssocOp::Assign, + AssocOp::AssignOp(t) => AssocOp::AssignOp(*t), + AssocOp::As => AssocOp::As, + AssocOp::DotDot => AssocOp::DotDot, + AssocOp::DotDotEq => AssocOp::DotDotEq, + AssocOp::Colon => AssocOp::Colon, + } + } + match self { + Sugg::NonParen(x) => Sugg::NonParen(x.clone()), + Sugg::MaybeParen(x) => Sugg::MaybeParen(x.clone()), + Sugg::BinOp(op, x) => Sugg::BinOp(clone_assoc_op(op), x.clone()), + } + } +} + #[allow(clippy::wrong_self_convention)] // ok, because of the function `as_ty` method impl<'a> Sugg<'a> { /// Prepare a suggestion from an expression. @@ -267,21 +307,49 @@ impl<'a> Sugg<'a> { } } -impl<'a, 'b> std::ops::Add> for Sugg<'a> { +impl std::ops::Add for Sugg<'_> { type Output = Sugg<'static>; - fn add(self, rhs: Sugg<'b>) -> Sugg<'static> { + fn add(self, rhs: Sugg<'_>) -> Sugg<'static> { make_binop(ast::BinOpKind::Add, &self, &rhs) } } -impl<'a, 'b> std::ops::Sub> for Sugg<'a> { +impl std::ops::Sub for Sugg<'_> { type Output = Sugg<'static>; - fn sub(self, rhs: Sugg<'b>) -> Sugg<'static> { + fn sub(self, rhs: Sugg<'_>) -> Sugg<'static> { make_binop(ast::BinOpKind::Sub, &self, &rhs) } } -impl<'a> std::ops::Not for Sugg<'a> { +impl std::ops::Add<&Sugg<'_>> for Sugg<'_> { + type Output = Sugg<'static>; + fn add(self, rhs: &Sugg<'_>) -> Sugg<'static> { + make_binop(ast::BinOpKind::Add, &self, rhs) + } +} + +impl std::ops::Sub<&Sugg<'_>> for Sugg<'_> { + type Output = Sugg<'static>; + fn sub(self, rhs: &Sugg<'_>) -> Sugg<'static> { + make_binop(ast::BinOpKind::Sub, &self, rhs) + } +} + +impl std::ops::Add for &Sugg<'_> { + type Output = Sugg<'static>; + fn add(self, rhs: &Sugg<'_>) -> Sugg<'static> { + make_binop(ast::BinOpKind::Add, self, rhs) + } +} + +impl std::ops::Sub for &Sugg<'_> { + type Output = Sugg<'static>; + fn sub(self, rhs: &Sugg<'_>) -> Sugg<'static> { + make_binop(ast::BinOpKind::Sub, self, rhs) + } +} + +impl std::ops::Not for Sugg<'_> { type Output = Sugg<'static>; fn not(self) -> Sugg<'static> { make_unop("!", self) From 8da6cfd17b7707d678d01a6688572169015ea83e Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Thu, 11 Jun 2020 12:11:06 +1200 Subject: [PATCH 021/446] fmt --- clippy_lints/src/loops.rs | 41 ++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index bd2ae47b723..2aee3b93e82 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1069,29 +1069,30 @@ fn build_manual_memcpy_suggestion<'tcx>( } } - let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| -> MinifyingSugg<'static> { - if_chain! { - if let ExprKind::MethodCall(method, _, len_args, _) = end.kind; - if method.ident.name == sym!(len); - if len_args.len() == 1; - if let Some(arg) = len_args.get(0); - if var_def_id(cx, arg) == var_def_id(cx, base); - then { - if sugg.as_str() == end_str { - MinifyingSugg::non_paren("") + let print_limit = + |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| -> MinifyingSugg<'static> { + if_chain! { + if let ExprKind::MethodCall(method, _, len_args, _) = end.kind; + if method.ident.name == sym!(len); + if len_args.len() == 1; + if let Some(arg) = len_args.get(0); + if var_def_id(cx, arg) == var_def_id(cx, base); + then { + if sugg.as_str() == end_str { + MinifyingSugg::non_paren("") + } else { + sugg + } } else { - sugg - } - } else { - match limits { - ast::RangeLimits::Closed => { - sugg + &MinifyingSugg::non_paren("1") - }, - ast::RangeLimits::HalfOpen => sugg, + match limits { + ast::RangeLimits::Closed => { + sugg + &MinifyingSugg::non_paren("1") + }, + ast::RangeLimits::HalfOpen => sugg, + } } } - } - }; + }; let start_str = MinifyingSugg::hir(cx, start, ""); let end_str = MinifyingSugg::hir(cx, end, ""); From d9a88be0b05c2cfec0679caf428d129c9d46256d Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Thu, 18 Jun 2020 10:24:12 +1200 Subject: [PATCH 022/446] Rename `get_offset` and its private items --- clippy_lints/src/loops.rs | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 2aee3b93e82..98c411f5ae6 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -942,20 +942,20 @@ fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { } } -fn get_offset<'tcx>( +fn get_details_from_idx<'tcx>( cx: &LateContext<'tcx>, idx: &Expr<'_>, starts: &[Start<'tcx>], ) -> Option<(StartKind<'tcx>, Offset)> { - fn extract_start<'tcx>( + fn get_start<'tcx>( cx: &LateContext<'tcx>, - expr: &Expr<'_>, + e: &Expr<'_>, starts: &[Start<'tcx>], ) -> Option> { - starts.iter().find(|var| same_var(cx, expr, var.id)).map(|v| v.kind) + starts.iter().find(|var| same_var(cx, e, var.id)).map(|v| v.kind) } - fn extract_offset<'tcx>( + fn get_offset<'tcx>( cx: &LateContext<'tcx>, e: &Expr<'_>, starts: &[Start<'tcx>], @@ -965,7 +965,7 @@ fn get_offset<'tcx>( ast::LitKind::Int(x, _ty) => Some(MinifyingSugg::non_paren(x.to_string())), _ => None, }, - ExprKind::Path(..) if extract_start(cx, e, starts).is_none() => { + ExprKind::Path(..) if get_start(cx, e, starts).is_none() => { // `e` is always non paren as it's a `Path` Some(MinifyingSugg::non_paren(snippet(cx, e.span, "???"))) }, @@ -976,21 +976,22 @@ fn get_offset<'tcx>( match idx.kind { ExprKind::Binary(op, lhs, rhs) => match op.node { BinOpKind::Add => { - let offset_opt = if let Some(s) = extract_start(cx, lhs, starts) { - extract_offset(cx, rhs, starts).map(|o| (s, o)) - } else if let Some(s) = extract_start(cx, rhs, starts) { - extract_offset(cx, lhs, starts).map(|o| (s, o)) + let offset_opt = if let Some(s) = get_start(cx, lhs, starts) { + get_offset(cx, rhs, starts).map(|o| (s, o)) + } else if let Some(s) = get_start(cx, rhs, starts) { + get_offset(cx, lhs, starts).map(|o| (s, o)) } else { None }; offset_opt.map(|(s, o)| (s, Offset::positive(o))) }, - BinOpKind::Sub => extract_start(cx, lhs, starts) - .and_then(|s| extract_offset(cx, rhs, starts).map(|o| (s, Offset::negative(o)))), + BinOpKind::Sub => { + get_start(cx, lhs, starts).and_then(|s| get_offset(cx, rhs, starts).map(|o| (s, Offset::negative(o)))) + }, _ => None, }, - ExprKind::Path(..) => extract_start(cx, idx, starts).map(|s| (s, Offset::empty())), + ExprKind::Path(..) => get_start(cx, idx, starts).map(|s| (s, Offset::empty())), _ => None, } } @@ -1196,8 +1197,8 @@ fn detect_manual_memcpy<'tcx>( if let ExprKind::Index(base_right, idx_right) = rhs.kind; if is_slice_like(cx, cx.typeck_results().expr_ty(base_left)) && is_slice_like(cx, cx.typeck_results().expr_ty(base_right)); - if let Some((start_left, offset_left)) = get_offset(cx, &idx_left, &starts); - if let Some((start_right, offset_right)) = get_offset(cx, &idx_right, &starts); + if let Some((start_left, offset_left)) = get_details_from_idx(cx, &idx_left, &starts); + if let Some((start_right, offset_right)) = get_details_from_idx(cx, &idx_right, &starts); // Source and destination must be different if var_def_id(cx, base_left) != var_def_id(cx, base_right); From 774e82a566c6c3349700a8bece44d6a8c6755039 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Thu, 11 Jun 2020 11:19:44 +1200 Subject: [PATCH 023/446] Add the tests for `manual_memcpy` with loop counters --- tests/ui/manual_memcpy.rs | 54 +++++++++++++++++++++++++++++++ tests/ui/manual_memcpy.stderr | 60 +++++++++++++++++++++++++++++++++-- 2 files changed, 111 insertions(+), 3 deletions(-) diff --git a/tests/ui/manual_memcpy.rs b/tests/ui/manual_memcpy.rs index 0083f94798f..87bfb4fdd16 100644 --- a/tests/ui/manual_memcpy.rs +++ b/tests/ui/manual_memcpy.rs @@ -115,6 +115,60 @@ pub fn manual_copy(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) { } } +#[allow(clippy::needless_range_loop, clippy::explicit_counter_loop)] +pub fn manual_copy_with_counters(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) { + let mut count = 0; + for i in 3..src.len() { + dst[i] = src[count]; + count += 1; + } + + let mut count = 0; + for i in 3..src.len() { + dst[count] = src[i]; + count += 1; + } + + let mut count = 3; + for i in 0..src.len() { + dst[count] = src[i]; + count += 1; + } + + let mut count = 3; + for i in 0..src.len() { + dst[i] = src[count]; + count += 1; + } + + let mut count = 0; + for i in 3..(3 + src.len()) { + dst[i] = src[count]; + count += 1; + } + + let mut count = 3; + for i in 5..src.len() { + dst[i] = src[count - 2]; + count += 1; + } + + let mut count = 5; + for i in 3..10 { + dst[i] = src[count]; + count += 1; + } + + let mut count = 3; + let mut count = 30; + for i in 0..src.len() { + dst[count] = src[i]; + dst2[count] = src[i]; + count += 1; + count += 1; + } +} + #[warn(clippy::needless_range_loop, clippy::manual_memcpy)] pub fn manual_clone(src: &[String], dst: &mut [String]) { for i in 0..src.len() { diff --git a/tests/ui/manual_memcpy.stderr b/tests/ui/manual_memcpy.stderr index bad84a58900..a5698b08103 100644 --- a/tests/ui/manual_memcpy.stderr +++ b/tests/ui/manual_memcpy.stderr @@ -16,7 +16,7 @@ error: it looks like you're manually copying between slices --> $DIR/manual_memcpy.rs:17:14 | LL | for i in 0..src.len() { - | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[10..])` + | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[10..(src.len() + 10)])` error: it looks like you're manually copying between slices --> $DIR/manual_memcpy.rs:22:14 @@ -79,10 +79,64 @@ LL | for i in 0..0 { | ^^^^ help: try replacing the loop by: `dst[..0].clone_from_slice(&src[..0])` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:120:14 + --> $DIR/manual_memcpy.rs:121:14 + | +LL | for i in 3..src.len() { + | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[3..src.len()].clone_from_slice(&src[..(src.len() - 3)])` + +error: it looks like you're manually copying between slices + --> $DIR/manual_memcpy.rs:127:14 + | +LL | for i in 3..src.len() { + | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..(src.len() - 3)].clone_from_slice(&src[3..])` + +error: it looks like you're manually copying between slices + --> $DIR/manual_memcpy.rs:133:14 + | +LL | for i in 0..src.len() { + | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[3..(src.len() + 3)].clone_from_slice(&src[..])` + +error: it looks like you're manually copying between slices + --> $DIR/manual_memcpy.rs:139:14 + | +LL | for i in 0..src.len() { + | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[3..(src.len() + 3)])` + +error: it looks like you're manually copying between slices + --> $DIR/manual_memcpy.rs:145:14 + | +LL | for i in 3..(3 + src.len()) { + | ^^^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[3..(3 + src.len())].clone_from_slice(&src[..((3 + src.len()) - 3)])` + +error: it looks like you're manually copying between slices + --> $DIR/manual_memcpy.rs:151:14 + | +LL | for i in 5..src.len() { + | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[5..src.len()].clone_from_slice(&src[(3 - 2)..((src.len() - 2) + 3 - 5)])` + +error: it looks like you're manually copying between slices + --> $DIR/manual_memcpy.rs:157:14 + | +LL | for i in 3..10 { + | ^^^^^ help: try replacing the loop by: `dst[3..10].clone_from_slice(&src[5..(10 + 5 - 3)])` + +error: it looks like you're manually copying between slices + --> $DIR/manual_memcpy.rs:164:14 + | +LL | for i in 0..src.len() { + | ^^^^^^^^^^^^ + | +help: try replacing the loop by + | +LL | for i in dst[3..(src.len() + 3)].clone_from_slice(&src[..]) +LL | dst2[30..(src.len() + 30)].clone_from_slice(&src[..]) { + | + +error: it looks like you're manually copying between slices + --> $DIR/manual_memcpy.rs:174:14 | LL | for i in 0..src.len() { | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])` -error: aborting due to 13 previous errors +error: aborting due to 21 previous errors From 9aad38bf614c3fb6d306f5dec4a0af606bb3c9c8 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Thu, 18 Jun 2020 10:48:44 +1200 Subject: [PATCH 024/446] Update `manual_memcpy.stderr` to reflect additional parentheses --- tests/ui/manual_memcpy.stderr | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ui/manual_memcpy.stderr b/tests/ui/manual_memcpy.stderr index a5698b08103..e6bef9981a3 100644 --- a/tests/ui/manual_memcpy.stderr +++ b/tests/ui/manual_memcpy.stderr @@ -58,13 +58,13 @@ error: it looks like you're manually copying between slices --> $DIR/manual_memcpy.rs:94:14 | LL | for i in from..from + src.len() { - | ^^^^^^^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..from + src.len()].clone_from_slice(&src[..(from + src.len() - from)])` + | ^^^^^^^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..(from + src.len())].clone_from_slice(&src[..(from + src.len() - from)])` error: it looks like you're manually copying between slices --> $DIR/manual_memcpy.rs:98:14 | LL | for i in from..from + 3 { - | ^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..from + 3].clone_from_slice(&src[..(from + 3 - from)])` + | ^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..(from + 3)].clone_from_slice(&src[..(from + 3 - from)])` error: it looks like you're manually copying between slices --> $DIR/manual_memcpy.rs:103:14 @@ -106,7 +106,7 @@ error: it looks like you're manually copying between slices --> $DIR/manual_memcpy.rs:145:14 | LL | for i in 3..(3 + src.len()) { - | ^^^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[3..(3 + src.len())].clone_from_slice(&src[..((3 + src.len()) - 3)])` + | ^^^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[3..((3 + src.len()))].clone_from_slice(&src[..((3 + src.len()) - 3)])` error: it looks like you're manually copying between slices --> $DIR/manual_memcpy.rs:151:14 From 4ea4a972500a8ddecfc737d51eec960324dcb02f Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Thu, 18 Jun 2020 12:31:13 +1200 Subject: [PATCH 025/446] Add tests for bitwise operations --- tests/ui/manual_memcpy.rs | 8 ++++++++ tests/ui/manual_memcpy.stderr | 8 +++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/ui/manual_memcpy.rs b/tests/ui/manual_memcpy.rs index 87bfb4fdd16..4846ab5eaaa 100644 --- a/tests/ui/manual_memcpy.rs +++ b/tests/ui/manual_memcpy.rs @@ -167,6 +167,14 @@ pub fn manual_copy_with_counters(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) count += 1; count += 1; } + + // make sure parentheses are added properly to bitwise operators, which have lower precedence than + // arithmetric ones + let mut count = 0 << 1; + for i in 0..1 << 1 { + dst[count] = src[i + 2]; + count += 1; + } } #[warn(clippy::needless_range_loop, clippy::manual_memcpy)] diff --git a/tests/ui/manual_memcpy.stderr b/tests/ui/manual_memcpy.stderr index e6bef9981a3..d189bde0508 100644 --- a/tests/ui/manual_memcpy.stderr +++ b/tests/ui/manual_memcpy.stderr @@ -135,8 +135,14 @@ LL | dst2[30..(src.len() + 30)].clone_from_slice(&src[..]) { error: it looks like you're manually copying between slices --> $DIR/manual_memcpy.rs:174:14 | +LL | for i in 0..1 << 1 { + | ^^^^^^^^^ help: try replacing the loop by: `dst[(0 << 1)..((1 << 1) + (0 << 1))].clone_from_slice(&src[2..((1 << 1) + 2)])` + +error: it looks like you're manually copying between slices + --> $DIR/manual_memcpy.rs:182:14 + | LL | for i in 0..src.len() { | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])` -error: aborting due to 21 previous errors +error: aborting due to 22 previous errors From eb3ffe6ed2999e9d3385be0ff981e30082ea0d2c Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Tue, 23 Jun 2020 18:51:05 +1200 Subject: [PATCH 026/446] make use of macros in operator overloading --- clippy_lints/src/utils/sugg.rs | 61 ++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 50d48650a09..aada4122e78 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -13,6 +13,7 @@ use rustc_span::{BytePos, Pos}; use std::borrow::Cow; use std::convert::TryInto; use std::fmt::Display; +use std::ops::{Add, Sub, Not}; /// A helper type to build suggestion correctly handling parenthesis. pub enum Sugg<'a> { @@ -307,49 +308,53 @@ impl<'a> Sugg<'a> { } } -impl std::ops::Add for Sugg<'_> { - type Output = Sugg<'static>; - fn add(self, rhs: Sugg<'_>) -> Sugg<'static> { - make_binop(ast::BinOpKind::Add, &self, &rhs) +// Copied from the rust standart library, and then edited +macro_rules! forward_binop_impls_to_ref { + (impl $imp:ident, $method:ident for $t:ty, type Output = $o:ty) => { + impl $imp<$t> for &$t { + type Output = $o; + + fn $method(self, other: $t) -> $o { + $imp::$method(self, &other) + } + } + + impl $imp<&$t> for $t { + type Output = $o; + + fn $method(self, other: &$t) -> $o { + $imp::$method(&self, other) + } + } + + impl $imp for $t { + type Output = $o; + + fn $method(self, other: $t) -> $o { + $imp::$method(&self, &other) + } + } } } -impl std::ops::Sub for Sugg<'_> { - type Output = Sugg<'static>; - fn sub(self, rhs: Sugg<'_>) -> Sugg<'static> { - make_binop(ast::BinOpKind::Sub, &self, &rhs) - } -} - -impl std::ops::Add<&Sugg<'_>> for Sugg<'_> { - type Output = Sugg<'static>; - fn add(self, rhs: &Sugg<'_>) -> Sugg<'static> { - make_binop(ast::BinOpKind::Add, &self, rhs) - } -} - -impl std::ops::Sub<&Sugg<'_>> for Sugg<'_> { - type Output = Sugg<'static>; - fn sub(self, rhs: &Sugg<'_>) -> Sugg<'static> { - make_binop(ast::BinOpKind::Sub, &self, rhs) - } -} - -impl std::ops::Add for &Sugg<'_> { +impl Add for &Sugg<'_> { type Output = Sugg<'static>; fn add(self, rhs: &Sugg<'_>) -> Sugg<'static> { make_binop(ast::BinOpKind::Add, self, rhs) } } -impl std::ops::Sub for &Sugg<'_> { +impl Sub for &Sugg<'_> { type Output = Sugg<'static>; fn sub(self, rhs: &Sugg<'_>) -> Sugg<'static> { make_binop(ast::BinOpKind::Sub, self, rhs) } } -impl std::ops::Not for Sugg<'_> { +forward_binop_impls_to_ref!(impl Add, add for Sugg<'_>, type Output = Sugg<'static>); +forward_binop_impls_to_ref!(impl Sub, sub for Sugg<'_>, type Output = Sugg<'static>); + +impl Not for Sugg<'_> { type Output = Sugg<'static>; fn not(self) -> Sugg<'static> { make_unop("!", self) From 10d7a18f72155f03dbd27b872a52b5dd45def8db Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Tue, 23 Jun 2020 22:37:36 +1200 Subject: [PATCH 027/446] fmt --- clippy_lints/src/utils/sugg.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index aada4122e78..8f2aa724d20 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -13,7 +13,7 @@ use rustc_span::{BytePos, Pos}; use std::borrow::Cow; use std::convert::TryInto; use std::fmt::Display; -use std::ops::{Add, Sub, Not}; +use std::ops::{Add, Not, Sub}; /// A helper type to build suggestion correctly handling parenthesis. pub enum Sugg<'a> { @@ -334,7 +334,7 @@ macro_rules! forward_binop_impls_to_ref { $imp::$method(&self, &other) } } - } + }; } impl Add for &Sugg<'_> { From 174065fc98ef9335ea45a234aa18286cdf6c3934 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Wed, 24 Jun 2020 11:33:49 +1200 Subject: [PATCH 028/446] fix the multiple counters test --- tests/ui/manual_memcpy.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ui/manual_memcpy.rs b/tests/ui/manual_memcpy.rs index 4846ab5eaaa..8318fd89811 100644 --- a/tests/ui/manual_memcpy.rs +++ b/tests/ui/manual_memcpy.rs @@ -160,12 +160,12 @@ pub fn manual_copy_with_counters(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) } let mut count = 3; - let mut count = 30; + let mut count2 = 30; for i in 0..src.len() { dst[count] = src[i]; - dst2[count] = src[i]; - count += 1; + dst2[count2] = src[i]; count += 1; + count2 += 1; } // make sure parentheses are added properly to bitwise operators, which have lower precedence than From 44187383f4724bd7e4b2b220235e93438043947a Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Wed, 24 Jun 2020 12:41:46 +1200 Subject: [PATCH 029/446] Use operator overloading instead of direct calls of `make_binop` --- clippy_lints/src/loops.rs | 4 ++-- clippy_lints/src/utils/sugg.rs | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 98c411f5ae6..5928d12f30b 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -875,7 +875,7 @@ impl std::ops::Sub for &MinifyingSugg<'static> { fn sub(self, rhs: &MinifyingSugg<'static>) -> MinifyingSugg<'static> { match (self.as_str(), rhs.as_str()) { (_, "0") => self.clone(), - ("0", _) => MinifyingSugg(sugg::make_unop("-", rhs.0.clone())), + ("0", _) => MinifyingSugg(-(rhs.0.clone())), (x, y) if x == y => MinifyingSugg::non_paren("0"), (_, _) => MinifyingSugg(&self.0 - &rhs.0), } @@ -898,7 +898,7 @@ impl std::ops::Sub<&MinifyingSugg<'static>> for MinifyingSugg<'static> { fn sub(self, rhs: &MinifyingSugg<'static>) -> MinifyingSugg<'static> { match (self.as_str(), rhs.as_str()) { (_, "0") => self, - ("0", _) => MinifyingSugg(sugg::make_unop("-", rhs.0.clone())), + ("0", _) => MinifyingSugg(-(rhs.0.clone())), (x, y) if x == y => MinifyingSugg::non_paren("0"), (_, _) => MinifyingSugg(self.0 - &rhs.0), } diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 8f2aa724d20..1f448f86d72 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -13,7 +13,7 @@ use rustc_span::{BytePos, Pos}; use std::borrow::Cow; use std::convert::TryInto; use std::fmt::Display; -use std::ops::{Add, Not, Sub}; +use std::ops::{Add, Neg, Not, Sub}; /// A helper type to build suggestion correctly handling parenthesis. pub enum Sugg<'a> { @@ -354,6 +354,13 @@ impl Sub for &Sugg<'_> { forward_binop_impls_to_ref!(impl Add, add for Sugg<'_>, type Output = Sugg<'static>); forward_binop_impls_to_ref!(impl Sub, sub for Sugg<'_>, type Output = Sugg<'static>); +impl Neg for Sugg<'_> { + type Output = Sugg<'static>; + fn neg(self) -> Sugg<'static> { + make_unop("-", self) + } +} + impl Not for Sugg<'_> { type Output = Sugg<'static>; fn not(self) -> Sugg<'static> { From f410df3c4810e80b6703dcfdbc4d48f812eb4889 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Sat, 27 Jun 2020 18:56:38 +1200 Subject: [PATCH 030/446] make clippy happy (`needless_pass_by_value`, `filter_map` and `find_map`) --- clippy_lints/src/loops.rs | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 5928d12f30b..f684e7de8f8 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -952,7 +952,13 @@ fn get_details_from_idx<'tcx>( e: &Expr<'_>, starts: &[Start<'tcx>], ) -> Option> { - starts.iter().find(|var| same_var(cx, e, var.id)).map(|v| v.kind) + starts.iter().find_map(|start| { + if same_var(cx, e, start.id) { + Some(start.kind) + } else { + None + } + }) } fn get_offset<'tcx>( @@ -1059,8 +1065,8 @@ fn build_manual_memcpy_suggestion<'tcx>( start: &Expr<'_>, end: &Expr<'_>, limits: ast::RangeLimits, - dst: IndexExpr<'_>, - src: IndexExpr<'_>, + dst: &IndexExpr<'_>, + src: &IndexExpr<'_>, ) -> String { fn print_offset(offset: MinifyingSugg<'static>) -> MinifyingSugg<'static> { if offset.as_str() == "0" { @@ -1211,7 +1217,7 @@ fn detect_manual_memcpy<'tcx>( } }) }) - .map(|o| o.map(|(dst, src)| build_manual_memcpy_suggestion(cx, start, end, limits, dst, src))) + .map(|o| o.map(|(dst, src)| build_manual_memcpy_suggestion(cx, start, end, limits, &dst, &src))) .collect::>>() .filter(|v| !v.is_empty()) .map(|v| v.join("\n ")); @@ -2319,10 +2325,13 @@ impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> { } fn into_results(self) -> impl Iterator { - self.states - .into_iter() - .filter(|(_, state)| *state == IncrementVisitorVarState::IncrOnce) - .map(|(id, _)| id) + self.states.into_iter().filter_map(|(id, state)| { + if state == IncrementVisitorVarState::IncrOnce { + Some(id) + } else { + None + } + }) } } From ce653d65a8f08d785c5061e26570b4e59372e325 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Wed, 1 Jul 2020 12:22:16 +1200 Subject: [PATCH 031/446] use `#[derive]` instead of the manual implementation --- clippy_lints/src/utils/sugg.rs | 41 +--------------------------------- 1 file changed, 1 insertion(+), 40 deletions(-) diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 1f448f86d72..062b273c0f4 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -16,6 +16,7 @@ use std::fmt::Display; use std::ops::{Add, Neg, Not, Sub}; /// A helper type to build suggestion correctly handling parenthesis. +#[derive(Clone)] pub enum Sugg<'a> { /// An expression that never needs parenthesis such as `1337` or `[0; 42]`. NonParen(Cow<'a, str>), @@ -37,46 +38,6 @@ impl Display for Sugg<'_> { } } -// It's impossible to derive Clone due to the lack of the impl Clone for AssocOp -impl Clone for Sugg<'_> { - fn clone(&self) -> Self { - /// manually cloning AssocOp - fn clone_assoc_op(this: &AssocOp) -> AssocOp { - match this { - AssocOp::Add => AssocOp::Add, - AssocOp::Subtract => AssocOp::Subtract, - AssocOp::Multiply => AssocOp::Multiply, - AssocOp::Divide => AssocOp::Divide, - AssocOp::Modulus => AssocOp::Modulus, - AssocOp::LAnd => AssocOp::LAnd, - AssocOp::LOr => AssocOp::LOr, - AssocOp::BitXor => AssocOp::BitXor, - AssocOp::BitAnd => AssocOp::BitAnd, - AssocOp::BitOr => AssocOp::BitOr, - AssocOp::ShiftLeft => AssocOp::ShiftLeft, - AssocOp::ShiftRight => AssocOp::ShiftRight, - AssocOp::Equal => AssocOp::Equal, - AssocOp::Less => AssocOp::Less, - AssocOp::LessEqual => AssocOp::LessEqual, - AssocOp::NotEqual => AssocOp::NotEqual, - AssocOp::Greater => AssocOp::Greater, - AssocOp::GreaterEqual => AssocOp::GreaterEqual, - AssocOp::Assign => AssocOp::Assign, - AssocOp::AssignOp(t) => AssocOp::AssignOp(*t), - AssocOp::As => AssocOp::As, - AssocOp::DotDot => AssocOp::DotDot, - AssocOp::DotDotEq => AssocOp::DotDotEq, - AssocOp::Colon => AssocOp::Colon, - } - } - match self { - Sugg::NonParen(x) => Sugg::NonParen(x.clone()), - Sugg::MaybeParen(x) => Sugg::MaybeParen(x.clone()), - Sugg::BinOp(op, x) => Sugg::BinOp(clone_assoc_op(op), x.clone()), - } - } -} - #[allow(clippy::wrong_self_convention)] // ok, because of the function `as_ty` method impl<'a> Sugg<'a> { /// Prepare a suggestion from an expression. From e855fe3620c0a6981a4238df548fa5c2f36a24c9 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:01:56 +1200 Subject: [PATCH 032/446] Reflect the changes that has been made and fmt --- clippy_lints/src/loops.rs | 45 ++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index f684e7de8f8..4ff567ffb0e 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -846,7 +846,7 @@ impl<'a> MinifyingSugg<'a> { s.as_ref() } - fn hir(cx: &LateContext<'_, '_>, expr: &Expr<'_>, default: &'a str) -> Self { + fn hir(cx: &LateContext<'_>, expr: &Expr<'_>, default: &'a str) -> Self { Self(sugg::Sugg::hir(cx, expr, default)) } @@ -947,11 +947,7 @@ fn get_details_from_idx<'tcx>( idx: &Expr<'_>, starts: &[Start<'tcx>], ) -> Option<(StartKind<'tcx>, Offset)> { - fn get_start<'tcx>( - cx: &LateContext<'tcx>, - e: &Expr<'_>, - starts: &[Start<'tcx>], - ) -> Option> { + fn get_start<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>, starts: &[Start<'tcx>]) -> Option> { starts.iter().find_map(|start| { if same_var(cx, e, start.id) { Some(start.kind) @@ -982,13 +978,9 @@ fn get_details_from_idx<'tcx>( match idx.kind { ExprKind::Binary(op, lhs, rhs) => match op.node { BinOpKind::Add => { - let offset_opt = if let Some(s) = get_start(cx, lhs, starts) { - get_offset(cx, rhs, starts).map(|o| (s, o)) - } else if let Some(s) = get_start(cx, rhs, starts) { - get_offset(cx, lhs, starts).map(|o| (s, o)) - } else { - None - }; + let offset_opt = get_start(cx, lhs, starts) + .and_then(|s| get_offset(cx, rhs, starts).map(|o| (s, o))) + .or_else(|| get_start(cx, rhs, starts).and_then(|s| get_offset(cx, lhs, starts).map(|o| (s, o)))); offset_opt.map(|(s, o)| (s, Offset::positive(o))) }, @@ -1011,7 +1003,7 @@ fn get_assignment<'tcx>(e: &'tcx Expr<'tcx>) -> Option<(&'tcx Expr<'tcx>, &'tcx } fn get_assignments<'a: 'c, 'tcx: 'c, 'c>( - cx: &'a LateContext<'a, 'tcx>, + cx: &'a LateContext<'tcx>, stmts: &'tcx [Stmt<'tcx>], expr: Option<&'tcx Expr<'tcx>>, loop_counters: &'c [Start<'tcx>], @@ -1032,7 +1024,7 @@ fn get_assignments<'a: 'c, 'tcx: 'c, 'c>( } fn get_loop_counters<'a, 'tcx>( - cx: &'a LateContext<'a, 'tcx>, + cx: &'a LateContext<'tcx>, body: &'tcx Block<'tcx>, expr: &'tcx Expr<'_>, ) -> Option> + 'a> { @@ -1042,7 +1034,7 @@ fn get_loop_counters<'a, 'tcx>( // For each candidate, check the parent block to see if // it's initialized to zero at the start of the loop. - if let Some(block) = get_enclosing_block(&cx, expr.hir_id) { + get_enclosing_block(&cx, expr.hir_id).and_then(|block| { increment_visitor .into_results() .filter_map(move |var_id| { @@ -1055,9 +1047,7 @@ fn get_loop_counters<'a, 'tcx>( }) }) .into() - } else { - None - } + }) } fn build_manual_memcpy_suggestion<'tcx>( @@ -2315,7 +2305,7 @@ struct IncrementVisitor<'a, 'tcx> { } impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> { - fn new(cx: &'a LateContext<'a, 'tcx>) -> Self { + fn new(cx: &'a LateContext<'tcx>) -> Self { Self { cx, states: FxHashMap::default(), @@ -2396,7 +2386,10 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { enum InitializeVisitorState<'hir> { Initial, // Not examined yet Declared(Symbol), // Declared but not (yet) initialized - Initialized { name: Symbol, initializer: &'hir Expr<'hir> }, + Initialized { + name: Symbol, + initializer: &'hir Expr<'hir>, + }, DontWarn, } @@ -2412,7 +2405,7 @@ struct InitializeVisitor<'a, 'tcx> { } impl<'a, 'tcx> InitializeVisitor<'a, 'tcx> { - fn new(cx: &'a LateContext<'a, 'tcx>, end_expr: &'tcx Expr<'tcx>, var_id: HirId) -> Self { + fn new(cx: &'a LateContext<'tcx>, end_expr: &'tcx Expr<'tcx>, var_id: HirId) -> Self { Self { cx, end_expr, @@ -2423,7 +2416,7 @@ impl<'a, 'tcx> InitializeVisitor<'a, 'tcx> { } } - fn get_result(&self) -> Option<(Name, &'tcx Expr<'tcx>)> { + fn get_result(&self) -> Option<(Symbol, &'tcx Expr<'tcx>)> { if let InitializeVisitorState::Initialized { name, initializer } = self.state { Some((name, initializer)) } else { @@ -2442,14 +2435,12 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { if local.pat.hir_id == self.var_id; if let PatKind::Binding(.., ident, _) = local.pat.kind; then { - self.state = if let Some(ref init) = local.init { + self.state = local.init.map_or(InitializeVisitorState::Declared(ident.name), |init| { InitializeVisitorState::Initialized { initializer: init, name: ident.name, } - } else { - InitializeVisitorState::Declared(ident.name) - } + }) } } walk_stmt(self, stmt); From 4918e7ad62259e4c35a0b9d6ac0f0e98e51ff7b1 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Sun, 27 Sep 2020 14:19:43 +1300 Subject: [PATCH 033/446] Replace `snippet_opt` + `unwrap_or_else` with `snippet` --- clippy_lints/src/loops.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 4ff567ffb0e..647537933f7 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -5,9 +5,8 @@ use crate::utils::usage::{is_unused, mutated_variables}; use crate::utils::{ get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item, last_path_segment, match_trait_method, - match_type, match_var, multispan_sugg, qpath_res, snippet, snippet_opt, snippet_with_applicability, - snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, - SpanlessEq, + match_type, match_var, multispan_sugg, qpath_res, snippet, snippet_with_applicability, snippet_with_macro_callsite, + span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, SpanlessEq, }; use if_chain::if_chain; use rustc_ast::ast; @@ -1121,8 +1120,8 @@ fn build_manual_memcpy_suggestion<'tcx>( let (dst_offset, dst_limit) = print_offset_and_limit(&dst); let (src_offset, src_limit) = print_offset_and_limit(&src); - let dst_base_str = snippet_opt(cx, dst.base.span).unwrap_or_else(|| "???".into()); - let src_base_str = snippet_opt(cx, src.base.span).unwrap_or_else(|| "???".into()); + let dst_base_str = snippet(cx, dst.base.span, "???"); + let src_base_str = snippet(cx, src.base.span, "???"); let dst = if dst_offset.as_str() == "" && dst_limit.as_str() == "" { dst_base_str @@ -1133,6 +1132,7 @@ fn build_manual_memcpy_suggestion<'tcx>( dst_offset.maybe_par(), dst_limit.maybe_par() ) + .into() }; format!( From 5c71352b18ee7a48e825aefd2862b8e0d16ea45b Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Sun, 27 Sep 2020 14:52:06 +1300 Subject: [PATCH 034/446] Prevent unnecessary lints from triggering --- clippy_lints/src/loops.rs | 12 ++++++++---- tests/ui/manual_memcpy.rs | 1 - tests/ui/manual_memcpy.stderr | 20 ++++++++++---------- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 647537933f7..f2df53aee4f 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -768,12 +768,14 @@ fn check_for_loop<'tcx>( body: &'tcx Expr<'_>, expr: &'tcx Expr<'_>, ) { - check_for_loop_range(cx, pat, arg, body, expr); + let is_manual_memcpy_triggered = detect_manual_memcpy(cx, pat, arg, body, expr); + if !is_manual_memcpy_triggered { + check_for_loop_range(cx, pat, arg, body, expr); + check_for_loop_explicit_counter(cx, pat, arg, body, expr); + } check_for_loop_arg(cx, pat, arg, expr); - check_for_loop_explicit_counter(cx, pat, arg, body, expr); check_for_loop_over_map_kv(cx, pat, arg, body, expr); check_for_mut_range_bound(cx, arg, body); - detect_manual_memcpy(cx, pat, arg, body, expr); detect_same_item_push(cx, pat, arg, body, expr); } @@ -1152,7 +1154,7 @@ fn detect_manual_memcpy<'tcx>( arg: &'tcx Expr<'_>, body: &'tcx Expr<'_>, expr: &'tcx Expr<'_>, -) { +) -> bool { if let Some(higher::Range { start: Some(start), end: Some(end), @@ -1222,9 +1224,11 @@ fn detect_manual_memcpy<'tcx>( big_sugg, Applicability::Unspecified, ); + return true; } } } + false } // Scans the body of the for loop and determines whether lint should be given diff --git a/tests/ui/manual_memcpy.rs b/tests/ui/manual_memcpy.rs index 8318fd89811..84758275dd7 100644 --- a/tests/ui/manual_memcpy.rs +++ b/tests/ui/manual_memcpy.rs @@ -115,7 +115,6 @@ pub fn manual_copy(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) { } } -#[allow(clippy::needless_range_loop, clippy::explicit_counter_loop)] pub fn manual_copy_with_counters(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) { let mut count = 0; for i in 3..src.len() { diff --git a/tests/ui/manual_memcpy.stderr b/tests/ui/manual_memcpy.stderr index d189bde0508..464b18984fb 100644 --- a/tests/ui/manual_memcpy.stderr +++ b/tests/ui/manual_memcpy.stderr @@ -79,49 +79,49 @@ LL | for i in 0..0 { | ^^^^ help: try replacing the loop by: `dst[..0].clone_from_slice(&src[..0])` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:121:14 + --> $DIR/manual_memcpy.rs:120:14 | LL | for i in 3..src.len() { | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[3..src.len()].clone_from_slice(&src[..(src.len() - 3)])` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:127:14 + --> $DIR/manual_memcpy.rs:126:14 | LL | for i in 3..src.len() { | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..(src.len() - 3)].clone_from_slice(&src[3..])` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:133:14 + --> $DIR/manual_memcpy.rs:132:14 | LL | for i in 0..src.len() { | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[3..(src.len() + 3)].clone_from_slice(&src[..])` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:139:14 + --> $DIR/manual_memcpy.rs:138:14 | LL | for i in 0..src.len() { | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[3..(src.len() + 3)])` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:145:14 + --> $DIR/manual_memcpy.rs:144:14 | LL | for i in 3..(3 + src.len()) { | ^^^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[3..((3 + src.len()))].clone_from_slice(&src[..((3 + src.len()) - 3)])` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:151:14 + --> $DIR/manual_memcpy.rs:150:14 | LL | for i in 5..src.len() { | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[5..src.len()].clone_from_slice(&src[(3 - 2)..((src.len() - 2) + 3 - 5)])` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:157:14 + --> $DIR/manual_memcpy.rs:156:14 | LL | for i in 3..10 { | ^^^^^ help: try replacing the loop by: `dst[3..10].clone_from_slice(&src[5..(10 + 5 - 3)])` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:164:14 + --> $DIR/manual_memcpy.rs:163:14 | LL | for i in 0..src.len() { | ^^^^^^^^^^^^ @@ -133,13 +133,13 @@ LL | dst2[30..(src.len() + 30)].clone_from_slice(&src[..]) { | error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:174:14 + --> $DIR/manual_memcpy.rs:173:14 | LL | for i in 0..1 << 1 { | ^^^^^^^^^ help: try replacing the loop by: `dst[(0 << 1)..((1 << 1) + (0 << 1))].clone_from_slice(&src[2..((1 << 1) + 2)])` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:182:14 + --> $DIR/manual_memcpy.rs:181:14 | LL | for i in 0..src.len() { | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])` From 99aceebf1c7cb382e18d66914bd9f576e529aa99 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Sun, 27 Sep 2020 16:38:41 +1300 Subject: [PATCH 035/446] Use the spans of the entire `for` loops for suggestions --- clippy_lints/src/loops.rs | 23 ++-- tests/ui/manual_memcpy.stderr | 196 ++++++++++++++++++++++------------ 2 files changed, 140 insertions(+), 79 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index f2df53aee4f..7c8b6f483bc 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -779,6 +779,17 @@ fn check_for_loop<'tcx>( detect_same_item_push(cx, pat, arg, body, expr); } +// this function assumes the given expression is a `for` loop. +fn get_span_of_entire_for_loop(expr: &Expr<'_>) -> Span { + // for some reason this is the only way to get the `Span` + // of the entire `for` loop + if let ExprKind::Match(_, arms, _) = &expr.kind { + arms[0].body.span + } else { + unreachable!() + } +} + fn same_var<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, var: HirId) -> bool { if_chain! { if let ExprKind::Path(qpath) = &expr.kind; @@ -1138,7 +1149,7 @@ fn build_manual_memcpy_suggestion<'tcx>( }; format!( - "{}.clone_from_slice(&{}[{}..{}])", + "{}.clone_from_slice(&{}[{}..{}]);", dst, src_base_str, src_offset.maybe_par(), @@ -1218,7 +1229,7 @@ fn detect_manual_memcpy<'tcx>( span_lint_and_sugg( cx, MANUAL_MEMCPY, - expr.span, + get_span_of_entire_for_loop(expr), "it looks like you're manually copying between slices", "try replacing the loop by", big_sugg, @@ -1734,13 +1745,7 @@ fn check_for_loop_explicit_counter<'tcx>( then { let mut applicability = Applicability::MachineApplicable; - // for some reason this is the only way to get the `Span` - // of the entire `for` loop - let for_span = if let ExprKind::Match(_, arms, _) = &expr.kind { - arms[0].body.span - } else { - unreachable!() - }; + let for_span = get_span_of_entire_for_loop(expr); span_lint_and_sugg( cx, diff --git a/tests/ui/manual_memcpy.stderr b/tests/ui/manual_memcpy.stderr index 464b18984fb..db62ed90d97 100644 --- a/tests/ui/manual_memcpy.stderr +++ b/tests/ui/manual_memcpy.stderr @@ -1,148 +1,204 @@ error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:7:14 + --> $DIR/manual_memcpy.rs:7:5 | -LL | for i in 0..src.len() { - | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])` +LL | / for i in 0..src.len() { +LL | | dst[i] = src[i]; +LL | | } + | |_____^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..]);` | = note: `-D clippy::manual-memcpy` implied by `-D warnings` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:12:14 + --> $DIR/manual_memcpy.rs:12:5 | -LL | for i in 0..src.len() { - | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[10..(src.len() + 10)].clone_from_slice(&src[..])` +LL | / for i in 0..src.len() { +LL | | dst[i + 10] = src[i]; +LL | | } + | |_____^ help: try replacing the loop by: `dst[10..(src.len() + 10)].clone_from_slice(&src[..]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:17:14 + --> $DIR/manual_memcpy.rs:17:5 | -LL | for i in 0..src.len() { - | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[10..(src.len() + 10)])` +LL | / for i in 0..src.len() { +LL | | dst[i] = src[i + 10]; +LL | | } + | |_____^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[10..(src.len() + 10)]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:22:14 + --> $DIR/manual_memcpy.rs:22:5 | -LL | for i in 11..src.len() { - | ^^^^^^^^^^^^^ help: try replacing the loop by: `dst[11..src.len()].clone_from_slice(&src[(11 - 10)..(src.len() - 10)])` +LL | / for i in 11..src.len() { +LL | | dst[i] = src[i - 10]; +LL | | } + | |_____^ help: try replacing the loop by: `dst[11..src.len()].clone_from_slice(&src[(11 - 10)..(src.len() - 10)]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:27:14 + --> $DIR/manual_memcpy.rs:27:5 | -LL | for i in 0..dst.len() { - | ^^^^^^^^^^^^ help: try replacing the loop by: `dst.clone_from_slice(&src[..dst.len()])` +LL | / for i in 0..dst.len() { +LL | | dst[i] = src[i]; +LL | | } + | |_____^ help: try replacing the loop by: `dst.clone_from_slice(&src[..dst.len()]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:40:14 + --> $DIR/manual_memcpy.rs:40:5 | -LL | for i in 10..256 { - | ^^^^^^^ +LL | / for i in 10..256 { +LL | | dst[i] = src[i - 5]; +LL | | dst2[i + 500] = src[i] +LL | | } + | |_____^ | help: try replacing the loop by | -LL | for i in dst[10..256].clone_from_slice(&src[(10 - 5)..(256 - 5)]) -LL | dst2[(10 + 500)..(256 + 500)].clone_from_slice(&src[10..256]) { +LL | dst[10..256].clone_from_slice(&src[(10 - 5)..(256 - 5)]); +LL | dst2[(10 + 500)..(256 + 500)].clone_from_slice(&src[10..256]); | error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:52:14 + --> $DIR/manual_memcpy.rs:52:5 | -LL | for i in 10..LOOP_OFFSET { - | ^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[(10 + LOOP_OFFSET)..(LOOP_OFFSET + LOOP_OFFSET)].clone_from_slice(&src[(10 - some_var)..(LOOP_OFFSET - some_var)])` +LL | / for i in 10..LOOP_OFFSET { +LL | | dst[i + LOOP_OFFSET] = src[i - some_var]; +LL | | } + | |_____^ help: try replacing the loop by: `dst[(10 + LOOP_OFFSET)..(LOOP_OFFSET + LOOP_OFFSET)].clone_from_slice(&src[(10 - some_var)..(LOOP_OFFSET - some_var)]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:65:14 + --> $DIR/manual_memcpy.rs:65:5 | -LL | for i in 0..src_vec.len() { - | ^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst_vec[..src_vec.len()].clone_from_slice(&src_vec[..])` +LL | / for i in 0..src_vec.len() { +LL | | dst_vec[i] = src_vec[i]; +LL | | } + | |_____^ help: try replacing the loop by: `dst_vec[..src_vec.len()].clone_from_slice(&src_vec[..]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:94:14 + --> $DIR/manual_memcpy.rs:94:5 | -LL | for i in from..from + src.len() { - | ^^^^^^^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..(from + src.len())].clone_from_slice(&src[..(from + src.len() - from)])` +LL | / for i in from..from + src.len() { +LL | | dst[i] = src[i - from]; +LL | | } + | |_____^ help: try replacing the loop by: `dst[from..(from + src.len())].clone_from_slice(&src[..(from + src.len() - from)]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:98:14 + --> $DIR/manual_memcpy.rs:98:5 | -LL | for i in from..from + 3 { - | ^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..(from + 3)].clone_from_slice(&src[..(from + 3 - from)])` +LL | / for i in from..from + 3 { +LL | | dst[i] = src[i - from]; +LL | | } + | |_____^ help: try replacing the loop by: `dst[from..(from + 3)].clone_from_slice(&src[..(from + 3 - from)]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:103:14 + --> $DIR/manual_memcpy.rs:103:5 | -LL | for i in 0..5 { - | ^^^^ help: try replacing the loop by: `dst[..5].clone_from_slice(&src[..5])` +LL | / for i in 0..5 { +LL | | dst[i - 0] = src[i]; +LL | | } + | |_____^ help: try replacing the loop by: `dst[..5].clone_from_slice(&src[..5]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:108:14 + --> $DIR/manual_memcpy.rs:108:5 | -LL | for i in 0..0 { - | ^^^^ help: try replacing the loop by: `dst[..0].clone_from_slice(&src[..0])` +LL | / for i in 0..0 { +LL | | dst[i] = src[i]; +LL | | } + | |_____^ help: try replacing the loop by: `dst[..0].clone_from_slice(&src[..0]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:120:14 + --> $DIR/manual_memcpy.rs:120:5 | -LL | for i in 3..src.len() { - | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[3..src.len()].clone_from_slice(&src[..(src.len() - 3)])` +LL | / for i in 3..src.len() { +LL | | dst[i] = src[count]; +LL | | count += 1; +LL | | } + | |_____^ help: try replacing the loop by: `dst[3..src.len()].clone_from_slice(&src[..(src.len() - 3)]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:126:14 + --> $DIR/manual_memcpy.rs:126:5 | -LL | for i in 3..src.len() { - | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..(src.len() - 3)].clone_from_slice(&src[3..])` +LL | / for i in 3..src.len() { +LL | | dst[count] = src[i]; +LL | | count += 1; +LL | | } + | |_____^ help: try replacing the loop by: `dst[..(src.len() - 3)].clone_from_slice(&src[3..]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:132:14 + --> $DIR/manual_memcpy.rs:132:5 | -LL | for i in 0..src.len() { - | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[3..(src.len() + 3)].clone_from_slice(&src[..])` +LL | / for i in 0..src.len() { +LL | | dst[count] = src[i]; +LL | | count += 1; +LL | | } + | |_____^ help: try replacing the loop by: `dst[3..(src.len() + 3)].clone_from_slice(&src[..]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:138:14 + --> $DIR/manual_memcpy.rs:138:5 | -LL | for i in 0..src.len() { - | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[3..(src.len() + 3)])` +LL | / for i in 0..src.len() { +LL | | dst[i] = src[count]; +LL | | count += 1; +LL | | } + | |_____^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[3..(src.len() + 3)]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:144:14 + --> $DIR/manual_memcpy.rs:144:5 | -LL | for i in 3..(3 + src.len()) { - | ^^^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[3..((3 + src.len()))].clone_from_slice(&src[..((3 + src.len()) - 3)])` +LL | / for i in 3..(3 + src.len()) { +LL | | dst[i] = src[count]; +LL | | count += 1; +LL | | } + | |_____^ help: try replacing the loop by: `dst[3..((3 + src.len()))].clone_from_slice(&src[..((3 + src.len()) - 3)]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:150:14 + --> $DIR/manual_memcpy.rs:150:5 | -LL | for i in 5..src.len() { - | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[5..src.len()].clone_from_slice(&src[(3 - 2)..((src.len() - 2) + 3 - 5)])` +LL | / for i in 5..src.len() { +LL | | dst[i] = src[count - 2]; +LL | | count += 1; +LL | | } + | |_____^ help: try replacing the loop by: `dst[5..src.len()].clone_from_slice(&src[(3 - 2)..((src.len() - 2) + 3 - 5)]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:156:14 + --> $DIR/manual_memcpy.rs:156:5 | -LL | for i in 3..10 { - | ^^^^^ help: try replacing the loop by: `dst[3..10].clone_from_slice(&src[5..(10 + 5 - 3)])` +LL | / for i in 3..10 { +LL | | dst[i] = src[count]; +LL | | count += 1; +LL | | } + | |_____^ help: try replacing the loop by: `dst[3..10].clone_from_slice(&src[5..(10 + 5 - 3)]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:163:14 + --> $DIR/manual_memcpy.rs:163:5 | -LL | for i in 0..src.len() { - | ^^^^^^^^^^^^ +LL | / for i in 0..src.len() { +LL | | dst[count] = src[i]; +LL | | dst2[count2] = src[i]; +LL | | count += 1; +LL | | count2 += 1; +LL | | } + | |_____^ | help: try replacing the loop by | -LL | for i in dst[3..(src.len() + 3)].clone_from_slice(&src[..]) -LL | dst2[30..(src.len() + 30)].clone_from_slice(&src[..]) { +LL | dst[3..(src.len() + 3)].clone_from_slice(&src[..]); +LL | dst2[30..(src.len() + 30)].clone_from_slice(&src[..]); | error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:173:14 + --> $DIR/manual_memcpy.rs:173:5 | -LL | for i in 0..1 << 1 { - | ^^^^^^^^^ help: try replacing the loop by: `dst[(0 << 1)..((1 << 1) + (0 << 1))].clone_from_slice(&src[2..((1 << 1) + 2)])` +LL | / for i in 0..1 << 1 { +LL | | dst[count] = src[i + 2]; +LL | | count += 1; +LL | | } + | |_____^ help: try replacing the loop by: `dst[(0 << 1)..((1 << 1) + (0 << 1))].clone_from_slice(&src[2..((1 << 1) + 2)]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:181:14 + --> $DIR/manual_memcpy.rs:181:5 | -LL | for i in 0..src.len() { - | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])` +LL | / for i in 0..src.len() { +LL | | dst[i] = src[i].clone(); +LL | | } + | |_____^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..]);` error: aborting due to 22 previous errors From 9725f00f4dd089b875a5d5306ff906494e041f38 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Mon, 28 Sep 2020 02:27:55 +1300 Subject: [PATCH 036/446] Use the `From` trait to make `MinifyingSugg` --- clippy_lints/src/loops.rs | 84 +++++++++++++++------------------- clippy_lints/src/utils/sugg.rs | 6 ++- 2 files changed, 42 insertions(+), 48 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 7c8b6f483bc..215700fed8c 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -817,22 +817,22 @@ struct Offset { } impl Offset { - fn negative(value: MinifyingSugg<'static>) -> Self { + fn negative(value: Sugg<'static>) -> Self { Self { - value, + value: value.into(), sign: OffsetSign::Negative, } } - fn positive(value: MinifyingSugg<'static>) -> Self { + fn positive(value: Sugg<'static>) -> Self { Self { - value, + value: value.into(), sign: OffsetSign::Positive, } } fn empty() -> Self { - Self::positive(MinifyingSugg::non_paren("0")) + Self::positive(sugg::ZERO) } } @@ -844,30 +844,22 @@ fn apply_offset(lhs: &MinifyingSugg<'static>, rhs: &Offset) -> MinifyingSugg<'st } #[derive(Clone)] -struct MinifyingSugg<'a>(sugg::Sugg<'a>); - -impl std::fmt::Display for MinifyingSugg<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - std::fmt::Display::fmt(&self.0, f) - } -} +struct MinifyingSugg<'a>(Sugg<'a>); impl<'a> MinifyingSugg<'a> { fn as_str(&self) -> &str { - let sugg::Sugg::NonParen(s) | sugg::Sugg::MaybeParen(s) | sugg::Sugg::BinOp(_, s) = &self.0; + let Sugg::NonParen(s) | Sugg::MaybeParen(s) | Sugg::BinOp(_, s) = &self.0; s.as_ref() } - fn hir(cx: &LateContext<'_>, expr: &Expr<'_>, default: &'a str) -> Self { - Self(sugg::Sugg::hir(cx, expr, default)) + fn into_sugg(self) -> Sugg<'a> { + self.0 } +} - fn maybe_par(self) -> Self { - Self(self.0.maybe_par()) - } - - fn non_paren(str: impl Into>) -> Self { - Self(sugg::Sugg::NonParen(str.into())) +impl<'a> From> for MinifyingSugg<'a> { + fn from(sugg: Sugg<'a>) -> Self { + Self(sugg) } } @@ -877,7 +869,7 @@ impl std::ops::Add for &MinifyingSugg<'static> { match (self.as_str(), rhs.as_str()) { ("0", _) => rhs.clone(), (_, "0") => self.clone(), - (_, _) => MinifyingSugg(&self.0 + &rhs.0), + (_, _) => (&self.0 + &rhs.0).into(), } } } @@ -887,9 +879,9 @@ impl std::ops::Sub for &MinifyingSugg<'static> { fn sub(self, rhs: &MinifyingSugg<'static>) -> MinifyingSugg<'static> { match (self.as_str(), rhs.as_str()) { (_, "0") => self.clone(), - ("0", _) => MinifyingSugg(-(rhs.0.clone())), - (x, y) if x == y => MinifyingSugg::non_paren("0"), - (_, _) => MinifyingSugg(&self.0 - &rhs.0), + ("0", _) => (-rhs.0.clone()).into(), + (x, y) if x == y => sugg::ZERO.into(), + (_, _) => (&self.0 - &rhs.0).into(), } } } @@ -900,7 +892,7 @@ impl std::ops::Add<&MinifyingSugg<'static>> for MinifyingSugg<'static> { match (self.as_str(), rhs.as_str()) { ("0", _) => rhs.clone(), (_, "0") => self, - (_, _) => MinifyingSugg(self.0 + &rhs.0), + (_, _) => (self.0 + &rhs.0).into(), } } } @@ -910,9 +902,9 @@ impl std::ops::Sub<&MinifyingSugg<'static>> for MinifyingSugg<'static> { fn sub(self, rhs: &MinifyingSugg<'static>) -> MinifyingSugg<'static> { match (self.as_str(), rhs.as_str()) { (_, "0") => self, - ("0", _) => MinifyingSugg(-(rhs.0.clone())), - (x, y) if x == y => MinifyingSugg::non_paren("0"), - (_, _) => MinifyingSugg(self.0 - &rhs.0), + ("0", _) => (-rhs.0.clone()).into(), + (x, y) if x == y => sugg::ZERO.into(), + (_, _) => (self.0 - &rhs.0).into(), } } } @@ -969,19 +961,15 @@ fn get_details_from_idx<'tcx>( }) } - fn get_offset<'tcx>( - cx: &LateContext<'tcx>, - e: &Expr<'_>, - starts: &[Start<'tcx>], - ) -> Option> { + fn get_offset<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>, starts: &[Start<'tcx>]) -> Option> { match &e.kind { ExprKind::Lit(l) => match l.node { - ast::LitKind::Int(x, _ty) => Some(MinifyingSugg::non_paren(x.to_string())), + ast::LitKind::Int(x, _ty) => Some(Sugg::NonParen(x.to_string().into())), _ => None, }, ExprKind::Path(..) if get_start(cx, e, starts).is_none() => { // `e` is always non paren as it's a `Path` - Some(MinifyingSugg::non_paren(snippet(cx, e.span, "???"))) + Some(Sugg::NonParen(snippet(cx, e.span, "???"))) }, _ => None, } @@ -1072,7 +1060,7 @@ fn build_manual_memcpy_suggestion<'tcx>( ) -> String { fn print_offset(offset: MinifyingSugg<'static>) -> MinifyingSugg<'static> { if offset.as_str() == "0" { - MinifyingSugg::non_paren("") + sugg::EMPTY.into() } else { offset } @@ -1088,14 +1076,14 @@ fn build_manual_memcpy_suggestion<'tcx>( if var_def_id(cx, arg) == var_def_id(cx, base); then { if sugg.as_str() == end_str { - MinifyingSugg::non_paren("") + sugg::EMPTY.into() } else { sugg } } else { match limits { ast::RangeLimits::Closed => { - sugg + &MinifyingSugg::non_paren("1") + sugg + &sugg::ONE.into() }, ast::RangeLimits::HalfOpen => sugg, } @@ -1103,29 +1091,31 @@ fn build_manual_memcpy_suggestion<'tcx>( } }; - let start_str = MinifyingSugg::hir(cx, start, ""); - let end_str = MinifyingSugg::hir(cx, end, ""); + let start_str = Sugg::hir(cx, start, "").into(); + let end_str: MinifyingSugg<'_> = Sugg::hir(cx, end, "").into(); let print_offset_and_limit = |idx_expr: &IndexExpr<'_>| match idx_expr.idx { StartKind::Range => ( - print_offset(apply_offset(&start_str, &idx_expr.idx_offset)), + print_offset(apply_offset(&start_str, &idx_expr.idx_offset)).into_sugg(), print_limit( end, end_str.as_str(), idx_expr.base, apply_offset(&end_str, &idx_expr.idx_offset), - ), + ) + .into_sugg(), ), StartKind::Counter { initializer } => { - let counter_start = MinifyingSugg::hir(cx, initializer, ""); + let counter_start = Sugg::hir(cx, initializer, "").into(); ( - print_offset(apply_offset(&counter_start, &idx_expr.idx_offset)), + print_offset(apply_offset(&counter_start, &idx_expr.idx_offset)).into_sugg(), print_limit( end, end_str.as_str(), idx_expr.base, apply_offset(&end_str, &idx_expr.idx_offset) + &counter_start - &start_str, - ), + ) + .into_sugg(), ) }, }; @@ -1136,7 +1126,7 @@ fn build_manual_memcpy_suggestion<'tcx>( let dst_base_str = snippet(cx, dst.base.span, "???"); let src_base_str = snippet(cx, src.base.span, "???"); - let dst = if dst_offset.as_str() == "" && dst_limit.as_str() == "" { + let dst = if dst_offset == sugg::EMPTY && dst_limit == sugg::EMPTY { dst_base_str } else { format!( diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 062b273c0f4..0b2cb667bf4 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -16,7 +16,7 @@ use std::fmt::Display; use std::ops::{Add, Neg, Not, Sub}; /// A helper type to build suggestion correctly handling parenthesis. -#[derive(Clone)] +#[derive(Clone, PartialEq)] pub enum Sugg<'a> { /// An expression that never needs parenthesis such as `1337` or `[0; 42]`. NonParen(Cow<'a, str>), @@ -27,8 +27,12 @@ pub enum Sugg<'a> { BinOp(AssocOp, Cow<'a, str>), } +/// Literal constant `0`, for convenience. +pub const ZERO: Sugg<'static> = Sugg::NonParen(Cow::Borrowed("0")); /// Literal constant `1`, for convenience. pub const ONE: Sugg<'static> = Sugg::NonParen(Cow::Borrowed("1")); +/// a constant represents an empty string, for convenience. +pub const EMPTY: Sugg<'static> = Sugg::NonParen(Cow::Borrowed("")); impl Display for Sugg<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { From ec94bd6cb45e337fd10ca19fadb9a71ecb67db5f Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Mon, 28 Sep 2020 02:43:45 +1300 Subject: [PATCH 037/446] split up the `manual_memcpy` test --- tests/ui/manual_memcpy/with_loop_counters.rs | 64 ++++++++++ .../manual_memcpy/with_loop_counters.stderr | 93 ++++++++++++++ .../without_loop_counters.rs} | 61 --------- .../without_loop_counters.stderr} | 117 +++--------------- 4 files changed, 171 insertions(+), 164 deletions(-) create mode 100644 tests/ui/manual_memcpy/with_loop_counters.rs create mode 100644 tests/ui/manual_memcpy/with_loop_counters.stderr rename tests/ui/{manual_memcpy.rs => manual_memcpy/without_loop_counters.rs} (68%) rename tests/ui/{manual_memcpy.stderr => manual_memcpy/without_loop_counters.stderr} (50%) diff --git a/tests/ui/manual_memcpy/with_loop_counters.rs b/tests/ui/manual_memcpy/with_loop_counters.rs new file mode 100644 index 00000000000..a49ba9eb10a --- /dev/null +++ b/tests/ui/manual_memcpy/with_loop_counters.rs @@ -0,0 +1,64 @@ +#![warn(clippy::needless_range_loop, clippy::manual_memcpy)] + +pub fn manual_copy_with_counters(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) { + let mut count = 0; + for i in 3..src.len() { + dst[i] = src[count]; + count += 1; + } + + let mut count = 0; + for i in 3..src.len() { + dst[count] = src[i]; + count += 1; + } + + let mut count = 3; + for i in 0..src.len() { + dst[count] = src[i]; + count += 1; + } + + let mut count = 3; + for i in 0..src.len() { + dst[i] = src[count]; + count += 1; + } + + let mut count = 0; + for i in 3..(3 + src.len()) { + dst[i] = src[count]; + count += 1; + } + + let mut count = 3; + for i in 5..src.len() { + dst[i] = src[count - 2]; + count += 1; + } + + let mut count = 5; + for i in 3..10 { + dst[i] = src[count]; + count += 1; + } + + let mut count = 3; + let mut count2 = 30; + for i in 0..src.len() { + dst[count] = src[i]; + dst2[count2] = src[i]; + count += 1; + count2 += 1; + } + + // make sure parentheses are added properly to bitwise operators, which have lower precedence than + // arithmetric ones + let mut count = 0 << 1; + for i in 0..1 << 1 { + dst[count] = src[i + 2]; + count += 1; + } +} + +fn main() {} diff --git a/tests/ui/manual_memcpy/with_loop_counters.stderr b/tests/ui/manual_memcpy/with_loop_counters.stderr new file mode 100644 index 00000000000..24393ad9b4d --- /dev/null +++ b/tests/ui/manual_memcpy/with_loop_counters.stderr @@ -0,0 +1,93 @@ +error: it looks like you're manually copying between slices + --> $DIR/with_loop_counters.rs:5:5 + | +LL | / for i in 3..src.len() { +LL | | dst[i] = src[count]; +LL | | count += 1; +LL | | } + | |_____^ help: try replacing the loop by: `dst[3..src.len()].clone_from_slice(&src[..(src.len() - 3)]);` + | + = note: `-D clippy::manual-memcpy` implied by `-D warnings` + +error: it looks like you're manually copying between slices + --> $DIR/with_loop_counters.rs:11:5 + | +LL | / for i in 3..src.len() { +LL | | dst[count] = src[i]; +LL | | count += 1; +LL | | } + | |_____^ help: try replacing the loop by: `dst[..(src.len() - 3)].clone_from_slice(&src[3..]);` + +error: it looks like you're manually copying between slices + --> $DIR/with_loop_counters.rs:17:5 + | +LL | / for i in 0..src.len() { +LL | | dst[count] = src[i]; +LL | | count += 1; +LL | | } + | |_____^ help: try replacing the loop by: `dst[3..(src.len() + 3)].clone_from_slice(&src[..]);` + +error: it looks like you're manually copying between slices + --> $DIR/with_loop_counters.rs:23:5 + | +LL | / for i in 0..src.len() { +LL | | dst[i] = src[count]; +LL | | count += 1; +LL | | } + | |_____^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[3..(src.len() + 3)]);` + +error: it looks like you're manually copying between slices + --> $DIR/with_loop_counters.rs:29:5 + | +LL | / for i in 3..(3 + src.len()) { +LL | | dst[i] = src[count]; +LL | | count += 1; +LL | | } + | |_____^ help: try replacing the loop by: `dst[3..((3 + src.len()))].clone_from_slice(&src[..((3 + src.len()) - 3)]);` + +error: it looks like you're manually copying between slices + --> $DIR/with_loop_counters.rs:35:5 + | +LL | / for i in 5..src.len() { +LL | | dst[i] = src[count - 2]; +LL | | count += 1; +LL | | } + | |_____^ help: try replacing the loop by: `dst[5..src.len()].clone_from_slice(&src[(3 - 2)..((src.len() - 2) + 3 - 5)]);` + +error: it looks like you're manually copying between slices + --> $DIR/with_loop_counters.rs:41:5 + | +LL | / for i in 3..10 { +LL | | dst[i] = src[count]; +LL | | count += 1; +LL | | } + | |_____^ help: try replacing the loop by: `dst[3..10].clone_from_slice(&src[5..(10 + 5 - 3)]);` + +error: it looks like you're manually copying between slices + --> $DIR/with_loop_counters.rs:48:5 + | +LL | / for i in 0..src.len() { +LL | | dst[count] = src[i]; +LL | | dst2[count2] = src[i]; +LL | | count += 1; +LL | | count2 += 1; +LL | | } + | |_____^ + | +help: try replacing the loop by + | +LL | dst[3..(src.len() + 3)].clone_from_slice(&src[..]); +LL | dst2[30..(src.len() + 30)].clone_from_slice(&src[..]); + | + +error: it looks like you're manually copying between slices + --> $DIR/with_loop_counters.rs:58:5 + | +LL | / for i in 0..1 << 1 { +LL | | dst[count] = src[i + 2]; +LL | | count += 1; +LL | | } + | |_____^ help: try replacing the loop by: `dst[(0 << 1)..((1 << 1) + (0 << 1))].clone_from_slice(&src[2..((1 << 1) + 2)]);` + +error: aborting due to 9 previous errors + diff --git a/tests/ui/manual_memcpy.rs b/tests/ui/manual_memcpy/without_loop_counters.rs similarity index 68% rename from tests/ui/manual_memcpy.rs rename to tests/ui/manual_memcpy/without_loop_counters.rs index 84758275dd7..0083f94798f 100644 --- a/tests/ui/manual_memcpy.rs +++ b/tests/ui/manual_memcpy/without_loop_counters.rs @@ -115,67 +115,6 @@ pub fn manual_copy(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) { } } -pub fn manual_copy_with_counters(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) { - let mut count = 0; - for i in 3..src.len() { - dst[i] = src[count]; - count += 1; - } - - let mut count = 0; - for i in 3..src.len() { - dst[count] = src[i]; - count += 1; - } - - let mut count = 3; - for i in 0..src.len() { - dst[count] = src[i]; - count += 1; - } - - let mut count = 3; - for i in 0..src.len() { - dst[i] = src[count]; - count += 1; - } - - let mut count = 0; - for i in 3..(3 + src.len()) { - dst[i] = src[count]; - count += 1; - } - - let mut count = 3; - for i in 5..src.len() { - dst[i] = src[count - 2]; - count += 1; - } - - let mut count = 5; - for i in 3..10 { - dst[i] = src[count]; - count += 1; - } - - let mut count = 3; - let mut count2 = 30; - for i in 0..src.len() { - dst[count] = src[i]; - dst2[count2] = src[i]; - count += 1; - count2 += 1; - } - - // make sure parentheses are added properly to bitwise operators, which have lower precedence than - // arithmetric ones - let mut count = 0 << 1; - for i in 0..1 << 1 { - dst[count] = src[i + 2]; - count += 1; - } -} - #[warn(clippy::needless_range_loop, clippy::manual_memcpy)] pub fn manual_clone(src: &[String], dst: &mut [String]) { for i in 0..src.len() { diff --git a/tests/ui/manual_memcpy.stderr b/tests/ui/manual_memcpy/without_loop_counters.stderr similarity index 50% rename from tests/ui/manual_memcpy.stderr rename to tests/ui/manual_memcpy/without_loop_counters.stderr index db62ed90d97..54b966f6e54 100644 --- a/tests/ui/manual_memcpy.stderr +++ b/tests/ui/manual_memcpy/without_loop_counters.stderr @@ -1,5 +1,5 @@ error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:7:5 + --> $DIR/without_loop_counters.rs:7:5 | LL | / for i in 0..src.len() { LL | | dst[i] = src[i]; @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::manual-memcpy` implied by `-D warnings` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:12:5 + --> $DIR/without_loop_counters.rs:12:5 | LL | / for i in 0..src.len() { LL | | dst[i + 10] = src[i]; @@ -17,7 +17,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[10..(src.len() + 10)].clone_from_slice(&src[..]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:17:5 + --> $DIR/without_loop_counters.rs:17:5 | LL | / for i in 0..src.len() { LL | | dst[i] = src[i + 10]; @@ -25,7 +25,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[10..(src.len() + 10)]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:22:5 + --> $DIR/without_loop_counters.rs:22:5 | LL | / for i in 11..src.len() { LL | | dst[i] = src[i - 10]; @@ -33,7 +33,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[11..src.len()].clone_from_slice(&src[(11 - 10)..(src.len() - 10)]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:27:5 + --> $DIR/without_loop_counters.rs:27:5 | LL | / for i in 0..dst.len() { LL | | dst[i] = src[i]; @@ -41,7 +41,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst.clone_from_slice(&src[..dst.len()]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:40:5 + --> $DIR/without_loop_counters.rs:40:5 | LL | / for i in 10..256 { LL | | dst[i] = src[i - 5]; @@ -56,7 +56,7 @@ LL | dst2[(10 + 500)..(256 + 500)].clone_from_slice(&src[10..256]); | error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:52:5 + --> $DIR/without_loop_counters.rs:52:5 | LL | / for i in 10..LOOP_OFFSET { LL | | dst[i + LOOP_OFFSET] = src[i - some_var]; @@ -64,7 +64,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[(10 + LOOP_OFFSET)..(LOOP_OFFSET + LOOP_OFFSET)].clone_from_slice(&src[(10 - some_var)..(LOOP_OFFSET - some_var)]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:65:5 + --> $DIR/without_loop_counters.rs:65:5 | LL | / for i in 0..src_vec.len() { LL | | dst_vec[i] = src_vec[i]; @@ -72,7 +72,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst_vec[..src_vec.len()].clone_from_slice(&src_vec[..]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:94:5 + --> $DIR/without_loop_counters.rs:94:5 | LL | / for i in from..from + src.len() { LL | | dst[i] = src[i - from]; @@ -80,7 +80,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[from..(from + src.len())].clone_from_slice(&src[..(from + src.len() - from)]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:98:5 + --> $DIR/without_loop_counters.rs:98:5 | LL | / for i in from..from + 3 { LL | | dst[i] = src[i - from]; @@ -88,7 +88,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[from..(from + 3)].clone_from_slice(&src[..(from + 3 - from)]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:103:5 + --> $DIR/without_loop_counters.rs:103:5 | LL | / for i in 0..5 { LL | | dst[i - 0] = src[i]; @@ -96,7 +96,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[..5].clone_from_slice(&src[..5]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:108:5 + --> $DIR/without_loop_counters.rs:108:5 | LL | / for i in 0..0 { LL | | dst[i] = src[i]; @@ -104,101 +104,12 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[..0].clone_from_slice(&src[..0]);` error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:120:5 - | -LL | / for i in 3..src.len() { -LL | | dst[i] = src[count]; -LL | | count += 1; -LL | | } - | |_____^ help: try replacing the loop by: `dst[3..src.len()].clone_from_slice(&src[..(src.len() - 3)]);` - -error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:126:5 - | -LL | / for i in 3..src.len() { -LL | | dst[count] = src[i]; -LL | | count += 1; -LL | | } - | |_____^ help: try replacing the loop by: `dst[..(src.len() - 3)].clone_from_slice(&src[3..]);` - -error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:132:5 - | -LL | / for i in 0..src.len() { -LL | | dst[count] = src[i]; -LL | | count += 1; -LL | | } - | |_____^ help: try replacing the loop by: `dst[3..(src.len() + 3)].clone_from_slice(&src[..]);` - -error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:138:5 - | -LL | / for i in 0..src.len() { -LL | | dst[i] = src[count]; -LL | | count += 1; -LL | | } - | |_____^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[3..(src.len() + 3)]);` - -error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:144:5 - | -LL | / for i in 3..(3 + src.len()) { -LL | | dst[i] = src[count]; -LL | | count += 1; -LL | | } - | |_____^ help: try replacing the loop by: `dst[3..((3 + src.len()))].clone_from_slice(&src[..((3 + src.len()) - 3)]);` - -error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:150:5 - | -LL | / for i in 5..src.len() { -LL | | dst[i] = src[count - 2]; -LL | | count += 1; -LL | | } - | |_____^ help: try replacing the loop by: `dst[5..src.len()].clone_from_slice(&src[(3 - 2)..((src.len() - 2) + 3 - 5)]);` - -error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:156:5 - | -LL | / for i in 3..10 { -LL | | dst[i] = src[count]; -LL | | count += 1; -LL | | } - | |_____^ help: try replacing the loop by: `dst[3..10].clone_from_slice(&src[5..(10 + 5 - 3)]);` - -error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:163:5 - | -LL | / for i in 0..src.len() { -LL | | dst[count] = src[i]; -LL | | dst2[count2] = src[i]; -LL | | count += 1; -LL | | count2 += 1; -LL | | } - | |_____^ - | -help: try replacing the loop by - | -LL | dst[3..(src.len() + 3)].clone_from_slice(&src[..]); -LL | dst2[30..(src.len() + 30)].clone_from_slice(&src[..]); - | - -error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:173:5 - | -LL | / for i in 0..1 << 1 { -LL | | dst[count] = src[i + 2]; -LL | | count += 1; -LL | | } - | |_____^ help: try replacing the loop by: `dst[(0 << 1)..((1 << 1) + (0 << 1))].clone_from_slice(&src[2..((1 << 1) + 2)]);` - -error: it looks like you're manually copying between slices - --> $DIR/manual_memcpy.rs:181:5 + --> $DIR/without_loop_counters.rs:120:5 | LL | / for i in 0..src.len() { LL | | dst[i] = src[i].clone(); LL | | } | |_____^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..]);` -error: aborting due to 22 previous errors +error: aborting due to 13 previous errors From a7bd6c449aef07dc8daa889f4ddbdda326593e32 Mon Sep 17 00:00:00 2001 From: follower Date: Mon, 28 Sep 2020 04:05:39 +1300 Subject: [PATCH 038/446] Link to "Contributing to Rust" rather than "Getting Started". Change to link to "Contributing to Rust" chapter of `rustc` Dev Guide, primarily on the basis that the GitHub "first contribution" Issue "pop-up" says "Be sure to review the [contributing guidelines] and [code of conduct]" and links to this file. When/if the guide/"Getting Started" section gets revised to not be `rustc`-specific the linked section can be changed. In the meantime this prevents leading first time contributors into a confusing cul de sac. --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2a4c42ea0a4..b600074c197 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,14 +2,14 @@ Thank you for your interest in contributing to Rust! -To get started, read the [Getting Started] guide in the [rustc-dev-guide]. +To get started, read the [Contributing to Rust] chapter of the [rustc-dev-guide]. ## Bug reports Did a compiler error message tell you to come here? If you want to create an ICE report, refer to [this section][contributing-bug-reports] and [open an issue][issue template]. -[Getting Started]: https://rustc-dev-guide.rust-lang.org/getting-started.html +[Contributing to Rust]: https://rustc-dev-guide.rust-lang.org/contributing.html#contributing-to-rust [rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/ [contributing-bug-reports]: https://rustc-dev-guide.rust-lang.org/contributing.html#bug-reports [issue template]: https://github.com/rust-lang/rust/issues/new/choose From 549f861f7d53811521cf929cf58fb6828a2a88d9 Mon Sep 17 00:00:00 2001 From: Camelid Date: Sun, 27 Sep 2020 13:36:48 -0700 Subject: [PATCH 039/446] Use correct article in help message for conversion or cast Before it always used `an`; now it uses the correct article for the type. --- compiler/rustc_middle/src/ty/sty.rs | 12 ++ compiler/rustc_typeck/src/check/demand.rs | 14 ++- .../associated-types-path-2.stderr | 2 +- src/test/ui/indexing-requires-a-uint.stderr | 2 +- .../integer-literal-suffix-inference.stderr | 40 +++---- src/test/ui/issues/issue-13359.stderr | 2 +- .../ui/mismatched_types/issue-26480.stderr | 2 +- src/test/ui/numeric/len.stderr | 2 +- src/test/ui/numeric/numeric-cast-2.stderr | 4 +- src/test/ui/numeric/numeric-cast-binop.stderr | 108 ++++++++--------- src/test/ui/numeric/numeric-cast.stderr | 112 +++++++++--------- src/test/ui/numeric/numeric-suffix.stderr | 12 +- src/test/ui/tail-typeck.stderr | 2 +- .../ui/tutorial-suffix-inference-test.stderr | 2 +- 14 files changed, 169 insertions(+), 147 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 724ec101b23..9e60253106b 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -210,6 +210,18 @@ impl TyKind<'tcx> { _ => false, } } + + /// Get the article ("a" or "an") to use with this type. + /// + /// **Panics if `self` is [`TyKind::Error`].** + pub fn article(&self) -> &'static str { + match self { + Int(_) | Float(_) | Array(_, _) => "an", + Adt(def, _) if def.is_enum() => "an", + Error(_) => panic!(), + _ => "a", + } + } } // `TyKind` is used a lot. Make sure it doesn't unintentionally get bigger. diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 247bbf637ce..cd7b692c588 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -752,8 +752,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let msg = format!("you can convert an `{}` to `{}`", checked_ty, expected_ty); - let cast_msg = format!("you can cast an `{} to `{}`", checked_ty, expected_ty); + let msg = format!( + "you can convert {} `{}` to `{}`", + checked_ty.kind().article(), + checked_ty, + expected_ty + ); + let cast_msg = format!( + "you can cast {} `{} to `{}`", + checked_ty.kind().article(), + checked_ty, + expected_ty + ); let lit_msg = format!( "change the type of the numeric literal from `{}` to `{}`", checked_ty, expected_ty, diff --git a/src/test/ui/associated-types/associated-types-path-2.stderr b/src/test/ui/associated-types/associated-types-path-2.stderr index b2599410f05..dfe7e4da22d 100644 --- a/src/test/ui/associated-types/associated-types-path-2.stderr +++ b/src/test/ui/associated-types/associated-types-path-2.stderr @@ -47,7 +47,7 @@ LL | let _: i32 = f2(2i32); | | | expected due to this | -help: you can convert an `u32` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `u32` to `i32` and panic if the converted value wouldn't fit | LL | let _: i32 = f2(2i32).try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/indexing-requires-a-uint.stderr b/src/test/ui/indexing-requires-a-uint.stderr index 31fcd4b1c2e..f290c0e632d 100644 --- a/src/test/ui/indexing-requires-a-uint.stderr +++ b/src/test/ui/indexing-requires-a-uint.stderr @@ -13,7 +13,7 @@ error[E0308]: mismatched types LL | bar::(i); // i should not be re-coerced back to an isize | ^ expected `isize`, found `usize` | -help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `isize` and panic if the converted value wouldn't fit | LL | bar::(i.try_into().unwrap()); // i should not be re-coerced back to an isize | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/integer-literal-suffix-inference.stderr b/src/test/ui/integer-literal-suffix-inference.stderr index b8502768e1d..8b541e6de06 100644 --- a/src/test/ui/integer-literal-suffix-inference.stderr +++ b/src/test/ui/integer-literal-suffix-inference.stderr @@ -328,7 +328,7 @@ error[E0308]: mismatched types LL | id_u8(b16); | ^^^ expected `u8`, found `u16` | -help: you can convert an `u16` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `u16` to `u8` and panic if the converted value wouldn't fit | LL | id_u8(b16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -339,7 +339,7 @@ error[E0308]: mismatched types LL | id_u8(b32); | ^^^ expected `u8`, found `u32` | -help: you can convert an `u32` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `u32` to `u8` and panic if the converted value wouldn't fit | LL | id_u8(b32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -350,7 +350,7 @@ error[E0308]: mismatched types LL | id_u8(b64); | ^^^ expected `u8`, found `u64` | -help: you can convert an `u64` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `u64` to `u8` and panic if the converted value wouldn't fit | LL | id_u8(b64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -361,7 +361,7 @@ error[E0308]: mismatched types LL | id_u8(bsize); | ^^^^^ expected `u8`, found `usize` | -help: you can convert an `usize` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `u8` and panic if the converted value wouldn't fit | LL | id_u8(bsize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -373,7 +373,7 @@ LL | id_u16(b8); | ^^ | | | expected `u16`, found `u8` - | help: you can convert an `u8` to `u16`: `b8.into()` + | help: you can convert a `u8` to `u16`: `b8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:169:12 @@ -381,7 +381,7 @@ error[E0308]: mismatched types LL | id_u16(b32); | ^^^ expected `u16`, found `u32` | -help: you can convert an `u32` to `u16` and panic if the converted value wouldn't fit +help: you can convert a `u32` to `u16` and panic if the converted value wouldn't fit | LL | id_u16(b32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -392,7 +392,7 @@ error[E0308]: mismatched types LL | id_u16(b64); | ^^^ expected `u16`, found `u64` | -help: you can convert an `u64` to `u16` and panic if the converted value wouldn't fit +help: you can convert a `u64` to `u16` and panic if the converted value wouldn't fit | LL | id_u16(b64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -403,7 +403,7 @@ error[E0308]: mismatched types LL | id_u16(bsize); | ^^^^^ expected `u16`, found `usize` | -help: you can convert an `usize` to `u16` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `u16` and panic if the converted value wouldn't fit | LL | id_u16(bsize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -415,7 +415,7 @@ LL | id_u32(b8); | ^^ | | | expected `u32`, found `u8` - | help: you can convert an `u8` to `u32`: `b8.into()` + | help: you can convert a `u8` to `u32`: `b8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:182:12 @@ -424,7 +424,7 @@ LL | id_u32(b16); | ^^^ | | | expected `u32`, found `u16` - | help: you can convert an `u16` to `u32`: `b16.into()` + | help: you can convert a `u16` to `u32`: `b16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:186:12 @@ -432,7 +432,7 @@ error[E0308]: mismatched types LL | id_u32(b64); | ^^^ expected `u32`, found `u64` | -help: you can convert an `u64` to `u32` and panic if the converted value wouldn't fit +help: you can convert a `u64` to `u32` and panic if the converted value wouldn't fit | LL | id_u32(b64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -443,7 +443,7 @@ error[E0308]: mismatched types LL | id_u32(bsize); | ^^^^^ expected `u32`, found `usize` | -help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `u32` and panic if the converted value wouldn't fit | LL | id_u32(bsize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -455,7 +455,7 @@ LL | id_u64(b8); | ^^ | | | expected `u64`, found `u8` - | help: you can convert an `u8` to `u64`: `b8.into()` + | help: you can convert a `u8` to `u64`: `b8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:196:12 @@ -464,7 +464,7 @@ LL | id_u64(b16); | ^^^ | | | expected `u64`, found `u16` - | help: you can convert an `u16` to `u64`: `b16.into()` + | help: you can convert a `u16` to `u64`: `b16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:199:12 @@ -473,7 +473,7 @@ LL | id_u64(b32); | ^^^ | | | expected `u64`, found `u32` - | help: you can convert an `u32` to `u64`: `b32.into()` + | help: you can convert a `u32` to `u64`: `b32.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:203:12 @@ -481,7 +481,7 @@ error[E0308]: mismatched types LL | id_u64(bsize); | ^^^^^ expected `u64`, found `usize` | -help: you can convert an `usize` to `u64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `u64` and panic if the converted value wouldn't fit | LL | id_u64(bsize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -493,7 +493,7 @@ LL | id_usize(b8); | ^^ | | | expected `usize`, found `u8` - | help: you can convert an `u8` to `usize`: `b8.into()` + | help: you can convert a `u8` to `usize`: `b8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:210:14 @@ -502,7 +502,7 @@ LL | id_usize(b16); | ^^^ | | | expected `usize`, found `u16` - | help: you can convert an `u16` to `usize`: `b16.into()` + | help: you can convert a `u16` to `usize`: `b16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:213:14 @@ -510,7 +510,7 @@ error[E0308]: mismatched types LL | id_usize(b32); | ^^^ expected `usize`, found `u32` | -help: you can convert an `u32` to `usize` and panic if the converted value wouldn't fit +help: you can convert a `u32` to `usize` and panic if the converted value wouldn't fit | LL | id_usize(b32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -521,7 +521,7 @@ error[E0308]: mismatched types LL | id_usize(b64); | ^^^ expected `usize`, found `u64` | -help: you can convert an `u64` to `usize` and panic if the converted value wouldn't fit +help: you can convert a `u64` to `usize` and panic if the converted value wouldn't fit | LL | id_usize(b64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/issues/issue-13359.stderr b/src/test/ui/issues/issue-13359.stderr index 68258a8888a..e99554ec684 100644 --- a/src/test/ui/issues/issue-13359.stderr +++ b/src/test/ui/issues/issue-13359.stderr @@ -15,7 +15,7 @@ error[E0308]: mismatched types LL | bar(1*(1 as usize)); | ^^^^^^^^^^^^^^ expected `u32`, found `usize` | -help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `u32` and panic if the converted value wouldn't fit | LL | bar((1*(1 as usize)).try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index d39b0a32077..35080716f28 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -8,7 +8,7 @@ LL | write!(hello); | -------------- in this macro invocation | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -help: you can convert an `usize` to `u64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `u64` and panic if the converted value wouldn't fit | LL | ($arr.len() * size_of($arr[0])).try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/numeric/len.stderr b/src/test/ui/numeric/len.stderr index dba6c723829..c0469f74d45 100644 --- a/src/test/ui/numeric/len.stderr +++ b/src/test/ui/numeric/len.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | test(array.len()); | ^^^^^^^^^^^ expected `u32`, found `usize` | -help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `u32` and panic if the converted value wouldn't fit | LL | test(array.len().try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/numeric/numeric-cast-2.stderr b/src/test/ui/numeric/numeric-cast-2.stderr index 3f900062cbb..fc9124be2a7 100644 --- a/src/test/ui/numeric/numeric-cast-2.stderr +++ b/src/test/ui/numeric/numeric-cast-2.stderr @@ -18,7 +18,7 @@ LL | let y: i64 = x + x; | --- ^^^^^ | | | | | expected `i64`, found `u16` - | | help: you can convert an `u16` to `i64`: `(x + x).into()` + | | help: you can convert a `u16` to `i64`: `(x + x).into()` | expected due to this error[E0308]: mismatched types @@ -28,7 +28,7 @@ LL | let z: i32 = x + x; | --- ^^^^^ | | | | | expected `i32`, found `u16` - | | help: you can convert an `u16` to `i32`: `(x + x).into()` + | | help: you can convert a `u16` to `i32`: `(x + x).into()` | expected due to this error: aborting due to 3 previous errors diff --git a/src/test/ui/numeric/numeric-cast-binop.stderr b/src/test/ui/numeric/numeric-cast-binop.stderr index 47be817b789..6523f31edbf 100644 --- a/src/test/ui/numeric/numeric-cast-binop.stderr +++ b/src/test/ui/numeric/numeric-cast-binop.stderr @@ -60,7 +60,7 @@ LL | x_u16 > x_u8; | ^^^^ | | | expected `u16`, found `u8` - | help: you can convert an `u8` to `u16`: `x_u8.into()` + | help: you can convert a `u8` to `u16`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:36:17 @@ -113,7 +113,7 @@ LL | x_u32 > x_u8; | ^^^^ | | | expected `u32`, found `u8` - | help: you can convert an `u8` to `u32`: `x_u8.into()` + | help: you can convert a `u8` to `u32`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:47:17 @@ -122,7 +122,7 @@ LL | x_u32 > x_u16; | ^^^^^ | | | expected `u32`, found `u16` - | help: you can convert an `u16` to `u32`: `x_u16.into()` + | help: you can convert a `u16` to `u32`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:49:17 @@ -152,7 +152,7 @@ error[E0308]: mismatched types LL | x_u32 > x_usize; | ^^^^^^^ expected `u32`, found `usize` | -help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `u32` and panic if the converted value wouldn't fit | LL | x_u32 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -164,7 +164,7 @@ LL | x_u64 > x_u8; | ^^^^ | | | expected `u64`, found `u8` - | help: you can convert an `u8` to `u64`: `x_u8.into()` + | help: you can convert a `u8` to `u64`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:58:17 @@ -173,7 +173,7 @@ LL | x_u64 > x_u16; | ^^^^^ | | | expected `u64`, found `u16` - | help: you can convert an `u16` to `u64`: `x_u16.into()` + | help: you can convert a `u16` to `u64`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:60:17 @@ -182,7 +182,7 @@ LL | x_u64 > x_u32; | ^^^^^ | | | expected `u64`, found `u32` - | help: you can convert an `u32` to `u64`: `x_u32.into()` + | help: you can convert a `u32` to `u64`: `x_u32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:62:17 @@ -201,7 +201,7 @@ error[E0308]: mismatched types LL | x_u64 > x_usize; | ^^^^^^^ expected `u64`, found `usize` | -help: you can convert an `usize` to `u64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `u64` and panic if the converted value wouldn't fit | LL | x_u64 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -213,7 +213,7 @@ LL | x_u128 > x_u8; | ^^^^ | | | expected `u128`, found `u8` - | help: you can convert an `u8` to `u128`: `x_u8.into()` + | help: you can convert a `u8` to `u128`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:69:18 @@ -222,7 +222,7 @@ LL | x_u128 > x_u16; | ^^^^^ | | | expected `u128`, found `u16` - | help: you can convert an `u16` to `u128`: `x_u16.into()` + | help: you can convert a `u16` to `u128`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:71:18 @@ -231,7 +231,7 @@ LL | x_u128 > x_u32; | ^^^^^ | | | expected `u128`, found `u32` - | help: you can convert an `u32` to `u128`: `x_u32.into()` + | help: you can convert a `u32` to `u128`: `x_u32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:73:18 @@ -240,7 +240,7 @@ LL | x_u128 > x_u64; | ^^^^^ | | | expected `u128`, found `u64` - | help: you can convert an `u64` to `u128`: `x_u64.into()` + | help: you can convert a `u64` to `u128`: `x_u64.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:75:18 @@ -248,7 +248,7 @@ error[E0308]: mismatched types LL | x_u128 > x_usize; | ^^^^^^^ expected `u128`, found `usize` | -help: you can convert an `usize` to `u128` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `u128` and panic if the converted value wouldn't fit | LL | x_u128 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -260,7 +260,7 @@ LL | x_usize > x_u8; | ^^^^ | | | expected `usize`, found `u8` - | help: you can convert an `u8` to `usize`: `x_u8.into()` + | help: you can convert a `u8` to `usize`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:80:19 @@ -269,7 +269,7 @@ LL | x_usize > x_u16; | ^^^^^ | | | expected `usize`, found `u16` - | help: you can convert an `u16` to `usize`: `x_u16.into()` + | help: you can convert a `u16` to `usize`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:82:19 @@ -277,7 +277,7 @@ error[E0308]: mismatched types LL | x_usize > x_u32; | ^^^^^ expected `usize`, found `u32` | -help: you can convert an `u32` to `usize` and panic if the converted value wouldn't fit +help: you can convert a `u32` to `usize` and panic if the converted value wouldn't fit | LL | x_usize > x_u32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -288,7 +288,7 @@ error[E0308]: mismatched types LL | x_usize > x_u64; | ^^^^^ expected `usize`, found `u64` | -help: you can convert an `u64` to `usize` and panic if the converted value wouldn't fit +help: you can convert a `u64` to `usize` and panic if the converted value wouldn't fit | LL | x_usize > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -299,7 +299,7 @@ error[E0308]: mismatched types LL | x_usize > x_u128; | ^^^^^^ expected `usize`, found `u128` | -help: you can convert an `u128` to `usize` and panic if the converted value wouldn't fit +help: you can convert a `u128` to `usize` and panic if the converted value wouldn't fit | LL | x_usize > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1012,7 +1012,7 @@ error[E0308]: mismatched types LL | x_i8 > x_u8; | ^^^^ expected `i8`, found `u8` | -help: you can convert an `u8` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u8` to `i8` and panic if the converted value wouldn't fit | LL | x_i8 > x_u8.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1023,7 +1023,7 @@ error[E0308]: mismatched types LL | x_i8 > x_u16; | ^^^^^ expected `i8`, found `u16` | -help: you can convert an `u16` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u16` to `i8` and panic if the converted value wouldn't fit | LL | x_i8 > x_u16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1034,7 +1034,7 @@ error[E0308]: mismatched types LL | x_i8 > x_u32; | ^^^^^ expected `i8`, found `u32` | -help: you can convert an `u32` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u32` to `i8` and panic if the converted value wouldn't fit | LL | x_i8 > x_u32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1045,7 +1045,7 @@ error[E0308]: mismatched types LL | x_i8 > x_u64; | ^^^^^ expected `i8`, found `u64` | -help: you can convert an `u64` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u64` to `i8` and panic if the converted value wouldn't fit | LL | x_i8 > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1056,7 +1056,7 @@ error[E0308]: mismatched types LL | x_i8 > x_u128; | ^^^^^^ expected `i8`, found `u128` | -help: you can convert an `u128` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u128` to `i8` and panic if the converted value wouldn't fit | LL | x_i8 > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1067,7 +1067,7 @@ error[E0308]: mismatched types LL | x_i8 > x_usize; | ^^^^^^^ expected `i8`, found `usize` | -help: you can convert an `usize` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `i8` and panic if the converted value wouldn't fit | LL | x_i8 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1079,7 +1079,7 @@ LL | x_i16 > x_u8; | ^^^^ | | | expected `i16`, found `u8` - | help: you can convert an `u8` to `i16`: `x_u8.into()` + | help: you can convert a `u8` to `i16`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:257:17 @@ -1087,7 +1087,7 @@ error[E0308]: mismatched types LL | x_i16 > x_u16; | ^^^^^ expected `i16`, found `u16` | -help: you can convert an `u16` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `u16` to `i16` and panic if the converted value wouldn't fit | LL | x_i16 > x_u16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1098,7 +1098,7 @@ error[E0308]: mismatched types LL | x_i16 > x_u32; | ^^^^^ expected `i16`, found `u32` | -help: you can convert an `u32` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `u32` to `i16` and panic if the converted value wouldn't fit | LL | x_i16 > x_u32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1109,7 +1109,7 @@ error[E0308]: mismatched types LL | x_i16 > x_u64; | ^^^^^ expected `i16`, found `u64` | -help: you can convert an `u64` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `u64` to `i16` and panic if the converted value wouldn't fit | LL | x_i16 > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1120,7 +1120,7 @@ error[E0308]: mismatched types LL | x_i16 > x_u128; | ^^^^^^ expected `i16`, found `u128` | -help: you can convert an `u128` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `u128` to `i16` and panic if the converted value wouldn't fit | LL | x_i16 > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1131,7 +1131,7 @@ error[E0308]: mismatched types LL | x_i16 > x_usize; | ^^^^^^^ expected `i16`, found `usize` | -help: you can convert an `usize` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `i16` and panic if the converted value wouldn't fit | LL | x_i16 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1143,7 +1143,7 @@ LL | x_i32 > x_u8; | ^^^^ | | | expected `i32`, found `u8` - | help: you can convert an `u8` to `i32`: `x_u8.into()` + | help: you can convert a `u8` to `i32`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:270:17 @@ -1152,7 +1152,7 @@ LL | x_i32 > x_u16; | ^^^^^ | | | expected `i32`, found `u16` - | help: you can convert an `u16` to `i32`: `x_u16.into()` + | help: you can convert a `u16` to `i32`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:272:17 @@ -1160,7 +1160,7 @@ error[E0308]: mismatched types LL | x_i32 > x_u32; | ^^^^^ expected `i32`, found `u32` | -help: you can convert an `u32` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `u32` to `i32` and panic if the converted value wouldn't fit | LL | x_i32 > x_u32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1171,7 +1171,7 @@ error[E0308]: mismatched types LL | x_i32 > x_u64; | ^^^^^ expected `i32`, found `u64` | -help: you can convert an `u64` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `u64` to `i32` and panic if the converted value wouldn't fit | LL | x_i32 > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1182,7 +1182,7 @@ error[E0308]: mismatched types LL | x_i32 > x_u128; | ^^^^^^ expected `i32`, found `u128` | -help: you can convert an `u128` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `u128` to `i32` and panic if the converted value wouldn't fit | LL | x_i32 > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1193,7 +1193,7 @@ error[E0308]: mismatched types LL | x_i32 > x_usize; | ^^^^^^^ expected `i32`, found `usize` | -help: you can convert an `usize` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `i32` and panic if the converted value wouldn't fit | LL | x_i32 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1205,7 +1205,7 @@ LL | x_i64 > x_u8; | ^^^^ | | | expected `i64`, found `u8` - | help: you can convert an `u8` to `i64`: `x_u8.into()` + | help: you can convert a `u8` to `i64`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:283:17 @@ -1214,7 +1214,7 @@ LL | x_i64 > x_u16; | ^^^^^ | | | expected `i64`, found `u16` - | help: you can convert an `u16` to `i64`: `x_u16.into()` + | help: you can convert a `u16` to `i64`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:285:17 @@ -1223,7 +1223,7 @@ LL | x_i64 > x_u32; | ^^^^^ | | | expected `i64`, found `u32` - | help: you can convert an `u32` to `i64`: `x_u32.into()` + | help: you can convert a `u32` to `i64`: `x_u32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:287:17 @@ -1231,7 +1231,7 @@ error[E0308]: mismatched types LL | x_i64 > x_u64; | ^^^^^ expected `i64`, found `u64` | -help: you can convert an `u64` to `i64` and panic if the converted value wouldn't fit +help: you can convert a `u64` to `i64` and panic if the converted value wouldn't fit | LL | x_i64 > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1242,7 +1242,7 @@ error[E0308]: mismatched types LL | x_i64 > x_u128; | ^^^^^^ expected `i64`, found `u128` | -help: you can convert an `u128` to `i64` and panic if the converted value wouldn't fit +help: you can convert a `u128` to `i64` and panic if the converted value wouldn't fit | LL | x_i64 > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1253,7 +1253,7 @@ error[E0308]: mismatched types LL | x_i64 > x_usize; | ^^^^^^^ expected `i64`, found `usize` | -help: you can convert an `usize` to `i64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `i64` and panic if the converted value wouldn't fit | LL | x_i64 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1265,7 +1265,7 @@ LL | x_i128 > x_u8; | ^^^^ | | | expected `i128`, found `u8` - | help: you can convert an `u8` to `i128`: `x_u8.into()` + | help: you can convert a `u8` to `i128`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:296:18 @@ -1274,7 +1274,7 @@ LL | x_i128 > x_u16; | ^^^^^ | | | expected `i128`, found `u16` - | help: you can convert an `u16` to `i128`: `x_u16.into()` + | help: you can convert a `u16` to `i128`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:298:18 @@ -1283,7 +1283,7 @@ LL | x_i128 > x_u32; | ^^^^^ | | | expected `i128`, found `u32` - | help: you can convert an `u32` to `i128`: `x_u32.into()` + | help: you can convert a `u32` to `i128`: `x_u32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:300:18 @@ -1292,7 +1292,7 @@ LL | x_i128 > x_u64; | ^^^^^ | | | expected `i128`, found `u64` - | help: you can convert an `u64` to `i128`: `x_u64.into()` + | help: you can convert a `u64` to `i128`: `x_u64.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:302:18 @@ -1300,7 +1300,7 @@ error[E0308]: mismatched types LL | x_i128 > x_u128; | ^^^^^^ expected `i128`, found `u128` | -help: you can convert an `u128` to `i128` and panic if the converted value wouldn't fit +help: you can convert a `u128` to `i128` and panic if the converted value wouldn't fit | LL | x_i128 > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1311,7 +1311,7 @@ error[E0308]: mismatched types LL | x_i128 > x_usize; | ^^^^^^^ expected `i128`, found `usize` | -help: you can convert an `usize` to `i128` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `i128` and panic if the converted value wouldn't fit | LL | x_i128 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1323,7 +1323,7 @@ LL | x_isize > x_u8; | ^^^^ | | | expected `isize`, found `u8` - | help: you can convert an `u8` to `isize`: `x_u8.into()` + | help: you can convert a `u8` to `isize`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:309:19 @@ -1331,7 +1331,7 @@ error[E0308]: mismatched types LL | x_isize > x_u16; | ^^^^^ expected `isize`, found `u16` | -help: you can convert an `u16` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `u16` to `isize` and panic if the converted value wouldn't fit | LL | x_isize > x_u16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1342,7 +1342,7 @@ error[E0308]: mismatched types LL | x_isize > x_u32; | ^^^^^ expected `isize`, found `u32` | -help: you can convert an `u32` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `u32` to `isize` and panic if the converted value wouldn't fit | LL | x_isize > x_u32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1353,7 +1353,7 @@ error[E0308]: mismatched types LL | x_isize > x_u64; | ^^^^^ expected `isize`, found `u64` | -help: you can convert an `u64` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `u64` to `isize` and panic if the converted value wouldn't fit | LL | x_isize > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1364,7 +1364,7 @@ error[E0308]: mismatched types LL | x_isize > x_u128; | ^^^^^^ expected `isize`, found `u128` | -help: you can convert an `u128` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `u128` to `isize` and panic if the converted value wouldn't fit | LL | x_isize > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1375,7 +1375,7 @@ error[E0308]: mismatched types LL | x_isize > x_usize; | ^^^^^^^ expected `isize`, found `usize` | -help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `isize` and panic if the converted value wouldn't fit | LL | x_isize > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/numeric/numeric-cast.stderr b/src/test/ui/numeric/numeric-cast.stderr index cc1aa72d214..3c78ea9e08a 100644 --- a/src/test/ui/numeric/numeric-cast.stderr +++ b/src/test/ui/numeric/numeric-cast.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `usize`, found `u64` | -help: you can convert an `u64` to `usize` and panic if the converted value wouldn't fit +help: you can convert a `u64` to `usize` and panic if the converted value wouldn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `usize`, found `u32` | -help: you can convert an `u32` to `usize` and panic if the converted value wouldn't fit +help: you can convert a `u32` to `usize` and panic if the converted value wouldn't fit | LL | foo::(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | foo::(x_u16); | ^^^^^ | | | expected `usize`, found `u16` - | help: you can convert an `u16` to `usize`: `x_u16.into()` + | help: you can convert a `u16` to `usize`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:29:18 @@ -36,7 +36,7 @@ LL | foo::(x_u8); | ^^^^ | | | expected `usize`, found `u8` - | help: you can convert an `u8` to `usize`: `x_u8.into()` + | help: you can convert a `u8` to `usize`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:31:18 @@ -99,7 +99,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `isize`, found `usize` | -help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `isize` and panic if the converted value wouldn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -110,7 +110,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `isize`, found `u64` | -help: you can convert an `u64` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `u64` to `isize` and panic if the converted value wouldn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `isize`, found `u32` | -help: you can convert an `u32` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `u32` to `isize` and panic if the converted value wouldn't fit | LL | foo::(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,7 +132,7 @@ error[E0308]: mismatched types LL | foo::(x_u16); | ^^^^^ expected `isize`, found `u16` | -help: you can convert an `u16` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `u16` to `isize` and panic if the converted value wouldn't fit | LL | foo::(x_u16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -144,7 +144,7 @@ LL | foo::(x_u8); | ^^^^ | | | expected `isize`, found `u8` - | help: you can convert an `u8` to `isize`: `x_u8.into()` + | help: you can convert a `u8` to `isize`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:55:18 @@ -192,7 +192,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `u64`, found `usize` | -help: you can convert an `usize` to `u64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `u64` and panic if the converted value wouldn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -204,7 +204,7 @@ LL | foo::(x_u32); | ^^^^^ | | | expected `u64`, found `u32` - | help: you can convert an `u32` to `u64`: `x_u32.into()` + | help: you can convert a `u32` to `u64`: `x_u32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:71:16 @@ -213,7 +213,7 @@ LL | foo::(x_u16); | ^^^^^ | | | expected `u64`, found `u16` - | help: you can convert an `u16` to `u64`: `x_u16.into()` + | help: you can convert a `u16` to `u64`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:73:16 @@ -222,7 +222,7 @@ LL | foo::(x_u8); | ^^^^ | | | expected `u64`, found `u8` - | help: you can convert an `u8` to `u64`: `x_u8.into()` + | help: you can convert a `u8` to `u64`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:75:16 @@ -285,7 +285,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `i64`, found `usize` | -help: you can convert an `usize` to `i64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `i64` and panic if the converted value wouldn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -296,7 +296,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `i64`, found `u64` | -help: you can convert an `u64` to `i64` and panic if the converted value wouldn't fit +help: you can convert a `u64` to `i64` and panic if the converted value wouldn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -308,7 +308,7 @@ LL | foo::(x_u32); | ^^^^^ | | | expected `i64`, found `u32` - | help: you can convert an `u32` to `i64`: `x_u32.into()` + | help: you can convert a `u32` to `i64`: `x_u32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:94:16 @@ -317,7 +317,7 @@ LL | foo::(x_u16); | ^^^^^ | | | expected `i64`, found `u16` - | help: you can convert an `u16` to `i64`: `x_u16.into()` + | help: you can convert a `u16` to `i64`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:96:16 @@ -326,7 +326,7 @@ LL | foo::(x_u8); | ^^^^ | | | expected `i64`, found `u8` - | help: you can convert an `u8` to `i64`: `x_u8.into()` + | help: you can convert a `u8` to `i64`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:98:16 @@ -372,7 +372,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `u32`, found `usize` | -help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `u32` and panic if the converted value wouldn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -383,7 +383,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `u32`, found `u64` | -help: you can convert an `u64` to `u32` and panic if the converted value wouldn't fit +help: you can convert a `u64` to `u32` and panic if the converted value wouldn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -395,7 +395,7 @@ LL | foo::(x_u16); | ^^^^^ | | | expected `u32`, found `u16` - | help: you can convert an `u16` to `u32`: `x_u16.into()` + | help: you can convert a `u16` to `u32`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:117:16 @@ -404,7 +404,7 @@ LL | foo::(x_u8); | ^^^^ | | | expected `u32`, found `u8` - | help: you can convert an `u8` to `u32`: `x_u8.into()` + | help: you can convert a `u8` to `u32`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:119:16 @@ -467,7 +467,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `i32`, found `usize` | -help: you can convert an `usize` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `i32` and panic if the converted value wouldn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -478,7 +478,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `i32`, found `u64` | -help: you can convert an `u64` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `u64` to `i32` and panic if the converted value wouldn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -489,7 +489,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `i32`, found `u32` | -help: you can convert an `u32` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `u32` to `i32` and panic if the converted value wouldn't fit | LL | foo::(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -501,7 +501,7 @@ LL | foo::(x_u16); | ^^^^^ | | | expected `i32`, found `u16` - | help: you can convert an `u16` to `i32`: `x_u16.into()` + | help: you can convert a `u16` to `i32`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:140:16 @@ -510,7 +510,7 @@ LL | foo::(x_u8); | ^^^^ | | | expected `i32`, found `u8` - | help: you can convert an `u8` to `i32`: `x_u8.into()` + | help: you can convert a `u8` to `i32`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:142:16 @@ -558,7 +558,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `u16`, found `usize` | -help: you can convert an `usize` to `u16` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `u16` and panic if the converted value wouldn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -569,7 +569,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `u16`, found `u64` | -help: you can convert an `u64` to `u16` and panic if the converted value wouldn't fit +help: you can convert a `u64` to `u16` and panic if the converted value wouldn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -580,7 +580,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `u16`, found `u32` | -help: you can convert an `u32` to `u16` and panic if the converted value wouldn't fit +help: you can convert a `u32` to `u16` and panic if the converted value wouldn't fit | LL | foo::(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -592,7 +592,7 @@ LL | foo::(x_u8); | ^^^^ | | | expected `u16`, found `u8` - | help: you can convert an `u8` to `u16`: `x_u8.into()` + | help: you can convert a `u8` to `u16`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:163:16 @@ -655,7 +655,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `i16`, found `usize` | -help: you can convert an `usize` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `i16` and panic if the converted value wouldn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -666,7 +666,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `i16`, found `u64` | -help: you can convert an `u64` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `u64` to `i16` and panic if the converted value wouldn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -677,7 +677,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `i16`, found `u32` | -help: you can convert an `u32` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `u32` to `i16` and panic if the converted value wouldn't fit | LL | foo::(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -688,7 +688,7 @@ error[E0308]: mismatched types LL | foo::(x_u16); | ^^^^^ expected `i16`, found `u16` | -help: you can convert an `u16` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `u16` to `i16` and panic if the converted value wouldn't fit | LL | foo::(x_u16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -700,7 +700,7 @@ LL | foo::(x_u8); | ^^^^ | | | expected `i16`, found `u8` - | help: you can convert an `u8` to `i16`: `x_u8.into()` + | help: you can convert a `u8` to `i16`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:186:16 @@ -750,7 +750,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `u8`, found `usize` | -help: you can convert an `usize` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `u8` and panic if the converted value wouldn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -761,7 +761,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `u8`, found `u64` | -help: you can convert an `u64` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `u64` to `u8` and panic if the converted value wouldn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -772,7 +772,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `u8`, found `u32` | -help: you can convert an `u32` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `u32` to `u8` and panic if the converted value wouldn't fit | LL | foo::(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -783,7 +783,7 @@ error[E0308]: mismatched types LL | foo::(x_u16); | ^^^^^ expected `u8`, found `u16` | -help: you can convert an `u16` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `u16` to `u8` and panic if the converted value wouldn't fit | LL | foo::(x_u16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -849,7 +849,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `i8`, found `usize` | -help: you can convert an `usize` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `i8` and panic if the converted value wouldn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -860,7 +860,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `i8`, found `u64` | -help: you can convert an `u64` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u64` to `i8` and panic if the converted value wouldn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -871,7 +871,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `i8`, found `u32` | -help: you can convert an `u32` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u32` to `i8` and panic if the converted value wouldn't fit | LL | foo::(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -882,7 +882,7 @@ error[E0308]: mismatched types LL | foo::(x_u16); | ^^^^^ expected `i8`, found `u16` | -help: you can convert an `u16` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u16` to `i8` and panic if the converted value wouldn't fit | LL | foo::(x_u16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -893,7 +893,7 @@ error[E0308]: mismatched types LL | foo::(x_u8); | ^^^^ expected `i8`, found `u8` | -help: you can convert an `u8` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u8` to `i8` and panic if the converted value wouldn't fit | LL | foo::(x_u8.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -948,7 +948,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `f64`, found `usize` | -help: you can cast an `usize to `f64`, producing the floating point representation of the integer, +help: you can cast a `usize to `f64`, producing the floating point representation of the integer, | rounded if necessary LL | foo::(x_usize as f64); | ^^^^^^^^^^^^^^ @@ -959,7 +959,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `f64`, found `u64` | -help: you can cast an `u64 to `f64`, producing the floating point representation of the integer, +help: you can cast a `u64 to `f64`, producing the floating point representation of the integer, | rounded if necessary LL | foo::(x_u64 as f64); | ^^^^^^^^^^^^ @@ -970,7 +970,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `f64`, found `u32` | -help: you can convert an `u32` to `f64`, producing the floating point representation of the integer +help: you can convert a `u32` to `f64`, producing the floating point representation of the integer | LL | foo::(x_u32.into()); | ^^^^^^^^^^^^ @@ -981,7 +981,7 @@ error[E0308]: mismatched types LL | foo::(x_u16); | ^^^^^ expected `f64`, found `u16` | -help: you can convert an `u16` to `f64`, producing the floating point representation of the integer +help: you can convert a `u16` to `f64`, producing the floating point representation of the integer | LL | foo::(x_u16.into()); | ^^^^^^^^^^^^ @@ -992,7 +992,7 @@ error[E0308]: mismatched types LL | foo::(x_u8); | ^^^^ expected `f64`, found `u8` | -help: you can convert an `u8` to `f64`, producing the floating point representation of the integer +help: you can convert a `u8` to `f64`, producing the floating point representation of the integer | LL | foo::(x_u8.into()); | ^^^^^^^^^^^ @@ -1067,7 +1067,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `f32`, found `usize` | -help: you can cast an `usize to `f32`, producing the floating point representation of the integer, +help: you can cast a `usize to `f32`, producing the floating point representation of the integer, | rounded if necessary LL | foo::(x_usize as f32); | ^^^^^^^^^^^^^^ @@ -1078,7 +1078,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `f32`, found `u64` | -help: you can cast an `u64 to `f32`, producing the floating point representation of the integer, +help: you can cast a `u64 to `f32`, producing the floating point representation of the integer, | rounded if necessary LL | foo::(x_u64 as f32); | ^^^^^^^^^^^^ @@ -1089,7 +1089,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `f32`, found `u32` | -help: you can cast an `u32 to `f32`, producing the floating point representation of the integer, +help: you can cast a `u32 to `f32`, producing the floating point representation of the integer, | rounded if necessary LL | foo::(x_u32 as f32); | ^^^^^^^^^^^^ @@ -1100,7 +1100,7 @@ error[E0308]: mismatched types LL | foo::(x_u16); | ^^^^^ expected `f32`, found `u16` | -help: you can convert an `u16` to `f32`, producing the floating point representation of the integer +help: you can convert a `u16` to `f32`, producing the floating point representation of the integer | LL | foo::(x_u16.into()); | ^^^^^^^^^^^^ @@ -1111,7 +1111,7 @@ error[E0308]: mismatched types LL | foo::(x_u8); | ^^^^ expected `f32`, found `u8` | -help: you can convert an `u8` to `f32`, producing the floating point representation of the integer +help: you can convert a `u8` to `f32`, producing the floating point representation of the integer | LL | foo::(x_u8.into()); | ^^^^^^^^^^^ @@ -1178,7 +1178,7 @@ LL | foo::(x_u8 as u16); | ^^^^^^^^^^^ | | | expected `u32`, found `u16` - | help: you can convert an `u16` to `u32`: `(x_u8 as u16).into()` + | help: you can convert a `u16` to `u32`: `(x_u8 as u16).into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:291:16 diff --git a/src/test/ui/numeric/numeric-suffix.stderr b/src/test/ui/numeric/numeric-suffix.stderr index 00f6e1abe43..890686f7737 100644 --- a/src/test/ui/numeric/numeric-suffix.stderr +++ b/src/test/ui/numeric/numeric-suffix.stderr @@ -1236,7 +1236,7 @@ error[E0308]: mismatched types LL | foo::(42_u32); | ^^^^^^ expected `f64`, found `u32` | -help: you can convert an `u32` to `f64`, producing the floating point representation of the integer +help: you can convert a `u32` to `f64`, producing the floating point representation of the integer | LL | foo::(42_u32.into()); | ^^^^^^^^^^^^^ @@ -1247,7 +1247,7 @@ error[E0308]: mismatched types LL | foo::(42_u16); | ^^^^^^ expected `f64`, found `u16` | -help: you can convert an `u16` to `f64`, producing the floating point representation of the integer +help: you can convert a `u16` to `f64`, producing the floating point representation of the integer | LL | foo::(42_u16.into()); | ^^^^^^^^^^^^^ @@ -1258,7 +1258,7 @@ error[E0308]: mismatched types LL | foo::(42_u8); | ^^^^^ expected `f64`, found `u8` | -help: you can convert an `u8` to `f64`, producing the floating point representation of the integer +help: you can convert a `u8` to `f64`, producing the floating point representation of the integer | LL | foo::(42_u8.into()); | ^^^^^^^^^^^^ @@ -1368,7 +1368,7 @@ error[E0308]: mismatched types LL | foo::(42_u16); | ^^^^^^ expected `f32`, found `u16` | -help: you can convert an `u16` to `f32`, producing the floating point representation of the integer +help: you can convert a `u16` to `f32`, producing the floating point representation of the integer | LL | foo::(42_u16.into()); | ^^^^^^^^^^^^^ @@ -1379,7 +1379,7 @@ error[E0308]: mismatched types LL | foo::(42_u8); | ^^^^^ expected `f32`, found `u8` | -help: you can convert an `u8` to `f32`, producing the floating point representation of the integer +help: you can convert a `u8` to `f32`, producing the floating point representation of the integer | LL | foo::(42_u8.into()); | ^^^^^^^^^^^^ @@ -1457,7 +1457,7 @@ LL | foo::(42_u8 as u16); | ^^^^^^^^^^^^ | | | expected `u32`, found `u16` - | help: you can convert an `u16` to `u32`: `(42_u8 as u16).into()` + | help: you can convert a `u16` to `u32`: `(42_u8 as u16).into()` error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:296:16 diff --git a/src/test/ui/tail-typeck.stderr b/src/test/ui/tail-typeck.stderr index 69f8ffa581b..4dc969e76ed 100644 --- a/src/test/ui/tail-typeck.stderr +++ b/src/test/ui/tail-typeck.stderr @@ -6,7 +6,7 @@ LL | fn f() -> isize { return g(); } | | | expected `isize` because of return type | -help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `usize` to `isize` and panic if the converted value wouldn't fit | LL | fn f() -> isize { return g().try_into().unwrap(); } | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/tutorial-suffix-inference-test.stderr b/src/test/ui/tutorial-suffix-inference-test.stderr index c6c7ba26794..4f36357598d 100644 --- a/src/test/ui/tutorial-suffix-inference-test.stderr +++ b/src/test/ui/tutorial-suffix-inference-test.stderr @@ -5,7 +5,7 @@ LL | identity_u16(x); | ^ | | | expected `u16`, found `u8` - | help: you can convert an `u8` to `u16`: `x.into()` + | help: you can convert a `u8` to `u16`: `x.into()` error[E0308]: mismatched types --> $DIR/tutorial-suffix-inference-test.rs:12:18 From 57e8fc56852e7728d7160242bf13c3ab6e066bd8 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 10 Sep 2020 19:54:17 +0100 Subject: [PATCH 040/446] passes: `check_attr` on more targets This commit modifies `check_attr` so that: - Enum variants are now checked (some attributes would not have been prohibited on variants previously). - `check_expr_attributes` and `check_stmt_attributes` are removed as `check_attributes` can perform the same checks. Signed-off-by: David Wood --- compiler/rustc_passes/src/check_attr.rs | 91 +++++++------------ src/test/ui/attr-usage-repr.rs | 8 +- src/test/ui/attr-usage-repr.stderr | 8 +- src/test/ui/error-codes/E0517.stderr | 8 +- src/test/ui/inline-disallow-on-variant.rs | 7 ++ src/test/ui/inline-disallow-on-variant.stderr | 12 +++ src/test/ui/issues/issue-31769.rs | 2 +- src/test/ui/issues/issue-31769.stderr | 2 +- src/test/ui/issues/issue-43988.rs | 10 +- src/test/ui/issues/issue-43988.stderr | 34 ++----- src/test/ui/issues/issue-74082.rs | 4 +- src/test/ui/issues/issue-74082.stderr | 4 +- src/test/ui/macros/issue-68060.rs | 3 - src/test/ui/macros/issue-68060.stderr | 15 +-- src/test/ui/repr/repr-disallow-on-variant.rs | 9 ++ .../ui/repr/repr-disallow-on-variant.stderr | 12 +++ .../repr-no-niche-inapplicable-to-unions.rs | 4 +- ...epr-no-niche-inapplicable-to-unions.stderr | 4 +- .../ui/repr/repr-transparent-other-items.rs | 4 +- .../repr/repr-transparent-other-items.stderr | 4 +- 20 files changed, 114 insertions(+), 131 deletions(-) create mode 100644 src/test/ui/inline-disallow-on-variant.rs create mode 100644 src/test/ui/inline-disallow-on-variant.stderr create mode 100644 src/test/ui/repr/repr-disallow-on-variant.rs create mode 100644 src/test/ui/repr/repr-disallow-on-variant.stderr diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index efe947daa28..758b4639811 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -94,7 +94,7 @@ impl CheckAttrVisitor<'tcx> { return; } - if matches!(target, Target::Fn | Target::Method(_) | Target::ForeignFn) { + if matches!(target, Target::Closure | Target::Fn | Target::Method(_) | Target::ForeignFn) { self.tcx.ensure().codegen_fn_attrs(self.tcx.hir().local_def_id(hir_id)); } @@ -185,7 +185,7 @@ impl CheckAttrVisitor<'tcx> { /// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. Returns `true` if valid. fn check_non_exhaustive(&self, attr: &Attribute, span: &Span, target: Target) -> bool { match target { - Target::Struct | Target::Enum => true, + Target::Struct | Target::Enum | Target::Variant => true, _ => { struct_span_err!( self.tcx.sess, @@ -470,6 +470,9 @@ impl CheckAttrVisitor<'tcx> { for hint in &hints { let (article, allowed_targets) = match hint.name_or_empty() { + _ if !matches!(target, Target::Struct | Target::Enum | Target::Union) => { + ("a", "struct, enum, or union") + } name @ sym::C | name @ sym::align => { is_c |= name == sym::C; match target { @@ -535,12 +538,16 @@ impl CheckAttrVisitor<'tcx> { } _ => continue, }; - self.emit_repr_error( + + struct_span_err!( + self.tcx.sess, hint.span(), - *span, - &format!("attribute should be applied to {}", allowed_targets), - &format!("not {} {}", article, allowed_targets), + E0517, + "{}", + &format!("attribute should be applied to {} {}", article, allowed_targets) ) + .span_label(*span, &format!("not {} {}", article, allowed_targets)) + .emit(); } // Just point at all repr hints if there are any incompatibilities. @@ -579,56 +586,6 @@ impl CheckAttrVisitor<'tcx> { } } - fn emit_repr_error( - &self, - hint_span: Span, - label_span: Span, - hint_message: &str, - label_message: &str, - ) { - struct_span_err!(self.tcx.sess, hint_span, E0517, "{}", hint_message) - .span_label(label_span, label_message) - .emit(); - } - - fn check_stmt_attributes(&self, stmt: &hir::Stmt<'_>) { - // When checking statements ignore expressions, they will be checked later - if let hir::StmtKind::Local(ref l) = stmt.kind { - self.check_attributes(l.hir_id, &l.attrs, &stmt.span, Target::Statement, None); - for attr in l.attrs.iter() { - if self.tcx.sess.check_name(attr, sym::repr) { - self.emit_repr_error( - attr.span, - stmt.span, - "attribute should not be applied to a statement", - "not a struct, enum, or union", - ); - } - } - } - } - - fn check_expr_attributes(&self, expr: &hir::Expr<'_>) { - let target = match expr.kind { - hir::ExprKind::Closure(..) => Target::Closure, - _ => Target::Expression, - }; - self.check_attributes(expr.hir_id, &expr.attrs, &expr.span, target, None); - for attr in expr.attrs.iter() { - if self.tcx.sess.check_name(attr, sym::repr) { - self.emit_repr_error( - attr.span, - expr.span, - "attribute should not be applied to an expression", - "not defining a struct, enum, or union", - ); - } - } - if target == Target::Closure { - self.tcx.ensure().codegen_fn_attrs(self.tcx.hir().local_def_id(expr.hir_id)); - } - } - fn check_used(&self, attrs: &'hir [Attribute], target: Target) { for attr in attrs { if self.tcx.sess.check_name(attr, sym::used) && target != Target::Static { @@ -672,14 +629,32 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> { } fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { - self.check_stmt_attributes(stmt); + // When checking statements ignore expressions, they will be checked later. + if let hir::StmtKind::Local(ref l) = stmt.kind { + self.check_attributes(l.hir_id, &l.attrs, &stmt.span, Target::Statement, None); + } intravisit::walk_stmt(self, stmt) } fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { - self.check_expr_attributes(expr); + let target = match expr.kind { + hir::ExprKind::Closure(..) => Target::Closure, + _ => Target::Expression, + }; + + self.check_attributes(expr.hir_id, &expr.attrs, &expr.span, target, None); intravisit::walk_expr(self, expr) } + + fn visit_variant( + &mut self, + variant: &'tcx hir::Variant<'tcx>, + generics: &'tcx hir::Generics<'tcx>, + item_id: HirId, + ) { + self.check_attributes(variant.id, variant.attrs, &variant.span, Target::Variant, None); + intravisit::walk_variant(self, variant, generics, item_id) + } } fn is_c_like_enum(item: &Item<'_>) -> bool { diff --git a/src/test/ui/attr-usage-repr.rs b/src/test/ui/attr-usage-repr.rs index a0b82375e77..8965decc379 100644 --- a/src/test/ui/attr-usage-repr.rs +++ b/src/test/ui/attr-usage-repr.rs @@ -1,6 +1,6 @@ #![feature(repr_simd)] -#[repr(C)] //~ ERROR: attribute should be applied to struct, enum, or union +#[repr(C)] //~ ERROR: attribute should be applied to a struct, enum, or union fn f() {} #[repr(C)] @@ -12,7 +12,7 @@ struct SPacked(f64, f64); #[repr(simd)] struct SSimd(f64, f64); -#[repr(i8)] //~ ERROR: attribute should be applied to enum +#[repr(i8)] //~ ERROR: attribute should be applied to an enum struct SInt(f64, f64); #[repr(C)] @@ -21,10 +21,10 @@ enum EExtern { A, B } #[repr(align(8))] enum EAlign { A, B } -#[repr(packed)] //~ ERROR: attribute should be applied to struct +#[repr(packed)] //~ ERROR: attribute should be applied to a struct enum EPacked { A, B } -#[repr(simd)] //~ ERROR: attribute should be applied to struct +#[repr(simd)] //~ ERROR: attribute should be applied to a struct enum ESimd { A, B } #[repr(i8)] diff --git a/src/test/ui/attr-usage-repr.stderr b/src/test/ui/attr-usage-repr.stderr index 82d80d8d0b1..42f65625a46 100644 --- a/src/test/ui/attr-usage-repr.stderr +++ b/src/test/ui/attr-usage-repr.stderr @@ -1,4 +1,4 @@ -error[E0517]: attribute should be applied to struct, enum, or union +error[E0517]: attribute should be applied to a struct, enum, or union --> $DIR/attr-usage-repr.rs:3:8 | LL | #[repr(C)] @@ -6,7 +6,7 @@ LL | #[repr(C)] LL | fn f() {} | --------- not a struct, enum, or union -error[E0517]: attribute should be applied to enum +error[E0517]: attribute should be applied to an enum --> $DIR/attr-usage-repr.rs:15:8 | LL | #[repr(i8)] @@ -14,7 +14,7 @@ LL | #[repr(i8)] LL | struct SInt(f64, f64); | ---------------------- not an enum -error[E0517]: attribute should be applied to struct or union +error[E0517]: attribute should be applied to a struct or union --> $DIR/attr-usage-repr.rs:24:8 | LL | #[repr(packed)] @@ -22,7 +22,7 @@ LL | #[repr(packed)] LL | enum EPacked { A, B } | --------------------- not a struct or union -error[E0517]: attribute should be applied to struct +error[E0517]: attribute should be applied to a struct --> $DIR/attr-usage-repr.rs:27:8 | LL | #[repr(simd)] diff --git a/src/test/ui/error-codes/E0517.stderr b/src/test/ui/error-codes/E0517.stderr index 2cfca1724c8..2f90d4d0baa 100644 --- a/src/test/ui/error-codes/E0517.stderr +++ b/src/test/ui/error-codes/E0517.stderr @@ -1,4 +1,4 @@ -error[E0517]: attribute should be applied to struct, enum, or union +error[E0517]: attribute should be applied to a struct, enum, or union --> $DIR/E0517.rs:1:8 | LL | #[repr(C)] @@ -6,7 +6,7 @@ LL | #[repr(C)] LL | type Foo = u8; | -------------- not a struct, enum, or union -error[E0517]: attribute should be applied to struct or union +error[E0517]: attribute should be applied to a struct or union --> $DIR/E0517.rs:4:8 | LL | #[repr(packed)] @@ -14,7 +14,7 @@ LL | #[repr(packed)] LL | enum Foo2 {Bar, Baz} | -------------------- not a struct or union -error[E0517]: attribute should be applied to enum +error[E0517]: attribute should be applied to an enum --> $DIR/E0517.rs:7:8 | LL | #[repr(u8)] @@ -22,7 +22,7 @@ LL | #[repr(u8)] LL | struct Foo3 {bar: bool, baz: bool} | ---------------------------------- not an enum -error[E0517]: attribute should be applied to struct, enum, or union +error[E0517]: attribute should be applied to a struct, enum, or union --> $DIR/E0517.rs:10:8 | LL | #[repr(C)] diff --git a/src/test/ui/inline-disallow-on-variant.rs b/src/test/ui/inline-disallow-on-variant.rs new file mode 100644 index 00000000000..d92a4e8cc8d --- /dev/null +++ b/src/test/ui/inline-disallow-on-variant.rs @@ -0,0 +1,7 @@ +enum Foo { + #[inline] + //~^ ERROR attribute should be applied + Variant, +} + +fn main() {} diff --git a/src/test/ui/inline-disallow-on-variant.stderr b/src/test/ui/inline-disallow-on-variant.stderr new file mode 100644 index 00000000000..1b176579bbb --- /dev/null +++ b/src/test/ui/inline-disallow-on-variant.stderr @@ -0,0 +1,12 @@ +error[E0518]: attribute should be applied to function or closure + --> $DIR/inline-disallow-on-variant.rs:2:5 + | +LL | #[inline] + | ^^^^^^^^^ +LL | +LL | Variant, + | ------- not a function or closure + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0518`. diff --git a/src/test/ui/issues/issue-31769.rs b/src/test/ui/issues/issue-31769.rs index 45eb5e40080..f56c6ea5656 100644 --- a/src/test/ui/issues/issue-31769.rs +++ b/src/test/ui/issues/issue-31769.rs @@ -1,4 +1,4 @@ fn main() { #[inline] struct Foo; //~ ERROR attribute should be applied to function or closure - #[repr(C)] fn foo() {} //~ ERROR attribute should be applied to struct, enum, or union + #[repr(C)] fn foo() {} //~ ERROR attribute should be applied to a struct, enum, or union } diff --git a/src/test/ui/issues/issue-31769.stderr b/src/test/ui/issues/issue-31769.stderr index 20534e1ae82..03e2f931c84 100644 --- a/src/test/ui/issues/issue-31769.stderr +++ b/src/test/ui/issues/issue-31769.stderr @@ -4,7 +4,7 @@ error[E0518]: attribute should be applied to function or closure LL | #[inline] struct Foo; | ^^^^^^^^^ ----------- not a function or closure -error[E0517]: attribute should be applied to struct, enum, or union +error[E0517]: attribute should be applied to a struct, enum, or union --> $DIR/issue-31769.rs:3:12 | LL | #[repr(C)] fn foo() {} diff --git a/src/test/ui/issues/issue-43988.rs b/src/test/ui/issues/issue-43988.rs index b80907560c3..4b3a0269bae 100644 --- a/src/test/ui/issues/issue-43988.rs +++ b/src/test/ui/issues/issue-43988.rs @@ -13,18 +13,17 @@ fn main() { #[repr(nothing)] let _x = 0; - //~^^ ERROR attribute should not be applied to a statement + //~^^ ERROR attribute should be applied to a struct, enum, or union #[repr(something_not_real)] loop { () }; - //~^^^^ ERROR attribute should not be applied to an expression + //~^^^^ ERROR attribute should be applied to a struct, enum, or union #[repr] let _y = "123"; - //~^^ ERROR attribute should not be applied to a statement - //~| ERROR malformed `repr` attribute + //~^^ ERROR malformed `repr` attribute fn foo() {} @@ -33,6 +32,5 @@ fn main() { //~^^ ERROR attribute should be applied to function or closure let _z = #[repr] 1; - //~^ ERROR attribute should not be applied to an expression - //~| ERROR malformed `repr` attribute + //~^ ERROR malformed `repr` attribute } diff --git a/src/test/ui/issues/issue-43988.stderr b/src/test/ui/issues/issue-43988.stderr index 37e56168c1d..f1205d447e4 100644 --- a/src/test/ui/issues/issue-43988.stderr +++ b/src/test/ui/issues/issue-43988.stderr @@ -5,7 +5,7 @@ LL | #[repr] | ^^^^^^^ help: must be of the form: `#[repr(C)]` error: malformed `repr` attribute input - --> $DIR/issue-43988.rs:35:14 + --> $DIR/issue-43988.rs:34:14 | LL | let _z = #[repr] 1; | ^^^^^^^ help: must be of the form: `#[repr(C)]` @@ -26,47 +26,33 @@ LL | #[inline(XYZ)] LL | let _b = 4; | ----------- not a function or closure -error[E0517]: attribute should not be applied to a statement - --> $DIR/issue-43988.rs:14:5 +error[E0517]: attribute should be applied to a struct, enum, or union + --> $DIR/issue-43988.rs:14:12 | LL | #[repr(nothing)] - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^ LL | let _x = 0; | ----------- not a struct, enum, or union -error[E0517]: attribute should not be applied to an expression - --> $DIR/issue-43988.rs:18:5 +error[E0517]: attribute should be applied to a struct, enum, or union + --> $DIR/issue-43988.rs:18:12 | LL | #[repr(something_not_real)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ LL | / loop { LL | | () LL | | }; - | |_____- not defining a struct, enum, or union - -error[E0517]: attribute should not be applied to a statement - --> $DIR/issue-43988.rs:24:5 - | -LL | #[repr] - | ^^^^^^^ -LL | let _y = "123"; - | --------------- not a struct, enum, or union + | |_____- not a struct, enum, or union error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43988.rs:31:5 + --> $DIR/issue-43988.rs:30:5 | LL | #[inline(ABC)] | ^^^^^^^^^^^^^^ LL | foo(); | ----- not a function or closure -error[E0517]: attribute should not be applied to an expression - --> $DIR/issue-43988.rs:35:14 - | -LL | let _z = #[repr] 1; - | ^^^^^^^ - not defining a struct, enum, or union - -error: aborting due to 9 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0517, E0518. For more information about an error, try `rustc --explain E0517`. diff --git a/src/test/ui/issues/issue-74082.rs b/src/test/ui/issues/issue-74082.rs index 982f8ef0253..e3e400c79d6 100644 --- a/src/test/ui/issues/issue-74082.rs +++ b/src/test/ui/issues/issue-74082.rs @@ -1,9 +1,9 @@ #![allow(dead_code)] -#[repr(i128)] //~ ERROR: attribute should be applied to enum +#[repr(i128)] //~ ERROR: attribute should be applied to an enum struct Foo; -#[repr(u128)] //~ ERROR: attribute should be applied to enum +#[repr(u128)] //~ ERROR: attribute should be applied to an enum struct Bar; fn main() {} diff --git a/src/test/ui/issues/issue-74082.stderr b/src/test/ui/issues/issue-74082.stderr index 08fe415513d..12f5a3b27bb 100644 --- a/src/test/ui/issues/issue-74082.stderr +++ b/src/test/ui/issues/issue-74082.stderr @@ -1,4 +1,4 @@ -error[E0517]: attribute should be applied to enum +error[E0517]: attribute should be applied to an enum --> $DIR/issue-74082.rs:3:8 | LL | #[repr(i128)] @@ -6,7 +6,7 @@ LL | #[repr(i128)] LL | struct Foo; | ----------- not an enum -error[E0517]: attribute should be applied to enum +error[E0517]: attribute should be applied to an enum --> $DIR/issue-74082.rs:6:8 | LL | #[repr(u128)] diff --git a/src/test/ui/macros/issue-68060.rs b/src/test/ui/macros/issue-68060.rs index f82eb338f4c..aa8f578adf6 100644 --- a/src/test/ui/macros/issue-68060.rs +++ b/src/test/ui/macros/issue-68060.rs @@ -3,10 +3,7 @@ fn main() { .map( #[target_feature(enable = "")] //~^ ERROR: attribute should be applied to a function - //~| ERROR: the feature named `` is not valid for this target - //~| NOTE: `` is not valid for this target #[track_caller] - //~^ ERROR: `#[track_caller]` requires Rust ABI [E0737] |_| (), //~^ NOTE: not a function ) diff --git a/src/test/ui/macros/issue-68060.stderr b/src/test/ui/macros/issue-68060.stderr index a01c3827bb5..1b58cf9c4ed 100644 --- a/src/test/ui/macros/issue-68060.stderr +++ b/src/test/ui/macros/issue-68060.stderr @@ -7,18 +7,5 @@ LL | #[target_feature(enable = "")] LL | |_| (), | ------ not a function -error: the feature named `` is not valid for this target - --> $DIR/issue-68060.rs:4:30 - | -LL | #[target_feature(enable = "")] - | ^^^^^^^^^^^ `` is not valid for this target +error: aborting due to previous error -error[E0737]: `#[track_caller]` requires Rust ABI - --> $DIR/issue-68060.rs:8:13 - | -LL | #[track_caller] - | ^^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0737`. diff --git a/src/test/ui/repr/repr-disallow-on-variant.rs b/src/test/ui/repr/repr-disallow-on-variant.rs new file mode 100644 index 00000000000..90cad7e647b --- /dev/null +++ b/src/test/ui/repr/repr-disallow-on-variant.rs @@ -0,0 +1,9 @@ +struct Test; + +enum Foo { + #[repr(u8)] + //~^ ERROR attribute should be applied to a struct, enum, or union + Variant, +} + +fn main() {} diff --git a/src/test/ui/repr/repr-disallow-on-variant.stderr b/src/test/ui/repr/repr-disallow-on-variant.stderr new file mode 100644 index 00000000000..70b45e393fc --- /dev/null +++ b/src/test/ui/repr/repr-disallow-on-variant.stderr @@ -0,0 +1,12 @@ +error[E0517]: attribute should be applied to a struct, enum, or union + --> $DIR/repr-disallow-on-variant.rs:4:12 + | +LL | #[repr(u8)] + | ^^ +LL | +LL | Variant, + | ------- not a struct, enum, or union + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0517`. diff --git a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs b/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs index 308634651a3..870eda89c20 100644 --- a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs +++ b/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs @@ -5,10 +5,10 @@ use std::num::NonZeroU16 as N16; #[repr(no_niche)] pub union Cloaked1 { _A: N16 } -//~^^ ERROR attribute should be applied to struct or enum [E0517] +//~^^ ERROR attribute should be applied to a struct or enum [E0517] #[repr(no_niche)] pub union Cloaked2 { _A: N16, _B: (u8, N8) } -//~^^ ERROR attribute should be applied to struct or enum [E0517] +//~^^ ERROR attribute should be applied to a struct or enum [E0517] fn main() { } diff --git a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr b/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr index 4c542c5f0da..9af929d4094 100644 --- a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr +++ b/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr @@ -1,4 +1,4 @@ -error[E0517]: attribute should be applied to struct or enum +error[E0517]: attribute should be applied to a struct or enum --> $DIR/repr-no-niche-inapplicable-to-unions.rs:6:8 | LL | #[repr(no_niche)] @@ -6,7 +6,7 @@ LL | #[repr(no_niche)] LL | pub union Cloaked1 { _A: N16 } | ------------------------------ not a struct or enum -error[E0517]: attribute should be applied to struct or enum +error[E0517]: attribute should be applied to a struct or enum --> $DIR/repr-no-niche-inapplicable-to-unions.rs:10:8 | LL | #[repr(no_niche)] diff --git a/src/test/ui/repr/repr-transparent-other-items.rs b/src/test/ui/repr/repr-transparent-other-items.rs index c3d772f6266..e537e3e1a63 100644 --- a/src/test/ui/repr/repr-transparent-other-items.rs +++ b/src/test/ui/repr/repr-transparent-other-items.rs @@ -1,9 +1,9 @@ // See also repr-transparent.rs -#[repr(transparent)] //~ ERROR should be applied to struct +#[repr(transparent)] //~ ERROR should be applied to a struct fn cant_repr_this() {} -#[repr(transparent)] //~ ERROR should be applied to struct +#[repr(transparent)] //~ ERROR should be applied to a struct static CANT_REPR_THIS: u32 = 0; fn main() {} diff --git a/src/test/ui/repr/repr-transparent-other-items.stderr b/src/test/ui/repr/repr-transparent-other-items.stderr index 03df3569b42..14e6f13e1ae 100644 --- a/src/test/ui/repr/repr-transparent-other-items.stderr +++ b/src/test/ui/repr/repr-transparent-other-items.stderr @@ -1,4 +1,4 @@ -error[E0517]: attribute should be applied to struct, enum, or union +error[E0517]: attribute should be applied to a struct, enum, or union --> $DIR/repr-transparent-other-items.rs:3:8 | LL | #[repr(transparent)] @@ -6,7 +6,7 @@ LL | #[repr(transparent)] LL | fn cant_repr_this() {} | ---------------------- not a struct, enum, or union -error[E0517]: attribute should be applied to struct, enum, or union +error[E0517]: attribute should be applied to a struct, enum, or union --> $DIR/repr-transparent-other-items.rs:6:8 | LL | #[repr(transparent)] From 81edbbc2bfacd29558a5020990d49fc07ed80ac7 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 29 Sep 2020 16:35:41 +0200 Subject: [PATCH 041/446] Implement TryFrom between NonZero types. --- library/core/src/convert/num.rs | 46 +++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 336c0b26bc7..173d824d390 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -485,3 +485,49 @@ nzint_impl_try_from_int! { i32, NonZeroI32, #[stable(feature = "nzint_try_from_i nzint_impl_try_from_int! { i64, NonZeroI64, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] } nzint_impl_try_from_int! { i128, NonZeroI128, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] } nzint_impl_try_from_int! { isize, NonZeroIsize, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] } + +macro_rules! nzint_impl_try_from_nzint { + ($From:ty => $To:ty, $doc: expr) => { + #[stable(feature = "nzint_try_from_nzint_conv", since = "1.48.0")] + #[doc = $doc] + impl TryFrom<$From> for $To { + type Error = TryFromIntError; + + #[inline] + fn try_from(value: $From) -> Result { + TryFrom::try_from(value.get()).map(|v| { + // SAFETY: $From is a NonZero type, so v is not zero. + unsafe { Self::new_unchecked(v) } + }) + } + } + }; + ($To:ty: $($From: ty),*) => {$( + nzint_impl_try_from_nzint!( + $From => $To, + concat!( + "Attempts to convert `", + stringify!($From), + "` to `", + stringify!($To), + "`.", + ) + ); + )*}; +} + +// Non-zero int -> non-zero unsigned int +nzint_impl_try_from_nzint! { NonZeroU8: NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize } +nzint_impl_try_from_nzint! { NonZeroU16: NonZeroI8, NonZeroI16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize } +nzint_impl_try_from_nzint! { NonZeroU32: NonZeroI8, NonZeroI16, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize } +nzint_impl_try_from_nzint! { NonZeroU64: NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize } +nzint_impl_try_from_nzint! { NonZeroU128: NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroUsize, NonZeroIsize } +nzint_impl_try_from_nzint! { NonZeroUsize: NonZeroI8, NonZeroI16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroIsize } + +// Non-zero int -> non-zero signed int +nzint_impl_try_from_nzint! { NonZeroI8: NonZeroU8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize } +nzint_impl_try_from_nzint! { NonZeroI16: NonZeroU16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize } +nzint_impl_try_from_nzint! { NonZeroI32: NonZeroU32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize } +nzint_impl_try_from_nzint! { NonZeroI64: NonZeroU64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize } +nzint_impl_try_from_nzint! { NonZeroI128: NonZeroU128, NonZeroUsize, NonZeroIsize } +nzint_impl_try_from_nzint! { NonZeroIsize: NonZeroU16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize } From 094f14c554c3a1f103a5d6778d4b4e131c297f11 Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 29 Sep 2020 10:30:42 -0700 Subject: [PATCH 042/446] Add article after "to" Also added missing backtick in "you can cast" message. --- compiler/rustc_typeck/src/check/demand.rs | 10 +- .../associated-types-path-2.stderr | 2 +- src/test/ui/indexing-requires-a-uint.stderr | 2 +- .../integer-literal-suffix-inference.stderr | 104 ++++---- src/test/ui/issues/issue-13359.stderr | 4 +- ...od-ambig-one-trait-unknown-int-type.stderr | 2 +- .../ui/mismatched_types/issue-26480.stderr | 2 +- src/test/ui/numeric/const-scope.stderr | 2 +- src/test/ui/numeric/len.stderr | 2 +- src/test/ui/numeric/numeric-cast-2.stderr | 6 +- src/test/ui/numeric/numeric-cast-binop.stderr | 194 +++++++-------- src/test/ui/numeric/numeric-cast.stderr | 226 +++++++++--------- src/test/ui/numeric/numeric-suffix.stderr | 24 +- .../ui/proc-macro/span-preservation.stderr | 2 +- src/test/ui/shift-various-bad-types.stderr | 2 +- ...e-mismatch-struct-field-shorthand-2.stderr | 4 +- ...ype-mismatch-struct-field-shorthand.stderr | 6 +- src/test/ui/tail-typeck.stderr | 2 +- ...ounds-inconsistent-projection-error.stderr | 2 +- .../ui/tutorial-suffix-inference-test.stderr | 6 +- src/test/ui/wrong-ret-type.stderr | 2 +- 21 files changed, 304 insertions(+), 302 deletions(-) diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index cd7b692c588..1081b3a229b 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -753,16 +753,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let msg = format!( - "you can convert {} `{}` to `{}`", + "you can convert {} `{}` to {} `{}`", checked_ty.kind().article(), checked_ty, - expected_ty + expected_ty.kind().article(), + expected_ty, ); let cast_msg = format!( - "you can cast {} `{} to `{}`", + "you can cast {} `{}` to {} `{}`", checked_ty.kind().article(), checked_ty, - expected_ty + expected_ty.kind().article(), + expected_ty, ); let lit_msg = format!( "change the type of the numeric literal from `{}` to `{}`", diff --git a/src/test/ui/associated-types/associated-types-path-2.stderr b/src/test/ui/associated-types/associated-types-path-2.stderr index dfe7e4da22d..618225274f1 100644 --- a/src/test/ui/associated-types/associated-types-path-2.stderr +++ b/src/test/ui/associated-types/associated-types-path-2.stderr @@ -47,7 +47,7 @@ LL | let _: i32 = f2(2i32); | | | expected due to this | -help: you can convert a `u32` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `i32` and panic if the converted value wouldn't fit | LL | let _: i32 = f2(2i32).try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/indexing-requires-a-uint.stderr b/src/test/ui/indexing-requires-a-uint.stderr index f290c0e632d..ac1ff99b8f8 100644 --- a/src/test/ui/indexing-requires-a-uint.stderr +++ b/src/test/ui/indexing-requires-a-uint.stderr @@ -13,7 +13,7 @@ error[E0308]: mismatched types LL | bar::(i); // i should not be re-coerced back to an isize | ^ expected `isize`, found `usize` | -help: you can convert a `usize` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `isize` and panic if the converted value wouldn't fit | LL | bar::(i.try_into().unwrap()); // i should not be re-coerced back to an isize | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/integer-literal-suffix-inference.stderr b/src/test/ui/integer-literal-suffix-inference.stderr index 8b541e6de06..642e0c3944c 100644 --- a/src/test/ui/integer-literal-suffix-inference.stderr +++ b/src/test/ui/integer-literal-suffix-inference.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | id_i8(a16); | ^^^ expected `i8`, found `i16` | -help: you can convert an `i16` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `i16` to an `i8` and panic if the converted value wouldn't fit | LL | id_i8(a16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ error[E0308]: mismatched types LL | id_i8(a32); | ^^^ expected `i8`, found `i32` | -help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `i8` and panic if the converted value wouldn't fit | LL | id_i8(a32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ error[E0308]: mismatched types LL | id_i8(a64); | ^^^ expected `i8`, found `i64` | -help: you can convert an `i64` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i8` and panic if the converted value wouldn't fit | LL | id_i8(a64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ error[E0308]: mismatched types LL | id_i8(asize); | ^^^^^ expected `i8`, found `isize` | -help: you can convert an `isize` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i8` and panic if the converted value wouldn't fit | LL | id_i8(asize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | id_i16(a8); | ^^ | | | expected `i16`, found `i8` - | help: you can convert an `i8` to `i16`: `a8.into()` + | help: you can convert an `i8` to an `i16`: `a8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:55:12 @@ -57,7 +57,7 @@ error[E0308]: mismatched types LL | id_i16(a32); | ^^^ expected `i16`, found `i32` | -help: you can convert an `i32` to `i16` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `i16` and panic if the converted value wouldn't fit | LL | id_i16(a32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -68,7 +68,7 @@ error[E0308]: mismatched types LL | id_i16(a64); | ^^^ expected `i16`, found `i64` | -help: you can convert an `i64` to `i16` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i16` and panic if the converted value wouldn't fit | LL | id_i16(a64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -79,7 +79,7 @@ error[E0308]: mismatched types LL | id_i16(asize); | ^^^^^ expected `i16`, found `isize` | -help: you can convert an `isize` to `i16` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i16` and panic if the converted value wouldn't fit | LL | id_i16(asize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -91,7 +91,7 @@ LL | id_i32(a8); | ^^ | | | expected `i32`, found `i8` - | help: you can convert an `i8` to `i32`: `a8.into()` + | help: you can convert an `i8` to an `i32`: `a8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:68:12 @@ -100,7 +100,7 @@ LL | id_i32(a16); | ^^^ | | | expected `i32`, found `i16` - | help: you can convert an `i16` to `i32`: `a16.into()` + | help: you can convert an `i16` to an `i32`: `a16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:72:12 @@ -108,7 +108,7 @@ error[E0308]: mismatched types LL | id_i32(a64); | ^^^ expected `i32`, found `i64` | -help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i32` and panic if the converted value wouldn't fit | LL | id_i32(a64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -119,7 +119,7 @@ error[E0308]: mismatched types LL | id_i32(asize); | ^^^^^ expected `i32`, found `isize` | -help: you can convert an `isize` to `i32` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i32` and panic if the converted value wouldn't fit | LL | id_i32(asize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL | id_i64(a8); | ^^ | | | expected `i64`, found `i8` - | help: you can convert an `i8` to `i64`: `a8.into()` + | help: you can convert an `i8` to an `i64`: `a8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:82:12 @@ -140,7 +140,7 @@ LL | id_i64(a16); | ^^^ | | | expected `i64`, found `i16` - | help: you can convert an `i16` to `i64`: `a16.into()` + | help: you can convert an `i16` to an `i64`: `a16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:85:12 @@ -149,7 +149,7 @@ LL | id_i64(a32); | ^^^ | | | expected `i64`, found `i32` - | help: you can convert an `i32` to `i64`: `a32.into()` + | help: you can convert an `i32` to an `i64`: `a32.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:89:12 @@ -157,7 +157,7 @@ error[E0308]: mismatched types LL | id_i64(asize); | ^^^^^ expected `i64`, found `isize` | -help: you can convert an `isize` to `i64` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i64` and panic if the converted value wouldn't fit | LL | id_i64(asize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL | id_isize(a8); | ^^ | | | expected `isize`, found `i8` - | help: you can convert an `i8` to `isize`: `a8.into()` + | help: you can convert an `i8` to an `isize`: `a8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:96:14 @@ -178,7 +178,7 @@ LL | id_isize(a16); | ^^^ | | | expected `isize`, found `i16` - | help: you can convert an `i16` to `isize`: `a16.into()` + | help: you can convert an `i16` to an `isize`: `a16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:99:14 @@ -186,7 +186,7 @@ error[E0308]: mismatched types LL | id_isize(a32); | ^^^ expected `isize`, found `i32` | -help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `isize` and panic if the converted value wouldn't fit | LL | id_isize(a32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -197,7 +197,7 @@ error[E0308]: mismatched types LL | id_isize(a64); | ^^^ expected `isize`, found `i64` | -help: you can convert an `i64` to `isize` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `isize` and panic if the converted value wouldn't fit | LL | id_isize(a64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -208,7 +208,7 @@ error[E0308]: mismatched types LL | id_i8(c16); | ^^^ expected `i8`, found `i16` | -help: you can convert an `i16` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `i16` to an `i8` and panic if the converted value wouldn't fit | LL | id_i8(c16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -219,7 +219,7 @@ error[E0308]: mismatched types LL | id_i8(c32); | ^^^ expected `i8`, found `i32` | -help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `i8` and panic if the converted value wouldn't fit | LL | id_i8(c32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -230,7 +230,7 @@ error[E0308]: mismatched types LL | id_i8(c64); | ^^^ expected `i8`, found `i64` | -help: you can convert an `i64` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i8` and panic if the converted value wouldn't fit | LL | id_i8(c64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -242,7 +242,7 @@ LL | id_i16(c8); | ^^ | | | expected `i16`, found `i8` - | help: you can convert an `i8` to `i16`: `c8.into()` + | help: you can convert an `i8` to an `i16`: `c8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:122:12 @@ -250,7 +250,7 @@ error[E0308]: mismatched types LL | id_i16(c32); | ^^^ expected `i16`, found `i32` | -help: you can convert an `i32` to `i16` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `i16` and panic if the converted value wouldn't fit | LL | id_i16(c32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -261,7 +261,7 @@ error[E0308]: mismatched types LL | id_i16(c64); | ^^^ expected `i16`, found `i64` | -help: you can convert an `i64` to `i16` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i16` and panic if the converted value wouldn't fit | LL | id_i16(c64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -273,7 +273,7 @@ LL | id_i32(c8); | ^^ | | | expected `i32`, found `i8` - | help: you can convert an `i8` to `i32`: `c8.into()` + | help: you can convert an `i8` to an `i32`: `c8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:132:12 @@ -282,7 +282,7 @@ LL | id_i32(c16); | ^^^ | | | expected `i32`, found `i16` - | help: you can convert an `i16` to `i32`: `c16.into()` + | help: you can convert an `i16` to an `i32`: `c16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:136:12 @@ -290,7 +290,7 @@ error[E0308]: mismatched types LL | id_i32(c64); | ^^^ expected `i32`, found `i64` | -help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i32` and panic if the converted value wouldn't fit | LL | id_i32(c64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -302,7 +302,7 @@ LL | id_i64(a8); | ^^ | | | expected `i64`, found `i8` - | help: you can convert an `i8` to `i64`: `a8.into()` + | help: you can convert an `i8` to an `i64`: `a8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:143:12 @@ -311,7 +311,7 @@ LL | id_i64(a16); | ^^^ | | | expected `i64`, found `i16` - | help: you can convert an `i16` to `i64`: `a16.into()` + | help: you can convert an `i16` to an `i64`: `a16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:146:12 @@ -320,7 +320,7 @@ LL | id_i64(a32); | ^^^ | | | expected `i64`, found `i32` - | help: you can convert an `i32` to `i64`: `a32.into()` + | help: you can convert an `i32` to an `i64`: `a32.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:152:11 @@ -328,7 +328,7 @@ error[E0308]: mismatched types LL | id_u8(b16); | ^^^ expected `u8`, found `u16` | -help: you can convert a `u16` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `u16` to a `u8` and panic if the converted value wouldn't fit | LL | id_u8(b16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -339,7 +339,7 @@ error[E0308]: mismatched types LL | id_u8(b32); | ^^^ expected `u8`, found `u32` | -help: you can convert a `u32` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `u32` to a `u8` and panic if the converted value wouldn't fit | LL | id_u8(b32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -350,7 +350,7 @@ error[E0308]: mismatched types LL | id_u8(b64); | ^^^ expected `u8`, found `u64` | -help: you can convert a `u64` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `u8` and panic if the converted value wouldn't fit | LL | id_u8(b64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -361,7 +361,7 @@ error[E0308]: mismatched types LL | id_u8(bsize); | ^^^^^ expected `u8`, found `usize` | -help: you can convert a `usize` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u8` and panic if the converted value wouldn't fit | LL | id_u8(bsize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -373,7 +373,7 @@ LL | id_u16(b8); | ^^ | | | expected `u16`, found `u8` - | help: you can convert a `u8` to `u16`: `b8.into()` + | help: you can convert a `u8` to a `u16`: `b8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:169:12 @@ -381,7 +381,7 @@ error[E0308]: mismatched types LL | id_u16(b32); | ^^^ expected `u16`, found `u32` | -help: you can convert a `u32` to `u16` and panic if the converted value wouldn't fit +help: you can convert a `u32` to a `u16` and panic if the converted value wouldn't fit | LL | id_u16(b32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -392,7 +392,7 @@ error[E0308]: mismatched types LL | id_u16(b64); | ^^^ expected `u16`, found `u64` | -help: you can convert a `u64` to `u16` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `u16` and panic if the converted value wouldn't fit | LL | id_u16(b64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -403,7 +403,7 @@ error[E0308]: mismatched types LL | id_u16(bsize); | ^^^^^ expected `u16`, found `usize` | -help: you can convert a `usize` to `u16` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u16` and panic if the converted value wouldn't fit | LL | id_u16(bsize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -415,7 +415,7 @@ LL | id_u32(b8); | ^^ | | | expected `u32`, found `u8` - | help: you can convert a `u8` to `u32`: `b8.into()` + | help: you can convert a `u8` to a `u32`: `b8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:182:12 @@ -424,7 +424,7 @@ LL | id_u32(b16); | ^^^ | | | expected `u32`, found `u16` - | help: you can convert a `u16` to `u32`: `b16.into()` + | help: you can convert a `u16` to a `u32`: `b16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:186:12 @@ -432,7 +432,7 @@ error[E0308]: mismatched types LL | id_u32(b64); | ^^^ expected `u32`, found `u64` | -help: you can convert a `u64` to `u32` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `u32` and panic if the converted value wouldn't fit | LL | id_u32(b64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -443,7 +443,7 @@ error[E0308]: mismatched types LL | id_u32(bsize); | ^^^^^ expected `u32`, found `usize` | -help: you can convert a `usize` to `u32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u32` and panic if the converted value wouldn't fit | LL | id_u32(bsize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -455,7 +455,7 @@ LL | id_u64(b8); | ^^ | | | expected `u64`, found `u8` - | help: you can convert a `u8` to `u64`: `b8.into()` + | help: you can convert a `u8` to a `u64`: `b8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:196:12 @@ -464,7 +464,7 @@ LL | id_u64(b16); | ^^^ | | | expected `u64`, found `u16` - | help: you can convert a `u16` to `u64`: `b16.into()` + | help: you can convert a `u16` to a `u64`: `b16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:199:12 @@ -473,7 +473,7 @@ LL | id_u64(b32); | ^^^ | | | expected `u64`, found `u32` - | help: you can convert a `u32` to `u64`: `b32.into()` + | help: you can convert a `u32` to a `u64`: `b32.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:203:12 @@ -481,7 +481,7 @@ error[E0308]: mismatched types LL | id_u64(bsize); | ^^^^^ expected `u64`, found `usize` | -help: you can convert a `usize` to `u64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u64` and panic if the converted value wouldn't fit | LL | id_u64(bsize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -493,7 +493,7 @@ LL | id_usize(b8); | ^^ | | | expected `usize`, found `u8` - | help: you can convert a `u8` to `usize`: `b8.into()` + | help: you can convert a `u8` to a `usize`: `b8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:210:14 @@ -502,7 +502,7 @@ LL | id_usize(b16); | ^^^ | | | expected `usize`, found `u16` - | help: you can convert a `u16` to `usize`: `b16.into()` + | help: you can convert a `u16` to a `usize`: `b16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:213:14 @@ -510,7 +510,7 @@ error[E0308]: mismatched types LL | id_usize(b32); | ^^^ expected `usize`, found `u32` | -help: you can convert a `u32` to `usize` and panic if the converted value wouldn't fit +help: you can convert a `u32` to a `usize` and panic if the converted value wouldn't fit | LL | id_usize(b32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -521,7 +521,7 @@ error[E0308]: mismatched types LL | id_usize(b64); | ^^^ expected `usize`, found `u64` | -help: you can convert a `u64` to `usize` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `usize` and panic if the converted value wouldn't fit | LL | id_usize(b64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/issues/issue-13359.stderr b/src/test/ui/issues/issue-13359.stderr index e99554ec684..2e7e42f1667 100644 --- a/src/test/ui/issues/issue-13359.stderr +++ b/src/test/ui/issues/issue-13359.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | foo(1*(1 as isize)); | ^^^^^^^^^^^^^^ expected `i16`, found `isize` | -help: you can convert an `isize` to `i16` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i16` and panic if the converted value wouldn't fit | LL | foo((1*(1 as isize)).try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ error[E0308]: mismatched types LL | bar(1*(1 as usize)); | ^^^^^^^^^^^^^^ expected `u32`, found `usize` | -help: you can convert a `usize` to `u32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u32` and panic if the converted value wouldn't fit | LL | bar((1*(1 as usize)).try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr index 33e8282c9d2..3f4dda81347 100644 --- a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr +++ b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr @@ -14,7 +14,7 @@ LL | let y: usize = x.foo(); | | | expected due to this | -help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `usize` and panic if the converted value wouldn't fit | LL | let y: usize = x.foo().try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index 35080716f28..7dc686c8e7b 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -8,7 +8,7 @@ LL | write!(hello); | -------------- in this macro invocation | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -help: you can convert a `usize` to `u64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u64` and panic if the converted value wouldn't fit | LL | ($arr.len() * size_of($arr[0])).try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/numeric/const-scope.stderr b/src/test/ui/numeric/const-scope.stderr index d7f18e19b41..94ff4623c60 100644 --- a/src/test/ui/numeric/const-scope.stderr +++ b/src/test/ui/numeric/const-scope.stderr @@ -57,7 +57,7 @@ LL | let d: i8 = c; | | | expected due to this | -help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `i8` and panic if the converted value wouldn't fit | LL | let d: i8 = c.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/numeric/len.stderr b/src/test/ui/numeric/len.stderr index c0469f74d45..946a4de4245 100644 --- a/src/test/ui/numeric/len.stderr +++ b/src/test/ui/numeric/len.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | test(array.len()); | ^^^^^^^^^^^ expected `u32`, found `usize` | -help: you can convert a `usize` to `u32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u32` and panic if the converted value wouldn't fit | LL | test(array.len().try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/numeric/numeric-cast-2.stderr b/src/test/ui/numeric/numeric-cast-2.stderr index fc9124be2a7..9409ce1ed0e 100644 --- a/src/test/ui/numeric/numeric-cast-2.stderr +++ b/src/test/ui/numeric/numeric-cast-2.stderr @@ -6,7 +6,7 @@ LL | let x: u16 = foo(); | | | expected due to this | -help: you can convert an `i32` to `u16` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u16` and panic if the converted value wouldn't fit | LL | let x: u16 = foo().try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | let y: i64 = x + x; | --- ^^^^^ | | | | | expected `i64`, found `u16` - | | help: you can convert a `u16` to `i64`: `(x + x).into()` + | | help: you can convert a `u16` to an `i64`: `(x + x).into()` | expected due to this error[E0308]: mismatched types @@ -28,7 +28,7 @@ LL | let z: i32 = x + x; | --- ^^^^^ | | | | | expected `i32`, found `u16` - | | help: you can convert a `u16` to `i32`: `(x + x).into()` + | | help: you can convert a `u16` to an `i32`: `(x + x).into()` | expected due to this error: aborting due to 3 previous errors diff --git a/src/test/ui/numeric/numeric-cast-binop.stderr b/src/test/ui/numeric/numeric-cast-binop.stderr index 6523f31edbf..c0f784309b9 100644 --- a/src/test/ui/numeric/numeric-cast-binop.stderr +++ b/src/test/ui/numeric/numeric-cast-binop.stderr @@ -60,7 +60,7 @@ LL | x_u16 > x_u8; | ^^^^ | | | expected `u16`, found `u8` - | help: you can convert a `u8` to `u16`: `x_u8.into()` + | help: you can convert a `u8` to a `u16`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:36:17 @@ -113,7 +113,7 @@ LL | x_u32 > x_u8; | ^^^^ | | | expected `u32`, found `u8` - | help: you can convert a `u8` to `u32`: `x_u8.into()` + | help: you can convert a `u8` to a `u32`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:47:17 @@ -122,7 +122,7 @@ LL | x_u32 > x_u16; | ^^^^^ | | | expected `u32`, found `u16` - | help: you can convert a `u16` to `u32`: `x_u16.into()` + | help: you can convert a `u16` to a `u32`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:49:17 @@ -152,7 +152,7 @@ error[E0308]: mismatched types LL | x_u32 > x_usize; | ^^^^^^^ expected `u32`, found `usize` | -help: you can convert a `usize` to `u32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u32` and panic if the converted value wouldn't fit | LL | x_u32 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -164,7 +164,7 @@ LL | x_u64 > x_u8; | ^^^^ | | | expected `u64`, found `u8` - | help: you can convert a `u8` to `u64`: `x_u8.into()` + | help: you can convert a `u8` to a `u64`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:58:17 @@ -173,7 +173,7 @@ LL | x_u64 > x_u16; | ^^^^^ | | | expected `u64`, found `u16` - | help: you can convert a `u16` to `u64`: `x_u16.into()` + | help: you can convert a `u16` to a `u64`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:60:17 @@ -182,7 +182,7 @@ LL | x_u64 > x_u32; | ^^^^^ | | | expected `u64`, found `u32` - | help: you can convert a `u32` to `u64`: `x_u32.into()` + | help: you can convert a `u32` to a `u64`: `x_u32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:62:17 @@ -201,7 +201,7 @@ error[E0308]: mismatched types LL | x_u64 > x_usize; | ^^^^^^^ expected `u64`, found `usize` | -help: you can convert a `usize` to `u64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u64` and panic if the converted value wouldn't fit | LL | x_u64 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -213,7 +213,7 @@ LL | x_u128 > x_u8; | ^^^^ | | | expected `u128`, found `u8` - | help: you can convert a `u8` to `u128`: `x_u8.into()` + | help: you can convert a `u8` to a `u128`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:69:18 @@ -222,7 +222,7 @@ LL | x_u128 > x_u16; | ^^^^^ | | | expected `u128`, found `u16` - | help: you can convert a `u16` to `u128`: `x_u16.into()` + | help: you can convert a `u16` to a `u128`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:71:18 @@ -231,7 +231,7 @@ LL | x_u128 > x_u32; | ^^^^^ | | | expected `u128`, found `u32` - | help: you can convert a `u32` to `u128`: `x_u32.into()` + | help: you can convert a `u32` to a `u128`: `x_u32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:73:18 @@ -240,7 +240,7 @@ LL | x_u128 > x_u64; | ^^^^^ | | | expected `u128`, found `u64` - | help: you can convert a `u64` to `u128`: `x_u64.into()` + | help: you can convert a `u64` to a `u128`: `x_u64.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:75:18 @@ -248,7 +248,7 @@ error[E0308]: mismatched types LL | x_u128 > x_usize; | ^^^^^^^ expected `u128`, found `usize` | -help: you can convert a `usize` to `u128` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u128` and panic if the converted value wouldn't fit | LL | x_u128 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -260,7 +260,7 @@ LL | x_usize > x_u8; | ^^^^ | | | expected `usize`, found `u8` - | help: you can convert a `u8` to `usize`: `x_u8.into()` + | help: you can convert a `u8` to a `usize`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:80:19 @@ -269,7 +269,7 @@ LL | x_usize > x_u16; | ^^^^^ | | | expected `usize`, found `u16` - | help: you can convert a `u16` to `usize`: `x_u16.into()` + | help: you can convert a `u16` to a `usize`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:82:19 @@ -277,7 +277,7 @@ error[E0308]: mismatched types LL | x_usize > x_u32; | ^^^^^ expected `usize`, found `u32` | -help: you can convert a `u32` to `usize` and panic if the converted value wouldn't fit +help: you can convert a `u32` to a `usize` and panic if the converted value wouldn't fit | LL | x_usize > x_u32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -288,7 +288,7 @@ error[E0308]: mismatched types LL | x_usize > x_u64; | ^^^^^ expected `usize`, found `u64` | -help: you can convert a `u64` to `usize` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `usize` and panic if the converted value wouldn't fit | LL | x_usize > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -299,7 +299,7 @@ error[E0308]: mismatched types LL | x_usize > x_u128; | ^^^^^^ expected `usize`, found `u128` | -help: you can convert a `u128` to `usize` and panic if the converted value wouldn't fit +help: you can convert a `u128` to a `usize` and panic if the converted value wouldn't fit | LL | x_usize > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -366,7 +366,7 @@ LL | x_i16 > x_i8; | ^^^^ | | | expected `i16`, found `i8` - | help: you can convert an `i8` to `i16`: `x_i8.into()` + | help: you can convert an `i8` to an `i16`: `x_i8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:105:17 @@ -419,7 +419,7 @@ LL | x_i32 > x_i8; | ^^^^ | | | expected `i32`, found `i8` - | help: you can convert an `i8` to `i32`: `x_i8.into()` + | help: you can convert an `i8` to an `i32`: `x_i8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:116:17 @@ -428,7 +428,7 @@ LL | x_i32 > x_i16; | ^^^^^ | | | expected `i32`, found `i16` - | help: you can convert an `i16` to `i32`: `x_i16.into()` + | help: you can convert an `i16` to an `i32`: `x_i16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:118:17 @@ -458,7 +458,7 @@ error[E0308]: mismatched types LL | x_i32 > x_isize; | ^^^^^^^ expected `i32`, found `isize` | -help: you can convert an `isize` to `i32` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i32` and panic if the converted value wouldn't fit | LL | x_i32 > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -470,7 +470,7 @@ LL | x_i64 > x_i8; | ^^^^ | | | expected `i64`, found `i8` - | help: you can convert an `i8` to `i64`: `x_i8.into()` + | help: you can convert an `i8` to an `i64`: `x_i8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:127:17 @@ -479,7 +479,7 @@ LL | x_i64 > x_i16; | ^^^^^ | | | expected `i64`, found `i16` - | help: you can convert an `i16` to `i64`: `x_i16.into()` + | help: you can convert an `i16` to an `i64`: `x_i16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:129:17 @@ -488,7 +488,7 @@ LL | x_i64 > x_i32; | ^^^^^ | | | expected `i64`, found `i32` - | help: you can convert an `i32` to `i64`: `x_i32.into()` + | help: you can convert an `i32` to an `i64`: `x_i32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:131:17 @@ -507,7 +507,7 @@ error[E0308]: mismatched types LL | x_i64 > x_isize; | ^^^^^^^ expected `i64`, found `isize` | -help: you can convert an `isize` to `i64` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i64` and panic if the converted value wouldn't fit | LL | x_i64 > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -519,7 +519,7 @@ LL | x_i128 > x_i8; | ^^^^ | | | expected `i128`, found `i8` - | help: you can convert an `i8` to `i128`: `x_i8.into()` + | help: you can convert an `i8` to an `i128`: `x_i8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:138:18 @@ -528,7 +528,7 @@ LL | x_i128 > x_i16; | ^^^^^ | | | expected `i128`, found `i16` - | help: you can convert an `i16` to `i128`: `x_i16.into()` + | help: you can convert an `i16` to an `i128`: `x_i16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:140:18 @@ -537,7 +537,7 @@ LL | x_i128 > x_i32; | ^^^^^ | | | expected `i128`, found `i32` - | help: you can convert an `i32` to `i128`: `x_i32.into()` + | help: you can convert an `i32` to an `i128`: `x_i32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:142:18 @@ -546,7 +546,7 @@ LL | x_i128 > x_i64; | ^^^^^ | | | expected `i128`, found `i64` - | help: you can convert an `i64` to `i128`: `x_i64.into()` + | help: you can convert an `i64` to an `i128`: `x_i64.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:144:18 @@ -554,7 +554,7 @@ error[E0308]: mismatched types LL | x_i128 > x_isize; | ^^^^^^^ expected `i128`, found `isize` | -help: you can convert an `isize` to `i128` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i128` and panic if the converted value wouldn't fit | LL | x_i128 > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -566,7 +566,7 @@ LL | x_isize > x_i8; | ^^^^ | | | expected `isize`, found `i8` - | help: you can convert an `i8` to `isize`: `x_i8.into()` + | help: you can convert an `i8` to an `isize`: `x_i8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:149:19 @@ -575,7 +575,7 @@ LL | x_isize > x_i16; | ^^^^^ | | | expected `isize`, found `i16` - | help: you can convert an `i16` to `isize`: `x_i16.into()` + | help: you can convert an `i16` to an `isize`: `x_i16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:151:19 @@ -583,7 +583,7 @@ error[E0308]: mismatched types LL | x_isize > x_i32; | ^^^^^ expected `isize`, found `i32` | -help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `isize` and panic if the converted value wouldn't fit | LL | x_isize > x_i32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -594,7 +594,7 @@ error[E0308]: mismatched types LL | x_isize > x_i64; | ^^^^^ expected `isize`, found `i64` | -help: you can convert an `i64` to `isize` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `isize` and panic if the converted value wouldn't fit | LL | x_isize > x_i64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -605,7 +605,7 @@ error[E0308]: mismatched types LL | x_isize > x_i128; | ^^^^^^ expected `isize`, found `i128` | -help: you can convert an `i128` to `isize` and panic if the converted value wouldn't fit +help: you can convert an `i128` to an `isize` and panic if the converted value wouldn't fit | LL | x_isize > x_i128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -616,7 +616,7 @@ error[E0308]: mismatched types LL | x_u8 > x_i8; | ^^^^ expected `u8`, found `i8` | -help: you can convert an `i8` to `u8` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u8` and panic if the converted value wouldn't fit | LL | x_u8 > x_i8.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -682,7 +682,7 @@ error[E0308]: mismatched types LL | x_u16 > x_i8; | ^^^^ expected `u16`, found `i8` | -help: you can convert an `i8` to `u16` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u16` and panic if the converted value wouldn't fit | LL | x_u16 > x_i8.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -693,7 +693,7 @@ error[E0308]: mismatched types LL | x_u16 > x_i16; | ^^^^^ expected `u16`, found `i16` | -help: you can convert an `i16` to `u16` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u16` and panic if the converted value wouldn't fit | LL | x_u16 > x_i16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -737,7 +737,7 @@ error[E0308]: mismatched types LL | x_u16 > x_isize; | ^^^^^^^ expected `u16`, found `isize` | -help: you can convert an `isize` to `u16` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u16` and panic if the converted value wouldn't fit | LL | x_u16 > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -748,7 +748,7 @@ error[E0308]: mismatched types LL | x_u32 > x_i8; | ^^^^ expected `u32`, found `i8` | -help: you can convert an `i8` to `u32` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u32` and panic if the converted value wouldn't fit | LL | x_u32 > x_i8.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -759,7 +759,7 @@ error[E0308]: mismatched types LL | x_u32 > x_i16; | ^^^^^ expected `u32`, found `i16` | -help: you can convert an `i16` to `u32` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u32` and panic if the converted value wouldn't fit | LL | x_u32 > x_i16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -770,7 +770,7 @@ error[E0308]: mismatched types LL | x_u32 > x_i32; | ^^^^^ expected `u32`, found `i32` | -help: you can convert an `i32` to `u32` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u32` and panic if the converted value wouldn't fit | LL | x_u32 > x_i32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -803,7 +803,7 @@ error[E0308]: mismatched types LL | x_u32 > x_isize; | ^^^^^^^ expected `u32`, found `isize` | -help: you can convert an `isize` to `u32` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u32` and panic if the converted value wouldn't fit | LL | x_u32 > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -814,7 +814,7 @@ error[E0308]: mismatched types LL | x_u64 > x_i8; | ^^^^ expected `u64`, found `i8` | -help: you can convert an `i8` to `u64` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u64` and panic if the converted value wouldn't fit | LL | x_u64 > x_i8.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -825,7 +825,7 @@ error[E0308]: mismatched types LL | x_u64 > x_i16; | ^^^^^ expected `u64`, found `i16` | -help: you can convert an `i16` to `u64` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u64` and panic if the converted value wouldn't fit | LL | x_u64 > x_i16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -836,7 +836,7 @@ error[E0308]: mismatched types LL | x_u64 > x_i32; | ^^^^^ expected `u64`, found `i32` | -help: you can convert an `i32` to `u64` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u64` and panic if the converted value wouldn't fit | LL | x_u64 > x_i32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -847,7 +847,7 @@ error[E0308]: mismatched types LL | x_u64 > x_i64; | ^^^^^ expected `u64`, found `i64` | -help: you can convert an `i64` to `u64` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `u64` and panic if the converted value wouldn't fit | LL | x_u64 > x_i64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -869,7 +869,7 @@ error[E0308]: mismatched types LL | x_u64 > x_isize; | ^^^^^^^ expected `u64`, found `isize` | -help: you can convert an `isize` to `u64` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u64` and panic if the converted value wouldn't fit | LL | x_u64 > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -880,7 +880,7 @@ error[E0308]: mismatched types LL | x_u128 > x_i8; | ^^^^ expected `u128`, found `i8` | -help: you can convert an `i8` to `u128` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u128` and panic if the converted value wouldn't fit | LL | x_u128 > x_i8.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -891,7 +891,7 @@ error[E0308]: mismatched types LL | x_u128 > x_i16; | ^^^^^ expected `u128`, found `i16` | -help: you can convert an `i16` to `u128` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u128` and panic if the converted value wouldn't fit | LL | x_u128 > x_i16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -902,7 +902,7 @@ error[E0308]: mismatched types LL | x_u128 > x_i32; | ^^^^^ expected `u128`, found `i32` | -help: you can convert an `i32` to `u128` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u128` and panic if the converted value wouldn't fit | LL | x_u128 > x_i32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -913,7 +913,7 @@ error[E0308]: mismatched types LL | x_u128 > x_i64; | ^^^^^ expected `u128`, found `i64` | -help: you can convert an `i64` to `u128` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `u128` and panic if the converted value wouldn't fit | LL | x_u128 > x_i64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -924,7 +924,7 @@ error[E0308]: mismatched types LL | x_u128 > x_i128; | ^^^^^^ expected `u128`, found `i128` | -help: you can convert an `i128` to `u128` and panic if the converted value wouldn't fit +help: you can convert an `i128` to a `u128` and panic if the converted value wouldn't fit | LL | x_u128 > x_i128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -935,7 +935,7 @@ error[E0308]: mismatched types LL | x_u128 > x_isize; | ^^^^^^^ expected `u128`, found `isize` | -help: you can convert an `isize` to `u128` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u128` and panic if the converted value wouldn't fit | LL | x_u128 > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -946,7 +946,7 @@ error[E0308]: mismatched types LL | x_usize > x_i8; | ^^^^ expected `usize`, found `i8` | -help: you can convert an `i8` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `usize` and panic if the converted value wouldn't fit | LL | x_usize > x_i8.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -957,7 +957,7 @@ error[E0308]: mismatched types LL | x_usize > x_i16; | ^^^^^ expected `usize`, found `i16` | -help: you can convert an `i16` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `usize` and panic if the converted value wouldn't fit | LL | x_usize > x_i16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -968,7 +968,7 @@ error[E0308]: mismatched types LL | x_usize > x_i32; | ^^^^^ expected `usize`, found `i32` | -help: you can convert an `i32` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `usize` and panic if the converted value wouldn't fit | LL | x_usize > x_i32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -979,7 +979,7 @@ error[E0308]: mismatched types LL | x_usize > x_i64; | ^^^^^ expected `usize`, found `i64` | -help: you can convert an `i64` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `usize` and panic if the converted value wouldn't fit | LL | x_usize > x_i64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -990,7 +990,7 @@ error[E0308]: mismatched types LL | x_usize > x_i128; | ^^^^^^ expected `usize`, found `i128` | -help: you can convert an `i128` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `i128` to a `usize` and panic if the converted value wouldn't fit | LL | x_usize > x_i128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1001,7 +1001,7 @@ error[E0308]: mismatched types LL | x_usize > x_isize; | ^^^^^^^ expected `usize`, found `isize` | -help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `usize` and panic if the converted value wouldn't fit | LL | x_usize > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1012,7 +1012,7 @@ error[E0308]: mismatched types LL | x_i8 > x_u8; | ^^^^ expected `i8`, found `u8` | -help: you can convert a `u8` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u8` to an `i8` and panic if the converted value wouldn't fit | LL | x_i8 > x_u8.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1023,7 +1023,7 @@ error[E0308]: mismatched types LL | x_i8 > x_u16; | ^^^^^ expected `i8`, found `u16` | -help: you can convert a `u16` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u16` to an `i8` and panic if the converted value wouldn't fit | LL | x_i8 > x_u16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1034,7 +1034,7 @@ error[E0308]: mismatched types LL | x_i8 > x_u32; | ^^^^^ expected `i8`, found `u32` | -help: you can convert a `u32` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `i8` and panic if the converted value wouldn't fit | LL | x_i8 > x_u32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1045,7 +1045,7 @@ error[E0308]: mismatched types LL | x_i8 > x_u64; | ^^^^^ expected `i8`, found `u64` | -help: you can convert a `u64` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i8` and panic if the converted value wouldn't fit | LL | x_i8 > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1056,7 +1056,7 @@ error[E0308]: mismatched types LL | x_i8 > x_u128; | ^^^^^^ expected `i8`, found `u128` | -help: you can convert a `u128` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u128` to an `i8` and panic if the converted value wouldn't fit | LL | x_i8 > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1067,7 +1067,7 @@ error[E0308]: mismatched types LL | x_i8 > x_usize; | ^^^^^^^ expected `i8`, found `usize` | -help: you can convert a `usize` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i8` and panic if the converted value wouldn't fit | LL | x_i8 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1079,7 +1079,7 @@ LL | x_i16 > x_u8; | ^^^^ | | | expected `i16`, found `u8` - | help: you can convert a `u8` to `i16`: `x_u8.into()` + | help: you can convert a `u8` to an `i16`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:257:17 @@ -1087,7 +1087,7 @@ error[E0308]: mismatched types LL | x_i16 > x_u16; | ^^^^^ expected `i16`, found `u16` | -help: you can convert a `u16` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `u16` to an `i16` and panic if the converted value wouldn't fit | LL | x_i16 > x_u16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1098,7 +1098,7 @@ error[E0308]: mismatched types LL | x_i16 > x_u32; | ^^^^^ expected `i16`, found `u32` | -help: you can convert a `u32` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `i16` and panic if the converted value wouldn't fit | LL | x_i16 > x_u32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1109,7 +1109,7 @@ error[E0308]: mismatched types LL | x_i16 > x_u64; | ^^^^^ expected `i16`, found `u64` | -help: you can convert a `u64` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i16` and panic if the converted value wouldn't fit | LL | x_i16 > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1120,7 +1120,7 @@ error[E0308]: mismatched types LL | x_i16 > x_u128; | ^^^^^^ expected `i16`, found `u128` | -help: you can convert a `u128` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `u128` to an `i16` and panic if the converted value wouldn't fit | LL | x_i16 > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1131,7 +1131,7 @@ error[E0308]: mismatched types LL | x_i16 > x_usize; | ^^^^^^^ expected `i16`, found `usize` | -help: you can convert a `usize` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i16` and panic if the converted value wouldn't fit | LL | x_i16 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1143,7 +1143,7 @@ LL | x_i32 > x_u8; | ^^^^ | | | expected `i32`, found `u8` - | help: you can convert a `u8` to `i32`: `x_u8.into()` + | help: you can convert a `u8` to an `i32`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:270:17 @@ -1152,7 +1152,7 @@ LL | x_i32 > x_u16; | ^^^^^ | | | expected `i32`, found `u16` - | help: you can convert a `u16` to `i32`: `x_u16.into()` + | help: you can convert a `u16` to an `i32`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:272:17 @@ -1160,7 +1160,7 @@ error[E0308]: mismatched types LL | x_i32 > x_u32; | ^^^^^ expected `i32`, found `u32` | -help: you can convert a `u32` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `i32` and panic if the converted value wouldn't fit | LL | x_i32 > x_u32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1171,7 +1171,7 @@ error[E0308]: mismatched types LL | x_i32 > x_u64; | ^^^^^ expected `i32`, found `u64` | -help: you can convert a `u64` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i32` and panic if the converted value wouldn't fit | LL | x_i32 > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1182,7 +1182,7 @@ error[E0308]: mismatched types LL | x_i32 > x_u128; | ^^^^^^ expected `i32`, found `u128` | -help: you can convert a `u128` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `u128` to an `i32` and panic if the converted value wouldn't fit | LL | x_i32 > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1193,7 +1193,7 @@ error[E0308]: mismatched types LL | x_i32 > x_usize; | ^^^^^^^ expected `i32`, found `usize` | -help: you can convert a `usize` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i32` and panic if the converted value wouldn't fit | LL | x_i32 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1205,7 +1205,7 @@ LL | x_i64 > x_u8; | ^^^^ | | | expected `i64`, found `u8` - | help: you can convert a `u8` to `i64`: `x_u8.into()` + | help: you can convert a `u8` to an `i64`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:283:17 @@ -1214,7 +1214,7 @@ LL | x_i64 > x_u16; | ^^^^^ | | | expected `i64`, found `u16` - | help: you can convert a `u16` to `i64`: `x_u16.into()` + | help: you can convert a `u16` to an `i64`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:285:17 @@ -1223,7 +1223,7 @@ LL | x_i64 > x_u32; | ^^^^^ | | | expected `i64`, found `u32` - | help: you can convert a `u32` to `i64`: `x_u32.into()` + | help: you can convert a `u32` to an `i64`: `x_u32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:287:17 @@ -1231,7 +1231,7 @@ error[E0308]: mismatched types LL | x_i64 > x_u64; | ^^^^^ expected `i64`, found `u64` | -help: you can convert a `u64` to `i64` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i64` and panic if the converted value wouldn't fit | LL | x_i64 > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1242,7 +1242,7 @@ error[E0308]: mismatched types LL | x_i64 > x_u128; | ^^^^^^ expected `i64`, found `u128` | -help: you can convert a `u128` to `i64` and panic if the converted value wouldn't fit +help: you can convert a `u128` to an `i64` and panic if the converted value wouldn't fit | LL | x_i64 > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1253,7 +1253,7 @@ error[E0308]: mismatched types LL | x_i64 > x_usize; | ^^^^^^^ expected `i64`, found `usize` | -help: you can convert a `usize` to `i64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i64` and panic if the converted value wouldn't fit | LL | x_i64 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1265,7 +1265,7 @@ LL | x_i128 > x_u8; | ^^^^ | | | expected `i128`, found `u8` - | help: you can convert a `u8` to `i128`: `x_u8.into()` + | help: you can convert a `u8` to an `i128`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:296:18 @@ -1274,7 +1274,7 @@ LL | x_i128 > x_u16; | ^^^^^ | | | expected `i128`, found `u16` - | help: you can convert a `u16` to `i128`: `x_u16.into()` + | help: you can convert a `u16` to an `i128`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:298:18 @@ -1283,7 +1283,7 @@ LL | x_i128 > x_u32; | ^^^^^ | | | expected `i128`, found `u32` - | help: you can convert a `u32` to `i128`: `x_u32.into()` + | help: you can convert a `u32` to an `i128`: `x_u32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:300:18 @@ -1292,7 +1292,7 @@ LL | x_i128 > x_u64; | ^^^^^ | | | expected `i128`, found `u64` - | help: you can convert a `u64` to `i128`: `x_u64.into()` + | help: you can convert a `u64` to an `i128`: `x_u64.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:302:18 @@ -1300,7 +1300,7 @@ error[E0308]: mismatched types LL | x_i128 > x_u128; | ^^^^^^ expected `i128`, found `u128` | -help: you can convert a `u128` to `i128` and panic if the converted value wouldn't fit +help: you can convert a `u128` to an `i128` and panic if the converted value wouldn't fit | LL | x_i128 > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1311,7 +1311,7 @@ error[E0308]: mismatched types LL | x_i128 > x_usize; | ^^^^^^^ expected `i128`, found `usize` | -help: you can convert a `usize` to `i128` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i128` and panic if the converted value wouldn't fit | LL | x_i128 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1323,7 +1323,7 @@ LL | x_isize > x_u8; | ^^^^ | | | expected `isize`, found `u8` - | help: you can convert a `u8` to `isize`: `x_u8.into()` + | help: you can convert a `u8` to an `isize`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:309:19 @@ -1331,7 +1331,7 @@ error[E0308]: mismatched types LL | x_isize > x_u16; | ^^^^^ expected `isize`, found `u16` | -help: you can convert a `u16` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `u16` to an `isize` and panic if the converted value wouldn't fit | LL | x_isize > x_u16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1342,7 +1342,7 @@ error[E0308]: mismatched types LL | x_isize > x_u32; | ^^^^^ expected `isize`, found `u32` | -help: you can convert a `u32` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `isize` and panic if the converted value wouldn't fit | LL | x_isize > x_u32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1353,7 +1353,7 @@ error[E0308]: mismatched types LL | x_isize > x_u64; | ^^^^^ expected `isize`, found `u64` | -help: you can convert a `u64` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `isize` and panic if the converted value wouldn't fit | LL | x_isize > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1364,7 +1364,7 @@ error[E0308]: mismatched types LL | x_isize > x_u128; | ^^^^^^ expected `isize`, found `u128` | -help: you can convert a `u128` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `u128` to an `isize` and panic if the converted value wouldn't fit | LL | x_isize > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1375,7 +1375,7 @@ error[E0308]: mismatched types LL | x_isize > x_usize; | ^^^^^^^ expected `isize`, found `usize` | -help: you can convert a `usize` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `isize` and panic if the converted value wouldn't fit | LL | x_isize > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/numeric/numeric-cast.stderr b/src/test/ui/numeric/numeric-cast.stderr index 3c78ea9e08a..ea2f87232ad 100644 --- a/src/test/ui/numeric/numeric-cast.stderr +++ b/src/test/ui/numeric/numeric-cast.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `usize`, found `u64` | -help: you can convert a `u64` to `usize` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `usize` and panic if the converted value wouldn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `usize`, found `u32` | -help: you can convert a `u32` to `usize` and panic if the converted value wouldn't fit +help: you can convert a `u32` to a `usize` and panic if the converted value wouldn't fit | LL | foo::(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | foo::(x_u16); | ^^^^^ | | | expected `usize`, found `u16` - | help: you can convert a `u16` to `usize`: `x_u16.into()` + | help: you can convert a `u16` to a `usize`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:29:18 @@ -36,7 +36,7 @@ LL | foo::(x_u8); | ^^^^ | | | expected `usize`, found `u8` - | help: you can convert a `u8` to `usize`: `x_u8.into()` + | help: you can convert a `u8` to a `usize`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:31:18 @@ -44,7 +44,7 @@ error[E0308]: mismatched types LL | foo::(x_isize); | ^^^^^^^ expected `usize`, found `isize` | -help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `usize` and panic if the converted value wouldn't fit | LL | foo::(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -55,7 +55,7 @@ error[E0308]: mismatched types LL | foo::(x_i64); | ^^^^^ expected `usize`, found `i64` | -help: you can convert an `i64` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `usize` and panic if the converted value wouldn't fit | LL | foo::(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -66,7 +66,7 @@ error[E0308]: mismatched types LL | foo::(x_i32); | ^^^^^ expected `usize`, found `i32` | -help: you can convert an `i32` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `usize` and panic if the converted value wouldn't fit | LL | foo::(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -77,7 +77,7 @@ error[E0308]: mismatched types LL | foo::(x_i16); | ^^^^^ expected `usize`, found `i16` | -help: you can convert an `i16` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `usize` and panic if the converted value wouldn't fit | LL | foo::(x_i16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ error[E0308]: mismatched types LL | foo::(x_i8); | ^^^^ expected `usize`, found `i8` | -help: you can convert an `i8` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `usize` and panic if the converted value wouldn't fit | LL | foo::(x_i8.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -99,7 +99,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `isize`, found `usize` | -help: you can convert a `usize` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `isize` and panic if the converted value wouldn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -110,7 +110,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `isize`, found `u64` | -help: you can convert a `u64` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `isize` and panic if the converted value wouldn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `isize`, found `u32` | -help: you can convert a `u32` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `isize` and panic if the converted value wouldn't fit | LL | foo::(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,7 +132,7 @@ error[E0308]: mismatched types LL | foo::(x_u16); | ^^^^^ expected `isize`, found `u16` | -help: you can convert a `u16` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `u16` to an `isize` and panic if the converted value wouldn't fit | LL | foo::(x_u16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -144,7 +144,7 @@ LL | foo::(x_u8); | ^^^^ | | | expected `isize`, found `u8` - | help: you can convert a `u8` to `isize`: `x_u8.into()` + | help: you can convert a `u8` to an `isize`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:55:18 @@ -152,7 +152,7 @@ error[E0308]: mismatched types LL | foo::(x_i64); | ^^^^^ expected `isize`, found `i64` | -help: you can convert an `i64` to `isize` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `isize` and panic if the converted value wouldn't fit | LL | foo::(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -163,7 +163,7 @@ error[E0308]: mismatched types LL | foo::(x_i32); | ^^^^^ expected `isize`, found `i32` | -help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `isize` and panic if the converted value wouldn't fit | LL | foo::(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -175,7 +175,7 @@ LL | foo::(x_i16); | ^^^^^ | | | expected `isize`, found `i16` - | help: you can convert an `i16` to `isize`: `x_i16.into()` + | help: you can convert an `i16` to an `isize`: `x_i16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:61:18 @@ -184,7 +184,7 @@ LL | foo::(x_i8); | ^^^^ | | | expected `isize`, found `i8` - | help: you can convert an `i8` to `isize`: `x_i8.into()` + | help: you can convert an `i8` to an `isize`: `x_i8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:66:16 @@ -192,7 +192,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `u64`, found `usize` | -help: you can convert a `usize` to `u64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u64` and panic if the converted value wouldn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -204,7 +204,7 @@ LL | foo::(x_u32); | ^^^^^ | | | expected `u64`, found `u32` - | help: you can convert a `u32` to `u64`: `x_u32.into()` + | help: you can convert a `u32` to a `u64`: `x_u32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:71:16 @@ -213,7 +213,7 @@ LL | foo::(x_u16); | ^^^^^ | | | expected `u64`, found `u16` - | help: you can convert a `u16` to `u64`: `x_u16.into()` + | help: you can convert a `u16` to a `u64`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:73:16 @@ -222,7 +222,7 @@ LL | foo::(x_u8); | ^^^^ | | | expected `u64`, found `u8` - | help: you can convert a `u8` to `u64`: `x_u8.into()` + | help: you can convert a `u8` to a `u64`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:75:16 @@ -230,7 +230,7 @@ error[E0308]: mismatched types LL | foo::(x_isize); | ^^^^^^^ expected `u64`, found `isize` | -help: you can convert an `isize` to `u64` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u64` and panic if the converted value wouldn't fit | LL | foo::(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,7 +241,7 @@ error[E0308]: mismatched types LL | foo::(x_i64); | ^^^^^ expected `u64`, found `i64` | -help: you can convert an `i64` to `u64` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `u64` and panic if the converted value wouldn't fit | LL | foo::(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -252,7 +252,7 @@ error[E0308]: mismatched types LL | foo::(x_i32); | ^^^^^ expected `u64`, found `i32` | -help: you can convert an `i32` to `u64` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u64` and panic if the converted value wouldn't fit | LL | foo::(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -263,7 +263,7 @@ error[E0308]: mismatched types LL | foo::(x_i16); | ^^^^^ expected `u64`, found `i16` | -help: you can convert an `i16` to `u64` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u64` and panic if the converted value wouldn't fit | LL | foo::(x_i16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -274,7 +274,7 @@ error[E0308]: mismatched types LL | foo::(x_i8); | ^^^^ expected `u64`, found `i8` | -help: you can convert an `i8` to `u64` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u64` and panic if the converted value wouldn't fit | LL | foo::(x_i8.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -285,7 +285,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `i64`, found `usize` | -help: you can convert a `usize` to `i64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i64` and panic if the converted value wouldn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -296,7 +296,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `i64`, found `u64` | -help: you can convert a `u64` to `i64` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i64` and panic if the converted value wouldn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -308,7 +308,7 @@ LL | foo::(x_u32); | ^^^^^ | | | expected `i64`, found `u32` - | help: you can convert a `u32` to `i64`: `x_u32.into()` + | help: you can convert a `u32` to an `i64`: `x_u32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:94:16 @@ -317,7 +317,7 @@ LL | foo::(x_u16); | ^^^^^ | | | expected `i64`, found `u16` - | help: you can convert a `u16` to `i64`: `x_u16.into()` + | help: you can convert a `u16` to an `i64`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:96:16 @@ -326,7 +326,7 @@ LL | foo::(x_u8); | ^^^^ | | | expected `i64`, found `u8` - | help: you can convert a `u8` to `i64`: `x_u8.into()` + | help: you can convert a `u8` to an `i64`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:98:16 @@ -334,7 +334,7 @@ error[E0308]: mismatched types LL | foo::(x_isize); | ^^^^^^^ expected `i64`, found `isize` | -help: you can convert an `isize` to `i64` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i64` and panic if the converted value wouldn't fit | LL | foo::(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -346,7 +346,7 @@ LL | foo::(x_i32); | ^^^^^ | | | expected `i64`, found `i32` - | help: you can convert an `i32` to `i64`: `x_i32.into()` + | help: you can convert an `i32` to an `i64`: `x_i32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:103:16 @@ -355,7 +355,7 @@ LL | foo::(x_i16); | ^^^^^ | | | expected `i64`, found `i16` - | help: you can convert an `i16` to `i64`: `x_i16.into()` + | help: you can convert an `i16` to an `i64`: `x_i16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:105:16 @@ -364,7 +364,7 @@ LL | foo::(x_i8); | ^^^^ | | | expected `i64`, found `i8` - | help: you can convert an `i8` to `i64`: `x_i8.into()` + | help: you can convert an `i8` to an `i64`: `x_i8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:110:16 @@ -372,7 +372,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `u32`, found `usize` | -help: you can convert a `usize` to `u32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u32` and panic if the converted value wouldn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -383,7 +383,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `u32`, found `u64` | -help: you can convert a `u64` to `u32` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `u32` and panic if the converted value wouldn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -395,7 +395,7 @@ LL | foo::(x_u16); | ^^^^^ | | | expected `u32`, found `u16` - | help: you can convert a `u16` to `u32`: `x_u16.into()` + | help: you can convert a `u16` to a `u32`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:117:16 @@ -404,7 +404,7 @@ LL | foo::(x_u8); | ^^^^ | | | expected `u32`, found `u8` - | help: you can convert a `u8` to `u32`: `x_u8.into()` + | help: you can convert a `u8` to a `u32`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:119:16 @@ -412,7 +412,7 @@ error[E0308]: mismatched types LL | foo::(x_isize); | ^^^^^^^ expected `u32`, found `isize` | -help: you can convert an `isize` to `u32` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u32` and panic if the converted value wouldn't fit | LL | foo::(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -423,7 +423,7 @@ error[E0308]: mismatched types LL | foo::(x_i64); | ^^^^^ expected `u32`, found `i64` | -help: you can convert an `i64` to `u32` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `u32` and panic if the converted value wouldn't fit | LL | foo::(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -434,7 +434,7 @@ error[E0308]: mismatched types LL | foo::(x_i32); | ^^^^^ expected `u32`, found `i32` | -help: you can convert an `i32` to `u32` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u32` and panic if the converted value wouldn't fit | LL | foo::(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -445,7 +445,7 @@ error[E0308]: mismatched types LL | foo::(x_i16); | ^^^^^ expected `u32`, found `i16` | -help: you can convert an `i16` to `u32` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u32` and panic if the converted value wouldn't fit | LL | foo::(x_i16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -456,7 +456,7 @@ error[E0308]: mismatched types LL | foo::(x_i8); | ^^^^ expected `u32`, found `i8` | -help: you can convert an `i8` to `u32` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u32` and panic if the converted value wouldn't fit | LL | foo::(x_i8.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -467,7 +467,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `i32`, found `usize` | -help: you can convert a `usize` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i32` and panic if the converted value wouldn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -478,7 +478,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `i32`, found `u64` | -help: you can convert a `u64` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i32` and panic if the converted value wouldn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -489,7 +489,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `i32`, found `u32` | -help: you can convert a `u32` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `i32` and panic if the converted value wouldn't fit | LL | foo::(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -501,7 +501,7 @@ LL | foo::(x_u16); | ^^^^^ | | | expected `i32`, found `u16` - | help: you can convert a `u16` to `i32`: `x_u16.into()` + | help: you can convert a `u16` to an `i32`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:140:16 @@ -510,7 +510,7 @@ LL | foo::(x_u8); | ^^^^ | | | expected `i32`, found `u8` - | help: you can convert a `u8` to `i32`: `x_u8.into()` + | help: you can convert a `u8` to an `i32`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:142:16 @@ -518,7 +518,7 @@ error[E0308]: mismatched types LL | foo::(x_isize); | ^^^^^^^ expected `i32`, found `isize` | -help: you can convert an `isize` to `i32` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i32` and panic if the converted value wouldn't fit | LL | foo::(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -529,7 +529,7 @@ error[E0308]: mismatched types LL | foo::(x_i64); | ^^^^^ expected `i32`, found `i64` | -help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i32` and panic if the converted value wouldn't fit | LL | foo::(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -541,7 +541,7 @@ LL | foo::(x_i16); | ^^^^^ | | | expected `i32`, found `i16` - | help: you can convert an `i16` to `i32`: `x_i16.into()` + | help: you can convert an `i16` to an `i32`: `x_i16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:149:16 @@ -550,7 +550,7 @@ LL | foo::(x_i8); | ^^^^ | | | expected `i32`, found `i8` - | help: you can convert an `i8` to `i32`: `x_i8.into()` + | help: you can convert an `i8` to an `i32`: `x_i8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:154:16 @@ -558,7 +558,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `u16`, found `usize` | -help: you can convert a `usize` to `u16` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u16` and panic if the converted value wouldn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -569,7 +569,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `u16`, found `u64` | -help: you can convert a `u64` to `u16` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `u16` and panic if the converted value wouldn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -580,7 +580,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `u16`, found `u32` | -help: you can convert a `u32` to `u16` and panic if the converted value wouldn't fit +help: you can convert a `u32` to a `u16` and panic if the converted value wouldn't fit | LL | foo::(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -592,7 +592,7 @@ LL | foo::(x_u8); | ^^^^ | | | expected `u16`, found `u8` - | help: you can convert a `u8` to `u16`: `x_u8.into()` + | help: you can convert a `u8` to a `u16`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:163:16 @@ -600,7 +600,7 @@ error[E0308]: mismatched types LL | foo::(x_isize); | ^^^^^^^ expected `u16`, found `isize` | -help: you can convert an `isize` to `u16` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u16` and panic if the converted value wouldn't fit | LL | foo::(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -611,7 +611,7 @@ error[E0308]: mismatched types LL | foo::(x_i64); | ^^^^^ expected `u16`, found `i64` | -help: you can convert an `i64` to `u16` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `u16` and panic if the converted value wouldn't fit | LL | foo::(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -622,7 +622,7 @@ error[E0308]: mismatched types LL | foo::(x_i32); | ^^^^^ expected `u16`, found `i32` | -help: you can convert an `i32` to `u16` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u16` and panic if the converted value wouldn't fit | LL | foo::(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -633,7 +633,7 @@ error[E0308]: mismatched types LL | foo::(x_i16); | ^^^^^ expected `u16`, found `i16` | -help: you can convert an `i16` to `u16` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u16` and panic if the converted value wouldn't fit | LL | foo::(x_i16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -644,7 +644,7 @@ error[E0308]: mismatched types LL | foo::(x_i8); | ^^^^ expected `u16`, found `i8` | -help: you can convert an `i8` to `u16` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u16` and panic if the converted value wouldn't fit | LL | foo::(x_i8.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -655,7 +655,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `i16`, found `usize` | -help: you can convert a `usize` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i16` and panic if the converted value wouldn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -666,7 +666,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `i16`, found `u64` | -help: you can convert a `u64` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i16` and panic if the converted value wouldn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -677,7 +677,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `i16`, found `u32` | -help: you can convert a `u32` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `i16` and panic if the converted value wouldn't fit | LL | foo::(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -688,7 +688,7 @@ error[E0308]: mismatched types LL | foo::(x_u16); | ^^^^^ expected `i16`, found `u16` | -help: you can convert a `u16` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `u16` to an `i16` and panic if the converted value wouldn't fit | LL | foo::(x_u16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -700,7 +700,7 @@ LL | foo::(x_u8); | ^^^^ | | | expected `i16`, found `u8` - | help: you can convert a `u8` to `i16`: `x_u8.into()` + | help: you can convert a `u8` to an `i16`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:186:16 @@ -708,7 +708,7 @@ error[E0308]: mismatched types LL | foo::(x_isize); | ^^^^^^^ expected `i16`, found `isize` | -help: you can convert an `isize` to `i16` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i16` and panic if the converted value wouldn't fit | LL | foo::(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -719,7 +719,7 @@ error[E0308]: mismatched types LL | foo::(x_i64); | ^^^^^ expected `i16`, found `i64` | -help: you can convert an `i64` to `i16` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i16` and panic if the converted value wouldn't fit | LL | foo::(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -730,7 +730,7 @@ error[E0308]: mismatched types LL | foo::(x_i32); | ^^^^^ expected `i16`, found `i32` | -help: you can convert an `i32` to `i16` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `i16` and panic if the converted value wouldn't fit | LL | foo::(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -742,7 +742,7 @@ LL | foo::(x_i8); | ^^^^ | | | expected `i16`, found `i8` - | help: you can convert an `i8` to `i16`: `x_i8.into()` + | help: you can convert an `i8` to an `i16`: `x_i8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:198:15 @@ -750,7 +750,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `u8`, found `usize` | -help: you can convert a `usize` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u8` and panic if the converted value wouldn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -761,7 +761,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `u8`, found `u64` | -help: you can convert a `u64` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `u8` and panic if the converted value wouldn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -772,7 +772,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `u8`, found `u32` | -help: you can convert a `u32` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `u32` to a `u8` and panic if the converted value wouldn't fit | LL | foo::(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -783,7 +783,7 @@ error[E0308]: mismatched types LL | foo::(x_u16); | ^^^^^ expected `u8`, found `u16` | -help: you can convert a `u16` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `u16` to a `u8` and panic if the converted value wouldn't fit | LL | foo::(x_u16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -794,7 +794,7 @@ error[E0308]: mismatched types LL | foo::(x_isize); | ^^^^^^^ expected `u8`, found `isize` | -help: you can convert an `isize` to `u8` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u8` and panic if the converted value wouldn't fit | LL | foo::(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -805,7 +805,7 @@ error[E0308]: mismatched types LL | foo::(x_i64); | ^^^^^ expected `u8`, found `i64` | -help: you can convert an `i64` to `u8` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `u8` and panic if the converted value wouldn't fit | LL | foo::(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -816,7 +816,7 @@ error[E0308]: mismatched types LL | foo::(x_i32); | ^^^^^ expected `u8`, found `i32` | -help: you can convert an `i32` to `u8` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u8` and panic if the converted value wouldn't fit | LL | foo::(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -827,7 +827,7 @@ error[E0308]: mismatched types LL | foo::(x_i16); | ^^^^^ expected `u8`, found `i16` | -help: you can convert an `i16` to `u8` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u8` and panic if the converted value wouldn't fit | LL | foo::(x_i16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -838,7 +838,7 @@ error[E0308]: mismatched types LL | foo::(x_i8); | ^^^^ expected `u8`, found `i8` | -help: you can convert an `i8` to `u8` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u8` and panic if the converted value wouldn't fit | LL | foo::(x_i8.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -849,7 +849,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `i8`, found `usize` | -help: you can convert a `usize` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i8` and panic if the converted value wouldn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -860,7 +860,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `i8`, found `u64` | -help: you can convert a `u64` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i8` and panic if the converted value wouldn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -871,7 +871,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `i8`, found `u32` | -help: you can convert a `u32` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `i8` and panic if the converted value wouldn't fit | LL | foo::(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -882,7 +882,7 @@ error[E0308]: mismatched types LL | foo::(x_u16); | ^^^^^ expected `i8`, found `u16` | -help: you can convert a `u16` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u16` to an `i8` and panic if the converted value wouldn't fit | LL | foo::(x_u16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -893,7 +893,7 @@ error[E0308]: mismatched types LL | foo::(x_u8); | ^^^^ expected `i8`, found `u8` | -help: you can convert a `u8` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u8` to an `i8` and panic if the converted value wouldn't fit | LL | foo::(x_u8.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -904,7 +904,7 @@ error[E0308]: mismatched types LL | foo::(x_isize); | ^^^^^^^ expected `i8`, found `isize` | -help: you can convert an `isize` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i8` and panic if the converted value wouldn't fit | LL | foo::(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -915,7 +915,7 @@ error[E0308]: mismatched types LL | foo::(x_i64); | ^^^^^ expected `i8`, found `i64` | -help: you can convert an `i64` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i8` and panic if the converted value wouldn't fit | LL | foo::(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -926,7 +926,7 @@ error[E0308]: mismatched types LL | foo::(x_i32); | ^^^^^ expected `i8`, found `i32` | -help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `i8` and panic if the converted value wouldn't fit | LL | foo::(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -937,7 +937,7 @@ error[E0308]: mismatched types LL | foo::(x_i16); | ^^^^^ expected `i8`, found `i16` | -help: you can convert an `i16` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `i16` to an `i8` and panic if the converted value wouldn't fit | LL | foo::(x_i16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -948,7 +948,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `f64`, found `usize` | -help: you can cast a `usize to `f64`, producing the floating point representation of the integer, +help: you can cast a `usize` to an `f64`, producing the floating point representation of the integer, | rounded if necessary LL | foo::(x_usize as f64); | ^^^^^^^^^^^^^^ @@ -959,7 +959,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `f64`, found `u64` | -help: you can cast a `u64 to `f64`, producing the floating point representation of the integer, +help: you can cast a `u64` to an `f64`, producing the floating point representation of the integer, | rounded if necessary LL | foo::(x_u64 as f64); | ^^^^^^^^^^^^ @@ -970,7 +970,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `f64`, found `u32` | -help: you can convert a `u32` to `f64`, producing the floating point representation of the integer +help: you can convert a `u32` to an `f64`, producing the floating point representation of the integer | LL | foo::(x_u32.into()); | ^^^^^^^^^^^^ @@ -981,7 +981,7 @@ error[E0308]: mismatched types LL | foo::(x_u16); | ^^^^^ expected `f64`, found `u16` | -help: you can convert a `u16` to `f64`, producing the floating point representation of the integer +help: you can convert a `u16` to an `f64`, producing the floating point representation of the integer | LL | foo::(x_u16.into()); | ^^^^^^^^^^^^ @@ -992,7 +992,7 @@ error[E0308]: mismatched types LL | foo::(x_u8); | ^^^^ expected `f64`, found `u8` | -help: you can convert a `u8` to `f64`, producing the floating point representation of the integer +help: you can convert a `u8` to an `f64`, producing the floating point representation of the integer | LL | foo::(x_u8.into()); | ^^^^^^^^^^^ @@ -1003,7 +1003,7 @@ error[E0308]: mismatched types LL | foo::(x_isize); | ^^^^^^^ expected `f64`, found `isize` | -help: you can convert an `isize` to `f64`, producing the floating point representation of the integer, rounded if necessary +help: you can convert an `isize` to an `f64`, producing the floating point representation of the integer, rounded if necessary | LL | foo::(x_isize as f64); | ^^^^^^^^^^^^^^ @@ -1014,7 +1014,7 @@ error[E0308]: mismatched types LL | foo::(x_i64); | ^^^^^ expected `f64`, found `i64` | -help: you can convert an `i64` to `f64`, producing the floating point representation of the integer, rounded if necessary +help: you can convert an `i64` to an `f64`, producing the floating point representation of the integer, rounded if necessary | LL | foo::(x_i64 as f64); | ^^^^^^^^^^^^ @@ -1025,7 +1025,7 @@ error[E0308]: mismatched types LL | foo::(x_i32); | ^^^^^ expected `f64`, found `i32` | -help: you can convert an `i32` to `f64`, producing the floating point representation of the integer +help: you can convert an `i32` to an `f64`, producing the floating point representation of the integer | LL | foo::(x_i32.into()); | ^^^^^^^^^^^^ @@ -1036,7 +1036,7 @@ error[E0308]: mismatched types LL | foo::(x_i16); | ^^^^^ expected `f64`, found `i16` | -help: you can convert an `i16` to `f64`, producing the floating point representation of the integer +help: you can convert an `i16` to an `f64`, producing the floating point representation of the integer | LL | foo::(x_i16.into()); | ^^^^^^^^^^^^ @@ -1047,7 +1047,7 @@ error[E0308]: mismatched types LL | foo::(x_i8); | ^^^^ expected `f64`, found `i8` | -help: you can convert an `i8` to `f64`, producing the floating point representation of the integer +help: you can convert an `i8` to an `f64`, producing the floating point representation of the integer | LL | foo::(x_i8.into()); | ^^^^^^^^^^^ @@ -1059,7 +1059,7 @@ LL | foo::(x_f32); | ^^^^^ | | | expected `f64`, found `f32` - | help: you can convert an `f32` to `f64`: `x_f32.into()` + | help: you can convert an `f32` to an `f64`: `x_f32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:266:16 @@ -1067,7 +1067,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `f32`, found `usize` | -help: you can cast a `usize to `f32`, producing the floating point representation of the integer, +help: you can cast a `usize` to an `f32`, producing the floating point representation of the integer, | rounded if necessary LL | foo::(x_usize as f32); | ^^^^^^^^^^^^^^ @@ -1078,7 +1078,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `f32`, found `u64` | -help: you can cast a `u64 to `f32`, producing the floating point representation of the integer, +help: you can cast a `u64` to an `f32`, producing the floating point representation of the integer, | rounded if necessary LL | foo::(x_u64 as f32); | ^^^^^^^^^^^^ @@ -1089,7 +1089,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `f32`, found `u32` | -help: you can cast a `u32 to `f32`, producing the floating point representation of the integer, +help: you can cast a `u32` to an `f32`, producing the floating point representation of the integer, | rounded if necessary LL | foo::(x_u32 as f32); | ^^^^^^^^^^^^ @@ -1100,7 +1100,7 @@ error[E0308]: mismatched types LL | foo::(x_u16); | ^^^^^ expected `f32`, found `u16` | -help: you can convert a `u16` to `f32`, producing the floating point representation of the integer +help: you can convert a `u16` to an `f32`, producing the floating point representation of the integer | LL | foo::(x_u16.into()); | ^^^^^^^^^^^^ @@ -1111,7 +1111,7 @@ error[E0308]: mismatched types LL | foo::(x_u8); | ^^^^ expected `f32`, found `u8` | -help: you can convert a `u8` to `f32`, producing the floating point representation of the integer +help: you can convert a `u8` to an `f32`, producing the floating point representation of the integer | LL | foo::(x_u8.into()); | ^^^^^^^^^^^ @@ -1122,7 +1122,7 @@ error[E0308]: mismatched types LL | foo::(x_isize); | ^^^^^^^ expected `f32`, found `isize` | -help: you can convert an `isize` to `f32`, producing the floating point representation of the integer, rounded if necessary +help: you can convert an `isize` to an `f32`, producing the floating point representation of the integer, rounded if necessary | LL | foo::(x_isize as f32); | ^^^^^^^^^^^^^^ @@ -1133,7 +1133,7 @@ error[E0308]: mismatched types LL | foo::(x_i64); | ^^^^^ expected `f32`, found `i64` | -help: you can convert an `i64` to `f32`, producing the floating point representation of the integer, rounded if necessary +help: you can convert an `i64` to an `f32`, producing the floating point representation of the integer, rounded if necessary | LL | foo::(x_i64 as f32); | ^^^^^^^^^^^^ @@ -1144,7 +1144,7 @@ error[E0308]: mismatched types LL | foo::(x_i32); | ^^^^^ expected `f32`, found `i32` | -help: you can convert an `i32` to `f32`, producing the floating point representation of the integer, rounded if necessary +help: you can convert an `i32` to an `f32`, producing the floating point representation of the integer, rounded if necessary | LL | foo::(x_i32 as f32); | ^^^^^^^^^^^^ @@ -1155,7 +1155,7 @@ error[E0308]: mismatched types LL | foo::(x_i16); | ^^^^^ expected `f32`, found `i16` | -help: you can convert an `i16` to `f32`, producing the floating point representation of the integer +help: you can convert an `i16` to an `f32`, producing the floating point representation of the integer | LL | foo::(x_i16.into()); | ^^^^^^^^^^^^ @@ -1166,7 +1166,7 @@ error[E0308]: mismatched types LL | foo::(x_i8); | ^^^^ expected `f32`, found `i8` | -help: you can convert an `i8` to `f32`, producing the floating point representation of the integer +help: you can convert an `i8` to an `f32`, producing the floating point representation of the integer | LL | foo::(x_i8.into()); | ^^^^^^^^^^^ @@ -1178,7 +1178,7 @@ LL | foo::(x_u8 as u16); | ^^^^^^^^^^^ | | | expected `u32`, found `u16` - | help: you can convert a `u16` to `u32`: `(x_u8 as u16).into()` + | help: you can convert a `u16` to a `u32`: `(x_u8 as u16).into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:291:16 @@ -1187,7 +1187,7 @@ LL | foo::(-x_i8); | ^^^^^ | | | expected `i32`, found `i8` - | help: you can convert an `i8` to `i32`: `(-x_i8).into()` + | help: you can convert an `i8` to an `i32`: `(-x_i8).into()` error: aborting due to 113 previous errors diff --git a/src/test/ui/numeric/numeric-suffix.stderr b/src/test/ui/numeric/numeric-suffix.stderr index 890686f7737..a62956ee8da 100644 --- a/src/test/ui/numeric/numeric-suffix.stderr +++ b/src/test/ui/numeric/numeric-suffix.stderr @@ -1236,7 +1236,7 @@ error[E0308]: mismatched types LL | foo::(42_u32); | ^^^^^^ expected `f64`, found `u32` | -help: you can convert a `u32` to `f64`, producing the floating point representation of the integer +help: you can convert a `u32` to an `f64`, producing the floating point representation of the integer | LL | foo::(42_u32.into()); | ^^^^^^^^^^^^^ @@ -1247,7 +1247,7 @@ error[E0308]: mismatched types LL | foo::(42_u16); | ^^^^^^ expected `f64`, found `u16` | -help: you can convert a `u16` to `f64`, producing the floating point representation of the integer +help: you can convert a `u16` to an `f64`, producing the floating point representation of the integer | LL | foo::(42_u16.into()); | ^^^^^^^^^^^^^ @@ -1258,7 +1258,7 @@ error[E0308]: mismatched types LL | foo::(42_u8); | ^^^^^ expected `f64`, found `u8` | -help: you can convert a `u8` to `f64`, producing the floating point representation of the integer +help: you can convert a `u8` to an `f64`, producing the floating point representation of the integer | LL | foo::(42_u8.into()); | ^^^^^^^^^^^^ @@ -1291,7 +1291,7 @@ error[E0308]: mismatched types LL | foo::(42_i32); | ^^^^^^ expected `f64`, found `i32` | -help: you can convert an `i32` to `f64`, producing the floating point representation of the integer +help: you can convert an `i32` to an `f64`, producing the floating point representation of the integer | LL | foo::(42_i32.into()); | ^^^^^^^^^^^^^ @@ -1302,7 +1302,7 @@ error[E0308]: mismatched types LL | foo::(42_i16); | ^^^^^^ expected `f64`, found `i16` | -help: you can convert an `i16` to `f64`, producing the floating point representation of the integer +help: you can convert an `i16` to an `f64`, producing the floating point representation of the integer | LL | foo::(42_i16.into()); | ^^^^^^^^^^^^^ @@ -1313,7 +1313,7 @@ error[E0308]: mismatched types LL | foo::(42_i8); | ^^^^^ expected `f64`, found `i8` | -help: you can convert an `i8` to `f64`, producing the floating point representation of the integer +help: you can convert an `i8` to an `f64`, producing the floating point representation of the integer | LL | foo::(42_i8.into()); | ^^^^^^^^^^^^ @@ -1368,7 +1368,7 @@ error[E0308]: mismatched types LL | foo::(42_u16); | ^^^^^^ expected `f32`, found `u16` | -help: you can convert a `u16` to `f32`, producing the floating point representation of the integer +help: you can convert a `u16` to an `f32`, producing the floating point representation of the integer | LL | foo::(42_u16.into()); | ^^^^^^^^^^^^^ @@ -1379,7 +1379,7 @@ error[E0308]: mismatched types LL | foo::(42_u8); | ^^^^^ expected `f32`, found `u8` | -help: you can convert a `u8` to `f32`, producing the floating point representation of the integer +help: you can convert a `u8` to an `f32`, producing the floating point representation of the integer | LL | foo::(42_u8.into()); | ^^^^^^^^^^^^ @@ -1423,7 +1423,7 @@ error[E0308]: mismatched types LL | foo::(42_i16); | ^^^^^^ expected `f32`, found `i16` | -help: you can convert an `i16` to `f32`, producing the floating point representation of the integer +help: you can convert an `i16` to an `f32`, producing the floating point representation of the integer | LL | foo::(42_i16.into()); | ^^^^^^^^^^^^^ @@ -1434,7 +1434,7 @@ error[E0308]: mismatched types LL | foo::(42_i8); | ^^^^^ expected `f32`, found `i8` | -help: you can convert an `i8` to `f32`, producing the floating point representation of the integer +help: you can convert an `i8` to an `f32`, producing the floating point representation of the integer | LL | foo::(42_i8.into()); | ^^^^^^^^^^^^ @@ -1457,7 +1457,7 @@ LL | foo::(42_u8 as u16); | ^^^^^^^^^^^^ | | | expected `u32`, found `u16` - | help: you can convert a `u16` to `u32`: `(42_u8 as u16).into()` + | help: you can convert a `u16` to a `u32`: `(42_u8 as u16).into()` error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:296:16 @@ -1466,7 +1466,7 @@ LL | foo::(-42_i8); | ^^^^^^ | | | expected `i32`, found `i8` - | help: you can convert an `i8` to `i32`: `(-42_i8).into()` + | help: you can convert an `i8` to an `i32`: `(-42_i8).into()` error: aborting due to 134 previous errors diff --git a/src/test/ui/proc-macro/span-preservation.stderr b/src/test/ui/proc-macro/span-preservation.stderr index 70e992a4f70..5df0ac417f8 100644 --- a/src/test/ui/proc-macro/span-preservation.stderr +++ b/src/test/ui/proc-macro/span-preservation.stderr @@ -15,7 +15,7 @@ LL | match x { LL | Some(x) => { return x }, | ^ expected `usize`, found `isize` | -help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `usize` and panic if the converted value wouldn't fit | LL | Some(x) => { return x.try_into().unwrap() }, | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/shift-various-bad-types.stderr b/src/test/ui/shift-various-bad-types.stderr index c27bdf09a8d..ceda6402148 100644 --- a/src/test/ui/shift-various-bad-types.stderr +++ b/src/test/ui/shift-various-bad-types.stderr @@ -30,7 +30,7 @@ LL | let _: i32 = 22_i64 >> 1_i32; | | | expected due to this | -help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i32` and panic if the converted value wouldn't fit | LL | let _: i32 = (22_i64 >> 1_i32).try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr index f717cc7addb..b391cd4beb4 100644 --- a/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr +++ b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr @@ -5,7 +5,7 @@ LL | let _ = RGB { r, g, c }; | ^ | | | expected `f64`, found `f32` - | help: you can convert an `f32` to `f64`: `r: r.into()` + | help: you can convert an `f32` to an `f64`: `r: r.into()` error[E0308]: mismatched types --> $DIR/type-mismatch-struct-field-shorthand-2.rs:5:22 @@ -14,7 +14,7 @@ LL | let _ = RGB { r, g, c }; | ^ | | | expected `f64`, found `f32` - | help: you can convert an `f32` to `f64`: `g: g.into()` + | help: you can convert an `f32` to an `f64`: `g: g.into()` error[E0560]: struct `RGB` has no field named `c` --> $DIR/type-mismatch-struct-field-shorthand-2.rs:5:25 diff --git a/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr index 7521c253545..61ea852a8c4 100644 --- a/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr +++ b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr @@ -5,7 +5,7 @@ LL | let _ = RGB { r, g, b }; | ^ | | | expected `f64`, found `f32` - | help: you can convert an `f32` to `f64`: `r: r.into()` + | help: you can convert an `f32` to an `f64`: `r: r.into()` error[E0308]: mismatched types --> $DIR/type-mismatch-struct-field-shorthand.rs:8:22 @@ -14,7 +14,7 @@ LL | let _ = RGB { r, g, b }; | ^ | | | expected `f64`, found `f32` - | help: you can convert an `f32` to `f64`: `g: g.into()` + | help: you can convert an `f32` to an `f64`: `g: g.into()` error[E0308]: mismatched types --> $DIR/type-mismatch-struct-field-shorthand.rs:8:25 @@ -23,7 +23,7 @@ LL | let _ = RGB { r, g, b }; | ^ | | | expected `f64`, found `f32` - | help: you can convert an `f32` to `f64`: `b: b.into()` + | help: you can convert an `f32` to an `f64`: `b: b.into()` error: aborting due to 3 previous errors diff --git a/src/test/ui/tail-typeck.stderr b/src/test/ui/tail-typeck.stderr index 4dc969e76ed..24049c2c587 100644 --- a/src/test/ui/tail-typeck.stderr +++ b/src/test/ui/tail-typeck.stderr @@ -6,7 +6,7 @@ LL | fn f() -> isize { return g(); } | | | expected `isize` because of return type | -help: you can convert a `usize` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `isize` and panic if the converted value wouldn't fit | LL | fn f() -> isize { return g().try_into().unwrap(); } | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr index 08c79519dfe..1816c5245f7 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr @@ -7,7 +7,7 @@ LL | fn global_bound_is_hidden() -> u8 LL | B::get_x() | ^^^^^^^^^^ expected `u8`, found `i32` | -help: you can convert an `i32` to `u8` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u8` and panic if the converted value wouldn't fit | LL | B::get_x().try_into().unwrap() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/tutorial-suffix-inference-test.stderr b/src/test/ui/tutorial-suffix-inference-test.stderr index 4f36357598d..5cea9f9fea8 100644 --- a/src/test/ui/tutorial-suffix-inference-test.stderr +++ b/src/test/ui/tutorial-suffix-inference-test.stderr @@ -5,7 +5,7 @@ LL | identity_u16(x); | ^ | | | expected `u16`, found `u8` - | help: you can convert a `u8` to `u16`: `x.into()` + | help: you can convert a `u8` to a `u16`: `x.into()` error[E0308]: mismatched types --> $DIR/tutorial-suffix-inference-test.rs:12:18 @@ -13,7 +13,7 @@ error[E0308]: mismatched types LL | identity_u16(y); | ^ expected `u16`, found `i32` | -help: you can convert an `i32` to `u16` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u16` and panic if the converted value wouldn't fit | LL | identity_u16(y.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ error[E0308]: mismatched types LL | identity_u16(a); | ^ expected `u16`, found `isize` | -help: you can convert an `isize` to `u16` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u16` and panic if the converted value wouldn't fit | LL | identity_u16(a.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/wrong-ret-type.stderr b/src/test/ui/wrong-ret-type.stderr index c1274bd0ea6..6a7aac25cde 100644 --- a/src/test/ui/wrong-ret-type.stderr +++ b/src/test/ui/wrong-ret-type.stderr @@ -6,7 +6,7 @@ LL | fn mk_int() -> usize { let i: isize = 3; return i; } | | | expected `usize` because of return type | -help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `usize` and panic if the converted value wouldn't fit | LL | fn mk_int() -> usize { let i: isize = 3; return i.try_into().unwrap(); } | ^^^^^^^^^^^^^^^^^^^^^ From 8a6831a7fd3fc624643b50f494212e0ceaad3c28 Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 29 Sep 2020 19:27:58 -0700 Subject: [PATCH 043/446] Say "doesn't" instead of "wouldn't" in convert message --- compiler/rustc_typeck/src/check/demand.rs | 2 +- .../associated-types-path-2.stderr | 2 +- src/test/ui/indexing-requires-a-uint.stderr | 2 +- .../integer-literal-suffix-inference.stderr | 60 ++++---- src/test/ui/issues/issue-13359.stderr | 4 +- ...od-ambig-one-trait-unknown-int-type.stderr | 2 +- .../ui/mismatched_types/issue-26480.stderr | 2 +- src/test/ui/numeric/const-scope.stderr | 2 +- src/test/ui/numeric/len.stderr | 2 +- src/test/ui/numeric/numeric-cast-2.stderr | 2 +- src/test/ui/numeric/numeric-cast-binop.stderr | 124 ++++++++-------- src/test/ui/numeric/numeric-cast.stderr | 134 +++++++++--------- .../ui/proc-macro/span-preservation.stderr | 2 +- src/test/ui/shift-various-bad-types.stderr | 2 +- src/test/ui/tail-typeck.stderr | 2 +- ...ounds-inconsistent-projection-error.stderr | 2 +- .../ui/tutorial-suffix-inference-test.stderr | 4 +- src/test/ui/wrong-ret-type.stderr | 2 +- 18 files changed, 176 insertions(+), 176 deletions(-) diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 1081b3a229b..7c1d4fc4129 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -827,7 +827,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let suggestion = format!("{}::from({})", checked_ty, lhs_src); (lhs_expr.span, msg, suggestion) } else { - let msg = format!("{} and panic if the converted value wouldn't fit", msg); + let msg = format!("{} and panic if the converted value doesn't fit", msg); let suggestion = format!("{}{}.try_into().unwrap()", prefix, with_opt_paren(&src)); (expr.span, msg, suggestion) diff --git a/src/test/ui/associated-types/associated-types-path-2.stderr b/src/test/ui/associated-types/associated-types-path-2.stderr index 618225274f1..0881258aca1 100644 --- a/src/test/ui/associated-types/associated-types-path-2.stderr +++ b/src/test/ui/associated-types/associated-types-path-2.stderr @@ -47,7 +47,7 @@ LL | let _: i32 = f2(2i32); | | | expected due to this | -help: you can convert a `u32` to an `i32` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit | LL | let _: i32 = f2(2i32).try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/indexing-requires-a-uint.stderr b/src/test/ui/indexing-requires-a-uint.stderr index ac1ff99b8f8..3152dec30a0 100644 --- a/src/test/ui/indexing-requires-a-uint.stderr +++ b/src/test/ui/indexing-requires-a-uint.stderr @@ -13,7 +13,7 @@ error[E0308]: mismatched types LL | bar::(i); // i should not be re-coerced back to an isize | ^ expected `isize`, found `usize` | -help: you can convert a `usize` to an `isize` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `isize` and panic if the converted value doesn't fit | LL | bar::(i.try_into().unwrap()); // i should not be re-coerced back to an isize | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/integer-literal-suffix-inference.stderr b/src/test/ui/integer-literal-suffix-inference.stderr index 642e0c3944c..bfb47515823 100644 --- a/src/test/ui/integer-literal-suffix-inference.stderr +++ b/src/test/ui/integer-literal-suffix-inference.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | id_i8(a16); | ^^^ expected `i8`, found `i16` | -help: you can convert an `i16` to an `i8` and panic if the converted value wouldn't fit +help: you can convert an `i16` to an `i8` and panic if the converted value doesn't fit | LL | id_i8(a16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ error[E0308]: mismatched types LL | id_i8(a32); | ^^^ expected `i8`, found `i32` | -help: you can convert an `i32` to an `i8` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `i8` and panic if the converted value doesn't fit | LL | id_i8(a32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ error[E0308]: mismatched types LL | id_i8(a64); | ^^^ expected `i8`, found `i64` | -help: you can convert an `i64` to an `i8` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i8` and panic if the converted value doesn't fit | LL | id_i8(a64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ error[E0308]: mismatched types LL | id_i8(asize); | ^^^^^ expected `i8`, found `isize` | -help: you can convert an `isize` to an `i8` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i8` and panic if the converted value doesn't fit | LL | id_i8(asize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -57,7 +57,7 @@ error[E0308]: mismatched types LL | id_i16(a32); | ^^^ expected `i16`, found `i32` | -help: you can convert an `i32` to an `i16` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `i16` and panic if the converted value doesn't fit | LL | id_i16(a32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -68,7 +68,7 @@ error[E0308]: mismatched types LL | id_i16(a64); | ^^^ expected `i16`, found `i64` | -help: you can convert an `i64` to an `i16` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i16` and panic if the converted value doesn't fit | LL | id_i16(a64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -79,7 +79,7 @@ error[E0308]: mismatched types LL | id_i16(asize); | ^^^^^ expected `i16`, found `isize` | -help: you can convert an `isize` to an `i16` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i16` and panic if the converted value doesn't fit | LL | id_i16(asize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -108,7 +108,7 @@ error[E0308]: mismatched types LL | id_i32(a64); | ^^^ expected `i32`, found `i64` | -help: you can convert an `i64` to an `i32` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i32` and panic if the converted value doesn't fit | LL | id_i32(a64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -119,7 +119,7 @@ error[E0308]: mismatched types LL | id_i32(asize); | ^^^^^ expected `i32`, found `isize` | -help: you can convert an `isize` to an `i32` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i32` and panic if the converted value doesn't fit | LL | id_i32(asize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ error[E0308]: mismatched types LL | id_i64(asize); | ^^^^^ expected `i64`, found `isize` | -help: you can convert an `isize` to an `i64` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i64` and panic if the converted value doesn't fit | LL | id_i64(asize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -186,7 +186,7 @@ error[E0308]: mismatched types LL | id_isize(a32); | ^^^ expected `isize`, found `i32` | -help: you can convert an `i32` to an `isize` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `isize` and panic if the converted value doesn't fit | LL | id_isize(a32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -197,7 +197,7 @@ error[E0308]: mismatched types LL | id_isize(a64); | ^^^ expected `isize`, found `i64` | -help: you can convert an `i64` to an `isize` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `isize` and panic if the converted value doesn't fit | LL | id_isize(a64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -208,7 +208,7 @@ error[E0308]: mismatched types LL | id_i8(c16); | ^^^ expected `i8`, found `i16` | -help: you can convert an `i16` to an `i8` and panic if the converted value wouldn't fit +help: you can convert an `i16` to an `i8` and panic if the converted value doesn't fit | LL | id_i8(c16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -219,7 +219,7 @@ error[E0308]: mismatched types LL | id_i8(c32); | ^^^ expected `i8`, found `i32` | -help: you can convert an `i32` to an `i8` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `i8` and panic if the converted value doesn't fit | LL | id_i8(c32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -230,7 +230,7 @@ error[E0308]: mismatched types LL | id_i8(c64); | ^^^ expected `i8`, found `i64` | -help: you can convert an `i64` to an `i8` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i8` and panic if the converted value doesn't fit | LL | id_i8(c64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -250,7 +250,7 @@ error[E0308]: mismatched types LL | id_i16(c32); | ^^^ expected `i16`, found `i32` | -help: you can convert an `i32` to an `i16` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `i16` and panic if the converted value doesn't fit | LL | id_i16(c32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -261,7 +261,7 @@ error[E0308]: mismatched types LL | id_i16(c64); | ^^^ expected `i16`, found `i64` | -help: you can convert an `i64` to an `i16` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i16` and panic if the converted value doesn't fit | LL | id_i16(c64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -290,7 +290,7 @@ error[E0308]: mismatched types LL | id_i32(c64); | ^^^ expected `i32`, found `i64` | -help: you can convert an `i64` to an `i32` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i32` and panic if the converted value doesn't fit | LL | id_i32(c64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -328,7 +328,7 @@ error[E0308]: mismatched types LL | id_u8(b16); | ^^^ expected `u8`, found `u16` | -help: you can convert a `u16` to a `u8` and panic if the converted value wouldn't fit +help: you can convert a `u16` to a `u8` and panic if the converted value doesn't fit | LL | id_u8(b16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -339,7 +339,7 @@ error[E0308]: mismatched types LL | id_u8(b32); | ^^^ expected `u8`, found `u32` | -help: you can convert a `u32` to a `u8` and panic if the converted value wouldn't fit +help: you can convert a `u32` to a `u8` and panic if the converted value doesn't fit | LL | id_u8(b32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -350,7 +350,7 @@ error[E0308]: mismatched types LL | id_u8(b64); | ^^^ expected `u8`, found `u64` | -help: you can convert a `u64` to a `u8` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `u8` and panic if the converted value doesn't fit | LL | id_u8(b64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -361,7 +361,7 @@ error[E0308]: mismatched types LL | id_u8(bsize); | ^^^^^ expected `u8`, found `usize` | -help: you can convert a `usize` to a `u8` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u8` and panic if the converted value doesn't fit | LL | id_u8(bsize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -381,7 +381,7 @@ error[E0308]: mismatched types LL | id_u16(b32); | ^^^ expected `u16`, found `u32` | -help: you can convert a `u32` to a `u16` and panic if the converted value wouldn't fit +help: you can convert a `u32` to a `u16` and panic if the converted value doesn't fit | LL | id_u16(b32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -392,7 +392,7 @@ error[E0308]: mismatched types LL | id_u16(b64); | ^^^ expected `u16`, found `u64` | -help: you can convert a `u64` to a `u16` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `u16` and panic if the converted value doesn't fit | LL | id_u16(b64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -403,7 +403,7 @@ error[E0308]: mismatched types LL | id_u16(bsize); | ^^^^^ expected `u16`, found `usize` | -help: you can convert a `usize` to a `u16` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u16` and panic if the converted value doesn't fit | LL | id_u16(bsize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -432,7 +432,7 @@ error[E0308]: mismatched types LL | id_u32(b64); | ^^^ expected `u32`, found `u64` | -help: you can convert a `u64` to a `u32` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `u32` and panic if the converted value doesn't fit | LL | id_u32(b64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -443,7 +443,7 @@ error[E0308]: mismatched types LL | id_u32(bsize); | ^^^^^ expected `u32`, found `usize` | -help: you can convert a `usize` to a `u32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit | LL | id_u32(bsize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -481,7 +481,7 @@ error[E0308]: mismatched types LL | id_u64(bsize); | ^^^^^ expected `u64`, found `usize` | -help: you can convert a `usize` to a `u64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u64` and panic if the converted value doesn't fit | LL | id_u64(bsize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -510,7 +510,7 @@ error[E0308]: mismatched types LL | id_usize(b32); | ^^^ expected `usize`, found `u32` | -help: you can convert a `u32` to a `usize` and panic if the converted value wouldn't fit +help: you can convert a `u32` to a `usize` and panic if the converted value doesn't fit | LL | id_usize(b32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -521,7 +521,7 @@ error[E0308]: mismatched types LL | id_usize(b64); | ^^^ expected `usize`, found `u64` | -help: you can convert a `u64` to a `usize` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `usize` and panic if the converted value doesn't fit | LL | id_usize(b64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/issues/issue-13359.stderr b/src/test/ui/issues/issue-13359.stderr index 2e7e42f1667..115b471e96b 100644 --- a/src/test/ui/issues/issue-13359.stderr +++ b/src/test/ui/issues/issue-13359.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | foo(1*(1 as isize)); | ^^^^^^^^^^^^^^ expected `i16`, found `isize` | -help: you can convert an `isize` to an `i16` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i16` and panic if the converted value doesn't fit | LL | foo((1*(1 as isize)).try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ error[E0308]: mismatched types LL | bar(1*(1 as usize)); | ^^^^^^^^^^^^^^ expected `u32`, found `usize` | -help: you can convert a `usize` to a `u32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit | LL | bar((1*(1 as usize)).try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr index 3f4dda81347..82660a7c416 100644 --- a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr +++ b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr @@ -14,7 +14,7 @@ LL | let y: usize = x.foo(); | | | expected due to this | -help: you can convert an `isize` to a `usize` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `usize` and panic if the converted value doesn't fit | LL | let y: usize = x.foo().try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index 7dc686c8e7b..e608cd99af2 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -8,7 +8,7 @@ LL | write!(hello); | -------------- in this macro invocation | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -help: you can convert a `usize` to a `u64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u64` and panic if the converted value doesn't fit | LL | ($arr.len() * size_of($arr[0])).try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/numeric/const-scope.stderr b/src/test/ui/numeric/const-scope.stderr index 94ff4623c60..5a275d5d089 100644 --- a/src/test/ui/numeric/const-scope.stderr +++ b/src/test/ui/numeric/const-scope.stderr @@ -57,7 +57,7 @@ LL | let d: i8 = c; | | | expected due to this | -help: you can convert an `i32` to an `i8` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `i8` and panic if the converted value doesn't fit | LL | let d: i8 = c.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/numeric/len.stderr b/src/test/ui/numeric/len.stderr index 946a4de4245..79b38b06986 100644 --- a/src/test/ui/numeric/len.stderr +++ b/src/test/ui/numeric/len.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | test(array.len()); | ^^^^^^^^^^^ expected `u32`, found `usize` | -help: you can convert a `usize` to a `u32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit | LL | test(array.len().try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/numeric/numeric-cast-2.stderr b/src/test/ui/numeric/numeric-cast-2.stderr index 9409ce1ed0e..858990fe59b 100644 --- a/src/test/ui/numeric/numeric-cast-2.stderr +++ b/src/test/ui/numeric/numeric-cast-2.stderr @@ -6,7 +6,7 @@ LL | let x: u16 = foo(); | | | expected due to this | -help: you can convert an `i32` to a `u16` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u16` and panic if the converted value doesn't fit | LL | let x: u16 = foo().try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/numeric/numeric-cast-binop.stderr b/src/test/ui/numeric/numeric-cast-binop.stderr index c0f784309b9..cb051aa1230 100644 --- a/src/test/ui/numeric/numeric-cast-binop.stderr +++ b/src/test/ui/numeric/numeric-cast-binop.stderr @@ -152,7 +152,7 @@ error[E0308]: mismatched types LL | x_u32 > x_usize; | ^^^^^^^ expected `u32`, found `usize` | -help: you can convert a `usize` to a `u32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit | LL | x_u32 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -201,7 +201,7 @@ error[E0308]: mismatched types LL | x_u64 > x_usize; | ^^^^^^^ expected `u64`, found `usize` | -help: you can convert a `usize` to a `u64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u64` and panic if the converted value doesn't fit | LL | x_u64 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -248,7 +248,7 @@ error[E0308]: mismatched types LL | x_u128 > x_usize; | ^^^^^^^ expected `u128`, found `usize` | -help: you can convert a `usize` to a `u128` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u128` and panic if the converted value doesn't fit | LL | x_u128 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -277,7 +277,7 @@ error[E0308]: mismatched types LL | x_usize > x_u32; | ^^^^^ expected `usize`, found `u32` | -help: you can convert a `u32` to a `usize` and panic if the converted value wouldn't fit +help: you can convert a `u32` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_u32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -288,7 +288,7 @@ error[E0308]: mismatched types LL | x_usize > x_u64; | ^^^^^ expected `usize`, found `u64` | -help: you can convert a `u64` to a `usize` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -299,7 +299,7 @@ error[E0308]: mismatched types LL | x_usize > x_u128; | ^^^^^^ expected `usize`, found `u128` | -help: you can convert a `u128` to a `usize` and panic if the converted value wouldn't fit +help: you can convert a `u128` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -458,7 +458,7 @@ error[E0308]: mismatched types LL | x_i32 > x_isize; | ^^^^^^^ expected `i32`, found `isize` | -help: you can convert an `isize` to an `i32` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i32` and panic if the converted value doesn't fit | LL | x_i32 > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -507,7 +507,7 @@ error[E0308]: mismatched types LL | x_i64 > x_isize; | ^^^^^^^ expected `i64`, found `isize` | -help: you can convert an `isize` to an `i64` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i64` and panic if the converted value doesn't fit | LL | x_i64 > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -554,7 +554,7 @@ error[E0308]: mismatched types LL | x_i128 > x_isize; | ^^^^^^^ expected `i128`, found `isize` | -help: you can convert an `isize` to an `i128` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i128` and panic if the converted value doesn't fit | LL | x_i128 > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -583,7 +583,7 @@ error[E0308]: mismatched types LL | x_isize > x_i32; | ^^^^^ expected `isize`, found `i32` | -help: you can convert an `i32` to an `isize` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_i32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -594,7 +594,7 @@ error[E0308]: mismatched types LL | x_isize > x_i64; | ^^^^^ expected `isize`, found `i64` | -help: you can convert an `i64` to an `isize` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_i64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -605,7 +605,7 @@ error[E0308]: mismatched types LL | x_isize > x_i128; | ^^^^^^ expected `isize`, found `i128` | -help: you can convert an `i128` to an `isize` and panic if the converted value wouldn't fit +help: you can convert an `i128` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_i128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -616,7 +616,7 @@ error[E0308]: mismatched types LL | x_u8 > x_i8; | ^^^^ expected `u8`, found `i8` | -help: you can convert an `i8` to a `u8` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u8` and panic if the converted value doesn't fit | LL | x_u8 > x_i8.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -682,7 +682,7 @@ error[E0308]: mismatched types LL | x_u16 > x_i8; | ^^^^ expected `u16`, found `i8` | -help: you can convert an `i8` to a `u16` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u16` and panic if the converted value doesn't fit | LL | x_u16 > x_i8.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -693,7 +693,7 @@ error[E0308]: mismatched types LL | x_u16 > x_i16; | ^^^^^ expected `u16`, found `i16` | -help: you can convert an `i16` to a `u16` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u16` and panic if the converted value doesn't fit | LL | x_u16 > x_i16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -737,7 +737,7 @@ error[E0308]: mismatched types LL | x_u16 > x_isize; | ^^^^^^^ expected `u16`, found `isize` | -help: you can convert an `isize` to a `u16` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u16` and panic if the converted value doesn't fit | LL | x_u16 > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -748,7 +748,7 @@ error[E0308]: mismatched types LL | x_u32 > x_i8; | ^^^^ expected `u32`, found `i8` | -help: you can convert an `i8` to a `u32` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u32` and panic if the converted value doesn't fit | LL | x_u32 > x_i8.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -759,7 +759,7 @@ error[E0308]: mismatched types LL | x_u32 > x_i16; | ^^^^^ expected `u32`, found `i16` | -help: you can convert an `i16` to a `u32` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u32` and panic if the converted value doesn't fit | LL | x_u32 > x_i16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -770,7 +770,7 @@ error[E0308]: mismatched types LL | x_u32 > x_i32; | ^^^^^ expected `u32`, found `i32` | -help: you can convert an `i32` to a `u32` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u32` and panic if the converted value doesn't fit | LL | x_u32 > x_i32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -803,7 +803,7 @@ error[E0308]: mismatched types LL | x_u32 > x_isize; | ^^^^^^^ expected `u32`, found `isize` | -help: you can convert an `isize` to a `u32` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u32` and panic if the converted value doesn't fit | LL | x_u32 > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -814,7 +814,7 @@ error[E0308]: mismatched types LL | x_u64 > x_i8; | ^^^^ expected `u64`, found `i8` | -help: you can convert an `i8` to a `u64` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u64` and panic if the converted value doesn't fit | LL | x_u64 > x_i8.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -825,7 +825,7 @@ error[E0308]: mismatched types LL | x_u64 > x_i16; | ^^^^^ expected `u64`, found `i16` | -help: you can convert an `i16` to a `u64` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u64` and panic if the converted value doesn't fit | LL | x_u64 > x_i16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -836,7 +836,7 @@ error[E0308]: mismatched types LL | x_u64 > x_i32; | ^^^^^ expected `u64`, found `i32` | -help: you can convert an `i32` to a `u64` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u64` and panic if the converted value doesn't fit | LL | x_u64 > x_i32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -847,7 +847,7 @@ error[E0308]: mismatched types LL | x_u64 > x_i64; | ^^^^^ expected `u64`, found `i64` | -help: you can convert an `i64` to a `u64` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `u64` and panic if the converted value doesn't fit | LL | x_u64 > x_i64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -869,7 +869,7 @@ error[E0308]: mismatched types LL | x_u64 > x_isize; | ^^^^^^^ expected `u64`, found `isize` | -help: you can convert an `isize` to a `u64` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u64` and panic if the converted value doesn't fit | LL | x_u64 > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -880,7 +880,7 @@ error[E0308]: mismatched types LL | x_u128 > x_i8; | ^^^^ expected `u128`, found `i8` | -help: you can convert an `i8` to a `u128` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u128` and panic if the converted value doesn't fit | LL | x_u128 > x_i8.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -891,7 +891,7 @@ error[E0308]: mismatched types LL | x_u128 > x_i16; | ^^^^^ expected `u128`, found `i16` | -help: you can convert an `i16` to a `u128` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u128` and panic if the converted value doesn't fit | LL | x_u128 > x_i16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -902,7 +902,7 @@ error[E0308]: mismatched types LL | x_u128 > x_i32; | ^^^^^ expected `u128`, found `i32` | -help: you can convert an `i32` to a `u128` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u128` and panic if the converted value doesn't fit | LL | x_u128 > x_i32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -913,7 +913,7 @@ error[E0308]: mismatched types LL | x_u128 > x_i64; | ^^^^^ expected `u128`, found `i64` | -help: you can convert an `i64` to a `u128` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `u128` and panic if the converted value doesn't fit | LL | x_u128 > x_i64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -924,7 +924,7 @@ error[E0308]: mismatched types LL | x_u128 > x_i128; | ^^^^^^ expected `u128`, found `i128` | -help: you can convert an `i128` to a `u128` and panic if the converted value wouldn't fit +help: you can convert an `i128` to a `u128` and panic if the converted value doesn't fit | LL | x_u128 > x_i128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -935,7 +935,7 @@ error[E0308]: mismatched types LL | x_u128 > x_isize; | ^^^^^^^ expected `u128`, found `isize` | -help: you can convert an `isize` to a `u128` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u128` and panic if the converted value doesn't fit | LL | x_u128 > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -946,7 +946,7 @@ error[E0308]: mismatched types LL | x_usize > x_i8; | ^^^^ expected `usize`, found `i8` | -help: you can convert an `i8` to a `usize` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_i8.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -957,7 +957,7 @@ error[E0308]: mismatched types LL | x_usize > x_i16; | ^^^^^ expected `usize`, found `i16` | -help: you can convert an `i16` to a `usize` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_i16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -968,7 +968,7 @@ error[E0308]: mismatched types LL | x_usize > x_i32; | ^^^^^ expected `usize`, found `i32` | -help: you can convert an `i32` to a `usize` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_i32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -979,7 +979,7 @@ error[E0308]: mismatched types LL | x_usize > x_i64; | ^^^^^ expected `usize`, found `i64` | -help: you can convert an `i64` to a `usize` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_i64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -990,7 +990,7 @@ error[E0308]: mismatched types LL | x_usize > x_i128; | ^^^^^^ expected `usize`, found `i128` | -help: you can convert an `i128` to a `usize` and panic if the converted value wouldn't fit +help: you can convert an `i128` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_i128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1001,7 +1001,7 @@ error[E0308]: mismatched types LL | x_usize > x_isize; | ^^^^^^^ expected `usize`, found `isize` | -help: you can convert an `isize` to a `usize` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1012,7 +1012,7 @@ error[E0308]: mismatched types LL | x_i8 > x_u8; | ^^^^ expected `i8`, found `u8` | -help: you can convert a `u8` to an `i8` and panic if the converted value wouldn't fit +help: you can convert a `u8` to an `i8` and panic if the converted value doesn't fit | LL | x_i8 > x_u8.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1023,7 +1023,7 @@ error[E0308]: mismatched types LL | x_i8 > x_u16; | ^^^^^ expected `i8`, found `u16` | -help: you can convert a `u16` to an `i8` and panic if the converted value wouldn't fit +help: you can convert a `u16` to an `i8` and panic if the converted value doesn't fit | LL | x_i8 > x_u16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1034,7 +1034,7 @@ error[E0308]: mismatched types LL | x_i8 > x_u32; | ^^^^^ expected `i8`, found `u32` | -help: you can convert a `u32` to an `i8` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `i8` and panic if the converted value doesn't fit | LL | x_i8 > x_u32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1045,7 +1045,7 @@ error[E0308]: mismatched types LL | x_i8 > x_u64; | ^^^^^ expected `i8`, found `u64` | -help: you can convert a `u64` to an `i8` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i8` and panic if the converted value doesn't fit | LL | x_i8 > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1056,7 +1056,7 @@ error[E0308]: mismatched types LL | x_i8 > x_u128; | ^^^^^^ expected `i8`, found `u128` | -help: you can convert a `u128` to an `i8` and panic if the converted value wouldn't fit +help: you can convert a `u128` to an `i8` and panic if the converted value doesn't fit | LL | x_i8 > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1067,7 +1067,7 @@ error[E0308]: mismatched types LL | x_i8 > x_usize; | ^^^^^^^ expected `i8`, found `usize` | -help: you can convert a `usize` to an `i8` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i8` and panic if the converted value doesn't fit | LL | x_i8 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1087,7 +1087,7 @@ error[E0308]: mismatched types LL | x_i16 > x_u16; | ^^^^^ expected `i16`, found `u16` | -help: you can convert a `u16` to an `i16` and panic if the converted value wouldn't fit +help: you can convert a `u16` to an `i16` and panic if the converted value doesn't fit | LL | x_i16 > x_u16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1098,7 +1098,7 @@ error[E0308]: mismatched types LL | x_i16 > x_u32; | ^^^^^ expected `i16`, found `u32` | -help: you can convert a `u32` to an `i16` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `i16` and panic if the converted value doesn't fit | LL | x_i16 > x_u32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1109,7 +1109,7 @@ error[E0308]: mismatched types LL | x_i16 > x_u64; | ^^^^^ expected `i16`, found `u64` | -help: you can convert a `u64` to an `i16` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i16` and panic if the converted value doesn't fit | LL | x_i16 > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1120,7 +1120,7 @@ error[E0308]: mismatched types LL | x_i16 > x_u128; | ^^^^^^ expected `i16`, found `u128` | -help: you can convert a `u128` to an `i16` and panic if the converted value wouldn't fit +help: you can convert a `u128` to an `i16` and panic if the converted value doesn't fit | LL | x_i16 > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1131,7 +1131,7 @@ error[E0308]: mismatched types LL | x_i16 > x_usize; | ^^^^^^^ expected `i16`, found `usize` | -help: you can convert a `usize` to an `i16` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i16` and panic if the converted value doesn't fit | LL | x_i16 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1160,7 +1160,7 @@ error[E0308]: mismatched types LL | x_i32 > x_u32; | ^^^^^ expected `i32`, found `u32` | -help: you can convert a `u32` to an `i32` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit | LL | x_i32 > x_u32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1171,7 +1171,7 @@ error[E0308]: mismatched types LL | x_i32 > x_u64; | ^^^^^ expected `i32`, found `u64` | -help: you can convert a `u64` to an `i32` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i32` and panic if the converted value doesn't fit | LL | x_i32 > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1182,7 +1182,7 @@ error[E0308]: mismatched types LL | x_i32 > x_u128; | ^^^^^^ expected `i32`, found `u128` | -help: you can convert a `u128` to an `i32` and panic if the converted value wouldn't fit +help: you can convert a `u128` to an `i32` and panic if the converted value doesn't fit | LL | x_i32 > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1193,7 +1193,7 @@ error[E0308]: mismatched types LL | x_i32 > x_usize; | ^^^^^^^ expected `i32`, found `usize` | -help: you can convert a `usize` to an `i32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i32` and panic if the converted value doesn't fit | LL | x_i32 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1231,7 +1231,7 @@ error[E0308]: mismatched types LL | x_i64 > x_u64; | ^^^^^ expected `i64`, found `u64` | -help: you can convert a `u64` to an `i64` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i64` and panic if the converted value doesn't fit | LL | x_i64 > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1242,7 +1242,7 @@ error[E0308]: mismatched types LL | x_i64 > x_u128; | ^^^^^^ expected `i64`, found `u128` | -help: you can convert a `u128` to an `i64` and panic if the converted value wouldn't fit +help: you can convert a `u128` to an `i64` and panic if the converted value doesn't fit | LL | x_i64 > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1253,7 +1253,7 @@ error[E0308]: mismatched types LL | x_i64 > x_usize; | ^^^^^^^ expected `i64`, found `usize` | -help: you can convert a `usize` to an `i64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i64` and panic if the converted value doesn't fit | LL | x_i64 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1300,7 +1300,7 @@ error[E0308]: mismatched types LL | x_i128 > x_u128; | ^^^^^^ expected `i128`, found `u128` | -help: you can convert a `u128` to an `i128` and panic if the converted value wouldn't fit +help: you can convert a `u128` to an `i128` and panic if the converted value doesn't fit | LL | x_i128 > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1311,7 +1311,7 @@ error[E0308]: mismatched types LL | x_i128 > x_usize; | ^^^^^^^ expected `i128`, found `usize` | -help: you can convert a `usize` to an `i128` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i128` and panic if the converted value doesn't fit | LL | x_i128 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1331,7 +1331,7 @@ error[E0308]: mismatched types LL | x_isize > x_u16; | ^^^^^ expected `isize`, found `u16` | -help: you can convert a `u16` to an `isize` and panic if the converted value wouldn't fit +help: you can convert a `u16` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_u16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1342,7 +1342,7 @@ error[E0308]: mismatched types LL | x_isize > x_u32; | ^^^^^ expected `isize`, found `u32` | -help: you can convert a `u32` to an `isize` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_u32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1353,7 +1353,7 @@ error[E0308]: mismatched types LL | x_isize > x_u64; | ^^^^^ expected `isize`, found `u64` | -help: you can convert a `u64` to an `isize` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1364,7 +1364,7 @@ error[E0308]: mismatched types LL | x_isize > x_u128; | ^^^^^^ expected `isize`, found `u128` | -help: you can convert a `u128` to an `isize` and panic if the converted value wouldn't fit +help: you can convert a `u128` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1375,7 +1375,7 @@ error[E0308]: mismatched types LL | x_isize > x_usize; | ^^^^^^^ expected `isize`, found `usize` | -help: you can convert a `usize` to an `isize` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/numeric/numeric-cast.stderr b/src/test/ui/numeric/numeric-cast.stderr index ea2f87232ad..ffd6368bac1 100644 --- a/src/test/ui/numeric/numeric-cast.stderr +++ b/src/test/ui/numeric/numeric-cast.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `usize`, found `u64` | -help: you can convert a `u64` to a `usize` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `usize` and panic if the converted value doesn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `usize`, found `u32` | -help: you can convert a `u32` to a `usize` and panic if the converted value wouldn't fit +help: you can convert a `u32` to a `usize` and panic if the converted value doesn't fit | LL | foo::(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ error[E0308]: mismatched types LL | foo::(x_isize); | ^^^^^^^ expected `usize`, found `isize` | -help: you can convert an `isize` to a `usize` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `usize` and panic if the converted value doesn't fit | LL | foo::(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -55,7 +55,7 @@ error[E0308]: mismatched types LL | foo::(x_i64); | ^^^^^ expected `usize`, found `i64` | -help: you can convert an `i64` to a `usize` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `usize` and panic if the converted value doesn't fit | LL | foo::(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -66,7 +66,7 @@ error[E0308]: mismatched types LL | foo::(x_i32); | ^^^^^ expected `usize`, found `i32` | -help: you can convert an `i32` to a `usize` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `usize` and panic if the converted value doesn't fit | LL | foo::(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -77,7 +77,7 @@ error[E0308]: mismatched types LL | foo::(x_i16); | ^^^^^ expected `usize`, found `i16` | -help: you can convert an `i16` to a `usize` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `usize` and panic if the converted value doesn't fit | LL | foo::(x_i16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ error[E0308]: mismatched types LL | foo::(x_i8); | ^^^^ expected `usize`, found `i8` | -help: you can convert an `i8` to a `usize` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `usize` and panic if the converted value doesn't fit | LL | foo::(x_i8.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -99,7 +99,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `isize`, found `usize` | -help: you can convert a `usize` to an `isize` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `isize` and panic if the converted value doesn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -110,7 +110,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `isize`, found `u64` | -help: you can convert a `u64` to an `isize` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `isize` and panic if the converted value doesn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `isize`, found `u32` | -help: you can convert a `u32` to an `isize` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `isize` and panic if the converted value doesn't fit | LL | foo::(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,7 +132,7 @@ error[E0308]: mismatched types LL | foo::(x_u16); | ^^^^^ expected `isize`, found `u16` | -help: you can convert a `u16` to an `isize` and panic if the converted value wouldn't fit +help: you can convert a `u16` to an `isize` and panic if the converted value doesn't fit | LL | foo::(x_u16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -152,7 +152,7 @@ error[E0308]: mismatched types LL | foo::(x_i64); | ^^^^^ expected `isize`, found `i64` | -help: you can convert an `i64` to an `isize` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `isize` and panic if the converted value doesn't fit | LL | foo::(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -163,7 +163,7 @@ error[E0308]: mismatched types LL | foo::(x_i32); | ^^^^^ expected `isize`, found `i32` | -help: you can convert an `i32` to an `isize` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `isize` and panic if the converted value doesn't fit | LL | foo::(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -192,7 +192,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `u64`, found `usize` | -help: you can convert a `usize` to a `u64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u64` and panic if the converted value doesn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -230,7 +230,7 @@ error[E0308]: mismatched types LL | foo::(x_isize); | ^^^^^^^ expected `u64`, found `isize` | -help: you can convert an `isize` to a `u64` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u64` and panic if the converted value doesn't fit | LL | foo::(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,7 +241,7 @@ error[E0308]: mismatched types LL | foo::(x_i64); | ^^^^^ expected `u64`, found `i64` | -help: you can convert an `i64` to a `u64` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `u64` and panic if the converted value doesn't fit | LL | foo::(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -252,7 +252,7 @@ error[E0308]: mismatched types LL | foo::(x_i32); | ^^^^^ expected `u64`, found `i32` | -help: you can convert an `i32` to a `u64` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u64` and panic if the converted value doesn't fit | LL | foo::(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -263,7 +263,7 @@ error[E0308]: mismatched types LL | foo::(x_i16); | ^^^^^ expected `u64`, found `i16` | -help: you can convert an `i16` to a `u64` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u64` and panic if the converted value doesn't fit | LL | foo::(x_i16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -274,7 +274,7 @@ error[E0308]: mismatched types LL | foo::(x_i8); | ^^^^ expected `u64`, found `i8` | -help: you can convert an `i8` to a `u64` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u64` and panic if the converted value doesn't fit | LL | foo::(x_i8.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -285,7 +285,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `i64`, found `usize` | -help: you can convert a `usize` to an `i64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i64` and panic if the converted value doesn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -296,7 +296,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `i64`, found `u64` | -help: you can convert a `u64` to an `i64` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i64` and panic if the converted value doesn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -334,7 +334,7 @@ error[E0308]: mismatched types LL | foo::(x_isize); | ^^^^^^^ expected `i64`, found `isize` | -help: you can convert an `isize` to an `i64` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i64` and panic if the converted value doesn't fit | LL | foo::(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -372,7 +372,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `u32`, found `usize` | -help: you can convert a `usize` to a `u32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -383,7 +383,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `u32`, found `u64` | -help: you can convert a `u64` to a `u32` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `u32` and panic if the converted value doesn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -412,7 +412,7 @@ error[E0308]: mismatched types LL | foo::(x_isize); | ^^^^^^^ expected `u32`, found `isize` | -help: you can convert an `isize` to a `u32` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u32` and panic if the converted value doesn't fit | LL | foo::(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -423,7 +423,7 @@ error[E0308]: mismatched types LL | foo::(x_i64); | ^^^^^ expected `u32`, found `i64` | -help: you can convert an `i64` to a `u32` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `u32` and panic if the converted value doesn't fit | LL | foo::(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -434,7 +434,7 @@ error[E0308]: mismatched types LL | foo::(x_i32); | ^^^^^ expected `u32`, found `i32` | -help: you can convert an `i32` to a `u32` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u32` and panic if the converted value doesn't fit | LL | foo::(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -445,7 +445,7 @@ error[E0308]: mismatched types LL | foo::(x_i16); | ^^^^^ expected `u32`, found `i16` | -help: you can convert an `i16` to a `u32` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u32` and panic if the converted value doesn't fit | LL | foo::(x_i16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -456,7 +456,7 @@ error[E0308]: mismatched types LL | foo::(x_i8); | ^^^^ expected `u32`, found `i8` | -help: you can convert an `i8` to a `u32` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u32` and panic if the converted value doesn't fit | LL | foo::(x_i8.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -467,7 +467,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `i32`, found `usize` | -help: you can convert a `usize` to an `i32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i32` and panic if the converted value doesn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -478,7 +478,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `i32`, found `u64` | -help: you can convert a `u64` to an `i32` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i32` and panic if the converted value doesn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -489,7 +489,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `i32`, found `u32` | -help: you can convert a `u32` to an `i32` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit | LL | foo::(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -518,7 +518,7 @@ error[E0308]: mismatched types LL | foo::(x_isize); | ^^^^^^^ expected `i32`, found `isize` | -help: you can convert an `isize` to an `i32` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i32` and panic if the converted value doesn't fit | LL | foo::(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -529,7 +529,7 @@ error[E0308]: mismatched types LL | foo::(x_i64); | ^^^^^ expected `i32`, found `i64` | -help: you can convert an `i64` to an `i32` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i32` and panic if the converted value doesn't fit | LL | foo::(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -558,7 +558,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `u16`, found `usize` | -help: you can convert a `usize` to a `u16` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u16` and panic if the converted value doesn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -569,7 +569,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `u16`, found `u64` | -help: you can convert a `u64` to a `u16` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `u16` and panic if the converted value doesn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -580,7 +580,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `u16`, found `u32` | -help: you can convert a `u32` to a `u16` and panic if the converted value wouldn't fit +help: you can convert a `u32` to a `u16` and panic if the converted value doesn't fit | LL | foo::(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -600,7 +600,7 @@ error[E0308]: mismatched types LL | foo::(x_isize); | ^^^^^^^ expected `u16`, found `isize` | -help: you can convert an `isize` to a `u16` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u16` and panic if the converted value doesn't fit | LL | foo::(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -611,7 +611,7 @@ error[E0308]: mismatched types LL | foo::(x_i64); | ^^^^^ expected `u16`, found `i64` | -help: you can convert an `i64` to a `u16` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `u16` and panic if the converted value doesn't fit | LL | foo::(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -622,7 +622,7 @@ error[E0308]: mismatched types LL | foo::(x_i32); | ^^^^^ expected `u16`, found `i32` | -help: you can convert an `i32` to a `u16` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u16` and panic if the converted value doesn't fit | LL | foo::(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -633,7 +633,7 @@ error[E0308]: mismatched types LL | foo::(x_i16); | ^^^^^ expected `u16`, found `i16` | -help: you can convert an `i16` to a `u16` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u16` and panic if the converted value doesn't fit | LL | foo::(x_i16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -644,7 +644,7 @@ error[E0308]: mismatched types LL | foo::(x_i8); | ^^^^ expected `u16`, found `i8` | -help: you can convert an `i8` to a `u16` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u16` and panic if the converted value doesn't fit | LL | foo::(x_i8.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -655,7 +655,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `i16`, found `usize` | -help: you can convert a `usize` to an `i16` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i16` and panic if the converted value doesn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -666,7 +666,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `i16`, found `u64` | -help: you can convert a `u64` to an `i16` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i16` and panic if the converted value doesn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -677,7 +677,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `i16`, found `u32` | -help: you can convert a `u32` to an `i16` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `i16` and panic if the converted value doesn't fit | LL | foo::(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -688,7 +688,7 @@ error[E0308]: mismatched types LL | foo::(x_u16); | ^^^^^ expected `i16`, found `u16` | -help: you can convert a `u16` to an `i16` and panic if the converted value wouldn't fit +help: you can convert a `u16` to an `i16` and panic if the converted value doesn't fit | LL | foo::(x_u16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -708,7 +708,7 @@ error[E0308]: mismatched types LL | foo::(x_isize); | ^^^^^^^ expected `i16`, found `isize` | -help: you can convert an `isize` to an `i16` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i16` and panic if the converted value doesn't fit | LL | foo::(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -719,7 +719,7 @@ error[E0308]: mismatched types LL | foo::(x_i64); | ^^^^^ expected `i16`, found `i64` | -help: you can convert an `i64` to an `i16` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i16` and panic if the converted value doesn't fit | LL | foo::(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -730,7 +730,7 @@ error[E0308]: mismatched types LL | foo::(x_i32); | ^^^^^ expected `i16`, found `i32` | -help: you can convert an `i32` to an `i16` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `i16` and panic if the converted value doesn't fit | LL | foo::(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -750,7 +750,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `u8`, found `usize` | -help: you can convert a `usize` to a `u8` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u8` and panic if the converted value doesn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -761,7 +761,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `u8`, found `u64` | -help: you can convert a `u64` to a `u8` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `u8` and panic if the converted value doesn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -772,7 +772,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `u8`, found `u32` | -help: you can convert a `u32` to a `u8` and panic if the converted value wouldn't fit +help: you can convert a `u32` to a `u8` and panic if the converted value doesn't fit | LL | foo::(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -783,7 +783,7 @@ error[E0308]: mismatched types LL | foo::(x_u16); | ^^^^^ expected `u8`, found `u16` | -help: you can convert a `u16` to a `u8` and panic if the converted value wouldn't fit +help: you can convert a `u16` to a `u8` and panic if the converted value doesn't fit | LL | foo::(x_u16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -794,7 +794,7 @@ error[E0308]: mismatched types LL | foo::(x_isize); | ^^^^^^^ expected `u8`, found `isize` | -help: you can convert an `isize` to a `u8` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u8` and panic if the converted value doesn't fit | LL | foo::(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -805,7 +805,7 @@ error[E0308]: mismatched types LL | foo::(x_i64); | ^^^^^ expected `u8`, found `i64` | -help: you can convert an `i64` to a `u8` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `u8` and panic if the converted value doesn't fit | LL | foo::(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -816,7 +816,7 @@ error[E0308]: mismatched types LL | foo::(x_i32); | ^^^^^ expected `u8`, found `i32` | -help: you can convert an `i32` to a `u8` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u8` and panic if the converted value doesn't fit | LL | foo::(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -827,7 +827,7 @@ error[E0308]: mismatched types LL | foo::(x_i16); | ^^^^^ expected `u8`, found `i16` | -help: you can convert an `i16` to a `u8` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u8` and panic if the converted value doesn't fit | LL | foo::(x_i16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -838,7 +838,7 @@ error[E0308]: mismatched types LL | foo::(x_i8); | ^^^^ expected `u8`, found `i8` | -help: you can convert an `i8` to a `u8` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u8` and panic if the converted value doesn't fit | LL | foo::(x_i8.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -849,7 +849,7 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `i8`, found `usize` | -help: you can convert a `usize` to an `i8` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i8` and panic if the converted value doesn't fit | LL | foo::(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -860,7 +860,7 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `i8`, found `u64` | -help: you can convert a `u64` to an `i8` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i8` and panic if the converted value doesn't fit | LL | foo::(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -871,7 +871,7 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `i8`, found `u32` | -help: you can convert a `u32` to an `i8` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `i8` and panic if the converted value doesn't fit | LL | foo::(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -882,7 +882,7 @@ error[E0308]: mismatched types LL | foo::(x_u16); | ^^^^^ expected `i8`, found `u16` | -help: you can convert a `u16` to an `i8` and panic if the converted value wouldn't fit +help: you can convert a `u16` to an `i8` and panic if the converted value doesn't fit | LL | foo::(x_u16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -893,7 +893,7 @@ error[E0308]: mismatched types LL | foo::(x_u8); | ^^^^ expected `i8`, found `u8` | -help: you can convert a `u8` to an `i8` and panic if the converted value wouldn't fit +help: you can convert a `u8` to an `i8` and panic if the converted value doesn't fit | LL | foo::(x_u8.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -904,7 +904,7 @@ error[E0308]: mismatched types LL | foo::(x_isize); | ^^^^^^^ expected `i8`, found `isize` | -help: you can convert an `isize` to an `i8` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i8` and panic if the converted value doesn't fit | LL | foo::(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -915,7 +915,7 @@ error[E0308]: mismatched types LL | foo::(x_i64); | ^^^^^ expected `i8`, found `i64` | -help: you can convert an `i64` to an `i8` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i8` and panic if the converted value doesn't fit | LL | foo::(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -926,7 +926,7 @@ error[E0308]: mismatched types LL | foo::(x_i32); | ^^^^^ expected `i8`, found `i32` | -help: you can convert an `i32` to an `i8` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `i8` and panic if the converted value doesn't fit | LL | foo::(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -937,7 +937,7 @@ error[E0308]: mismatched types LL | foo::(x_i16); | ^^^^^ expected `i8`, found `i16` | -help: you can convert an `i16` to an `i8` and panic if the converted value wouldn't fit +help: you can convert an `i16` to an `i8` and panic if the converted value doesn't fit | LL | foo::(x_i16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/proc-macro/span-preservation.stderr b/src/test/ui/proc-macro/span-preservation.stderr index 5df0ac417f8..4064c5b3819 100644 --- a/src/test/ui/proc-macro/span-preservation.stderr +++ b/src/test/ui/proc-macro/span-preservation.stderr @@ -15,7 +15,7 @@ LL | match x { LL | Some(x) => { return x }, | ^ expected `usize`, found `isize` | -help: you can convert an `isize` to a `usize` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `usize` and panic if the converted value doesn't fit | LL | Some(x) => { return x.try_into().unwrap() }, | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/shift-various-bad-types.stderr b/src/test/ui/shift-various-bad-types.stderr index ceda6402148..63b70f7fcd9 100644 --- a/src/test/ui/shift-various-bad-types.stderr +++ b/src/test/ui/shift-various-bad-types.stderr @@ -30,7 +30,7 @@ LL | let _: i32 = 22_i64 >> 1_i32; | | | expected due to this | -help: you can convert an `i64` to an `i32` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i32` and panic if the converted value doesn't fit | LL | let _: i32 = (22_i64 >> 1_i32).try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/tail-typeck.stderr b/src/test/ui/tail-typeck.stderr index 24049c2c587..cff09910721 100644 --- a/src/test/ui/tail-typeck.stderr +++ b/src/test/ui/tail-typeck.stderr @@ -6,7 +6,7 @@ LL | fn f() -> isize { return g(); } | | | expected `isize` because of return type | -help: you can convert a `usize` to an `isize` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `isize` and panic if the converted value doesn't fit | LL | fn f() -> isize { return g().try_into().unwrap(); } | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr index 1816c5245f7..edb48b6625e 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr @@ -7,7 +7,7 @@ LL | fn global_bound_is_hidden() -> u8 LL | B::get_x() | ^^^^^^^^^^ expected `u8`, found `i32` | -help: you can convert an `i32` to a `u8` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u8` and panic if the converted value doesn't fit | LL | B::get_x().try_into().unwrap() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/tutorial-suffix-inference-test.stderr b/src/test/ui/tutorial-suffix-inference-test.stderr index 5cea9f9fea8..f9974acfb70 100644 --- a/src/test/ui/tutorial-suffix-inference-test.stderr +++ b/src/test/ui/tutorial-suffix-inference-test.stderr @@ -13,7 +13,7 @@ error[E0308]: mismatched types LL | identity_u16(y); | ^ expected `u16`, found `i32` | -help: you can convert an `i32` to a `u16` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u16` and panic if the converted value doesn't fit | LL | identity_u16(y.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ error[E0308]: mismatched types LL | identity_u16(a); | ^ expected `u16`, found `isize` | -help: you can convert an `isize` to a `u16` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u16` and panic if the converted value doesn't fit | LL | identity_u16(a.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/wrong-ret-type.stderr b/src/test/ui/wrong-ret-type.stderr index 6a7aac25cde..5498dae718f 100644 --- a/src/test/ui/wrong-ret-type.stderr +++ b/src/test/ui/wrong-ret-type.stderr @@ -6,7 +6,7 @@ LL | fn mk_int() -> usize { let i: isize = 3; return i; } | | | expected `usize` because of return type | -help: you can convert an `isize` to a `usize` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `usize` and panic if the converted value doesn't fit | LL | fn mk_int() -> usize { let i: isize = 3; return i.try_into().unwrap(); } | ^^^^^^^^^^^^^^^^^^^^^ From 13dfbb64d313137b7d3c33067910e90f27bc6345 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Thu, 6 Aug 2020 11:53:09 +0600 Subject: [PATCH 044/446] Suggest imports of unresolved macros --- compiler/rustc_resolve/src/diagnostics.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 612bc3e7491..42af8a2fb0e 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -929,6 +929,10 @@ impl<'a> Resolver<'a> { ); self.add_typo_suggestion(err, suggestion, ident.span); + let import_suggestions = + self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, |_| true); + show_candidates(err, None, &import_suggestions, false, true); + if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) { let msg = format!("unsafe traits like `{}` should be implemented explicitly", ident); err.span_note(ident.span, &msg); From 479298e05e8177b171c6d6bcd35fc7553b424bee Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Thu, 6 Aug 2020 16:42:06 +0600 Subject: [PATCH 045/446] Re-run tests with --bless --- src/test/ui/empty/empty-macro-use.stderr | 3 +++ src/test/ui/hygiene/no_implicit_prelude-2018.stderr | 3 +++ src/test/ui/hygiene/no_implicit_prelude.stderr | 3 +++ src/test/ui/issues/issue-11692-2.stderr | 3 +++ src/test/ui/macros/macro-use-wrong-name.stderr | 3 +++ src/test/ui/missing/missing-macro-use.stderr | 3 +++ src/test/ui/proc-macro/derive-helper-shadowing.stderr | 4 ++++ src/test/ui/proc-macro/macro-namespace-reserved-2.stderr | 6 ++++++ 8 files changed, 28 insertions(+) diff --git a/src/test/ui/empty/empty-macro-use.stderr b/src/test/ui/empty/empty-macro-use.stderr index 8e3e06896ee..700f6616af4 100644 --- a/src/test/ui/empty/empty-macro-use.stderr +++ b/src/test/ui/empty/empty-macro-use.stderr @@ -3,6 +3,9 @@ error: cannot find macro `macro_two` in this scope | LL | macro_two!(); | ^^^^^^^^^ + | + = note: consider importing this macro: + two_macros::macro_two error: aborting due to previous error diff --git a/src/test/ui/hygiene/no_implicit_prelude-2018.stderr b/src/test/ui/hygiene/no_implicit_prelude-2018.stderr index f31b75238df..02ddc391f6e 100644 --- a/src/test/ui/hygiene/no_implicit_prelude-2018.stderr +++ b/src/test/ui/hygiene/no_implicit_prelude-2018.stderr @@ -3,6 +3,9 @@ error: cannot find macro `print` in this scope | LL | print!(); | ^^^^^ + | + = note: consider importing this macro: + std::print error: aborting due to previous error diff --git a/src/test/ui/hygiene/no_implicit_prelude.stderr b/src/test/ui/hygiene/no_implicit_prelude.stderr index 3c0c0450774..843dee2478b 100644 --- a/src/test/ui/hygiene/no_implicit_prelude.stderr +++ b/src/test/ui/hygiene/no_implicit_prelude.stderr @@ -4,6 +4,9 @@ error: cannot find macro `panic` in this scope LL | assert_eq!(0, 0); | ^^^^^^^^^^^^^^^^^ | + = note: consider importing one of these items: + core::panic + std::panic = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error[E0433]: failed to resolve: use of undeclared type `Vec` diff --git a/src/test/ui/issues/issue-11692-2.stderr b/src/test/ui/issues/issue-11692-2.stderr index f021943da32..22b4dbce54a 100644 --- a/src/test/ui/issues/issue-11692-2.stderr +++ b/src/test/ui/issues/issue-11692-2.stderr @@ -3,6 +3,9 @@ error: cannot find macro `test` in this scope | LL | concat!(test!()); | ^^^^ + | + = note: consider importing this attribute macro: + std::prelude::v1::test error: aborting due to previous error diff --git a/src/test/ui/macros/macro-use-wrong-name.stderr b/src/test/ui/macros/macro-use-wrong-name.stderr index 74fb519cc82..888fb913fb7 100644 --- a/src/test/ui/macros/macro-use-wrong-name.stderr +++ b/src/test/ui/macros/macro-use-wrong-name.stderr @@ -8,6 +8,9 @@ LL | macro_two!(); | LL | macro_rules! macro_one { () => ("one") } | ---------------------- similarly named macro `macro_one` defined here + | + = note: consider importing this macro: + two_macros::macro_two error: aborting due to previous error diff --git a/src/test/ui/missing/missing-macro-use.stderr b/src/test/ui/missing/missing-macro-use.stderr index 711e249d2bc..ced062269df 100644 --- a/src/test/ui/missing/missing-macro-use.stderr +++ b/src/test/ui/missing/missing-macro-use.stderr @@ -3,6 +3,9 @@ error: cannot find macro `macro_two` in this scope | LL | macro_two!(); | ^^^^^^^^^ + | + = note: consider importing this macro: + two_macros::macro_two error: aborting due to previous error diff --git a/src/test/ui/proc-macro/derive-helper-shadowing.stderr b/src/test/ui/proc-macro/derive-helper-shadowing.stderr index f82f49aa775..6aff0cb8e9c 100644 --- a/src/test/ui/proc-macro/derive-helper-shadowing.stderr +++ b/src/test/ui/proc-macro/derive-helper-shadowing.stderr @@ -16,6 +16,8 @@ error: cannot find attribute `empty_helper` in this scope LL | #[derive(GenHelperUse)] | ^^^^^^^^^^^^ | + = note: consider importing this attribute macro: + empty_helper = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: cannot find attribute `empty_helper` in this scope @@ -27,6 +29,8 @@ LL | #[empty_helper] LL | gen_helper_use!(); | ------------------ in this macro invocation | + = note: consider importing this attribute macro: + crate::empty_helper = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `empty_helper` is ambiguous (name vs any other name during import resolution) diff --git a/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr b/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr index a617319faea..8073fafb0d8 100644 --- a/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr +++ b/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr @@ -93,12 +93,18 @@ error: cannot find macro `my_macro_attr` in this scope | LL | my_macro_attr!(); | ^^^^^^^^^^^^^ + | + = note: consider importing this attribute macro: + my_macro_attr error: cannot find macro `MyTrait` in this scope --> $DIR/macro-namespace-reserved-2.rs:33:5 | LL | MyTrait!(); | ^^^^^^^ + | + = note: consider importing this derive macro: + MyTrait error: cannot find attribute `my_macro` in this scope --> $DIR/macro-namespace-reserved-2.rs:38:3 From ea7cf6106864ce7929eb9f3cfe580f05ee418ac8 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sat, 29 Aug 2020 01:01:29 +0600 Subject: [PATCH 046/446] Don't suggest macros that out of scope --- compiler/rustc_resolve/src/diagnostics.rs | 11 +++++++++-- src/test/ui/issues/issue-11692-2.stderr | 3 --- src/test/ui/proc-macro/derive-helper-shadowing.stderr | 4 ---- .../ui/proc-macro/macro-namespace-reserved-2.stderr | 6 ------ 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 42af8a2fb0e..0ad057822b3 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -929,8 +929,15 @@ impl<'a> Resolver<'a> { ); self.add_typo_suggestion(err, suggestion, ident.span); - let import_suggestions = - self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, |_| true); + let import_suggestions = self.lookup_import_candidates( + ident, + Namespace::MacroNS, + parent_scope, + |res| match res { + Res::Def(DefKind::Macro(MacroKind::Bang), _) => true, + _ => false, + }, + ); show_candidates(err, None, &import_suggestions, false, true); if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) { diff --git a/src/test/ui/issues/issue-11692-2.stderr b/src/test/ui/issues/issue-11692-2.stderr index 22b4dbce54a..f021943da32 100644 --- a/src/test/ui/issues/issue-11692-2.stderr +++ b/src/test/ui/issues/issue-11692-2.stderr @@ -3,9 +3,6 @@ error: cannot find macro `test` in this scope | LL | concat!(test!()); | ^^^^ - | - = note: consider importing this attribute macro: - std::prelude::v1::test error: aborting due to previous error diff --git a/src/test/ui/proc-macro/derive-helper-shadowing.stderr b/src/test/ui/proc-macro/derive-helper-shadowing.stderr index 6aff0cb8e9c..f82f49aa775 100644 --- a/src/test/ui/proc-macro/derive-helper-shadowing.stderr +++ b/src/test/ui/proc-macro/derive-helper-shadowing.stderr @@ -16,8 +16,6 @@ error: cannot find attribute `empty_helper` in this scope LL | #[derive(GenHelperUse)] | ^^^^^^^^^^^^ | - = note: consider importing this attribute macro: - empty_helper = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: cannot find attribute `empty_helper` in this scope @@ -29,8 +27,6 @@ LL | #[empty_helper] LL | gen_helper_use!(); | ------------------ in this macro invocation | - = note: consider importing this attribute macro: - crate::empty_helper = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `empty_helper` is ambiguous (name vs any other name during import resolution) diff --git a/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr b/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr index 8073fafb0d8..a617319faea 100644 --- a/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr +++ b/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr @@ -93,18 +93,12 @@ error: cannot find macro `my_macro_attr` in this scope | LL | my_macro_attr!(); | ^^^^^^^^^^^^^ - | - = note: consider importing this attribute macro: - my_macro_attr error: cannot find macro `MyTrait` in this scope --> $DIR/macro-namespace-reserved-2.rs:33:5 | LL | MyTrait!(); | ^^^^^^^ - | - = note: consider importing this derive macro: - MyTrait error: cannot find attribute `my_macro` in this scope --> $DIR/macro-namespace-reserved-2.rs:38:3 From 77e6c56ab6f108fdbb8acbd176497be9f074af9a Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 1 Oct 2020 11:03:16 -0700 Subject: [PATCH 047/446] Unify `&mut` and `&raw mut` const-checking errors --- .../src/transform/check_consts/ops.rs | 38 ++++++------------- .../src/transform/check_consts/validation.rs | 6 ++- 2 files changed, 15 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index 25ed7859d21..8eaa8fb7e1d 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -235,7 +235,8 @@ impl NonConstOp for CellBorrow { } #[derive(Debug)] -pub struct MutBorrow; +pub struct MutBorrow(pub hir::BorrowKind); + impl NonConstOp for MutBorrow { fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { // Forbid everywhere except in const fn with a feature gate @@ -247,22 +248,28 @@ impl NonConstOp for MutBorrow { } fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let raw = match self.0 { + hir::BorrowKind::Raw => "raw ", + hir::BorrowKind::Ref => "", + }; + let mut err = if ccx.const_kind() == hir::ConstContext::ConstFn { feature_err( &ccx.tcx.sess.parse_sess, sym::const_mut_refs, span, - &format!("mutable references are not allowed in {}s", ccx.const_kind()), + &format!("{}mutable references are not allowed in {}s", raw, ccx.const_kind()), ) } else { let mut err = struct_span_err!( ccx.tcx.sess, span, E0764, - "mutable references are not allowed in {}s", + "{}mutable references are not allowed in {}s", + raw, ccx.const_kind(), ); - err.span_label(span, format!("`&mut` is only allowed in `const fn`")); + err.span_label(span, format!("`&{}mut` is only allowed in `const fn`", raw)); err }; if ccx.tcx.sess.teach(&err.get_code().unwrap()) { @@ -281,29 +288,6 @@ impl NonConstOp for MutBorrow { } } -// FIXME(ecstaticmorse): Unify this with `MutBorrow`. It has basically the same issues. -#[derive(Debug)] -pub struct MutAddressOf; -impl NonConstOp for MutAddressOf { - fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { - // Forbid everywhere except in const fn with a feature gate - if ccx.const_kind() == hir::ConstContext::ConstFn { - Status::Unstable(sym::const_mut_refs) - } else { - Status::Forbidden - } - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_mut_refs, - span, - &format!("`&raw mut` is not allowed in {}s", ccx.const_kind()), - ) - } -} - #[derive(Debug)] pub struct MutDeref; impl NonConstOp for MutDeref { diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index ab63fd03a33..462fafcf1b5 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -522,14 +522,16 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { if !is_allowed { if let BorrowKind::Mut { .. } = kind { - self.check_op(ops::MutBorrow); + self.check_op(ops::MutBorrow(hir::BorrowKind::Ref)); } else { self.check_op(ops::CellBorrow); } } } - Rvalue::AddressOf(Mutability::Mut, _) => self.check_op(ops::MutAddressOf), + Rvalue::AddressOf(Mutability::Mut, _) => { + self.check_op(ops::MutBorrow(hir::BorrowKind::Raw)) + } Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Shallow, ref place) | Rvalue::AddressOf(Mutability::Not, ref place) => { From c1494d60dbad39c218e7b0825bfe590cc22bf2fa Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 1 Oct 2020 11:03:52 -0700 Subject: [PATCH 048/446] Bless tests --- src/test/ui/consts/const-address-of-mut.rs | 8 +++--- .../ui/consts/const-address-of-mut.stderr | 26 +++++++------------ src/test/ui/consts/min_const_fn/address_of.rs | 4 +-- .../ui/consts/min_const_fn/address_of.stderr | 4 +-- 4 files changed, 17 insertions(+), 25 deletions(-) diff --git a/src/test/ui/consts/const-address-of-mut.rs b/src/test/ui/consts/const-address-of-mut.rs index fe9188cb490..3788088b810 100644 --- a/src/test/ui/consts/const-address-of-mut.rs +++ b/src/test/ui/consts/const-address-of-mut.rs @@ -1,14 +1,14 @@ #![feature(raw_ref_op)] -const A: () = { let mut x = 2; &raw mut x; }; //~ ERROR `&raw mut` is not allowed +const A: () = { let mut x = 2; &raw mut x; }; //~ mutable reference -static B: () = { let mut x = 2; &raw mut x; }; //~ ERROR `&raw mut` is not allowed +static B: () = { let mut x = 2; &raw mut x; }; //~ mutable reference -static mut C: () = { let mut x = 2; &raw mut x; }; //~ ERROR `&raw mut` is not allowed +static mut C: () = { let mut x = 2; &raw mut x; }; //~ mutable reference const fn foo() { let mut x = 0; - let y = &raw mut x; //~ ERROR `&raw mut` is not allowed + let y = &raw mut x; //~ mutable reference } fn main() {} diff --git a/src/test/ui/consts/const-address-of-mut.stderr b/src/test/ui/consts/const-address-of-mut.stderr index 1d9a325b0c2..ec2dac5a7d1 100644 --- a/src/test/ui/consts/const-address-of-mut.stderr +++ b/src/test/ui/consts/const-address-of-mut.stderr @@ -1,31 +1,22 @@ -error[E0658]: `&raw mut` is not allowed in constants +error[E0764]: raw mutable references are not allowed in constants --> $DIR/const-address-of-mut.rs:3:32 | LL | const A: () = { let mut x = 2; &raw mut x; }; - | ^^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^^^^^ `&raw mut` is only allowed in `const fn` -error[E0658]: `&raw mut` is not allowed in statics +error[E0764]: raw mutable references are not allowed in statics --> $DIR/const-address-of-mut.rs:5:33 | LL | static B: () = { let mut x = 2; &raw mut x; }; - | ^^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^^^^^ `&raw mut` is only allowed in `const fn` -error[E0658]: `&raw mut` is not allowed in statics +error[E0764]: raw mutable references are not allowed in statics --> $DIR/const-address-of-mut.rs:7:37 | LL | static mut C: () = { let mut x = 2; &raw mut x; }; - | ^^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^^^^^ `&raw mut` is only allowed in `const fn` -error[E0658]: `&raw mut` is not allowed in constant functions +error[E0658]: raw mutable references are not allowed in constant functions --> $DIR/const-address-of-mut.rs:11:13 | LL | let y = &raw mut x; @@ -36,4 +27,5 @@ LL | let y = &raw mut x; error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0658, E0764. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/min_const_fn/address_of.rs b/src/test/ui/consts/min_const_fn/address_of.rs index f8506d70b24..40d1882d7d2 100644 --- a/src/test/ui/consts/min_const_fn/address_of.rs +++ b/src/test/ui/consts/min_const_fn/address_of.rs @@ -2,7 +2,7 @@ const fn mutable_address_of_in_const() { let mut a = 0; - let b = &raw mut a; //~ ERROR `&raw mut` is not allowed + let b = &raw mut a; //~ ERROR mutable reference } struct X; @@ -10,7 +10,7 @@ struct X; impl X { const fn inherent_mutable_address_of_in_const() { let mut a = 0; - let b = &raw mut a; //~ ERROR `&raw mut` is not allowed + let b = &raw mut a; //~ ERROR mutable reference } } diff --git a/src/test/ui/consts/min_const_fn/address_of.stderr b/src/test/ui/consts/min_const_fn/address_of.stderr index 4d9d1d79284..facc566513c 100644 --- a/src/test/ui/consts/min_const_fn/address_of.stderr +++ b/src/test/ui/consts/min_const_fn/address_of.stderr @@ -1,4 +1,4 @@ -error[E0658]: `&raw mut` is not allowed in constant functions +error[E0658]: raw mutable references are not allowed in constant functions --> $DIR/address_of.rs:5:13 | LL | let b = &raw mut a; @@ -7,7 +7,7 @@ LL | let b = &raw mut a; = note: see issue #57349 for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0658]: `&raw mut` is not allowed in constant functions +error[E0658]: raw mutable references are not allowed in constant functions --> $DIR/address_of.rs:13:17 | LL | let b = &raw mut a; From 388384177e89db60280dc275e4239e97e61f6a59 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Fri, 2 Oct 2020 13:30:50 +1300 Subject: [PATCH 049/446] document `MinifyingSugg` and `Offset` ...and also swap their position --- clippy_lints/src/loops.rs | 82 +++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 215700fed8c..9a1ba4907cd 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -805,44 +805,10 @@ fn same_var<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, var: HirId) -> bool { } } -#[derive(Clone, Copy)] -enum OffsetSign { - Positive, - Negative, -} - -struct Offset { - value: MinifyingSugg<'static>, - sign: OffsetSign, -} - -impl Offset { - fn negative(value: Sugg<'static>) -> Self { - Self { - value: value.into(), - sign: OffsetSign::Negative, - } - } - - fn positive(value: Sugg<'static>) -> Self { - Self { - value: value.into(), - sign: OffsetSign::Positive, - } - } - - fn empty() -> Self { - Self::positive(sugg::ZERO) - } -} - -fn apply_offset(lhs: &MinifyingSugg<'static>, rhs: &Offset) -> MinifyingSugg<'static> { - match rhs.sign { - OffsetSign::Positive => lhs + &rhs.value, - OffsetSign::Negative => lhs - &rhs.value, - } -} - +/// a wrapper of `Sugg`. Besides what `Sugg` do, this removes unnecessary `0`; +/// and also, it avoids subtracting a variable from the same one by replacing it with `0`. +/// it exists for the convenience of the overloaded operators while normal functions can do the +/// same. #[derive(Clone)] struct MinifyingSugg<'a>(Sugg<'a>); @@ -909,6 +875,46 @@ impl std::ops::Sub<&MinifyingSugg<'static>> for MinifyingSugg<'static> { } } +/// a wrapper around `MinifyingSugg`, which carries a operator like currying +/// so that the suggested code become more efficient (e.g. `foo + -bar` `foo - bar`). +struct Offset { + value: MinifyingSugg<'static>, + sign: OffsetSign, +} + +#[derive(Clone, Copy)] +enum OffsetSign { + Positive, + Negative, +} + +impl Offset { + fn negative(value: Sugg<'static>) -> Self { + Self { + value: value.into(), + sign: OffsetSign::Negative, + } + } + + fn positive(value: Sugg<'static>) -> Self { + Self { + value: value.into(), + sign: OffsetSign::Positive, + } + } + + fn empty() -> Self { + Self::positive(sugg::ZERO) + } +} + +fn apply_offset(lhs: &MinifyingSugg<'static>, rhs: &Offset) -> MinifyingSugg<'static> { + match rhs.sign { + OffsetSign::Positive => lhs + &rhs.value, + OffsetSign::Negative => lhs - &rhs.value, + } +} + #[derive(Debug, Clone, Copy)] enum StartKind<'hir> { Range, From 94d7b82340792af6e5c9b7c105dca1f2fef1b495 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Fri, 2 Oct 2020 14:04:46 +1300 Subject: [PATCH 050/446] simplify the code --- clippy_lints/src/loops.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 9a1ba4907cd..2ae5a9acb75 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -973,10 +973,7 @@ fn get_details_from_idx<'tcx>( ast::LitKind::Int(x, _ty) => Some(Sugg::NonParen(x.to_string().into())), _ => None, }, - ExprKind::Path(..) if get_start(cx, e, starts).is_none() => { - // `e` is always non paren as it's a `Path` - Some(Sugg::NonParen(snippet(cx, e.span, "???"))) - }, + ExprKind::Path(..) if get_start(cx, e, starts).is_none() => Some(Sugg::hir(cx, e, "???")), _ => None, } } @@ -1010,8 +1007,7 @@ fn get_assignment<'tcx>(e: &'tcx Expr<'tcx>) -> Option<(&'tcx Expr<'tcx>, &'tcx fn get_assignments<'a: 'c, 'tcx: 'c, 'c>( cx: &'a LateContext<'tcx>, - stmts: &'tcx [Stmt<'tcx>], - expr: Option<&'tcx Expr<'tcx>>, + Block { stmts, expr, .. }: &'tcx Block<'tcx>, loop_counters: &'c [Start<'tcx>], ) -> impl Iterator, &'tcx Expr<'tcx>)>> + 'c { stmts @@ -1025,7 +1021,7 @@ fn get_assignments<'a: 'c, 'tcx: 'c, 'c>( then { None } else { Some(e) } }, }) - .chain(expr.into_iter()) + .chain((*expr).into_iter()) .map(get_assignment) } @@ -1184,7 +1180,7 @@ fn detect_manual_memcpy<'tcx>( if let Some(loop_counters) = get_loop_counters(cx, block, expr) { starts.extend(loop_counters); } - iter_a = Some(get_assignments(cx, block.stmts, block.expr, &starts)); + iter_a = Some(get_assignments(cx, block, &starts)); } else { iter_b = Some(get_assignment(body)); } From 1402d8ae4f0c07ac48bd8297ec07901346c32d32 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Fri, 2 Oct 2020 14:18:37 +1300 Subject: [PATCH 051/446] fix a FN where incr exprs with no semicolon at ends --- clippy_lints/src/loops.rs | 18 ++++++++++++------ tests/ui/manual_memcpy/with_loop_counters.rs | 7 +++++++ .../ui/manual_memcpy/with_loop_counters.stderr | 11 ++++++++++- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 2ae5a9acb75..ea40c2af4f7 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1014,14 +1014,20 @@ fn get_assignments<'a: 'c, 'tcx: 'c, 'c>( .iter() .filter_map(move |stmt| match stmt.kind { StmtKind::Local(..) | StmtKind::Item(..) => None, - StmtKind::Expr(e) | StmtKind::Semi(e) => if_chain! { - if let ExprKind::AssignOp(_, var, _) = e.kind; - // skip StartKind::Range - if loop_counters.iter().skip(1).any(|counter| Some(counter.id) == var_def_id(cx, var)); - then { None } else { Some(e) } - }, + StmtKind::Expr(e) | StmtKind::Semi(e) => Some(e), }) .chain((*expr).into_iter()) + .filter(move |e| { + if let ExprKind::AssignOp(_, place, _) = e.kind { + !loop_counters + .iter() + // skip StartKind::Range + .skip(1) + .any(|counter| same_var(cx, place, counter.id)) + } else { + true + } + }) .map(get_assignment) } diff --git a/tests/ui/manual_memcpy/with_loop_counters.rs b/tests/ui/manual_memcpy/with_loop_counters.rs index a49ba9eb10a..70873c9e994 100644 --- a/tests/ui/manual_memcpy/with_loop_counters.rs +++ b/tests/ui/manual_memcpy/with_loop_counters.rs @@ -59,6 +59,13 @@ pub fn manual_copy_with_counters(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) dst[count] = src[i + 2]; count += 1; } + + // make sure incrementing expressions without semicolons at the end of loops are handled correctly. + let mut count = 0; + for i in 3..src.len() { + dst[i] = src[count]; + count += 1 + } } fn main() {} diff --git a/tests/ui/manual_memcpy/with_loop_counters.stderr b/tests/ui/manual_memcpy/with_loop_counters.stderr index 24393ad9b4d..598c881b4d6 100644 --- a/tests/ui/manual_memcpy/with_loop_counters.stderr +++ b/tests/ui/manual_memcpy/with_loop_counters.stderr @@ -89,5 +89,14 @@ LL | | count += 1; LL | | } | |_____^ help: try replacing the loop by: `dst[(0 << 1)..((1 << 1) + (0 << 1))].clone_from_slice(&src[2..((1 << 1) + 2)]);` -error: aborting due to 9 previous errors +error: it looks like you're manually copying between slices + --> $DIR/with_loop_counters.rs:65:5 + | +LL | / for i in 3..src.len() { +LL | | dst[i] = src[count]; +LL | | count += 1 +LL | | } + | |_____^ help: try replacing the loop by: `dst[3..src.len()].clone_from_slice(&src[..(src.len() - 3)]);` + +error: aborting due to 10 previous errors From 41a0ccbc57902e488e62ed8ca9a1ebb565129c09 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Fri, 2 Oct 2020 21:19:14 +1300 Subject: [PATCH 052/446] add comments around `loop_counters` --- clippy_lints/src/loops.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index ea40c2af4f7..4f279cc5ef7 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1005,6 +1005,10 @@ fn get_assignment<'tcx>(e: &'tcx Expr<'tcx>) -> Option<(&'tcx Expr<'tcx>, &'tcx } } +/// Get assignments from the given block. +/// The returned iterator yields `None` if no assignment expressions are there, +/// filtering out the increments of the given whitelisted loop counters; +/// because its job is to make sure there's nothing other than assignments and the increments. fn get_assignments<'a: 'c, 'tcx: 'c, 'c>( cx: &'a LateContext<'tcx>, Block { stmts, expr, .. }: &'tcx Block<'tcx>, @@ -1021,7 +1025,8 @@ fn get_assignments<'a: 'c, 'tcx: 'c, 'c>( if let ExprKind::AssignOp(_, place, _) = e.kind { !loop_counters .iter() - // skip StartKind::Range + // skip the first item which should be `StartKind::Range` + // this makes it possible to use the slice with `StartKind::Range` in the same iterator loop. .skip(1) .any(|counter| same_var(cx, place, counter.id)) } else { @@ -1191,11 +1196,11 @@ fn detect_manual_memcpy<'tcx>( iter_b = Some(get_assignment(body)); } - // The only statements in the for loops can be indexed assignments from - // indexed retrievals. let assignments = iter_a.into_iter().flatten().chain(iter_b.into_iter()); let big_sugg = assignments + // The only statements in the for loops can be indexed assignments from + // indexed retrievals (except increments of loop counters). .map(|o| { o.and_then(|(lhs, rhs)| { let rhs = fetch_cloned_expr(rhs); From 2a0e45b8dbfa9c8494371983b128b933082a9c13 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Fri, 2 Oct 2020 21:30:21 +1300 Subject: [PATCH 053/446] supress `clippy::filter_map` --- clippy_lints/src/loops.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 4f279cc5ef7..d3a1683cc0c 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1014,6 +1014,9 @@ fn get_assignments<'a: 'c, 'tcx: 'c, 'c>( Block { stmts, expr, .. }: &'tcx Block<'tcx>, loop_counters: &'c [Start<'tcx>], ) -> impl Iterator, &'tcx Expr<'tcx>)>> + 'c { + // As the `filter` and `map` below do different things, I think putting together + // just increases complexity. (cc #3188 and #4193) + #[allow(clippy::filter_map)] stmts .iter() .filter_map(move |stmt| match stmt.kind { From 7820cb14421f751c05d6d2d5925236c3429cd93f Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Fri, 2 Oct 2020 23:21:24 +1300 Subject: [PATCH 054/446] Add tests for * `dst.len()` as the end of the range with loop counters * the increment of the loop counter at the top of the loop --- tests/ui/manual_memcpy/with_loop_counters.rs | 17 +++++++++++++++++ .../ui/manual_memcpy/with_loop_counters.stderr | 17 +++++++++++++---- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/tests/ui/manual_memcpy/with_loop_counters.rs b/tests/ui/manual_memcpy/with_loop_counters.rs index 70873c9e994..ba388a05a28 100644 --- a/tests/ui/manual_memcpy/with_loop_counters.rs +++ b/tests/ui/manual_memcpy/with_loop_counters.rs @@ -37,6 +37,12 @@ pub fn manual_copy_with_counters(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) count += 1; } + let mut count = 2; + for i in 0..dst.len() { + dst[i] = src[count]; + count += 1; + } + let mut count = 5; for i in 3..10 { dst[i] = src[count]; @@ -66,6 +72,17 @@ pub fn manual_copy_with_counters(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) dst[i] = src[count]; count += 1 } + + // make sure ones where the increment is not at the end of the loop. + // As a possible enhancement, one could adjust the offset in the suggestion according to + // the position. For example, if the increment is at the top of the loop; + // treating the loop counter as if it were initialized 1 greater than the original value. + let mut count = 0; + #[allow(clippy::needless_range_loop)] + for i in 0..src.len() { + count += 1; + dst[i] = src[count]; + } } fn main() {} diff --git a/tests/ui/manual_memcpy/with_loop_counters.stderr b/tests/ui/manual_memcpy/with_loop_counters.stderr index 598c881b4d6..2547b19f5d1 100644 --- a/tests/ui/manual_memcpy/with_loop_counters.stderr +++ b/tests/ui/manual_memcpy/with_loop_counters.stderr @@ -57,6 +57,15 @@ LL | | } error: it looks like you're manually copying between slices --> $DIR/with_loop_counters.rs:41:5 | +LL | / for i in 0..dst.len() { +LL | | dst[i] = src[count]; +LL | | count += 1; +LL | | } + | |_____^ help: try replacing the loop by: `dst.clone_from_slice(&src[2..(dst.len() + 2)]);` + +error: it looks like you're manually copying between slices + --> $DIR/with_loop_counters.rs:47:5 + | LL | / for i in 3..10 { LL | | dst[i] = src[count]; LL | | count += 1; @@ -64,7 +73,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[3..10].clone_from_slice(&src[5..(10 + 5 - 3)]);` error: it looks like you're manually copying between slices - --> $DIR/with_loop_counters.rs:48:5 + --> $DIR/with_loop_counters.rs:54:5 | LL | / for i in 0..src.len() { LL | | dst[count] = src[i]; @@ -81,7 +90,7 @@ LL | dst2[30..(src.len() + 30)].clone_from_slice(&src[..]); | error: it looks like you're manually copying between slices - --> $DIR/with_loop_counters.rs:58:5 + --> $DIR/with_loop_counters.rs:64:5 | LL | / for i in 0..1 << 1 { LL | | dst[count] = src[i + 2]; @@ -90,7 +99,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[(0 << 1)..((1 << 1) + (0 << 1))].clone_from_slice(&src[2..((1 << 1) + 2)]);` error: it looks like you're manually copying between slices - --> $DIR/with_loop_counters.rs:65:5 + --> $DIR/with_loop_counters.rs:71:5 | LL | / for i in 3..src.len() { LL | | dst[i] = src[count]; @@ -98,5 +107,5 @@ LL | | count += 1 LL | | } | |_____^ help: try replacing the loop by: `dst[3..src.len()].clone_from_slice(&src[..(src.len() - 3)]);` -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors From b54188429409a6da5f931fa4be5df1f40b377015 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Fri, 2 Oct 2020 23:38:10 +1300 Subject: [PATCH 055/446] remove the explicit return value of `print_limit` --- clippy_lints/src/loops.rs | 41 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index d3a1683cc0c..3e9265c1215 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1082,30 +1082,29 @@ fn build_manual_memcpy_suggestion<'tcx>( } } - let print_limit = - |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| -> MinifyingSugg<'static> { - if_chain! { - if let ExprKind::MethodCall(method, _, len_args, _) = end.kind; - if method.ident.name == sym!(len); - if len_args.len() == 1; - if let Some(arg) = len_args.get(0); - if var_def_id(cx, arg) == var_def_id(cx, base); - then { - if sugg.as_str() == end_str { - sugg::EMPTY.into() - } else { - sugg - } + let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| { + if_chain! { + if let ExprKind::MethodCall(method, _, len_args, _) = end.kind; + if method.ident.name == sym!(len); + if len_args.len() == 1; + if let Some(arg) = len_args.get(0); + if var_def_id(cx, arg) == var_def_id(cx, base); + then { + if sugg.as_str() == end_str { + sugg::EMPTY.into() } else { - match limits { - ast::RangeLimits::Closed => { - sugg + &sugg::ONE.into() - }, - ast::RangeLimits::HalfOpen => sugg, - } + sugg + } + } else { + match limits { + ast::RangeLimits::Closed => { + sugg + &sugg::ONE.into() + }, + ast::RangeLimits::HalfOpen => sugg, } } - }; + } + }; let start_str = Sugg::hir(cx, start, "").into(); let end_str: MinifyingSugg<'_> = Sugg::hir(cx, end, "").into(); From 8fe61546696b626ecf68ef838d5d82e393719e80 Mon Sep 17 00:00:00 2001 From: Alexander Mols Date: Fri, 2 Oct 2020 07:44:32 -0700 Subject: [PATCH 056/446] Use posix_spawn() on unix if program is a path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously `Command::spawn` would fall back to the non-posix_spawn based implementation if the `PATH` environment variable was possibly changed. On systems with a modern (g)libc `posix_spawn()` can be significantly faster. If program is a path itself the `PATH` environment variable is not used for the lookup and it should be safe to use the `posix_spawnp()` method. [1] We found this, because we have a cli application that effectively runs a lot of subprocesses. It would sometimes noticeably hang while printing output. Profiling showed that the process was spending the majority of time in the kernel's `copy_page_range` function while spawning subprocesses. During this time the process is completely blocked from running, explaining why users were reporting the cli app hanging. Through this we discovered that `std::process::Command` has a fast and slow path for process execution. The fast path is backed by `posix_spawnp()` and the slow path by fork/exec syscalls being called explicitly. Using fork for process creation is supposed to be fast, but it slows down as your process uses more memory. It's not because the kernel copies the actual memory from the parent, but it does need to copy the references to it (see `copy_page_range` above!). We ended up using the slow path, because the command spawn implementation in falls back to the slow path if it suspects the PATH environment variable was changed. Here is a smallish program demonstrating the slowdown before this code change: ``` use std::process::Command; use std::time::Instant; fn main() { let mut args = std::env::args().skip(1); if let Some(size) = args.next() { // Allocate some memory let _xs: Vec<_> = std::iter::repeat(0) .take(size.parse().expect("valid number")) .collect(); let mut command = Command::new("/bin/sh"); command .arg("-c") .arg("echo hello"); if args.next().is_some() { println!("Overriding PATH"); command.env("PATH", std::env::var("PATH").expect("PATH env var")); } let now = Instant::now(); let child = command .spawn() .expect("failed to execute process"); println!("Spawn took: {:?}", now.elapsed()); let output = child.wait_with_output().expect("failed to wait on process"); println!("Output: {:?}", output); } else { eprintln!("Usage: prog [size]"); std::process::exit(1); } () } ``` Running it and passing different amounts of elements to use to allocate memory shows that the time taken for `spawn()` can differ quite significantly. In latter case the `posix_spawnp()` implementation is 30x faster: ``` $ cargo run --release 10000000 ... Spawn took: 324.275µs hello $ cargo run --release 10000000 changepath ... Overriding PATH Spawn took: 2.346809ms hello $ cargo run --release 100000000 ... Spawn took: 387.842µs hello $ cargo run --release 100000000 changepath ... Overriding PATH Spawn took: 13.434677ms hello ``` [1]: https://github.com/bminor/glibc/blob/5f72f9800b250410cad3abfeeb09469ef12b2438/posix/execvpe.c#L81 --- library/std/src/sys/unix/process/process_common.rs | 6 ++++++ library/std/src/sys/unix/process/process_unix.rs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index 9ddd4ad4000..2a384d8817c 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -253,11 +253,17 @@ impl Command { let maybe_env = self.env.capture_if_changed(); maybe_env.map(|env| construct_envp(env, &mut self.saw_nul)) } + #[allow(dead_code)] pub fn env_saw_path(&self) -> bool { self.env.have_changed_path() } + #[allow(dead_code)] + pub fn program_is_path(&self) -> bool { + self.program.to_bytes().contains(&b'/') + } + pub fn setup_io( &self, default: Stdio, diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index ea7ea6f067c..6be71980810 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -279,7 +279,7 @@ impl Command { if self.get_gid().is_some() || self.get_uid().is_some() - || self.env_saw_path() + || (self.env_saw_path() && !self.program_is_path()) || !self.get_closures().is_empty() { return Ok(None); From f302af33bc1901ddd0226c8d3a6433682a85f69b Mon Sep 17 00:00:00 2001 From: nahuakang Date: Fri, 2 Oct 2020 20:13:01 +0200 Subject: [PATCH 057/446] Add doc comment issue of #5834 to known problems of lint doc_markdown --- clippy_lints/src/doc.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 62bb70af06e..07f604cf714 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -32,6 +32,11 @@ declare_clippy_lint! { /// **Known problems:** Lots of bad docs won’t be fixed, what the lint checks /// for is limited, and there are still false positives. /// + /// In addition, when writing documentation comments, including `[]` brackets + /// inside a link text would trip the parser. Therfore, documenting link with + /// `[`SmallVec<[T; INLINE_CAPACITY]>`]` and then [`SmallVec<[T; INLINE_CAPACITY]>`]: SmallVec + /// would fail. + /// /// **Examples:** /// ```rust /// /// Do something with the foo_bar parameter. See also @@ -39,6 +44,14 @@ declare_clippy_lint! { /// // ^ `foo_bar` and `that::other::module::foo` should be ticked. /// fn doit(foo_bar: usize) {} /// ``` + /// + /// ```rust + /// // Link text with `[]` brackets should be written as following: + /// /// Consume the array and return the inner + /// /// [`SmallVec<[T; INLINE_CAPACITY]>`][SmallVec]. + /// /// [SmallVec]: SmallVec + /// fn main() {} + /// ``` pub DOC_MARKDOWN, pedantic, "presence of `_`, `::` or camel-case outside backticks in documentation" From f6f96e2a8757717ca8d701d26d37b067e95bb584 Mon Sep 17 00:00:00 2001 From: Tyson Nottingham Date: Fri, 2 Oct 2020 19:34:01 -0700 Subject: [PATCH 058/446] perf: buffer SipHasher128 --- compiler/rustc_data_structures/src/lib.rs | 1 + compiler/rustc_data_structures/src/sip128.rs | 491 +++++++++++------- .../rustc_data_structures/src/sip128/tests.rs | 45 ++ 3 files changed, 345 insertions(+), 192 deletions(-) diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 90b0f254751..20c68227bd9 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -28,6 +28,7 @@ #![feature(const_panic)] #![feature(min_const_generics)] #![feature(once_cell)] +#![feature(maybe_uninit_uninit_array)] #![allow(rustc::default_hash_types)] #[macro_use] diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs index 2c4eff618c6..4acb0e69e99 100644 --- a/compiler/rustc_data_structures/src/sip128.rs +++ b/compiler/rustc_data_structures/src/sip128.rs @@ -1,21 +1,24 @@ //! This is a copy of `core::hash::sip` adapted to providing 128 bit hashes. -use std::cmp; use std::hash::Hasher; -use std::mem; +use std::mem::{self, MaybeUninit}; use std::ptr; #[cfg(test)] mod tests; +const BUFFER_SIZE_ELEMS: usize = 8; +const BUFFER_SIZE_BYTES: usize = BUFFER_SIZE_ELEMS * mem::size_of::(); +const BUFFER_SIZE_ELEMS_SPILL: usize = BUFFER_SIZE_ELEMS + 1; +const BUFFER_SIZE_BYTES_SPILL: usize = BUFFER_SIZE_ELEMS_SPILL * mem::size_of::(); +const BUFFER_SPILL_INDEX: usize = BUFFER_SIZE_ELEMS_SPILL - 1; + #[derive(Debug, Clone)] pub struct SipHasher128 { - k0: u64, - k1: u64, - length: usize, // how many bytes we've processed - state: State, // hash State - tail: u64, // unprocessed bytes le - ntail: usize, // how many bytes in tail are valid + nbuf: usize, // how many bytes in buf are valid + buf: [MaybeUninit; BUFFER_SIZE_ELEMS_SPILL], // unprocessed bytes le + state: State, // hash State + processed: usize, // how many bytes we've processed } #[derive(Debug, Clone, Copy)] @@ -51,178 +54,317 @@ macro_rules! compress { }}; } -/// Loads an integer of the desired type from a byte stream, in LE order. Uses -/// `copy_nonoverlapping` to let the compiler generate the most efficient way -/// to load it from a possibly unaligned address. -/// -/// Unsafe because: unchecked indexing at i..i+size_of(int_ty) -macro_rules! load_int_le { - ($buf:expr, $i:expr, $int_ty:ident) => {{ - debug_assert!($i + mem::size_of::<$int_ty>() <= $buf.len()); - let mut data = 0 as $int_ty; - ptr::copy_nonoverlapping( - $buf.get_unchecked($i), - &mut data as *mut _ as *mut u8, - mem::size_of::<$int_ty>(), - ); - data.to_le() - }}; -} - -/// Loads a u64 using up to 7 bytes of a byte slice. It looks clumsy but the -/// `copy_nonoverlapping` calls that occur (via `load_int_le!`) all have fixed -/// sizes and avoid calling `memcpy`, which is good for speed. -/// -/// Unsafe because: unchecked indexing at start..start+len +// Copies up to 8 bytes from source to destination. This may be faster than +// calling `ptr::copy_nonoverlapping` with an arbitrary count, since all of +// the copies have fixed sizes and thus avoid calling memcpy. #[inline] -unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 { - debug_assert!(len < 8); - let mut i = 0; // current byte index (from LSB) in the output u64 - let mut out = 0; - if i + 3 < len { - out = load_int_le!(buf, start + i, u32) as u64; +unsafe fn copy_nonoverlapping_small(src: *const u8, dst: *mut u8, count: usize) { + debug_assert!(count <= 8); + + if count == 8 { + ptr::copy_nonoverlapping(src, dst, 8); + return; + } + + let mut i = 0; + if i + 3 < count { + ptr::copy_nonoverlapping(src.add(i), dst.add(i), 4); i += 4; } - if i + 1 < len { - out |= (load_int_le!(buf, start + i, u16) as u64) << (i * 8); + + if i + 1 < count { + ptr::copy_nonoverlapping(src.add(i), dst.add(i), 2); i += 2 } - if i < len { - out |= (*buf.get_unchecked(start + i) as u64) << (i * 8); + + if i < count { + *dst.add(i) = *src.add(i); i += 1; } - debug_assert_eq!(i, len); - out + + debug_assert_eq!(i, count); } +// Implementation +// +// This implementation uses buffering to reduce the hashing cost for inputs +// consisting of many small integers. Buffering simplifies the integration of +// integer input--the integer write function typically just appends to the +// buffer with a statically sized write, updates metadata, and returns. +// +// Buffering also prevents alternating between writes that do and do not trigger +// the hashing process. Only when the entire buffer is full do we transition +// into hashing. This allows us to keep the hash state in registers for longer, +// instead of loading and storing it before and after processing each element. +// +// When a write fills the buffer, a buffer processing function is invoked to +// hash all of the buffered input. The buffer processing functions are marked +// #[inline(never)] so that they aren't inlined into the append functions, which +// ensures the more frequently called append functions remain inlineable and +// don't include register pushing/popping that would only be made necessary by +// inclusion of the complex buffer processing path which uses those registers. +// +// The buffer includes a "spill"--an extra element at the end--which simplifies +// the integer write buffer processing path. The value that fills the buffer can +// be written with a statically sized write that may spill over into the spill. +// After the buffer is processed, the part of the value that spilled over can +// written from the spill to the beginning of the buffer with another statically +// sized write. Due to static sizes, this scheme performs better than copying +// the exact number of bytes needed into the end and beginning of the buffer. +// +// The buffer is uninitialized, which improves performance, but may preclude +// efficient implementation of alternative approaches. The improvement is not so +// large that an alternative approach should be disregarded because it cannot be +// efficiently implemented with an uninitialized buffer. On the other hand, an +// uninitialized buffer may become more important should a larger one be used. +// +// Platform Dependence +// +// The SipHash algorithm operates on byte sequences. It parses the input stream +// as 8-byte little-endian integers. Therefore, given the same byte sequence, it +// produces the same result on big- and little-endian hardware. +// +// However, the Hasher trait has methods which operate on multi-byte integers. +// How they are converted into byte sequences can be endian-dependent (by using +// native byte order) or independent (by consistently using either LE or BE byte +// order). It can also be `isize` and `usize` size dependent (by using the +// native size), or independent (by converting to a common size), supposing the +// values can be represented in 32 bits. +// +// In order to make SipHasher128 consistent with SipHasher in libstd, we choose +// to do the integer to byte sequence conversion in the platform-dependent way. +// Clients can achieve (nearly) platform-independent hashing by widening `isize` +// and `usize` integers to 64 bits on 32-bit systems and byte-swapping integers +// on big-endian systems before passing them to the writing functions. This +// causes the input byte sequence to look identical on big- and little- endian +// systems (supposing `isize` and `usize` values can be represented in 32 bits), +// which ensures platform-independent results. impl SipHasher128 { #[inline] pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher128 { - let mut state = SipHasher128 { - k0: key0, - k1: key1, - length: 0, - state: State { v0: 0, v1: 0, v2: 0, v3: 0 }, - tail: 0, - ntail: 0, + let mut hasher = SipHasher128 { + nbuf: 0, + buf: MaybeUninit::uninit_array(), + state: State { + v0: key0 ^ 0x736f6d6570736575, + // The XOR with 0xee is only done on 128-bit algorithm version. + v1: key1 ^ (0x646f72616e646f6d ^ 0xee), + v2: key0 ^ 0x6c7967656e657261, + v3: key1 ^ 0x7465646279746573, + }, + processed: 0, }; - state.reset(); - state - } - #[inline] - fn reset(&mut self) { - self.length = 0; - self.state.v0 = self.k0 ^ 0x736f6d6570736575; - self.state.v1 = self.k1 ^ 0x646f72616e646f6d; - self.state.v2 = self.k0 ^ 0x6c7967656e657261; - self.state.v3 = self.k1 ^ 0x7465646279746573; - self.ntail = 0; + unsafe { + // Initialize spill because we read from it in short_write_process_buffer. + *hasher.buf.get_unchecked_mut(BUFFER_SPILL_INDEX) = MaybeUninit::zeroed(); + } - // This is only done in the 128 bit version: - self.state.v1 ^= 0xee; + hasher } // A specialized write function for values with size <= 8. - // - // The input must be zero-extended to 64-bits by the caller. This extension - // isn't hashed, but the implementation requires it for correctness. - // - // This function, given the same integer size and value, has the same effect - // on both little- and big-endian hardware. It operates on values without - // depending on their sequence in memory, so is independent of endianness. - // - // However, we want SipHasher128 to be platform-dependent, in order to be - // consistent with the platform-dependent SipHasher in libstd. In other - // words, we want: - // - // - little-endian: `write_u32(0xDDCCBBAA)` == `write([0xAA, 0xBB, 0xCC, 0xDD])` - // - big-endian: `write_u32(0xDDCCBBAA)` == `write([0xDD, 0xCC, 0xBB, 0xAA])` - // - // Therefore, in order to produce endian-dependent results, SipHasher128's - // `write_xxx` Hasher trait methods byte-swap `x` prior to zero-extending. - // - // If clients of SipHasher128 itself want platform-independent results, they - // *also* must byte-swap integer inputs before invoking the `write_xxx` - // methods on big-endian hardware (that is, two byte-swaps must occur--one - // in the client, and one in SipHasher128). Additionally, they must extend - // `usize` and `isize` types to 64 bits on 32-bit systems. #[inline] - fn short_write(&mut self, _x: T, x: u64) { + fn short_write(&mut self, x: T) { let size = mem::size_of::(); - self.length += size; + let nbuf = self.nbuf; + debug_assert!(size <= 8); + debug_assert!(nbuf < BUFFER_SIZE_BYTES); + debug_assert!(nbuf + size < BUFFER_SIZE_BYTES_SPILL); - // The original number must be zero-extended, not sign-extended. - debug_assert!(if size < 8 { x >> (8 * size) == 0 } else { true }); + if nbuf + size < BUFFER_SIZE_BYTES { + unsafe { + // The memcpy call is optimized away because the size is known. + let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); + ptr::copy_nonoverlapping(&x as *const _ as *const u8, dst, size); + } - // The number of bytes needed to fill `self.tail`. - let needed = 8 - self.ntail; + self.nbuf = nbuf + size; - // SipHash parses the input stream as 8-byte little-endian integers. - // Inputs are put into `self.tail` until 8 bytes of data have been - // collected, and then that word is processed. - // - // For example, imagine that `self.tail` is 0x0000_00EE_DDCC_BBAA, - // `self.ntail` is 5 (because 5 bytes have been put into `self.tail`), - // and `needed` is therefore 3. - // - // - Scenario 1, `self.write_u8(0xFF)`: we have already zero-extended - // the input to 0x0000_0000_0000_00FF. We now left-shift it five - // bytes, giving 0x0000_FF00_0000_0000. We then bitwise-OR that value - // into `self.tail`, resulting in 0x0000_FFEE_DDCC_BBAA. - // (Zero-extension of the original input is critical in this scenario - // because we don't want the high two bytes of `self.tail` to be - // touched by the bitwise-OR.) `self.tail` is not yet full, so we - // return early, after updating `self.ntail` to 6. - // - // - Scenario 2, `self.write_u32(0xIIHH_GGFF)`: we have already - // zero-extended the input to 0x0000_0000_IIHH_GGFF. We now - // left-shift it five bytes, giving 0xHHGG_FF00_0000_0000. We then - // bitwise-OR that value into `self.tail`, resulting in - // 0xHHGG_FFEE_DDCC_BBAA. `self.tail` is now full, and we can use it - // to update `self.state`. (As mentioned above, this assumes a - // little-endian machine; on a big-endian machine we would have - // byte-swapped 0xIIHH_GGFF in the caller, giving 0xFFGG_HHII, and we - // would then end up bitwise-ORing 0xGGHH_II00_0000_0000 into - // `self.tail`). - // - self.tail |= x << (8 * self.ntail); - if size < needed { - self.ntail += size; return; } - // `self.tail` is full, process it. - self.state.v3 ^= self.tail; - Sip24Rounds::c_rounds(&mut self.state); - self.state.v0 ^= self.tail; + unsafe { self.short_write_process_buffer(x) } + } - // Continuing scenario 2: we have one byte left over from the input. We - // set `self.ntail` to 1 and `self.tail` to `0x0000_0000_IIHH_GGFF >> - // 8*3`, which is 0x0000_0000_0000_00II. (Or on a big-endian machine - // the prior byte-swapping would leave us with 0x0000_0000_0000_00FF.) - // - // The `if` is needed to avoid shifting by 64 bits, which Rust - // complains about. - self.ntail = size - needed; - self.tail = if needed < 8 { x >> (8 * needed) } else { 0 }; + // A specialized write function for values with size <= 8 that should only + // be called when the write would cause the buffer to fill. + // + // SAFETY: the write of x into self.buf starting at byte offset self.nbuf + // must cause self.buf to become fully initialized (and not overflow) if it + // wasn't already. + #[inline(never)] + unsafe fn short_write_process_buffer(&mut self, x: T) { + let size = mem::size_of::(); + let nbuf = self.nbuf; + debug_assert!(size <= 8); + debug_assert!(nbuf < BUFFER_SIZE_BYTES); + debug_assert!(nbuf + size >= BUFFER_SIZE_BYTES); + debug_assert!(nbuf + size < BUFFER_SIZE_BYTES_SPILL); + + // Copy first part of input into end of buffer, possibly into spill + // element. The memcpy call is optimized away because the size is known. + let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); + ptr::copy_nonoverlapping(&x as *const _ as *const u8, dst, size); + + // Process buffer. + for i in 0..BUFFER_SIZE_ELEMS { + let elem = self.buf.get_unchecked(i).assume_init().to_le(); + self.state.v3 ^= elem; + Sip24Rounds::c_rounds(&mut self.state); + self.state.v0 ^= elem; + } + + // Copy remaining input into start of buffer by copying size - 1 + // elements from spill (at most size - 1 bytes could have overflowed + // into the spill). The memcpy call is optimized away because the size + // is known. And the whole copy is optimized away for size == 1. + let src = self.buf.get_unchecked(BUFFER_SPILL_INDEX) as *const _ as *const u8; + ptr::copy_nonoverlapping(src, self.buf.as_mut_ptr() as *mut u8, size - 1); + + // This function should only be called when the write fills the buffer. + // Therefore, when size == 1, the new self.nbuf must be zero. The size + // is statically known, so the branch is optimized away. + self.nbuf = if size == 1 { 0 } else { nbuf + size - BUFFER_SIZE_BYTES }; + self.processed += BUFFER_SIZE_BYTES; + } + + // A write function for byte slices. + #[inline] + fn slice_write(&mut self, msg: &[u8]) { + let length = msg.len(); + let nbuf = self.nbuf; + debug_assert!(nbuf < BUFFER_SIZE_BYTES); + + if nbuf + length < BUFFER_SIZE_BYTES { + unsafe { + let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); + + if length < 8 { + copy_nonoverlapping_small(msg.as_ptr(), dst, length); + } else { + // This memcpy is *not* optimized away. + ptr::copy_nonoverlapping(msg.as_ptr(), dst, length); + } + } + + self.nbuf = nbuf + length; + + return; + } + + unsafe { self.slice_write_process_buffer(msg) } + } + + // A write function for byte slices that should only be called when the + // write would cause the buffer to fill. + // + // SAFETY: self.buf must be initialized up to the byte offset self.nbuf, and + // msg must contain enough bytes to initialize the rest of the element + // containing the byte offset self.nbuf. + #[inline(never)] + unsafe fn slice_write_process_buffer(&mut self, msg: &[u8]) { + let length = msg.len(); + let nbuf = self.nbuf; + debug_assert!(nbuf < BUFFER_SIZE_BYTES); + debug_assert!(nbuf + length >= BUFFER_SIZE_BYTES); + + // Always copy first part of input into current element of buffer. + // This function should only be called when the write fills the buffer, + // so we know that there is enough input to fill the current element. + let valid_in_elem = nbuf & 0x7; + let needed_in_elem = 8 - valid_in_elem; + + let src = msg.as_ptr(); + let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); + copy_nonoverlapping_small(src, dst, needed_in_elem); + + // Process buffer. + + // Using nbuf / 8 + 1 rather than (nbuf + needed_in_elem) / 8 to show + // the compiler that this loop's upper bound is > 0. We know that is + // true, because last step ensured we have a full element in the buffer. + let last = nbuf / 8 + 1; + + for i in 0..last { + let elem = self.buf.get_unchecked(i).assume_init().to_le(); + self.state.v3 ^= elem; + Sip24Rounds::c_rounds(&mut self.state); + self.state.v0 ^= elem; + } + + // Process the remaining u64-sized chunks of input. + let mut processed = needed_in_elem; + let input_left = length - processed; + let u64s_left = input_left / 8; + let u8s_left = input_left & 0x7; + + for _ in 0..u64s_left { + let elem = (msg.as_ptr().add(processed) as *const u64).read_unaligned().to_le(); + self.state.v3 ^= elem; + Sip24Rounds::c_rounds(&mut self.state); + self.state.v0 ^= elem; + processed += 8; + } + + // Copy remaining input into start of buffer. + let src = msg.as_ptr().add(processed); + let dst = self.buf.as_mut_ptr() as *mut u8; + copy_nonoverlapping_small(src, dst, u8s_left); + + self.nbuf = u8s_left; + self.processed += nbuf + processed; } #[inline] pub fn finish128(mut self) -> (u64, u64) { - let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail; + debug_assert!(self.nbuf < BUFFER_SIZE_BYTES); - self.state.v3 ^= b; - Sip24Rounds::c_rounds(&mut self.state); - self.state.v0 ^= b; + // Process full elements in buffer. + let last = self.nbuf / 8; - self.state.v2 ^= 0xee; - Sip24Rounds::d_rounds(&mut self.state); - let _0 = self.state.v0 ^ self.state.v1 ^ self.state.v2 ^ self.state.v3; + // Since we're consuming self, avoid updating members for a potential + // performance gain. + let mut state = self.state; + + for i in 0..last { + let elem = unsafe { self.buf.get_unchecked(i).assume_init().to_le() }; + state.v3 ^= elem; + Sip24Rounds::c_rounds(&mut state); + state.v0 ^= elem; + } + + // Get remaining partial element. + let elem = if self.nbuf % 8 != 0 { + unsafe { + // Ensure element is initialized by writing zero bytes. At most + // seven are required given the above check. It's safe to write + // this many because we have the spill element and we maintain + // self.nbuf such that this write will start before the spill. + let dst = (self.buf.as_mut_ptr() as *mut u8).add(self.nbuf); + ptr::write_bytes(dst, 0, 7); + self.buf.get_unchecked(last).assume_init().to_le() + } + } else { + 0 + }; + + // Finalize the hash. + let length = self.processed + self.nbuf; + let b: u64 = ((length as u64 & 0xff) << 56) | elem; + + state.v3 ^= b; + Sip24Rounds::c_rounds(&mut state); + state.v0 ^= b; + + state.v2 ^= 0xee; + Sip24Rounds::d_rounds(&mut state); + let _0 = state.v0 ^ state.v1 ^ state.v2 ^ state.v3; + + state.v1 ^= 0xdd; + Sip24Rounds::d_rounds(&mut state); + let _1 = state.v0 ^ state.v1 ^ state.v2 ^ state.v3; - self.state.v1 ^= 0xdd; - Sip24Rounds::d_rounds(&mut self.state); - let _1 = self.state.v0 ^ self.state.v1 ^ self.state.v2 ^ self.state.v3; (_0, _1) } } @@ -230,92 +372,57 @@ impl SipHasher128 { impl Hasher for SipHasher128 { #[inline] fn write_u8(&mut self, i: u8) { - self.short_write(i, i as u64); + self.short_write(i); } #[inline] fn write_u16(&mut self, i: u16) { - self.short_write(i, i.to_le() as u64); + self.short_write(i); } #[inline] fn write_u32(&mut self, i: u32) { - self.short_write(i, i.to_le() as u64); + self.short_write(i); } #[inline] fn write_u64(&mut self, i: u64) { - self.short_write(i, i.to_le() as u64); + self.short_write(i); } #[inline] fn write_usize(&mut self, i: usize) { - self.short_write(i, i.to_le() as u64); + self.short_write(i); } #[inline] fn write_i8(&mut self, i: i8) { - self.short_write(i, i as u8 as u64); + self.short_write(i as u8); } #[inline] fn write_i16(&mut self, i: i16) { - self.short_write(i, (i as u16).to_le() as u64); + self.short_write(i as u16); } #[inline] fn write_i32(&mut self, i: i32) { - self.short_write(i, (i as u32).to_le() as u64); + self.short_write(i as u32); } #[inline] fn write_i64(&mut self, i: i64) { - self.short_write(i, (i as u64).to_le() as u64); + self.short_write(i as u64); } #[inline] fn write_isize(&mut self, i: isize) { - self.short_write(i, (i as usize).to_le() as u64); + self.short_write(i as usize); } #[inline] fn write(&mut self, msg: &[u8]) { - let length = msg.len(); - self.length += length; - - let mut needed = 0; - - if self.ntail != 0 { - needed = 8 - self.ntail; - self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << (8 * self.ntail); - if length < needed { - self.ntail += length; - return; - } else { - self.state.v3 ^= self.tail; - Sip24Rounds::c_rounds(&mut self.state); - self.state.v0 ^= self.tail; - self.ntail = 0; - } - } - - // Buffered tail is now flushed, process new input. - let len = length - needed; - let left = len & 0x7; - - let mut i = needed; - while i < len - left { - let mi = unsafe { load_int_le!(msg, i, u64) }; - - self.state.v3 ^= mi; - Sip24Rounds::c_rounds(&mut self.state); - self.state.v0 ^= mi; - - i += 8; - } - - self.tail = unsafe { u8to64_le(msg, i, left) }; - self.ntail = left; + self.slice_write(msg); } fn finish(&self) -> u64 { diff --git a/compiler/rustc_data_structures/src/sip128/tests.rs b/compiler/rustc_data_structures/src/sip128/tests.rs index 2e2274a7b77..eda7ddc4f6d 100644 --- a/compiler/rustc_data_structures/src/sip128/tests.rs +++ b/compiler/rustc_data_structures/src/sip128/tests.rs @@ -450,3 +450,48 @@ fn test_short_write_works() { assert_eq!(h1_hash, h2_hash); } + +macro_rules! test_fill_buffer { + ($type:ty, $write_method:ident) => {{ + // Test filling and overfilling the buffer from all possible offsets + // for a given integer type and its corresponding write method. + const SIZE: usize = std::mem::size_of::<$type>(); + let input = [42; BUFFER_SIZE_BYTES]; + let x = 0x01234567_89ABCDEF_76543210_FEDCBA98_u128 as $type; + let x_bytes = &x.to_ne_bytes(); + + for i in 1..=SIZE { + let s = &input[..BUFFER_SIZE_BYTES - i]; + + let mut h1 = SipHasher128::new_with_keys(7, 13); + h1.write(s); + h1.$write_method(x); + + let mut h2 = SipHasher128::new_with_keys(7, 13); + h2.write(s); + h2.write(x_bytes); + + let h1_hash = h1.finish128(); + let h2_hash = h2.finish128(); + + assert_eq!(h1_hash, h2_hash); + } + }}; +} + +#[test] +fn test_fill_buffer() { + test_fill_buffer!(u8, write_u8); + test_fill_buffer!(u16, write_u16); + test_fill_buffer!(u32, write_u32); + test_fill_buffer!(u64, write_u64); + test_fill_buffer!(u128, write_u128); + test_fill_buffer!(usize, write_usize); + + test_fill_buffer!(i8, write_i8); + test_fill_buffer!(i16, write_i16); + test_fill_buffer!(i32, write_i32); + test_fill_buffer!(i64, write_i64); + test_fill_buffer!(i128, write_i128); + test_fill_buffer!(isize, write_isize); +} From d727f642b939305ed7a68e5f74875d4d52304ebf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Oct 2020 15:25:26 +0200 Subject: [PATCH 059/446] stop promoting union field accesses in 'const' --- .../rustc_mir/src/transform/promote_consts.rs | 34 ++++++++----------- src/test/ui/consts/promote-not.rs | 5 +++ src/test/ui/consts/promote-not.stderr | 12 ++++++- 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index 89f7531b3a7..32c18c80b24 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -294,17 +294,6 @@ impl std::ops::Deref for Validator<'a, 'tcx> { struct Unpromotable; impl<'tcx> Validator<'_, 'tcx> { - /// Determines if this code could be executed at runtime and thus is subject to codegen. - /// That means even unused constants need to be evaluated. - /// - /// `const_kind` should not be used in this file other than through this method! - fn maybe_runtime(&self) -> bool { - match self.const_kind { - None | Some(hir::ConstContext::ConstFn) => true, - Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) => false, - } - } - fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> { match candidate { Candidate::Ref(loc) => { @@ -555,14 +544,12 @@ impl<'tcx> Validator<'_, 'tcx> { } ProjectionElem::Field(..) => { - if self.maybe_runtime() { - let base_ty = - Place::ty_from(place.local, proj_base, self.body, self.tcx).ty; - if let Some(def) = base_ty.ty_adt_def() { - // No promotion of union field accesses. - if def.is_union() { - return Err(Unpromotable); - } + let base_ty = + Place::ty_from(place.local, proj_base, self.body, self.tcx).ty; + if let Some(def) = base_ty.ty_adt_def() { + // No promotion of union field accesses. + if def.is_union() { + return Err(Unpromotable); } } } @@ -744,7 +731,14 @@ impl<'tcx> Validator<'_, 'tcx> { ) -> Result<(), Unpromotable> { let fn_ty = callee.ty(self.body, self.tcx); - if !self.explicit && self.maybe_runtime() { + // When doing explicit promotion and inside const/static items, we promote all (eligible) function calls. + // Everywhere else, we require `#[rustc_promotable]` on the callee. + let promote_all_const_fn = self.explicit + || matches!( + self.const_kind, + Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) + ); + if !promote_all_const_fn { if let ty::FnDef(def_id, _) = *fn_ty.kind() { // Never promote runtime `const fn` calls of // functions without `#[rustc_promotable]`. diff --git a/src/test/ui/consts/promote-not.rs b/src/test/ui/consts/promote-not.rs index 8daac758377..30bb9917bf7 100644 --- a/src/test/ui/consts/promote-not.rs +++ b/src/test/ui/consts/promote-not.rs @@ -27,4 +27,9 @@ pub const fn promote_union() { let _x: &'static i32 = &unsafe { U { x: 0 }.x }; //~ ERROR temporary value dropped while borrowed } +// We do not promote union field accesses in `const`, either. +const TEST_UNION: () = { + let _x: &'static i32 = &unsafe { U { x: 0 }.x }; //~ ERROR temporary value dropped while borrowed +}; + fn main() {} diff --git a/src/test/ui/consts/promote-not.stderr b/src/test/ui/consts/promote-not.stderr index efe921b6011..6ca7a4c273e 100644 --- a/src/test/ui/consts/promote-not.stderr +++ b/src/test/ui/consts/promote-not.stderr @@ -38,6 +38,16 @@ LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x }; LL | } | - temporary value is freed at the end of this statement -error: aborting due to 4 previous errors +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:32:29 + | +LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x }; + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | }; + | - temporary value is freed at the end of this statement + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0716`. From b86161ad9c2ba27d8b2c899a7adead7d4ebd54bd Mon Sep 17 00:00:00 2001 From: Tyson Nottingham Date: Sun, 4 Oct 2020 19:39:17 -0700 Subject: [PATCH 060/446] SipHasher128: use more named constants, update comments --- compiler/rustc_data_structures/src/sip128.rs | 104 ++++++++++--------- 1 file changed, 54 insertions(+), 50 deletions(-) diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs index 4acb0e69e99..8b91407acff 100644 --- a/compiler/rustc_data_structures/src/sip128.rs +++ b/compiler/rustc_data_structures/src/sip128.rs @@ -7,10 +7,11 @@ use std::ptr; #[cfg(test)] mod tests; +const ELEM_SIZE: usize = mem::size_of::(); const BUFFER_SIZE_ELEMS: usize = 8; -const BUFFER_SIZE_BYTES: usize = BUFFER_SIZE_ELEMS * mem::size_of::(); +const BUFFER_SIZE_BYTES: usize = BUFFER_SIZE_ELEMS * ELEM_SIZE; const BUFFER_SIZE_ELEMS_SPILL: usize = BUFFER_SIZE_ELEMS + 1; -const BUFFER_SIZE_BYTES_SPILL: usize = BUFFER_SIZE_ELEMS_SPILL * mem::size_of::(); +const BUFFER_SIZE_BYTES_SPILL: usize = BUFFER_SIZE_ELEMS_SPILL * ELEM_SIZE; const BUFFER_SPILL_INDEX: usize = BUFFER_SIZE_ELEMS_SPILL - 1; #[derive(Debug, Clone)] @@ -54,15 +55,16 @@ macro_rules! compress { }}; } -// Copies up to 8 bytes from source to destination. This may be faster than -// calling `ptr::copy_nonoverlapping` with an arbitrary count, since all of -// the copies have fixed sizes and thus avoid calling memcpy. +// Copies up to 8 bytes from source to destination. This performs better than +// `ptr::copy_nonoverlapping` on microbenchmarks and may perform better on real +// workloads since all of the copies have fixed sizes and avoid calling memcpy. #[inline] unsafe fn copy_nonoverlapping_small(src: *const u8, dst: *mut u8, count: usize) { - debug_assert!(count <= 8); + const COUNT_MAX: usize = 8; + debug_assert!(count <= COUNT_MAX); - if count == 8 { - ptr::copy_nonoverlapping(src, dst, 8); + if count == COUNT_MAX { + ptr::copy_nonoverlapping(src, dst, COUNT_MAX); return; } @@ -85,7 +87,7 @@ unsafe fn copy_nonoverlapping_small(src: *const u8, dst: *mut u8, count: usize) debug_assert_eq!(i, count); } -// Implementation +// # Implementation // // This implementation uses buffering to reduce the hashing cost for inputs // consisting of many small integers. Buffering simplifies the integration of @@ -99,10 +101,11 @@ unsafe fn copy_nonoverlapping_small(src: *const u8, dst: *mut u8, count: usize) // // When a write fills the buffer, a buffer processing function is invoked to // hash all of the buffered input. The buffer processing functions are marked -// #[inline(never)] so that they aren't inlined into the append functions, which -// ensures the more frequently called append functions remain inlineable and -// don't include register pushing/popping that would only be made necessary by -// inclusion of the complex buffer processing path which uses those registers. +// `#[inline(never)]` so that they aren't inlined into the append functions, +// which ensures the more frequently called append functions remain inlineable +// and don't include register pushing/popping that would only be made necessary +// by inclusion of the complex buffer processing path which uses those +// registers. // // The buffer includes a "spill"--an extra element at the end--which simplifies // the integer write buffer processing path. The value that fills the buffer can @@ -118,7 +121,7 @@ unsafe fn copy_nonoverlapping_small(src: *const u8, dst: *mut u8, count: usize) // efficiently implemented with an uninitialized buffer. On the other hand, an // uninitialized buffer may become more important should a larger one be used. // -// Platform Dependence +// # Platform Dependence // // The SipHash algorithm operates on byte sequences. It parses the input stream // as 8-byte little-endian integers. Therefore, given the same byte sequence, it @@ -131,14 +134,14 @@ unsafe fn copy_nonoverlapping_small(src: *const u8, dst: *mut u8, count: usize) // native size), or independent (by converting to a common size), supposing the // values can be represented in 32 bits. // -// In order to make SipHasher128 consistent with SipHasher in libstd, we choose -// to do the integer to byte sequence conversion in the platform-dependent way. -// Clients can achieve (nearly) platform-independent hashing by widening `isize` -// and `usize` integers to 64 bits on 32-bit systems and byte-swapping integers -// on big-endian systems before passing them to the writing functions. This -// causes the input byte sequence to look identical on big- and little- endian -// systems (supposing `isize` and `usize` values can be represented in 32 bits), -// which ensures platform-independent results. +// In order to make `SipHasher128` consistent with `SipHasher` in libstd, we +// choose to do the integer to byte sequence conversion in the platform- +// dependent way. Clients can achieve (nearly) platform-independent hashing by +// widening `isize` and `usize` integers to 64 bits on 32-bit systems and +// byte-swapping integers on big-endian systems before passing them to the +// writing functions. This causes the input byte sequence to look identical on +// big- and little- endian systems (supposing `isize` and `usize` values can be +// represented in 32 bits), which ensures platform-independent results. impl SipHasher128 { #[inline] pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher128 { @@ -156,7 +159,7 @@ impl SipHasher128 { }; unsafe { - // Initialize spill because we read from it in short_write_process_buffer. + // Initialize spill because we read from it in `short_write_process_buffer`. *hasher.buf.get_unchecked_mut(BUFFER_SPILL_INDEX) = MaybeUninit::zeroed(); } @@ -190,9 +193,9 @@ impl SipHasher128 { // A specialized write function for values with size <= 8 that should only // be called when the write would cause the buffer to fill. // - // SAFETY: the write of x into self.buf starting at byte offset self.nbuf - // must cause self.buf to become fully initialized (and not overflow) if it - // wasn't already. + // SAFETY: the write of `x` into `self.buf` starting at byte offset + // `self.nbuf` must cause `self.buf` to become fully initialized (and not + // overflow) if it wasn't already. #[inline(never)] unsafe fn short_write_process_buffer(&mut self, x: T) { let size = mem::size_of::(); @@ -223,7 +226,7 @@ impl SipHasher128 { ptr::copy_nonoverlapping(src, self.buf.as_mut_ptr() as *mut u8, size - 1); // This function should only be called when the write fills the buffer. - // Therefore, when size == 1, the new self.nbuf must be zero. The size + // Therefore, when size == 1, the new `self.nbuf` must be zero. The size // is statically known, so the branch is optimized away. self.nbuf = if size == 1 { 0 } else { nbuf + size - BUFFER_SIZE_BYTES }; self.processed += BUFFER_SIZE_BYTES; @@ -240,7 +243,7 @@ impl SipHasher128 { unsafe { let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); - if length < 8 { + if length <= 8 { copy_nonoverlapping_small(msg.as_ptr(), dst, length); } else { // This memcpy is *not* optimized away. @@ -259,9 +262,9 @@ impl SipHasher128 { // A write function for byte slices that should only be called when the // write would cause the buffer to fill. // - // SAFETY: self.buf must be initialized up to the byte offset self.nbuf, and - // msg must contain enough bytes to initialize the rest of the element - // containing the byte offset self.nbuf. + // SAFETY: `self.buf` must be initialized up to the byte offset `self.nbuf`, + // and `msg` must contain enough bytes to initialize the rest of the element + // containing the byte offset `self.nbuf`. #[inline(never)] unsafe fn slice_write_process_buffer(&mut self, msg: &[u8]) { let length = msg.len(); @@ -272,8 +275,8 @@ impl SipHasher128 { // Always copy first part of input into current element of buffer. // This function should only be called when the write fills the buffer, // so we know that there is enough input to fill the current element. - let valid_in_elem = nbuf & 0x7; - let needed_in_elem = 8 - valid_in_elem; + let valid_in_elem = nbuf % ELEM_SIZE; + let needed_in_elem = ELEM_SIZE - valid_in_elem; let src = msg.as_ptr(); let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); @@ -281,10 +284,11 @@ impl SipHasher128 { // Process buffer. - // Using nbuf / 8 + 1 rather than (nbuf + needed_in_elem) / 8 to show - // the compiler that this loop's upper bound is > 0. We know that is - // true, because last step ensured we have a full element in the buffer. - let last = nbuf / 8 + 1; + // Using `nbuf / ELEM_SIZE + 1` rather than `(nbuf + needed_in_elem) / + // ELEM_SIZE` to show the compiler that this loop's upper bound is > 0. + // We know that is true, because last step ensured we have a full + // element in the buffer. + let last = nbuf / ELEM_SIZE + 1; for i in 0..last { let elem = self.buf.get_unchecked(i).assume_init().to_le(); @@ -293,26 +297,26 @@ impl SipHasher128 { self.state.v0 ^= elem; } - // Process the remaining u64-sized chunks of input. + // Process the remaining element-sized chunks of input. let mut processed = needed_in_elem; let input_left = length - processed; - let u64s_left = input_left / 8; - let u8s_left = input_left & 0x7; + let elems_left = input_left / ELEM_SIZE; + let extra_bytes_left = input_left % ELEM_SIZE; - for _ in 0..u64s_left { + for _ in 0..elems_left { let elem = (msg.as_ptr().add(processed) as *const u64).read_unaligned().to_le(); self.state.v3 ^= elem; Sip24Rounds::c_rounds(&mut self.state); self.state.v0 ^= elem; - processed += 8; + processed += ELEM_SIZE; } // Copy remaining input into start of buffer. let src = msg.as_ptr().add(processed); let dst = self.buf.as_mut_ptr() as *mut u8; - copy_nonoverlapping_small(src, dst, u8s_left); + copy_nonoverlapping_small(src, dst, extra_bytes_left); - self.nbuf = u8s_left; + self.nbuf = extra_bytes_left; self.processed += nbuf + processed; } @@ -321,7 +325,7 @@ impl SipHasher128 { debug_assert!(self.nbuf < BUFFER_SIZE_BYTES); // Process full elements in buffer. - let last = self.nbuf / 8; + let last = self.nbuf / ELEM_SIZE; // Since we're consuming self, avoid updating members for a potential // performance gain. @@ -335,14 +339,14 @@ impl SipHasher128 { } // Get remaining partial element. - let elem = if self.nbuf % 8 != 0 { + let elem = if self.nbuf % ELEM_SIZE != 0 { unsafe { // Ensure element is initialized by writing zero bytes. At most - // seven are required given the above check. It's safe to write - // this many because we have the spill element and we maintain - // self.nbuf such that this write will start before the spill. + // `ELEM_SIZE - 1` are required given the above check. It's safe + // to write this many because we have the spill and we maintain + // `self.nbuf` such that this write will start before the spill. let dst = (self.buf.as_mut_ptr() as *mut u8).add(self.nbuf); - ptr::write_bytes(dst, 0, 7); + ptr::write_bytes(dst, 0, ELEM_SIZE - 1); self.buf.get_unchecked(last).assume_init().to_le() } } else { From 581cc4abf5dd2802914cf4fee832cda2ae7a89a0 Mon Sep 17 00:00:00 2001 From: Tyson Nottingham Date: Mon, 5 Oct 2020 00:47:44 -0700 Subject: [PATCH 061/446] SipHasher128: use specific struct layout --- compiler/rustc_data_structures/src/sip128.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs index 8b91407acff..5bbc53945ed 100644 --- a/compiler/rustc_data_structures/src/sip128.rs +++ b/compiler/rustc_data_structures/src/sip128.rs @@ -15,7 +15,13 @@ const BUFFER_SIZE_BYTES_SPILL: usize = BUFFER_SIZE_ELEMS_SPILL * ELEM_SIZE; const BUFFER_SPILL_INDEX: usize = BUFFER_SIZE_ELEMS_SPILL - 1; #[derive(Debug, Clone)] +#[repr(C)] pub struct SipHasher128 { + // The access pattern during hashing consists of accesses to `nbuf` and + // `buf` until the buffer is full, followed by accesses to `state` and + // `processed`, and then repetition of that pattern until hashing is done. + // This is the basis for the ordering of fields below. However, in practice + // the cache miss-rate for data access is extremely low regardless of order. nbuf: usize, // how many bytes in buf are valid buf: [MaybeUninit; BUFFER_SIZE_ELEMS_SPILL], // unprocessed bytes le state: State, // hash State From 9c302f55bd07a04305dfa2bd815d2559deb8468f Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 28 Sep 2020 20:56:52 +0200 Subject: [PATCH 062/446] normalize in codegen_fulfill_obligations --- compiler/rustc_trait_selection/src/traits/codegen/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/codegen/mod.rs b/compiler/rustc_trait_selection/src/traits/codegen/mod.rs index dd7ea55cc10..753d64d6115 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen/mod.rs @@ -19,11 +19,11 @@ use rustc_middle::ty::{self, TyCtxt}; /// obligations *could be* resolved if we wanted to. /// Assumes that this is run after the entire crate has been successfully type-checked. pub fn codegen_fulfill_obligation<'tcx>( - ty: TyCtxt<'tcx>, + tcx: TyCtxt<'tcx>, (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), ) -> Result, ErrorReported> { - // Remove any references to regions; this helps improve caching. - let trait_ref = ty.erase_regions(&trait_ref); + // Remove any references to regions and normalize; this helps improve caching. + let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref); debug!( "codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})", @@ -33,7 +33,7 @@ pub fn codegen_fulfill_obligation<'tcx>( // Do the initial selection for the obligation. This yields the // shallow result we are looking for -- that is, what specific impl. - ty.infer_ctxt().enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let mut selcx = SelectionContext::new(&infcx); let obligation_cause = ObligationCause::dummy(); From f0487cee7439f3a4b4c7daec0e7f2a0ccc21053c Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 4 Oct 2020 16:40:06 +0200 Subject: [PATCH 063/446] normalize substs during inlining --- compiler/rustc_mir/src/transform/inline.rs | 10 +++++++--- .../src/traits/codegen/mod.rs | 9 ++++++--- src/test/ui/mir/mir-inlining/ice-issue-77306.rs | 17 +++++++++++++++++ 3 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/mir/mir-inlining/ice-issue-77306.rs diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index bec1eb79047..e0bd4e8b68b 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -201,9 +201,13 @@ impl Inliner<'tcx> { let terminator = bb_data.terminator(); if let TerminatorKind::Call { func: ref op, .. } = terminator.kind { if let ty::FnDef(callee_def_id, substs) = *op.ty(caller_body, self.tcx).kind() { - let instance = Instance::resolve(self.tcx, self.param_env, callee_def_id, substs) - .ok() - .flatten()?; + // To resolve an instance its substs have to be fully normalized, so + // we do this here. + let normalized_substs = self.tcx.normalize_erasing_regions(self.param_env, substs); + let instance = + Instance::resolve(self.tcx, self.param_env, callee_def_id, normalized_substs) + .ok() + .flatten()?; if let InstanceDef::Virtual(..) = instance.def { return None; diff --git a/compiler/rustc_trait_selection/src/traits/codegen/mod.rs b/compiler/rustc_trait_selection/src/traits/codegen/mod.rs index 753d64d6115..05e6c4804ff 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen/mod.rs @@ -17,14 +17,17 @@ use rustc_middle::ty::{self, TyCtxt}; /// (necessarily) resolve all nested obligations on the impl. Note /// that type check should guarantee to us that all nested /// obligations *could be* resolved if we wanted to. +/// /// Assumes that this is run after the entire crate has been successfully type-checked. +/// This also expects that `trait_ref` is fully normalized. pub fn codegen_fulfill_obligation<'tcx>( tcx: TyCtxt<'tcx>, (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), ) -> Result, ErrorReported> { - // Remove any references to regions and normalize; this helps improve caching. - let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref); - + // Remove any references to regions; this helps improve caching. + let trait_ref = tcx.erase_regions(&trait_ref); + // We expect the input to be fully normalized. + debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref)); debug!( "codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})", (param_env, trait_ref), diff --git a/src/test/ui/mir/mir-inlining/ice-issue-77306.rs b/src/test/ui/mir/mir-inlining/ice-issue-77306.rs new file mode 100644 index 00000000000..4d083bf2321 --- /dev/null +++ b/src/test/ui/mir/mir-inlining/ice-issue-77306.rs @@ -0,0 +1,17 @@ +// run-pass +// compile-flags:-Zmir-opt-level=2 + +// Previously ICEd because we did not normalize during inlining, +// see https://github.com/rust-lang/rust/pull/77306 for more discussion. + +pub fn write() { + create()() +} + +pub fn create() -> impl FnOnce() { + || () +} + +fn main() { + write(); +} From 32739a2ff1b7b6e5c1b475341b01f4a499830a84 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 4 Oct 2020 22:42:01 +0200 Subject: [PATCH 064/446] add regression test --- .../ui/mir/mir-inlining/ice-issue-68347.rs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/test/ui/mir/mir-inlining/ice-issue-68347.rs diff --git a/src/test/ui/mir/mir-inlining/ice-issue-68347.rs b/src/test/ui/mir/mir-inlining/ice-issue-68347.rs new file mode 100644 index 00000000000..88b80bc3333 --- /dev/null +++ b/src/test/ui/mir/mir-inlining/ice-issue-68347.rs @@ -0,0 +1,28 @@ +// run-pass +// compile-flags:-Zmir-opt-level=2 +pub fn main() { + let _x: fn() = handle_debug_column; +} + +fn handle_debug_column() { + let sampler = sample_columns(); + + let foo = || { + sampler.get(17); + }; + foo(); +} + +fn sample_columns() -> impl Sampler { + ColumnGen {} +} + +struct ColumnGen {} + +trait Sampler { + fn get(&self, index: i32); +} + +impl Sampler for ColumnGen { + fn get(&self, _index: i32) {} +} From ac893b8a02788eec6f6fad0cc89de0177b0c0a50 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 6 Oct 2020 17:51:02 +0200 Subject: [PATCH 065/446] add test for should_inline incorrect param_env --- ...ce-issue-77306.rs => ice-issue-77306-1.rs} | 0 .../ui/mir/mir-inlining/ice-issue-77306-2.rs | 32 +++++++++++++++++++ 2 files changed, 32 insertions(+) rename src/test/ui/mir/mir-inlining/{ice-issue-77306.rs => ice-issue-77306-1.rs} (100%) create mode 100644 src/test/ui/mir/mir-inlining/ice-issue-77306-2.rs diff --git a/src/test/ui/mir/mir-inlining/ice-issue-77306.rs b/src/test/ui/mir/mir-inlining/ice-issue-77306-1.rs similarity index 100% rename from src/test/ui/mir/mir-inlining/ice-issue-77306.rs rename to src/test/ui/mir/mir-inlining/ice-issue-77306-1.rs diff --git a/src/test/ui/mir/mir-inlining/ice-issue-77306-2.rs b/src/test/ui/mir/mir-inlining/ice-issue-77306-2.rs new file mode 100644 index 00000000000..a346d450586 --- /dev/null +++ b/src/test/ui/mir/mir-inlining/ice-issue-77306-2.rs @@ -0,0 +1,32 @@ +// run-pass +// compile-flags:-Zmir-opt-level=2 + +struct Cursor {} +struct TokenTree {} + +impl Iterator for Cursor { + type Item = TokenTree; + + fn next(&mut self) -> Option { + None + } +} + +fn tokenstream_probably_equal_for_proc_macro() { + fn break_tokens(_tree: TokenTree) -> impl Iterator { + let token_trees: Vec = vec![]; + token_trees.into_iter() + } + + let c1 = Cursor {}; + let c2 = Cursor {}; + + let mut t1 = c1.flat_map(break_tokens); + let mut t2 = c2.flat_map(break_tokens); + + for (_t1, _t2) in t1.by_ref().zip(t2.by_ref()) {} +} + +fn main() { + tokenstream_probably_equal_for_proc_macro(); +} From 8f13705e3b5cb563cee1c43446c0a682514a6f15 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 4 Oct 2020 22:48:57 +0200 Subject: [PATCH 066/446] fix def collector for impl trait --- compiler/rustc_resolve/src/def_collector.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 5d5088de31b..d7a1d30b0e4 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -239,13 +239,13 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { fn visit_ty(&mut self, ty: &'a Ty) { match ty.kind { - TyKind::MacCall(..) => return self.visit_macro_invoc(ty.id), + TyKind::MacCall(..) => self.visit_macro_invoc(ty.id), TyKind::ImplTrait(node_id, _) => { - self.create_def(node_id, DefPathData::ImplTrait, ty.span); + let parent_def = self.create_def(node_id, DefPathData::ImplTrait, ty.span); + self.with_parent(parent_def, |this| visit::walk_ty(this, ty)); } - _ => {} + _ => visit::walk_ty(self, ty), } - visit::walk_ty(self, ty); } fn visit_stmt(&mut self, stmt: &'a Stmt) { From 5ac268c43557102dabcd3dc45b2bcaf01cb228ee Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 5 Oct 2020 00:25:51 +0200 Subject: [PATCH 067/446] do not lower patterns in impl Trait --- compiler/rustc_ast_lowering/src/lib.rs | 5 +++++ src/test/ui/impl-trait/closure-in-impl-trait.rs | 14 ++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 src/test/ui/impl-trait/closure-in-impl-trait.rs diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a28d022c661..64c034f7ec9 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -538,6 +538,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } self.visit_fn_ret_ty(&f.decl.output) } + TyKind::ImplTrait(_, ref bounds) => { + self.with_hir_id_owner(None, |this| { + walk_list!(this, visit_param_bound, bounds); + }); + } _ => visit::walk_ty(self, t), } } diff --git a/src/test/ui/impl-trait/closure-in-impl-trait.rs b/src/test/ui/impl-trait/closure-in-impl-trait.rs new file mode 100644 index 00000000000..3593a1d5c8d --- /dev/null +++ b/src/test/ui/impl-trait/closure-in-impl-trait.rs @@ -0,0 +1,14 @@ +// run-pass +#![allow(unused_must_use)] +fn bug() -> impl Iterator { + std::iter::empty() +} + +fn ok() -> Box> { + Box::new(std::iter::empty()) +} + +fn main() { + for _item in ok::() {} + for _item in bug::() {} +} From a5d2db4a58b4f3c196ed58d3a95cd7c7b61d746b Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 5 Oct 2020 01:19:58 +0200 Subject: [PATCH 068/446] arg position --- src/test/ui/impl-trait/closure-in-impl-trait-arg.rs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/test/ui/impl-trait/closure-in-impl-trait-arg.rs diff --git a/src/test/ui/impl-trait/closure-in-impl-trait-arg.rs b/src/test/ui/impl-trait/closure-in-impl-trait-arg.rs new file mode 100644 index 00000000000..3cfce459e37 --- /dev/null +++ b/src/test/ui/impl-trait/closure-in-impl-trait-arg.rs @@ -0,0 +1,7 @@ +// run-pass +#![allow(unused_must_use)] +fn bug(_: impl Iterator) {} + +fn main() { + bug(std::iter::empty()); +} From f865e3d22f93664c85059f88ceef433718c4f2f0 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 5 Oct 2020 01:27:10 +0200 Subject: [PATCH 069/446] bodge --- compiler/rustc_ast_lowering/src/lib.rs | 19 ++++++++++------ .../rustc_middle/src/hir/map/collector.rs | 22 +++++++++++++++++-- compiler/rustc_passes/src/hir_id_validator.rs | 12 ++++++++++ 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 64c034f7ec9..41e1aafd9bd 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -538,9 +538,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } self.visit_fn_ret_ty(&f.decl.output) } - TyKind::ImplTrait(_, ref bounds) => { - self.with_hir_id_owner(None, |this| { - walk_list!(this, visit_param_bound, bounds); + TyKind::ImplTrait(def_node_id, _) => { + self.lctx.allocate_hir_id_counter(def_node_id); + self.with_hir_id_owner(Some(def_node_id), |this| { + visit::walk_ty(this, t); }); } _ => visit::walk_ty(self, t), @@ -1351,10 +1352,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Add a definition for the in-band `Param`. let def_id = self.resolver.local_def_id(def_node_id); - let hir_bounds = self.lower_param_bounds( - bounds, - ImplTraitContext::Universal(in_band_ty_params), - ); + self.allocate_hir_id_counter(def_node_id); + + let hir_bounds = self.with_hir_id_owner(def_node_id, |this| { + this.lower_param_bounds( + bounds, + ImplTraitContext::Universal(in_band_ty_params), + ) + }); // Set the name to `impl Bound1 + Bound2`. let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span); in_band_ty_params.push(hir::GenericParam { diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs index d6869ab8875..516c9b6752b 100644 --- a/compiler/rustc_middle/src/hir/map/collector.rs +++ b/compiler/rustc_middle/src/hir/map/collector.rs @@ -360,8 +360,26 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { } fn visit_generic_param(&mut self, param: &'hir GenericParam<'hir>) { - self.insert(param.span, param.hir_id, Node::GenericParam(param)); - intravisit::walk_generic_param(self, param); + if let hir::GenericParamKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), + .. + } = param.kind + { + debug_assert_eq!( + param.hir_id.owner, + self.definitions.opt_hir_id_to_local_def_id(param.hir_id).unwrap() + ); + self.with_dep_node_owner(param.hir_id.owner, param, |this, hash| { + this.insert_with_hash(param.span, param.hir_id, Node::GenericParam(param), hash); + + this.with_parent(param.hir_id, |this| { + intravisit::walk_generic_param(this, param); + }); + }); + } else { + self.insert(param.span, param.hir_id, Node::GenericParam(param)); + intravisit::walk_generic_param(self, param); + } } fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) { diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs index 24695f5cdfa..7d4bafc1089 100644 --- a/compiler/rustc_passes/src/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -163,4 +163,16 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { // we are currently in. So for those it's correct that they have a // different owner. } + + fn visit_generic_param(&mut self, param: &'hir hir::GenericParam<'hir>) { + if let hir::GenericParamKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), + .. + } = param.kind + { + // Do nothing because bodging is fun. + } else { + intravisit::walk_generic_param(self, param); + } + } } From 236689d6eb241e92bea7449c07ba55783926391f Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 5 Oct 2020 01:43:15 +0200 Subject: [PATCH 070/446] split SyntheticTyParamKind --- compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_hir/src/hir.rs | 2 ++ compiler/rustc_typeck/src/astconv/generics.rs | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 41e1aafd9bd..6e60191892f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2210,7 +2210,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .attrs .iter() .filter(|attr| self.sess.check_name(attr, sym::rustc_synthetic)) - .map(|_| hir::SyntheticTyParamKind::ImplTrait) + .map(|_| hir::SyntheticTyParamKind::Rustc) .next(), }; diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 636f67a77c8..52d24a2eb48 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -508,6 +508,8 @@ impl Generics<'hir> { #[derive(HashStable_Generic)] pub enum SyntheticTyParamKind { ImplTrait, + // Created by the `#[rustc_synthetic]` attribute. + Rustc, } /// A where-clause in a definition. diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index b867798c76c..a877dfcfcb7 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -550,7 +550,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let explicit = !seg.infer_args; let impl_trait = generics.params.iter().any(|param| match param.kind { ty::GenericParamDefKind::Type { - synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), + synthetic: + Some(hir::SyntheticTyParamKind::ImplTrait | hir::SyntheticTyParamKind::Rustc), .. } => true, _ => false, From 604bc876e03a4169a1fb42408d778c65ab39cec2 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 5 Oct 2020 02:01:32 +0200 Subject: [PATCH 071/446] implement nits --- compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_passes/src/hir_id_validator.rs | 3 ++- compiler/rustc_typeck/src/astconv/generics.rs | 20 +++++++++++-------- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 6e60191892f..a70309b64c1 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2210,7 +2210,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .attrs .iter() .filter(|attr| self.sess.check_name(attr, sym::rustc_synthetic)) - .map(|_| hir::SyntheticTyParamKind::Rustc) + .map(|_| hir::SyntheticTyParamKind::FromAttr) .next(), }; diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 52d24a2eb48..befdfdbd7cf 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -509,7 +509,7 @@ impl Generics<'hir> { pub enum SyntheticTyParamKind { ImplTrait, // Created by the `#[rustc_synthetic]` attribute. - Rustc, + FromAttr, } /// A where-clause in a definition. diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs index 7d4bafc1089..6d1a5fcc10b 100644 --- a/compiler/rustc_passes/src/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -170,7 +170,8 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { .. } = param.kind { - // Do nothing because bodging is fun. + // Synthetic impl trait parameters are owned by the node of the desugared type. + // This means it is correct for them to have a different owner. } else { intravisit::walk_generic_param(self, param); } diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index a877dfcfcb7..3bfb2d3f1b0 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -548,14 +548,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { generics: &ty::Generics, ) -> bool { let explicit = !seg.infer_args; - let impl_trait = generics.params.iter().any(|param| match param.kind { - ty::GenericParamDefKind::Type { - synthetic: - Some(hir::SyntheticTyParamKind::ImplTrait | hir::SyntheticTyParamKind::Rustc), - .. - } => true, - _ => false, - }); + let impl_trait = + generics.params.iter().any(|param| match param.kind { + ty::GenericParamDefKind::Type { + synthetic: + Some( + hir::SyntheticTyParamKind::ImplTrait + | hir::SyntheticTyParamKind::FromAttr, + ), + .. + } => true, + _ => false, + }); if explicit && impl_trait { let spans = seg From 5bad9175fb363917ffee2c2da7223e96daa2f5ac Mon Sep 17 00:00:00 2001 From: Bruno BELANYI Date: Wed, 7 Oct 2020 11:37:32 +0200 Subject: [PATCH 072/446] New lint: Recommend using `ptr::eq` when possible This is based almost entirely on the code available in the previous PR #4596. --- clippy_lints/src/lib.rs | 5 ++ clippy_lints/src/ptr_eq.rs | 96 ++++++++++++++++++++++++++++++++++++++ tests/ui/ptr_eq.fixed | 38 +++++++++++++++ tests/ui/ptr_eq.rs | 38 +++++++++++++++ tests/ui/ptr_eq.stderr | 16 +++++++ 5 files changed, 193 insertions(+) create mode 100644 clippy_lints/src/ptr_eq.rs create mode 100644 tests/ui/ptr_eq.fixed create mode 100644 tests/ui/ptr_eq.rs create mode 100644 tests/ui/ptr_eq.stderr diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 826a059f92a..d11eeff8032 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -281,6 +281,7 @@ mod path_buf_push_overwrite; mod pattern_type_mismatch; mod precedence; mod ptr; +mod ptr_eq; mod ptr_offset_with_cast; mod question_mark; mod ranges; @@ -778,6 +779,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &ptr::CMP_NULL, &ptr::MUT_FROM_REF, &ptr::PTR_ARG, + &ptr_eq::PTR_EQ, &ptr_offset_with_cast::PTR_OFFSET_WITH_CAST, &question_mark::QUESTION_MARK, &ranges::RANGE_MINUS_ONE, @@ -916,6 +918,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold; store.register_late_pass(move || box bit_mask::BitMask::new(verbose_bit_mask_threshold)); store.register_late_pass(|| box ptr::Ptr); + store.register_late_pass(|| box ptr_eq::PtrEq); store.register_late_pass(|| box needless_bool::NeedlessBool); store.register_late_pass(|| box needless_bool::BoolComparison); store.register_late_pass(|| box approx_const::ApproxConstant); @@ -1456,6 +1459,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&ptr::CMP_NULL), LintId::of(&ptr::MUT_FROM_REF), LintId::of(&ptr::PTR_ARG), + LintId::of(&ptr_eq::PTR_EQ), LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), LintId::of(&question_mark::QUESTION_MARK), LintId::of(&ranges::RANGE_ZIP_WITH_LEN), @@ -1612,6 +1616,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&panic_unimplemented::PANIC_PARAMS), LintId::of(&ptr::CMP_NULL), LintId::of(&ptr::PTR_ARG), + LintId::of(&ptr_eq::PTR_EQ), LintId::of(&question_mark::QUESTION_MARK), LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES), LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), diff --git a/clippy_lints/src/ptr_eq.rs b/clippy_lints/src/ptr_eq.rs new file mode 100644 index 00000000000..a05cb6270b7 --- /dev/null +++ b/clippy_lints/src/ptr_eq.rs @@ -0,0 +1,96 @@ +use crate::utils; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** Use `std::ptr::eq` when applicable + /// + /// **Why is this bad?**`ptr::eq` can be used to compare `&T` references + /// (which coerce to `*const T` implicitly) by their address rather than + /// comparing the values they point to. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// let a = &[1, 2, 3]; + /// let b = &[1, 2, 3]; + /// + /// assert!(a as *const _ as usize == b as *const _ as usize); + /// ``` + /// Use instead: + /// ```rust + /// let a = &[1, 2, 3]; + /// let b = &[1, 2, 3]; + /// + /// assert!(std::ptr::eq(a, b)); + /// ``` + pub PTR_EQ, + style, + "use `std::ptr::eq` when comparing raw pointers" +} + +declare_lint_pass!(PtrEq => [PTR_EQ]); + +static LINT_MSG: &str = "use `std::ptr::eq` when comparing raw pointers"; + +impl LateLintPass<'_> for PtrEq { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if utils::in_macro(expr.span) { + return; + } + + if let ExprKind::Binary(ref op, ref left, ref right) = expr.kind { + if BinOpKind::Eq == op.node { + let (left, right) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) { + (Some(lhs), Some(rhs)) => (lhs, rhs), + _ => (&**left, &**right), + }; + + if_chain! { + if let Some(left_var) = expr_as_cast_to_raw_pointer(cx, left); + if let Some(right_var) = expr_as_cast_to_raw_pointer(cx, right); + if let Some(left_snip) = utils::snippet_opt(cx, left_var.span); + if let Some(right_snip) = utils::snippet_opt(cx, right_var.span); + then { + utils::span_lint_and_sugg( + cx, + PTR_EQ, + expr.span, + LINT_MSG, + "try", + format!("std::ptr::eq({}, {})", left_snip, right_snip), + Applicability::MachineApplicable, + ); + } + } + } + } + } +} + +// If the given expression is a cast to an usize, return the lhs of the cast +// E.g., `foo as *const _ as usize` returns `foo as *const _`. +fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { + if cx.typeck_results().expr_ty(cast_expr) == cx.tcx.types.usize { + if let ExprKind::Cast(ref expr, _) = cast_expr.kind { + return Some(expr); + } + } + None +} + +// If the given expression is a cast to a `*const` pointer, return the lhs of the cast +// E.g., `foo as *const _` returns `foo`. +fn expr_as_cast_to_raw_pointer<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { + if cx.typeck_results().expr_ty(cast_expr).is_unsafe_ptr() { + if let ExprKind::Cast(ref expr, _) = cast_expr.kind { + return Some(expr); + } + } + None +} diff --git a/tests/ui/ptr_eq.fixed b/tests/ui/ptr_eq.fixed new file mode 100644 index 00000000000..209081e6e80 --- /dev/null +++ b/tests/ui/ptr_eq.fixed @@ -0,0 +1,38 @@ +// run-rustfix +#![warn(clippy::ptr_eq)] + +macro_rules! mac { + ($a:expr, $b:expr) => { + $a as *const _ as usize == $b as *const _ as usize + }; +} + +macro_rules! another_mac { + ($a:expr, $b:expr) => { + $a as *const _ == $b as *const _ + }; +} + +fn main() { + let a = &[1, 2, 3]; + let b = &[1, 2, 3]; + + let _ = std::ptr::eq(a, b); + let _ = std::ptr::eq(a, b); + let _ = a.as_ptr() == b as *const _; + let _ = a.as_ptr() == b.as_ptr(); + + // Do not lint + + let _ = mac!(a, b); + let _ = another_mac!(a, b); + + let a = &mut [1, 2, 3]; + let b = &mut [1, 2, 3]; + + let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; + let _ = a.as_mut_ptr() == b.as_mut_ptr(); + + let _ = a == b; + let _ = core::ptr::eq(a, b); +} diff --git a/tests/ui/ptr_eq.rs b/tests/ui/ptr_eq.rs new file mode 100644 index 00000000000..69162870807 --- /dev/null +++ b/tests/ui/ptr_eq.rs @@ -0,0 +1,38 @@ +// run-rustfix +#![warn(clippy::ptr_eq)] + +macro_rules! mac { + ($a:expr, $b:expr) => { + $a as *const _ as usize == $b as *const _ as usize + }; +} + +macro_rules! another_mac { + ($a:expr, $b:expr) => { + $a as *const _ == $b as *const _ + }; +} + +fn main() { + let a = &[1, 2, 3]; + let b = &[1, 2, 3]; + + let _ = a as *const _ as usize == b as *const _ as usize; + let _ = a as *const _ == b as *const _; + let _ = a.as_ptr() == b as *const _; + let _ = a.as_ptr() == b.as_ptr(); + + // Do not lint + + let _ = mac!(a, b); + let _ = another_mac!(a, b); + + let a = &mut [1, 2, 3]; + let b = &mut [1, 2, 3]; + + let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; + let _ = a.as_mut_ptr() == b.as_mut_ptr(); + + let _ = a == b; + let _ = core::ptr::eq(a, b); +} diff --git a/tests/ui/ptr_eq.stderr b/tests/ui/ptr_eq.stderr new file mode 100644 index 00000000000..45d8c60382b --- /dev/null +++ b/tests/ui/ptr_eq.stderr @@ -0,0 +1,16 @@ +error: use `std::ptr::eq` when comparing raw pointers + --> $DIR/ptr_eq.rs:20:13 + | +LL | let _ = a as *const _ as usize == b as *const _ as usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a, b)` + | + = note: `-D clippy::ptr-eq` implied by `-D warnings` + +error: use `std::ptr::eq` when comparing raw pointers + --> $DIR/ptr_eq.rs:21:13 + | +LL | let _ = a as *const _ == b as *const _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a, b)` + +error: aborting due to 2 previous errors + From aa7c42f75668bc514baf0a64f31771353c3af6cb Mon Sep 17 00:00:00 2001 From: Bruno BELANYI Date: Wed, 7 Oct 2020 11:54:00 +0200 Subject: [PATCH 073/446] fixup! New lint: Recommend using `ptr::eq` when possible Add missing modified files. --- CHANGELOG.md | 1 + src/lintlist/mod.rs | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 617bf32f463..552a0e96ceb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1774,6 +1774,7 @@ Released 2018-09-13 [`print_with_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_with_newline [`println_empty_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#println_empty_string [`ptr_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_arg +[`ptr_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_eq [`ptr_offset_with_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_with_cast [`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names [`question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#question_mark diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 0dba5a71c50..3cba9867600 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1844,6 +1844,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "ptr", }, + Lint { + name: "ptr_eq", + group: "style", + desc: "use `std::ptr::eq` when comparing raw pointers", + deprecation: None, + module: "ptr_eq", + }, Lint { name: "ptr_offset_with_cast", group: "complexity", From 9ef311b47706cc0babce08ee86bc9ca7727fc2f5 Mon Sep 17 00:00:00 2001 From: Bruno BELANYI Date: Wed, 7 Oct 2020 11:59:20 +0200 Subject: [PATCH 074/446] Rename tables to typecheck_result() --- doc/common_tools_writing_lints.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/doc/common_tools_writing_lints.md b/doc/common_tools_writing_lints.md index 53c3d084dbc..27d4f1b03d7 100644 --- a/doc/common_tools_writing_lints.md +++ b/doc/common_tools_writing_lints.md @@ -45,11 +45,13 @@ Similarly in [`TypeckResults`][TypeckResults] methods, you have the [`pat_ty()`] to retrieve a type from a pattern. Two noticeable items here: -- `cx` is the lint context [`LateContext`][LateContext]. - The two most useful data structures in this context are `tcx` and `tables`, - allowing us to jump to type definitions and other compilation stages such as HIR. -- `tables` is [`TypeckResults`][TypeckResults] and is created by type checking step, - it includes useful information such as types of expressions, ways to resolve methods and so on. +- `cx` is the lint context [`LateContext`][LateContext]. The two most useful + data structures in this context are `tcx` and the `TypeckResults` returned by + 'LateContext::typeck_results', allowing us to jump to type definitions and + other compilation stages such as HIR. +- `typeck_results`'s return value is [`TypeckResults`][TypeckResults] and is + created by type checking step, it includes useful information such as types + of expressions, ways to resolve methods and so on. # Checking if an expr is calling a specific method From 326090dbb8285e9486d77fd9aa2ea206f78bf978 Mon Sep 17 00:00:00 2001 From: Bruno BELANYI Date: Wed, 7 Oct 2020 17:10:31 +0200 Subject: [PATCH 075/446] fixup! Rename tables to typecheck_result() Co-authored-by: Takayuki Nakata --- doc/common_tools_writing_lints.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/common_tools_writing_lints.md b/doc/common_tools_writing_lints.md index 27d4f1b03d7..d56079a4ab7 100644 --- a/doc/common_tools_writing_lints.md +++ b/doc/common_tools_writing_lints.md @@ -47,7 +47,7 @@ to retrieve a type from a pattern. Two noticeable items here: - `cx` is the lint context [`LateContext`][LateContext]. The two most useful data structures in this context are `tcx` and the `TypeckResults` returned by - 'LateContext::typeck_results', allowing us to jump to type definitions and + `LateContext::typeck_results`, allowing us to jump to type definitions and other compilation stages such as HIR. - `typeck_results`'s return value is [`TypeckResults`][TypeckResults] and is created by type checking step, it includes useful information such as types From 6edde811b5437f926c26b1b844acd60e3dd0a0c9 Mon Sep 17 00:00:00 2001 From: Bruno BELANYI Date: Wed, 7 Oct 2020 17:11:11 +0200 Subject: [PATCH 076/446] fixup! New lint: Recommend using `ptr::eq` when possible Co-authored-by: Takayuki Nakata --- clippy_lints/src/ptr_eq.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/ptr_eq.rs b/clippy_lints/src/ptr_eq.rs index a05cb6270b7..3be792ce5e4 100644 --- a/clippy_lints/src/ptr_eq.rs +++ b/clippy_lints/src/ptr_eq.rs @@ -8,7 +8,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { /// **What it does:** Use `std::ptr::eq` when applicable /// - /// **Why is this bad?**`ptr::eq` can be used to compare `&T` references + /// **Why is this bad?** `ptr::eq` can be used to compare `&T` references /// (which coerce to `*const T` implicitly) by their address rather than /// comparing the values they point to. /// From 16e10bf81ee73f61cf813acef3d5dbbce4f66da2 Mon Sep 17 00:00:00 2001 From: Francesca Lovebloom Date: Wed, 7 Oct 2020 15:46:05 -0700 Subject: [PATCH 077/446] Revert "Allow dynamic linking for iOS/tvOS targets." This reverts commit 56e115a2627ba8bdd2e66c759457af96b2b0286a. --- compiler/rustc_target/src/spec/apple_sdk_base.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_target/src/spec/apple_sdk_base.rs b/compiler/rustc_target/src/spec/apple_sdk_base.rs index e34277d5af0..1b17c2c278f 100644 --- a/compiler/rustc_target/src/spec/apple_sdk_base.rs +++ b/compiler/rustc_target/src/spec/apple_sdk_base.rs @@ -34,6 +34,7 @@ fn link_env_remove(arch: Arch) -> Vec { pub fn opts(arch: Arch) -> TargetOptions { TargetOptions { cpu: target_cpu(arch), + dynamic_linking: false, executables: true, link_env_remove: link_env_remove(arch), has_elf_tls: false, From 1385eb9b5562ec78f772341e1ad5c3d2f5443141 Mon Sep 17 00:00:00 2001 From: Darshan Kathiriya Date: Wed, 7 Oct 2020 09:09:59 -0300 Subject: [PATCH 078/446] Replace run_compiler with RunCompiler builder pattern. RunCompiler::new takes non-optional params, and optional params can be set using set_*field_name* method. finally `run` will forward all fields to `run_compiler`. --- src/driver.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/driver.rs b/src/driver.rs index f4f2259cefd..377f6d22446 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -357,7 +357,7 @@ pub fn main() { args.extend(vec!["--sysroot".into(), sys_root]); }; - return rustc_driver::run_compiler(&args, &mut DefaultCallbacks, None, None, None); + return rustc_driver::RunCompiler::new(&args, &mut DefaultCallbacks).run(); } if orig_args.iter().any(|a| a == "--version" || a == "-V") { @@ -420,6 +420,6 @@ pub fn main() { let mut default = DefaultCallbacks; let callbacks: &mut (dyn rustc_driver::Callbacks + Send) = if clippy_enabled { &mut clippy } else { &mut default }; - rustc_driver::run_compiler(&args, callbacks, None, None, None) + rustc_driver::RunCompiler::new(&args, callbacks).run() })) } From 64839ee00ab4076d797901ddea55f2613c5b75b5 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 8 Oct 2020 23:51:56 +0200 Subject: [PATCH 079/446] Add Pin::new_static. --- library/core/src/pin.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 9f0284d5d95..cc93f0fa5fc 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -781,6 +781,19 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { } } +impl Pin<&'static T> { + /// Get a pinned reference from a static reference. + /// + /// This is safe, because the `'static` lifetime guarantees the data will + /// never be moved. + #[unstable(feature = "pin_static_ref", issue = "none")] + pub fn new_static(r: &'static T) -> Pin<&'static T> { + // SAFETY: The 'static lifetime guarantees the data will not be + // moved/invalidated until it gets dropped (which is never). + unsafe { Pin::new_unchecked(r) } + } +} + #[stable(feature = "pin", since = "1.33.0")] impl Deref for Pin

{ type Target = P::Target; From 390883e888c580d054ab4a2584c851aba50865e9 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 9 Oct 2020 00:06:39 +0200 Subject: [PATCH 080/446] Make Pin::new_static const. --- library/core/src/pin.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index cc93f0fa5fc..3f058124d2b 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -787,7 +787,8 @@ impl Pin<&'static T> { /// This is safe, because the `'static` lifetime guarantees the data will /// never be moved. #[unstable(feature = "pin_static_ref", issue = "none")] - pub fn new_static(r: &'static T) -> Pin<&'static T> { + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + pub const fn new_static(r: &'static T) -> Pin<&'static T> { // SAFETY: The 'static lifetime guarantees the data will not be // moved/invalidated until it gets dropped (which is never). unsafe { Pin::new_unchecked(r) } From 2c8cd7d93cd137d9f606d15c20b92634c68c98f4 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 9 Oct 2020 09:17:48 +0200 Subject: [PATCH 081/446] Update actions due to deprecation of set-env and add-path --- .github/workflows/clippy.yml | 4 ++-- .github/workflows/clippy_bors.yml | 14 +++++++------- .github/workflows/clippy_dev.yml | 4 ++-- .github/workflows/deploy.yml | 4 ++-- .github/workflows/remark.yml | 4 ++-- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index 99e371631b1..0cbe73affda 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -36,14 +36,14 @@ jobs: github_token: "${{ secrets.github_token }}" - name: rust-toolchain - uses: actions-rs/toolchain@v1.0.3 + uses: actions-rs/toolchain@v1.0.6 with: toolchain: nightly target: x86_64-unknown-linux-gnu profile: minimal - name: Checkout - uses: actions/checkout@v2.0.0 + uses: actions/checkout@v2.3.3 - name: Run cargo update run: cargo update diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index fd0cd7a1890..a5c00b3418e 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -20,7 +20,7 @@ jobs: with: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v2.0.0 + uses: actions/checkout@v2.3.3 with: ref: ${{ github.ref }} @@ -81,14 +81,14 @@ jobs: if: matrix.host == 'i686-unknown-linux-gnu' - name: rust-toolchain - uses: actions-rs/toolchain@v1.0.3 + uses: actions-rs/toolchain@v1.0.6 with: toolchain: nightly target: ${{ matrix.host }} profile: minimal - name: Checkout - uses: actions/checkout@v2.0.0 + uses: actions/checkout@v2.3.3 - name: Run cargo update run: cargo update @@ -177,14 +177,14 @@ jobs: github_token: "${{ secrets.github_token }}" - name: rust-toolchain - uses: actions-rs/toolchain@v1.0.3 + uses: actions-rs/toolchain@v1.0.6 with: toolchain: nightly target: x86_64-unknown-linux-gnu profile: minimal - name: Checkout - uses: actions/checkout@v2.0.0 + uses: actions/checkout@v2.3.3 - name: Run cargo update run: cargo update @@ -258,14 +258,14 @@ jobs: github_token: "${{ secrets.github_token }}" - name: rust-toolchain - uses: actions-rs/toolchain@v1.0.3 + uses: actions-rs/toolchain@v1.0.6 with: toolchain: nightly target: x86_64-unknown-linux-gnu profile: minimal - name: Checkout - uses: actions/checkout@v2.0.0 + uses: actions/checkout@v2.3.3 - name: Run cargo update run: cargo update diff --git a/.github/workflows/clippy_dev.yml b/.github/workflows/clippy_dev.yml index ec3b43c2f43..5ee157cf23b 100644 --- a/.github/workflows/clippy_dev.yml +++ b/.github/workflows/clippy_dev.yml @@ -23,7 +23,7 @@ jobs: steps: # Setup - name: rust-toolchain - uses: actions-rs/toolchain@v1.0.3 + uses: actions-rs/toolchain@v1.0.6 with: toolchain: nightly target: x86_64-unknown-linux-gnu @@ -31,7 +31,7 @@ jobs: components: rustfmt - name: Checkout - uses: actions/checkout@v2.0.0 + uses: actions/checkout@v2.3.3 # Run - name: Build diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index f542f9b02c1..5b7252532c2 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -21,10 +21,10 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v2.0.0 + uses: actions/checkout@v2.3.3 - name: Checkout - uses: actions/checkout@v2.0.0 + uses: actions/checkout@v2.3.3 with: ref: ${{ env.TARGET_BRANCH }} path: 'out' diff --git a/.github/workflows/remark.yml b/.github/workflows/remark.yml index cc175e8bf24..4f25a86b2e4 100644 --- a/.github/workflows/remark.yml +++ b/.github/workflows/remark.yml @@ -16,10 +16,10 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v2.0.0 + uses: actions/checkout@v2.3.3 - name: Setup Node.js - uses: actions/setup-node@v1.1.0 + uses: actions/setup-node@v1.4.4 - name: Install remark run: npm install remark-cli remark-lint remark-lint-maximum-line-length remark-preset-lint-recommended From c85cb76064ae24ee16efa426280ccbd7b7b54f4b Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 9 Oct 2020 09:40:57 +0200 Subject: [PATCH 082/446] Update release documentation --- doc/release.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/release.md b/doc/release.md index 391952ea6b1..eaa6a9af277 100644 --- a/doc/release.md +++ b/doc/release.md @@ -68,7 +68,7 @@ be updated. ```bash # Assuming the current directory corresponds to the Clippy repository $ git checkout beta -$ git rebase $BETA_SHA +$ git reset --hard $BETA_SHA $ git push upstream beta ``` From 732d370404198ca68a96901b25a5f2ab3ba9d562 Mon Sep 17 00:00:00 2001 From: Jean SIMARD Date: Fri, 9 Oct 2020 09:47:53 +0200 Subject: [PATCH 083/446] clippy_lint: Fix doc on 'option_if_let_else' - a typo in `expresion` - a useless double space - Some back-tick quotes for 'if let' --- clippy_lints/src/option_if_let_else.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 4a3eb9c983a..383a62da821 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -13,14 +13,14 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { /// **What it does:** - /// Lints usage of `if let Some(v) = ... { y } else { x }` which is more + /// Lints usage of `if let Some(v) = ... { y } else { x }` which is more /// idiomatically done with `Option::map_or` (if the else bit is a pure /// expression) or `Option::map_or_else` (if the else bit is an impure - /// expresion). + /// expression). /// /// **Why is this bad?** /// Using the dedicated functions of the Option type is clearer and - /// more concise than an if let expression. + /// more concise than an `if let` expression. /// /// **Known problems:** /// This lint uses a deliberately conservative metric for checking From 64a7d019f10bafa386817de3bb15ef2eead4cda5 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 9 Oct 2020 10:40:04 +0200 Subject: [PATCH 084/446] Remove all usage of set-env --- .github/workflows/clippy.yml | 2 +- .github/workflows/clippy_bors.yml | 8 ++++---- .github/workflows/deploy.yml | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index 0cbe73affda..cf4aa39e49b 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -63,7 +63,7 @@ jobs: - name: Set LD_LIBRARY_PATH (Linux) run: | SYSROOT=$(rustc --print sysroot) - echo "::set-env name=LD_LIBRARY_PATH::${SYSROOT}/lib${LD_LIBRARY_PATH+:${LD_LIBRARY_PATH}}" + echo "LD_LIBRARY_PATH=${SYSROOT}/lib${LD_LIBRARY_PATH+:${LD_LIBRARY_PATH}}" >> $GITHUB_ENV - name: Build run: cargo build --features deny-warnings diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index a5c00b3418e..f83861950f8 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -112,7 +112,7 @@ jobs: if: runner.os == 'Linux' run: | SYSROOT=$(rustc --print sysroot) - echo "::set-env name=LD_LIBRARY_PATH::${SYSROOT}/lib${LD_LIBRARY_PATH+:${LD_LIBRARY_PATH}}" + echo "LD_LIBRARY_PATH=${SYSROOT}/lib${LD_LIBRARY_PATH+:${LD_LIBRARY_PATH}}" >> $GITHUB_ENV - name: Link rustc dylib (MacOS) if: runner.os == 'macOS' run: | @@ -122,9 +122,9 @@ jobs: - name: Set PATH (Windows) if: runner.os == 'Windows' run: | - $sysroot = rustc --print sysroot - $env:PATH += ';' + $sysroot + '\bin' - echo "::set-env name=PATH::$env:PATH" + SYSROOT=$(rustc --print sysroot) + echo "$SYSROOT/bin" >> $GITHUB_PATH + shell: bash - name: Build run: cargo build --features deny-warnings diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 5b7252532c2..15aeaf907dc 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -34,10 +34,10 @@ jobs: if: startswith(github.ref, 'refs/tags/') run: | TAG=$(basename ${{ github.ref }}) - echo "::set-env name=TAG_NAME::$TAG" + echo "TAG_NAME=$TAG" >> $GITHUB_ENV - name: Set beta to true if: github.ref == 'refs/heads/beta' - run: echo "::set-env name=BETA::true" + run: echo "BETA=true" >> $GITHUB_ENV - name: Use scripts and templates from master branch run: | From c4c9453ccfc69d00ced80db4cdd5be805f1ee1c2 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 9 Oct 2020 11:53:10 +0200 Subject: [PATCH 085/446] Use defaults.run.shell instead of setting shell every time --- .github/workflows/clippy_bors.yml | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index f83861950f8..7509d90c6c2 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -11,6 +11,10 @@ env: CARGO_TARGET_DIR: '${{ github.workspace }}/target' NO_FMT_TEST: 1 +defaults: + run: + shell: bash + jobs: changelog: runs-on: ubuntu-latest @@ -105,7 +109,6 @@ jobs: run: bash setup-toolchain.sh env: HOST_TOOLCHAIN: ${{ matrix.host }} - shell: bash # Run - name: Set LD_LIBRARY_PATH (Linux) @@ -124,39 +127,31 @@ jobs: run: | SYSROOT=$(rustc --print sysroot) echo "$SYSROOT/bin" >> $GITHUB_PATH - shell: bash - name: Build run: cargo build --features deny-warnings - shell: bash - name: Test run: cargo test --features deny-warnings - shell: bash - name: Test clippy_lints run: cargo test --features deny-warnings - shell: bash working-directory: clippy_lints - name: Test rustc_tools_util run: cargo test --features deny-warnings - shell: bash working-directory: rustc_tools_util - name: Test clippy_dev run: cargo test --features deny-warnings - shell: bash working-directory: clippy_dev - name: Test cargo-clippy run: ../target/debug/cargo-clippy - shell: bash working-directory: clippy_workspace_tests - name: Test clippy-driver run: bash .github/driver.sh - shell: bash env: OS: ${{ runner.os }} @@ -165,7 +160,7 @@ jobs: run: | cargo +nightly install cargo-cache --no-default-features --features ci-autoclean cargo-cache cargo cache - shell: bash + integration_build: needs: changelog runs-on: ubuntu-latest From fbf2430f0279adb8132efe60b16f8dd7b6a2acb3 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 9 Oct 2020 12:45:29 +0200 Subject: [PATCH 086/446] Merge commit '2f6439ae6a6803d030cceb3ee14c9150e91b328b' into clippyup --- CHANGELOG.md | 129 +++++++++++- README.md | 2 +- clippy_dev/Cargo.toml | 2 +- clippy_dev/src/lib.rs | 43 ++-- clippy_dev/src/main.rs | 20 +- clippy_dev/src/serve.rs | 64 ++++++ clippy_lints/Cargo.toml | 1 - clippy_lints/src/asm_syntax.rs | 125 ++++++++++++ clippy_lints/src/attrs.rs | 6 +- clippy_lints/src/disallowed_method.rs | 73 +++++++ clippy_lints/src/escape.rs | 9 +- clippy_lints/src/lib.rs | 31 ++- clippy_lints/src/lifetimes.rs | 169 +++++++-------- clippy_lints/src/literal_representation.rs | 9 +- clippy_lints/src/loops.rs | 12 +- clippy_lints/src/macro_use.rs | 4 +- clippy_lints/src/methods/mod.rs | 24 +-- clippy_lints/src/missing_const_for_fn.rs | 2 +- .../src/needless_arbitrary_self_type.rs | 30 ++- clippy_lints/src/non_copy_const.rs | 28 ++- clippy_lints/src/regex.rs | 2 +- clippy_lints/src/strings.rs | 24 ++- clippy_lints/src/types.rs | 17 +- clippy_lints/src/unicode.rs | 23 ++- clippy_lints/src/unnecessary_sort_by.rs | 58 ++---- clippy_lints/src/utils/conf.rs | 10 +- clippy_lints/src/utils/mod.rs | 14 +- clippy_lints/src/utils/numeric_literal.rs | 19 +- clippy_lints/src/utils/paths.rs | 3 + .../src/utils/qualify_min_const_fn.rs | 193 +++++++----------- clippy_lints/src/write.rs | 17 +- clippy_workspace_tests/build.rs | 7 + doc/adding_lints.md | 3 +- doc/basics.md | 6 + src/lintlist/mod.rs | 43 +++- tests/cargo/mod.rs | 37 ++-- tests/compile-test.rs | 3 +- tests/dogfood.rs | 7 +- .../toml_disallowed_method/clippy.toml | 1 + .../conf_disallowed_method.rs | 13 ++ .../conf_disallowed_method.stderr | 16 ++ .../toml_unknown_key/conf_unknown_key.stderr | 2 +- tests/ui/asm_syntax.rs | 31 +++ tests/ui/asm_syntax.stderr | 44 ++++ tests/ui/attrs.rs | 3 - tests/ui/attrs.stderr | 25 +-- tests/ui/auxiliary/proc_macro_attr.rs | 62 +++++- tests/ui/auxiliary/proc_macro_derive.rs | 1 + tests/ui/blanket_clippy_restriction_lints.rs | 8 + .../blanket_clippy_restriction_lints.stderr | 27 +++ tests/ui/crashes/associated-constant-ice.rs | 2 - .../ui/crashes/auxiliary/proc_macro_crash.rs | 1 + tests/ui/crashes/cc_seme.rs | 2 - tests/ui/crashes/enum-glob-import-crate.rs | 2 - tests/ui/crashes/ice-1588.rs | 2 - tests/ui/crashes/ice-1782.rs | 2 - tests/ui/crashes/ice-1969.rs | 2 - tests/ui/crashes/ice-2499.rs | 2 - tests/ui/crashes/ice-2594.rs | 2 - tests/ui/crashes/ice-2727.rs | 2 - tests/ui/crashes/ice-2760.rs | 2 - tests/ui/crashes/ice-2774.rs | 2 - tests/ui/crashes/ice-2774.stderr | 10 + tests/ui/crashes/ice-2862.rs | 2 - tests/ui/crashes/ice-2865.rs | 2 - tests/ui/crashes/ice-3151.rs | 2 - tests/ui/crashes/ice-3462.rs | 2 - tests/ui/crashes/ice-3741.rs | 1 - tests/ui/crashes/ice-3747.rs | 2 - tests/ui/crashes/ice-4727.rs | 2 - tests/ui/crashes/ice-4760.rs | 1 - tests/ui/crashes/ice-700.rs | 2 - tests/ui/crashes/ice_exacte_size.rs | 2 - tests/ui/crashes/if_same_then_else.rs | 2 - tests/ui/crashes/issue-825.rs | 2 - tests/ui/crashes/issues_loop_mut_cond.rs | 2 - tests/ui/crashes/match_same_arms_const.rs | 2 - tests/ui/crashes/mut_mut_macro.rs | 2 - tests/ui/crashes/needless_borrow_fp.rs | 2 - .../crashes/needless_lifetimes_impl_trait.rs | 2 - .../needless_lifetimes_impl_trait.stderr | 14 ++ tests/ui/crashes/procedural_macro.rs | 2 - tests/ui/crashes/regressions.rs | 2 - tests/ui/crashes/returns.rs | 2 - tests/ui/crashes/single-match-else.rs | 2 - tests/ui/crashes/trivial_bounds.rs | 2 - .../crashes/used_underscore_binding_macro.rs | 2 - tests/ui/escape_analysis.rs | 8 + tests/ui/explicit_counter_loop.rs | 29 ++- tests/ui/inconsistent_digit_grouping.fixed | 4 + tests/ui/inconsistent_digit_grouping.rs | 4 + tests/ui/mistyped_literal_suffix.fixed | 11 +- tests/ui/mistyped_literal_suffix.rs | 11 +- tests/ui/mistyped_literal_suffix.stderr | 36 ++-- .../needless_arbitrary_self_type_unfixable.rs | 45 ++++ ...dless_arbitrary_self_type_unfixable.stderr | 10 + tests/ui/needless_lifetimes.rs | 98 +++++++++ tests/ui/needless_lifetimes.stderr | 50 ++++- tests/ui/needless_range_loop2.rs | 14 ++ tests/ui/or_fun_call.fixed | 25 +-- tests/ui/or_fun_call.rs | 25 +-- tests/ui/or_fun_call.stderr | 20 +- tests/ui/print_stdout_build_script.rs | 12 ++ tests/ui/regex.rs | 3 + tests/ui/unicode.rs | 6 +- tests/ui/unicode.stderr | 22 +- tests/ui/unnecessary_sort_by.fixed | 30 +-- tests/ui/unnecessary_sort_by.rs | 10 +- tests/ui/unnecessary_sort_by.stderr | 52 ++++- 109 files changed, 1502 insertions(+), 616 deletions(-) create mode 100644 clippy_dev/src/serve.rs create mode 100644 clippy_lints/src/asm_syntax.rs create mode 100644 clippy_lints/src/disallowed_method.rs create mode 100644 clippy_workspace_tests/build.rs create mode 100644 tests/ui-toml/toml_disallowed_method/clippy.toml create mode 100644 tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs create mode 100644 tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr create mode 100644 tests/ui/asm_syntax.rs create mode 100644 tests/ui/asm_syntax.stderr create mode 100644 tests/ui/blanket_clippy_restriction_lints.rs create mode 100644 tests/ui/blanket_clippy_restriction_lints.stderr create mode 100644 tests/ui/crashes/ice-2774.stderr create mode 100644 tests/ui/crashes/needless_lifetimes_impl_trait.stderr create mode 100644 tests/ui/needless_arbitrary_self_type_unfixable.rs create mode 100644 tests/ui/needless_arbitrary_self_type_unfixable.stderr create mode 100644 tests/ui/print_stdout_build_script.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index d1dfe36ffd8..0bd13320dc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,129 @@ document. ## Unreleased / In Rust Nightly -[09bd400...master](https://github.com/rust-lang/rust-clippy/compare/09bd400...master) +[e636b88...master](https://github.com/rust-lang/rust-clippy/compare/e636b88...master) + +## Rust 1.48 + +Current beta, release 2020-11-19 + +[09bd400...e636b88](https://github.com/rust-lang/rust-clippy/compare/09bd400...e636b88) + +### New lints + +* [`self_assignment`] [#5894](https://github.com/rust-lang/rust-clippy/pull/5894) +* [`unnecessary_lazy_evaluations`] [#5720](https://github.com/rust-lang/rust-clippy/pull/5720) +* [`manual_strip`] [#6038](https://github.com/rust-lang/rust-clippy/pull/6038) +* [`map_err_ignore`] [#5998](https://github.com/rust-lang/rust-clippy/pull/5998) +* [`rc_buffer`] [#6044](https://github.com/rust-lang/rust-clippy/pull/6044) +* [`to_string_in_display`] [#5831](https://github.com/rust-lang/rust-clippy/pull/5831) +* [`single_char_push_str`] [#5881](https://github.com/rust-lang/rust-clippy/pull/5881) + +### Moves and Deprecations + +* Downgrade [`verbose_bit_mask`] to pedantic + [#6036](https://github.com/rust-lang/rust-clippy/pull/6036) + +### Enhancements + +* Extend [`precedence`] to handle chains of methods combined with unary negation + [#5928](https://github.com/rust-lang/rust-clippy/pull/5928) +* [`useless_vec`]: add a configuration value for the maximum allowed size on the stack + [#5907](https://github.com/rust-lang/rust-clippy/pull/5907) +* [`suspicious_arithmetic_impl`]: extend to implementations of `BitAnd`, `BitOr`, `BitXor`, `Rem`, `Shl`, and `Shr` + [#5884](https://github.com/rust-lang/rust-clippy/pull/5884) +* [`invalid_atomic_ordering`]: detect misuse of `compare_exchange`, `compare_exchange_weak`, and `fetch_update` + [#6025](https://github.com/rust-lang/rust-clippy/pull/6025) +* Avoid [`redundant_pattern_matching`] triggering in macros + [#6069](https://github.com/rust-lang/rust-clippy/pull/6069) +* [`option_if_let_else`]: distinguish pure from impure `else` expressions + [#5937](https://github.com/rust-lang/rust-clippy/pull/5937) +* [`needless_doctest_main`]: parse doctests instead of using textual search + [#5912](https://github.com/rust-lang/rust-clippy/pull/5912) +* [`wildcard_imports`]: allow `prelude` to appear in any segment of an import + [#5929](https://github.com/rust-lang/rust-clippy/pull/5929) +* Re-enable [`len_zero`] for ranges now that `range_is_empty` is stable + [#5961](https://github.com/rust-lang/rust-clippy/pull/5961) +* [`option_as_ref_deref`]: catch fully-qualified calls to `Deref::deref` and `DerefMut::deref_mut` + [#5933](https://github.com/rust-lang/rust-clippy/pull/5933) + +### False Positive Fixes + +* [`useless_attribute`]: permit allowing [`wildcard_imports`] and [`enum_glob_use`] + [#5994](https://github.com/rust-lang/rust-clippy/pull/5994) +* [`transmute_ptr_to_ptr`]: avoid suggesting dereferencing raw pointers in const contexts + [#5999](https://github.com/rust-lang/rust-clippy/pull/5999) +* [`redundant_closure_call`]: take into account usages of the closure in nested functions and closures + [#5920](https://github.com/rust-lang/rust-clippy/pull/5920) +* Fix false positive in [`borrow_interior_mutable_const`] when referencing a field behind a pointer + [#5949](https://github.com/rust-lang/rust-clippy/pull/5949) +* [`doc_markdown`]: allow using "GraphQL" without backticks + [#5996](https://github.com/rust-lang/rust-clippy/pull/5996) +* [`to_string_in_display`]: avoid linting when calling `to_string()` on anything that is not `self` + [#5971](https://github.com/rust-lang/rust-clippy/pull/5971) +* [`indexing_slicing`] and [`out_of_bounds_indexing`] treat references to arrays as arrays + [#6034](https://github.com/rust-lang/rust-clippy/pull/6034) +* [`should_implement_trait`]: ignore methods with lifetime parameters + [#5725](https://github.com/rust-lang/rust-clippy/pull/5725) +* [`needless_return`]: avoid linting if a temporary borrows a local variable + [#5903](https://github.com/rust-lang/rust-clippy/pull/5903) +* Restrict [`unnecessary_sort_by`] to non-reference, Copy types + [#6006](https://github.com/rust-lang/rust-clippy/pull/6006) +* Avoid suggesting `from_bits`/`to_bits` in const contexts in [`transmute_int_to_float`] + [#5919](https://github.com/rust-lang/rust-clippy/pull/5919) +* [`declare_interior_mutable_const`] and [`borrow_interior_mutable_const`]: improve detection of interior mutable types + [#6046](https://github.com/rust-lang/rust-clippy/pull/6046) + +### Suggestion Fixes/Improvements + +* [`let_and_return`]: add a cast to the suggestion when the return expression has adjustments + [#5946](https://github.com/rust-lang/rust-clippy/pull/5946) +* [`useless_conversion`]: show the type in the error message + [#6035](https://github.com/rust-lang/rust-clippy/pull/6035) +* [`unnecessary_mut_passed`]: discriminate between functions and methods in the error message + [#5892](https://github.com/rust-lang/rust-clippy/pull/5892) +* [`float_cmp`] and [`float_cmp_const`]: change wording to make margin of error less ambiguous + [#6043](https://github.com/rust-lang/rust-clippy/pull/6043) +* [`default_trait_access`]: do not use unnecessary type parameters in the suggestion + [#5993](https://github.com/rust-lang/rust-clippy/pull/5993) +* [`collapsible_if`]: don't use expanded code in the suggestion + [#5992](https://github.com/rust-lang/rust-clippy/pull/5992) +* Do not suggest empty format strings in [`print_with_newline`] and [`write_with_newline`] + [#6042](https://github.com/rust-lang/rust-clippy/pull/6042) +* [`unit_arg`]: improve the readability of the suggestion + [#5931](https://github.com/rust-lang/rust-clippy/pull/5931) +* [`stable_sort_primitive`]: print the type that is being sorted in the lint message + [#5935](https://github.com/rust-lang/rust-clippy/pull/5935) +* Show line count and max lines in [`too_many_lines`] lint message + [#6009](https://github.com/rust-lang/rust-clippy/pull/6009) +* Keep parentheses in the suggestion of [`useless_conversion`] where applicable + [#5900](https://github.com/rust-lang/rust-clippy/pull/5900) +* [`option_map_unit_fn`] and [`result_map_unit_fn`]: print the unit type `()` explicitly + [#6024](https://github.com/rust-lang/rust-clippy/pull/6024) +* [`redundant_allocation`]: suggest replacing `Rc>` with `Rc` + [#5899](https://github.com/rust-lang/rust-clippy/pull/5899) +* Make lint messages adhere to rustc dev guide conventions + [#5893](https://github.com/rust-lang/rust-clippy/pull/5893) + +### ICE Fixes + +* Fix ICE in [`repeat_once`] + [#5948](https://github.com/rust-lang/rust-clippy/pull/5948) + +### Documentation Improvements + +* [`mutable_key_type`]: explain potential for false positives when the interior mutable type is not accessed in the `Hash` implementation + [#6019](https://github.com/rust-lang/rust-clippy/pull/6019) +* [`unnecessary_mut_passed`]: fix typo + [#5913](https://github.com/rust-lang/rust-clippy/pull/5913) +* Add example of false positive to [`ptr_arg`] docs. + [#5885](https://github.com/rust-lang/rust-clippy/pull/5885) +* [`box_vec`], [`vec_box`] and [`borrowed_box`]: add link to the documentation of `Box` + [#6023](https://github.com/rust-lang/rust-clippy/pull/6023) ## Rust 1.47 -Current beta, release 2020-10-08 +Current stable, released 2020-10-08 [c2c07fa...09bd400](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...09bd400) @@ -112,7 +230,7 @@ Current beta, release 2020-10-08 ## Rust 1.46 -Current stable, released 2020-08-27 +Released 2020-08-27 [7ea7cd1...c2c07fa](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...c2c07fa) @@ -1559,6 +1677,7 @@ Released 2018-09-13 [`deref_addrof`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_addrof [`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq [`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord +[`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method [`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown [`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons @@ -1634,6 +1753,8 @@ Released 2018-09-13 [`inherent_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string [`inherent_to_string_shadow_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string_shadow_display [`inline_always`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_always +[`inline_asm_x86_att_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_att_syntax +[`inline_asm_x86_intel_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_intel_syntax [`inline_fn_without_body`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_fn_without_body [`int_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#int_plus_one [`integer_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_arithmetic @@ -1644,6 +1765,7 @@ Released 2018-09-13 [`invalid_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_ref [`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex [`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons +[`invisible_characters`]: https://rust-lang.github.io/rust-clippy/master/index.html#invisible_characters [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements [`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect [`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop @@ -1919,6 +2041,5 @@ Released 2018-09-13 [`zero_divided_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_divided_by_zero [`zero_prefixed_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_prefixed_literal [`zero_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_ptr -[`zero_width_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_width_space [`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset diff --git a/README.md b/README.md index a2984d73641..62a8be0abf2 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 350 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 400 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_dev/Cargo.toml b/clippy_dev/Cargo.toml index c861efc8afb..b8a4a20114b 100644 --- a/clippy_dev/Cargo.toml +++ b/clippy_dev/Cargo.toml @@ -8,8 +8,8 @@ edition = "2018" bytecount = "0.6" clap = "2.33" itertools = "0.9" +opener = "0.4" regex = "1" -lazy_static = "1.0" shell-escape = "0.1" walkdir = "2" diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 5baa31d5cde..43cb2954b74 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -1,42 +1,47 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] +#![feature(once_cell)] use itertools::Itertools; -use lazy_static::lazy_static; use regex::Regex; use std::collections::HashMap; use std::ffi::OsStr; use std::fs; +use std::lazy::SyncLazy; use std::path::{Path, PathBuf}; use walkdir::WalkDir; pub mod fmt; pub mod new_lint; pub mod ra_setup; +pub mod serve; pub mod stderr_length_check; pub mod update_lints; -lazy_static! { - static ref DEC_CLIPPY_LINT_RE: Regex = Regex::new( +static DEC_CLIPPY_LINT_RE: SyncLazy = SyncLazy::new(|| { + Regex::new( r#"(?x) - declare_clippy_lint!\s*[\{(] - (?:\s+///.*)* - \s+pub\s+(?P[A-Z_][A-Z_0-9]*)\s*,\s* - (?P[a-z_]+)\s*,\s* - "(?P(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})] - "# + declare_clippy_lint!\s*[\{(] + (?:\s+///.*)* + \s+pub\s+(?P[A-Z_][A-Z_0-9]*)\s*,\s* + (?P[a-z_]+)\s*,\s* + "(?P(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})] +"#, ) - .unwrap(); - static ref DEC_DEPRECATED_LINT_RE: Regex = Regex::new( + .unwrap() +}); + +static DEC_DEPRECATED_LINT_RE: SyncLazy = SyncLazy::new(|| { + Regex::new( r#"(?x) - declare_deprecated_lint!\s*[{(]\s* - (?:\s+///.*)* - \s+pub\s+(?P[A-Z_][A-Z_0-9]*)\s*,\s* - "(?P(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})] - "# + declare_deprecated_lint!\s*[{(]\s* + (?:\s+///.*)* + \s+pub\s+(?P[A-Z_][A-Z_0-9]*)\s*,\s* + "(?P(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})] +"#, ) - .unwrap(); - static ref NL_ESCAPE_RE: Regex = Regex::new(r#"\\\n\s*"#).unwrap(); -} + .unwrap() +}); +static NL_ESCAPE_RE: SyncLazy = SyncLazy::new(|| Regex::new(r#"\\\n\s*"#).unwrap()); pub static DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.html"; diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 281037ae37c..7a8cbd5251d 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -1,7 +1,7 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] use clap::{App, Arg, SubCommand}; -use clippy_dev::{fmt, new_lint, ra_setup, stderr_length_check, update_lints}; +use clippy_dev::{fmt, new_lint, ra_setup, serve, stderr_length_check, update_lints}; fn main() { let matches = App::new("Clippy developer tooling") @@ -100,6 +100,19 @@ fn main() { .required(true), ), ) + .subcommand( + SubCommand::with_name("serve") + .about("Launch a local 'ALL the Clippy Lints' website in a browser") + .arg( + Arg::with_name("port") + .long("port") + .short("p") + .help("Local port for the http server") + .default_value("8000") + .validator_os(serve::validate_port), + ) + .arg(Arg::with_name("lint").help("Which lint's page to load initially (optional)")), + ) .get_matches(); match matches.subcommand() { @@ -129,6 +142,11 @@ fn main() { stderr_length_check::check(); }, ("ra-setup", Some(matches)) => ra_setup::run(matches.value_of("rustc-repo-path")), + ("serve", Some(matches)) => { + let port = matches.value_of("port").unwrap().parse().unwrap(); + let lint = matches.value_of("lint"); + serve::run(port, lint); + }, _ => {}, } } diff --git a/clippy_dev/src/serve.rs b/clippy_dev/src/serve.rs new file mode 100644 index 00000000000..a46c0e4d3f0 --- /dev/null +++ b/clippy_dev/src/serve.rs @@ -0,0 +1,64 @@ +use std::ffi::{OsStr, OsString}; +use std::path::Path; +use std::process::Command; +use std::thread; +use std::time::{Duration, SystemTime}; + +pub fn run(port: u16, lint: Option<&str>) -> ! { + let mut url = Some(match lint { + None => format!("http://localhost:{}", port), + Some(lint) => format!("http://localhost:{}/#{}", port, lint), + }); + + loop { + if mtime("util/gh-pages/lints.json") < mtime("clippy_lints/src") { + Command::new("python3") + .arg("util/export.py") + .spawn() + .unwrap() + .wait() + .unwrap(); + } + if let Some(url) = url.take() { + thread::spawn(move || { + Command::new("python3") + .arg("-m") + .arg("http.server") + .arg(port.to_string()) + .current_dir("util/gh-pages") + .spawn() + .unwrap(); + // Give some time for python to start + thread::sleep(Duration::from_millis(500)); + // Launch browser after first export.py has completed and http.server is up + let _ = opener::open(url); + }); + } + thread::sleep(Duration::from_millis(1000)); + } +} + +fn mtime(path: impl AsRef) -> SystemTime { + let path = path.as_ref(); + if path.is_dir() { + path.read_dir() + .into_iter() + .flatten() + .flatten() + .map(|entry| mtime(&entry.path())) + .max() + .unwrap_or(SystemTime::UNIX_EPOCH) + } else { + path.metadata() + .and_then(|metadata| metadata.modified()) + .unwrap_or(SystemTime::UNIX_EPOCH) + } +} + +#[allow(clippy::missing_errors_doc)] +pub fn validate_port(arg: &OsStr) -> Result<(), OsString> { + match arg.to_string_lossy().parse::() { + Ok(_port) => Ok(()), + Err(err) => Err(OsString::from(err.to_string())), + } +} diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 341d9e601ee..fcf817b82c8 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -20,7 +20,6 @@ edition = "2018" cargo_metadata = "0.11.1" if_chain = "1.0.0" itertools = "0.9" -lazy_static = "1.0.2" pulldown-cmark = { version = "0.8", default-features = false } quine-mc_cluskey = "0.2.2" regex-syntax = "0.6" diff --git a/clippy_lints/src/asm_syntax.rs b/clippy_lints/src/asm_syntax.rs new file mode 100644 index 00000000000..ef1f1a14afc --- /dev/null +++ b/clippy_lints/src/asm_syntax.rs @@ -0,0 +1,125 @@ +use std::fmt; + +use crate::utils::span_lint_and_help; +use rustc_ast::ast::{Expr, ExprKind, InlineAsmOptions}; +use rustc_lint::{EarlyContext, EarlyLintPass, Lint}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +#[derive(Clone, Copy, PartialEq, Eq)] +enum AsmStyle { + Intel, + Att, +} + +impl fmt::Display for AsmStyle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + AsmStyle::Intel => f.write_str("Intel"), + AsmStyle::Att => f.write_str("AT&T"), + } + } +} + +impl std::ops::Not for AsmStyle { + type Output = AsmStyle; + + fn not(self) -> AsmStyle { + match self { + AsmStyle::Intel => AsmStyle::Att, + AsmStyle::Att => AsmStyle::Intel, + } + } +} + +fn check_expr_asm_syntax(lint: &'static Lint, cx: &EarlyContext<'_>, expr: &Expr, check_for: AsmStyle) { + if let ExprKind::InlineAsm(ref inline_asm) = expr.kind { + let style = if inline_asm.options.contains(InlineAsmOptions::ATT_SYNTAX) { + AsmStyle::Att + } else { + AsmStyle::Intel + }; + + if style == check_for { + span_lint_and_help( + cx, + lint, + expr.span, + &format!("{} x86 assembly syntax used", style), + None, + &format!("use {} x86 assembly syntax", !style), + ); + } + } +} + +declare_clippy_lint! { + /// **What it does:** Checks for usage of Intel x86 assembly syntax. + /// + /// **Why is this bad?** The lint has been enabled to indicate a preference + /// for AT&T x86 assembly syntax. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust,no_run + /// # #![feature(asm)] + /// # unsafe { let ptr = "".as_ptr(); + /// asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr); + /// # } + /// ``` + /// Use instead: + /// ```rust,no_run + /// # #![feature(asm)] + /// # unsafe { let ptr = "".as_ptr(); + /// asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax)); + /// # } + /// ``` + pub INLINE_ASM_X86_INTEL_SYNTAX, + restriction, + "prefer AT&T x86 assembly syntax" +} + +declare_lint_pass!(InlineAsmX86IntelSyntax => [INLINE_ASM_X86_INTEL_SYNTAX]); + +impl EarlyLintPass for InlineAsmX86IntelSyntax { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + check_expr_asm_syntax(Self::get_lints()[0], cx, expr, AsmStyle::Intel); + } +} + +declare_clippy_lint! { + /// **What it does:** Checks for usage of AT&T x86 assembly syntax. + /// + /// **Why is this bad?** The lint has been enabled to indicate a preference + /// for Intel x86 assembly syntax. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust,no_run + /// # #![feature(asm)] + /// # unsafe { let ptr = "".as_ptr(); + /// asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax)); + /// # } + /// ``` + /// Use instead: + /// ```rust,no_run + /// # #![feature(asm)] + /// # unsafe { let ptr = "".as_ptr(); + /// asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr); + /// # } + /// ``` + pub INLINE_ASM_X86_ATT_SYNTAX, + restriction, + "prefer Intel x86 assembly syntax" +} + +declare_lint_pass!(InlineAsmX86AttSyntax => [INLINE_ASM_X86_ATT_SYNTAX]); + +impl EarlyLintPass for InlineAsmX86AttSyntax { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + check_expr_asm_syntax(Self::get_lints()[0], cx, expr, AsmStyle::Att); + } +} diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index c8f153e7201..f6eadbdef0b 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -137,17 +137,17 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// // Good (as inner attribute) - /// #![inline(always)] + /// #![allow(dead_code)] /// /// fn this_is_fine() { } /// /// // Bad - /// #[inline(always)] + /// #[allow(dead_code)] /// /// fn not_quite_good_code() { } /// /// // Good (as outer attribute) - /// #[inline(always)] + /// #[allow(dead_code)] /// fn this_is_fine_too() { } /// ``` pub EMPTY_LINE_AFTER_OUTER_ATTR, diff --git a/clippy_lints/src/disallowed_method.rs b/clippy_lints/src/disallowed_method.rs new file mode 100644 index 00000000000..581c3242e37 --- /dev/null +++ b/clippy_lints/src/disallowed_method.rs @@ -0,0 +1,73 @@ +use crate::utils::span_lint; + +use rustc_data_structures::fx::FxHashSet; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::Symbol; + +declare_clippy_lint! { + /// **What it does:** Lints for specific trait methods defined in clippy.toml + /// + /// **Why is this bad?** Some methods are undesirable in certain contexts, + /// and it would be beneficial to lint for them as needed. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust,ignore + /// // example code where clippy issues a warning + /// foo.bad_method(); // Foo::bad_method is disallowed in the configuration + /// ``` + /// Use instead: + /// ```rust,ignore + /// // example code which does not raise clippy warning + /// goodStruct.bad_method(); // GoodStruct::bad_method is not disallowed + /// ``` + pub DISALLOWED_METHOD, + nursery, + "use of a disallowed method call" +} + +#[derive(Clone, Debug)] +pub struct DisallowedMethod { + disallowed: FxHashSet>, +} + +impl DisallowedMethod { + pub fn new(disallowed: &FxHashSet) -> Self { + Self { + disallowed: disallowed + .iter() + .map(|s| s.split("::").map(|seg| Symbol::intern(seg)).collect::>()) + .collect(), + } + } +} + +impl_lint_pass!(DisallowedMethod => [DISALLOWED_METHOD]); + +impl<'tcx> LateLintPass<'tcx> for DisallowedMethod { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if let ExprKind::MethodCall(_path, _, _args, _) = &expr.kind { + let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap(); + + let method_call = cx.get_def_path(def_id); + if self.disallowed.contains(&method_call) { + let method = method_call + .iter() + .map(|s| s.to_ident_string()) + .collect::>() + .join("::"); + + span_lint( + cx, + DISALLOWED_METHOD, + expr.span, + &format!("use of a disallowed method `{}`", method), + ); + } + } + } +} diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 82549c12d0a..8b022912573 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -6,6 +6,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_target::abi::LayoutOf; +use rustc_target::spec::abi::Abi; use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use crate::utils::span_lint; @@ -60,12 +61,18 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { fn check_fn( &mut self, cx: &LateContext<'tcx>, - _: intravisit::FnKind<'tcx>, + fn_kind: intravisit::FnKind<'tcx>, _: &'tcx FnDecl<'_>, body: &'tcx Body<'_>, _: Span, hir_id: HirId, ) { + if let Some(header) = fn_kind.header() { + if header.abi != Abi::Rust { + return; + } + } + // If the method is an impl for a trait, don't warn. let parent_id = cx.tcx.hir().get_parent_item(hir_id); let parent_node = cx.tcx.hir().find(parent_id); diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 70efdaeb9c6..93b5d9e178c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -7,6 +7,7 @@ #![feature(crate_visibility_modifier)] #![feature(drain_filter)] #![feature(in_band_lifetimes)] +#![feature(once_cell)] #![feature(or_patterns)] #![feature(rustc_private)] #![feature(stmt_expr_attributes)] @@ -153,6 +154,7 @@ mod utils; mod approx_const; mod arithmetic; mod as_conversions; +mod asm_syntax; mod assertions_on_constants; mod assign_ops; mod async_yields_async; @@ -176,6 +178,7 @@ mod dbg_macro; mod default_trait_access; mod dereference; mod derive; +mod disallowed_method; mod doc; mod double_comparison; mod double_parens; @@ -489,6 +492,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &arithmetic::FLOAT_ARITHMETIC, &arithmetic::INTEGER_ARITHMETIC, &as_conversions::AS_CONVERSIONS, + &asm_syntax::INLINE_ASM_X86_ATT_SYNTAX, + &asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX, &assertions_on_constants::ASSERTIONS_ON_CONSTANTS, &assign_ops::ASSIGN_OP_PATTERN, &assign_ops::MISREFACTORED_ASSIGN_OP, @@ -529,6 +534,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &derive::DERIVE_ORD_XOR_PARTIAL_ORD, &derive::EXPL_IMPL_CLONE_ON_COPY, &derive::UNSAFE_DERIVE_DESERIALIZE, + &disallowed_method::DISALLOWED_METHOD, &doc::DOC_MARKDOWN, &doc::MISSING_ERRORS_DOC, &doc::MISSING_SAFETY_DOC, @@ -851,9 +857,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &types::UNIT_CMP, &types::UNNECESSARY_CAST, &types::VEC_BOX, + &unicode::INVISIBLE_CHARACTERS, &unicode::NON_ASCII_LITERAL, &unicode::UNICODE_NOT_NFC, - &unicode::ZERO_WIDTH_SPACE, &unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD, &unnamed_address::FN_ADDRESS_COMPARISONS, &unnamed_address::VTABLE_ADDRESS_COMPARISONS, @@ -1120,11 +1126,18 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync); store.register_late_pass(|| box manual_strip::ManualStrip); store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem); + let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::>(); + store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods)); + store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax); + store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax); + store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), LintId::of(&arithmetic::INTEGER_ARITHMETIC), LintId::of(&as_conversions::AS_CONVERSIONS), + LintId::of(&asm_syntax::INLINE_ASM_X86_ATT_SYNTAX), + LintId::of(&asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX), LintId::of(&create_dir::CREATE_DIR), LintId::of(&dbg_macro::DBG_MACRO), LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE), @@ -1159,6 +1172,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&shadow::SHADOW_REUSE), LintId::of(&shadow::SHADOW_SAME), LintId::of(&strings::STRING_ADD), + LintId::of(&types::RC_BUFFER), LintId::of(&unwrap_in_result::UNWRAP_IN_RESULT), LintId::of(&verbose_file_reads::VERBOSE_FILE_READS), LintId::of(&write::PRINT_STDOUT), @@ -1463,7 +1477,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE), - LintId::of(&strings::STRING_LIT_AS_BYTES), LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), LintId::of(&swap::ALMOST_SWAPPED), @@ -1492,14 +1505,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::CHAR_LIT_AS_U8), LintId::of(&types::FN_TO_NUMERIC_CAST), LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), - LintId::of(&types::RC_BUFFER), LintId::of(&types::REDUNDANT_ALLOCATION), LintId::of(&types::TYPE_COMPLEXITY), LintId::of(&types::UNIT_ARG), LintId::of(&types::UNIT_CMP), LintId::of(&types::UNNECESSARY_CAST), LintId::of(&types::VEC_BOX), - LintId::of(&unicode::ZERO_WIDTH_SPACE), + LintId::of(&unicode::INVISIBLE_CHARACTERS), LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS), LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), @@ -1592,6 +1604,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&mut_reference::UNNECESSARY_MUT_PASSED), LintId::of(&neg_multiply::NEG_MULTIPLY), LintId::of(&new_without_default::NEW_WITHOUT_DEFAULT), + LintId::of(&non_copy_const::BORROW_INTERIOR_MUTABLE_CONST), + LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES), LintId::of(&panic_unimplemented::PANIC_PARAMS), @@ -1604,7 +1618,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&returns::LET_AND_RETURN), LintId::of(&returns::NEEDLESS_RETURN), LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), - LintId::of(&strings::STRING_LIT_AS_BYTES), LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME), LintId::of(&try_err::TRY_ERR), @@ -1747,8 +1760,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&misc::FLOAT_CMP), LintId::of(&misc::MODULO_ONE), LintId::of(&mut_key::MUTABLE_KEY_TYPE), - LintId::of(&non_copy_const::BORROW_INTERIOR_MUTABLE_CONST), - LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS), LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP), LintId::of(&ptr::MUT_FROM_REF), @@ -1766,7 +1777,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::ABSURD_EXTREME_COMPARISONS), LintId::of(&types::CAST_REF_TO_MUT), LintId::of(&types::UNIT_CMP), - LintId::of(&unicode::ZERO_WIDTH_SPACE), + LintId::of(&unicode::INVISIBLE_CHARACTERS), LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS), LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), @@ -1793,7 +1804,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE), LintId::of(&types::BOX_VEC), - LintId::of(&types::RC_BUFFER), LintId::of(&types::REDUNDANT_ALLOCATION), LintId::of(&vec::USELESS_VEC), ]); @@ -1807,6 +1817,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR), LintId::of(&cognitive_complexity::COGNITIVE_COMPLEXITY), + LintId::of(&disallowed_method::DISALLOWED_METHOD), LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM), LintId::of(&floating_point_arithmetic::IMPRECISE_FLOPS), LintId::of(&floating_point_arithmetic::SUBOPTIMAL_FLOPS), @@ -1818,6 +1829,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&needless_borrow::NEEDLESS_BORROW), LintId::of(&path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), LintId::of(&redundant_pub_crate::REDUNDANT_PUB_CRATE), + LintId::of(&strings::STRING_LIT_AS_BYTES), LintId::of(&transmute::USELESS_TRANSMUTE), LintId::of(&use_self::USE_SELF), ]); @@ -1896,6 +1908,7 @@ pub fn register_renamed(ls: &mut rustc_lint::LintStore) { ls.register_renamed("clippy::for_loop_over_option", "clippy::for_loops_over_fallibles"); ls.register_renamed("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles"); ls.register_renamed("clippy::identity_conversion", "clippy::useless_conversion"); + ls.register_renamed("clippy::zero_width_space", "clippy::invisible_characters"); } // only exists to let the dogfood integration test works. diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 4df6827d77f..d7043e7bd8f 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -1,21 +1,22 @@ +use crate::utils::paths; +use crate::utils::{get_trait_def_id, in_macro, span_lint, trait_ref_of_method}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{ - walk_fn_decl, walk_generic_param, walk_generics, walk_param_bound, walk_ty, NestedVisitorMap, Visitor, + walk_fn_decl, walk_generic_param, walk_generics, walk_item, walk_param_bound, walk_poly_trait_ref, walk_ty, + NestedVisitorMap, Visitor, }; use rustc_hir::FnRetTy::Return; use rustc_hir::{ - BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, - ItemKind, Lifetime, LifetimeName, ParamName, QPath, TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, - TyKind, WhereClause, WherePredicate, + BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, + ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, ParamName, PolyTraitRef, TraitBoundModifier, TraitFn, + TraitItem, TraitItemKind, Ty, TyKind, WhereClause, WherePredicate, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::{kw, Symbol}; - -use crate::utils::{in_macro, last_path_segment, span_lint, trait_ref_of_method}; +use std::iter::FromIterator; declare_clippy_lint! { /// **What it does:** Checks for lifetime annotations which can be removed by @@ -25,8 +26,11 @@ declare_clippy_lint! { /// complicated, while there is nothing out of the ordinary going on. Removing /// them leads to more readable code. /// - /// **Known problems:** Potential false negatives: we bail out if the function - /// has a `where` clause where lifetimes are mentioned. + /// **Known problems:** + /// - We bail out if the function has a `where` clause where lifetimes + /// are mentioned due to potenial false positives. + /// - Lifetime bounds such as `impl Foo + 'a` and `T: 'a` must be elided with the + /// placeholder notation `'_` because the fully elided notation leaves the type bound to `'static`. /// /// **Example:** /// ```rust @@ -108,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { } /// The lifetime of a &-reference. -#[derive(PartialEq, Eq, Hash, Debug)] +#[derive(PartialEq, Eq, Hash, Debug, Clone)] enum RefLt { Unnamed, Static, @@ -127,7 +131,6 @@ fn check_fn_inner<'tcx>( return; } - let mut bounds_lts = Vec::new(); let types = generics .params .iter() @@ -156,13 +159,12 @@ fn check_fn_inner<'tcx>( if bound.name != LifetimeName::Static && !bound.is_elided() { return; } - bounds_lts.push(bound); } } } } } - if could_use_elision(cx, decl, body, &generics.params, bounds_lts) { + if could_use_elision(cx, decl, body, &generics.params) { span_lint( cx, NEEDLESS_LIFETIMES, @@ -181,7 +183,6 @@ fn could_use_elision<'tcx>( func: &'tcx FnDecl<'_>, body: Option, named_generics: &'tcx [GenericParam<'_>], - bounds_lts: Vec<&'tcx Lifetime>, ) -> bool { // There are two scenarios where elision works: // * no output references, all input references have different LT @@ -204,15 +205,31 @@ fn could_use_elision<'tcx>( if let Return(ref ty) = func.output { output_visitor.visit_ty(ty); } + for lt in named_generics { + input_visitor.visit_generic_param(lt) + } - let input_lts = match input_visitor.into_vec() { - Some(lts) => lts_from_bounds(lts, bounds_lts.into_iter()), - None => return false, - }; - let output_lts = match output_visitor.into_vec() { - Some(val) => val, - None => return false, - }; + if input_visitor.abort() || output_visitor.abort() { + return false; + } + + if allowed_lts + .intersection(&FxHashSet::from_iter( + input_visitor + .nested_elision_site_lts + .iter() + .chain(output_visitor.nested_elision_site_lts.iter()) + .cloned() + .filter(|v| matches!(v, RefLt::Named(_))), + )) + .next() + .is_some() + { + return false; + } + + let input_lts = input_visitor.lts; + let output_lts = output_visitor.lts; if let Some(body_id) = body { let mut checker = BodyLifetimeChecker { @@ -277,27 +294,20 @@ fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet { allowed_lts } -fn lts_from_bounds<'a, T: Iterator>(mut vec: Vec, bounds_lts: T) -> Vec { - for lt in bounds_lts { - if lt.name != LifetimeName::Static { - vec.push(RefLt::Named(lt.name.ident().name)); - } - } - - vec -} - /// Number of unique lifetimes in the given vector. #[must_use] fn unique_lifetimes(lts: &[RefLt]) -> usize { lts.iter().collect::>().len() } +const CLOSURE_TRAIT_BOUNDS: [&[&str]; 3] = [&paths::FN, &paths::FN_MUT, &paths::FN_ONCE]; + /// A visitor usable for `rustc_front::visit::walk_ty()`. struct RefVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, lts: Vec, - abort: bool, + nested_elision_site_lts: Vec, + unelided_trait_object_lifetime: bool, } impl<'a, 'tcx> RefVisitor<'a, 'tcx> { @@ -305,7 +315,8 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> { Self { cx, lts: Vec::new(), - abort: false, + nested_elision_site_lts: Vec::new(), + unelided_trait_object_lifetime: false, } } @@ -325,40 +336,16 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> { } } - fn into_vec(self) -> Option> { - if self.abort { - None - } else { - Some(self.lts) - } + fn all_lts(&self) -> Vec { + self.lts + .iter() + .chain(self.nested_elision_site_lts.iter()) + .cloned() + .collect::>() } - fn collect_anonymous_lifetimes(&mut self, qpath: &QPath<'_>, ty: &Ty<'_>) { - if let Some(ref last_path_segment) = last_path_segment(qpath).args { - if !last_path_segment.parenthesized - && !last_path_segment - .args - .iter() - .any(|arg| matches!(arg, GenericArg::Lifetime(_))) - { - let hir_id = ty.hir_id; - match self.cx.qpath_res(qpath, hir_id) { - Res::Def(DefKind::TyAlias | DefKind::Struct, def_id) => { - let generics = self.cx.tcx.generics_of(def_id); - for _ in generics.params.as_slice() { - self.record(&None); - } - }, - Res::Def(DefKind::Trait, def_id) => { - let trait_def = self.cx.tcx.trait_def(def_id); - for _ in &self.cx.tcx.generics_of(trait_def.def_id).params { - self.record(&None); - } - }, - _ => (), - } - } - } + fn abort(&self) -> bool { + self.unelided_trait_object_lifetime } } @@ -370,30 +357,37 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { self.record(&Some(*lifetime)); } + fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'tcx>, tbm: TraitBoundModifier) { + let trait_ref = &poly_tref.trait_ref; + if CLOSURE_TRAIT_BOUNDS + .iter() + .any(|trait_path| trait_ref.trait_def_id() == get_trait_def_id(self.cx, trait_path)) + { + let mut sub_visitor = RefVisitor::new(self.cx); + sub_visitor.visit_trait_ref(trait_ref); + self.nested_elision_site_lts.append(&mut sub_visitor.all_lts()); + } else { + walk_poly_trait_ref(self, poly_tref, tbm); + } + } + fn visit_ty(&mut self, ty: &'tcx Ty<'_>) { match ty.kind { - TyKind::Rptr(ref lt, _) if lt.is_elided() => { - self.record(&None); - }, - TyKind::Path(ref path) => { - self.collect_anonymous_lifetimes(path, ty); - }, TyKind::OpaqueDef(item, _) => { let map = self.cx.tcx.hir(); - if let ItemKind::OpaqueTy(ref exist_ty) = map.expect_item(item.id).kind { - for bound in exist_ty.bounds { - if let GenericBound::Outlives(_) = *bound { - self.record(&None); - } - } - } else { - unreachable!() - } + let item = map.expect_item(item.id); + walk_item(self, item); walk_ty(self, ty); }, + TyKind::BareFn(&BareFnTy { decl, .. }) => { + let mut sub_visitor = RefVisitor::new(self.cx); + sub_visitor.visit_fn_decl(decl); + self.nested_elision_site_lts.append(&mut sub_visitor.all_lts()); + return; + }, TyKind::TraitObject(bounds, ref lt) => { if !lt.is_elided() { - self.abort = true; + self.unelided_trait_object_lifetime = true; } for bound in bounds { self.visit_poly_trait_ref(bound, TraitBoundModifier::None); @@ -430,16 +424,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, where_clause: &'tcx WhereCl walk_param_bound(&mut visitor, bound); } // and check that all lifetimes are allowed - match visitor.into_vec() { - None => return false, - Some(lts) => { - for lt in lts { - if !allowed_lts.contains(<) { - return true; - } - } - }, - } + return visitor.all_lts().iter().any(|it| !allowed_lts.contains(it)); }, WherePredicate::EqPredicate(ref pred) => { let mut visitor = RefVisitor::new(cx); diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index a36fdca5d5d..c54103b25c2 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -264,13 +264,10 @@ impl LiteralDigitGrouping { let (part, mistyped_suffixes, missing_char) = if let Some((_, exponent)) = &mut num_lit.exponent { (exponent, &["32", "64"][..], 'f') + } else if num_lit.fraction.is_some() { + (&mut num_lit.integer, &["32", "64"][..], 'f') } else { - num_lit - .fraction - .as_mut() - .map_or((&mut num_lit.integer, &["8", "16", "32", "64"][..], 'i'), |fraction| { - (fraction, &["32", "64"][..], 'f') - }) + (&mut num_lit.integer, &["8", "16", "32", "64"][..], 'i') }; let mut split = part.rsplit('_'); diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 3410341a1e3..61b63597b16 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -3,7 +3,7 @@ use crate::utils::paths; use crate::utils::sugg::Sugg; use crate::utils::usage::{is_unused, mutated_variables}; use crate::utils::{ - get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, + contains_name, get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item, last_path_segment, match_trait_method, match_type, match_var, multispan_sugg, qpath_res, snippet, snippet_opt, snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, @@ -1276,6 +1276,8 @@ fn check_for_loop_range<'tcx>( let skip = if starts_at_zero { String::new() + } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, start) { + return; } else { format!(".skip({})", snippet(cx, start.span, "..")) }; @@ -1302,6 +1304,8 @@ fn check_for_loop_range<'tcx>( if is_len_call(end, indexed) || is_end_eq_array_len(cx, end, limits, indexed_ty) { String::new() + } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, take_expr) { + return; } else { match limits { ast::RangeLimits::Closed => { @@ -2134,7 +2138,7 @@ enum VarState { DontWarn, } -/// Scan a for loop for variables that are incremented exactly once. +/// Scan a for loop for variables that are incremented exactly once and not used after that. struct IncrementVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, // context reference states: FxHashMap, // incremented variables @@ -2154,6 +2158,10 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { if let Some(def_id) = var_def_id(self.cx, expr) { if let Some(parent) = get_parent_expr(self.cx, expr) { let state = self.states.entry(def_id).or_insert(VarState::Initial); + if *state == VarState::IncrOnce { + *state = VarState::DontWarn; + return; + } match parent.kind { ExprKind::AssignOp(op, ref lhs, ref rhs) => { diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index 065c7c042d3..b4b4b3dc18d 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -18,9 +18,9 @@ declare_clippy_lint! { /// **Known problems:** None. /// /// **Example:** - /// ```rust + /// ```rust,ignore /// #[macro_use] - /// use lazy_static; + /// use some_macro; /// ``` pub MACRO_USE_IMPORTS, pedantic, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e0651f9ab5d..c0824bacbc7 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -400,8 +400,8 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for usage of `_.map(_).flatten(_)`, /// - /// **Why is this bad?** Readability, this can be written more concisely as a - /// single method call using `_.flat_map(_)` + /// **Why is this bad?** Readability, this can be written more concisely as + /// `_.flat_map(_)` /// /// **Known problems:** /// @@ -424,8 +424,8 @@ declare_clippy_lint! { /// **What it does:** Checks for usage of `_.filter(_).map(_)`, /// `_.filter(_).flat_map(_)`, `_.filter_map(_).flat_map(_)` and similar. /// - /// **Why is this bad?** Readability, this can be written more concisely as a - /// single method call. + /// **Why is this bad?** Readability, this can be written more concisely as + /// `_.filter_map(_)`. /// /// **Known problems:** Often requires a condition + Option/Iterator creation /// inside the closure. @@ -452,8 +452,8 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for usage of `_.filter_map(_).next()`. /// - /// **Why is this bad?** Readability, this can be written more concisely as a - /// single method call. + /// **Why is this bad?** Readability, this can be written more concisely as + /// `_.find_map(_)`. /// /// **Known problems:** None /// @@ -496,8 +496,8 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for usage of `_.find(_).map(_)`. /// - /// **Why is this bad?** Readability, this can be written more concisely as a - /// single method call. + /// **Why is this bad?** Readability, this can be written more concisely as + /// `_.find_map(_)`. /// /// **Known problems:** Often requires a condition + Option/Iterator creation /// inside the closure. @@ -1276,8 +1276,8 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for usage of `_.as_ref().map(Deref::deref)` or it's aliases (such as String::as_str). /// - /// **Why is this bad?** Readability, this can be written more concisely as a - /// single method call. + /// **Why is this bad?** Readability, this can be written more concisely as + /// `_.as_deref()`. /// /// **Known problems:** None. /// @@ -1668,9 +1668,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if let ty::Opaque(def_id, _) = *ret_ty.kind() { // one of the associated types must be Self for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) { - if let ty::PredicateAtom::Projection(projection_predicate) = - predicate.skip_binders() - { + if let ty::PredicateAtom::Projection(projection_predicate) = predicate.skip_binders() { // walk the associated type and check for Self if contains_ty(projection_predicate.ty, self_ty) { return; diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 80da04fb7de..25245b3dbf0 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -1,10 +1,10 @@ +use crate::utils::qualify_min_const_fn::is_min_const_fn; use crate::utils::{fn_has_unsatisfiable_preds, has_drop, is_entrypoint_fn, span_lint, trait_ref_of_method}; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; -use crate::utils::qualify_min_const_fn::is_min_const_fn; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; use rustc_typeck::hir_ty_to_ty; diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs index 38bdd0f7ed2..7687962bdd9 100644 --- a/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/clippy_lints/src/needless_arbitrary_self_type.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_sugg; +use crate::utils::{in_macro, span_lint_and_sugg}; use if_chain::if_chain; use rustc_ast::ast::{BindingMode, Lifetime, Mutability, Param, PatKind, Path, TyKind}; use rustc_errors::Applicability; @@ -69,11 +69,30 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod if let [segment] = &path.segments[..]; if segment.ident.name == kw::SelfUpper; then { + // In case we have a named lifetime, we check if the name comes from expansion. + // If it does, at this point we know the rest of the parameter was written by the user, + // so let them decide what the name of the lifetime should be. + // See #6089 for more details. + let mut applicability = Applicability::MachineApplicable; let self_param = match (binding_mode, mutbl) { (Mode::Ref(None), Mutability::Mut) => "&mut self".to_string(), - (Mode::Ref(Some(lifetime)), Mutability::Mut) => format!("&{} mut self", &lifetime.ident.name), + (Mode::Ref(Some(lifetime)), Mutability::Mut) => { + if in_macro(lifetime.ident.span) { + applicability = Applicability::HasPlaceholders; + "&'_ mut self".to_string() + } else { + format!("&{} mut self", &lifetime.ident.name) + } + }, (Mode::Ref(None), Mutability::Not) => "&self".to_string(), - (Mode::Ref(Some(lifetime)), Mutability::Not) => format!("&{} self", &lifetime.ident.name), + (Mode::Ref(Some(lifetime)), Mutability::Not) => { + if in_macro(lifetime.ident.span) { + applicability = Applicability::HasPlaceholders; + "&'_ self".to_string() + } else { + format!("&{} self", &lifetime.ident.name) + } + }, (Mode::Value, Mutability::Mut) => "mut self".to_string(), (Mode::Value, Mutability::Not) => "self".to_string(), }; @@ -85,7 +104,7 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod "the type of the `self` parameter does not need to be arbitrary", "consider to change this parameter to", self_param, - Applicability::MachineApplicable, + applicability, ) } } @@ -93,7 +112,8 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod impl EarlyLintPass for NeedlessArbitrarySelfType { fn check_param(&mut self, cx: &EarlyContext<'_>, p: &Param) { - if !p.is_self() { + // Bail out if the parameter it's not a receiver or was not written by the user + if !p.is_self() || in_macro(p.span) { return; } diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index bb44eeb6adc..7b662eae775 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -1,6 +1,6 @@ //! Checks for uses of const which the type is not `Freeze` (`Cell`-free). //! -//! This lint is **deny** by default. +//! This lint is **warn** by default. use std::ptr; @@ -17,6 +17,8 @@ use rustc_typeck::hir_ty_to_ty; use crate::utils::{in_constant, qpath_res, span_lint_and_then}; use if_chain::if_chain; +// FIXME: this is a correctness problem but there's no suitable +// warn-by-default category. declare_clippy_lint! { /// **What it does:** Checks for declaration of `const` items which is interior /// mutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.). @@ -34,6 +36,15 @@ declare_clippy_lint! { /// `std::sync::ONCE_INIT` constant). In this case the use of `const` is legit, /// and this lint should be suppressed. /// + /// When an enum has variants with interior mutability, use of its non interior mutable + /// variants can generate false positives. See issue + /// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962) + /// + /// Types that have underlying or potential interior mutability trigger the lint whether + /// the interior mutable field is used or not. See issues + /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and + /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825) + /// /// **Example:** /// ```rust /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; @@ -49,10 +60,12 @@ declare_clippy_lint! { /// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance /// ``` pub DECLARE_INTERIOR_MUTABLE_CONST, - correctness, + style, "declaring `const` with interior mutability" } +// FIXME: this is a correctness problem but there's no suitable +// warn-by-default category. declare_clippy_lint! { /// **What it does:** Checks if `const` items which is interior mutable (e.g., /// contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly. @@ -64,7 +77,14 @@ declare_clippy_lint! { /// /// The `const` value should be stored inside a `static` item. /// - /// **Known problems:** None + /// **Known problems:** When an enum has variants with interior mutability, use of its non + /// interior mutable variants can generate false positives. See issue + /// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962) + /// + /// Types that have underlying or potential interior mutability trigger the lint whether + /// the interior mutable field is used or not. See issues + /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and + /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825) /// /// **Example:** /// ```rust @@ -81,7 +101,7 @@ declare_clippy_lint! { /// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance /// ``` pub BORROW_INTERIOR_MUTABLE_CONST, - correctness, + style, "referencing `const` with interior mutability" } diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index dfc158661cb..95594e38c9e 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -143,7 +143,7 @@ fn check_set<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) { fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) { let mut parser = regex_syntax::ParserBuilder::new() - .unicode(utf8) + .unicode(true) .allow_invalid_utf8(!utf8) .build(); diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 15b66684eab..3783bd78de2 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -69,7 +69,27 @@ declare_clippy_lint! { /// **Why is this bad?** Byte string literals (e.g., `b"foo"`) can be used /// instead. They are shorter but less discoverable than `as_bytes()`. /// - /// **Known Problems:** None. + /// **Known Problems:** + /// `"str".as_bytes()` and the suggested replacement of `b"str"` are not + /// equivalent because they have different types. The former is `&[u8]` + /// while the latter is `&[u8; 3]`. That means in general they will have a + /// different set of methods and different trait implementations. + /// + /// ```compile_fail + /// fn f(v: Vec) {} + /// + /// f("...".as_bytes().to_owned()); // works + /// f(b"...".to_owned()); // does not work, because arg is [u8; 3] not Vec + /// + /// fn g(r: impl std::io::Read) {} + /// + /// g("...".as_bytes()); // works + /// g(b"..."); // does not work + /// ``` + /// + /// The actual equivalent of `"str".as_bytes()` with the same type is not + /// `b"str"` but `&b"str"[..]`, which is a great deal of punctuation and not + /// more readable than a function call. /// /// **Example:** /// ```rust @@ -80,7 +100,7 @@ declare_clippy_lint! { /// let bs = b"a byte string"; /// ``` pub STRING_LIT_AS_BYTES, - style, + nursery, "calling `as_bytes` on a string literal instead of using a byte string literal" } diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index a29a199b8c3..5e83b6c81ec 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -216,18 +216,19 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for Rc and Arc when T is a mutable buffer type such as String or Vec + /// **What it does:** Checks for `Rc` and `Arc` when `T` is a mutable buffer type such as `String` or `Vec`. /// - /// **Why is this bad?** Expressions such as Rc have no advantage over Rc, since - /// it is larger and involves an extra level of indirection, and doesn't implement Borrow. + /// **Why is this bad?** Expressions such as `Rc` usually have no advantage over `Rc`, since + /// it is larger and involves an extra level of indirection, and doesn't implement `Borrow`. /// - /// While mutating a buffer type would still be possible with Rc::get_mut(), it only - /// works if there are no additional references yet, which defeats the purpose of + /// While mutating a buffer type would still be possible with `Rc::get_mut()`, it only + /// works if there are no additional references yet, which usually defeats the purpose of /// enclosing it in a shared ownership type. Instead, additionally wrapping the inner - /// type with an interior mutable container (such as RefCell or Mutex) would normally + /// type with an interior mutable container (such as `RefCell` or `Mutex`) would normally /// be used. /// - /// **Known problems:** None. + /// **Known problems:** This pattern can be desirable to avoid the overhead of a `RefCell` or `Mutex` for + /// cases where mutation only happens before there are any additional references. /// /// **Example:** /// ```rust,ignore @@ -241,7 +242,7 @@ declare_clippy_lint! { /// fn foo(interned: Rc) { ... } /// ``` pub RC_BUFFER, - perf, + restriction, "shared ownership of a buffer type" } diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index d8c57f0e7ae..93d59cc7fcd 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -8,18 +8,18 @@ use rustc_span::source_map::Span; use unicode_normalization::UnicodeNormalization; declare_clippy_lint! { - /// **What it does:** Checks for the Unicode zero-width space in the code. + /// **What it does:** Checks for invisible Unicode characters in the code. /// /// **Why is this bad?** Having an invisible character in the code makes for all /// sorts of April fools, but otherwise is very much frowned upon. /// /// **Known problems:** None. /// - /// **Example:** You don't see it, but there may be a zero-width space - /// somewhere in this text. - pub ZERO_WIDTH_SPACE, + /// **Example:** You don't see it, but there may be a zero-width space or soft hyphen + /// some­where in this text. + pub INVISIBLE_CHARACTERS, correctness, - "using a zero-width space in a string literal, which is confusing" + "using an invisible character in a string literal, which is confusing" } declare_clippy_lint! { @@ -63,7 +63,7 @@ declare_clippy_lint! { "using a Unicode literal not in NFC normal form (see [Unicode tr15](http://www.unicode.org/reports/tr15/) for further information)" } -declare_lint_pass!(Unicode => [ZERO_WIDTH_SPACE, NON_ASCII_LITERAL, UNICODE_NOT_NFC]); +declare_lint_pass!(Unicode => [INVISIBLE_CHARACTERS, NON_ASCII_LITERAL, UNICODE_NOT_NFC]); impl LateLintPass<'_> for Unicode { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { @@ -91,14 +91,17 @@ fn escape>(s: T) -> String { fn check_str(cx: &LateContext<'_>, span: Span, id: HirId) { let string = snippet(cx, span, ""); - if string.contains('\u{200B}') { + if string.chars().any(|c| ['\u{200B}', '\u{ad}', '\u{2060}'].contains(&c)) { span_lint_and_sugg( cx, - ZERO_WIDTH_SPACE, + INVISIBLE_CHARACTERS, span, - "zero-width space detected", + "invisible character detected", "consider replacing the string with", - string.replace("\u{200B}", "\\u{200B}"), + string + .replace("\u{200B}", "\\u{200B}") + .replace("\u{ad}", "\\u{AD}") + .replace("\u{2060}", "\\u{2060}"), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/unnecessary_sort_by.rs b/clippy_lints/src/unnecessary_sort_by.rs index 9b6a9075a29..1307237dbc7 100644 --- a/clippy_lints/src/unnecessary_sort_by.rs +++ b/clippy_lints/src/unnecessary_sort_by.rs @@ -170,22 +170,12 @@ fn mirrored_exprs( } fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { - // NOTE: Vectors of references are not supported. In order to avoid hitting https://github.com/rust-lang/rust/issues/34162, - // (different unnamed lifetimes for closure arg and return type) we need to make sure the suggested - // closure parameter is not a reference in case we suggest `Reverse`. Trying to destructure more - // than one level of references would add some extra complexity as we would have to compensate - // in the closure body. - if_chain! { if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind; if let name = name_ident.ident.name.to_ident_string(); if name == "sort_by" || name == "sort_unstable_by"; if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args; - let vec_ty = cx.typeck_results().expr_ty(vec); - if utils::is_type_diagnostic_item(cx, vec_ty, sym!(vec_type)); - let ty = vec_ty.walk().nth(1).unwrap().expect_ty(); // T in Vec - if !matches!(&ty.kind(), ty::Ref(..)); - if utils::is_copy(cx, ty); + if utils::is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym!(vec_type)); if let closure_body = cx.tcx.hir().body(*closure_body_id); if let &[ Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..}, @@ -210,40 +200,32 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { let vec_name = Sugg::hir(cx, &args[0], "..").to_string(); let unstable = name == "sort_unstable_by"; - if_chain! { - if let ExprKind::Path(QPath::Resolved(_, Path { - segments: [PathSegment { ident: left_name, .. }], .. - })) = &left_expr.kind; - if left_name == left_ident; - then { - return Some(LintTrigger::Sort(SortDetection { vec_name, unstable })) - } else { - if !key_returns_borrow(cx, left_expr) { - return Some(LintTrigger::SortByKey(SortByKeyDetection { - vec_name, - unstable, - closure_arg, - closure_body, - reverse - })) - } + if let ExprKind::Path(QPath::Resolved(_, Path { + segments: [PathSegment { ident: left_name, .. }], .. + })) = &left_expr.kind { + if left_name == left_ident { + return Some(LintTrigger::Sort(SortDetection { vec_name, unstable })); } } + + if !expr_borrows(cx, left_expr) { + return Some(LintTrigger::SortByKey(SortByKeyDetection { + vec_name, + unstable, + closure_arg, + closure_body, + reverse + })); + } } } None } -fn key_returns_borrow(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - if let Some(def_id) = utils::fn_def_id(cx, expr) { - let output = cx.tcx.fn_sig(def_id).output(); - let ty = output.skip_binder(); - return matches!(ty.kind(), ty::Ref(..)) - || ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))); - } - - false +fn expr_borrows(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + let ty = cx.typeck_results().expr_ty(expr); + matches!(ty.kind(), ty::Ref(..)) || ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))) } impl LateLintPass<'_> for UnnecessarySortBy { @@ -256,7 +238,7 @@ impl LateLintPass<'_> for UnnecessarySortBy { "use Vec::sort_by_key here instead", "try", format!( - "{}.sort{}_by_key(|&{}| {})", + "{}.sort{}_by_key(|{}| {})", trigger.vec_name, if trigger.unstable { "_unstable" } else { "" }, trigger.closure_arg, diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 9c5a12ea9c8..dd2fd0bb445 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -2,10 +2,10 @@ #![deny(clippy::missing_docs_in_private_items)] -use lazy_static::lazy_static; use rustc_ast::ast::{LitKind, MetaItemKind, NestedMetaItem}; use rustc_span::source_map; use source_map::Span; +use std::lazy::SyncLazy; use std::path::{Path, PathBuf}; use std::sync::Mutex; use std::{env, fmt, fs, io}; @@ -54,9 +54,8 @@ impl From for Error { } } -lazy_static! { - static ref ERRORS: Mutex> = Mutex::new(Vec::new()); -} +/// Vec of errors that might be collected during config toml parsing +static ERRORS: SyncLazy>> = SyncLazy::new(|| Mutex::new(Vec::new())); macro_rules! define_Conf { ($(#[$doc:meta] ($config:ident, $config_str:literal: $Ty:ty, $default:expr),)+) => { @@ -82,6 +81,7 @@ macro_rules! define_Conf { use serde::Deserialize; pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<$Ty, D::Error> { use super::super::{ERRORS, Error}; + Ok( <$Ty>::deserialize(deserializer).unwrap_or_else(|e| { ERRORS @@ -164,6 +164,8 @@ define_Conf! { (max_fn_params_bools, "max_fn_params_bools": u64, 3), /// Lint: WILDCARD_IMPORTS. Whether to allow certain wildcard imports (prelude, super in tests). (warn_on_all_wildcard_imports, "warn_on_all_wildcard_imports": bool, false), + /// Lint: DISALLOWED_METHOD. The list of blacklisted methods to lint about. NB: `bar` is not here since it has legitimate uses + (disallowed_methods, "disallowed_methods": Vec, Vec::::new()), } impl Default for Conf { diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 247effde19b..790ac4f7dd8 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -18,9 +18,9 @@ pub mod internal_lints; pub mod numeric_literal; pub mod paths; pub mod ptr; +pub mod qualify_min_const_fn; pub mod sugg; pub mod usage; -pub mod qualify_min_const_fn; pub use self::attrs::*; pub use self::diagnostics::*; @@ -47,7 +47,6 @@ use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; use rustc_middle::ty::{self, layout::IntegerExt, Ty, TyCtxt, TypeFoldable}; -use rustc_mir::const_eval; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::original_sp; use rustc_span::symbol::{self, kw, Symbol}; @@ -884,19 +883,11 @@ pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { /// Checks if an expression is constructing a tuple-like enum variant or struct pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - fn has_no_arguments(cx: &LateContext<'_>, def_id: DefId) -> bool { - cx.tcx.fn_sig(def_id).skip_binder().inputs().is_empty() - } - if let ExprKind::Call(ref fun, _) = expr.kind { if let ExprKind::Path(ref qp) = fun.kind { let res = cx.qpath_res(qp, fun.hir_id); return match res { def::Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true, - // FIXME: check the constness of the arguments, see https://github.com/rust-lang/rust-clippy/pull/5682#issuecomment-638681210 - def::Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) if has_no_arguments(cx, def_id) => { - const_eval::is_const_fn(cx.tcx, def_id) - }, def::Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id), _ => false, }; @@ -1287,8 +1278,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { ty::Opaque(ref def_id, _) => { for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { if let ty::PredicateAtom::Trait(trait_predicate, _) = predicate.skip_binders() { - if must_use_attr(&cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() - { + if must_use_attr(&cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() { return true; } } diff --git a/clippy_lints/src/utils/numeric_literal.rs b/clippy_lints/src/utils/numeric_literal.rs index 5e8800d38eb..52d3c2c1daf 100644 --- a/clippy_lints/src/utils/numeric_literal.rs +++ b/clippy_lints/src/utils/numeric_literal.rs @@ -36,8 +36,9 @@ pub struct NumericLiteral<'a> { pub integer: &'a str, /// The fraction part of the number. pub fraction: Option<&'a str>, - /// The character used as exponent separator (b'e' or b'E') and the exponent part. - pub exponent: Option<(char, &'a str)>, + /// The exponent separator (b'e' or b'E') including preceding underscore if present + /// and the exponent part. + pub exponent: Option<(&'a str, &'a str)>, /// The type suffix, including preceding underscore if present. pub suffix: Option<&'a str>, @@ -100,7 +101,7 @@ impl<'a> NumericLiteral<'a> { self.radix == Radix::Decimal } - pub fn split_digit_parts(digits: &str, float: bool) -> (&str, Option<&str>, Option<(char, &str)>) { + pub fn split_digit_parts(digits: &str, float: bool) -> (&str, Option<&str>, Option<(&str, &str)>) { let mut integer = digits; let mut fraction = None; let mut exponent = None; @@ -113,12 +114,14 @@ impl<'a> NumericLiteral<'a> { fraction = Some(&digits[i + 1..]); }, 'e' | 'E' => { - if integer.len() > i { - integer = &digits[..i]; + let exp_start = if digits[..i].ends_with('_') { i - 1 } else { i }; + + if integer.len() > exp_start { + integer = &digits[..exp_start]; } else { - fraction = Some(&digits[integer.len() + 1..i]); + fraction = Some(&digits[integer.len() + 1..exp_start]); }; - exponent = Some((c, &digits[i + 1..])); + exponent = Some((&digits[exp_start..=i], &digits[i + 1..])); break; }, _ => {}, @@ -153,7 +156,7 @@ impl<'a> NumericLiteral<'a> { } if let Some((separator, exponent)) = self.exponent { - output.push(separator); + output.push_str(separator); Self::group_digits(&mut output, exponent, group_size, true, false); } diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index be837a61dc0..277da9d3f3a 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -41,6 +41,9 @@ pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"]; pub const FMT_ARGUMENTS_NEW_V1: [&str; 4] = ["core", "fmt", "Arguments", "new_v1"]; pub const FMT_ARGUMENTS_NEW_V1_FORMATTED: [&str; 4] = ["core", "fmt", "Arguments", "new_v1_formatted"]; pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"]; +pub const FN: [&str; 3] = ["core", "ops", "Fn"]; +pub const FN_MUT: [&str; 3] = ["core", "ops", "FnMut"]; +pub const FN_ONCE: [&str; 3] = ["core", "ops", "FnOnce"]; pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"]; pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"]; pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"]; diff --git a/clippy_lints/src/utils/qualify_min_const_fn.rs b/clippy_lints/src/utils/qualify_min_const_fn.rs index 19d890b4554..1b4f2034272 100644 --- a/clippy_lints/src/utils/qualify_min_const_fn.rs +++ b/clippy_lints/src/utils/qualify_min_const_fn.rs @@ -1,9 +1,12 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_middle::mir::*; +use rustc_middle::mir::{ + Body, CastKind, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, + TerminatorKind, +}; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt}; -use rustc_span::symbol::{sym}; +use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::spec::abi::Abi::RustIntrinsic; use std::borrow::Cow; @@ -24,15 +27,9 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>) -> McfResult { | ty::PredicateAtom::ConstEvaluatable(..) | ty::PredicateAtom::ConstEquate(..) | ty::PredicateAtom::TypeWellFormedFromEnv(..) => continue, - ty::PredicateAtom::ObjectSafe(_) => { - panic!("object safe predicate on function: {:#?}", predicate) - } - ty::PredicateAtom::ClosureKind(..) => { - panic!("closure kind predicate on function: {:#?}", predicate) - } - ty::PredicateAtom::Subtype(_) => { - panic!("subtype predicate on function: {:#?}", predicate) - } + ty::PredicateAtom::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate), + ty::PredicateAtom::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate), + ty::PredicateAtom::Subtype(_) => panic!("subtype predicate on function: {:#?}", predicate), ty::PredicateAtom::Trait(pred, _) => { if Some(pred.def_id()) == tcx.lang_items().sized_trait() { continue; @@ -48,12 +45,12 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>) -> McfResult { on const fn parameters are unstable" .into(), )); - } + }, // other kinds of bounds are either tautologies // or cause errors in other passes _ => continue, } - } + }, } } match predicates.parent { @@ -93,24 +90,23 @@ fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { match ty.kind() { ty::Ref(_, _, hir::Mutability::Mut) => { - return Err((span, "mutable references in const fn are unstable".into())); - } + return Err((span, "mutable references in const fn are unstable".into())); + }, ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())), ty::FnPtr(..) => { - return Err((span, "function pointers in const fn are unstable".into())); - } + return Err((span, "function pointers in const fn are unstable".into())); + }, ty::Dynamic(preds, _) => { for pred in preds.iter() { match pred.skip_binder() { - ty::ExistentialPredicate::AutoTrait(_) - | ty::ExistentialPredicate::Projection(_) => { + ty::ExistentialPredicate::AutoTrait(_) | ty::ExistentialPredicate::Projection(_) => { return Err(( span, "trait bounds other than `Sized` \ on const fn parameters are unstable" .into(), )); - } + }, ty::ExistentialPredicate::Trait(trait_ref) => { if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() { return Err(( @@ -120,34 +116,23 @@ fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { .into(), )); } - } + }, } } - } - _ => {} + }, + _ => {}, } } Ok(()) } -fn check_rvalue( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - def_id: DefId, - rvalue: &Rvalue<'tcx>, - span: Span, -) -> McfResult { +fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rvalue<'tcx>, span: Span) -> McfResult { match rvalue { - Rvalue::ThreadLocalRef(_) => { - Err((span, "cannot access thread local storage in const fn".into())) - } - Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => { - check_operand(tcx, operand, span, body) - } - Rvalue::Len(place) - | Rvalue::Discriminant(place) - | Rvalue::Ref(_, _, place) - | Rvalue::AddressOf(_, place) => check_place(tcx, *place, span, body), + Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())), + Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => check_operand(tcx, operand, span, body), + Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { + check_place(tcx, *place, span, body) + }, Rvalue::Cast(CastKind::Misc, operand, cast_ty) => { use rustc_middle::ty::cast::CastTy; let cast_in = CastTy::from_ty(operand.ty(body, tcx)).expect("bad input type for cast"); @@ -155,20 +140,16 @@ fn check_rvalue( match (cast_in, cast_out) { (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => { Err((span, "casting pointers to ints is unstable in const fn".into())) - } + }, _ => check_operand(tcx, operand, span, body), } - } - Rvalue::Cast( - CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), - operand, - _, - ) => check_operand(tcx, operand, span, body), + }, + Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), operand, _) => { + check_operand(tcx, operand, span, body) + }, Rvalue::Cast( CastKind::Pointer( - PointerCast::UnsafeFnPointer - | PointerCast::ClosureFnPointer(_) - | PointerCast::ReifyFnPointer, + PointerCast::UnsafeFnPointer | PointerCast::ClosureFnPointer(_) | PointerCast::ReifyFnPointer, ), _, _, @@ -178,10 +159,7 @@ fn check_rvalue( deref_ty.ty } else { // We cannot allow this for now. - return Err(( - span, - "unsizing casts are only allowed for references right now".into(), - )); + return Err((span, "unsizing casts are only allowed for references right now".into())); }; let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id)); if let ty::Slice(_) | ty::Str = unsized_ty.kind() { @@ -192,7 +170,7 @@ fn check_rvalue( // We just can't allow trait objects until we have figured out trait method calls. 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, lhs, span, body)?; @@ -201,13 +179,14 @@ fn check_rvalue( if ty.is_integral() || ty.is_bool() || ty.is_char() { Ok(()) } else { - Err((span, "only int, `bool` and `char` operations are stable in const fn".into())) + Err(( + span, + "only int, `bool` and `char` operations are stable in const fn".into(), + )) } - } + }, Rvalue::NullaryOp(NullOp::SizeOf, _) => Ok(()), - Rvalue::NullaryOp(NullOp::Box, _) => { - Err((span, "heap allocations are not allowed in const fn".into())) - } + Rvalue::NullaryOp(NullOp::Box, _) => Err((span, "heap allocations are not allowed in const fn".into())), Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(body, tcx); if ty.is_integral() || ty.is_bool() { @@ -215,39 +194,29 @@ fn check_rvalue( } else { Err((span, "only int and `bool` operations are stable in const fn".into())) } - } + }, Rvalue::Aggregate(_, operands) => { for operand in operands { check_operand(tcx, operand, span, body)?; } Ok(()) - } + }, } } -fn check_statement( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - def_id: DefId, - statement: &Statement<'tcx>, -) -> McfResult { +fn check_statement(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, statement: &Statement<'tcx>) -> McfResult { let span = statement.source_info.span; match &statement.kind { StatementKind::Assign(box (place, rval)) => { - check_place(tcx, *place, span, body)?; + check_place(tcx, *place, span, body)?; check_rvalue(tcx, body, def_id, rval, span) - } - - StatementKind::FakeRead(_, place) => check_place(tcx, **place, span, body), + }, + StatementKind::FakeRead(_, place) | // just an assignment - StatementKind::SetDiscriminant { place, .. } => { - check_place(tcx, **place, span, body) - } + StatementKind::SetDiscriminant { place, .. } => check_place(tcx, **place, span, body), - StatementKind::LlvmInlineAsm { .. } => { - Err((span, "cannot use inline assembly in const fn".into())) - } + StatementKind::LlvmInlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())), // These are all NOPs StatementKind::StorageLive(_) @@ -259,12 +228,7 @@ fn check_statement( } } -fn check_operand( - tcx: TyCtxt<'tcx>, - operand: &Operand<'tcx>, - span: Span, - body: &Body<'tcx>, -) -> McfResult { +fn check_operand(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult { match operand { Operand::Move(place) | Operand::Copy(place) => check_place(tcx, *place, span, body), Operand::Constant(c) => match c.check_static_ptr(tcx) { @@ -274,14 +238,9 @@ fn check_operand( } } -fn check_place( - tcx: TyCtxt<'tcx>, - place: Place<'tcx>, - span: Span, - body: &Body<'tcx>, -) -> McfResult { +fn check_place(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult { let mut cursor = place.projection.as_ref(); - while let &[ref proj_base @ .., elem] = cursor { + while let [ref proj_base @ .., elem] = *cursor { cursor = proj_base; match elem { ProjectionElem::Field(..) => { @@ -289,26 +248,22 @@ fn check_place( if let Some(def) = base_ty.ty_adt_def() { // No union field accesses in `const fn` if def.is_union() { - return Err((span, "accessing union fields is unstable".into())); + return Err((span, "accessing union fields is unstable".into())); } } - } + }, ProjectionElem::ConstantIndex { .. } | ProjectionElem::Downcast(..) | ProjectionElem::Subslice { .. } | ProjectionElem::Deref - | ProjectionElem::Index(_) => {} + | ProjectionElem::Index(_) => {}, } } Ok(()) } -fn check_terminator( - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, - terminator: &Terminator<'tcx>, -) -> McfResult { +fn check_terminator(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, terminator: &Terminator<'tcx>) -> McfResult { let span = terminator.source_info.span; match &terminator.kind { TerminatorKind::FalseEdge { .. } @@ -318,20 +273,23 @@ fn check_terminator( | TerminatorKind::Resume | TerminatorKind::Unreachable => Ok(()), - TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span, body), + TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span, body), TerminatorKind::DropAndReplace { place, value, .. } => { - check_place(tcx, *place, span, body)?; + check_place(tcx, *place, span, body)?; check_operand(tcx, value, span, body) - } + }, - TerminatorKind::SwitchInt { discr, switch_ty: _, values: _, targets: _ } => { - check_operand(tcx, discr, span, body) - } + TerminatorKind::SwitchInt { + discr, + switch_ty: _, + values: _, + targets: _, + } => check_operand(tcx, discr, span, body), TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())), TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => { Err((span, "const fn generators are unstable".into())) - } + }, TerminatorKind::Call { func, @@ -343,8 +301,7 @@ fn check_terminator( } => { let fn_ty = func.ty(body, tcx); if let ty::FnDef(fn_def_id, _) = *fn_ty.kind() { - if !rustc_mir::const_eval::is_min_const_fn(tcx, fn_def_id) - { + if !rustc_mir::const_eval::is_min_const_fn(tcx, fn_def_id) { return Err(( span, format!( @@ -360,9 +317,7 @@ fn check_terminator( // within const fns. `transmute` is allowed in all other const contexts. // This won't really scale to more intrinsics or functions. Let's allow const // transmutes in const fn before we add more hacks to this. - if tcx.fn_sig(fn_def_id).abi() == RustIntrinsic - && tcx.item_name(fn_def_id) == sym::transmute - { + if tcx.fn_sig(fn_def_id).abi() == RustIntrinsic && tcx.item_name(fn_def_id) == sym::transmute { return Err(( span, "can only call `transmute` from const items, not `const fn`".into(), @@ -378,14 +333,16 @@ fn check_terminator( } else { Err((span, "can only call other const fns within const fn".into())) } - } + }, - TerminatorKind::Assert { cond, expected: _, msg: _, target: _, cleanup: _ } => { - check_operand(tcx, cond, span, body) - } + TerminatorKind::Assert { + cond, + expected: _, + msg: _, + target: _, + cleanup: _, + } => check_operand(tcx, cond, span, body), - TerminatorKind::InlineAsm { .. } => { - Err((span, "cannot use inline assembly in const fn".into())) - } + TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())), } } diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index fac63bcb993..d9d60fffcd7 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -235,8 +235,19 @@ impl EarlyLintPass for Write { } fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &MacCall) { + fn is_build_script(cx: &EarlyContext<'_>) -> bool { + // Cargo sets the crate name for build scripts to `build_script_build` + cx.sess + .opts + .crate_name + .as_ref() + .map_or(false, |crate_name| crate_name == "build_script_build") + } + if mac.path == sym!(println) { - span_lint(cx, PRINT_STDOUT, mac.span(), "use of `println!`"); + if !is_build_script(cx) { + span_lint(cx, PRINT_STDOUT, mac.span(), "use of `println!`"); + } if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) { if fmt_str.symbol == Symbol::intern("") { span_lint_and_sugg( @@ -251,7 +262,9 @@ impl EarlyLintPass for Write { } } } else if mac.path == sym!(print) { - span_lint(cx, PRINT_STDOUT, mac.span(), "use of `print!`"); + if !is_build_script(cx) { + span_lint(cx, PRINT_STDOUT, mac.span(), "use of `print!`"); + } if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) { if check_newlines(&fmt_str) { span_lint_and_then( diff --git a/clippy_workspace_tests/build.rs b/clippy_workspace_tests/build.rs new file mode 100644 index 00000000000..3507168a3a9 --- /dev/null +++ b/clippy_workspace_tests/build.rs @@ -0,0 +1,7 @@ +#![deny(clippy::print_stdout)] + +fn main() { + // Test for #6041 + println!("Hello"); + print!("Hello"); +} diff --git a/doc/adding_lints.md b/doc/adding_lints.md index 21e0f6f4fc7..2869c3bf7d4 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -189,7 +189,8 @@ declare_clippy_lint! { * The section of lines prefixed with `///` constitutes the lint documentation section. This is the default documentation style and will be displayed - [like this][example_lint_page]. + [like this][example_lint_page]. To render and open this documentation locally + in a browser, run `cargo dev serve`. * `FOO_FUNCTIONS` is the name of our lint. Be sure to follow the [lint naming guidelines][lint_naming] here when naming your lint. In short, the name should state the thing that is being checked for and diff --git a/doc/basics.md b/doc/basics.md index c81e7f6e069..38959e2331b 100644 --- a/doc/basics.md +++ b/doc/basics.md @@ -13,6 +13,7 @@ Lints] or [Common Tools]. - [Setup](#setup) - [Building and Testing](#building-and-testing) - [`cargo dev`](#cargo-dev) + - [PR](#pr) ## Get the Code @@ -110,3 +111,8 @@ cargo dev new_lint # (experimental) Setup Clippy to work with rust-analyzer cargo dev ra-setup ``` + +## PR + +We follow a rustc no merge-commit policy. +See . diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index f6d529de9a3..ce3d0efab3a 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -110,7 +110,7 @@ pub static ref ALL_LINTS: Vec = vec![ }, Lint { name: "borrow_interior_mutable_const", - group: "correctness", + group: "style", desc: "referencing `const` with interior mutability", deprecation: None, module: "non_copy_const", @@ -334,7 +334,7 @@ pub static ref ALL_LINTS: Vec = vec![ }, Lint { name: "declare_interior_mutable_const", - group: "correctness", + group: "style", desc: "declaring `const` with interior mutability", deprecation: None, module: "non_copy_const", @@ -381,6 +381,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "derive", }, + Lint { + name: "disallowed_method", + group: "nursery", + desc: "use of a disallowed method call", + deprecation: None, + module: "disallowed_method", + }, Lint { name: "diverging_sub_expression", group: "complexity", @@ -885,6 +892,20 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "attrs", }, + Lint { + name: "inline_asm_x86_att_syntax", + group: "restriction", + desc: "prefer Intel x86 assembly syntax", + deprecation: None, + module: "asm_syntax", + }, + Lint { + name: "inline_asm_x86_intel_syntax", + group: "restriction", + desc: "prefer AT&T x86 assembly syntax", + deprecation: None, + module: "asm_syntax", + }, Lint { name: "inline_fn_without_body", group: "correctness", @@ -941,6 +962,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "types", }, + Lint { + name: "invisible_characters", + group: "correctness", + desc: "using an invisible character in a string literal, which is confusing", + deprecation: None, + module: "unicode", + }, Lint { name: "items_after_statements", group: "pedantic", @@ -1860,7 +1888,7 @@ pub static ref ALL_LINTS: Vec = vec![ }, Lint { name: "rc_buffer", - group: "perf", + group: "restriction", desc: "shared ownership of a buffer type", deprecation: None, module: "types", @@ -2133,7 +2161,7 @@ pub static ref ALL_LINTS: Vec = vec![ }, Lint { name: "string_lit_as_bytes", - group: "style", + group: "nursery", desc: "calling `as_bytes` on a string literal instead of using a byte string literal", deprecation: None, module: "strings", @@ -2782,13 +2810,6 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "misc", }, - Lint { - name: "zero_width_space", - group: "correctness", - desc: "using a zero-width space in a string literal, which is confusing", - deprecation: None, - module: "unicode", - }, Lint { name: "zst_offset", group: "correctness", diff --git a/tests/cargo/mod.rs b/tests/cargo/mod.rs index 3c385343f70..a8f3e3145f6 100644 --- a/tests/cargo/mod.rs +++ b/tests/cargo/mod.rs @@ -1,27 +1,24 @@ -use lazy_static::lazy_static; use std::env; +use std::lazy::SyncLazy; use std::path::PathBuf; -lazy_static! { - pub static ref CARGO_TARGET_DIR: PathBuf = { - match env::var_os("CARGO_TARGET_DIR") { - Some(v) => v.into(), - None => env::current_dir().unwrap().join("target"), +pub static CARGO_TARGET_DIR: SyncLazy = SyncLazy::new(|| match env::var_os("CARGO_TARGET_DIR") { + Some(v) => v.into(), + None => env::current_dir().unwrap().join("target"), +}); + +pub static TARGET_LIB: SyncLazy = SyncLazy::new(|| { + if let Some(path) = option_env!("TARGET_LIBS") { + path.into() + } else { + let mut dir = CARGO_TARGET_DIR.clone(); + if let Some(target) = env::var_os("CARGO_BUILD_TARGET") { + dir.push(target); } - }; - pub static ref TARGET_LIB: PathBuf = { - if let Some(path) = option_env!("TARGET_LIBS") { - path.into() - } else { - let mut dir = CARGO_TARGET_DIR.clone(); - if let Some(target) = env::var_os("CARGO_BUILD_TARGET") { - dir.push(target); - } - dir.push(env!("PROFILE")); - dir - } - }; -} + dir.push(env!("PROFILE")); + dir + } +}); #[must_use] pub fn is_rustc_test_suite() -> bool { diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 697823712bf..0e8f7683103 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -1,4 +1,5 @@ #![feature(test)] // compiletest_rs requires this attribute +#![feature(once_cell)] use compiletest_rs as compiletest; use compiletest_rs::common::Mode as TestMode; @@ -71,7 +72,7 @@ fn default_config() -> compiletest::Config { } config.target_rustcflags = Some(format!( - "-L {0} -L {1} -Dwarnings -Zui-testing {2}", + "--emit=metadata -L {0} -L {1} -Dwarnings -Zui-testing {2}", host_lib().join("deps").display(), cargo::TARGET_LIB.join("deps").display(), third_party_crates(), diff --git a/tests/dogfood.rs b/tests/dogfood.rs index 81af3d3033b..48e0478f169 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -1,15 +1,14 @@ // Dogfood cannot run on Windows #![cfg(not(windows))] +#![feature(once_cell)] -use lazy_static::lazy_static; +use std::lazy::SyncLazy; use std::path::PathBuf; use std::process::Command; mod cargo; -lazy_static! { - static ref CLIPPY_PATH: PathBuf = cargo::TARGET_LIB.join("cargo-clippy"); -} +static CLIPPY_PATH: SyncLazy = SyncLazy::new(|| cargo::TARGET_LIB.join("cargo-clippy")); #[test] fn dogfood_clippy() { diff --git a/tests/ui-toml/toml_disallowed_method/clippy.toml b/tests/ui-toml/toml_disallowed_method/clippy.toml new file mode 100644 index 00000000000..a1f515e443d --- /dev/null +++ b/tests/ui-toml/toml_disallowed_method/clippy.toml @@ -0,0 +1 @@ +disallowed-methods = ["core::iter::traits::iterator::Iterator::sum", "regex::re_unicode::Regex::is_match"] diff --git a/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs b/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs new file mode 100644 index 00000000000..3d3f0729abd --- /dev/null +++ b/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs @@ -0,0 +1,13 @@ +#![warn(clippy::disallowed_method)] + +extern crate regex; +use regex::Regex; + +fn main() { + let a = vec![1, 2, 3, 4]; + let re = Regex::new(r"ab.*c").unwrap(); + + re.is_match("abc"); + + a.iter().sum::(); +} diff --git a/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr b/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr new file mode 100644 index 00000000000..ed91b5a6796 --- /dev/null +++ b/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr @@ -0,0 +1,16 @@ +error: use of a disallowed method `regex::re_unicode::Regex::is_match` + --> $DIR/conf_disallowed_method.rs:10:5 + | +LL | re.is_match("abc"); + | ^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::disallowed-method` implied by `-D warnings` + +error: use of a disallowed method `core::iter::traits::iterator::Iterator::sum` + --> $DIR/conf_disallowed_method.rs:12:5 + | +LL | a.iter().sum::(); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 6fbba01416a..103ec27e7d7 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -1,4 +1,4 @@ -error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `third-party` at line 5 column 1 +error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `third-party` at line 5 column 1 error: aborting due to previous error diff --git a/tests/ui/asm_syntax.rs b/tests/ui/asm_syntax.rs new file mode 100644 index 00000000000..658cae397e1 --- /dev/null +++ b/tests/ui/asm_syntax.rs @@ -0,0 +1,31 @@ +#![feature(asm)] +// only-x86_64 + +#[warn(clippy::inline_asm_x86_intel_syntax)] +mod warn_intel { + pub(super) unsafe fn use_asm() { + asm!(""); + asm!("", options()); + asm!("", options(nostack)); + asm!("", options(att_syntax)); + asm!("", options(nostack, att_syntax)); + } +} + +#[warn(clippy::inline_asm_x86_att_syntax)] +mod warn_att { + pub(super) unsafe fn use_asm() { + asm!(""); + asm!("", options()); + asm!("", options(nostack)); + asm!("", options(att_syntax)); + asm!("", options(nostack, att_syntax)); + } +} + +fn main() { + unsafe { + warn_att::use_asm(); + warn_intel::use_asm(); + } +} diff --git a/tests/ui/asm_syntax.stderr b/tests/ui/asm_syntax.stderr new file mode 100644 index 00000000000..27b51166eac --- /dev/null +++ b/tests/ui/asm_syntax.stderr @@ -0,0 +1,44 @@ +error: Intel x86 assembly syntax used + --> $DIR/asm_syntax.rs:7:9 + | +LL | asm!(""); + | ^^^^^^^^^ + | + = note: `-D clippy::inline-asm-x86-intel-syntax` implied by `-D warnings` + = help: use AT&T x86 assembly syntax + +error: Intel x86 assembly syntax used + --> $DIR/asm_syntax.rs:8:9 + | +LL | asm!("", options()); + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: use AT&T x86 assembly syntax + +error: Intel x86 assembly syntax used + --> $DIR/asm_syntax.rs:9:9 + | +LL | asm!("", options(nostack)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use AT&T x86 assembly syntax + +error: AT&T x86 assembly syntax used + --> $DIR/asm_syntax.rs:21:9 + | +LL | asm!("", options(att_syntax)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::inline-asm-x86-att-syntax` implied by `-D warnings` + = help: use Intel x86 assembly syntax + +error: AT&T x86 assembly syntax used + --> $DIR/asm_syntax.rs:22:9 + | +LL | asm!("", options(nostack, att_syntax)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use Intel x86 assembly syntax + +error: aborting due to 5 previous errors + diff --git a/tests/ui/attrs.rs b/tests/ui/attrs.rs index 32685038067..8df6e19421e 100644 --- a/tests/ui/attrs.rs +++ b/tests/ui/attrs.rs @@ -1,8 +1,5 @@ #![warn(clippy::inline_always, clippy::deprecated_semver)] #![allow(clippy::assertions_on_constants)] -// Test that the whole restriction group is not enabled -#![warn(clippy::restriction)] -#![deny(clippy::restriction)] #![allow(clippy::missing_docs_in_private_items, clippy::panic, clippy::unreachable)] #[inline(always)] diff --git a/tests/ui/attrs.stderr b/tests/ui/attrs.stderr index 4324984dd60..df4e9e20b64 100644 --- a/tests/ui/attrs.stderr +++ b/tests/ui/attrs.stderr @@ -1,5 +1,5 @@ error: you have declared `#[inline(always)]` on `test_attr_lint`. This is usually a bad idea - --> $DIR/attrs.rs:8:1 + --> $DIR/attrs.rs:5:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[inline(always)] = note: `-D clippy::inline-always` implied by `-D warnings` error: the since field must contain a semver-compliant version - --> $DIR/attrs.rs:28:14 + --> $DIR/attrs.rs:25:14 | LL | #[deprecated(since = "forever")] | ^^^^^^^^^^^^^^^^^ @@ -15,27 +15,10 @@ LL | #[deprecated(since = "forever")] = note: `-D clippy::deprecated-semver` implied by `-D warnings` error: the since field must contain a semver-compliant version - --> $DIR/attrs.rs:31:14 + --> $DIR/attrs.rs:28:14 | LL | #[deprecated(since = "1")] | ^^^^^^^^^^^ -error: restriction lints are not meant to be all enabled - --> $DIR/attrs.rs:4:9 - | -LL | #![warn(clippy::restriction)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings` - = help: try enabling only the lints you really need - -error: restriction lints are not meant to be all enabled - --> $DIR/attrs.rs:5:9 - | -LL | #![deny(clippy::restriction)] - | ^^^^^^^^^^^^^^^^^^^ - | - = help: try enabling only the lints you really need - -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/auxiliary/proc_macro_attr.rs b/tests/ui/auxiliary/proc_macro_attr.rs index e6626d57a77..de670cdfc31 100644 --- a/tests/ui/auxiliary/proc_macro_attr.rs +++ b/tests/ui/auxiliary/proc_macro_attr.rs @@ -1,7 +1,8 @@ +// compile-flags: --emit=link // no-prefer-dynamic #![crate_type = "proc-macro"] -#![feature(repr128, proc_macro_hygiene, proc_macro_quote)] +#![feature(repr128, proc_macro_hygiene, proc_macro_quote, box_patterns)] #![allow(clippy::useless_conversion)] extern crate proc_macro; @@ -11,7 +12,11 @@ extern crate syn; use proc_macro::TokenStream; use quote::{quote, quote_spanned}; use syn::parse_macro_input; -use syn::{parse_quote, ItemTrait, TraitItem}; +use syn::spanned::Spanned; +use syn::token::Star; +use syn::{ + parse_quote, FnArg, ImplItem, ItemImpl, ItemTrait, Lifetime, Pat, PatIdent, PatType, Signature, TraitItem, Type, +}; #[proc_macro_attribute] pub fn fake_async_trait(_args: TokenStream, input: TokenStream) -> TokenStream { @@ -35,3 +40,56 @@ pub fn fake_async_trait(_args: TokenStream, input: TokenStream) -> TokenStream { } TokenStream::from(quote!(#item)) } + +#[proc_macro_attribute] +pub fn rename_my_lifetimes(_args: TokenStream, input: TokenStream) -> TokenStream { + fn make_name(count: usize) -> String { + format!("'life{}", count) + } + + fn mut_receiver_of(sig: &mut Signature) -> Option<&mut FnArg> { + let arg = sig.inputs.first_mut()?; + if let FnArg::Typed(PatType { pat, .. }) = arg { + if let Pat::Ident(PatIdent { ident, .. }) = &**pat { + if ident == "self" { + return Some(arg); + } + } + } + None + } + + let mut elided = 0; + let mut item = parse_macro_input!(input as ItemImpl); + + // Look for methods having arbitrary self type taken by &mut ref + for inner in &mut item.items { + if let ImplItem::Method(method) = inner { + if let Some(FnArg::Typed(pat_type)) = mut_receiver_of(&mut method.sig) { + if let box Type::Reference(reference) = &mut pat_type.ty { + // Target only unnamed lifetimes + let name = match &reference.lifetime { + Some(lt) if lt.ident == "_" => make_name(elided), + None => make_name(elided), + _ => continue, + }; + elided += 1; + + // HACK: Syn uses `Span` from the proc_macro2 crate, and does not seem to reexport it. + // In order to avoid adding the dependency, get a default span from a non-existent token. + // A default span is needed to mark the code as coming from expansion. + let span = Star::default().span(); + + // Replace old lifetime with the named one + let lifetime = Lifetime::new(&name, span); + reference.lifetime = Some(parse_quote!(#lifetime)); + + // Add lifetime to the generics of the method + method.sig.generics.params.push(parse_quote!(#lifetime)); + } + } + } + } + + TokenStream::from(quote!(#item)) +} diff --git a/tests/ui/auxiliary/proc_macro_derive.rs b/tests/ui/auxiliary/proc_macro_derive.rs index 05ffb55f620..3df8be6c232 100644 --- a/tests/ui/auxiliary/proc_macro_derive.rs +++ b/tests/ui/auxiliary/proc_macro_derive.rs @@ -1,3 +1,4 @@ +// compile-flags: --emit=link // no-prefer-dynamic #![crate_type = "proc-macro"] diff --git a/tests/ui/blanket_clippy_restriction_lints.rs b/tests/ui/blanket_clippy_restriction_lints.rs new file mode 100644 index 00000000000..d055f17526b --- /dev/null +++ b/tests/ui/blanket_clippy_restriction_lints.rs @@ -0,0 +1,8 @@ +#![warn(clippy::blanket_clippy_restriction_lints)] + +//! Test that the whole restriction group is not enabled +#![warn(clippy::restriction)] +#![deny(clippy::restriction)] +#![forbid(clippy::restriction)] + +fn main() {} diff --git a/tests/ui/blanket_clippy_restriction_lints.stderr b/tests/ui/blanket_clippy_restriction_lints.stderr new file mode 100644 index 00000000000..537557f8b0a --- /dev/null +++ b/tests/ui/blanket_clippy_restriction_lints.stderr @@ -0,0 +1,27 @@ +error: restriction lints are not meant to be all enabled + --> $DIR/blanket_clippy_restriction_lints.rs:4:9 + | +LL | #![warn(clippy::restriction)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings` + = help: try enabling only the lints you really need + +error: restriction lints are not meant to be all enabled + --> $DIR/blanket_clippy_restriction_lints.rs:5:9 + | +LL | #![deny(clippy::restriction)] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: try enabling only the lints you really need + +error: restriction lints are not meant to be all enabled + --> $DIR/blanket_clippy_restriction_lints.rs:6:11 + | +LL | #![forbid(clippy::restriction)] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: try enabling only the lints you really need + +error: aborting due to 3 previous errors + diff --git a/tests/ui/crashes/associated-constant-ice.rs b/tests/ui/crashes/associated-constant-ice.rs index 4bb833795bb..948deba3ea6 100644 --- a/tests/ui/crashes/associated-constant-ice.rs +++ b/tests/ui/crashes/associated-constant-ice.rs @@ -1,5 +1,3 @@ -// run-pass - /// Test for https://github.com/rust-lang/rust-clippy/issues/1698 pub trait Trait { diff --git a/tests/ui/crashes/auxiliary/proc_macro_crash.rs b/tests/ui/crashes/auxiliary/proc_macro_crash.rs index 086548e58ed..619d11cefc4 100644 --- a/tests/ui/crashes/auxiliary/proc_macro_crash.rs +++ b/tests/ui/crashes/auxiliary/proc_macro_crash.rs @@ -1,3 +1,4 @@ +// compile-flags: --emit=link // no-prefer-dynamic // ^ compiletest by default builds all aux files as dylibs, but we don't want that for proc-macro // crates. If we don't set this, compiletest will override the `crate_type` attribute below and diff --git a/tests/ui/crashes/cc_seme.rs b/tests/ui/crashes/cc_seme.rs index c48c7e9e6c6..98588be9cf8 100644 --- a/tests/ui/crashes/cc_seme.rs +++ b/tests/ui/crashes/cc_seme.rs @@ -1,5 +1,3 @@ -// run-pass - #[allow(dead_code)] /// Test for https://github.com/rust-lang/rust-clippy/issues/478 diff --git a/tests/ui/crashes/enum-glob-import-crate.rs b/tests/ui/crashes/enum-glob-import-crate.rs index db1fa871afe..dca32aa3b56 100644 --- a/tests/ui/crashes/enum-glob-import-crate.rs +++ b/tests/ui/crashes/enum-glob-import-crate.rs @@ -1,5 +1,3 @@ -// run-pass - #![deny(clippy::all)] #![allow(unused_imports)] diff --git a/tests/ui/crashes/ice-1588.rs b/tests/ui/crashes/ice-1588.rs index 15d0f705b36..b0a3d11bce4 100644 --- a/tests/ui/crashes/ice-1588.rs +++ b/tests/ui/crashes/ice-1588.rs @@ -1,5 +1,3 @@ -// run-pass - #![allow(clippy::all)] /// Test for https://github.com/rust-lang/rust-clippy/issues/1588 diff --git a/tests/ui/crashes/ice-1782.rs b/tests/ui/crashes/ice-1782.rs index 1ca6b6976b3..81af88962a6 100644 --- a/tests/ui/crashes/ice-1782.rs +++ b/tests/ui/crashes/ice-1782.rs @@ -1,5 +1,3 @@ -// run-pass - #![allow(dead_code, unused_variables)] /// Should not trigger an ICE in `SpanlessEq` / `consts::constant` diff --git a/tests/ui/crashes/ice-1969.rs b/tests/ui/crashes/ice-1969.rs index 837ec9df31a..96a8fe6c24d 100644 --- a/tests/ui/crashes/ice-1969.rs +++ b/tests/ui/crashes/ice-1969.rs @@ -1,5 +1,3 @@ -// run-pass - #![allow(clippy::all)] /// Test for https://github.com/rust-lang/rust-clippy/issues/1969 diff --git a/tests/ui/crashes/ice-2499.rs b/tests/ui/crashes/ice-2499.rs index ffef1631775..45b3b1869dd 100644 --- a/tests/ui/crashes/ice-2499.rs +++ b/tests/ui/crashes/ice-2499.rs @@ -1,5 +1,3 @@ -// run-pass - #![allow(dead_code, clippy::char_lit_as_u8, clippy::needless_bool)] /// Should not trigger an ICE in `SpanlessHash` / `consts::constant` diff --git a/tests/ui/crashes/ice-2594.rs b/tests/ui/crashes/ice-2594.rs index ac19f1976e9..3f3986b6fc6 100644 --- a/tests/ui/crashes/ice-2594.rs +++ b/tests/ui/crashes/ice-2594.rs @@ -1,5 +1,3 @@ -// run-pass - #![allow(dead_code, unused_variables)] /// Should not trigger an ICE in `SpanlessHash` / `consts::constant` diff --git a/tests/ui/crashes/ice-2727.rs b/tests/ui/crashes/ice-2727.rs index d832c286033..56024abc8f5 100644 --- a/tests/ui/crashes/ice-2727.rs +++ b/tests/ui/crashes/ice-2727.rs @@ -1,5 +1,3 @@ -// run-pass - /// Test for https://github.com/rust-lang/rust-clippy/issues/2727 pub fn f(new: fn()) { diff --git a/tests/ui/crashes/ice-2760.rs b/tests/ui/crashes/ice-2760.rs index 9e5e299c336..f1a229f3f4f 100644 --- a/tests/ui/crashes/ice-2760.rs +++ b/tests/ui/crashes/ice-2760.rs @@ -1,5 +1,3 @@ -// run-pass - #![allow( unused_variables, clippy::blacklisted_name, diff --git a/tests/ui/crashes/ice-2774.rs b/tests/ui/crashes/ice-2774.rs index 47f8e3b18ee..d44b0fae820 100644 --- a/tests/ui/crashes/ice-2774.rs +++ b/tests/ui/crashes/ice-2774.rs @@ -1,5 +1,3 @@ -// run-pass - use std::collections::HashSet; // See rust-lang/rust-clippy#2774. diff --git a/tests/ui/crashes/ice-2774.stderr b/tests/ui/crashes/ice-2774.stderr new file mode 100644 index 00000000000..0c2d48f938f --- /dev/null +++ b/tests/ui/crashes/ice-2774.stderr @@ -0,0 +1,10 @@ +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/ice-2774.rs:15:1 + | +LL | pub fn add_barfoos_to_foos<'a>(bars: &HashSet<&'a Bar>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::needless-lifetimes` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui/crashes/ice-2862.rs b/tests/ui/crashes/ice-2862.rs index 47324ce1831..8326e3663b0 100644 --- a/tests/ui/crashes/ice-2862.rs +++ b/tests/ui/crashes/ice-2862.rs @@ -1,5 +1,3 @@ -// run-pass - /// Test for https://github.com/rust-lang/rust-clippy/issues/2862 pub trait FooMap { diff --git a/tests/ui/crashes/ice-2865.rs b/tests/ui/crashes/ice-2865.rs index c4f6c0fed68..6b1ceb50569 100644 --- a/tests/ui/crashes/ice-2865.rs +++ b/tests/ui/crashes/ice-2865.rs @@ -1,5 +1,3 @@ -// run-pass - #[allow(dead_code)] /// Test for https://github.com/rust-lang/rust-clippy/issues/2865 diff --git a/tests/ui/crashes/ice-3151.rs b/tests/ui/crashes/ice-3151.rs index ffad2d06b56..fef4d7db84d 100644 --- a/tests/ui/crashes/ice-3151.rs +++ b/tests/ui/crashes/ice-3151.rs @@ -1,5 +1,3 @@ -// run-pass - /// Test for https://github.com/rust-lang/rust-clippy/issues/2865 #[derive(Clone)] diff --git a/tests/ui/crashes/ice-3462.rs b/tests/ui/crashes/ice-3462.rs index 95c7dff9be3..7d62e315da2 100644 --- a/tests/ui/crashes/ice-3462.rs +++ b/tests/ui/crashes/ice-3462.rs @@ -1,5 +1,3 @@ -// run-pass - #![warn(clippy::all)] #![allow(clippy::blacklisted_name)] #![allow(unused)] diff --git a/tests/ui/crashes/ice-3741.rs b/tests/ui/crashes/ice-3741.rs index a548415da62..1253ddcfaeb 100644 --- a/tests/ui/crashes/ice-3741.rs +++ b/tests/ui/crashes/ice-3741.rs @@ -1,5 +1,4 @@ // aux-build:proc_macro_crash.rs -// run-pass #![warn(clippy::suspicious_else_formatting)] diff --git a/tests/ui/crashes/ice-3747.rs b/tests/ui/crashes/ice-3747.rs index d0b44ebafee..cdf018cbc88 100644 --- a/tests/ui/crashes/ice-3747.rs +++ b/tests/ui/crashes/ice-3747.rs @@ -1,5 +1,3 @@ -// run-pass - /// Test for https://github.com/rust-lang/rust-clippy/issues/3747 macro_rules! a { diff --git a/tests/ui/crashes/ice-4727.rs b/tests/ui/crashes/ice-4727.rs index cdb59caec67..2a4bc83f58a 100644 --- a/tests/ui/crashes/ice-4727.rs +++ b/tests/ui/crashes/ice-4727.rs @@ -1,5 +1,3 @@ -// run-pass - #![warn(clippy::use_self)] #[path = "auxiliary/ice-4727-aux.rs"] diff --git a/tests/ui/crashes/ice-4760.rs b/tests/ui/crashes/ice-4760.rs index ead67d5ed1b..08b06961760 100644 --- a/tests/ui/crashes/ice-4760.rs +++ b/tests/ui/crashes/ice-4760.rs @@ -1,4 +1,3 @@ -// run-pass const COUNT: usize = 2; struct Thing; trait Dummy {} diff --git a/tests/ui/crashes/ice-700.rs b/tests/ui/crashes/ice-700.rs index b06df83d51a..0cbceedbd6b 100644 --- a/tests/ui/crashes/ice-700.rs +++ b/tests/ui/crashes/ice-700.rs @@ -1,5 +1,3 @@ -// run-pass - #![deny(clippy::all)] /// Test for https://github.com/rust-lang/rust-clippy/issues/700 diff --git a/tests/ui/crashes/ice_exacte_size.rs b/tests/ui/crashes/ice_exacte_size.rs index e02eb28ab86..30e4b11ec0b 100644 --- a/tests/ui/crashes/ice_exacte_size.rs +++ b/tests/ui/crashes/ice_exacte_size.rs @@ -1,5 +1,3 @@ -// run-pass - #![deny(clippy::all)] /// Test for https://github.com/rust-lang/rust-clippy/issues/1336 diff --git a/tests/ui/crashes/if_same_then_else.rs b/tests/ui/crashes/if_same_then_else.rs index 4ef992b05e7..2f913292995 100644 --- a/tests/ui/crashes/if_same_then_else.rs +++ b/tests/ui/crashes/if_same_then_else.rs @@ -1,5 +1,3 @@ -// run-pass - #![allow(clippy::comparison_chain)] #![deny(clippy::if_same_then_else)] diff --git a/tests/ui/crashes/issue-825.rs b/tests/ui/crashes/issue-825.rs index 3d4a88ab3c4..05696e3d7d5 100644 --- a/tests/ui/crashes/issue-825.rs +++ b/tests/ui/crashes/issue-825.rs @@ -1,5 +1,3 @@ -// run-pass - #![allow(warnings)] /// Test for https://github.com/rust-lang/rust-clippy/issues/825 diff --git a/tests/ui/crashes/issues_loop_mut_cond.rs b/tests/ui/crashes/issues_loop_mut_cond.rs index c4acd5cda1b..bb238c81ebc 100644 --- a/tests/ui/crashes/issues_loop_mut_cond.rs +++ b/tests/ui/crashes/issues_loop_mut_cond.rs @@ -1,5 +1,3 @@ -// run-pass - #![allow(dead_code)] /// Issue: https://github.com/rust-lang/rust-clippy/issues/2596 diff --git a/tests/ui/crashes/match_same_arms_const.rs b/tests/ui/crashes/match_same_arms_const.rs index 848f0ea52ca..94c939665e6 100644 --- a/tests/ui/crashes/match_same_arms_const.rs +++ b/tests/ui/crashes/match_same_arms_const.rs @@ -1,5 +1,3 @@ -// run-pass - #![deny(clippy::match_same_arms)] /// Test for https://github.com/rust-lang/rust-clippy/issues/2427 diff --git a/tests/ui/crashes/mut_mut_macro.rs b/tests/ui/crashes/mut_mut_macro.rs index d8fbaa54146..a238e7896fc 100644 --- a/tests/ui/crashes/mut_mut_macro.rs +++ b/tests/ui/crashes/mut_mut_macro.rs @@ -1,5 +1,3 @@ -// run-pass - #![deny(clippy::mut_mut, clippy::zero_ptr, clippy::cmp_nan)] #![allow(dead_code)] diff --git a/tests/ui/crashes/needless_borrow_fp.rs b/tests/ui/crashes/needless_borrow_fp.rs index 48507efe1e9..4f61c76828d 100644 --- a/tests/ui/crashes/needless_borrow_fp.rs +++ b/tests/ui/crashes/needless_borrow_fp.rs @@ -1,5 +1,3 @@ -// run-pass - #[deny(clippy::all)] #[derive(Debug)] pub enum Error { diff --git a/tests/ui/crashes/needless_lifetimes_impl_trait.rs b/tests/ui/crashes/needless_lifetimes_impl_trait.rs index bd1fa4a0b1e..676564b2445 100644 --- a/tests/ui/crashes/needless_lifetimes_impl_trait.rs +++ b/tests/ui/crashes/needless_lifetimes_impl_trait.rs @@ -1,5 +1,3 @@ -// run-pass - #![deny(clippy::needless_lifetimes)] #![allow(dead_code)] diff --git a/tests/ui/crashes/needless_lifetimes_impl_trait.stderr b/tests/ui/crashes/needless_lifetimes_impl_trait.stderr new file mode 100644 index 00000000000..d68bbe78802 --- /dev/null +++ b/tests/ui/crashes/needless_lifetimes_impl_trait.stderr @@ -0,0 +1,14 @@ +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/needless_lifetimes_impl_trait.rs:15:5 + | +LL | fn baz<'a>(&'a self) -> impl Foo + 'a { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/needless_lifetimes_impl_trait.rs:1:9 + | +LL | #![deny(clippy::needless_lifetimes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/crashes/procedural_macro.rs b/tests/ui/crashes/procedural_macro.rs index f79d9ab6460..c7468493380 100644 --- a/tests/ui/crashes/procedural_macro.rs +++ b/tests/ui/crashes/procedural_macro.rs @@ -1,5 +1,3 @@ -// run-pass - #[macro_use] extern crate clippy_mini_macro_test; diff --git a/tests/ui/crashes/regressions.rs b/tests/ui/crashes/regressions.rs index 3d5063d1a3a..a41bcb33b44 100644 --- a/tests/ui/crashes/regressions.rs +++ b/tests/ui/crashes/regressions.rs @@ -1,5 +1,3 @@ -// run-pass - #![allow(clippy::blacklisted_name)] pub fn foo(bar: *const u8) { diff --git a/tests/ui/crashes/returns.rs b/tests/ui/crashes/returns.rs index f2153efc388..8021ed4607d 100644 --- a/tests/ui/crashes/returns.rs +++ b/tests/ui/crashes/returns.rs @@ -1,5 +1,3 @@ -// run-pass - /// Test for https://github.com/rust-lang/rust-clippy/issues/1346 #[deny(warnings)] diff --git a/tests/ui/crashes/single-match-else.rs b/tests/ui/crashes/single-match-else.rs index 3a4bbe310cc..1ba7ac08213 100644 --- a/tests/ui/crashes/single-match-else.rs +++ b/tests/ui/crashes/single-match-else.rs @@ -1,5 +1,3 @@ -// run-pass - #![warn(clippy::single_match_else)] //! Test for https://github.com/rust-lang/rust-clippy/issues/1588 diff --git a/tests/ui/crashes/trivial_bounds.rs b/tests/ui/crashes/trivial_bounds.rs index 2bb95c18a39..60105a8213f 100644 --- a/tests/ui/crashes/trivial_bounds.rs +++ b/tests/ui/crashes/trivial_bounds.rs @@ -1,5 +1,3 @@ -// run-pass - #![feature(trivial_bounds)] #![allow(unused, trivial_bounds)] diff --git a/tests/ui/crashes/used_underscore_binding_macro.rs b/tests/ui/crashes/used_underscore_binding_macro.rs index 265017c51d9..6d2124c12fe 100644 --- a/tests/ui/crashes/used_underscore_binding_macro.rs +++ b/tests/ui/crashes/used_underscore_binding_macro.rs @@ -1,5 +1,3 @@ -// run-pass - #![allow(clippy::useless_attribute)] //issue #2910 #[macro_use] diff --git a/tests/ui/escape_analysis.rs b/tests/ui/escape_analysis.rs index c0a52d832c0..07004489610 100644 --- a/tests/ui/escape_analysis.rs +++ b/tests/ui/escape_analysis.rs @@ -174,3 +174,11 @@ mod issue_3739 { }; } } + +/// Issue #5542 +/// +/// This shouldn't warn for `boxed_local` as it is intended to called from non-Rust code. +pub extern "C" fn do_not_warn_me(_c_pointer: Box) -> () {} + +#[rustfmt::skip] // Forces rustfmt to not add ABI +pub extern fn do_not_warn_me_no_abi(_c_pointer: Box) -> () {} diff --git a/tests/ui/explicit_counter_loop.rs b/tests/ui/explicit_counter_loop.rs index aa6ef162fe4..81d8221bd13 100644 --- a/tests/ui/explicit_counter_loop.rs +++ b/tests/ui/explicit_counter_loop.rs @@ -38,54 +38,54 @@ mod issue_1219 { let text = "banana"; let mut count = 0; for ch in text.chars() { + println!("{}", count); if ch == 'a' { continue; } count += 1; - println!("{}", count); } // should not trigger the lint because the count is conditional let text = "banana"; let mut count = 0; for ch in text.chars() { + println!("{}", count); if ch == 'a' { count += 1; } - println!("{}", count); } // should trigger the lint because the count is not conditional let text = "banana"; let mut count = 0; for ch in text.chars() { + println!("{}", count); count += 1; if ch == 'a' { continue; } - println!("{}", count); } // should trigger the lint because the count is not conditional let text = "banana"; let mut count = 0; for ch in text.chars() { + println!("{}", count); count += 1; for i in 0..2 { let _ = 123; } - println!("{}", count); } // should not trigger the lint because the count is incremented multiple times let text = "banana"; let mut count = 0; for ch in text.chars() { + println!("{}", count); count += 1; for i in 0..2 { count += 1; } - println!("{}", count); } } } @@ -96,30 +96,30 @@ mod issue_3308 { let mut skips = 0; let erasures = vec![]; for i in 0..10 { + println!("{}", skips); while erasures.contains(&(i + skips)) { skips += 1; } - println!("{}", skips); } // should not trigger the lint because the count is incremented multiple times let mut skips = 0; for i in 0..10 { + println!("{}", skips); let mut j = 0; while j < 5 { skips += 1; j += 1; } - println!("{}", skips); } // should not trigger the lint because the count is incremented multiple times let mut skips = 0; for i in 0..10 { + println!("{}", skips); for j in 0..5 { skips += 1; } - println!("{}", skips); } } } @@ -145,3 +145,16 @@ mod issue_4732 { let _closure = || println!("index: {}", index); } } + +mod issue_4677 { + pub fn test() { + let slice = &[1, 2, 3]; + + // should not trigger the lint because the count is used after incremented + let mut count = 0; + for _i in slice { + count += 1; + println!("{}", count); + } + } +} diff --git a/tests/ui/inconsistent_digit_grouping.fixed b/tests/ui/inconsistent_digit_grouping.fixed index b75f10917df..dd683e7f746 100644 --- a/tests/ui/inconsistent_digit_grouping.fixed +++ b/tests/ui/inconsistent_digit_grouping.fixed @@ -40,4 +40,8 @@ fn main() { // Ignore literals in macros let _ = mac1!(); let _ = mac2!(); + + // Issue #6096 + // Allow separating exponent with '_' + let _ = 1.025_011_10_E0; } diff --git a/tests/ui/inconsistent_digit_grouping.rs b/tests/ui/inconsistent_digit_grouping.rs index 79ce38be19b..d5d27c853c2 100644 --- a/tests/ui/inconsistent_digit_grouping.rs +++ b/tests/ui/inconsistent_digit_grouping.rs @@ -40,4 +40,8 @@ fn main() { // Ignore literals in macros let _ = mac1!(); let _ = mac2!(); + + // Issue #6096 + // Allow separating exponent with '_' + let _ = 1.025_011_10_E0; } diff --git a/tests/ui/mistyped_literal_suffix.fixed b/tests/ui/mistyped_literal_suffix.fixed index baee7735730..70cdb067d91 100644 --- a/tests/ui/mistyped_literal_suffix.fixed +++ b/tests/ui/mistyped_literal_suffix.fixed @@ -1,6 +1,11 @@ // run-rustfix -#![allow(dead_code, unused_variables, clippy::excessive_precision)] +#![allow( + dead_code, + unused_variables, + clippy::excessive_precision, + clippy::inconsistent_digit_grouping +)] fn main() { let fail14 = 2_i32; @@ -12,13 +17,13 @@ fn main() { let fail20 = 2_i8; // let fail21 = 4_i16; // - let fail24 = 12.34_f64; + let ok24 = 12.34_64; let fail25 = 1E2_f32; let fail26 = 43E7_f64; let fail27 = 243E17_f32; #[allow(overflowing_literals)] let fail28 = 241_251_235E723_f64; - let fail29 = 42_279.911_f32; + let ok29 = 42279.911_32; let _ = 1.123_45E1_f32; } diff --git a/tests/ui/mistyped_literal_suffix.rs b/tests/ui/mistyped_literal_suffix.rs index 6de447f4021..729990af399 100644 --- a/tests/ui/mistyped_literal_suffix.rs +++ b/tests/ui/mistyped_literal_suffix.rs @@ -1,6 +1,11 @@ // run-rustfix -#![allow(dead_code, unused_variables, clippy::excessive_precision)] +#![allow( + dead_code, + unused_variables, + clippy::excessive_precision, + clippy::inconsistent_digit_grouping +)] fn main() { let fail14 = 2_32; @@ -12,13 +17,13 @@ fn main() { let fail20 = 2__8; // let fail21 = 4___16; // - let fail24 = 12.34_64; + let ok24 = 12.34_64; let fail25 = 1E2_32; let fail26 = 43E7_64; let fail27 = 243E17_32; #[allow(overflowing_literals)] let fail28 = 241251235E723_64; - let fail29 = 42279.911_32; + let ok29 = 42279.911_32; let _ = 1.12345E1_32; } diff --git a/tests/ui/mistyped_literal_suffix.stderr b/tests/ui/mistyped_literal_suffix.stderr index 48a7ae90494..b338b8aa622 100644 --- a/tests/ui/mistyped_literal_suffix.stderr +++ b/tests/ui/mistyped_literal_suffix.stderr @@ -1,5 +1,5 @@ error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:6:18 + --> $DIR/mistyped_literal_suffix.rs:11:18 | LL | let fail14 = 2_32; | ^^^^ help: did you mean to write: `2_i32` @@ -7,76 +7,64 @@ LL | let fail14 = 2_32; = note: `#[deny(clippy::mistyped_literal_suffixes)]` on by default error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:7:18 + --> $DIR/mistyped_literal_suffix.rs:12:18 | LL | let fail15 = 4_64; | ^^^^ help: did you mean to write: `4_i64` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:8:18 + --> $DIR/mistyped_literal_suffix.rs:13:18 | LL | let fail16 = 7_8; // | ^^^ help: did you mean to write: `7_i8` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:9:18 + --> $DIR/mistyped_literal_suffix.rs:14:18 | LL | let fail17 = 23_16; // | ^^^^^ help: did you mean to write: `23_i16` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:12:18 + --> $DIR/mistyped_literal_suffix.rs:17:18 | LL | let fail20 = 2__8; // | ^^^^ help: did you mean to write: `2_i8` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:13:18 + --> $DIR/mistyped_literal_suffix.rs:18:18 | LL | let fail21 = 4___16; // | ^^^^^^ help: did you mean to write: `4_i16` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:15:18 - | -LL | let fail24 = 12.34_64; - | ^^^^^^^^ help: did you mean to write: `12.34_f64` - -error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:16:18 + --> $DIR/mistyped_literal_suffix.rs:21:18 | LL | let fail25 = 1E2_32; | ^^^^^^ help: did you mean to write: `1E2_f32` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:17:18 + --> $DIR/mistyped_literal_suffix.rs:22:18 | LL | let fail26 = 43E7_64; | ^^^^^^^ help: did you mean to write: `43E7_f64` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:18:18 + --> $DIR/mistyped_literal_suffix.rs:23:18 | LL | let fail27 = 243E17_32; | ^^^^^^^^^ help: did you mean to write: `243E17_f32` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:20:18 + --> $DIR/mistyped_literal_suffix.rs:25:18 | LL | let fail28 = 241251235E723_64; | ^^^^^^^^^^^^^^^^ help: did you mean to write: `241_251_235E723_f64` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:21:18 - | -LL | let fail29 = 42279.911_32; - | ^^^^^^^^^^^^ help: did you mean to write: `42_279.911_f32` - -error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:23:13 + --> $DIR/mistyped_literal_suffix.rs:28:13 | LL | let _ = 1.12345E1_32; | ^^^^^^^^^^^^ help: did you mean to write: `1.123_45E1_f32` -error: aborting due to 13 previous errors +error: aborting due to 11 previous errors diff --git a/tests/ui/needless_arbitrary_self_type_unfixable.rs b/tests/ui/needless_arbitrary_self_type_unfixable.rs new file mode 100644 index 00000000000..a39d96109f1 --- /dev/null +++ b/tests/ui/needless_arbitrary_self_type_unfixable.rs @@ -0,0 +1,45 @@ +// aux-build:proc_macro_attr.rs + +#![warn(clippy::needless_arbitrary_self_type)] + +#[macro_use] +extern crate proc_macro_attr; + +mod issue_6089 { + // Check that we don't lint if the `self` parameter comes from expansion + + macro_rules! test_from_expansion { + () => { + trait T1 { + fn test(self: &Self); + } + + struct S1 {} + + impl T1 for S1 { + fn test(self: &Self) {} + } + }; + } + + test_from_expansion!(); + + // If only the lifetime name comes from expansion we will lint, but the suggestion will have + // placeholders and will not be applied automatically, as we can't reliably know the original name. + // This specific case happened with async_trait. + + trait T2 { + fn call_with_mut_self(&mut self); + } + + struct S2 {} + + // The method's signature will be expanded to: + // fn call_with_mut_self<'life0>(self: &'life0 mut Self) {} + #[rename_my_lifetimes] + impl T2 for S2 { + fn call_with_mut_self(self: &mut Self) {} + } +} + +fn main() {} diff --git a/tests/ui/needless_arbitrary_self_type_unfixable.stderr b/tests/ui/needless_arbitrary_self_type_unfixable.stderr new file mode 100644 index 00000000000..44a0e6ddeac --- /dev/null +++ b/tests/ui/needless_arbitrary_self_type_unfixable.stderr @@ -0,0 +1,10 @@ +error: the type of the `self` parameter does not need to be arbitrary + --> $DIR/needless_arbitrary_self_type_unfixable.rs:41:31 + | +LL | fn call_with_mut_self(self: &mut Self) {} + | ^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'_ mut self` + | + = note: `-D clippy::needless-arbitrary-self-type` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index 913cd004f19..d482d466e44 100644 --- a/tests/ui/needless_lifetimes.rs +++ b/tests/ui/needless_lifetimes.rs @@ -259,4 +259,102 @@ mod issue4291 { } } +mod issue2944 { + trait Foo {} + struct Bar {} + struct Baz<'a> { + bar: &'a Bar, + } + + impl<'a> Foo for Baz<'a> {} + impl Bar { + fn baz<'a>(&'a self) -> impl Foo + 'a { + Baz { bar: self } + } + } +} + +mod nested_elision_sites { + // issue #issue2944 + + // closure trait bounds subject to nested elision + // don't lint because they refer to outer lifetimes + fn trait_fn<'a>(i: &'a i32) -> impl Fn() -> &'a i32 { + move || i + } + fn trait_fn_mut<'a>(i: &'a i32) -> impl FnMut() -> &'a i32 { + move || i + } + fn trait_fn_once<'a>(i: &'a i32) -> impl FnOnce() -> &'a i32 { + move || i + } + + // don't lint + fn impl_trait_in_input_position<'a>(f: impl Fn() -> &'a i32) -> &'a i32 { + f() + } + fn impl_trait_in_output_position<'a>(i: &'a i32) -> impl Fn() -> &'a i32 { + move || i + } + // lint + fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 { + f(i) + } + fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 { + f(i) + } + + // don't lint + fn generics_not_elidable<'a, T: Fn() -> &'a i32>(f: T) -> &'a i32 { + f() + } + // lint + fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 { + f(i) + } + + // don't lint + fn where_clause_not_elidable<'a, T>(f: T) -> &'a i32 + where + T: Fn() -> &'a i32, + { + f() + } + // lint + fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32 + where + T: Fn(&i32) -> &i32, + { + f(i) + } + + // don't lint + fn pointer_fn_in_input_position<'a>(f: fn(&'a i32) -> &'a i32, i: &'a i32) -> &'a i32 { + f(i) + } + fn pointer_fn_in_output_position<'a>(_: &'a i32) -> fn(&'a i32) -> &'a i32 { + |i| i + } + // lint + fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 { + f(i) + } + + // don't lint + fn nested_fn_pointer_1<'a>(_: &'a i32) -> fn(fn(&'a i32) -> &'a i32) -> i32 { + |f| 42 + } + fn nested_fn_pointer_2<'a>(_: &'a i32) -> impl Fn(fn(&'a i32)) { + |f| () + } + + // lint + fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 { + |f| 42 + } + fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) { + |f| () + } +} + fn main() {} diff --git a/tests/ui/needless_lifetimes.stderr b/tests/ui/needless_lifetimes.stderr index d3a360ed8b5..c8a2e8b81c0 100644 --- a/tests/ui/needless_lifetimes.stderr +++ b/tests/ui/needless_lifetimes.stderr @@ -102,5 +102,53 @@ error: explicit lifetimes given in parameter types where they could be elided (o LL | fn needless_lt<'a>(_x: &'a u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 17 previous errors +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/needless_lifetimes.rs:271:9 + | +LL | fn baz<'a>(&'a self) -> impl Foo + 'a { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/needless_lifetimes.rs:300:5 + | +LL | fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/needless_lifetimes.rs:303:5 + | +LL | fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/needless_lifetimes.rs:312:5 + | +LL | fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/needless_lifetimes.rs:324:5 + | +LL | fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/needless_lifetimes.rs:339:5 + | +LL | fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/needless_lifetimes.rs:352:5 + | +LL | fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/needless_lifetimes.rs:355:5 + | +LL | fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 25 previous errors diff --git a/tests/ui/needless_range_loop2.rs b/tests/ui/needless_range_loop2.rs index a82b1159161..7633316e0f8 100644 --- a/tests/ui/needless_range_loop2.rs +++ b/tests/ui/needless_range_loop2.rs @@ -82,6 +82,20 @@ fn main() { for i in 1..3 { println!("{}", arr[i]); } + + // Fix #5945 + let mut vec = vec![1, 2, 3, 4]; + for i in 0..vec.len() - 1 { + vec[i] += 1; + } + let mut vec = vec![1, 2, 3, 4]; + for i in vec.len() - 3..vec.len() { + vec[i] += 1; + } + let mut vec = vec![1, 2, 3, 4]; + for i in vec.len() - 3..vec.len() - 1 { + vec[i] += 1; + } } mod issue2277 { diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 5fb568672d3..2045ffdb5f0 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -58,6 +58,12 @@ fn or_fun_call() { let without_default = Some(Foo); without_default.unwrap_or_else(Foo::new); + let mut map = HashMap::::new(); + map.entry(42).or_insert_with(String::new); + + let mut btree = BTreeMap::::new(); + btree.entry(42).or_insert_with(String::new); + let stringy = Some(String::from("")); let _ = stringy.unwrap_or_else(|| "".to_owned()); @@ -110,23 +116,4 @@ fn f() -> Option<()> { Some(()) } -// Issue 5886 - const fn (with no arguments) -pub fn skip_const_fn_with_no_args() { - const fn foo() -> Option { - Some(42) - } - let _ = None.or(foo()); - - // See issue #5693. - let mut map = std::collections::HashMap::new(); - map.insert(1, vec![1]); - map.entry(1).or_insert(vec![]); - - let mut map = HashMap::::new(); - map.entry(42).or_insert(String::new()); - - let mut btree = BTreeMap::::new(); - btree.entry(42).or_insert(String::new()); -} - fn main() {} diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 737b0f7e55b..522f31b72d0 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -58,6 +58,12 @@ fn or_fun_call() { let without_default = Some(Foo); without_default.unwrap_or(Foo::new()); + let mut map = HashMap::::new(); + map.entry(42).or_insert(String::new()); + + let mut btree = BTreeMap::::new(); + btree.entry(42).or_insert(String::new()); + let stringy = Some(String::from("")); let _ = stringy.unwrap_or("".to_owned()); @@ -110,23 +116,4 @@ fn f() -> Option<()> { Some(()) } -// Issue 5886 - const fn (with no arguments) -pub fn skip_const_fn_with_no_args() { - const fn foo() -> Option { - Some(42) - } - let _ = None.or(foo()); - - // See issue #5693. - let mut map = std::collections::HashMap::new(); - map.insert(1, vec![1]); - map.entry(1).or_insert(vec![]); - - let mut map = HashMap::::new(); - map.entry(42).or_insert(String::new()); - - let mut btree = BTreeMap::::new(); - btree.entry(42).or_insert(String::new()); -} - fn main() {} diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index b8a436993f3..bc5978b538f 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -60,23 +60,35 @@ error: use of `unwrap_or` followed by a function call LL | without_default.unwrap_or(Foo::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)` +error: use of `or_insert` followed by a function call + --> $DIR/or_fun_call.rs:62:19 + | +LL | map.entry(42).or_insert(String::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)` + +error: use of `or_insert` followed by a function call + --> $DIR/or_fun_call.rs:65:21 + | +LL | btree.entry(42).or_insert(String::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)` + error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:62:21 + --> $DIR/or_fun_call.rs:68:21 | LL | let _ = stringy.unwrap_or("".to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())` error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:87:35 + --> $DIR/or_fun_call.rs:93:35 | LL | let _ = Some("a".to_string()).or(Some("b".to_string())); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))` error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:91:10 + --> $DIR/or_fun_call.rs:97:10 | LL | .or(Some(Bar(b, Duration::from_secs(2)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))` -error: aborting due to 13 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui/print_stdout_build_script.rs b/tests/ui/print_stdout_build_script.rs new file mode 100644 index 00000000000..997ebef8a69 --- /dev/null +++ b/tests/ui/print_stdout_build_script.rs @@ -0,0 +1,12 @@ +// compile-flags: --crate-name=build_script_build + +#![warn(clippy::print_stdout)] + +fn main() { + // Fix #6041 + // + // The `print_stdout` lint shouldn't emit in `build.rs` + // as these methods are used for the build script. + println!("Hello"); + print!("Hello"); +} diff --git a/tests/ui/regex.rs b/tests/ui/regex.rs index 9767e5bf76a..f7f3b195ccc 100644 --- a/tests/ui/regex.rs +++ b/tests/ui/regex.rs @@ -71,6 +71,9 @@ fn trivial_regex() { let non_trivial_ends_with = Regex::new("foo|bar"); let non_trivial_binary = BRegex::new("foo|bar"); let non_trivial_binary_builder = BRegexBuilder::new("foo|bar"); + + // #6005: unicode classes in bytes::Regex + let a_byte_of_unicode = BRegex::new(r"\p{C}"); } fn main() { diff --git a/tests/ui/unicode.rs b/tests/ui/unicode.rs index 27db9594f3b..1f596c312fe 100644 --- a/tests/ui/unicode.rs +++ b/tests/ui/unicode.rs @@ -1,7 +1,11 @@ -#[warn(clippy::zero_width_space)] +#[warn(clippy::invisible_characters)] fn zero() { print!("Here >​< is a ZWS, and ​another"); print!("This\u{200B}is\u{200B}fine"); + print!("Here >­< is a SHY, and ­another"); + print!("This\u{ad}is\u{ad}fine"); + print!("Here >⁠< is a WJ, and ⁠another"); + print!("This\u{2060}is\u{2060}fine"); } #[warn(clippy::unicode_not_nfc)] diff --git a/tests/ui/unicode.stderr b/tests/ui/unicode.stderr index 4575a132e5b..3fca463c620 100644 --- a/tests/ui/unicode.stderr +++ b/tests/ui/unicode.stderr @@ -1,13 +1,25 @@ -error: zero-width space detected +error: invisible character detected --> $DIR/unicode.rs:3:12 | LL | print!("Here >​< is a ZWS, and ​another"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{200B}< is a ZWS, and /u{200B}another"` | - = note: `-D clippy::zero-width-space` implied by `-D warnings` + = note: `-D clippy::invisible-characters` implied by `-D warnings` + +error: invisible character detected + --> $DIR/unicode.rs:5:12 + | +LL | print!("Here >­< is a SHY, and ­another"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{AD}< is a SHY, and /u{AD}another"` + +error: invisible character detected + --> $DIR/unicode.rs:7:12 + | +LL | print!("Here >⁠< is a WJ, and ⁠another"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{2060}< is a WJ, and /u{2060}another"` error: non-NFC Unicode sequence detected - --> $DIR/unicode.rs:9:12 + --> $DIR/unicode.rs:13:12 | LL | print!("̀àh?"); | ^^^^^ help: consider replacing the string with: `"̀àh?"` @@ -15,12 +27,12 @@ LL | print!("̀àh?"); = note: `-D clippy::unicode-not-nfc` implied by `-D warnings` error: literal non-ASCII character detected - --> $DIR/unicode.rs:15:12 + --> $DIR/unicode.rs:19:12 | LL | print!("Üben!"); | ^^^^^^^ help: consider replacing the string with: `"/u{dc}ben!"` | = note: `-D clippy::non-ascii-literal` implied by `-D warnings` -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/unnecessary_sort_by.fixed b/tests/ui/unnecessary_sort_by.fixed index ad0d0387db0..b45b27d8f23 100644 --- a/tests/ui/unnecessary_sort_by.fixed +++ b/tests/ui/unnecessary_sort_by.fixed @@ -13,12 +13,12 @@ fn unnecessary_sort_by() { // Forward examples vec.sort(); vec.sort_unstable(); - vec.sort_by_key(|&a| (a + 5).abs()); - vec.sort_unstable_by_key(|&a| id(-a)); + vec.sort_by_key(|a| (a + 5).abs()); + vec.sort_unstable_by_key(|a| id(-a)); // Reverse examples - vec.sort_by_key(|&b| Reverse(b)); - vec.sort_by_key(|&b| Reverse((b + 5).abs())); - vec.sort_unstable_by_key(|&b| Reverse(id(-b))); + vec.sort_by(|a, b| b.cmp(a)); // not linted to avoid suggesting `Reverse(b)` which would borrow + vec.sort_by_key(|b| Reverse((b + 5).abs())); + vec.sort_unstable_by_key(|b| Reverse(id(-b))); // Negative examples (shouldn't be changed) let c = &7; vec.sort_by(|a, b| (b - a).cmp(&(a - b))); @@ -26,10 +26,11 @@ fn unnecessary_sort_by() { vec.sort_by(|_, b| b.cmp(c)); vec.sort_unstable_by(|a, _| a.cmp(c)); - // Ignore vectors of references + // Vectors of references are fine as long as the resulting key does not borrow let mut vec: Vec<&&&isize> = vec![&&&3, &&&6, &&&1, &&&2, &&&5]; - vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs())); - vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs())); + vec.sort_by_key(|a| (***a).abs()); + vec.sort_unstable_by_key(|a| (***a).abs()); + // `Reverse(b)` would borrow in the following cases, don't lint vec.sort_by(|a, b| b.cmp(a)); vec.sort_unstable_by(|a, b| b.cmp(a)); } @@ -68,10 +69,9 @@ mod issue_5754 { } } -// `Vec::sort_by_key` closure parameter is `F: FnMut(&T) -> K` -// The suggestion is destructuring T and we know T is not a reference, so test that non-Copy T are -// not linted. +// The closure parameter is not dereferenced anymore, so non-Copy types can be linted mod issue_6001 { + use super::*; struct Test(String); impl Test { @@ -85,11 +85,11 @@ mod issue_6001 { let mut args: Vec = vec![]; // Forward - args.sort_by(|a, b| a.name().cmp(&b.name())); - args.sort_unstable_by(|a, b| a.name().cmp(&b.name())); + args.sort_by_key(|a| a.name()); + args.sort_unstable_by_key(|a| a.name()); // Reverse - args.sort_by(|a, b| b.name().cmp(&a.name())); - args.sort_unstable_by(|a, b| b.name().cmp(&a.name())); + args.sort_by_key(|b| Reverse(b.name())); + args.sort_unstable_by_key(|b| Reverse(b.name())); } } diff --git a/tests/ui/unnecessary_sort_by.rs b/tests/ui/unnecessary_sort_by.rs index 9746f6e6849..be2abe7f701 100644 --- a/tests/ui/unnecessary_sort_by.rs +++ b/tests/ui/unnecessary_sort_by.rs @@ -16,7 +16,7 @@ fn unnecessary_sort_by() { vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs())); vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b))); // Reverse examples - vec.sort_by(|a, b| b.cmp(a)); + vec.sort_by(|a, b| b.cmp(a)); // not linted to avoid suggesting `Reverse(b)` which would borrow vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a))); // Negative examples (shouldn't be changed) @@ -26,10 +26,11 @@ fn unnecessary_sort_by() { vec.sort_by(|_, b| b.cmp(c)); vec.sort_unstable_by(|a, _| a.cmp(c)); - // Ignore vectors of references + // Vectors of references are fine as long as the resulting key does not borrow let mut vec: Vec<&&&isize> = vec![&&&3, &&&6, &&&1, &&&2, &&&5]; vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs())); vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs())); + // `Reverse(b)` would borrow in the following cases, don't lint vec.sort_by(|a, b| b.cmp(a)); vec.sort_unstable_by(|a, b| b.cmp(a)); } @@ -68,10 +69,9 @@ mod issue_5754 { } } -// `Vec::sort_by_key` closure parameter is `F: FnMut(&T) -> K` -// The suggestion is destructuring T and we know T is not a reference, so test that non-Copy T are -// not linted. +// The closure parameter is not dereferenced anymore, so non-Copy types can be linted mod issue_6001 { + use super::*; struct Test(String); impl Test { diff --git a/tests/ui/unnecessary_sort_by.stderr b/tests/ui/unnecessary_sort_by.stderr index 70c6cf0a3b6..50607933e18 100644 --- a/tests/ui/unnecessary_sort_by.stderr +++ b/tests/ui/unnecessary_sort_by.stderr @@ -16,31 +16,61 @@ error: use Vec::sort_by_key here instead --> $DIR/unnecessary_sort_by.rs:16:5 | LL | vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&a| (a + 5).abs())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| (a + 5).abs())` error: use Vec::sort_by_key here instead --> $DIR/unnecessary_sort_by.rs:17:5 | LL | vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|&a| id(-a))` - -error: use Vec::sort_by_key here instead - --> $DIR/unnecessary_sort_by.rs:19:5 - | -LL | vec.sort_by(|a, b| b.cmp(a)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse(b))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| id(-a))` error: use Vec::sort_by_key here instead --> $DIR/unnecessary_sort_by.rs:20:5 | LL | vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse((b + 5).abs()))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|b| Reverse((b + 5).abs()))` error: use Vec::sort_by_key here instead --> $DIR/unnecessary_sort_by.rs:21:5 | LL | vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|&b| Reverse(id(-b)))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|b| Reverse(id(-b)))` -error: aborting due to 7 previous errors +error: use Vec::sort_by_key here instead + --> $DIR/unnecessary_sort_by.rs:31:5 + | +LL | vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| (***a).abs())` + +error: use Vec::sort_by_key here instead + --> $DIR/unnecessary_sort_by.rs:32:5 + | +LL | vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| (***a).abs())` + +error: use Vec::sort_by_key here instead + --> $DIR/unnecessary_sort_by.rs:88:9 + | +LL | args.sort_by(|a, b| a.name().cmp(&b.name())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_by_key(|a| a.name())` + +error: use Vec::sort_by_key here instead + --> $DIR/unnecessary_sort_by.rs:89:9 + | +LL | args.sort_unstable_by(|a, b| a.name().cmp(&b.name())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_unstable_by_key(|a| a.name())` + +error: use Vec::sort_by_key here instead + --> $DIR/unnecessary_sort_by.rs:91:9 + | +LL | args.sort_by(|a, b| b.name().cmp(&a.name())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_by_key(|b| Reverse(b.name()))` + +error: use Vec::sort_by_key here instead + --> $DIR/unnecessary_sort_by.rs:92:9 + | +LL | args.sort_unstable_by(|a, b| b.name().cmp(&a.name())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_unstable_by_key(|b| Reverse(b.name()))` + +error: aborting due to 12 previous errors From 7f846c930b9d35061e6eb6b8dbfbc890d38d539c Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 9 Oct 2020 14:14:49 +0200 Subject: [PATCH 087/446] Update backport documentation to the subtree workflow --- doc/backport.md | 47 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/doc/backport.md b/doc/backport.md index 259696658ea..15f3d1f0806 100644 --- a/doc/backport.md +++ b/doc/backport.md @@ -5,7 +5,7 @@ Backports in Clippy are rare and should be approved by the Clippy team. For example, a backport is done, if a crucial ICE was fixed or a lint is broken to a point, that it has to be disabled, before landing on stable. -Backports are done to the `beta` release of Clippy. Backports to stable Clippy +Backports are done to the `beta` branch of Clippy. Backports to stable Clippy releases basically don't exist, since this would require a Rust point release, which is almost never justifiable for a Clippy fix. @@ -18,7 +18,31 @@ Backports are done on the beta branch of the Clippy repository. # Assuming the current directory corresponds to the Clippy repository $ git checkout beta $ git checkout -b backport -$ git cherry-pick # `` is the commit hash of the commit, that should be backported +$ git cherry-pick # `` is the commit hash of the commit(s), that should be backported +$ git push origin backport +``` + +Now you should test that the backport passes all the tests in the Rust +repository. You can do this with: + +```bash +# Assuming the current directory corresponds to the Rust repository +$ git checkout beta +$ git subtree pull -p src/tools/clippy https://github.com//rust-clippy backport +$ ./x.py test src/tools/clippy +``` + +Should the test fail, you can fix Clippy directly in the Rust repository. This +has to be first applied to the Clippy beta branch and then again synced to the +Rust repository, though. The easiest way to do this is: + +```bash +# In the Rust repository +$ git diff --patch --relative=src/tools/clippy > clippy.patch +# In the Clippy repository +$ git apply /path/to/clippy.patch +$ git add -u +$ git commit -m "Fix rustup fallout" $ git push origin backport ``` @@ -29,22 +53,19 @@ After this, you can open a PR to the `beta` branch of the Clippy repository. This step must be done, **after** the PR of the previous step was merged. -After the backport landed in the Clippy repository, also the Clippy version on -the Rust `beta` branch has to be updated. +After the backport landed in the Clippy repository, the branch has to be synced +back to the beta branch of the Rust repository. ```bash # Assuming the current directory corresponds to the Rust repository $ git checkout beta $ git checkout -b clippy_backport -$ pushd src/tools/clippy -$ git fetch -$ git checkout beta -$ popd -$ git add src/tools/clippy -§ git commit -m "Update Clippy" +$ git subtree pull -p src/tools/clippy https://github.com/rust-lang/rust-clippy beta $ git push origin clippy_backport ``` -After this you can open a PR to the `beta` branch of the Rust repository. In -this PR you should tag the Clippy team member, that agreed to the backport or -the `@rust-lang/clippy` team. Make sure to add `[beta]` to the title of the PR. +Make sure to test the backport in the Rust repository before opening a PR. This +is done with `./x.py test src/tools/clippy`. If that passes all tests, open a PR +to the `beta` branch of the Rust repository. In this PR you should tag the +Clippy team member, that agreed to the backport or the `@rust-lang/clippy` team. +Make sure to add `[beta]` to the title of the PR. From ecd308ec394f9d01b4392ee0315ea64d52ab7caa Mon Sep 17 00:00:00 2001 From: hosseind75 Date: Sat, 19 Sep 2020 17:51:24 +0430 Subject: [PATCH 088/446] ICEs should print the top of the query stack --- src/driver.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/driver.rs b/src/driver.rs index f4f2259cefd..c88dffc88f4 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -274,12 +274,7 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { handler.note_without_error(¬e); } - // If backtraces are enabled, also print the query stack - let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0"); - - if backtrace { - TyCtxt::try_print_query_stack(&handler); - } + TyCtxt::try_print_query_stack(&handler, Some(2)); } fn toolchain_path(home: Option, toolchain: Option) -> Option { From a9053e4baf251f53d8d6b95cd3f5b8a829ad0ba6 Mon Sep 17 00:00:00 2001 From: hosseind75 Date: Sat, 19 Sep 2020 18:37:58 +0430 Subject: [PATCH 089/446] run full query stack print just when RUST_BACKTRACE is set --- src/driver.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/driver.rs b/src/driver.rs index c88dffc88f4..0b324775b0d 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -274,7 +274,10 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { handler.note_without_error(¬e); } - TyCtxt::try_print_query_stack(&handler, Some(2)); + // If backtraces are enabled, also print the query stack + let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0"); + + TyCtxt::try_print_query_stack(&handler, Some(2), Some(backtrace)); } fn toolchain_path(home: Option, toolchain: Option) -> Option { From 49bc85e947ab7ca793c14b6f3af4a8e9d8db0337 Mon Sep 17 00:00:00 2001 From: hosseind75 Date: Fri, 25 Sep 2020 19:55:32 +0330 Subject: [PATCH 090/446] fix clippy custom_ice_message test --- tests/ui/custom_ice_message.stderr | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/ui/custom_ice_message.stderr b/tests/ui/custom_ice_message.stderr index a9a65a38c10..784ab9e5c70 100644 --- a/tests/ui/custom_ice_message.stderr +++ b/tests/ui/custom_ice_message.stderr @@ -9,3 +9,5 @@ note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy note: Clippy version: foo +query stack during panic: +we're just showing a limited slice of the query stack \ No newline at end of file From 7f07577e6f873f4a1b3428d29bf520189f4ef79e Mon Sep 17 00:00:00 2001 From: hosseind75 Date: Mon, 28 Sep 2020 22:07:31 +0330 Subject: [PATCH 091/446] add new line --- tests/ui/custom_ice_message.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/custom_ice_message.stderr b/tests/ui/custom_ice_message.stderr index 784ab9e5c70..87cdb7a8b99 100644 --- a/tests/ui/custom_ice_message.stderr +++ b/tests/ui/custom_ice_message.stderr @@ -10,4 +10,4 @@ note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy note: Clippy version: foo query stack during panic: -we're just showing a limited slice of the query stack \ No newline at end of file +we're just showing a limited slice of the query stack From 3c94914f0c87ba00987e515063dcc9e079a8918d Mon Sep 17 00:00:00 2001 From: hosseind75 Date: Tue, 29 Sep 2020 18:14:07 +0330 Subject: [PATCH 092/446] rebase with master --- src/driver.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/driver.rs b/src/driver.rs index 0b324775b0d..bf9110b4349 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -277,7 +277,9 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { // If backtraces are enabled, also print the query stack let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0"); - TyCtxt::try_print_query_stack(&handler, Some(2), Some(backtrace)); + let num_frames = if backtrace { None } else { Some(2) }; + + TyCtxt::try_print_query_stack(&handler, num_frames); } fn toolchain_path(home: Option, toolchain: Option) -> Option { From 36d9b72354560528f07796a8a09b339bdcf37d53 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Fri, 9 Oct 2020 13:06:04 +0200 Subject: [PATCH 093/446] liballoc: VecDeque: Add binary search functions --- library/alloc/src/collections/vec_deque.rs | 150 ++++++++++++++++++++- library/alloc/tests/lib.rs | 1 + library/alloc/tests/vec_deque.rs | 39 ++++++ 3 files changed, 189 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/collections/vec_deque.rs b/library/alloc/src/collections/vec_deque.rs index ff9b1553bf2..1560263684a 100644 --- a/library/alloc/src/collections/vec_deque.rs +++ b/library/alloc/src/collections/vec_deque.rs @@ -2181,7 +2181,7 @@ impl VecDeque { /// /// This method does not allocate and does not change the order of the /// inserted elements. As it returns a mutable slice, this can be used to - /// sort or binary search a deque. + /// sort a deque. /// /// Once the internal storage is contiguous, the [`as_slices`] and /// [`as_mut_slices`] methods will return the entire contents of the @@ -2430,6 +2430,154 @@ impl VecDeque { self.wrap_copy(self.tail, self.head, k); } } + + /// Binary searches this sorted `VecDeque` for a given element. + /// + /// If the value is found then [`Result::Ok`] is returned, containing the + /// index of the matching element. If there are multiple matches, then any + /// one of the matches could be returned. If the value is not found then + /// [`Result::Err`] is returned, containing the index where a matching + /// element could be inserted while maintaining sorted order. + /// + /// # Examples + /// + /// Looks up a series of four elements. The first is found, with a + /// uniquely determined position; the second and third are not + /// found; the fourth could match any position in `[1, 4]`. + /// + /// ``` + /// #![feature(vecdeque_binary_search)] + /// use std::collections::VecDeque; + /// + /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into(); + /// + /// assert_eq!(deque.binary_search(&13), Ok(9)); + /// assert_eq!(deque.binary_search(&4), Err(7)); + /// assert_eq!(deque.binary_search(&100), Err(13)); + /// let r = deque.binary_search(&1); + /// assert!(matches!(r, Ok(1..=4))); + /// ``` + /// + /// If you want to insert an item to a sorted `VecDeque`, while maintaining + /// sort order: + /// + /// ``` + /// #![feature(vecdeque_binary_search)] + /// use std::collections::VecDeque; + /// + /// let mut deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into(); + /// let num = 42; + /// let idx = deque.binary_search(&num).unwrap_or_else(|x| x); + /// deque.insert(idx, num); + /// assert_eq!(deque, &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); + /// ``` + #[unstable(feature = "vecdeque_binary_search", issue = "1")] + #[inline] + pub fn binary_search(&self, x: &T) -> Result + where + T: Ord, + { + self.binary_search_by(|e| e.cmp(x)) + } + + /// Binary searches this sorted `VecDeque` with a comparator function. + /// + /// The comparator function should implement an order consistent + /// with the sort order of the underlying `VecDeque`, returning an + /// order code that indicates whether its argument is `Less`, + /// `Equal` or `Greater` than the desired target. + /// + /// If the value is found then [`Result::Ok`] is returned, containing the + /// index of the matching element. If there are multiple matches, then any + /// one of the matches could be returned. If the value is not found then + /// [`Result::Err`] is returned, containing the index where a matching + /// element could be inserted while maintaining sorted order. + /// + /// # Examples + /// + /// Looks up a series of four elements. The first is found, with a + /// uniquely determined position; the second and third are not + /// found; the fourth could match any position in `[1, 4]`. + /// + /// ``` + /// #![feature(vecdeque_binary_search)] + /// use std::collections::VecDeque; + /// + /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into(); + /// + /// assert_eq!(deque.binary_search_by(|x| x.cmp(&13)), Ok(9)); + /// assert_eq!(deque.binary_search_by(|x| x.cmp(&4)), Err(7)); + /// assert_eq!(deque.binary_search_by(|x| x.cmp(&100)), Err(13)); + /// let r = deque.binary_search_by(|x| x.cmp(&1)); + /// assert!(matches!(r, Ok(1..=4))); + /// ``` + #[unstable(feature = "vecdeque_binary_search", issue = "1")] + pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result + where + F: FnMut(&'a T) -> Ordering, + { + if self.is_empty() { + return Err(0); + } + + let (front, back) = self.as_slices(); + + match back.first().map(|elem| f(elem)) { + Some(Ordering::Equal) => return Ok(front.len()), + Some(Ordering::Less) => { + return back[1..] + .binary_search_by(f) + .map(|idx| idx + front.len() + 1) + .map_err(|idx| idx + front.len() + 1); + } + _ => {} + } + + front.binary_search_by(f) + } + + /// Binary searches this sorted `VecDeque` with a key extraction function. + /// + /// Assumes that the `VecDeque` is sorted by the key, for instance with + /// [`make_contiguous().sort_by_key()`](#method.make_contiguous) using the same + /// key extraction function. + /// + /// If the value is found then [`Result::Ok`] is returned, containing the + /// index of the matching element. If there are multiple matches, then any + /// one of the matches could be returned. If the value is not found then + /// [`Result::Err`] is returned, containing the index where a matching + /// element could be inserted while maintaining sorted order. + /// + /// # Examples + /// + /// Looks up a series of four elements in a slice of pairs sorted by + /// their second elements. The first is found, with a uniquely + /// determined position; the second and third are not found; the + /// fourth could match any position in `[1, 4]`. + /// + /// ``` + /// #![feature(vecdeque_binary_search)] + /// use std::collections::VecDeque; + /// + /// let deque: VecDeque<_> = vec![(0, 0), (2, 1), (4, 1), (5, 1), + /// (3, 1), (1, 2), (2, 3), (4, 5), (5, 8), (3, 13), + /// (1, 21), (2, 34), (4, 55)].into(); + /// + /// assert_eq!(deque.binary_search_by_key(&13, |&(a,b)| b), Ok(9)); + /// assert_eq!(deque.binary_search_by_key(&4, |&(a,b)| b), Err(7)); + /// assert_eq!(deque.binary_search_by_key(&100, |&(a,b)| b), Err(13)); + /// let r = deque.binary_search_by_key(&1, |&(a,b)| b); + /// assert!(matches!(r, Ok(1..=4))); + /// ``` + #[unstable(feature = "vecdeque_binary_search", issue = "1")] + #[inline] + pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result + where + F: FnMut(&'a T) -> B, + B: Ord, + { + self.binary_search_by(|k| f(k).cmp(b)) + } } impl VecDeque { diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index cff8ff9ac7a..b7cc03f8eb9 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -20,6 +20,7 @@ #![feature(inplace_iteration)] #![feature(iter_map_while)] #![feature(int_bits_const)] +#![feature(vecdeque_binary_search)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs index 46d8a3c4cb4..05cb3a2c03d 100644 --- a/library/alloc/tests/vec_deque.rs +++ b/library/alloc/tests/vec_deque.rs @@ -1659,3 +1659,42 @@ fn test_drain_leak() { drop(v); assert_eq!(unsafe { DROPS }, 7); } + +#[test] +fn test_binary_search() { + // Contiguous (front only) search: + let deque: VecDeque<_> = vec![1, 2, 3, 5, 6].into(); + assert!(deque.as_slices().1.is_empty()); + assert_eq!(deque.binary_search(&3), Ok(2)); + assert_eq!(deque.binary_search(&4), Err(3)); + + // Split search (both front & back non-empty): + let mut deque: VecDeque<_> = vec![5, 6].into(); + deque.push_front(3); + deque.push_front(2); + deque.push_front(1); + deque.push_back(10); + assert!(!deque.as_slices().0.is_empty()); + assert!(!deque.as_slices().1.is_empty()); + assert_eq!(deque.binary_search(&0), Err(0)); + assert_eq!(deque.binary_search(&1), Ok(0)); + assert_eq!(deque.binary_search(&5), Ok(3)); + assert_eq!(deque.binary_search(&7), Err(5)); + assert_eq!(deque.binary_search(&20), Err(6)); +} + +#[test] +fn test_binary_search_by() { + let deque: VecDeque<_> = vec![(1,), (2,), (3,), (5,), (6,)].into(); + + assert_eq!(deque.binary_search_by(|&(v,)| v.cmp(&3)), Ok(2)); + assert_eq!(deque.binary_search_by(|&(v,)| v.cmp(&4)), Err(3)); +} + +#[test] +fn test_binary_search_by_key() { + let deque: VecDeque<_> = vec![(1,), (2,), (3,), (5,), (6,)].into(); + + assert_eq!(deque.binary_search_by_key(&3, |&(v,)| v), Ok(2)); + assert_eq!(deque.binary_search_by_key(&4, |&(v,)| v), Err(3)); +} From 7b7ddfa55da889b41e90243ac59a04eed832a71e Mon Sep 17 00:00:00 2001 From: Sebastian Andersson Date: Fri, 9 Oct 2020 20:23:03 +0200 Subject: [PATCH 094/446] Preserve raw strs for: format!(s) to s.to_string() lint Ie: | let s = format!(r#""hello""#); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `r#""hello""#.to_string()` --- clippy_lints/src/format.rs | 8 ++++++-- tests/ui/format.fixed | 3 ++- tests/ui/format.stderr | 8 +++++++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index d6541010bca..26da058598e 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,6 +1,6 @@ use crate::utils::paths; use crate::utils::{ - is_expn_of, is_type_diagnostic_item, last_path_segment, match_def_path, match_function_call, snippet, + is_expn_of, is_type_diagnostic_item, last_path_segment, match_def_path, match_function_call, snippet, snippet_opt, span_lint_and_then, }; use if_chain::if_chain; @@ -132,7 +132,11 @@ fn on_new_v1<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option [], }` if tup.is_empty() { - return Some(format!("{:?}.to_string()", s.as_str())); + if let Some(s_src) = snippet_opt(cx, lit.span) { + // Simulate macro expansion, converting {{ and }} to { and }. + let s_expand = s_src.replace("{{", "{").replace("}}", "}"); + return Some(format!("{}.to_string()", s_expand)) + } } else if s.as_str().is_empty() { return on_argumentv1_new(cx, &tup[0], arms); } diff --git a/tests/ui/format.fixed b/tests/ui/format.fixed index 30651476999..740a22a07d7 100644 --- a/tests/ui/format.fixed +++ b/tests/ui/format.fixed @@ -13,7 +13,8 @@ fn main() { "foo".to_string(); "{}".to_string(); "{} abc {}".to_string(); - "foo {}\n\" bar".to_string(); + r##"foo {} +" bar"##.to_string(); "foo".to_string(); format!("{:?}", "foo"); // Don't warn about `Debug`. diff --git a/tests/ui/format.stderr b/tests/ui/format.stderr index 9734492154e..96df7f37f77 100644 --- a/tests/ui/format.stderr +++ b/tests/ui/format.stderr @@ -25,7 +25,13 @@ LL | / format!( LL | | r##"foo {{}} LL | | " bar"## LL | | ); - | |______^ help: consider using `.to_string()`: `"foo {}/n/" bar".to_string();` + | |______^ + | +help: consider using `.to_string()` + | +LL | r##"foo {} +LL | " bar"##.to_string(); + | error: useless use of `format!` --> $DIR/format.rs:21:5 From 26e4de9557e5924d001652138ec0f8f40dc40372 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Fri, 9 Oct 2020 00:49:27 +0200 Subject: [PATCH 095/446] allow refs in our constant handling --- clippy_lints/src/consts.rs | 10 +++++++++- tests/ui/float_cmp.rs | 5 +++++ tests/ui/float_cmp.stderr | 12 ++++++------ 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index 062c9bd2d9e..c5e33b288a9 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -40,6 +40,8 @@ pub enum Constant { Tuple(Vec), /// A raw pointer. RawPtr(u128), + /// A reference + Ref(Box), /// A literal with syntax error. Err(Symbol), } @@ -66,6 +68,7 @@ impl PartialEq for Constant { (&Self::Bool(l), &Self::Bool(r)) => l == r, (&Self::Vec(ref l), &Self::Vec(ref r)) | (&Self::Tuple(ref l), &Self::Tuple(ref r)) => l == r, (&Self::Repeat(ref lv, ref ls), &Self::Repeat(ref rv, ref rs)) => ls == rs && lv == rv, + (&Self::Ref(ref lb), &Self::Ref(ref rb)) => *lb == *rb, // TODO: are there inter-type equalities? _ => false, } @@ -110,6 +113,9 @@ impl Hash for Constant { Self::RawPtr(u) => { u.hash(state); }, + Self::Ref(ref r) => { + r.hash(state); + }, Self::Err(ref s) => { s.hash(state); }, @@ -144,6 +150,7 @@ impl Constant { x => x, } }, + (&Self::Ref(ref lb), &Self::Ref(ref rb)) => Self::partial_cmp(tcx, cmp_type, lb, rb), // TODO: are there any useful inter-type orderings? _ => None, } @@ -239,7 +246,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { ExprKind::Unary(op, ref operand) => self.expr(operand).and_then(|o| match op { UnOp::UnNot => self.constant_not(&o, self.typeck_results.expr_ty(e)), UnOp::UnNeg => self.constant_negate(&o, self.typeck_results.expr_ty(e)), - UnOp::UnDeref => Some(o), + UnOp::UnDeref => Some(if let Constant::Ref(r) = o { *r } else { o }), }), ExprKind::Binary(op, ref left, ref right) => self.binop(op, left, right), ExprKind::Call(ref callee, ref args) => { @@ -269,6 +276,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { } }, ExprKind::Index(ref arr, ref index) => self.index(arr, index), + ExprKind::AddrOf(_, _, ref inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))), // TODO: add other expressions. _ => None, } diff --git a/tests/ui/float_cmp.rs b/tests/ui/float_cmp.rs index 9fa0e5f5c07..586784b73e6 100644 --- a/tests/ui/float_cmp.rs +++ b/tests/ui/float_cmp.rs @@ -2,6 +2,7 @@ #![allow( unused, clippy::no_effect, + clippy::op_ref, clippy::unnecessary_operation, clippy::cast_lossless, clippy::many_single_char_names @@ -116,4 +117,8 @@ fn main() { 1.23f64.signum() != x64.signum(); 1.23f64.signum() != -(x64.signum()); 1.23f64.signum() != 3.21f64.signum(); + + // the comparison should also look through references + &0.0 == &ZERO; + &&&&0.0 == &&&&ZERO; } diff --git a/tests/ui/float_cmp.stderr b/tests/ui/float_cmp.stderr index f7c380fc915..bb4051c4662 100644 --- a/tests/ui/float_cmp.stderr +++ b/tests/ui/float_cmp.stderr @@ -1,5 +1,5 @@ error: strict comparison of `f32` or `f64` - --> $DIR/float_cmp.rs:65:5 + --> $DIR/float_cmp.rs:66:5 | LL | ONE as f64 != 2.0; | ^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE as f64 - 2.0).abs() > error_margin` @@ -8,7 +8,7 @@ LL | ONE as f64 != 2.0; = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` - --> $DIR/float_cmp.rs:70:5 + --> $DIR/float_cmp.rs:71:5 | LL | x == 1.0; | ^^^^^^^^ help: consider comparing them within some margin of error: `(x - 1.0).abs() < error_margin` @@ -16,7 +16,7 @@ LL | x == 1.0; = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` - --> $DIR/float_cmp.rs:73:5 + --> $DIR/float_cmp.rs:74:5 | LL | twice(x) != twice(ONE as f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(twice(x) - twice(ONE as f64)).abs() > error_margin` @@ -24,7 +24,7 @@ LL | twice(x) != twice(ONE as f64); = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` - --> $DIR/float_cmp.rs:93:5 + --> $DIR/float_cmp.rs:94:5 | LL | NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(NON_ZERO_ARRAY[i] - NON_ZERO_ARRAY[j]).abs() < error_margin` @@ -32,7 +32,7 @@ LL | NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` arrays - --> $DIR/float_cmp.rs:98:5 + --> $DIR/float_cmp.rs:99:5 | LL | a1 == a2; | ^^^^^^^^ @@ -40,7 +40,7 @@ LL | a1 == a2; = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` - --> $DIR/float_cmp.rs:99:5 + --> $DIR/float_cmp.rs:100:5 | LL | a1[0] == a2[0]; | ^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(a1[0] - a2[0]).abs() < error_margin` From 6d88803a1c5516fda1d1030e5676d6b15be130fc Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 9 Oct 2020 22:21:47 +0200 Subject: [PATCH 096/446] Add regression test for ICE 6139 --- tests/ui/crashes/ice-6139.rs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/ui/crashes/ice-6139.rs diff --git a/tests/ui/crashes/ice-6139.rs b/tests/ui/crashes/ice-6139.rs new file mode 100644 index 00000000000..f3966e47f5e --- /dev/null +++ b/tests/ui/crashes/ice-6139.rs @@ -0,0 +1,7 @@ +trait T<'a> {} + +fn foo(_: Vec>>) {} + +fn main() { + foo(vec![]); +} From a98f9d21fcdad85ae95d00d3931cf438f9d5a9de Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 9 Oct 2020 22:22:21 +0200 Subject: [PATCH 097/446] (Hacky) Fix for ICE #6139 --- clippy_lints/src/types.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 5e83b6c81ec..a982b92bb2b 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -541,6 +541,11 @@ impl Types { _ => None, }); let ty_ty = hir_ty_to_ty(cx.tcx, boxed_ty); + // HACK(flip1995): This is a fix for an ICE occuring when `ty_ty` is a + // trait object with a lifetime, e.g. `dyn T<'_>`. Since trait objects + // don't have a known size, this shouldn't introduce FNs. But there + // should be a better solution. + if !matches!(ty_ty.kind(), ty::Dynamic(..)); if ty_ty.is_sized(cx.tcx.at(ty.span), cx.param_env); if let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes()); if ty_ty_size <= self.vec_box_size_threshold; From bd135674814d74ca6fca3ab79d778ecaaeb02cf5 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 9 Oct 2020 23:41:57 -0400 Subject: [PATCH 098/446] Allow setting up git hooks from other worktrees --- src/bootstrap/setup.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs index dcfb9fd6734..9eb2dc84e08 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/setup.rs @@ -1,5 +1,6 @@ use crate::t; use std::path::{Path, PathBuf}; +use std::process::Command; use std::str::FromStr; use std::{ env, fmt, fs, @@ -155,10 +156,17 @@ simply delete the `pre-commit` file from .git/hooks." Ok(if should_install { let src = src_path.join("src").join("etc").join("pre-commit.sh"); - let dst = src_path.join(".git").join("hooks").join("pre-commit"); - match fs::hard_link(src, dst) { + let git = t!(Command::new("git").args(&["rev-parse", "--git-common-dir"]).output().map( + |output| { + assert!(output.status.success(), "failed to run `git`"); + PathBuf::from(t!(String::from_utf8(output.stdout)).trim()) + } + )); + let dst = git.join("hooks").join("pre-commit"); + match fs::hard_link(src, &dst) { Err(e) => println!( - "x.py encountered an error -- do you already have the git hook installed?\n{}", + "error: could not create hook {}: do you already have the git hook installed?\n{}", + dst.display(), e ), Ok(_) => println!("Linked `src/etc/pre-commit.sh` to `.git/hooks/pre-commit`"), From cf81975d7765bf0cf82fee9f3e991c880f77cd13 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Sat, 10 Oct 2020 14:04:14 +0200 Subject: [PATCH 099/446] Fix two ICEs caused by ty.is_{sized,freeze} --- clippy_lints/src/mut_key.rs | 7 ++++++- clippy_lints/src/types.rs | 7 ++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 8a2dbdc50ea..4525b12689f 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -1,6 +1,7 @@ use crate::utils::{match_def_path, paths, span_lint, trait_ref_of_method}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::{Adt, Array, RawPtr, Ref, Slice, Tuple, Ty, TypeAndMut}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; @@ -120,7 +121,11 @@ fn is_mutable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span) -> bo size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0) && is_mutable_type(cx, inner_ty, span) }, Tuple(..) => ty.tuple_fields().any(|ty| is_mutable_type(cx, ty, span)), - Adt(..) => cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx.at(span), cx.param_env), + Adt(..) => { + cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() + && !ty.has_escaping_bound_vars() + && !ty.is_freeze(cx.tcx.at(span), cx.param_env) + }, _ => false, } } diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index a982b92bb2b..9a948af8bfc 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -17,6 +17,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::{self, InferTy, Ty, TyCtxt, TyS, TypeckResults}; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::{ExpnKind, MacroKind}; @@ -541,11 +542,7 @@ impl Types { _ => None, }); let ty_ty = hir_ty_to_ty(cx.tcx, boxed_ty); - // HACK(flip1995): This is a fix for an ICE occuring when `ty_ty` is a - // trait object with a lifetime, e.g. `dyn T<'_>`. Since trait objects - // don't have a known size, this shouldn't introduce FNs. But there - // should be a better solution. - if !matches!(ty_ty.kind(), ty::Dynamic(..)); + if !ty_ty.has_escaping_bound_vars(); if ty_ty.is_sized(cx.tcx.at(ty.span), cx.param_env); if let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes()); if ty_ty_size <= self.vec_box_size_threshold; From 52e650ae88a63b41686f646f2240de7c870e6ea6 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Sat, 10 Oct 2020 15:03:49 +0200 Subject: [PATCH 100/446] Add test for ICE #6153 --- tests/ui/crashes/ice-6153.rs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/ui/crashes/ice-6153.rs diff --git a/tests/ui/crashes/ice-6153.rs b/tests/ui/crashes/ice-6153.rs new file mode 100644 index 00000000000..9f73f39f10d --- /dev/null +++ b/tests/ui/crashes/ice-6153.rs @@ -0,0 +1,9 @@ +pub struct S<'a, 'e>(&'a str, &'e str); + +pub type T<'a, 'e> = std::collections::HashMap, ()>; + +impl<'e, 'a: 'e> S<'a, 'e> { + pub fn foo(_a: &str, _b: &str, _map: &T) {} +} + +fn main() {} From 117877745738f21e851686efe57a09e14606dadc Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 10 Oct 2020 17:36:04 +0200 Subject: [PATCH 101/446] Refactor how SwitchInt stores jump targets --- clippy_lints/src/utils/qualify_min_const_fn.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/clippy_lints/src/utils/qualify_min_const_fn.rs b/clippy_lints/src/utils/qualify_min_const_fn.rs index 1b4f2034272..7cb7d0a26b6 100644 --- a/clippy_lints/src/utils/qualify_min_const_fn.rs +++ b/clippy_lints/src/utils/qualify_min_const_fn.rs @@ -282,7 +282,6 @@ fn check_terminator(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, terminator: &Termin TerminatorKind::SwitchInt { discr, switch_ty: _, - values: _, targets: _, } => check_operand(tcx, discr, span, body), From 16d65d04322de4a00327dfe26b4af6bd3e4187c8 Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Tue, 6 Oct 2020 11:39:59 +0200 Subject: [PATCH 102/446] revise Hermit's mutex interface to support the behaviour of StaticMutex rust-lang/rust#77147 simplifies things by splitting this Mutex type into two types matching the two use cases: StaticMutex and MovableMutex. To support the behavior of StaticMutex, we move part of the mutex implementation into libstd. --- library/std/src/sys/hermit/mutex.rs | 190 ++++++++++++++++++++++++++-- 1 file changed, 182 insertions(+), 8 deletions(-) diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs index 3d4813209cb..511a5100ac6 100644 --- a/library/std/src/sys/hermit/mutex.rs +++ b/library/std/src/sys/hermit/mutex.rs @@ -1,9 +1,161 @@ +use crate::cell::UnsafeCell; +use crate::collections::VecDeque; use crate::ffi::c_void; +use crate::ops::{Deref, DerefMut, Drop}; use crate::ptr; +use crate::sync::atomic::{AtomicUsize, Ordering, spin_loop_hint}; use crate::sys::hermit::abi; +/// This type provides a lock based on busy waiting to realize mutual exclusion +/// +/// # Description +/// +/// This structure behaves a lot like a common mutex. There are some differences: +/// +/// - By using busy waiting, it can be used outside the runtime. +/// - It is a so called ticket lock (https://en.wikipedia.org/wiki/Ticket_lock) +/// and completly fair. +#[cfg_attr(target_arch = "x86_64", repr(align(128)))] +#[cfg_attr(not(target_arch = "x86_64"), repr(align(64)))] +struct Spinlock { + queue: AtomicUsize, + dequeue: AtomicUsize, + data: UnsafeCell, +} + +unsafe impl Sync for Spinlock {} +unsafe impl Send for Spinlock {} + +/// A guard to which the protected data can be accessed +/// +/// When the guard falls out of scope it will release the lock. +struct SpinlockGuard<'a, T: ?Sized + 'a> { + dequeue: &'a AtomicUsize, + data: &'a mut T, +} + +impl Spinlock { + pub const fn new(user_data: T) -> Spinlock { + SpinlockGuard { dequeue: &self.dequeue, data: &mut *self.data.get() } + } + + #[inline] + fn obtain_lock(&self) { + let ticket = self.queue.fetch_add(1, Ordering::SeqCst) + 1; + while self.dequeue.load(Ordering::SeqCst) != ticket { + spin_loop_hint(); + } + } + + #[inline] + pub unsafe fn lock(&self) -> SpinlockGuard<'_, T> { + self.obtain_lock(); + SpinlockGuard { + dequeue: &self.dequeue, + data: &mut *self.data.get(), + } + } +} + +impl Default for Spinlock { + fn default() -> Spinlock { + Spinlock::new(Default::default()) + } +} + +impl<'a, T: ?Sized> Deref for SpinlockGuard<'a, T> { + type Target = T; + fn deref(&self) -> &T { + &*self.data + } +} + +impl<'a, T: ?Sized> DerefMut for SpinlockGuard<'a, T> { + fn deref_mut(&mut self) -> &mut T { + &mut *self.data + } +} + +impl<'a, T: ?Sized> Drop for SpinlockGuard<'a, T> { + /// The dropping of the SpinlockGuard will release the lock it was created from. + fn drop(&mut self) { + self.dequeue.fetch_add(1, Ordering::SeqCst); + } +} + +/// Realize a priority queue for tasks +struct PriorityQueue { + queues: [Option>; abi::NO_PRIORITIES], + prio_bitmap: u64, +} + +impl PriorityQueue { + pub const fn new() -> PriorityQueue { + PriorityQueue { + queues: [ + None, None, None, None, None, None, None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, None, None, None, None, None, None, None, + None, None, None, + ], + prio_bitmap: 0, + } + } + + /// Add a task handle by its priority to the queue + pub fn push(&mut self, prio: abi::Priority, id: abi::Tid) { + let i: usize = prio.into().into(); + self.prio_bitmap |= (1 << i) as u64; + if let Some(queue) = &mut self.queues[i] { + queue.push_back(id); + } else { + let mut queue = VecDeque::new(); + queue.push_back(id); + self.queues[i] = Some(queue); + } + } + + fn pop_from_queue(&mut self, queue_index: usize) -> Option { + if let Some(queue) = &mut self.queues[queue_index] { + let id = queue.pop_front(); + + if queue.is_empty() { + self.prio_bitmap &= !(1 << queue_index as u64); + } + + id + } else { + None + } + } + + /// Pop the task handle with the highest priority from the queue + pub fn pop(&mut self) -> Option { + for i in 0..abi::NO_PRIORITIES { + if self.prio_bitmap & (1 << i) != 0 { + return self.pop_from_queue(i); + } + } + + None + } +} + +struct MutexInner { + locked: bool, + blocked_task: PriorityQueue, +} + +impl MutexInner { + pub const fn new() -> MutexInner { + MutexInner { + locked: false, + blocked_task: PriorityQueue::new(), + } + } +} + pub struct Mutex { - inner: *const c_void, + inner: Spinlock, } unsafe impl Send for Mutex {} @@ -11,33 +163,55 @@ unsafe impl Sync for Mutex {} impl Mutex { pub const fn new() -> Mutex { - Mutex { inner: ptr::null() } + Mutex { + inner: Spinlock::new(MutexInner::new()), + } } #[inline] pub unsafe fn init(&mut self) { - let _ = abi::sem_init(&mut self.inner as *mut *const c_void, 1); + self.inner = Spinlock::new(MutexInner::new()); } #[inline] pub unsafe fn lock(&self) { - let _ = abi::sem_timedwait(self.inner, 0); + loop { + let mut guard = self.inner.lock(); + if guard.locked == false { + guard.locked = true; + return; + } else { + let prio = abi::get_priority(); + let id = abi::getpid(); + + guard.blocked_task.push(prio, id); + abi::block_current_task(); + drop(guard); + abi::yield_now(); + } + } } #[inline] pub unsafe fn unlock(&self) { - let _ = abi::sem_post(self.inner); + let mut guard = self.inner.lock(); + guard.locked = false; + if let Some(tid) = guard.blocked_task.pop() { + abi::wakeup_task(tid); + } } #[inline] pub unsafe fn try_lock(&self) -> bool { - let result = abi::sem_trywait(self.inner); - result == 0 + let mut guard = self.inner.lock(); + if guard.locked == false { + guard.locked = true; + } + guard.locked } #[inline] pub unsafe fn destroy(&self) { - let _ = abi::sem_destroy(self.inner); } } From 98fcc3fbc7b2f3420d393b8916746002d501401c Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Tue, 6 Oct 2020 11:42:57 +0200 Subject: [PATCH 103/446] using the latest version of libhermit-rs --- Cargo.lock | 4 ++-- library/std/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ec4f3091d2d..493c184313c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1328,9 +1328,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.15" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" +checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" dependencies = [ "compiler_builtins", "libc", diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index c08828bc0cd..98d955efb28 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -42,7 +42,7 @@ dlmalloc = { version = "0.1", features = ['rustc-dep-of-std'] } fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] } [target.'cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_os = "hermit"))'.dependencies] -hermit-abi = { version = "0.1.15", features = ['rustc-dep-of-std'] } +hermit-abi = { version = "0.1.17", features = ['rustc-dep-of-std'] } [target.wasm32-wasi.dependencies] wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = false } From d560b50d87c05ea5a8e6186c05a50ecd828eaaae Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Tue, 6 Oct 2020 12:12:15 +0200 Subject: [PATCH 104/446] revise code to pass the format check --- library/std/src/sys/hermit/mutex.rs | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs index 511a5100ac6..bd9a9023396 100644 --- a/library/std/src/sys/hermit/mutex.rs +++ b/library/std/src/sys/hermit/mutex.rs @@ -3,7 +3,7 @@ use crate::collections::VecDeque; use crate::ffi::c_void; use crate::ops::{Deref, DerefMut, Drop}; use crate::ptr; -use crate::sync::atomic::{AtomicUsize, Ordering, spin_loop_hint}; +use crate::sync::atomic::{spin_loop_hint, AtomicUsize, Ordering}; use crate::sys::hermit::abi; /// This type provides a lock based on busy waiting to realize mutual exclusion @@ -50,10 +50,7 @@ impl Spinlock { #[inline] pub unsafe fn lock(&self) -> SpinlockGuard<'_, T> { self.obtain_lock(); - SpinlockGuard { - dequeue: &self.dequeue, - data: &mut *self.data.get(), - } + SpinlockGuard { dequeue: &self.dequeue, data: &mut *self.data.get() } } } @@ -147,10 +144,7 @@ struct MutexInner { impl MutexInner { pub const fn new() -> MutexInner { - MutexInner { - locked: false, - blocked_task: PriorityQueue::new(), - } + MutexInner { locked: false, blocked_task: PriorityQueue::new() } } } @@ -163,9 +157,7 @@ unsafe impl Sync for Mutex {} impl Mutex { pub const fn new() -> Mutex { - Mutex { - inner: Spinlock::new(MutexInner::new()), - } + Mutex { inner: Spinlock::new(MutexInner::new()) } } #[inline] @@ -211,8 +203,7 @@ impl Mutex { } #[inline] - pub unsafe fn destroy(&self) { - } + pub unsafe fn destroy(&self) {} } pub struct ReentrantMutex { From 986c1fc053828a051c9fd888cbf49393f276f4f5 Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Wed, 7 Oct 2020 10:39:22 +0200 Subject: [PATCH 105/446] revise comments and descriptions of the helper functions --- library/std/src/sys/hermit/mutex.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs index bd9a9023396..1bf142ec683 100644 --- a/library/std/src/sys/hermit/mutex.rs +++ b/library/std/src/sys/hermit/mutex.rs @@ -13,8 +13,7 @@ use crate::sys::hermit::abi; /// This structure behaves a lot like a common mutex. There are some differences: /// /// - By using busy waiting, it can be used outside the runtime. -/// - It is a so called ticket lock (https://en.wikipedia.org/wiki/Ticket_lock) -/// and completly fair. +/// - It is a so called ticket lock and is completly fair. #[cfg_attr(target_arch = "x86_64", repr(align(128)))] #[cfg_attr(not(target_arch = "x86_64"), repr(align(64)))] struct Spinlock { @@ -98,7 +97,7 @@ impl PriorityQueue { } } - /// Add a task handle by its priority to the queue + /// Add a task id by its priority to the queue pub fn push(&mut self, prio: abi::Priority, id: abi::Tid) { let i: usize = prio.into().into(); self.prio_bitmap |= (1 << i) as u64; From d6e955f3bfd0a47240879549dc2fb3284dfe08e4 Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Fri, 9 Oct 2020 06:42:19 +0200 Subject: [PATCH 106/446] fix typos in new method --- library/std/src/sys/hermit/mutex.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs index 1bf142ec683..c3f88ada0f4 100644 --- a/library/std/src/sys/hermit/mutex.rs +++ b/library/std/src/sys/hermit/mutex.rs @@ -35,7 +35,11 @@ struct SpinlockGuard<'a, T: ?Sized + 'a> { impl Spinlock { pub const fn new(user_data: T) -> Spinlock { - SpinlockGuard { dequeue: &self.dequeue, data: &mut *self.data.get() } + Spinlock { + queue: AtomicUsize::new(0), + dequeue: AtomicUsize::new(1), + data: UnsafeCell::new(user_data), + } } #[inline] From 530f5754664699dee29bde6cfa99aaf861499544 Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Fri, 9 Oct 2020 07:26:48 +0200 Subject: [PATCH 107/446] revise code to pass the format check --- library/std/src/sys/hermit/mutex.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs index c3f88ada0f4..e9222f34b89 100644 --- a/library/std/src/sys/hermit/mutex.rs +++ b/library/std/src/sys/hermit/mutex.rs @@ -36,9 +36,9 @@ struct SpinlockGuard<'a, T: ?Sized + 'a> { impl Spinlock { pub const fn new(user_data: T) -> Spinlock { Spinlock { - queue: AtomicUsize::new(0), - dequeue: AtomicUsize::new(1), - data: UnsafeCell::new(user_data), + queue: AtomicUsize::new(0), + dequeue: AtomicUsize::new(1), + data: UnsafeCell::new(user_data), } } From 8d8a290c691db7a8ee566edbd485a729eb41d4ba Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Fri, 9 Oct 2020 08:25:19 +0200 Subject: [PATCH 108/446] add hermit to the list of omit OS --- library/std/src/sys/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index 7b5fac922d0..b4628b64911 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -89,6 +89,7 @@ cfg_if::cfg_if! { #[stable(feature = "rust1", since = "1.0.0")] pub use self::ext as windows_ext; } else if #[cfg(any(target_os = "cloudabi", + target_os = "hermit", target_arch = "wasm32", all(target_vendor = "fortanix", target_env = "sgx")))] { // On CloudABI and wasm right now the shim below doesn't compile, so From 377d1fab1f1fe104c12cea17f7f24a8e23775942 Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Sun, 11 Oct 2020 22:57:22 +0900 Subject: [PATCH 109/446] Remove the generated files by `update-references.sh` if they are empty --- doc/adding_lints.md | 3 ++- tests/ui-cargo/update-references.sh | 8 ++++++++ tests/ui-toml/update-references.sh | 8 ++++++++ tests/ui/update-references.sh | 12 ++++++++++++ 4 files changed, 30 insertions(+), 1 deletion(-) diff --git a/doc/adding_lints.md b/doc/adding_lints.md index 2869c3bf7d4..344bb455aa5 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -104,7 +104,8 @@ every time before running `tests/ui/update-all-references.sh`. Running `TESTNAME=foo_functions cargo uitest` should pass then. When we commit our lint, we need to commit the generated `.stderr` files, too. In general, you should only commit files changed by `tests/ui/update-all-references.sh` for the -specific lint you are creating/editing. +specific lint you are creating/editing. Note that if the generated files are +empty, they should be removed. ### Cargo lints diff --git a/tests/ui-cargo/update-references.sh b/tests/ui-cargo/update-references.sh index 50d42678734..2ab51168bca 100755 --- a/tests/ui-cargo/update-references.sh +++ b/tests/ui-cargo/update-references.sh @@ -29,10 +29,18 @@ while [[ "$1" != "" ]]; do ! (cmp -s -- "$BUILD_DIR"/"$STDOUT_NAME" "$MYDIR"/"$STDOUT_NAME"); then echo updating "$MYDIR"/"$STDOUT_NAME" cp "$BUILD_DIR"/"$STDOUT_NAME" "$MYDIR"/"$STDOUT_NAME" + if [[ ! -s "$MYDIR"/"$STDOUT_NAME" ]]; then + echo removing "$MYDIR"/"$STDOUT_NAME" + rm "$MYDIR"/"$STDOUT_NAME" + fi fi if [[ -f "$BUILD_DIR"/"$STDERR_NAME" ]] && \ ! (cmp -s -- "$BUILD_DIR"/"$STDERR_NAME" "$MYDIR"/"$STDERR_NAME"); then echo updating "$MYDIR"/"$STDERR_NAME" cp "$BUILD_DIR"/"$STDERR_NAME" "$MYDIR"/"$STDERR_NAME" + if [[ ! -s "$MYDIR"/"$STDERR_NAME" ]]; then + echo removing "$MYDIR"/"$STDERR_NAME" + rm "$MYDIR"/"$STDERR_NAME" + fi fi done diff --git a/tests/ui-toml/update-references.sh b/tests/ui-toml/update-references.sh index 50d42678734..2ab51168bca 100755 --- a/tests/ui-toml/update-references.sh +++ b/tests/ui-toml/update-references.sh @@ -29,10 +29,18 @@ while [[ "$1" != "" ]]; do ! (cmp -s -- "$BUILD_DIR"/"$STDOUT_NAME" "$MYDIR"/"$STDOUT_NAME"); then echo updating "$MYDIR"/"$STDOUT_NAME" cp "$BUILD_DIR"/"$STDOUT_NAME" "$MYDIR"/"$STDOUT_NAME" + if [[ ! -s "$MYDIR"/"$STDOUT_NAME" ]]; then + echo removing "$MYDIR"/"$STDOUT_NAME" + rm "$MYDIR"/"$STDOUT_NAME" + fi fi if [[ -f "$BUILD_DIR"/"$STDERR_NAME" ]] && \ ! (cmp -s -- "$BUILD_DIR"/"$STDERR_NAME" "$MYDIR"/"$STDERR_NAME"); then echo updating "$MYDIR"/"$STDERR_NAME" cp "$BUILD_DIR"/"$STDERR_NAME" "$MYDIR"/"$STDERR_NAME" + if [[ ! -s "$MYDIR"/"$STDERR_NAME" ]]; then + echo removing "$MYDIR"/"$STDERR_NAME" + rm "$MYDIR"/"$STDERR_NAME" + fi fi done diff --git a/tests/ui/update-references.sh b/tests/ui/update-references.sh index 2c13c327d79..e16ed600ef8 100755 --- a/tests/ui/update-references.sh +++ b/tests/ui/update-references.sh @@ -30,15 +30,27 @@ while [[ "$1" != "" ]]; do ! (cmp -s -- "$BUILD_DIR"/"$STDOUT_NAME" "$MYDIR"/"$STDOUT_NAME"); then echo updating "$MYDIR"/"$STDOUT_NAME" cp "$BUILD_DIR"/"$STDOUT_NAME" "$MYDIR"/"$STDOUT_NAME" + if [[ ! -s "$MYDIR"/"$STDOUT_NAME" ]]; then + echo removing "$MYDIR"/"$STDOUT_NAME" + rm "$MYDIR"/"$STDOUT_NAME" + fi fi if [[ -f "$BUILD_DIR"/"$STDERR_NAME" ]] && \ ! (cmp -s -- "$BUILD_DIR"/"$STDERR_NAME" "$MYDIR"/"$STDERR_NAME"); then echo updating "$MYDIR"/"$STDERR_NAME" cp "$BUILD_DIR"/"$STDERR_NAME" "$MYDIR"/"$STDERR_NAME" + if [[ ! -s "$MYDIR"/"$STDERR_NAME" ]]; then + echo removing "$MYDIR"/"$STDERR_NAME" + rm "$MYDIR"/"$STDERR_NAME" + fi fi if [[ -f "$BUILD_DIR"/"$FIXED_NAME" ]] && \ ! (cmp -s -- "$BUILD_DIR"/"$FIXED_NAME" "$MYDIR"/"$FIXED_NAME"); then echo updating "$MYDIR"/"$FIXED_NAME" cp "$BUILD_DIR"/"$FIXED_NAME" "$MYDIR"/"$FIXED_NAME" + if [[ ! -s "$MYDIR"/"$FIXED_NAME" ]]; then + echo removing "$MYDIR"/"$FIXED_NAME" + rm "$MYDIR"/"$FIXED_NAME" + fi fi done From 54bf8a681bededa6c7e09f4c1da3cb68efb885a3 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 11 Oct 2020 14:56:12 -0400 Subject: [PATCH 110/446] Don't link to nightly primitives on stable channel I am not sure how to test this. --- src/librustdoc/clean/types.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 1e07f8e2eac..f81c6c3df76 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -14,6 +14,7 @@ use rustc_ast::util::comments::beautify_doc_string; use rustc_ast::{self as ast, AttrStyle}; use rustc_ast::{FloatTy, IntTy, UintTy}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_feature::UnstableFeatures; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; @@ -698,9 +699,13 @@ impl Attributes { "../".repeat(depth) } Some(&(_, _, ExternalLocation::Remote(ref s))) => s.to_string(), - Some(&(_, _, ExternalLocation::Unknown)) | None => { - String::from("https://doc.rust-lang.org/nightly") - } + Some(&(_, _, ExternalLocation::Unknown)) | None => String::from( + if UnstableFeatures::from_environment().is_nightly_build() { + "https://doc.rust-lang.org/nightly" + } else { + "https://doc.rust-lang.org" + }, + ), }; // This is a primitive so the url is done "by hand". let tail = fragment.find('#').unwrap_or_else(|| fragment.len()); From 6021c231599eabcb07b3a8207bddbb3796c93eee Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Sun, 11 Oct 2020 13:27:20 +0200 Subject: [PATCH 111/446] New lint: result-unit-err --- CHANGELOG.md | 1 + clippy_lints/src/functions.rs | 106 ++++++++++++++++++++++++++---- clippy_lints/src/lib.rs | 3 + src/lintlist/mod.rs | 7 ++ tests/ui/doc_errors.rs | 1 + tests/ui/doc_errors.stderr | 14 ++-- tests/ui/double_must_use.rs | 1 + tests/ui/double_must_use.stderr | 6 +- tests/ui/result_unit_error.rs | 38 +++++++++++ tests/ui/result_unit_error.stderr | 35 ++++++++++ 10 files changed, 189 insertions(+), 23 deletions(-) create mode 100644 tests/ui/result_unit_error.rs create mode 100644 tests/ui/result_unit_error.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fb6cf75d96..f21768c4498 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1918,6 +1918,7 @@ Released 2018-09-13 [`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs [`result_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option [`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn +[`result_unit_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unit_err [`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges [`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition [`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 50b39cf4ea7..212a3100637 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -1,8 +1,9 @@ use crate::utils::{ - attr_by_name, attrs::is_proc_macro, is_must_use_ty, is_trait_impl_item, iter_input_pats, match_def_path, - must_use_attr, qpath_res, return_ty, snippet, snippet_opt, span_lint, span_lint_and_help, span_lint_and_then, - trait_ref_of_method, type_is_unsafe_function, + attr_by_name, attrs::is_proc_macro, is_must_use_ty, is_trait_impl_item, is_type_diagnostic_item, iter_input_pats, + last_path_segment, match_def_path, must_use_attr, qpath_res, return_ty, snippet, snippet_opt, span_lint, + span_lint_and_help, span_lint_and_then, trait_ref_of_method, type_is_unsafe_function, }; +use if_chain::if_chain; use rustc_ast::ast::Attribute; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -16,6 +17,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_target::spec::abi::Abi; +use rustc_typeck::hir_ty_to_ty; declare_clippy_lint! { /// **What it does:** Checks for functions with too many parameters. @@ -169,6 +171,52 @@ declare_clippy_lint! { "function or method that could take a `#[must_use]` attribute" } +declare_clippy_lint! { + /// **What it does:** Checks for public functions that return a `Result` + /// with an `Err` type of `()`. It suggests using a custom type that + /// implements [`std::error::Error`]. + /// + /// **Why is this bad?** Unit does not implement `Error` and carries no + /// further information about what went wrong. + /// + /// **Known problems:** Of course, this lint assumes that `Result` is used + /// for a fallible operation (which is after all the intended use). However + /// code may opt to (mis)use it as a basic two-variant-enum. In that case, + /// the suggestion is misguided, and the code should use a custom enum + /// instead. + /// + /// **Examples:** + /// ```rust + /// pub fn read_u8() -> Result { Err(()) } + /// ``` + /// should become + /// ```rust,should_panic + /// use std::fmt; + /// + /// #[derive(Debug)] + /// struct EndOfStream; + /// + /// impl fmt::Display for EndOfStream { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "End of Stream") + /// } + /// } + /// + /// impl std::error::Error for EndOfStream { } + /// + /// pub fn read_u8() -> Result { Err(EndOfStream) } + ///# fn main() { + ///# read_u8().unwrap(); + ///# } + /// ``` + /// + /// Note that there are crates that simplify creating the error type, e.g. + /// [`thiserror`](https://docs.rs/thiserror). + pub RESULT_UNIT_ERR, + style, + "public function returning `Result` with an `Err` type of `()`" +} + #[derive(Copy, Clone)] pub struct Functions { threshold: u64, @@ -188,6 +236,7 @@ impl_lint_pass!(Functions => [ MUST_USE_UNIT, DOUBLE_MUST_USE, MUST_USE_CANDIDATE, + RESULT_UNIT_ERR, ]); impl<'tcx> LateLintPass<'tcx> for Functions { @@ -233,15 +282,16 @@ impl<'tcx> LateLintPass<'tcx> for Functions { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { let attr = must_use_attr(&item.attrs); if let hir::ItemKind::Fn(ref sig, ref _generics, ref body_id) = item.kind { + let is_public = cx.access_levels.is_exported(item.hir_id); + let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); + if is_public { + check_result_unit_err(cx, &sig.decl, item.span, fn_header_span); + } if let Some(attr) = attr { - let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); check_needless_must_use(cx, &sig.decl, item.hir_id, item.span, fn_header_span, attr); return; } - if cx.access_levels.is_exported(item.hir_id) - && !is_proc_macro(cx.sess(), &item.attrs) - && attr_by_name(&item.attrs, "no_mangle").is_none() - { + if is_public && !is_proc_macro(cx.sess(), &item.attrs) && attr_by_name(&item.attrs, "no_mangle").is_none() { check_must_use_candidate( cx, &sig.decl, @@ -257,11 +307,15 @@ impl<'tcx> LateLintPass<'tcx> for Functions { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) { if let hir::ImplItemKind::Fn(ref sig, ref body_id) = item.kind { + let is_public = cx.access_levels.is_exported(item.hir_id); + let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); + if is_public && trait_ref_of_method(cx, item.hir_id).is_none() { + check_result_unit_err(cx, &sig.decl, item.span, fn_header_span); + } let attr = must_use_attr(&item.attrs); if let Some(attr) = attr { - let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); check_needless_must_use(cx, &sig.decl, item.hir_id, item.span, fn_header_span, attr); - } else if cx.access_levels.is_exported(item.hir_id) + } else if is_public && !is_proc_macro(cx.sess(), &item.attrs) && trait_ref_of_method(cx, item.hir_id).is_none() { @@ -284,18 +338,21 @@ impl<'tcx> LateLintPass<'tcx> for Functions { if sig.header.abi == Abi::Rust { self.check_arg_number(cx, &sig.decl, item.span.with_hi(sig.decl.output.span().hi())); } + let is_public = cx.access_levels.is_exported(item.hir_id); + let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); + if is_public { + check_result_unit_err(cx, &sig.decl, item.span, fn_header_span); + } let attr = must_use_attr(&item.attrs); if let Some(attr) = attr { - let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); check_needless_must_use(cx, &sig.decl, item.hir_id, item.span, fn_header_span, attr); } if let hir::TraitFn::Provided(eid) = *eid { let body = cx.tcx.hir().body(eid); Self::check_raw_ptr(cx, sig.header.unsafety, &sig.decl, body, item.hir_id); - if attr.is_none() && cx.access_levels.is_exported(item.hir_id) && !is_proc_macro(cx.sess(), &item.attrs) - { + if attr.is_none() && is_public && !is_proc_macro(cx.sess(), &item.attrs) { check_must_use_candidate( cx, &sig.decl, @@ -411,6 +468,29 @@ impl<'tcx> Functions { } } +fn check_result_unit_err(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, item_span: Span, fn_header_span: Span) { + if_chain! { + if !in_external_macro(cx.sess(), item_span); + if let hir::FnRetTy::Return(ref ty) = decl.output; + if let hir::TyKind::Path(ref qpath) = ty.kind; + if is_type_diagnostic_item(cx, hir_ty_to_ty(cx.tcx, ty), sym!(result_type)); + if let Some(ref args) = last_path_segment(qpath).args; + if let [_, hir::GenericArg::Type(ref err_ty)] = args.args; + if let hir::TyKind::Tup(t) = err_ty.kind; + if t.is_empty(); + then { + span_lint_and_help( + cx, + RESULT_UNIT_ERR, + fn_header_span, + "This returns a `Result<_, ()>", + None, + "Use a custom Error type instead", + ); + } + } +} + fn check_needless_must_use( cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 097eca0af57..26a727687b1 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -582,6 +582,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &functions::MUST_USE_CANDIDATE, &functions::MUST_USE_UNIT, &functions::NOT_UNSAFE_PTR_ARG_DEREF, + &functions::RESULT_UNIT_ERR, &functions::TOO_MANY_ARGUMENTS, &functions::TOO_MANY_LINES, &future_not_send::FUTURE_NOT_SEND, @@ -1327,6 +1328,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&functions::DOUBLE_MUST_USE), LintId::of(&functions::MUST_USE_UNIT), LintId::of(&functions::NOT_UNSAFE_PTR_ARG_DEREF), + LintId::of(&functions::RESULT_UNIT_ERR), LintId::of(&functions::TOO_MANY_ARGUMENTS), LintId::of(&get_last_with_len::GET_LAST_WITH_LEN), LintId::of(&identity_op::IDENTITY_OP), @@ -1558,6 +1560,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&formatting::SUSPICIOUS_UNARY_OP_FORMATTING), LintId::of(&functions::DOUBLE_MUST_USE), LintId::of(&functions::MUST_USE_UNIT), + LintId::of(&functions::RESULT_UNIT_ERR), LintId::of(&if_let_some_result::IF_LET_SOME_RESULT), LintId::of(&inherent_to_string::INHERENT_TO_STRING), LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 96c9d12d75f..d0fc8f0c8a9 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2005,6 +2005,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "map_unit_fn", }, + Lint { + name: "result_unit_err", + group: "style", + desc: "public function returning `Result` with an `Err` type of `()`", + deprecation: None, + module: "functions", + }, Lint { name: "reversed_empty_ranges", group: "correctness", diff --git a/tests/ui/doc_errors.rs b/tests/ui/doc_errors.rs index 445fc8d31d7..f47b81a450e 100644 --- a/tests/ui/doc_errors.rs +++ b/tests/ui/doc_errors.rs @@ -1,5 +1,6 @@ // edition:2018 #![warn(clippy::missing_errors_doc)] +#![allow(clippy::result_unit_err)] use std::io; diff --git a/tests/ui/doc_errors.stderr b/tests/ui/doc_errors.stderr index f44d6693d30..c7b616e2897 100644 --- a/tests/ui/doc_errors.stderr +++ b/tests/ui/doc_errors.stderr @@ -1,5 +1,5 @@ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:6:1 + --> $DIR/doc_errors.rs:7:1 | LL | / pub fn pub_fn_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::missing-errors-doc` implied by `-D warnings` error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:10:1 + --> $DIR/doc_errors.rs:11:1 | LL | / pub async fn async_pub_fn_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -17,7 +17,7 @@ LL | | } | |_^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:15:1 + --> $DIR/doc_errors.rs:16:1 | LL | / pub fn pub_fn_returning_io_result() -> io::Result<()> { LL | | unimplemented!(); @@ -25,7 +25,7 @@ LL | | } | |_^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:20:1 + --> $DIR/doc_errors.rs:21:1 | LL | / pub async fn async_pub_fn_returning_io_result() -> io::Result<()> { LL | | unimplemented!(); @@ -33,7 +33,7 @@ LL | | } | |_^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:50:5 + --> $DIR/doc_errors.rs:51:5 | LL | / pub fn pub_method_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -41,7 +41,7 @@ LL | | } | |_____^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:55:5 + --> $DIR/doc_errors.rs:56:5 | LL | / pub async fn async_pub_method_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -49,7 +49,7 @@ LL | | } | |_____^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:84:5 + --> $DIR/doc_errors.rs:85:5 | LL | fn trait_method_missing_errors_header() -> Result<(), ()>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/double_must_use.rs b/tests/ui/double_must_use.rs index a48e675e4ea..05e087b08bc 100644 --- a/tests/ui/double_must_use.rs +++ b/tests/ui/double_must_use.rs @@ -1,4 +1,5 @@ #![warn(clippy::double_must_use)] +#![allow(clippy::result_unit_err)] #[must_use] pub fn must_use_result() -> Result<(), ()> { diff --git a/tests/ui/double_must_use.stderr b/tests/ui/double_must_use.stderr index bc37785294f..8290ece1cad 100644 --- a/tests/ui/double_must_use.stderr +++ b/tests/ui/double_must_use.stderr @@ -1,5 +1,5 @@ error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]` - --> $DIR/double_must_use.rs:4:1 + --> $DIR/double_must_use.rs:5:1 | LL | pub fn must_use_result() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | pub fn must_use_result() -> Result<(), ()> { = help: either add some descriptive text or remove the attribute error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]` - --> $DIR/double_must_use.rs:9:1 + --> $DIR/double_must_use.rs:10:1 | LL | pub fn must_use_tuple() -> (Result<(), ()>, u8) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | pub fn must_use_tuple() -> (Result<(), ()>, u8) { = help: either add some descriptive text or remove the attribute error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]` - --> $DIR/double_must_use.rs:14:1 + --> $DIR/double_must_use.rs:15:1 | LL | pub fn must_use_array() -> [Result<(), ()>; 1] { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/result_unit_error.rs b/tests/ui/result_unit_error.rs new file mode 100644 index 00000000000..a66f581b215 --- /dev/null +++ b/tests/ui/result_unit_error.rs @@ -0,0 +1,38 @@ +#[warn(clippy::result_unit_err)] +#[allow(unused)] + +pub fn returns_unit_error() -> Result { + Err(()) +} + +fn private_unit_errors() -> Result { + Err(()) +} + +pub trait HasUnitError { + fn get_that_error(&self) -> Result; + + fn get_this_one_too(&self) -> Result { + Err(()) + } +} + +impl HasUnitError for () { + fn get_that_error(&self) -> Result { + Ok(true) + } +} + +trait PrivateUnitError { + fn no_problem(&self) -> Result; +} + +pub struct UnitErrorHolder; + +impl UnitErrorHolder { + pub fn unit_error(&self) -> Result { + Ok(0) + } +} + +fn main() {} diff --git a/tests/ui/result_unit_error.stderr b/tests/ui/result_unit_error.stderr new file mode 100644 index 00000000000..986d9718acd --- /dev/null +++ b/tests/ui/result_unit_error.stderr @@ -0,0 +1,35 @@ +error: This returns a `Result<_, ()> + --> $DIR/result_unit_error.rs:4:1 + | +LL | pub fn returns_unit_error() -> Result { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::result-unit-err` implied by `-D warnings` + = help: Use a custom Error type instead + +error: This returns a `Result<_, ()> + --> $DIR/result_unit_error.rs:13:5 + | +LL | fn get_that_error(&self) -> Result; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: Use a custom Error type instead + +error: This returns a `Result<_, ()> + --> $DIR/result_unit_error.rs:15:5 + | +LL | fn get_this_one_too(&self) -> Result { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: Use a custom Error type instead + +error: This returns a `Result<_, ()> + --> $DIR/result_unit_error.rs:33:5 + | +LL | pub fn unit_error(&self) -> Result { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: Use a custom Error type instead + +error: aborting due to 4 previous errors + From 74ae116131696e4385d5b8e5da34deaad0d25ec9 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Sun, 11 Oct 2020 22:15:56 +0200 Subject: [PATCH 112/446] Use lowercase in error messages --- clippy_lints/src/functions.rs | 14 +++++++------- tests/ui/result_unit_error.stderr | 16 ++++++++-------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 212a3100637..fd45a6da61c 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -194,19 +194,19 @@ declare_clippy_lint! { /// use std::fmt; /// /// #[derive(Debug)] - /// struct EndOfStream; + /// pub struct EndOfStream; /// /// impl fmt::Display for EndOfStream { - /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// write!(f, "End of Stream") - /// } + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "End of Stream") + /// } /// } /// /// impl std::error::Error for EndOfStream { } /// /// pub fn read_u8() -> Result { Err(EndOfStream) } ///# fn main() { - ///# read_u8().unwrap(); + ///# read_u8().unwrap(); ///# } /// ``` /// @@ -483,9 +483,9 @@ fn check_result_unit_err(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, item_span cx, RESULT_UNIT_ERR, fn_header_span, - "This returns a `Result<_, ()>", + "this returns a `Result<_, ()>", None, - "Use a custom Error type instead", + "use a custom Error type instead", ); } } diff --git a/tests/ui/result_unit_error.stderr b/tests/ui/result_unit_error.stderr index 986d9718acd..b8230032491 100644 --- a/tests/ui/result_unit_error.stderr +++ b/tests/ui/result_unit_error.stderr @@ -1,35 +1,35 @@ -error: This returns a `Result<_, ()> +error: this returns a `Result<_, ()> --> $DIR/result_unit_error.rs:4:1 | LL | pub fn returns_unit_error() -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::result-unit-err` implied by `-D warnings` - = help: Use a custom Error type instead + = help: use a custom Error type instead -error: This returns a `Result<_, ()> +error: this returns a `Result<_, ()> --> $DIR/result_unit_error.rs:13:5 | LL | fn get_that_error(&self) -> Result; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: Use a custom Error type instead + = help: use a custom Error type instead -error: This returns a `Result<_, ()> +error: this returns a `Result<_, ()> --> $DIR/result_unit_error.rs:15:5 | LL | fn get_this_one_too(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: Use a custom Error type instead + = help: use a custom Error type instead -error: This returns a `Result<_, ()> +error: this returns a `Result<_, ()> --> $DIR/result_unit_error.rs:33:5 | LL | pub fn unit_error(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: Use a custom Error type instead + = help: use a custom Error type instead error: aborting due to 4 previous errors From 0ec3ea9e697ea9c2ce225ba0b9f3715434fc773e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Oct 2020 00:10:37 +0200 Subject: [PATCH 113/446] const keyword: brief paragraph on 'const fn' --- library/std/src/keyword_docs.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 54ce0e7b831..c76f9b923cd 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -102,7 +102,9 @@ mod break_keyword {} #[doc(keyword = "const")] // -/// Compile-time constants and deterministic functions. +/// Compile-time constants and compile-time evaluable functions. +/// +/// ## Compile-time constants /// /// Sometimes a certain value is used many times throughout a program, and it can become /// inconvenient to copy it over and over. What's more, it's not always possible or desirable to @@ -145,15 +147,28 @@ mod break_keyword {} /// /// Constants, like statics, should always be in `SCREAMING_SNAKE_CASE`. /// +/// For more detail on `const`, see the [Rust Book] or the [Reference]. +/// +/// ## Compile-time evaluable functions +/// +/// The other main use of the `const` keyword is in `const fn`. This marks a function as being +/// callable in the body of a `const` or `static` item and in array initializers (commonly called +/// "const contexts"). `const fn` are restricted in the set of operations they can perform, to +/// ensure that they can be evaluated at compile-time. See the [Reference][const-eval] for more +/// detail. +/// +/// Turning a `fn` into a `const fn` has no effect on run-time uses of that function. +/// +/// ## Other uses of `const` +/// /// The `const` keyword is also used in raw pointers in combination with `mut`, as seen in `*const /// T` and `*mut T`. More about `const` as used in raw pointers can be read at the Rust docs for the [pointer primitive]. /// -/// For more detail on `const`, see the [Rust Book] or the [Reference]. -/// /// [pointer primitive]: primitive.pointer.html /// [Rust Book]: /// ../book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants /// [Reference]: ../reference/items/constant-items.html +/// [cosnt-eval]: ./reference/const_eval.html mod const_keyword {} #[doc(keyword = "continue")] From 33fd08b61f57cde81bf01964b2fc4d2dca0e4d3f Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Mon, 12 Oct 2020 06:51:52 +0200 Subject: [PATCH 114/446] remove obsolete function diverge --- library/std/src/sys/hermit/fs.rs | 4 - library/std/src/sys/hermit/process.rs | 149 -------------------------- 2 files changed, 153 deletions(-) delete mode 100644 library/std/src/sys/hermit/process.rs diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs index 82ccab1462b..829d4c943f1 100644 --- a/library/std/src/sys/hermit/fs.rs +++ b/library/std/src/sys/hermit/fs.rs @@ -334,10 +334,6 @@ impl File { pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { Err(Error::from_raw_os_error(22)) } - - pub fn diverge(&self) -> ! { - loop {} - } } impl DirBuilder { diff --git a/library/std/src/sys/hermit/process.rs b/library/std/src/sys/hermit/process.rs deleted file mode 100644 index 4702e5c5492..00000000000 --- a/library/std/src/sys/hermit/process.rs +++ /dev/null @@ -1,149 +0,0 @@ -use crate::ffi::OsStr; -use crate::fmt; -use crate::io; -use crate::sys::fs::File; -use crate::sys::pipe::AnonPipe; -use crate::sys::{unsupported, Void}; -use crate::sys_common::process::CommandEnv; - -pub use crate::ffi::OsString as EnvKey; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -pub struct Command { - env: CommandEnv, -} - -// passed back to std::process with the pipes connected to the child, if any -// were requested -pub struct StdioPipes { - pub stdin: Option, - pub stdout: Option, - pub stderr: Option, -} - -pub enum Stdio { - Inherit, - Null, - MakePipe, -} - -impl Command { - pub fn new(_program: &OsStr) -> Command { - Command { env: Default::default() } - } - - pub fn arg(&mut self, _arg: &OsStr) {} - - pub fn env_mut(&mut self) -> &mut CommandEnv { - &mut self.env - } - - pub fn cwd(&mut self, _dir: &OsStr) {} - - pub fn stdin(&mut self, _stdin: Stdio) {} - - pub fn stdout(&mut self, _stdout: Stdio) {} - - pub fn stderr(&mut self, _stderr: Stdio) {} - - pub fn spawn( - &mut self, - _default: Stdio, - _needs_stdin: bool, - ) -> io::Result<(Process, StdioPipes)> { - unsupported() - } -} - -impl From for Stdio { - fn from(pipe: AnonPipe) -> Stdio { - pipe.diverge() - } -} - -impl From for Stdio { - fn from(file: File) -> Stdio { - file.diverge() - } -} - -impl fmt::Debug for Command { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - Ok(()) - } -} - -pub struct ExitStatus(Void); - -impl ExitStatus { - pub fn success(&self) -> bool { - match self.0 {} - } - - pub fn code(&self) -> Option { - match self.0 {} - } -} - -impl Clone for ExitStatus { - fn clone(&self) -> ExitStatus { - match self.0 {} - } -} - -impl Copy for ExitStatus {} - -impl PartialEq for ExitStatus { - fn eq(&self, _other: &ExitStatus) -> bool { - match self.0 {} - } -} - -impl Eq for ExitStatus {} - -impl fmt::Debug for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -impl fmt::Display for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitCode(bool); - -impl ExitCode { - pub const SUCCESS: ExitCode = ExitCode(false); - pub const FAILURE: ExitCode = ExitCode(true); - - pub fn as_i32(&self) -> i32 { - self.0 as i32 - } -} - -pub struct Process(Void); - -impl Process { - pub fn id(&self) -> u32 { - match self.0 {} - } - - pub fn kill(&mut self) -> io::Result<()> { - match self.0 {} - } - - pub fn wait(&mut self) -> io::Result { - match self.0 {} - } - - pub fn try_wait(&mut self) -> io::Result> { - match self.0 {} - } -} From 30c3dadb4da44c950f79e9772b36bbaf2660bb0e Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Mon, 12 Oct 2020 06:53:06 +0200 Subject: [PATCH 115/446] reuse implementation of the system provider "unsupported" --- library/std/src/sys/hermit/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs index 8eaf07e52d6..af05310a8d3 100644 --- a/library/std/src/sys/hermit/mod.rs +++ b/library/std/src/sys/hermit/mod.rs @@ -31,6 +31,7 @@ pub mod net; pub mod os; pub mod path; pub mod pipe; +#[path = "../unsupported/process.rs"] pub mod process; pub mod rwlock; pub mod stack_overflow; From 1741e5b8f581960a6e9cb9f0b8261b5f0c26e92d Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Mon, 12 Oct 2020 06:54:48 +0200 Subject: [PATCH 116/446] define required type 'MovableMutex' --- library/std/src/sys/hermit/mutex.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs index e9222f34b89..e12c2f4e00c 100644 --- a/library/std/src/sys/hermit/mutex.rs +++ b/library/std/src/sys/hermit/mutex.rs @@ -155,6 +155,8 @@ pub struct Mutex { inner: Spinlock, } +pub type MovableMutex = Mutex; + unsafe impl Send for Mutex {} unsafe impl Sync for Mutex {} From a602d155f06bb3fb7129c036f372e1cb4595ab01 Mon Sep 17 00:00:00 2001 From: Tyson Nottingham Date: Sun, 11 Oct 2020 23:16:01 -0700 Subject: [PATCH 117/446] SipHasher128: improve constant names and add more comments --- compiler/rustc_data_structures/src/sip128.rs | 102 +++++++++++------- .../rustc_data_structures/src/sip128/tests.rs | 4 +- 2 files changed, 68 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs index 5bbc53945ed..53062b9c20d 100644 --- a/compiler/rustc_data_structures/src/sip128.rs +++ b/compiler/rustc_data_structures/src/sip128.rs @@ -7,12 +7,34 @@ use std::ptr; #[cfg(test)] mod tests; +// The SipHash algorithm operates on 8-byte chunks. const ELEM_SIZE: usize = mem::size_of::(); -const BUFFER_SIZE_ELEMS: usize = 8; -const BUFFER_SIZE_BYTES: usize = BUFFER_SIZE_ELEMS * ELEM_SIZE; -const BUFFER_SIZE_ELEMS_SPILL: usize = BUFFER_SIZE_ELEMS + 1; -const BUFFER_SIZE_BYTES_SPILL: usize = BUFFER_SIZE_ELEMS_SPILL * ELEM_SIZE; -const BUFFER_SPILL_INDEX: usize = BUFFER_SIZE_ELEMS_SPILL - 1; + +// Size of the buffer in number of elements, not including the spill. +// +// The selection of this size was guided by rustc-perf benchmark comparisons of +// different buffer sizes. It should be periodically reevaluated as the compiler +// implementation and input characteristics change. +// +// Using the same-sized buffer for everything we hash is a performance versus +// complexity tradeoff. The ideal buffer size, and whether buffering should even +// be used, depends on what is being hashed. It may be worth it to size the +// buffer appropriately (perhaps by making SipHasher128 generic over the buffer +// size) or disable buffering depending on what is being hashed. But at this +// time, we use the same buffer size for everything. +const BUFFER_CAPACITY: usize = 8; + +// Size of the buffer in bytes, not including the spill. +const BUFFER_SIZE: usize = BUFFER_CAPACITY * ELEM_SIZE; + +// Size of the buffer in number of elements, including the spill. +const BUFFER_WITH_SPILL_CAPACITY: usize = BUFFER_CAPACITY + 1; + +// Size of the buffer in bytes, including the spill. +const BUFFER_WITH_SPILL_SIZE: usize = BUFFER_WITH_SPILL_CAPACITY * ELEM_SIZE; + +// Index of the spill element in the buffer. +const BUFFER_SPILL_INDEX: usize = BUFFER_WITH_SPILL_CAPACITY - 1; #[derive(Debug, Clone)] #[repr(C)] @@ -22,10 +44,10 @@ pub struct SipHasher128 { // `processed`, and then repetition of that pattern until hashing is done. // This is the basis for the ordering of fields below. However, in practice // the cache miss-rate for data access is extremely low regardless of order. - nbuf: usize, // how many bytes in buf are valid - buf: [MaybeUninit; BUFFER_SIZE_ELEMS_SPILL], // unprocessed bytes le - state: State, // hash State - processed: usize, // how many bytes we've processed + nbuf: usize, // how many bytes in buf are valid + buf: [MaybeUninit; BUFFER_WITH_SPILL_CAPACITY], // unprocessed bytes le + state: State, // hash State + processed: usize, // how many bytes we've processed } #[derive(Debug, Clone, Copy)] @@ -64,13 +86,18 @@ macro_rules! compress { // Copies up to 8 bytes from source to destination. This performs better than // `ptr::copy_nonoverlapping` on microbenchmarks and may perform better on real // workloads since all of the copies have fixed sizes and avoid calling memcpy. +// +// This is specifically designed for copies of up to 8 bytes, because that's the +// maximum of number bytes needed to fill an 8-byte-sized element on which +// SipHash operates. Note that for variable-sized copies which are known to be +// less than 8 bytes, this function will perform more work than necessary unless +// the compiler is able to optimize the extra work away. #[inline] unsafe fn copy_nonoverlapping_small(src: *const u8, dst: *mut u8, count: usize) { - const COUNT_MAX: usize = 8; - debug_assert!(count <= COUNT_MAX); + debug_assert!(count <= 8); - if count == COUNT_MAX { - ptr::copy_nonoverlapping(src, dst, COUNT_MAX); + if count == 8 { + ptr::copy_nonoverlapping(src, dst, 8); return; } @@ -116,10 +143,13 @@ unsafe fn copy_nonoverlapping_small(src: *const u8, dst: *mut u8, count: usize) // The buffer includes a "spill"--an extra element at the end--which simplifies // the integer write buffer processing path. The value that fills the buffer can // be written with a statically sized write that may spill over into the spill. -// After the buffer is processed, the part of the value that spilled over can +// After the buffer is processed, the part of the value that spilled over can be // written from the spill to the beginning of the buffer with another statically -// sized write. Due to static sizes, this scheme performs better than copying -// the exact number of bytes needed into the end and beginning of the buffer. +// sized write. This write may copy more bytes than actually spilled over, but +// we maintain the metadata such that any extra copied bytes will be ignored by +// subsequent processing. Due to the static sizes, this scheme performs better +// than copying the exact number of bytes needed into the end and beginning of +// the buffer. // // The buffer is uninitialized, which improves performance, but may preclude // efficient implementation of alternative approaches. The improvement is not so @@ -142,12 +172,12 @@ unsafe fn copy_nonoverlapping_small(src: *const u8, dst: *mut u8, count: usize) // // In order to make `SipHasher128` consistent with `SipHasher` in libstd, we // choose to do the integer to byte sequence conversion in the platform- -// dependent way. Clients can achieve (nearly) platform-independent hashing by -// widening `isize` and `usize` integers to 64 bits on 32-bit systems and -// byte-swapping integers on big-endian systems before passing them to the -// writing functions. This causes the input byte sequence to look identical on -// big- and little- endian systems (supposing `isize` and `usize` values can be -// represented in 32 bits), which ensures platform-independent results. +// dependent way. Clients can achieve platform-independent hashing by widening +// `isize` and `usize` integers to 64 bits on 32-bit systems and byte-swapping +// integers on big-endian systems before passing them to the writing functions. +// This causes the input byte sequence to look identical on big- and little- +// endian systems (supposing `isize` and `usize` values can be represented in 32 +// bits), which ensures platform-independent results. impl SipHasher128 { #[inline] pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher128 { @@ -178,10 +208,10 @@ impl SipHasher128 { let size = mem::size_of::(); let nbuf = self.nbuf; debug_assert!(size <= 8); - debug_assert!(nbuf < BUFFER_SIZE_BYTES); - debug_assert!(nbuf + size < BUFFER_SIZE_BYTES_SPILL); + debug_assert!(nbuf < BUFFER_SIZE); + debug_assert!(nbuf + size < BUFFER_WITH_SPILL_SIZE); - if nbuf + size < BUFFER_SIZE_BYTES { + if nbuf + size < BUFFER_SIZE { unsafe { // The memcpy call is optimized away because the size is known. let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); @@ -207,9 +237,9 @@ impl SipHasher128 { let size = mem::size_of::(); let nbuf = self.nbuf; debug_assert!(size <= 8); - debug_assert!(nbuf < BUFFER_SIZE_BYTES); - debug_assert!(nbuf + size >= BUFFER_SIZE_BYTES); - debug_assert!(nbuf + size < BUFFER_SIZE_BYTES_SPILL); + debug_assert!(nbuf < BUFFER_SIZE); + debug_assert!(nbuf + size >= BUFFER_SIZE); + debug_assert!(nbuf + size < BUFFER_WITH_SPILL_SIZE); // Copy first part of input into end of buffer, possibly into spill // element. The memcpy call is optimized away because the size is known. @@ -217,7 +247,7 @@ impl SipHasher128 { ptr::copy_nonoverlapping(&x as *const _ as *const u8, dst, size); // Process buffer. - for i in 0..BUFFER_SIZE_ELEMS { + for i in 0..BUFFER_CAPACITY { let elem = self.buf.get_unchecked(i).assume_init().to_le(); self.state.v3 ^= elem; Sip24Rounds::c_rounds(&mut self.state); @@ -234,8 +264,8 @@ impl SipHasher128 { // This function should only be called when the write fills the buffer. // Therefore, when size == 1, the new `self.nbuf` must be zero. The size // is statically known, so the branch is optimized away. - self.nbuf = if size == 1 { 0 } else { nbuf + size - BUFFER_SIZE_BYTES }; - self.processed += BUFFER_SIZE_BYTES; + self.nbuf = if size == 1 { 0 } else { nbuf + size - BUFFER_SIZE }; + self.processed += BUFFER_SIZE; } // A write function for byte slices. @@ -243,9 +273,9 @@ impl SipHasher128 { fn slice_write(&mut self, msg: &[u8]) { let length = msg.len(); let nbuf = self.nbuf; - debug_assert!(nbuf < BUFFER_SIZE_BYTES); + debug_assert!(nbuf < BUFFER_SIZE); - if nbuf + length < BUFFER_SIZE_BYTES { + if nbuf + length < BUFFER_SIZE { unsafe { let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); @@ -275,8 +305,8 @@ impl SipHasher128 { unsafe fn slice_write_process_buffer(&mut self, msg: &[u8]) { let length = msg.len(); let nbuf = self.nbuf; - debug_assert!(nbuf < BUFFER_SIZE_BYTES); - debug_assert!(nbuf + length >= BUFFER_SIZE_BYTES); + debug_assert!(nbuf < BUFFER_SIZE); + debug_assert!(nbuf + length >= BUFFER_SIZE); // Always copy first part of input into current element of buffer. // This function should only be called when the write fills the buffer, @@ -328,7 +358,7 @@ impl SipHasher128 { #[inline] pub fn finish128(mut self) -> (u64, u64) { - debug_assert!(self.nbuf < BUFFER_SIZE_BYTES); + debug_assert!(self.nbuf < BUFFER_SIZE); // Process full elements in buffer. let last = self.nbuf / ELEM_SIZE; diff --git a/compiler/rustc_data_structures/src/sip128/tests.rs b/compiler/rustc_data_structures/src/sip128/tests.rs index eda7ddc4f6d..5fe967c4158 100644 --- a/compiler/rustc_data_structures/src/sip128/tests.rs +++ b/compiler/rustc_data_structures/src/sip128/tests.rs @@ -456,12 +456,12 @@ macro_rules! test_fill_buffer { // Test filling and overfilling the buffer from all possible offsets // for a given integer type and its corresponding write method. const SIZE: usize = std::mem::size_of::<$type>(); - let input = [42; BUFFER_SIZE_BYTES]; + let input = [42; BUFFER_SIZE]; let x = 0x01234567_89ABCDEF_76543210_FEDCBA98_u128 as $type; let x_bytes = &x.to_ne_bytes(); for i in 1..=SIZE { - let s = &input[..BUFFER_SIZE_BYTES - i]; + let s = &input[..BUFFER_SIZE - i]; let mut h1 = SipHasher128::new_with_keys(7, 13); h1.write(s); From c8405d2251ce78651f591ed8a2189c41593f5110 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Oct 2020 09:18:15 +0200 Subject: [PATCH 118/446] fix markdown reference Co-authored-by: Dariusz Niedoba --- library/std/src/keyword_docs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index c76f9b923cd..a4bbb18da59 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -168,7 +168,7 @@ mod break_keyword {} /// [Rust Book]: /// ../book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants /// [Reference]: ../reference/items/constant-items.html -/// [cosnt-eval]: ./reference/const_eval.html +/// [const-eval]: ../reference/const_eval.html mod const_keyword {} #[doc(keyword = "continue")] From e3c3efe5abb2025fdc8a4937b22e76fbd8093dd5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 10 Oct 2020 15:31:14 +0200 Subject: [PATCH 119/446] Filter out imports added by the compiler --- src/librustdoc/clean/mod.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 501891da573..4bbf5edeaf3 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -24,9 +24,9 @@ use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::{self, AdtKind, Lift, Ty, TyCtxt}; use rustc_mir::const_eval::{is_const_fn, is_min_const_fn, is_unstable_const_fn}; -use rustc_span::hygiene::MacroKind; +use rustc_span::hygiene::{AstPass, MacroKind}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{self, Pos}; +use rustc_span::{self, ExpnKind, Pos}; use rustc_typeck::hir_ty_to_ty; use std::collections::hash_map::Entry; @@ -2232,6 +2232,13 @@ impl Clean> for doctree::ExternCrate<'_> { impl Clean> for doctree::Import<'_> { fn clean(&self, cx: &DocContext<'_>) -> Vec { + // We need this comparison because some imports (for std types for example) + // are "inserted" as well but directly by the compiler and they should not be + // taken into account. + if self.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::StdImports) { + return Vec::new(); + } + // We consider inlining the documentation of `pub use` statements, but we // forcefully don't inline if this is not public or if the // #[doc(no_inline)] attribute is present. From 0faaa499ccc9fb4835251845cf457bae385f07f5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 10 Oct 2020 15:34:18 +0200 Subject: [PATCH 120/446] Add test for compiler reexports removal --- src/test/rustdoc/no-compiler-reexport.rs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/test/rustdoc/no-compiler-reexport.rs diff --git a/src/test/rustdoc/no-compiler-reexport.rs b/src/test/rustdoc/no-compiler-reexport.rs new file mode 100644 index 00000000000..6d50325fed5 --- /dev/null +++ b/src/test/rustdoc/no-compiler-reexport.rs @@ -0,0 +1,7 @@ +// compile-flags: --no-defaults + +#![crate_name = "foo"] + +// @has 'foo/index.html' '//code' 'extern crate std;' +// @!has 'foo/index.html' '//code' 'use std::prelude::v1::*;' +pub struct Foo; From 07637db8836b2354241df91470886e228a7af87e Mon Sep 17 00:00:00 2001 From: Kornel Date: Mon, 12 Oct 2020 13:36:19 +0100 Subject: [PATCH 121/446] Remove deprecated unstable Vec::resize_default --- library/alloc/src/vec.rs | 44 ---------------------------------------- 1 file changed, 44 deletions(-) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 5e68f76693f..805e1085cf3 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -1603,50 +1603,6 @@ impl Vec { } } -impl Vec { - /// Resizes the `Vec` in-place so that `len` is equal to `new_len`. - /// - /// If `new_len` is greater than `len`, the `Vec` is extended by the - /// difference, with each additional slot filled with [`Default::default()`]. - /// If `new_len` is less than `len`, the `Vec` is simply truncated. - /// - /// This method uses [`Default`] to create new values on every push. If - /// you'd rather [`Clone`] a given value, use [`resize`]. - /// - /// # Examples - /// - /// ``` - /// # #![allow(deprecated)] - /// #![feature(vec_resize_default)] - /// - /// let mut vec = vec![1, 2, 3]; - /// vec.resize_default(5); - /// assert_eq!(vec, [1, 2, 3, 0, 0]); - /// - /// let mut vec = vec![1, 2, 3, 4]; - /// vec.resize_default(2); - /// assert_eq!(vec, [1, 2]); - /// ``` - /// - /// [`resize`]: Vec::resize - #[unstable(feature = "vec_resize_default", issue = "41758")] - #[rustc_deprecated( - reason = "This is moving towards being removed in favor \ - of `.resize_with(Default::default)`. If you disagree, please comment \ - in the tracking issue.", - since = "1.33.0" - )] - pub fn resize_default(&mut self, new_len: usize) { - let len = self.len(); - - if new_len > len { - self.extend_with(new_len - len, ExtendDefault); - } else { - self.truncate(new_len); - } - } -} - // This code generalizes `extend_with_{element,default}`. trait ExtendWith { fn next(&mut self) -> T; From 4b96049da2329ba6e9a7fd4cd8224417fb4baede Mon Sep 17 00:00:00 2001 From: Jacob Hughes Date: Mon, 12 Oct 2020 08:44:53 -0400 Subject: [PATCH 122/446] BTreeMap: refactor Entry out of map.rs into its own file btree/map.rs is approaching the 3000 line mark, splitting out the entry code buys about 500 lines of headroom --- library/alloc/src/collections/btree/map.rs | 473 +---------------- .../alloc/src/collections/btree/map/entry.rs | 475 ++++++++++++++++++ 2 files changed, 480 insertions(+), 468 deletions(-) create mode 100644 library/alloc/src/collections/btree/map/entry.rs diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 606bf94f998..92cbce96054 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -9,13 +9,16 @@ use core::ops::{Index, RangeBounds}; use core::ptr; use super::borrow::DormantMutRef; -use super::node::{self, marker, ForceResult::*, Handle, InsertResult::*, NodeRef}; +use super::node::{self, marker, ForceResult::*, Handle, NodeRef}; use super::search::{self, SearchResult::*}; use super::unwrap_unchecked; -use Entry::*; use UnderflowResult::*; +mod entry; +pub use entry::{Entry, OccupiedEntry, VacantEntry}; +use Entry::*; + /// A map based on a B-Tree. /// /// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing @@ -452,69 +455,6 @@ impl fmt::Debug for RangeMut<'_, K, V> { } } -/// A view into a single entry in a map, which may either be vacant or occupied. -/// -/// This `enum` is constructed from the [`entry`] method on [`BTreeMap`]. -/// -/// [`entry`]: BTreeMap::entry -#[stable(feature = "rust1", since = "1.0.0")] -pub enum Entry<'a, K: 'a, V: 'a> { - /// A vacant entry. - #[stable(feature = "rust1", since = "1.0.0")] - Vacant(#[stable(feature = "rust1", since = "1.0.0")] VacantEntry<'a, K, V>), - - /// An occupied entry. - #[stable(feature = "rust1", since = "1.0.0")] - Occupied(#[stable(feature = "rust1", since = "1.0.0")] OccupiedEntry<'a, K, V>), -} - -#[stable(feature = "debug_btree_map", since = "1.12.0")] -impl Debug for Entry<'_, K, V> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), - Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), - } - } -} - -/// A view into a vacant entry in a `BTreeMap`. -/// It is part of the [`Entry`] enum. -#[stable(feature = "rust1", since = "1.0.0")] -pub struct VacantEntry<'a, K: 'a, V: 'a> { - key: K, - handle: Handle, K, V, marker::Leaf>, marker::Edge>, - dormant_map: DormantMutRef<'a, BTreeMap>, - - // Be invariant in `K` and `V` - _marker: PhantomData<&'a mut (K, V)>, -} - -#[stable(feature = "debug_btree_map", since = "1.12.0")] -impl Debug for VacantEntry<'_, K, V> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("VacantEntry").field(self.key()).finish() - } -} - -/// A view into an occupied entry in a `BTreeMap`. -/// It is part of the [`Entry`] enum. -#[stable(feature = "rust1", since = "1.0.0")] -pub struct OccupiedEntry<'a, K: 'a, V: 'a> { - handle: Handle, K, V, marker::LeafOrInternal>, marker::KV>, - dormant_map: DormantMutRef<'a, BTreeMap>, - - // Be invariant in `K` and `V` - _marker: PhantomData<&'a mut (K, V)>, -} - -#[stable(feature = "debug_btree_map", since = "1.12.0")] -impl Debug for OccupiedEntry<'_, K, V> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("OccupiedEntry").field("key", self.key()).field("value", self.get()).finish() - } -} - // An iterator for merging two sorted sequences into one struct MergeIter> { left: Peekable, @@ -2310,409 +2250,6 @@ impl BTreeMap { } } -impl<'a, K: Ord, V> Entry<'a, K, V> { - /// Ensures a value is in the entry by inserting the default if empty, and returns - /// a mutable reference to the value in the entry. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// assert_eq!(map["poneyland"], 12); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn or_insert(self, default: V) -> &'a mut V { - match self { - Occupied(entry) => entry.into_mut(), - Vacant(entry) => entry.insert(default), - } - } - - /// Ensures a value is in the entry by inserting the result of the default function if empty, - /// and returns a mutable reference to the value in the entry. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, String> = BTreeMap::new(); - /// let s = "hoho".to_string(); - /// - /// map.entry("poneyland").or_insert_with(|| s); - /// - /// assert_eq!(map["poneyland"], "hoho".to_string()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn or_insert_with V>(self, default: F) -> &'a mut V { - match self { - Occupied(entry) => entry.into_mut(), - Vacant(entry) => entry.insert(default()), - } - } - - #[unstable(feature = "or_insert_with_key", issue = "71024")] - /// Ensures a value is in the entry by inserting, if empty, the result of the default function, - /// which takes the key as its argument, and returns a mutable reference to the value in the - /// entry. - /// - /// # Examples - /// - /// ``` - /// #![feature(or_insert_with_key)] - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// - /// map.entry("poneyland").or_insert_with_key(|key| key.chars().count()); - /// - /// assert_eq!(map["poneyland"], 9); - /// ``` - #[inline] - pub fn or_insert_with_key V>(self, default: F) -> &'a mut V { - match self { - Occupied(entry) => entry.into_mut(), - Vacant(entry) => { - let value = default(entry.key()); - entry.insert(value) - } - } - } - - /// Returns a reference to this entry's key. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); - /// ``` - #[stable(feature = "map_entry_keys", since = "1.10.0")] - pub fn key(&self) -> &K { - match *self { - Occupied(ref entry) => entry.key(), - Vacant(ref entry) => entry.key(), - } - } - - /// Provides in-place mutable access to an occupied entry before any - /// potential inserts into the map. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// - /// map.entry("poneyland") - /// .and_modify(|e| { *e += 1 }) - /// .or_insert(42); - /// assert_eq!(map["poneyland"], 42); - /// - /// map.entry("poneyland") - /// .and_modify(|e| { *e += 1 }) - /// .or_insert(42); - /// assert_eq!(map["poneyland"], 43); - /// ``` - #[stable(feature = "entry_and_modify", since = "1.26.0")] - pub fn and_modify(self, f: F) -> Self - where - F: FnOnce(&mut V), - { - match self { - Occupied(mut entry) => { - f(entry.get_mut()); - Occupied(entry) - } - Vacant(entry) => Vacant(entry), - } - } -} - -impl<'a, K: Ord, V: Default> Entry<'a, K, V> { - #[stable(feature = "entry_or_default", since = "1.28.0")] - /// Ensures a value is in the entry by inserting the default value if empty, - /// and returns a mutable reference to the value in the entry. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, Option> = BTreeMap::new(); - /// map.entry("poneyland").or_default(); - /// - /// assert_eq!(map["poneyland"], None); - /// ``` - pub fn or_default(self) -> &'a mut V { - match self { - Occupied(entry) => entry.into_mut(), - Vacant(entry) => entry.insert(Default::default()), - } - } -} - -impl<'a, K: Ord, V> VacantEntry<'a, K, V> { - /// Gets a reference to the key that would be used when inserting a value - /// through the VacantEntry. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); - /// ``` - #[stable(feature = "map_entry_keys", since = "1.10.0")] - pub fn key(&self) -> &K { - &self.key - } - - /// Take ownership of the key. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::collections::btree_map::Entry; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// - /// if let Entry::Vacant(v) = map.entry("poneyland") { - /// v.into_key(); - /// } - /// ``` - #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] - pub fn into_key(self) -> K { - self.key - } - - /// Sets the value of the entry with the `VacantEntry`'s key, - /// and returns a mutable reference to it. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::collections::btree_map::Entry; - /// - /// let mut map: BTreeMap<&str, u32> = BTreeMap::new(); - /// - /// if let Entry::Vacant(o) = map.entry("poneyland") { - /// o.insert(37); - /// } - /// assert_eq!(map["poneyland"], 37); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn insert(self, value: V) -> &'a mut V { - let out_ptr = match self.handle.insert_recursing(self.key, value) { - (Fit(_), val_ptr) => { - // Safety: We have consumed self.handle and the handle returned. - let map = unsafe { self.dormant_map.awaken() }; - map.length += 1; - val_ptr - } - (Split(ins), val_ptr) => { - drop(ins.left); - // Safety: We have consumed self.handle and the reference returned. - let map = unsafe { self.dormant_map.awaken() }; - let root = map.root.as_mut().unwrap(); - root.push_internal_level().push(ins.k, ins.v, ins.right); - map.length += 1; - val_ptr - } - }; - // Now that we have finished growing the tree using borrowed references, - // dereference the pointer to a part of it, that we picked up along the way. - unsafe { &mut *out_ptr } - } -} - -impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { - /// Gets a reference to the key in the entry. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); - /// ``` - #[stable(feature = "map_entry_keys", since = "1.10.0")] - pub fn key(&self) -> &K { - self.handle.reborrow().into_kv().0 - } - - /// Take ownership of the key and value from the map. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::collections::btree_map::Entry; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// if let Entry::Occupied(o) = map.entry("poneyland") { - /// // We delete the entry from the map. - /// o.remove_entry(); - /// } - /// - /// // If now try to get the value, it will panic: - /// // println!("{}", map["poneyland"]); - /// ``` - #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] - pub fn remove_entry(self) -> (K, V) { - self.remove_kv() - } - - /// Gets a reference to the value in the entry. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::collections::btree_map::Entry; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// if let Entry::Occupied(o) = map.entry("poneyland") { - /// assert_eq!(o.get(), &12); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get(&self) -> &V { - self.handle.reborrow().into_kv().1 - } - - /// Gets a mutable reference to the value in the entry. - /// - /// If you need a reference to the `OccupiedEntry` that may outlive the - /// destruction of the `Entry` value, see [`into_mut`]. - /// - /// [`into_mut`]: OccupiedEntry::into_mut - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::collections::btree_map::Entry; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// assert_eq!(map["poneyland"], 12); - /// if let Entry::Occupied(mut o) = map.entry("poneyland") { - /// *o.get_mut() += 10; - /// assert_eq!(*o.get(), 22); - /// - /// // We can use the same Entry multiple times. - /// *o.get_mut() += 2; - /// } - /// assert_eq!(map["poneyland"], 24); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self) -> &mut V { - self.handle.kv_mut().1 - } - - /// Converts the entry into a mutable reference to its value. - /// - /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. - /// - /// [`get_mut`]: OccupiedEntry::get_mut - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::collections::btree_map::Entry; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// assert_eq!(map["poneyland"], 12); - /// if let Entry::Occupied(o) = map.entry("poneyland") { - /// *o.into_mut() += 10; - /// } - /// assert_eq!(map["poneyland"], 22); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_mut(self) -> &'a mut V { - self.handle.into_val_mut() - } - - /// Sets the value of the entry with the `OccupiedEntry`'s key, - /// and returns the entry's old value. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::collections::btree_map::Entry; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// if let Entry::Occupied(mut o) = map.entry("poneyland") { - /// assert_eq!(o.insert(15), 12); - /// } - /// assert_eq!(map["poneyland"], 15); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn insert(&mut self, value: V) -> V { - mem::replace(self.get_mut(), value) - } - - /// Takes the value of the entry out of the map, and returns it. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::collections::btree_map::Entry; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// if let Entry::Occupied(o) = map.entry("poneyland") { - /// assert_eq!(o.remove(), 12); - /// } - /// // If we try to get "poneyland"'s value, it'll panic: - /// // println!("{}", map["poneyland"]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn remove(self) -> V { - self.remove_kv().1 - } - - // Body of `remove_entry`, separate to keep the above implementations short. - fn remove_kv(self) -> (K, V) { - let mut emptied_internal_root = false; - let (old_kv, _) = self.handle.remove_kv_tracking(|| emptied_internal_root = true); - // SAFETY: we consumed the intermediate root borrow, `self.handle`. - let map = unsafe { self.dormant_map.awaken() }; - map.length -= 1; - if emptied_internal_root { - let root = map.root.as_mut().unwrap(); - root.pop_internal_level(); - } - old_kv - } -} - impl<'a, K: 'a, V: 'a> Handle, K, V, marker::LeafOrInternal>, marker::KV> { /// Removes a key/value-pair from the map, and returns that pair, as well as /// the leaf edge corresponding to that former pair. diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs new file mode 100644 index 00000000000..73a0ca21f67 --- /dev/null +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -0,0 +1,475 @@ +use core::fmt::{self, Debug}; +use core::marker::PhantomData; +use core::mem; + +use super::super::borrow::DormantMutRef; +use super::super::node::{marker, Handle, InsertResult::*, NodeRef}; +use super::BTreeMap; + +use Entry::*; + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`BTreeMap`]. +/// +/// [`entry`]: BTreeMap::entry +#[stable(feature = "rust1", since = "1.0.0")] +pub enum Entry<'a, K: 'a, V: 'a> { + /// A vacant entry. + #[stable(feature = "rust1", since = "1.0.0")] + Vacant(#[stable(feature = "rust1", since = "1.0.0")] VacantEntry<'a, K, V>), + + /// An occupied entry. + #[stable(feature = "rust1", since = "1.0.0")] + Occupied(#[stable(feature = "rust1", since = "1.0.0")] OccupiedEntry<'a, K, V>), +} + +#[stable(feature = "debug_btree_map", since = "1.12.0")] +impl Debug for Entry<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +/// A view into a vacant entry in a `BTreeMap`. +/// It is part of the [`Entry`] enum. +#[stable(feature = "rust1", since = "1.0.0")] +pub struct VacantEntry<'a, K: 'a, V: 'a> { + pub(super) key: K, + pub(super) handle: Handle, K, V, marker::Leaf>, marker::Edge>, + pub(super) dormant_map: DormantMutRef<'a, BTreeMap>, + + // Be invariant in `K` and `V` + pub(super) _marker: PhantomData<&'a mut (K, V)>, +} + +#[stable(feature = "debug_btree_map", since = "1.12.0")] +impl Debug for VacantEntry<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.key()).finish() + } +} + +/// A view into an occupied entry in a `BTreeMap`. +/// It is part of the [`Entry`] enum. +#[stable(feature = "rust1", since = "1.0.0")] +pub struct OccupiedEntry<'a, K: 'a, V: 'a> { + pub(super) handle: Handle, K, V, marker::LeafOrInternal>, marker::KV>, + pub(super) dormant_map: DormantMutRef<'a, BTreeMap>, + + // Be invariant in `K` and `V` + pub(super) _marker: PhantomData<&'a mut (K, V)>, +} + +#[stable(feature = "debug_btree_map", since = "1.12.0")] +impl Debug for OccupiedEntry<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry").field("key", self.key()).field("value", self.get()).finish() + } +} + +impl<'a, K: Ord, V> Entry<'a, K, V> { + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn or_insert(self, default: V) -> &'a mut V { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, String> = BTreeMap::new(); + /// let s = "hoho".to_string(); + /// + /// map.entry("poneyland").or_insert_with(|| s); + /// + /// assert_eq!(map["poneyland"], "hoho".to_string()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn or_insert_with V>(self, default: F) -> &'a mut V { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(default()), + } + } + + #[unstable(feature = "or_insert_with_key", issue = "71024")] + /// Ensures a value is in the entry by inserting, if empty, the result of the default function, + /// which takes the key as its argument, and returns a mutable reference to the value in the + /// entry. + /// + /// # Examples + /// + /// ``` + /// #![feature(or_insert_with_key)] + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// + /// map.entry("poneyland").or_insert_with_key(|key| key.chars().count()); + /// + /// assert_eq!(map["poneyland"], 9); + /// ``` + #[inline] + pub fn or_insert_with_key V>(self, default: F) -> &'a mut V { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => { + let value = default(entry.key()); + entry.insert(value) + } + } + } + + /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` + #[stable(feature = "map_entry_keys", since = "1.10.0")] + pub fn key(&self) -> &K { + match *self { + Occupied(ref entry) => entry.key(), + Vacant(ref entry) => entry.key(), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// + /// map.entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[stable(feature = "entry_and_modify", since = "1.26.0")] + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut V), + { + match self { + Occupied(mut entry) => { + f(entry.get_mut()); + Occupied(entry) + } + Vacant(entry) => Vacant(entry), + } + } +} + +impl<'a, K: Ord, V: Default> Entry<'a, K, V> { + #[stable(feature = "entry_or_default", since = "1.28.0")] + /// Ensures a value is in the entry by inserting the default value if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, Option> = BTreeMap::new(); + /// map.entry("poneyland").or_default(); + /// + /// assert_eq!(map["poneyland"], None); + /// ``` + pub fn or_default(self) -> &'a mut V { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(Default::default()), + } + } +} + +impl<'a, K: Ord, V> VacantEntry<'a, K, V> { + /// Gets a reference to the key that would be used when inserting a value + /// through the VacantEntry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` + #[stable(feature = "map_entry_keys", since = "1.10.0")] + pub fn key(&self) -> &K { + &self.key + } + + /// Take ownership of the key. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// + /// if let Entry::Vacant(v) = map.entry("poneyland") { + /// v.into_key(); + /// } + /// ``` + #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] + pub fn into_key(self) -> K { + self.key + } + + /// Sets the value of the entry with the `VacantEntry`'s key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, u32> = BTreeMap::new(); + /// + /// if let Entry::Vacant(o) = map.entry("poneyland") { + /// o.insert(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn insert(self, value: V) -> &'a mut V { + let out_ptr = match self.handle.insert_recursing(self.key, value) { + (Fit(_), val_ptr) => { + // Safety: We have consumed self.handle and the handle returned. + let map = unsafe { self.dormant_map.awaken() }; + map.length += 1; + val_ptr + } + (Split(ins), val_ptr) => { + drop(ins.left); + // Safety: We have consumed self.handle and the reference returned. + let map = unsafe { self.dormant_map.awaken() }; + let root = map.root.as_mut().unwrap(); + root.push_internal_level().push(ins.k, ins.v, ins.right); + map.length += 1; + val_ptr + } + }; + // Now that we have finished growing the tree using borrowed references, + // dereference the pointer to a part of it, that we picked up along the way. + unsafe { &mut *out_ptr } + } +} + +impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { + /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` + #[stable(feature = "map_entry_keys", since = "1.10.0")] + pub fn key(&self) -> &K { + self.handle.reborrow().into_kv().0 + } + + /// Take ownership of the key and value from the map. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// // We delete the entry from the map. + /// o.remove_entry(); + /// } + /// + /// // If now try to get the value, it will panic: + /// // println!("{}", map["poneyland"]); + /// ``` + #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] + pub fn remove_entry(self) -> (K, V) { + self.remove_kv() + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.get(), &12); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get(&self) -> &V { + self.handle.reborrow().into_kv().1 + } + + /// Gets a mutable reference to the value in the entry. + /// + /// If you need a reference to the `OccupiedEntry` that may outlive the + /// destruction of the `Entry` value, see [`into_mut`]. + /// + /// [`into_mut`]: OccupiedEntry::into_mut + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// *o.get_mut() += 10; + /// assert_eq!(*o.get(), 22); + /// + /// // We can use the same Entry multiple times. + /// *o.get_mut() += 2; + /// } + /// assert_eq!(map["poneyland"], 24); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_mut(&mut self) -> &mut V { + self.handle.kv_mut().1 + } + + /// Converts the entry into a mutable reference to its value. + /// + /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: OccupiedEntry::get_mut + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// *o.into_mut() += 10; + /// } + /// assert_eq!(map["poneyland"], 22); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_mut(self) -> &'a mut V { + self.handle.into_val_mut() + } + + /// Sets the value of the entry with the `OccupiedEntry`'s key, + /// and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// assert_eq!(o.insert(15), 12); + /// } + /// assert_eq!(map["poneyland"], 15); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Takes the value of the entry out of the map, and returns it. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.remove(), 12); + /// } + /// // If we try to get "poneyland"'s value, it'll panic: + /// // println!("{}", map["poneyland"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn remove(self) -> V { + self.remove_kv().1 + } + + // Body of `remove_entry`, separate to keep the above implementations short. + pub(super) fn remove_kv(self) -> (K, V) { + let mut emptied_internal_root = false; + let (old_kv, _) = self.handle.remove_kv_tracking(|| emptied_internal_root = true); + // SAFETY: we consumed the intermediate root borrow, `self.handle`. + let map = unsafe { self.dormant_map.awaken() }; + map.length -= 1; + if emptied_internal_root { + let root = map.root.as_mut().unwrap(); + root.pop_internal_level(); + } + old_kv + } +} From 39b0e7928579c4ce3a42e849695f9380b7869d62 Mon Sep 17 00:00:00 2001 From: Julian Wollersberger Date: Mon, 12 Oct 2020 16:04:49 +0200 Subject: [PATCH 123/446] Remove generic argument from `QueryConfig`. --- compiler/rustc_middle/src/ty/query/plumbing.rs | 6 +++--- compiler/rustc_query_system/src/query/config.rs | 6 ++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_middle/src/ty/query/plumbing.rs b/compiler/rustc_middle/src/ty/query/plumbing.rs index f3fa3634026..76c7b8f1253 100644 --- a/compiler/rustc_middle/src/ty/query/plumbing.rs +++ b/compiler/rustc_middle/src/ty/query/plumbing.rs @@ -346,7 +346,7 @@ macro_rules! define_queries_inner { $(pub type $name<$tcx> = $V;)* } - $(impl<$tcx> QueryConfig> for queries::$name<$tcx> { + $(impl<$tcx> QueryConfig for queries::$name<$tcx> { type Key = $($K)*; type Value = $V; type Stored = < @@ -447,7 +447,7 @@ macro_rules! define_queries_inner { #[inline(always)] #[must_use] pub fn $name(self, key: query_helper_param_ty!($($K)*)) - -> as QueryConfig>>::Stored + -> as QueryConfig>::Stored { self.at(DUMMY_SP).$name(key.into_query_param()) })* @@ -486,7 +486,7 @@ macro_rules! define_queries_inner { $($(#[$attr])* #[inline(always)] pub fn $name(self, key: query_helper_param_ty!($($K)*)) - -> as QueryConfig>>::Stored + -> as QueryConfig>::Stored { get_query::, _>(self.tcx, self.span, key.into_query_param()) })* diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index 549056570f9..423b1fab143 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -12,9 +12,7 @@ use std::borrow::Cow; use std::fmt::Debug; use std::hash::Hash; -// The parameter `CTX` is required in librustc_middle: -// implementations may need to access the `'tcx` lifetime in `CTX = TyCtxt<'tcx>`. -pub trait QueryConfig { +pub trait QueryConfig { const NAME: &'static str; const CATEGORY: ProfileCategory; @@ -70,7 +68,7 @@ impl QueryVtable { } } -pub trait QueryAccessors: QueryConfig { +pub trait QueryAccessors: QueryConfig { const ANON: bool; const EVAL_ALWAYS: bool; const DEP_KIND: CTX::DepKind; From c5774f94efd60b60fc7120ba3d6de7f79b05681b Mon Sep 17 00:00:00 2001 From: Philipp Hansch Date: Mon, 12 Oct 2020 16:50:34 +0200 Subject: [PATCH 124/446] lintlist.rs: Replace lazy_static with once_cell Follow-up to https://github.com/rust-lang/rust-clippy/pull/6120 --- clippy_dev/src/update_lints.rs | 2 +- src/driver.rs | 1 + src/lintlist/mod.rs | 13 +++++++------ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index a9a70929942..556b67e0b37 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -29,7 +29,7 @@ pub fn run(update_mode: UpdateMode) { false, update_mode == UpdateMode::Change, || { - format!("pub static ref ALL_LINTS: Vec = vec!{:#?};", sorted_usable_lints) + format!("vec!{:#?}", sorted_usable_lints) .lines() .map(ToString::to_string) .collect::>() diff --git a/src/driver.rs b/src/driver.rs index 377f6d22446..c9b07855af1 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -1,4 +1,5 @@ #![feature(rustc_private)] +#![feature(once_cell)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] // warn on lints, that are included in `rust-lang/rust`s bootstrap #![warn(rust_2018_idioms, unused_lifetimes)] diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index d0fc8f0c8a9..624223ff706 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1,15 +1,16 @@ -//! This file is managed by `cargo dev update_lints`. Do not edit. +//! This file is managed by `cargo dev update_lints`. Do not edit or format this file. -use lazy_static::lazy_static; +use std::lazy::SyncLazy; pub mod lint; pub use lint::Level; pub use lint::Lint; pub use lint::LINT_LEVELS; -lazy_static! { +#[rustfmt::skip] +pub static ALL_LINTS: SyncLazy> = SyncLazy::new(|| { // begin lint list, do not remove this comment, it’s used in `update_lints` -pub static ref ALL_LINTS: Vec = vec![ +vec![ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -2831,6 +2832,6 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "methods", }, -]; +] // end lint list, do not remove this comment, it’s used in `update_lints` -} +}); From 098e4f119595cc199bf09ccf150aeefa6b2c49ac Mon Sep 17 00:00:00 2001 From: Philipp Hansch Date: Mon, 12 Oct 2020 18:29:29 +0200 Subject: [PATCH 125/446] driver.rs: Replace lazy_static with once_cell --- Cargo.toml | 2 -- src/driver.rs | 16 +++++++--------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c7a3099b8ab..13db35f4b0e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,13 +34,11 @@ clippy_lints = { version = "0.0.212", path = "clippy_lints" } semver = "0.10" rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util"} tempfile = { version = "3.1.0", optional = true } -lazy_static = "1.0" [dev-dependencies] cargo_metadata = "0.11.1" compiletest_rs = { version = "0.5.0", features = ["tmp"] } tester = "0.7" -lazy_static = "1.0" clippy-mini-macro-test = { version = "0.2", path = "mini-macro" } serde = { version = "1.0", features = ["derive"] } derive-new = "0.5" diff --git a/src/driver.rs b/src/driver.rs index c9b07855af1..e32ba116939 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -18,13 +18,13 @@ use rustc_interface::interface; use rustc_middle::ty::TyCtxt; use rustc_tools_util::VersionInfo; -use lazy_static::lazy_static; use std::borrow::Cow; use std::env; use std::ops::Deref; use std::panic; use std::path::{Path, PathBuf}; use std::process::{exit, Command}; +use std::lazy::SyncLazy; mod lintlist; @@ -231,13 +231,11 @@ You can use tool lints to allow or deny lints from your code, eg.: const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new"; -lazy_static! { - static ref ICE_HOOK: Box) + Sync + Send + 'static> = { - let hook = panic::take_hook(); - panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL))); - hook - }; -} +static ICE_HOOK: SyncLazy) + Sync + Send + 'static>> = SyncLazy::new(|| { + let hook = panic::take_hook(); + panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL))); + hook +}); fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { // Invoke our ICE handler, which prints the actual panic message and optionally a backtrace @@ -296,7 +294,7 @@ fn toolchain_path(home: Option, toolchain: Option) -> Option = env::args().collect(); From 7b3493c0e95e8cf9656d2cefffc621cb3e5eb726 Mon Sep 17 00:00:00 2001 From: Philipp Hansch Date: Mon, 12 Oct 2020 18:34:06 +0200 Subject: [PATCH 126/446] fmt --- src/driver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/driver.rs b/src/driver.rs index e32ba116939..e5d740cecd3 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -20,11 +20,11 @@ use rustc_tools_util::VersionInfo; use std::borrow::Cow; use std::env; +use std::lazy::SyncLazy; use std::ops::Deref; use std::panic; use std::path::{Path, PathBuf}; use std::process::{exit, Command}; -use std::lazy::SyncLazy; mod lintlist; From 104c0f0194177442ff16cf14907a96d2f8d200dd Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 12 Oct 2020 20:00:44 +0200 Subject: [PATCH 127/446] Rename Pin::new_static to Pin::static_ref. --- library/core/src/pin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 3f058124d2b..9e2d64a866f 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -788,7 +788,7 @@ impl Pin<&'static T> { /// never be moved. #[unstable(feature = "pin_static_ref", issue = "none")] #[rustc_const_unstable(feature = "const_pin", issue = "76654")] - pub const fn new_static(r: &'static T) -> Pin<&'static T> { + pub const fn static_ref(r: &'static T) -> Pin<&'static T> { // SAFETY: The 'static lifetime guarantees the data will not be // moved/invalidated until it gets dropped (which is never). unsafe { Pin::new_unchecked(r) } From 2c71f682d74d13ae6673dc701a9bb3a0562f57c0 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 12 Oct 2020 20:00:56 +0200 Subject: [PATCH 128/446] Add Pin::static_mut. --- library/core/src/pin.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 9e2d64a866f..b27167a7e7c 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -795,6 +795,20 @@ impl Pin<&'static T> { } } +impl Pin<&'static T> { + /// Get a pinned mutable reference from a static mutable reference. + /// + /// This is safe, because the `'static` lifetime guarantees the data will + /// never be moved. + #[unstable(feature = "pin_static_ref", issue = "none")] + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + pub const fn static_mut(r: &'static mut T) -> Pin<&'static mut T> { + // SAFETY: The 'static lifetime guarantees the data will not be + // moved/invalidated until it gets dropped (which is never). + unsafe { Pin::new_unchecked(r) } + } +} + #[stable(feature = "pin", since = "1.33.0")] impl Deref for Pin

{ type Target = P::Target; From 32fdb8fb0c15ddc202eed70b82babca8d529e39b Mon Sep 17 00:00:00 2001 From: ThibsG Date: Thu, 8 Oct 2020 23:02:16 +0200 Subject: [PATCH 129/446] Lint on identical variable used as args in `assert_eq!` macro call --- clippy_lints/src/eq_op.rs | 37 ++++++++++++++++++++++++- clippy_lints/src/lib.rs | 2 ++ tests/ui/auxiliary/proc_macro_derive.rs | 1 + tests/ui/double_parens.rs | 2 +- tests/ui/eq_op_early.rs | 15 ++++++++++ tests/ui/eq_op_early.stderr | 16 +++++++++++ tests/ui/used_underscore_binding.rs | 2 +- 7 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 tests/ui/eq_op_early.rs create mode 100644 tests/ui/eq_op_early.stderr diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index e16ec783fab..7126c98a0b4 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -1,9 +1,13 @@ +use crate::utils::ast_utils::eq_expr; use crate::utils::{ eq_expr_value, implements_trait, in_macro, is_copy, multispan_sugg, snippet, span_lint, span_lint_and_then, }; +use if_chain::if_chain; +use rustc_ast::{ast, token}; use rustc_errors::Applicability; use rustc_hir::{BinOp, BinOpKind, BorrowKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; +use rustc_parse::parser; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -23,6 +27,12 @@ declare_clippy_lint! { /// # let x = 1; /// if x + 1 == x + 1 {} /// ``` + /// or + /// ```rust + /// # let a = 3; + /// # let b = 4; + /// assert_eq!(a, a); + /// ``` pub EQ_OP, correctness, "equal operands on both sides of a comparison or bitwise combination (e.g., `x == x`)" @@ -52,6 +62,31 @@ declare_clippy_lint! { declare_lint_pass!(EqOp => [EQ_OP, OP_REF]); +impl EarlyLintPass for EqOp { + fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) { + if_chain! { + if mac.path == sym!(assert_eq); + let tokens = mac.args.inner_tokens(); + let mut parser = parser::Parser::new(&cx.sess.parse_sess, tokens, false, None); + if let Ok(left) = parser.parse_expr(); + if parser.eat(&token::Comma); + if let Ok(right) = parser.parse_expr(); + let left_expr = left.into_inner(); + let right_expr = right.into_inner(); + if eq_expr(&left_expr, &right_expr); + + then { + span_lint( + cx, + EQ_OP, + left_expr.span.to(right_expr.span), + "identical args used in this `assert_eq!` macro call", + ); + } + } + } +} + impl<'tcx> LateLintPass<'tcx> for EqOp { #[allow(clippy::similar_names, clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index fc4afde9d9e..dd99b6b9040 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -348,6 +348,7 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore) { store.register_pre_expansion_pass(|| box write::Write::default()); store.register_pre_expansion_pass(|| box attrs::EarlyAttributes); store.register_pre_expansion_pass(|| box dbg_macro::DbgMacro); + store.register_pre_expansion_pass(|| box eq_op::EqOp); } #[doc(hidden)] @@ -910,6 +911,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: let vec_box_size_threshold = conf.vec_box_size_threshold; store.register_late_pass(move || box types::Types::new(vec_box_size_threshold)); store.register_late_pass(|| box booleans::NonminimalBool); + store.register_early_pass(|| box eq_op::EqOp); store.register_late_pass(|| box eq_op::EqOp); store.register_late_pass(|| box enum_clike::UnportableVariant); store.register_late_pass(|| box float_literal::FloatLiteral); diff --git a/tests/ui/auxiliary/proc_macro_derive.rs b/tests/ui/auxiliary/proc_macro_derive.rs index 3df8be6c232..e369f62f8bf 100644 --- a/tests/ui/auxiliary/proc_macro_derive.rs +++ b/tests/ui/auxiliary/proc_macro_derive.rs @@ -3,6 +3,7 @@ #![crate_type = "proc-macro"] #![feature(repr128, proc_macro_quote)] +#![allow(clippy::eq_op)] extern crate proc_macro; diff --git a/tests/ui/double_parens.rs b/tests/ui/double_parens.rs index 9c7590c7dd6..ff1dc76ab63 100644 --- a/tests/ui/double_parens.rs +++ b/tests/ui/double_parens.rs @@ -1,5 +1,5 @@ #![warn(clippy::double_parens)] -#![allow(dead_code)] +#![allow(dead_code, clippy::eq_op)] #![feature(custom_inner_attributes)] #![rustfmt::skip] diff --git a/tests/ui/eq_op_early.rs b/tests/ui/eq_op_early.rs new file mode 100644 index 00000000000..cf5660ea98d --- /dev/null +++ b/tests/ui/eq_op_early.rs @@ -0,0 +1,15 @@ +#![warn(clippy::eq_op)] + +fn main() { + let a = 1; + let b = 2; + + // lint identical args in `assert_eq!` (see #3574) + assert_eq!(a, a); + assert_eq!(a + 1, a + 1); + + // ok + assert_eq!(a, b); + assert_eq!(a, a + 1); + assert_eq!(a + 1, b + 1); +} diff --git a/tests/ui/eq_op_early.stderr b/tests/ui/eq_op_early.stderr new file mode 100644 index 00000000000..9206e9026e9 --- /dev/null +++ b/tests/ui/eq_op_early.stderr @@ -0,0 +1,16 @@ +error: identical args used in this `assert_eq!` macro call + --> $DIR/eq_op_early.rs:8:16 + | +LL | assert_eq!(a, a); + | ^^^^ + | + = note: `-D clippy::eq-op` implied by `-D warnings` + +error: identical args used in this `assert_eq!` macro call + --> $DIR/eq_op_early.rs:9:16 + | +LL | assert_eq!(a + 1, a + 1); + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/used_underscore_binding.rs b/tests/ui/used_underscore_binding.rs index 8e0243c49aa..d8bda7e8f48 100644 --- a/tests/ui/used_underscore_binding.rs +++ b/tests/ui/used_underscore_binding.rs @@ -3,7 +3,7 @@ #![feature(rustc_private)] #![warn(clippy::all)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::blacklisted_name, clippy::eq_op)] #![warn(clippy::used_underscore_binding)] #[macro_use] From 5573a163530f12a38a865b67eb7994414e9cd49c Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 3 Sep 2020 17:11:02 -0700 Subject: [PATCH 130/446] Use `try{}` in `try_fold` to decouple library from `Try` details --- library/core/src/iter/adapters/chain.rs | 4 +-- library/core/src/iter/adapters/flatten.rs | 4 +-- library/core/src/iter/adapters/fuse.rs | 4 +-- library/core/src/iter/adapters/mod.rs | 36 ++++++++++---------- library/core/src/iter/range.rs | 8 ++--- library/core/src/iter/traits/double_ended.rs | 2 +- library/core/src/iter/traits/iterator.rs | 2 +- library/core/src/lib.rs | 1 + 8 files changed, 31 insertions(+), 30 deletions(-) diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs index 38fb74372db..2e070d71224 100644 --- a/library/core/src/iter/adapters/chain.rs +++ b/library/core/src/iter/adapters/chain.rs @@ -109,7 +109,7 @@ where acc = b.try_fold(acc, f)?; // we don't fuse the second iterator } - Try::from_ok(acc) + try { acc } } fn fold(self, mut acc: Acc, mut f: F) -> Acc @@ -292,7 +292,7 @@ where acc = a.try_rfold(acc, f)?; // we don't fuse the second iterator } - Try::from_ok(acc) + try { acc } } fn rfold(self, mut acc: Acc, mut f: F) -> Acc diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index ddb1aaebc1f..35adb4f69d8 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -317,7 +317,7 @@ where } self.backiter = None; - Try::from_ok(init) + try { init } } #[inline] @@ -397,7 +397,7 @@ where } self.frontiter = None; - Try::from_ok(init) + try { init } } #[inline] diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index a78da369c24..60ac3524e66 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -303,7 +303,7 @@ where acc = iter.try_fold(acc, fold)?; self.iter = None; } - Try::from_ok(acc) + try { acc } } #[inline] @@ -353,7 +353,7 @@ where acc = iter.try_rfold(acc, fold)?; self.iter = None; } - Try::from_ok(acc) + try { acc } } #[inline] diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 1e520b62f77..ba66ba2912f 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -579,7 +579,7 @@ where })?; if is_empty { - return Try::from_ok(acc); + return try { acc }; } loop { @@ -715,7 +715,7 @@ where if self.first_take { self.first_take = false; match self.iter.next() { - None => return Try::from_ok(acc), + None => return try { acc }, Some(x) => acc = f(acc, x)?, } } @@ -792,7 +792,7 @@ where } match self.next_back() { - None => Try::from_ok(init), + None => try { init }, Some(x) => { let acc = f(init, x)?; from_fn(nth_back(&mut self.iter, self.step)).try_fold(acc, f) @@ -1075,7 +1075,7 @@ fn filter_try_fold<'a, T, Acc, R: Try>( predicate: &'a mut impl FnMut(&T) -> bool, mut fold: impl FnMut(Acc, T) -> R + 'a, ) -> impl FnMut(Acc, T) -> R + 'a { - move |acc, item| if predicate(&item) { fold(acc, item) } else { R::from_ok(acc) } + move |acc, item| if predicate(&item) { fold(acc, item) } else { try { acc } } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1229,7 +1229,7 @@ fn filter_map_try_fold<'a, T, B, Acc, R: Try>( ) -> impl FnMut(Acc, T) -> R + 'a { move |acc, item| match f(item) { Some(x) => fold(acc, x), - None => R::from_ok(acc), + None => try { acc }, } } @@ -1660,7 +1660,7 @@ impl Iterator for Peekable { R: Try, { let acc = match self.peeked.take() { - Some(None) => return Try::from_ok(init), + Some(None) => return try { init }, Some(Some(v)) => f(init, v)?, None => init, }; @@ -1703,7 +1703,7 @@ where R: Try, { match self.peeked.take() { - Some(None) => Try::from_ok(init), + Some(None) => try { init }, Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() { Ok(acc) => f(acc, v), Err(e) => { @@ -1938,7 +1938,7 @@ where if !self.flag { match self.next() { Some(v) => init = fold(init, v)?, - None => return Try::from_ok(init), + None => return try { init }, } } self.iter.try_fold(init, fold) @@ -2065,13 +2065,13 @@ where ControlFlow::from_try(fold(acc, x)) } else { *flag = true; - ControlFlow::Break(Try::from_ok(acc)) + ControlFlow::Break(try { acc }) } } } if self.flag { - Try::from_ok(init) + try { init } } else { let flag = &mut self.flag; let p = &mut self.predicate; @@ -2180,7 +2180,7 @@ where let Self { iter, predicate } = self; iter.try_fold(init, |acc, x| match predicate(x) { Some(item) => ControlFlow::from_try(fold(acc, item)), - None => ControlFlow::Break(Try::from_ok(acc)), + None => ControlFlow::Break(try { acc }), }) .into_try() } @@ -2316,7 +2316,7 @@ where if n > 0 { // nth(n) skips n+1 if self.iter.nth(n - 1).is_none() { - return Try::from_ok(init); + return try { init }; } } self.iter.try_fold(init, fold) @@ -2382,7 +2382,7 @@ where let n = self.len(); if n == 0 { - Try::from_ok(init) + try { init } } else { self.iter.try_rfold(init, check(n, fold)).into_try() } @@ -2509,7 +2509,7 @@ where } if self.n == 0 { - Try::from_ok(init) + try { init } } else { let n = &mut self.n; self.iter.try_fold(init, check(n, fold)).into_try() @@ -2587,11 +2587,11 @@ where R: Try, { if self.n == 0 { - Try::from_ok(init) + try { init } } else { let len = self.iter.len(); if len > self.n && self.iter.nth_back(len - self.n - 1).is_none() { - Try::from_ok(init) + try { init } } else { self.iter.try_rfold(init, fold) } @@ -2687,7 +2687,7 @@ where mut fold: impl FnMut(Acc, B) -> R + 'a, ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { move |acc, x| match f(state, x) { - None => ControlFlow::Break(Try::from_ok(acc)), + None => ControlFlow::Break(try { acc }), Some(x) => ControlFlow::from_try(fold(acc, x)), } } @@ -2951,7 +2951,7 @@ where Ok(x) => ControlFlow::from_try(f(acc, x)), Err(e) => { *error = Err(e); - ControlFlow::Break(Try::from_ok(acc)) + ControlFlow::Break(try { acc }) } }) .into_try() diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 9f34aee1947..cd8ab11cb84 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -713,7 +713,7 @@ impl Iterator for ops::RangeInclusive { R: Try, { if self.is_empty() { - return Try::from_ok(init); + return try { init }; } let mut accum = init; @@ -731,7 +731,7 @@ impl Iterator for ops::RangeInclusive { accum = f(accum, self.start.clone())?; } - Try::from_ok(accum) + try { accum } } #[inline] @@ -818,7 +818,7 @@ impl DoubleEndedIterator for ops::RangeInclusive { R: Try, { if self.is_empty() { - return Try::from_ok(init); + return try { init }; } let mut accum = init; @@ -836,7 +836,7 @@ impl DoubleEndedIterator for ops::RangeInclusive { accum = f(accum, self.start.clone())?; } - Try::from_ok(accum) + try { accum } } #[inline] diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index 16bee0e2eee..465b427624d 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -221,7 +221,7 @@ pub trait DoubleEndedIterator: Iterator { while let Some(x) = self.next_back() { accum = f(accum, x)?; } - Try::from_ok(accum) + try { accum } } /// An iterator method that reduces the iterator's elements to a single, diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 813afcc0ec6..de671ec13d1 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1887,7 +1887,7 @@ pub trait Iterator { while let Some(x) = self.next() { accum = f(accum, x)?; } - Try::from_ok(accum) + try { accum } } /// An iterator method that applies a fallible function to each item in the diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index c9a80b5bc77..ff2696bb0a4 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -127,6 +127,7 @@ #![feature(std_internals)] #![feature(stmt_expr_attributes)] #![feature(transparent_unions)] +#![feature(try_blocks)] #![feature(unboxed_closures)] #![feature(unsized_locals)] #![feature(untagged_unions)] From 8c28ba39b573c0d9be2ce7aa3cfc60757f3c81e6 Mon Sep 17 00:00:00 2001 From: Chris Ayoup Date: Mon, 12 Oct 2020 21:51:05 -0400 Subject: [PATCH 131/446] suggest a compatible shell for running setup-toolchain.sh setup-toolchain.sh uses "[[" which is a bash builtin, but the guide suggests running it with sh. On Ubuntu, /bin/sh points to dash and running the script as described fails. --- doc/basics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/basics.md b/doc/basics.md index 38959e2331b..f25edb793e2 100644 --- a/doc/basics.md +++ b/doc/basics.md @@ -46,7 +46,7 @@ this toolchain, you can just use the `setup-toolchain.sh` script or use `rustup-toolchain-install-master`: ```bash -sh setup-toolchain.sh +bash setup-toolchain.sh # OR cargo install rustup-toolchain-install-master # For better IDE integration also add `-c rustfmt -c rust-src` (optional) From a3e0446afe0ebd7a420f65cd6aec1c56687f0ef5 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 13 Oct 2020 09:31:53 +0200 Subject: [PATCH 132/446] Extend to the `assert` macro family --- clippy_lints/src/eq_op.rs | 17 ++++++++++++++--- tests/ui/eq_op_early.rs | 25 +++++++++++++++++++++++- tests/ui/eq_op_early.stderr | 38 ++++++++++++++++++++++++++++++++++++- 3 files changed, 75 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 7126c98a0b4..a95d71042ee 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -7,6 +7,7 @@ use rustc_ast::{ast, token}; use rustc_errors::Applicability; use rustc_hir::{BinOp, BinOpKind, BorrowKind, Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; +use rustc_middle::lint::in_external_macro; use rustc_parse::parser; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -64,10 +65,20 @@ declare_lint_pass!(EqOp => [EQ_OP, OP_REF]); impl EarlyLintPass for EqOp { fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) { + let macro_list = [ + sym!(assert_eq), + sym!(assert_ne), + sym!(debug_assert_eq), + sym!(debug_assert_ne), + ]; if_chain! { - if mac.path == sym!(assert_eq); + if !in_external_macro(cx.sess, mac.span()); + if mac.path.segments.len() == 1; + let macro_name = mac.path.segments[0].ident.name; + if macro_list.contains(¯o_name); let tokens = mac.args.inner_tokens(); - let mut parser = parser::Parser::new(&cx.sess.parse_sess, tokens, false, None); + let mut parser = parser::Parser::new( + &cx.sess.parse_sess, tokens, false, None); if let Ok(left) = parser.parse_expr(); if parser.eat(&token::Comma); if let Ok(right) = parser.parse_expr(); @@ -80,7 +91,7 @@ impl EarlyLintPass for EqOp { cx, EQ_OP, left_expr.span.to(right_expr.span), - "identical args used in this `assert_eq!` macro call", + &format!("identical args used in this `{}!` macro call", macro_name), ); } } diff --git a/tests/ui/eq_op_early.rs b/tests/ui/eq_op_early.rs index cf5660ea98d..25e1c6ac6b7 100644 --- a/tests/ui/eq_op_early.rs +++ b/tests/ui/eq_op_early.rs @@ -7,9 +7,32 @@ fn main() { // lint identical args in `assert_eq!` (see #3574) assert_eq!(a, a); assert_eq!(a + 1, a + 1); - // ok assert_eq!(a, b); assert_eq!(a, a + 1); assert_eq!(a + 1, b + 1); + + // lint identical args in `assert_ne!` + assert_ne!(a, a); + assert_ne!(a + 1, a + 1); + // ok + assert_ne!(a, b); + assert_ne!(a, a + 1); + assert_ne!(a + 1, b + 1); + + // lint identical args in `debug_assert_eq!` + debug_assert_eq!(a, a); + debug_assert_eq!(a + 1, a + 1); + // ok + debug_assert_eq!(a, b); + debug_assert_eq!(a, a + 1); + debug_assert_eq!(a + 1, b + 1); + + // lint identical args in `debug_assert_ne!` + debug_assert_ne!(a, a); + debug_assert_ne!(a + 1, a + 1); + // ok + debug_assert_ne!(a, b); + debug_assert_ne!(a, a + 1); + debug_assert_ne!(a + 1, b + 1); } diff --git a/tests/ui/eq_op_early.stderr b/tests/ui/eq_op_early.stderr index 9206e9026e9..1df094fae18 100644 --- a/tests/ui/eq_op_early.stderr +++ b/tests/ui/eq_op_early.stderr @@ -12,5 +12,41 @@ error: identical args used in this `assert_eq!` macro call LL | assert_eq!(a + 1, a + 1); | ^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: identical args used in this `assert_ne!` macro call + --> $DIR/eq_op_early.rs:16:16 + | +LL | assert_ne!(a, a); + | ^^^^ + +error: identical args used in this `assert_ne!` macro call + --> $DIR/eq_op_early.rs:17:16 + | +LL | assert_ne!(a + 1, a + 1); + | ^^^^^^^^^^^^ + +error: identical args used in this `debug_assert_eq!` macro call + --> $DIR/eq_op_early.rs:24:22 + | +LL | debug_assert_eq!(a, a); + | ^^^^ + +error: identical args used in this `debug_assert_eq!` macro call + --> $DIR/eq_op_early.rs:25:22 + | +LL | debug_assert_eq!(a + 1, a + 1); + | ^^^^^^^^^^^^ + +error: identical args used in this `debug_assert_ne!` macro call + --> $DIR/eq_op_early.rs:32:22 + | +LL | debug_assert_ne!(a, a); + | ^^^^ + +error: identical args used in this `debug_assert_ne!` macro call + --> $DIR/eq_op_early.rs:33:22 + | +LL | debug_assert_ne!(a + 1, a + 1); + | ^^^^^^^^^^^^ + +error: aborting due to 8 previous errors From 0c32e811577fbf2ff46a607897f9ea7b6b95b364 Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Tue, 13 Oct 2020 08:30:11 +0100 Subject: [PATCH 133/446] Fixing escaping to ensure generation of welformed json. --- library/test/src/formatters/json.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/library/test/src/formatters/json.rs b/library/test/src/formatters/json.rs index 9ebc991d638..cfb06827be4 100644 --- a/library/test/src/formatters/json.rs +++ b/library/test/src/formatters/json.rs @@ -39,9 +39,12 @@ impl JsonFormatter { stdout: Option>, extra: Option<&str>, ) -> io::Result<()> { + // A doc test's name includes a filename which must be escaped for correct json. self.write_message(&*format!( r#"{{ "type": "{}", "name": "{}", "event": "{}""#, - ty, name, evt + ty, + EscapedString(name), + evt ))?; if let Some(exec_time) = exec_time { self.write_message(&*format!(r#", "exec_time": "{}""#, exec_time))?; @@ -67,7 +70,7 @@ impl OutputFormatter for JsonFormatter { fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> { self.writeln_message(&*format!( r#"{{ "type": "test", "event": "started", "name": "{}" }}"#, - desc.name + EscapedString(desc.name.as_slice()) )) } @@ -140,7 +143,10 @@ impl OutputFormatter for JsonFormatter { \"name\": \"{}\", \ \"median\": {}, \ \"deviation\": {}{} }}", - desc.name, median, deviation, mbps + EscapedString(desc.name.as_slice()), + median, + deviation, + mbps ); self.writeln_message(&*line) @@ -151,7 +157,7 @@ impl OutputFormatter for JsonFormatter { fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> { self.writeln_message(&*format!( r#"{{ "type": "test", "event": "timeout", "name": "{}" }}"#, - desc.name + EscapedString(desc.name.as_slice()) )) } From 45f67625291af6432c42b99a3b68b2b77fb8ad9c Mon Sep 17 00:00:00 2001 From: nasso Date: Sun, 11 Oct 2020 02:53:37 +0200 Subject: [PATCH 134/446] Add a setting to use the system theme --- src/librustdoc/html/render/mod.rs | 103 ++++++++++++++++++++---- src/librustdoc/html/static/settings.css | 40 ++++++++- src/librustdoc/html/static/settings.js | 55 +++++++++---- src/librustdoc/html/static/storage.js | 72 +++++++++++++++-- 4 files changed, 233 insertions(+), 37 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 76334f0213d..a9d4c2cc813 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -575,7 +575,8 @@ impl FormatRenderer for Context { settings( self.shared.static_root_path.as_deref().unwrap_or("./"), &self.shared.resource_suffix, - ), + &self.shared.style_files, + )?, &style_files, ); self.shared.fs.write(&settings_file, v.as_bytes())?; @@ -810,6 +811,7 @@ themePicker.onblur = handleThemeButtonsBlur; but.textContent = item; but.onclick = function(el) {{ switchTheme(currentTheme, mainTheme, item, true); + useSystemTheme(false); }}; but.onblur = handleThemeButtonsBlur; themes.appendChild(but); @@ -1343,12 +1345,25 @@ impl AllTypes { #[derive(Debug)] enum Setting { - Section { description: &'static str, sub_settings: Vec }, - Entry { js_data_name: &'static str, description: &'static str, default_value: bool }, + Section { + description: &'static str, + sub_settings: Vec, + }, + Toggle { + js_data_name: &'static str, + description: &'static str, + default_value: bool, + }, + Select { + js_data_name: &'static str, + description: &'static str, + default_value: &'static str, + options: Vec<(String, String)>, + }, } impl Setting { - fn display(&self) -> String { + fn display(&self, root_path: &str, suffix: &str) -> String { match *self { Setting::Section { ref description, ref sub_settings } => format!( "

", description, - sub_settings.iter().map(|s| s.display()).collect::() + sub_settings.iter().map(|s| s.display(root_path, suffix)).collect::() ), - Setting::Entry { ref js_data_name, ref description, ref default_value } => format!( + Setting::Toggle { ref js_data_name, ref description, ref default_value } => format!( "
\
\
{}
\
{}
@@ -1373,7 +1373,7 @@ impl Setting { description, sub_settings.iter().map(|s| s.display(root_path, suffix)).collect::() ), - Setting::Toggle { ref js_data_name, ref description, ref default_value } => format!( + Setting::Toggle { js_data_name, description, default_value } => format!( "
\
", js_data_name, - if *default_value { " checked" } else { "" }, + if default_value { " checked" } else { "" }, description, ), - Setting::Select { - ref js_data_name, - ref description, - ref default_value, - ref options, - } => format!( + Setting::Select { js_data_name, description, default_value, ref options } => format!( "
\
{}
\
\ + "
\
{}
\ -
", description, diff --git a/src/librustdoc/html/static/settings.css b/src/librustdoc/html/static/settings.css index 7c91f6b7d18..4bacd7b245b 100644 --- a/src/librustdoc/html/static/settings.css +++ b/src/librustdoc/html/static/settings.css @@ -31,9 +31,7 @@ .select-wrapper { float: right; - position: relative; - height: 27px; min-width: 25%; } @@ -42,23 +40,18 @@ appearance: none; -moz-appearance: none; -webkit-appearance: none; - background: none; border: 2px solid #ccc; padding-right: 28px; - width: 100%; } .select-wrapper img { pointer-events: none; - position: absolute; right: 0; bottom: 0; - background: #ccc; - height: 100%; width: 28px; padding: 0px 4px; diff --git a/src/librustdoc/html/static/settings.js b/src/librustdoc/html/static/settings.js index 67dc77330ee..00a01ac30bc 100644 --- a/src/librustdoc/html/static/settings.js +++ b/src/librustdoc/html/static/settings.js @@ -1,21 +1,21 @@ // Local js definitions: -/* global getCurrentValue, updateLocalStorage */ +/* global getCurrentValue, updateLocalStorage, updateSystemTheme */ (function () { function changeSetting(settingName, value) { - updateLocalStorage('rustdoc-' + settingName, value); + updateLocalStorage("rustdoc-" + settingName, value); switch (settingName) { - case 'preferred-dark-theme': - case 'preferred-light-theme': - case 'use-system-theme': + case "preferred-dark-theme": + case "preferred-light-theme": + case "use-system-theme": updateSystemTheme(); break; } } function getSettingValue(settingName) { - return getCurrentValue('rustdoc-' + settingName); + return getCurrentValue("rustdoc-" + settingName); } function setEvents() { @@ -23,9 +23,10 @@ toggles: document.getElementsByClassName("slider"), selects: document.getElementsByClassName("select-wrapper") }; + var i; if (elems.toggles && elems.toggles.length > 0) { - for (var i = 0; i < elems.toggles.length; ++i) { + for (i = 0; i < elems.toggles.length; ++i) { var toggle = elems.toggles[i].previousElementSibling; var settingId = toggle.id; var settingValue = getSettingValue(settingId); @@ -39,8 +40,8 @@ } if (elems.selects && elems.selects.length > 0) { - for (var i = 0; i < elems.selects.length; ++i) { - var select = elems.selects[i].getElementsByTagName('select')[0]; + for (i = 0; i < elems.selects.length; ++i) { + var select = elems.selects[i].getElementsByTagName("select")[0]; var settingId = select.id; var settingValue = getSettingValue(settingId); if (settingValue !== null) { diff --git a/src/librustdoc/html/static/storage.js b/src/librustdoc/html/static/storage.js index 3ee693d6eac..cf8b806501f 100644 --- a/src/librustdoc/html/static/storage.js +++ b/src/librustdoc/html/static/storage.js @@ -110,8 +110,8 @@ function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) { }); if (found === true) { styleElem.href = newHref; - // If this new value comes from a system setting or from the previously saved theme, no - // need to save it. + // If this new value comes from a system setting or from the previously + // saved theme, no need to save it. if (saveTheme === true) { updateLocalStorage("rustdoc-theme", newTheme); } @@ -182,7 +182,10 @@ if (getCurrentValue("rustdoc-use-system-theme") !== "false" && window.matchMedia // call the function to initialize the theme at least once! updateSystemTheme(); } else { - switchTheme(currentTheme, mainTheme, - getCurrentValue("rustdoc-theme") || "light", - false); + switchTheme( + currentTheme, + mainTheme, + getCurrentValue("rustdoc-theme") || "light", + false + ); } From e2124086b8107a59129e163aa120dec50add0f77 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 13 Oct 2020 11:17:51 +0200 Subject: [PATCH 137/446] Fix FP in `same_functions_in_if_condition` lint about condition as macro --- clippy_lints/src/copies.rs | 6 +++++- tests/ui/same_functions_in_if_condition.rs | 12 +++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 10a64769585..6c969c3ead0 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,4 +1,4 @@ -use crate::utils::{eq_expr_value, SpanlessEq, SpanlessHash}; +use crate::utils::{eq_expr_value, in_macro, SpanlessEq, SpanlessHash}; use crate::utils::{get_parent_expr, higher, if_sequence, snippet, span_lint_and_note, span_lint_and_then}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{Arm, Block, Expr, ExprKind, MatchSource, Pat, PatKind}; @@ -220,6 +220,10 @@ fn lint_same_fns_in_if_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) { }; let eq: &dyn Fn(&&Expr<'_>, &&Expr<'_>) -> bool = &|&lhs, &rhs| -> bool { + // Do not lint if any expr originates from a macro + if in_macro(lhs.span) || in_macro(rhs.span) { + return false; + } // Do not spawn warning if `IFS_SAME_COND` already produced it. if eq_expr_value(cx, lhs, rhs) { return false; diff --git a/tests/ui/same_functions_in_if_condition.rs b/tests/ui/same_functions_in_if_condition.rs index 686867cf5c6..7f28f025790 100644 --- a/tests/ui/same_functions_in_if_condition.rs +++ b/tests/ui/same_functions_in_if_condition.rs @@ -77,4 +77,14 @@ fn ifs_same_cond_fn() { } } -fn main() {} +fn main() { + // macro as condition (see #6168) + let os = if cfg!(target_os = "macos") { + "macos" + } else if cfg!(target_os = "windows") { + "windows" + } else { + "linux" + }; + println!("{}", os); +} From bc6b2ac449a0f6d9a8bd87788a0eae9516cb58ce Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Tue, 13 Oct 2020 12:06:48 +0200 Subject: [PATCH 138/446] move __rg_oom to the libos to avoid duplicated symbols --- library/alloc/src/alloc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 4646d4a8335..850451bb29e 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -372,7 +372,7 @@ pub fn handle_alloc_error(layout: Layout) -> ! { unsafe { oom_impl(layout) } } -#[cfg(not(any(test, bootstrap)))] +#[cfg(not(any(target_os="hermit", test, bootstrap)))] #[doc(hidden)] #[allow(unused_attributes)] #[unstable(feature = "alloc_internals", issue = "none")] From 77d98316f489f4490459b3dcf12d14f45caf1286 Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Tue, 13 Oct 2020 12:22:18 +0200 Subject: [PATCH 139/446] minor changes to pass the format check --- library/alloc/src/alloc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 850451bb29e..1ea34be71dd 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -372,7 +372,7 @@ pub fn handle_alloc_error(layout: Layout) -> ! { unsafe { oom_impl(layout) } } -#[cfg(not(any(target_os="hermit", test, bootstrap)))] +#[cfg(not(any(target_os = "hermit", test, bootstrap)))] #[doc(hidden)] #[allow(unused_attributes)] #[unstable(feature = "alloc_internals", issue = "none")] From f83446b836900ce9afbaa0816a5b4feda654b51e Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 13 Oct 2020 13:13:09 +0200 Subject: [PATCH 140/446] Reword safety guarantee of Pin::static_{ref,mut}. Co-authored-by: Peter Todd --- library/core/src/pin.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index b27167a7e7c..633e96eb7d8 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -784,12 +784,12 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { impl Pin<&'static T> { /// Get a pinned reference from a static reference. /// - /// This is safe, because the `'static` lifetime guarantees the data will - /// never be moved. + /// This is safe, because `T` is borrowed for the `'static` lifetime, which + /// never ends. #[unstable(feature = "pin_static_ref", issue = "none")] #[rustc_const_unstable(feature = "const_pin", issue = "76654")] pub const fn static_ref(r: &'static T) -> Pin<&'static T> { - // SAFETY: The 'static lifetime guarantees the data will not be + // SAFETY: The 'static borrow guarantees the data will not be // moved/invalidated until it gets dropped (which is never). unsafe { Pin::new_unchecked(r) } } @@ -798,12 +798,12 @@ impl Pin<&'static T> { impl Pin<&'static T> { /// Get a pinned mutable reference from a static mutable reference. /// - /// This is safe, because the `'static` lifetime guarantees the data will - /// never be moved. + /// This is safe, because `T` is borrowed for the `'static` lifetime, which + /// never ends. #[unstable(feature = "pin_static_ref", issue = "none")] #[rustc_const_unstable(feature = "const_pin", issue = "76654")] pub const fn static_mut(r: &'static mut T) -> Pin<&'static mut T> { - // SAFETY: The 'static lifetime guarantees the data will not be + // SAFETY: The 'static borrow guarantees the data will not be // moved/invalidated until it gets dropped (which is never). unsafe { Pin::new_unchecked(r) } } From 8c0c7ec4ec6c4f305c229d74f74f08f86a59fc69 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Tue, 13 Oct 2020 15:57:31 +0200 Subject: [PATCH 141/446] Use fdatasync for File::sync_data on more OSes Add support for the following OSes: * Android * FreeBSD: https://www.freebsd.org/cgi/man.cgi?query=fdatasync&sektion=2 * OpenBSD: https://man.openbsd.org/OpenBSD-5.8/fsync.2 * NetBSD: https://man.netbsd.org/fdatasync.2 * illumos: https://illumos.org/man/3c/fdatasync --- library/std/src/sys/unix/fs.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 566ac0920dc..576cc24cc0f 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -752,11 +752,25 @@ impl File { unsafe fn os_datasync(fd: c_int) -> c_int { libc::fcntl(fd, libc::F_FULLFSYNC) } - #[cfg(target_os = "linux")] + #[cfg(any( + target_os = "freebsd", + target_os = "linux", + target_os = "android", + target_os = "netbsd", + target_os = "openbsd" + ))] unsafe fn os_datasync(fd: c_int) -> c_int { libc::fdatasync(fd) } - #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "linux")))] + #[cfg(not(any( + target_os = "android", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + )))] unsafe fn os_datasync(fd: c_int) -> c_int { libc::fsync(fd) } From 8374c1702c1d9858d8906051cd531757be63998d Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 13 Oct 2020 07:58:22 -0700 Subject: [PATCH 142/446] Bump the version of rustfmt used in tidy To pick up https://github.com/rust-lang/rustfmt/pull/4461 So that rustfmt has the parsing fix from https://github.com/rust-lang/rust/pull/76274 ...and do a reformat that it wants. --- library/core/src/iter/adapters/mod.rs | 6 +----- src/stage0.txt | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index ba66ba2912f..bf30dcb7689 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -2381,11 +2381,7 @@ where } let n = self.len(); - if n == 0 { - try { init } - } else { - self.iter.try_rfold(init, check(n, fold)).into_try() - } + if n == 0 { try { init } } else { self.iter.try_rfold(init, check(n, fold)).into_try() } } fn rfold(mut self, init: Acc, fold: Fold) -> Acc diff --git a/src/stage0.txt b/src/stage0.txt index 98b4dfa9c74..d90adecab78 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -20,7 +20,7 @@ cargo: beta # bootstrapping issues with use of new syntax in this repo. If you're looking at # the beta/stable branch, this key should be omitted, as we don't want to depend # on rustfmt from nightly there. -rustfmt: nightly-2020-10-07 +rustfmt: nightly-2020-10-12 # When making a stable release the process currently looks like: # From a93f58f5e6c9e4e1fbc076d966a9e1e853ea06fd Mon Sep 17 00:00:00 2001 From: wcampbell Date: Tue, 13 Oct 2020 17:01:09 -0400 Subject: [PATCH 143/446] Join map operators Signed-off-by: wcampbell --- library/std/src/fs/tests.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 65a29076fef..38fd470a1c3 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -73,10 +73,9 @@ pub fn got_symlink_permission(tmpdir: &TempDir) -> bool { let link = tmpdir.join("some_hopefully_unique_link_name"); match symlink_file(r"nonexisting_target", link) { - Ok(_) => true, // ERROR_PRIVILEGE_NOT_HELD = 1314 Err(ref err) if err.raw_os_error() == Some(1314) => false, - Err(_) => true, + Ok(_) | Err(_) => true, } } From 964a5ac962d32c280d036df42b2e747809939cc4 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Tue, 13 Oct 2020 17:01:50 -0400 Subject: [PATCH 144/446] Use is_ok() instead of empty Ok(_) Signed-off-by: wcampbell --- library/std/src/net/udp/tests.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs index 658369f79aa..fbed3d32d45 100644 --- a/library/std/src/net/udp/tests.rs +++ b/library/std/src/net/udp/tests.rs @@ -152,19 +152,13 @@ fn udp_clone_two_write() { let (done, rx) = channel(); let tx2 = tx.clone(); let _t = thread::spawn(move || { - match sock3.send_to(&[1], &addr2) { - Ok(..) => { - let _ = tx2.send(()); - } - Err(..) => {} + if sock3.send_to(&[1], &addr2).is_ok() { + let _ = tx2.send(()); } done.send(()).unwrap(); }); - match sock1.send_to(&[2], &addr2) { - Ok(..) => { - let _ = tx.send(()); - } - Err(..) => {} + if sock1.send_to(&[2], &addr2).is_ok() { + let _ = tx.send(()); } drop(tx); From abfbd1bd719bd1440132ead24ec64c0acd293f41 Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Tue, 13 Oct 2020 16:11:51 -0500 Subject: [PATCH 145/446] Avoid extraneous space between visibility kw and ident for statics Today, given a static like `static mut FOO: usize = 1`, rustdoc would emit `static mut FOO: usize = 1`, as it emits both the mutability kw with a space and reserves a space after the mutability kw. This patch fixes that misformatting. This patch also adds some tests for emit of other statics, as I could not find an existing test devoted to statics. --- src/librustdoc/html/render/mod.rs | 2 +- src/test/rustdoc/static.rs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 src/test/rustdoc/static.rs diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 76334f0213d..97d0a4d4e7d 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2289,7 +2289,7 @@ fn item_static(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Static render_attributes(w, it, false); write!( w, - "{vis}static {mutability} {name}: {typ}", + "{vis}static {mutability}{name}: {typ}", vis = it.visibility.print_with_space(), mutability = s.mutability.print_with_space(), name = it.name.as_ref().unwrap(), diff --git a/src/test/rustdoc/static.rs b/src/test/rustdoc/static.rs new file mode 100644 index 00000000000..aa48644918d --- /dev/null +++ b/src/test/rustdoc/static.rs @@ -0,0 +1,12 @@ +// compile-flags: --document-private-items + +#![crate_type = "lib"] + +// @has static/static.FOO.html '//pre[@class="static"]' 'static FOO: usize' +static FOO: usize = 1; + +// @has static/static.BAR.html '//pre[@class="static"]' 'pub static BAR: usize' +pub static BAR: usize = 1; + +// @has static/static.BAZ.html '//pre[@class="static"]' 'pub static mut BAZ: usize' +pub static mut BAZ: usize = 1; From bf268fe928eae8d85a868ccdbcc086ea033ae51c Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Tue, 13 Oct 2020 23:25:42 +0200 Subject: [PATCH 146/446] box mutex to get a movable mutex the commit avoid an alignement issue in Mutex implementation --- library/std/src/sys/hermit/mutex.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs index e12c2f4e00c..f988a019cfe 100644 --- a/library/std/src/sys/hermit/mutex.rs +++ b/library/std/src/sys/hermit/mutex.rs @@ -155,7 +155,7 @@ pub struct Mutex { inner: Spinlock, } -pub type MovableMutex = Mutex; +pub type MovableMutex = Box; unsafe impl Send for Mutex {} unsafe impl Sync for Mutex {} From e60072f5c65c619263d137daf9afab9c6cb94c8e Mon Sep 17 00:00:00 2001 From: ayazhafiz Date: Tue, 13 Oct 2020 16:47:53 -0500 Subject: [PATCH 147/446] fixup! Avoid extraneous space between visibility kw and ident for statics --- src/test/rustdoc/static.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/rustdoc/static.rs b/src/test/rustdoc/static.rs index aa48644918d..90dafd8b348 100644 --- a/src/test/rustdoc/static.rs +++ b/src/test/rustdoc/static.rs @@ -2,11 +2,11 @@ #![crate_type = "lib"] -// @has static/static.FOO.html '//pre[@class="static"]' 'static FOO: usize' +// @has static/static.FOO.html '//pre' 'static FOO: usize' static FOO: usize = 1; -// @has static/static.BAR.html '//pre[@class="static"]' 'pub static BAR: usize' +// @has static/static.BAR.html '//pre' 'pub static BAR: usize' pub static BAR: usize = 1; -// @has static/static.BAZ.html '//pre[@class="static"]' 'pub static mut BAZ: usize' +// @has static/static.BAZ.html '//pre' 'pub static mut BAZ: usize' pub static mut BAZ: usize = 1; From 121a047645270d5e9ac965d57c324301ea1f21c0 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 13 Oct 2020 23:46:23 +0200 Subject: [PATCH 148/446] Move linting of `assert` macros from early to late pass --- clippy_lints/src/eq_op.rs | 73 +++++++++++++--------------- clippy_lints/src/lib.rs | 2 - tests/ui/eq_op.rs | 53 +++++++++++++++++++++ tests/ui/eq_op.stderr | 95 ++++++++++++++++++++++++++++++++++++- tests/ui/eq_op_early.rs | 38 --------------- tests/ui/eq_op_early.stderr | 52 -------------------- 6 files changed, 179 insertions(+), 134 deletions(-) delete mode 100644 tests/ui/eq_op_early.rs delete mode 100644 tests/ui/eq_op_early.stderr diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index a95d71042ee..9653e62cad0 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -1,14 +1,11 @@ -use crate::utils::ast_utils::eq_expr; use crate::utils::{ - eq_expr_value, implements_trait, in_macro, is_copy, multispan_sugg, snippet, span_lint, span_lint_and_then, + eq_expr_value, implements_trait, in_macro, is_copy, is_expn_of, multispan_sugg, snippet, span_lint, + span_lint_and_then, }; use if_chain::if_chain; -use rustc_ast::{ast, token}; use rustc_errors::Applicability; -use rustc_hir::{BinOp, BinOpKind, BorrowKind, Expr, ExprKind}; -use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; -use rustc_middle::lint::in_external_macro; -use rustc_parse::parser; +use rustc_hir::{BinOp, BinOpKind, BorrowKind, Expr, ExprKind, StmtKind}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -63,44 +60,38 @@ declare_clippy_lint! { declare_lint_pass!(EqOp => [EQ_OP, OP_REF]); -impl EarlyLintPass for EqOp { - fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) { - let macro_list = [ - sym!(assert_eq), - sym!(assert_ne), - sym!(debug_assert_eq), - sym!(debug_assert_ne), - ]; - if_chain! { - if !in_external_macro(cx.sess, mac.span()); - if mac.path.segments.len() == 1; - let macro_name = mac.path.segments[0].ident.name; - if macro_list.contains(¯o_name); - let tokens = mac.args.inner_tokens(); - let mut parser = parser::Parser::new( - &cx.sess.parse_sess, tokens, false, None); - if let Ok(left) = parser.parse_expr(); - if parser.eat(&token::Comma); - if let Ok(right) = parser.parse_expr(); - let left_expr = left.into_inner(); - let right_expr = right.into_inner(); - if eq_expr(&left_expr, &right_expr); - - then { - span_lint( - cx, - EQ_OP, - left_expr.span.to(right_expr.span), - &format!("identical args used in this `{}!` macro call", macro_name), - ); - } - } - } -} +const ASSERT_MACRO_NAMES: [&str; 4] = ["assert_eq", "assert_ne", "debug_assert_eq", "debug_assert_ne"]; impl<'tcx> LateLintPass<'tcx> for EqOp { #[allow(clippy::similar_names, clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { + if let ExprKind::Block(ref block, _) = e.kind { + for stmt in block.stmts { + for amn in &ASSERT_MACRO_NAMES { + if_chain! { + if is_expn_of(stmt.span, amn).is_some(); + if let StmtKind::Semi(ref matchexpr) = stmt.kind; + if let ExprKind::Block(ref matchblock, _) = matchexpr.kind; + if let Some(ref matchheader) = matchblock.expr; + if let ExprKind::Match(ref headerexpr, _, _) = matchheader.kind; + if let ExprKind::Tup(ref conditions) = headerexpr.kind; + if conditions.len() == 2; + if let ExprKind::AddrOf(BorrowKind::Ref, _, ref lhs) = conditions[0].kind; + if let ExprKind::AddrOf(BorrowKind::Ref, _, ref rhs) = conditions[1].kind; + if eq_expr_value(cx, lhs, rhs); + + then { + span_lint( + cx, + EQ_OP, + lhs.span.to(rhs.span), + &format!("identical args used in this `{}!` macro call", amn), + ); + } + } + } + } + } if let ExprKind::Binary(op, ref left, ref right) = e.kind { if e.span.from_expansion() { return; diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index dd99b6b9040..fc4afde9d9e 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -348,7 +348,6 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore) { store.register_pre_expansion_pass(|| box write::Write::default()); store.register_pre_expansion_pass(|| box attrs::EarlyAttributes); store.register_pre_expansion_pass(|| box dbg_macro::DbgMacro); - store.register_pre_expansion_pass(|| box eq_op::EqOp); } #[doc(hidden)] @@ -911,7 +910,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: let vec_box_size_threshold = conf.vec_box_size_threshold; store.register_late_pass(move || box types::Types::new(vec_box_size_threshold)); store.register_late_pass(|| box booleans::NonminimalBool); - store.register_early_pass(|| box eq_op::EqOp); store.register_late_pass(|| box eq_op::EqOp); store.register_late_pass(|| box enum_clike::UnportableVariant); store.register_late_pass(|| box float_literal::FloatLiteral); diff --git a/tests/ui/eq_op.rs b/tests/ui/eq_op.rs index 272b0900a31..3ab4dfc439b 100644 --- a/tests/ui/eq_op.rs +++ b/tests/ui/eq_op.rs @@ -60,6 +60,8 @@ fn main() { const B: u32 = 10; const C: u32 = A / B; // ok, different named constants const D: u32 = A / A; + + check_assert_identical_args(); } #[rustfmt::skip] @@ -85,3 +87,54 @@ fn check_ignore_macro() { // checks if the lint ignores macros with `!` operator !bool_macro!(1) && !bool_macro!(""); } + +macro_rules! assert_in_macro_def { + () => { + let a = 42; + assert_eq!(a, a); + assert_ne!(a, a); + debug_assert_eq!(a, a); + debug_assert_ne!(a, a); + }; +} + +// lint identical args in assert-like macro invocations (see #3574) +fn check_assert_identical_args() { + // lint also in macro definition + assert_in_macro_def!(); + + let a = 1; + let b = 2; + + // lint identical args in `assert_eq!` + assert_eq!(a, a); + assert_eq!(a + 1, a + 1); + // ok + assert_eq!(a, b); + assert_eq!(a, a + 1); + assert_eq!(a + 1, b + 1); + + // lint identical args in `assert_ne!` + assert_ne!(a, a); + assert_ne!(a + 1, a + 1); + // ok + assert_ne!(a, b); + assert_ne!(a, a + 1); + assert_ne!(a + 1, b + 1); + + // lint identical args in `debug_assert_eq!` + debug_assert_eq!(a, a); + debug_assert_eq!(a + 1, a + 1); + // ok + debug_assert_eq!(a, b); + debug_assert_eq!(a, a + 1); + debug_assert_eq!(a + 1, b + 1); + + // lint identical args in `debug_assert_ne!` + debug_assert_ne!(a, a); + debug_assert_ne!(a + 1, a + 1); + // ok + debug_assert_ne!(a, b); + debug_assert_ne!(a, a + 1); + debug_assert_ne!(a + 1, b + 1); +} diff --git a/tests/ui/eq_op.stderr b/tests/ui/eq_op.stderr index 5b80e6078ee..21a63aec7a1 100644 --- a/tests/ui/eq_op.stderr +++ b/tests/ui/eq_op.stderr @@ -162,5 +162,98 @@ error: equal expressions as operands to `/` LL | const D: u32 = A / A; | ^^^^^ -error: aborting due to 27 previous errors +error: identical args used in this `assert_eq!` macro call + --> $DIR/eq_op.rs:94:20 + | +LL | assert_eq!(a, a); + | ^^^^ +... +LL | assert_in_macro_def!(); + | ----------------------- in this macro invocation + | + = note: `#[deny(clippy::eq_op)]` on by default + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: identical args used in this `assert_ne!` macro call + --> $DIR/eq_op.rs:95:20 + | +LL | assert_ne!(a, a); + | ^^^^ +... +LL | assert_in_macro_def!(); + | ----------------------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: identical args used in this `assert_eq!` macro call + --> $DIR/eq_op.rs:110:16 + | +LL | assert_eq!(a, a); + | ^^^^ + +error: identical args used in this `assert_eq!` macro call + --> $DIR/eq_op.rs:111:16 + | +LL | assert_eq!(a + 1, a + 1); + | ^^^^^^^^^^^^ + +error: identical args used in this `assert_ne!` macro call + --> $DIR/eq_op.rs:118:16 + | +LL | assert_ne!(a, a); + | ^^^^ + +error: identical args used in this `assert_ne!` macro call + --> $DIR/eq_op.rs:119:16 + | +LL | assert_ne!(a + 1, a + 1); + | ^^^^^^^^^^^^ + +error: identical args used in this `debug_assert_eq!` macro call + --> $DIR/eq_op.rs:96:26 + | +LL | debug_assert_eq!(a, a); + | ^^^^ +... +LL | assert_in_macro_def!(); + | ----------------------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: identical args used in this `debug_assert_ne!` macro call + --> $DIR/eq_op.rs:97:26 + | +LL | debug_assert_ne!(a, a); + | ^^^^ +... +LL | assert_in_macro_def!(); + | ----------------------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: identical args used in this `debug_assert_eq!` macro call + --> $DIR/eq_op.rs:126:22 + | +LL | debug_assert_eq!(a, a); + | ^^^^ + +error: identical args used in this `debug_assert_eq!` macro call + --> $DIR/eq_op.rs:127:22 + | +LL | debug_assert_eq!(a + 1, a + 1); + | ^^^^^^^^^^^^ + +error: identical args used in this `debug_assert_ne!` macro call + --> $DIR/eq_op.rs:134:22 + | +LL | debug_assert_ne!(a, a); + | ^^^^ + +error: identical args used in this `debug_assert_ne!` macro call + --> $DIR/eq_op.rs:135:22 + | +LL | debug_assert_ne!(a + 1, a + 1); + | ^^^^^^^^^^^^ + +error: aborting due to 39 previous errors diff --git a/tests/ui/eq_op_early.rs b/tests/ui/eq_op_early.rs deleted file mode 100644 index 25e1c6ac6b7..00000000000 --- a/tests/ui/eq_op_early.rs +++ /dev/null @@ -1,38 +0,0 @@ -#![warn(clippy::eq_op)] - -fn main() { - let a = 1; - let b = 2; - - // lint identical args in `assert_eq!` (see #3574) - assert_eq!(a, a); - assert_eq!(a + 1, a + 1); - // ok - assert_eq!(a, b); - assert_eq!(a, a + 1); - assert_eq!(a + 1, b + 1); - - // lint identical args in `assert_ne!` - assert_ne!(a, a); - assert_ne!(a + 1, a + 1); - // ok - assert_ne!(a, b); - assert_ne!(a, a + 1); - assert_ne!(a + 1, b + 1); - - // lint identical args in `debug_assert_eq!` - debug_assert_eq!(a, a); - debug_assert_eq!(a + 1, a + 1); - // ok - debug_assert_eq!(a, b); - debug_assert_eq!(a, a + 1); - debug_assert_eq!(a + 1, b + 1); - - // lint identical args in `debug_assert_ne!` - debug_assert_ne!(a, a); - debug_assert_ne!(a + 1, a + 1); - // ok - debug_assert_ne!(a, b); - debug_assert_ne!(a, a + 1); - debug_assert_ne!(a + 1, b + 1); -} diff --git a/tests/ui/eq_op_early.stderr b/tests/ui/eq_op_early.stderr deleted file mode 100644 index 1df094fae18..00000000000 --- a/tests/ui/eq_op_early.stderr +++ /dev/null @@ -1,52 +0,0 @@ -error: identical args used in this `assert_eq!` macro call - --> $DIR/eq_op_early.rs:8:16 - | -LL | assert_eq!(a, a); - | ^^^^ - | - = note: `-D clippy::eq-op` implied by `-D warnings` - -error: identical args used in this `assert_eq!` macro call - --> $DIR/eq_op_early.rs:9:16 - | -LL | assert_eq!(a + 1, a + 1); - | ^^^^^^^^^^^^ - -error: identical args used in this `assert_ne!` macro call - --> $DIR/eq_op_early.rs:16:16 - | -LL | assert_ne!(a, a); - | ^^^^ - -error: identical args used in this `assert_ne!` macro call - --> $DIR/eq_op_early.rs:17:16 - | -LL | assert_ne!(a + 1, a + 1); - | ^^^^^^^^^^^^ - -error: identical args used in this `debug_assert_eq!` macro call - --> $DIR/eq_op_early.rs:24:22 - | -LL | debug_assert_eq!(a, a); - | ^^^^ - -error: identical args used in this `debug_assert_eq!` macro call - --> $DIR/eq_op_early.rs:25:22 - | -LL | debug_assert_eq!(a + 1, a + 1); - | ^^^^^^^^^^^^ - -error: identical args used in this `debug_assert_ne!` macro call - --> $DIR/eq_op_early.rs:32:22 - | -LL | debug_assert_ne!(a, a); - | ^^^^ - -error: identical args used in this `debug_assert_ne!` macro call - --> $DIR/eq_op_early.rs:33:22 - | -LL | debug_assert_ne!(a + 1, a + 1); - | ^^^^^^^^^^^^ - -error: aborting due to 8 previous errors - From 058699d0a2fca02127761f014d0ecfce1c5541ec Mon Sep 17 00:00:00 2001 From: wcampbell Date: Tue, 13 Oct 2020 17:58:29 -0400 Subject: [PATCH 149/446] [net] clippy: needless_update warning: struct update has no effect, all the fields in the struct have already been specified --> library/std/src/net/addr.rs:367:19 | 367 | ..unsafe { mem::zeroed() } | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(clippy::needless_update)]` on by default = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_update --- library/std/src/net/addr.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/std/src/net/addr.rs b/library/std/src/net/addr.rs index 63de8712834..549192c9d30 100644 --- a/library/std/src/net/addr.rs +++ b/library/std/src/net/addr.rs @@ -364,7 +364,6 @@ impl SocketAddrV6 { sin6_addr: *ip.as_inner(), sin6_flowinfo: flowinfo, sin6_scope_id: scope_id, - ..unsafe { mem::zeroed() } }, } } From e6dc604e8b184b1224ae7acf58f06fa021ece82c Mon Sep 17 00:00:00 2001 From: wcampbell Date: Tue, 13 Oct 2020 18:00:59 -0400 Subject: [PATCH 150/446] [net] clippy: match_like_matches_macro warning: match expression looks like `matches!` macro --> library/std/src/net/ip.rs:459:9 | 459 | / match self.octets() { 460 | | [169, 254, ..] => true, 461 | | _ => false, 462 | | } | |_________^ help: try this: `matches!(self.octets(), [169, 254, ..])` | = note: `#[warn(clippy::match_like_matches_macro)]` on by default = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro Signed-off-by: wcampbell --- library/std/src/net/ip.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index f01a7b72a65..4ff12da8832 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -456,10 +456,7 @@ impl Ipv4Addr { #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] pub const fn is_link_local(&self) -> bool { - match self.octets() { - [169, 254, ..] => true, - _ => false, - } + matches!(self.octets(), [169, 254, ..]) } /// Returns [`true`] if the address appears to be globally routable. From 7a75f4418313da0173192ed4d2f198e505e11428 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Tue, 13 Oct 2020 18:03:27 -0400 Subject: [PATCH 151/446] [net] clippy: identity_op warning: the operation is ineffective. Consider reducing it to `self.segments()[0]` --> library/std/src/net/ip.rs:1265:9 | 1265 | (self.segments()[0] & 0xffff) == 0xfe80 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(clippy::identity_op)]` on by default = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#identity_op warning: the operation is ineffective. Consider reducing it to `self.segments()[1]` --> library/std/src/net/ip.rs:1266:16 | 1266 | && (self.segments()[1] & 0xffff) == 0 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#identity_op warning: the operation is ineffective. Consider reducing it to `self.segments()[2]` --> library/std/src/net/ip.rs:1267:16 | 1267 | && (self.segments()[2] & 0xffff) == 0 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#identity_op warning: the operation is ineffective. Consider reducing it to `self.segments()[3]` --> library/std/src/net/ip.rs:1268:16 | 1268 | && (self.segments()[3] & 0xffff) == 0 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#identity_op Signed-off-by: wcampbell --- library/std/src/net/ip.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 4ff12da8832..6bf71d28bb6 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -1259,10 +1259,10 @@ impl Ipv6Addr { /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_unicast_link_local_strict(&self) -> bool { - (self.segments()[0] & 0xffff) == 0xfe80 - && (self.segments()[1] & 0xffff) == 0 - && (self.segments()[2] & 0xffff) == 0 - && (self.segments()[3] & 0xffff) == 0 + (self.segments()[0]) == 0xfe80 + && self.segments()[1] == 0 + && self.segments()[2] == 0 + && self.segments()[3] == 0 } /// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`). From 39867f3c9fea0e01b5b199d8c2b6b0889284cc85 Mon Sep 17 00:00:00 2001 From: aticu <15schnic@gmail.com> Date: Wed, 14 Oct 2020 01:13:48 +0200 Subject: [PATCH 152/446] Fixed false positive for `unused_parens` lint --- compiler/rustc_lint/src/unused.rs | 11 +++++++++-- src/test/ui/lint/lint-unnecessary-parens.fixed | 2 ++ src/test/ui/lint/lint-unnecessary-parens.rs | 2 ++ src/test/ui/lint/lint-unnecessary-parens.stderr | 8 ++++---- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 3abd9a6325d..51ec5994933 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -751,13 +751,20 @@ impl UnusedDelimLint for UnusedParens { if !Self::is_expr_delims_necessary(inner, followed_by_block) && value.attrs.is_empty() && !value.span.from_expansion() + && (ctx != UnusedDelimsCtx::LetScrutineeExpr + || match inner.kind { + ast::ExprKind::Binary( + rustc_span::source_map::Spanned { node, .. }, + _, + _, + ) if node.lazy() => false, + _ => true, + }) { self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos) } } ast::ExprKind::Let(_, ref expr) => { - // FIXME(#60336): Properly handle `let true = (false && true)` - // actually needing the parenthesis. self.check_unused_delims_expr( cx, expr, diff --git a/src/test/ui/lint/lint-unnecessary-parens.fixed b/src/test/ui/lint/lint-unnecessary-parens.fixed index c9dec395580..9c144324f2f 100644 --- a/src/test/ui/lint/lint-unnecessary-parens.fixed +++ b/src/test/ui/lint/lint-unnecessary-parens.fixed @@ -60,6 +60,8 @@ fn main() { if (v == X { y: true }) {} if (X { y: true } == v) {} if (X { y: false }.y) {} + // this shouldn't warn, because the parens are necessary to disambiguate let chains + if let true = (true && false) {} while (X { y: false }.foo(true)) {} while (true | X { y: false }.y) {} diff --git a/src/test/ui/lint/lint-unnecessary-parens.rs b/src/test/ui/lint/lint-unnecessary-parens.rs index 884bb4d2e99..4fd9cabb3b0 100644 --- a/src/test/ui/lint/lint-unnecessary-parens.rs +++ b/src/test/ui/lint/lint-unnecessary-parens.rs @@ -60,6 +60,8 @@ fn main() { if (v == X { y: true }) {} if (X { y: true } == v) {} if (X { y: false }.y) {} + // this shouldn't warn, because the parens are necessary to disambiguate let chains + if let true = (true && false) {} while (X { y: false }.foo(true)) {} while (true | X { y: false }.y) {} diff --git a/src/test/ui/lint/lint-unnecessary-parens.stderr b/src/test/ui/lint/lint-unnecessary-parens.stderr index 1abf47c8af5..9eae7da9004 100644 --- a/src/test/ui/lint/lint-unnecessary-parens.stderr +++ b/src/test/ui/lint/lint-unnecessary-parens.stderr @@ -83,25 +83,25 @@ LL | while let 1 = (2) {} | ^^^ help: remove these parentheses error: unnecessary parentheses around method argument - --> $DIR/lint-unnecessary-parens.rs:71:24 + --> $DIR/lint-unnecessary-parens.rs:73:24 | LL | X { y: false }.foo((true)); | ^^^^^^ help: remove these parentheses error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:73:18 + --> $DIR/lint-unnecessary-parens.rs:75:18 | LL | let mut _a = (0); | ^^^ help: remove these parentheses error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:74:10 + --> $DIR/lint-unnecessary-parens.rs:76:10 | LL | _a = (0); | ^^^ help: remove these parentheses error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:75:11 + --> $DIR/lint-unnecessary-parens.rs:77:11 | LL | _a += (1); | ^^^ help: remove these parentheses From 7da0e58da4f1a4a7f102eb5478dbd4e7fa7edbaf Mon Sep 17 00:00:00 2001 From: wcampbell Date: Tue, 13 Oct 2020 19:33:39 -0400 Subject: [PATCH 153/446] use matches! in library/std/src/net/ip.rs Apply suggestion from review Co-authored-by: LingMan --- library/std/src/net/ip.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 6bf71d28bb6..eb054b08117 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -1259,10 +1259,7 @@ impl Ipv6Addr { /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_unicast_link_local_strict(&self) -> bool { - (self.segments()[0]) == 0xfe80 - && self.segments()[1] == 0 - && self.segments()[2] == 0 - && self.segments()[3] == 0 + matches!(self.segments(), [0xfe80, 0, 0, 0, ..]) } /// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`). From ce04836327e6aebab6a834d89e7305d1b1be958b Mon Sep 17 00:00:00 2001 From: wcampbell Date: Tue, 13 Oct 2020 20:11:29 -0400 Subject: [PATCH 154/446] fmt Signed-off-by: wcampbell --- library/std/src/net/ip.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index eb054b08117..8089d7a8ba6 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -1259,7 +1259,7 @@ impl Ipv6Addr { /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_unicast_link_local_strict(&self) -> bool { - matches!(self.segments(), [0xfe80, 0, 0, 0, ..]) + matches!(self.segments(), [0xfe80, 0, 0, 0, ..]) } /// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`). From 28af355b9ffa7fdd1761caa4dd323eacd68ee0ed Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Thu, 8 Oct 2020 22:15:18 +0200 Subject: [PATCH 155/446] BTreeMap: improve gdb introspection of BTreeMap with ZST keys or values --- library/alloc/src/collections/btree/node.rs | 1 - src/etc/gdb_providers.py | 20 +++++++------- src/test/debuginfo/pretty-std-collections.rs | 28 ++++++++++++++------ 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 4fa97ff053e..6864cd06cb7 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -87,7 +87,6 @@ impl LeafNode { #[repr(C)] // gdb_providers.py uses this type name for introspection. struct InternalNode { - // gdb_providers.py uses this field name for introspection. data: LeafNode, /// The pointers to the children of this node. `len + 1` of these are considered diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py index b2d343fd7af..eec3027085c 100644 --- a/src/etc/gdb_providers.py +++ b/src/etc/gdb_providers.py @@ -229,8 +229,8 @@ def children_of_node(boxed_node, height): yield child if i < length: # Avoid "Cannot perform pointer math on incomplete type" on zero-sized arrays. - key = keys[i]["value"]["value"] if keys.type.sizeof > 0 else None - val = vals[i]["value"]["value"] if vals.type.sizeof > 0 else None + key = keys[i]["value"]["value"] if keys.type.sizeof > 0 else "()" + val = vals[i]["value"]["value"] if vals.type.sizeof > 0 else "()" yield key, val @@ -242,11 +242,8 @@ def children_of_map(map): root = root.cast(gdb.lookup_type(root.type.name[21:-1])) boxed_root_node = root["node"] height = root["height"] - for i, (key, val) in enumerate(children_of_node(boxed_root_node, height)): - if key is not None: - yield "key{}".format(i), key - if val is not None: - yield "val{}".format(i), val + for child in children_of_node(boxed_root_node, height): + yield child class StdBTreeSetProvider: @@ -258,8 +255,8 @@ class StdBTreeSetProvider: def children(self): inner_map = self.valobj["map"] - for child in children_of_map(inner_map): - yield child + for i, (child, _) in enumerate(children_of_map(inner_map)): + yield "[{}]".format(i), child @staticmethod def display_hint(): @@ -274,8 +271,9 @@ class StdBTreeMapProvider: return "BTreeMap(size={})".format(self.valobj["length"]) def children(self): - for child in children_of_map(self.valobj): - yield child + for i, (key, val) in enumerate(children_of_map(self.valobj)): + yield "key{}".format(i), key + yield "val{}".format(i), val @staticmethod def display_hint(): diff --git a/src/test/debuginfo/pretty-std-collections.rs b/src/test/debuginfo/pretty-std-collections.rs index c6d2090759f..cc2a3a34510 100644 --- a/src/test/debuginfo/pretty-std-collections.rs +++ b/src/test/debuginfo/pretty-std-collections.rs @@ -34,20 +34,26 @@ // gdb-check:$6 = BTreeMap(size=15) = {[0] = pretty_std_collections::MyLeafNode (0), [...]} // (abbreviated because it's boring but we need enough elements to include internal nodes) -// gdb-command: print zst_btree_map -// gdb-check:$7 = BTreeMap(size=1) +// gdb-command: print zst_key_btree_map +// gdb-check:$7 = BTreeMap(size=1) = {[()] = 1} + +// gdb-command: print zst_val_btree_map +// gdb-check:$8 = BTreeMap(size=1) = {[1] = ()} + +// gdb-command: print zst_key_val_btree_map +// gdb-check:$9 = BTreeMap(size=1) = {[()] = ()} // gdb-command: print vec_deque -// gdb-check:$8 = VecDeque(size=3) = {5, 3, 7} +// gdb-check:$10 = VecDeque(size=3) = {5, 3, 7} // gdb-command: print vec_deque2 -// gdb-check:$9 = VecDeque(size=7) = {2, 3, 4, 5, 6, 7, 8} +// gdb-check:$11 = VecDeque(size=7) = {2, 3, 4, 5, 6, 7, 8} // gdb-command: print hash_map -// gdb-check:$10 = HashMap(size=4) = {[1] = 10, [2] = 20, [3] = 30, [4] = 40} +// gdb-check:$12 = HashMap(size=4) = {[1] = 10, [2] = 20, [3] = 30, [4] = 40} // gdb-command: print hash_set -// gdb-check:$11 = HashSet(size=4) = {1, 2, 3, 4} +// gdb-check:$13 = HashSet(size=4) = {1, 2, 3, 4} // === LLDB TESTS ================================================================================== @@ -114,8 +120,14 @@ fn main() { nasty_btree_map.insert(i, MyLeafNode(i)); } - let mut zst_btree_map: BTreeMap<(), ()> = BTreeMap::new(); - zst_btree_map.insert((), ()); + let mut zst_key_btree_map: BTreeMap<(), i32> = BTreeMap::new(); + zst_key_btree_map.insert((), 1); + + let mut zst_val_btree_map: BTreeMap = BTreeMap::new(); + zst_val_btree_map.insert(1, ()); + + let mut zst_key_val_btree_map: BTreeMap<(), ()> = BTreeMap::new(); + zst_key_val_btree_map.insert((), ()); // VecDeque let mut vec_deque = VecDeque::new(); From e82264860dd275fe95c335929ee9a231c3a61236 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Wed, 14 Oct 2020 23:15:01 +1100 Subject: [PATCH 156/446] Add a known problem for transmute_ptr_to_ref lint --- clippy_lints/src/transmute.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index c75adb62f25..47c650ac27d 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -98,7 +98,11 @@ declare_clippy_lint! { /// /// **Why is this bad?** This can always be rewritten with `&` and `*`. /// - /// **Known problems:** None. + /// **Known problems:** + /// - `mem::transmute` in statics and constants is stable from Rust 1.46.0, + /// while dereferencing raw pointer is not stable yet. + /// If you need to do this in those places, + /// you would have to use `transmute` instead. /// /// **Example:** /// ```rust,ignore From 8ba18aeb6963d70767a0880ecb7929864fe14ef9 Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Wed, 14 Oct 2020 11:58:22 +0200 Subject: [PATCH 157/446] README: sort en/disabling section, fix typos, add note --- README.md | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 62a8be0abf2..e1b3c84d691 100644 --- a/README.md +++ b/README.md @@ -169,12 +169,33 @@ You can add options to your code to `allow`/`warn`/`deny` Clippy lints: Note: `deny` produces errors instead of warnings. -If you do not want to include your lint levels in your code, you can globally enable/disable lints by passing extra -flags to Clippy during the run: `cargo clippy -- -A clippy::lint_name` will run Clippy with `lint_name` disabled and -`cargo clippy -- -W clippy::lint_name` will run it with that enabled. This also works with lint groups. For example you -can run Clippy with warnings for all lints enabled: `cargo clippy -- -W clippy::pedantic` +If you do not want to include your lint levels in your code, you can globally enable/disable lints +by passing extra flags to Clippy during the run: + +To disable `lint_name`, run + +```terminal +cargo clippy -- -A clippy::lint_name +``` + +And to enable `lint_name`, run + +```terminal +cargo clippy -- -W clippy::lint_name +``` + +This also works with lint groups. For example you +can run Clippy with warnings for all lints enabled: +```terminal +cargo clippy -- -W clippy::pedantic +``` + If you care only about a single lint, you can allow all others and then explicitly reenable -the lint(s) you are interested in: `cargo clippy -- -Aclippy::all -Wclippy::useless_format -Wclippy::...` +the lint(s) you are interested in: +```terminal +cargo clippy -- -A clippy::all -W clippy::useless_format -W clippy::... +``` +Note that if you've run clippy before, this may only take effect after you've modified a file or ran `cargo clean`. ## Contributing From ab0fc477b8b83cb14c584aca281b16fb5cce4c1a Mon Sep 17 00:00:00 2001 From: hosseind88 Date: Wed, 14 Oct 2020 18:19:26 +0330 Subject: [PATCH 158/446] fix stderr file of clippy/custom_ice_message test --- tests/ui/custom_ice_message.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/custom_ice_message.stderr b/tests/ui/custom_ice_message.stderr index 87cdb7a8b99..a1b8e2ee162 100644 --- a/tests/ui/custom_ice_message.stderr +++ b/tests/ui/custom_ice_message.stderr @@ -10,4 +10,4 @@ note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy note: Clippy version: foo query stack during panic: -we're just showing a limited slice of the query stack +end of query stack From 71c29b5be8526562c3de8d3b7dc94611647ee120 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Wed, 14 Oct 2020 21:29:53 +0200 Subject: [PATCH 159/446] Add iterator test case for `eq_op` lint --- tests/ui/eq_op.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/ui/eq_op.rs b/tests/ui/eq_op.rs index 3ab4dfc439b..20613ac6afe 100644 --- a/tests/ui/eq_op.rs +++ b/tests/ui/eq_op.rs @@ -137,4 +137,8 @@ fn check_assert_identical_args() { debug_assert_ne!(a, b); debug_assert_ne!(a, a + 1); debug_assert_ne!(a + 1, b + 1); + + let my_vec = vec![1; 5]; + let mut my_iter = my_vec.iter(); + assert_ne!(my_iter.next(), my_iter.next()); } From 07b2da884cda8103af50beb327723dec8204fc61 Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Tue, 6 Oct 2020 11:49:08 +0200 Subject: [PATCH 160/446] add lint less_concise_than_option_unwrap_or --- CHANGELOG.md | 1 + clippy_lints/src/less_concise_than.rs | 107 ++++++++++++++++++++++++ clippy_lints/src/lib.rs | 4 + clippy_lints/src/option_if_let_else.rs | 53 +----------- clippy_lints/src/utils/eager_or_lazy.rs | 2 +- clippy_lints/src/utils/usage.rs | 50 ++++++++++- src/lintlist/mod.rs | 7 ++ tests/ui/less_concise_than.fixed | 43 ++++++++++ tests/ui/less_concise_than.rs | 55 ++++++++++++ tests/ui/less_concise_than.stderr | 52 ++++++++++++ tests/ui/shadow.rs | 1 + tests/ui/shadow.stderr | 94 ++++++++++----------- 12 files changed, 369 insertions(+), 100 deletions(-) create mode 100644 clippy_lints/src/less_concise_than.rs create mode 100644 tests/ui/less_concise_than.fixed create mode 100644 tests/ui/less_concise_than.rs create mode 100644 tests/ui/less_concise_than.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index f21768c4498..93ce6bb85d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1781,6 +1781,7 @@ Released 2018-09-13 [`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays [`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty [`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero +[`less_concise_than_option_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#less_concise_than_option_unwrap_or [`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return [`let_underscore_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock [`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use diff --git a/clippy_lints/src/less_concise_than.rs b/clippy_lints/src/less_concise_than.rs new file mode 100644 index 00000000000..097aff4b178 --- /dev/null +++ b/clippy_lints/src/less_concise_than.rs @@ -0,0 +1,107 @@ +use crate::utils; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{def, Arm, Expr, ExprKind, PatKind, QPath}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** + /// Finds patterns that can be encoded more concisely with `Option::unwrap_or`. + /// + /// **Why is this bad?** + /// Concise code helps focusing on behavior instead of boilerplate. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// match int_optional { + /// Some(v) => v, + /// None => 1, + /// } + /// ``` + /// + /// Use instead: + /// ```rust + /// int_optional.unwrap_or(1) + /// ``` + pub LESS_CONCISE_THAN_OPTION_UNWRAP_OR, + pedantic, + "finds patterns that can be encoded more concisely with `Option::unwrap_or`" +} + +declare_lint_pass!(LessConciseThan => [LESS_CONCISE_THAN_OPTION_UNWRAP_OR]); + +impl LateLintPass<'_> for LessConciseThan { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if utils::in_macro(expr.span) { + return; + } + if lint_option_unwrap_or_case(cx, expr) { + return; + } + } +} + +fn lint_option_unwrap_or_case<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + #[allow(clippy::needless_bool)] + fn applicable_none_arm<'a>(arms: &'a [Arm<'a>]) -> Option<&'a Arm<'a>> { + if_chain! { + if arms.len() == 2; + if arms.iter().all(|arm| arm.guard.is_none()); + if let Some((idx, none_arm)) = arms.iter().enumerate().find(|(_, arm)| + if_chain! { + if let PatKind::Path(ref qpath) = arm.pat.kind; + if utils::match_qpath(qpath, &utils::paths::OPTION_NONE); + then { true } + else { false } + } + ); + let some_arm = &arms[1 - idx]; + if let PatKind::TupleStruct(ref some_qpath, &[some_binding], _) = some_arm.pat.kind; + if utils::match_qpath(some_qpath, &utils::paths::OPTION_SOME); + if let PatKind::Binding(_, binding_hir_id, ..) = some_binding.kind; + if let ExprKind::Path(QPath::Resolved(_, body_path)) = some_arm.body.kind; + if let def::Res::Local(body_path_hir_id) = body_path.res; + if body_path_hir_id == binding_hir_id; + then { Some(none_arm) } + else { None } + } + } + if_chain! { + if !utils::usage::contains_return_break_continue_macro(expr); + if let ExprKind::Match (match_expr, match_arms, _) = expr.kind; + let ty = cx.typeck_results().expr_ty(match_expr); + if utils::is_type_diagnostic_item(cx, ty, sym!(option_type)); + if let Some(none_arm) = applicable_none_arm(match_arms); + if let Some(match_expr_snippet) = utils::snippet_opt(cx, match_expr.span); + if let Some(none_body_snippet) = utils::snippet_opt(cx, none_arm.body.span); + if let Some(indent) = utils::indent_of(cx, expr.span); + then { + let reindented_none_body = + utils::reindent_multiline(none_body_snippet.into(), true, Some(indent)); + let eager_eval = utils::eager_or_lazy::is_eagerness_candidate(cx, none_arm.body); + let method = if eager_eval { + "unwrap_or" + } else { + "unwrap_or_else" + }; + utils::span_lint_and_sugg( + cx, + LESS_CONCISE_THAN_OPTION_UNWRAP_OR, expr.span, + "this pattern can be more concisely encoded with `Option::unwrap_or`", + "replace with", + format!( + "{}.{}({}{})", + match_expr_snippet, + method, + if eager_eval { ""} else { "|| " }, + reindented_none_body + ), + Applicability::MachineApplicable, + ); + true + } else { false} + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 26a727687b1..2e9900815d9 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -224,6 +224,7 @@ mod large_const_arrays; mod large_enum_variant; mod large_stack_arrays; mod len_zero; +mod less_concise_than; mod let_if_seq; mod let_underscore; mod lifetimes; @@ -609,6 +610,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &large_stack_arrays::LARGE_STACK_ARRAYS, &len_zero::LEN_WITHOUT_IS_EMPTY, &len_zero::LEN_ZERO, + &less_concise_than::LESS_CONCISE_THAN_OPTION_UNWRAP_OR, &let_if_seq::USELESS_LET_IF_SEQ, &let_underscore::LET_UNDERSCORE_LOCK, &let_underscore::LET_UNDERSCORE_MUST_USE, @@ -1126,6 +1128,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box repeat_once::RepeatOnce); store.register_late_pass(|| box unwrap_in_result::UnwrapInResult); store.register_late_pass(|| box self_assignment::SelfAssignment); + store.register_late_pass(|| box less_concise_than::LessConciseThan); store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs); store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync); store.register_late_pass(|| box manual_strip::ManualStrip); @@ -1210,6 +1213,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&infinite_iter::MAYBE_INFINITE_ITER), LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS), LintId::of(&large_stack_arrays::LARGE_STACK_ARRAYS), + LintId::of(&less_concise_than::LESS_CONCISE_THAN_OPTION_UNWRAP_OR), LintId::of(&literal_representation::LARGE_DIGIT_GROUPS), LintId::of(&literal_representation::UNREADABLE_LITERAL), LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP), diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 383a62da821..eb7624b25a3 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -5,10 +5,8 @@ use crate::utils::{is_type_diagnostic_item, paths, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::intravisit::{NestedVisitorMap, Visitor}; use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, MatchSource, Mutability, PatKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -84,53 +82,6 @@ struct OptionIfLetElseOccurence { wrap_braces: bool, } -struct ReturnBreakContinueMacroVisitor { - seen_return_break_continue: bool, -} - -impl ReturnBreakContinueMacroVisitor { - fn new() -> ReturnBreakContinueMacroVisitor { - ReturnBreakContinueMacroVisitor { - seen_return_break_continue: false, - } - } -} - -impl<'tcx> Visitor<'tcx> for ReturnBreakContinueMacroVisitor { - type Map = Map<'tcx>; - fn nested_visit_map(&mut self) -> NestedVisitorMap { - NestedVisitorMap::None - } - - fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { - if self.seen_return_break_continue { - // No need to look farther if we've already seen one of them - return; - } - match &ex.kind { - ExprKind::Ret(..) | ExprKind::Break(..) | ExprKind::Continue(..) => { - self.seen_return_break_continue = true; - }, - // Something special could be done here to handle while or for loop - // desugaring, as this will detect a break if there's a while loop - // or a for loop inside the expression. - _ => { - if utils::in_macro(ex.span) { - self.seen_return_break_continue = true; - } else { - rustc_hir::intravisit::walk_expr(self, ex); - } - }, - } - } -} - -fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool { - let mut recursive_visitor = ReturnBreakContinueMacroVisitor::new(); - recursive_visitor.visit_expr(expression); - recursive_visitor.seen_return_break_continue -} - /// Extracts the body of a given arm. If the arm contains only an expression, /// then it returns the expression. Otherwise, it returns the entire block fn extract_body_from_arm<'a>(arm: &'a Arm<'a>) -> Option<&'a Expr<'a>> { @@ -208,8 +159,8 @@ fn detect_option_if_let_else<'tcx>( if let PatKind::TupleStruct(struct_qpath, &[inner_pat], _) = &arms[0].pat.kind; if utils::match_qpath(struct_qpath, &paths::OPTION_SOME); if let PatKind::Binding(bind_annotation, _, id, _) = &inner_pat.kind; - if !contains_return_break_continue_macro(arms[0].body); - if !contains_return_break_continue_macro(arms[1].body); + if !utils::usage::contains_return_break_continue_macro(arms[0].body); + if !utils::usage::contains_return_break_continue_macro(arms[1].body); then { let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" }; let some_body = extract_body_from_arm(&arms[0])?; diff --git a/clippy_lints/src/utils/eager_or_lazy.rs b/clippy_lints/src/utils/eager_or_lazy.rs index 6938d9971d9..30e812c284b 100644 --- a/clippy_lints/src/utils/eager_or_lazy.rs +++ b/clippy_lints/src/utils/eager_or_lazy.rs @@ -82,7 +82,7 @@ fn identify_some_pure_patterns(expr: &Expr<'_>) -> bool { /// Identify some potentially computationally expensive patterns. /// This function is named so to stress that its implementation is non-exhaustive. /// It returns FNs and FPs. -fn identify_some_potentially_expensive_patterns<'a, 'tcx>(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { +fn identify_some_potentially_expensive_patterns<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { // Searches an expression for method calls or function calls that aren't ctors struct FunCallFinder<'a, 'tcx> { cx: &'a LateContext<'tcx>, diff --git a/clippy_lints/src/utils/usage.rs b/clippy_lints/src/utils/usage.rs index ea1dc3be29b..2fd6046ebcf 100644 --- a/clippy_lints/src/utils/usage.rs +++ b/clippy_lints/src/utils/usage.rs @@ -1,10 +1,11 @@ +use crate::utils; use crate::utils::match_var; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::intravisit; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; -use rustc_hir::{Expr, HirId, Path}; +use rustc_hir::{Expr, ExprKind, HirId, Path}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; @@ -174,3 +175,50 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> { intravisit::NestedVisitorMap::OnlyBodies(self.cx.tcx.hir()) } } + +struct ReturnBreakContinueMacroVisitor { + seen_return_break_continue: bool, +} + +impl ReturnBreakContinueMacroVisitor { + fn new() -> ReturnBreakContinueMacroVisitor { + ReturnBreakContinueMacroVisitor { + seen_return_break_continue: false, + } + } +} + +impl<'tcx> Visitor<'tcx> for ReturnBreakContinueMacroVisitor { + type Map = Map<'tcx>; + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } + + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { + if self.seen_return_break_continue { + // No need to look farther if we've already seen one of them + return; + } + match &ex.kind { + ExprKind::Ret(..) | ExprKind::Break(..) | ExprKind::Continue(..) => { + self.seen_return_break_continue = true; + }, + // Something special could be done here to handle while or for loop + // desugaring, as this will detect a break if there's a while loop + // or a for loop inside the expression. + _ => { + if utils::in_macro(ex.span) { + self.seen_return_break_continue = true; + } else { + rustc_hir::intravisit::walk_expr(self, ex); + } + }, + } + } +} + +pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool { + let mut recursive_visitor = ReturnBreakContinueMacroVisitor::new(); + recursive_visitor.visit_expr(expression); + recursive_visitor.seen_return_break_continue +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 624223ff706..6dc95fcfdb2 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1075,6 +1075,13 @@ vec![ deprecation: None, module: "len_zero", }, + Lint { + name: "less_concise_than_option_unwrap_or", + group: "pedantic", + desc: "finds patterns that can be encoded more concisely with `Option::unwrap_or`", + deprecation: None, + module: "less_concise_than", + }, Lint { name: "let_and_return", group: "style", diff --git a/tests/ui/less_concise_than.fixed b/tests/ui/less_concise_than.fixed new file mode 100644 index 00000000000..52b69ebba3e --- /dev/null +++ b/tests/ui/less_concise_than.fixed @@ -0,0 +1,43 @@ +// run-rustfix +#![warn(clippy::less_concise_than_option_unwrap_or)] +#![allow(dead_code)] + +fn unwrap_or() { + // int case + Some(1).unwrap_or(42); + + // richer none expr + Some(1).unwrap_or_else(|| 1 + 42); + + // multiline case + Some(1).unwrap_or_else(|| { + let a = 1 + 42; + let b = a + 42; + b + 42 + }); + + // string case + Some("Bob").unwrap_or("Alice"); + + // don't lint + match Some(1) { + Some(i) => i + 2, + None => 42, + }; + match Some(1) { + Some(i) => i, + None => return, + }; + for j in 0..4 { + match Some(j) { + Some(i) => i, + None => continue, + }; + match Some(j) { + Some(i) => i, + None => break, + }; + } +} + +fn main() {} diff --git a/tests/ui/less_concise_than.rs b/tests/ui/less_concise_than.rs new file mode 100644 index 00000000000..bb2a8f2050a --- /dev/null +++ b/tests/ui/less_concise_than.rs @@ -0,0 +1,55 @@ +// run-rustfix +#![warn(clippy::less_concise_than_option_unwrap_or)] +#![allow(dead_code)] + +fn unwrap_or() { + // int case + match Some(1) { + Some(i) => i, + None => 42, + }; + + // richer none expr + match Some(1) { + Some(i) => i, + None => 1 + 42, + }; + + // multiline case + match Some(1) { + Some(i) => i, + None => { + let a = 1 + 42; + let b = a + 42; + b + 42 + }, + }; + + // string case + match Some("Bob") { + Some(i) => i, + None => "Alice", + }; + + // don't lint + match Some(1) { + Some(i) => i + 2, + None => 42, + }; + match Some(1) { + Some(i) => i, + None => return, + }; + for j in 0..4 { + match Some(j) { + Some(i) => i, + None => continue, + }; + match Some(j) { + Some(i) => i, + None => break, + }; + } +} + +fn main() {} diff --git a/tests/ui/less_concise_than.stderr b/tests/ui/less_concise_than.stderr new file mode 100644 index 00000000000..e3e8a406db1 --- /dev/null +++ b/tests/ui/less_concise_than.stderr @@ -0,0 +1,52 @@ +error: this pattern can be more concisely encoded with `Option::unwrap_or` + --> $DIR/less_concise_than.rs:7:5 + | +LL | / match Some(1) { +LL | | Some(i) => i, +LL | | None => 42, +LL | | }; + | |_____^ help: replace with: `Some(1).unwrap_or(42)` + | + = note: `-D clippy::less-concise-than-option-unwrap-or` implied by `-D warnings` + +error: this pattern can be more concisely encoded with `Option::unwrap_or` + --> $DIR/less_concise_than.rs:13:5 + | +LL | / match Some(1) { +LL | | Some(i) => i, +LL | | None => 1 + 42, +LL | | }; + | |_____^ help: replace with: `Some(1).unwrap_or_else(|| 1 + 42)` + +error: this pattern can be more concisely encoded with `Option::unwrap_or` + --> $DIR/less_concise_than.rs:19:5 + | +LL | / match Some(1) { +LL | | Some(i) => i, +LL | | None => { +LL | | let a = 1 + 42; +... | +LL | | }, +LL | | }; + | |_____^ + | +help: replace with + | +LL | Some(1).unwrap_or_else(|| { +LL | let a = 1 + 42; +LL | let b = a + 42; +LL | b + 42 +LL | }); + | + +error: this pattern can be more concisely encoded with `Option::unwrap_or` + --> $DIR/less_concise_than.rs:29:5 + | +LL | / match Some("Bob") { +LL | | Some(i) => i, +LL | | None => "Alice", +LL | | }; + | |_____^ help: replace with: `Some("Bob").unwrap_or("Alice")` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/shadow.rs b/tests/ui/shadow.rs index bd91ae4e934..e7441293d45 100644 --- a/tests/ui/shadow.rs +++ b/tests/ui/shadow.rs @@ -8,6 +8,7 @@ #![allow( unused_parens, unused_variables, + clippy::less_concise_than_option_unwrap_or, clippy::missing_docs_in_private_items, clippy::single_match )] diff --git a/tests/ui/shadow.stderr b/tests/ui/shadow.stderr index 8a831375b41..7c1ad2949e9 100644 --- a/tests/ui/shadow.stderr +++ b/tests/ui/shadow.stderr @@ -1,135 +1,135 @@ error: `x` is shadowed by itself in `&mut x` - --> $DIR/shadow.rs:26:5 + --> $DIR/shadow.rs:27:5 | LL | let x = &mut x; | ^^^^^^^^^^^^^^^ | = note: `-D clippy::shadow-same` implied by `-D warnings` note: previous binding is here - --> $DIR/shadow.rs:25:13 + --> $DIR/shadow.rs:26:13 | LL | let mut x = 1; | ^ error: `x` is shadowed by itself in `{ x }` - --> $DIR/shadow.rs:27:5 - | -LL | let x = { x }; - | ^^^^^^^^^^^^^^ - | -note: previous binding is here - --> $DIR/shadow.rs:26:9 - | -LL | let x = &mut x; - | ^ - -error: `x` is shadowed by itself in `(&*x)` --> $DIR/shadow.rs:28:5 | -LL | let x = (&*x); +LL | let x = { x }; | ^^^^^^^^^^^^^^ | note: previous binding is here --> $DIR/shadow.rs:27:9 | +LL | let x = &mut x; + | ^ + +error: `x` is shadowed by itself in `(&*x)` + --> $DIR/shadow.rs:29:5 + | +LL | let x = (&*x); + | ^^^^^^^^^^^^^^ + | +note: previous binding is here + --> $DIR/shadow.rs:28:9 + | LL | let x = { x }; | ^ error: `x` is shadowed by `{ *x + 1 }` which reuses the original value - --> $DIR/shadow.rs:29:9 + --> $DIR/shadow.rs:30:9 | LL | let x = { *x + 1 }; | ^ | = note: `-D clippy::shadow-reuse` implied by `-D warnings` note: initialization happens here - --> $DIR/shadow.rs:29:13 + --> $DIR/shadow.rs:30:13 | LL | let x = { *x + 1 }; | ^^^^^^^^^^ note: previous binding is here - --> $DIR/shadow.rs:28:9 + --> $DIR/shadow.rs:29:9 | LL | let x = (&*x); | ^ error: `x` is shadowed by `id(x)` which reuses the original value - --> $DIR/shadow.rs:30:9 - | -LL | let x = id(x); - | ^ - | -note: initialization happens here - --> $DIR/shadow.rs:30:13 - | -LL | let x = id(x); - | ^^^^^ -note: previous binding is here - --> $DIR/shadow.rs:29:9 - | -LL | let x = { *x + 1 }; - | ^ - -error: `x` is shadowed by `(1, x)` which reuses the original value --> $DIR/shadow.rs:31:9 | -LL | let x = (1, x); +LL | let x = id(x); | ^ | note: initialization happens here --> $DIR/shadow.rs:31:13 | -LL | let x = (1, x); - | ^^^^^^ +LL | let x = id(x); + | ^^^^^ note: previous binding is here --> $DIR/shadow.rs:30:9 | -LL | let x = id(x); +LL | let x = { *x + 1 }; | ^ -error: `x` is shadowed by `first(x)` which reuses the original value +error: `x` is shadowed by `(1, x)` which reuses the original value --> $DIR/shadow.rs:32:9 | -LL | let x = first(x); +LL | let x = (1, x); | ^ | note: initialization happens here --> $DIR/shadow.rs:32:13 | +LL | let x = (1, x); + | ^^^^^^ +note: previous binding is here + --> $DIR/shadow.rs:31:9 + | +LL | let x = id(x); + | ^ + +error: `x` is shadowed by `first(x)` which reuses the original value + --> $DIR/shadow.rs:33:9 + | +LL | let x = first(x); + | ^ + | +note: initialization happens here + --> $DIR/shadow.rs:33:13 + | LL | let x = first(x); | ^^^^^^^^ note: previous binding is here - --> $DIR/shadow.rs:31:9 + --> $DIR/shadow.rs:32:9 | LL | let x = (1, x); | ^ error: `x` is being shadowed - --> $DIR/shadow.rs:34:9 + --> $DIR/shadow.rs:35:9 | LL | let x = y; | ^ | = note: `-D clippy::shadow-unrelated` implied by `-D warnings` note: initialization happens here - --> $DIR/shadow.rs:34:13 + --> $DIR/shadow.rs:35:13 | LL | let x = y; | ^ note: previous binding is here - --> $DIR/shadow.rs:32:9 + --> $DIR/shadow.rs:33:9 | LL | let x = first(x); | ^ error: `x` shadows a previous declaration - --> $DIR/shadow.rs:36:5 + --> $DIR/shadow.rs:37:5 | LL | let x; | ^^^^^^ | note: previous binding is here - --> $DIR/shadow.rs:34:9 + --> $DIR/shadow.rs:35:9 | LL | let x = y; | ^ From 9c9327980becadc15a68307705b3a06c28116ae1 Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Sun, 11 Oct 2020 22:42:45 +0200 Subject: [PATCH 161/446] manual-unwrap-or / rename files --- clippy_lints/src/{less_concise_than.rs => manual_unwrap_or.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename clippy_lints/src/{less_concise_than.rs => manual_unwrap_or.rs} (100%) diff --git a/clippy_lints/src/less_concise_than.rs b/clippy_lints/src/manual_unwrap_or.rs similarity index 100% rename from clippy_lints/src/less_concise_than.rs rename to clippy_lints/src/manual_unwrap_or.rs From 6d4eeeabcda6d6d25738e1e8e2b64580daefc4b9 Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Sun, 11 Oct 2020 22:55:05 +0200 Subject: [PATCH 162/446] manual-unwrap-or / pr remarks --- CHANGELOG.md | 2 +- clippy_lints/src/lib.rs | 9 +- clippy_lints/src/manual_unwrap_or.rs | 113 +++++++++--------- src/lintlist/mod.rs | 14 +-- ...cise_than.fixed => manual_unwrap_or.fixed} | 4 +- ...ss_concise_than.rs => manual_unwrap_or.rs} | 7 +- ...se_than.stderr => manual_unwrap_or.stderr} | 29 +++-- tests/ui/shadow.rs | 2 +- 8 files changed, 101 insertions(+), 79 deletions(-) rename tests/ui/{less_concise_than.fixed => manual_unwrap_or.fixed} (93%) rename tests/ui/{less_concise_than.rs => manual_unwrap_or.rs} (90%) rename tests/ui/{less_concise_than.stderr => manual_unwrap_or.stderr} (54%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93ce6bb85d8..d82f970b8bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1781,7 +1781,6 @@ Released 2018-09-13 [`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays [`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty [`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero -[`less_concise_than_option_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#less_concise_than_option_unwrap_or [`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return [`let_underscore_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock [`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use @@ -1797,6 +1796,7 @@ Released 2018-09-13 [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic [`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap +[`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or [`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names [`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone [`map_entry`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_entry diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 2e9900815d9..d4d2f92a6a6 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -224,7 +224,6 @@ mod large_const_arrays; mod large_enum_variant; mod large_stack_arrays; mod len_zero; -mod less_concise_than; mod let_if_seq; mod let_underscore; mod lifetimes; @@ -235,6 +234,7 @@ mod main_recursion; mod manual_async_fn; mod manual_non_exhaustive; mod manual_strip; +mod manual_unwrap_or; mod map_clone; mod map_err_ignore; mod map_identity; @@ -610,7 +610,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &large_stack_arrays::LARGE_STACK_ARRAYS, &len_zero::LEN_WITHOUT_IS_EMPTY, &len_zero::LEN_ZERO, - &less_concise_than::LESS_CONCISE_THAN_OPTION_UNWRAP_OR, &let_if_seq::USELESS_LET_IF_SEQ, &let_underscore::LET_UNDERSCORE_LOCK, &let_underscore::LET_UNDERSCORE_MUST_USE, @@ -642,6 +641,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &manual_async_fn::MANUAL_ASYNC_FN, &manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, &manual_strip::MANUAL_STRIP, + &manual_unwrap_or::MANUAL_UNWRAP_OR, &map_clone::MAP_CLONE, &map_err_ignore::MAP_ERR_IGNORE, &map_identity::MAP_IDENTITY, @@ -1128,7 +1128,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box repeat_once::RepeatOnce); store.register_late_pass(|| box unwrap_in_result::UnwrapInResult); store.register_late_pass(|| box self_assignment::SelfAssignment); - store.register_late_pass(|| box less_concise_than::LessConciseThan); + store.register_late_pass(|| box manual_unwrap_or::ManualUnwrapOr); store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs); store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync); store.register_late_pass(|| box manual_strip::ManualStrip); @@ -1213,7 +1213,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&infinite_iter::MAYBE_INFINITE_ITER), LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS), LintId::of(&large_stack_arrays::LARGE_STACK_ARRAYS), - LintId::of(&less_concise_than::LESS_CONCISE_THAN_OPTION_UNWRAP_OR), LintId::of(&literal_representation::LARGE_DIGIT_GROUPS), LintId::of(&literal_representation::UNREADABLE_LITERAL), LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP), @@ -1371,6 +1370,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&manual_async_fn::MANUAL_ASYNC_FN), LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), LintId::of(&manual_strip::MANUAL_STRIP), + LintId::of(&manual_unwrap_or::MANUAL_UNWRAP_OR), LintId::of(&map_clone::MAP_CLONE), LintId::of(&map_identity::MAP_IDENTITY), LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN), @@ -1666,6 +1666,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&loops::MUT_RANGE_BOUND), LintId::of(&loops::WHILE_LET_LOOP), LintId::of(&manual_strip::MANUAL_STRIP), + LintId::of(&manual_unwrap_or::MANUAL_UNWRAP_OR), LintId::of(&map_identity::MAP_IDENTITY), LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN), LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN), diff --git a/clippy_lints/src/manual_unwrap_or.rs b/clippy_lints/src/manual_unwrap_or.rs index 097aff4b178..9d8fc863424 100644 --- a/clippy_lints/src/manual_unwrap_or.rs +++ b/clippy_lints/src/manual_unwrap_or.rs @@ -2,12 +2,14 @@ use crate::utils; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{def, Arm, Expr, ExprKind, PatKind, QPath}; +use rustc_lint::LintContext; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { /// **What it does:** - /// Finds patterns that can be encoded more concisely with `Option::unwrap_or`. + /// Finds patterns that reimplement `Option::unwrap_or`. /// /// **Why is this bad?** /// Concise code helps focusing on behavior instead of boilerplate. @@ -16,7 +18,7 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust - /// match int_optional { + /// match int_option { /// Some(v) => v, /// None => 1, /// } @@ -24,39 +26,35 @@ declare_clippy_lint! { /// /// Use instead: /// ```rust - /// int_optional.unwrap_or(1) + /// int_option.unwrap_or(1) /// ``` - pub LESS_CONCISE_THAN_OPTION_UNWRAP_OR, - pedantic, - "finds patterns that can be encoded more concisely with `Option::unwrap_or`" + pub MANUAL_UNWRAP_OR, + complexity, + "finds patterns that can be encoded more concisely with `Option::unwrap_or(_else)`" } -declare_lint_pass!(LessConciseThan => [LESS_CONCISE_THAN_OPTION_UNWRAP_OR]); +declare_lint_pass!(ManualUnwrapOr => [MANUAL_UNWRAP_OR]); -impl LateLintPass<'_> for LessConciseThan { +impl LateLintPass<'_> for ManualUnwrapOr { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if utils::in_macro(expr.span) { - return; - } - if lint_option_unwrap_or_case(cx, expr) { + if in_external_macro(cx.sess(), expr.span) { return; } + lint_option_unwrap_or_case(cx, expr); } } fn lint_option_unwrap_or_case<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { - #[allow(clippy::needless_bool)] fn applicable_none_arm<'a>(arms: &'a [Arm<'a>]) -> Option<&'a Arm<'a>> { if_chain! { if arms.len() == 2; if arms.iter().all(|arm| arm.guard.is_none()); if let Some((idx, none_arm)) = arms.iter().enumerate().find(|(_, arm)| - if_chain! { - if let PatKind::Path(ref qpath) = arm.pat.kind; - if utils::match_qpath(qpath, &utils::paths::OPTION_NONE); - then { true } - else { false } - } + if let PatKind::Path(ref qpath) = arm.pat.kind { + utils::match_qpath(qpath, &utils::paths::OPTION_NONE) + } else { + false + } ); let some_arm = &arms[1 - idx]; if let PatKind::TupleStruct(ref some_qpath, &[some_binding], _) = some_arm.pat.kind; @@ -65,43 +63,50 @@ fn lint_option_unwrap_or_case<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tc if let ExprKind::Path(QPath::Resolved(_, body_path)) = some_arm.body.kind; if let def::Res::Local(body_path_hir_id) = body_path.res; if body_path_hir_id == binding_hir_id; - then { Some(none_arm) } - else { None } + if !utils::usage::contains_return_break_continue_macro(none_arm.body); + then { + Some(none_arm) + } + else { + None + } } } + if_chain! { - if !utils::usage::contains_return_break_continue_macro(expr); - if let ExprKind::Match (match_expr, match_arms, _) = expr.kind; - let ty = cx.typeck_results().expr_ty(match_expr); - if utils::is_type_diagnostic_item(cx, ty, sym!(option_type)); - if let Some(none_arm) = applicable_none_arm(match_arms); - if let Some(match_expr_snippet) = utils::snippet_opt(cx, match_expr.span); - if let Some(none_body_snippet) = utils::snippet_opt(cx, none_arm.body.span); - if let Some(indent) = utils::indent_of(cx, expr.span); - then { - let reindented_none_body = - utils::reindent_multiline(none_body_snippet.into(), true, Some(indent)); - let eager_eval = utils::eager_or_lazy::is_eagerness_candidate(cx, none_arm.body); - let method = if eager_eval { - "unwrap_or" - } else { - "unwrap_or_else" - }; - utils::span_lint_and_sugg( - cx, - LESS_CONCISE_THAN_OPTION_UNWRAP_OR, expr.span, - "this pattern can be more concisely encoded with `Option::unwrap_or`", - "replace with", - format!( - "{}.{}({}{})", - match_expr_snippet, - method, - if eager_eval { ""} else { "|| " }, - reindented_none_body - ), - Applicability::MachineApplicable, - ); - true - } else { false} + if let ExprKind::Match(scrutinee, match_arms, _) = expr.kind; + let ty = cx.typeck_results().expr_ty(scrutinee); + if utils::is_type_diagnostic_item(cx, ty, sym!(option_type)); + if let Some(none_arm) = applicable_none_arm(match_arms); + if let Some(scrutinee_snippet) = utils::snippet_opt(cx, scrutinee.span); + if let Some(none_body_snippet) = utils::snippet_opt(cx, none_arm.body.span); + if let Some(indent) = utils::indent_of(cx, expr.span); + then { + let reindented_none_body = + utils::reindent_multiline(none_body_snippet.into(), true, Some(indent)); + let eager_eval = utils::eager_or_lazy::is_eagerness_candidate(cx, none_arm.body); + let method = if eager_eval { + "unwrap_or" + } else { + "unwrap_or_else" + }; + utils::span_lint_and_sugg( + cx, + MANUAL_UNWRAP_OR, expr.span, + &format!("this pattern reimplements `Option::{}`", &method), + "replace with", + format!( + "{}.{}({}{})", + scrutinee_snippet, + method, + if eager_eval { ""} else { "|| " }, + reindented_none_body + ), + Applicability::MachineApplicable, + ); + true + } else { + false + } } } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 6dc95fcfdb2..debd3c31d8b 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1075,13 +1075,6 @@ vec![ deprecation: None, module: "len_zero", }, - Lint { - name: "less_concise_than_option_unwrap_or", - group: "pedantic", - desc: "finds patterns that can be encoded more concisely with `Option::unwrap_or`", - deprecation: None, - module: "less_concise_than", - }, Lint { name: "let_and_return", group: "style", @@ -1187,6 +1180,13 @@ vec![ deprecation: None, module: "swap", }, + Lint { + name: "manual_unwrap_or", + group: "complexity", + desc: "finds patterns that can be encoded more concisely with `Option::unwrap_or(_else)`", + deprecation: None, + module: "manual_unwrap_or", + }, Lint { name: "many_single_char_names", group: "style", diff --git a/tests/ui/less_concise_than.fixed b/tests/ui/manual_unwrap_or.fixed similarity index 93% rename from tests/ui/less_concise_than.fixed rename to tests/ui/manual_unwrap_or.fixed index 52b69ebba3e..99d30360db1 100644 --- a/tests/ui/less_concise_than.fixed +++ b/tests/ui/manual_unwrap_or.fixed @@ -1,11 +1,13 @@ // run-rustfix -#![warn(clippy::less_concise_than_option_unwrap_or)] #![allow(dead_code)] fn unwrap_or() { // int case Some(1).unwrap_or(42); + // int case reversed + Some(1).unwrap_or(42); + // richer none expr Some(1).unwrap_or_else(|| 1 + 42); diff --git a/tests/ui/less_concise_than.rs b/tests/ui/manual_unwrap_or.rs similarity index 90% rename from tests/ui/less_concise_than.rs rename to tests/ui/manual_unwrap_or.rs index bb2a8f2050a..5d03d9db163 100644 --- a/tests/ui/less_concise_than.rs +++ b/tests/ui/manual_unwrap_or.rs @@ -1,5 +1,4 @@ // run-rustfix -#![warn(clippy::less_concise_than_option_unwrap_or)] #![allow(dead_code)] fn unwrap_or() { @@ -9,6 +8,12 @@ fn unwrap_or() { None => 42, }; + // int case reversed + match Some(1) { + None => 42, + Some(i) => i, + }; + // richer none expr match Some(1) { Some(i) => i, diff --git a/tests/ui/less_concise_than.stderr b/tests/ui/manual_unwrap_or.stderr similarity index 54% rename from tests/ui/less_concise_than.stderr rename to tests/ui/manual_unwrap_or.stderr index e3e8a406db1..03da118a0c4 100644 --- a/tests/ui/less_concise_than.stderr +++ b/tests/ui/manual_unwrap_or.stderr @@ -1,5 +1,5 @@ -error: this pattern can be more concisely encoded with `Option::unwrap_or` - --> $DIR/less_concise_than.rs:7:5 +error: this pattern reimplements `Option::unwrap_or` + --> $DIR/manual_unwrap_or.rs:6:5 | LL | / match Some(1) { LL | | Some(i) => i, @@ -7,10 +7,19 @@ LL | | None => 42, LL | | }; | |_____^ help: replace with: `Some(1).unwrap_or(42)` | - = note: `-D clippy::less-concise-than-option-unwrap-or` implied by `-D warnings` + = note: `-D clippy::manual-unwrap-or` implied by `-D warnings` -error: this pattern can be more concisely encoded with `Option::unwrap_or` - --> $DIR/less_concise_than.rs:13:5 +error: this pattern reimplements `Option::unwrap_or` + --> $DIR/manual_unwrap_or.rs:12:5 + | +LL | / match Some(1) { +LL | | None => 42, +LL | | Some(i) => i, +LL | | }; + | |_____^ help: replace with: `Some(1).unwrap_or(42)` + +error: this pattern reimplements `Option::unwrap_or_else` + --> $DIR/manual_unwrap_or.rs:18:5 | LL | / match Some(1) { LL | | Some(i) => i, @@ -18,8 +27,8 @@ LL | | None => 1 + 42, LL | | }; | |_____^ help: replace with: `Some(1).unwrap_or_else(|| 1 + 42)` -error: this pattern can be more concisely encoded with `Option::unwrap_or` - --> $DIR/less_concise_than.rs:19:5 +error: this pattern reimplements `Option::unwrap_or_else` + --> $DIR/manual_unwrap_or.rs:24:5 | LL | / match Some(1) { LL | | Some(i) => i, @@ -39,8 +48,8 @@ LL | b + 42 LL | }); | -error: this pattern can be more concisely encoded with `Option::unwrap_or` - --> $DIR/less_concise_than.rs:29:5 +error: this pattern reimplements `Option::unwrap_or` + --> $DIR/manual_unwrap_or.rs:34:5 | LL | / match Some("Bob") { LL | | Some(i) => i, @@ -48,5 +57,5 @@ LL | | None => "Alice", LL | | }; | |_____^ help: replace with: `Some("Bob").unwrap_or("Alice")` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/shadow.rs b/tests/ui/shadow.rs index e7441293d45..e366c75335c 100644 --- a/tests/ui/shadow.rs +++ b/tests/ui/shadow.rs @@ -8,7 +8,7 @@ #![allow( unused_parens, unused_variables, - clippy::less_concise_than_option_unwrap_or, + clippy::manual_unwrap_or, clippy::missing_docs_in_private_items, clippy::single_match )] From fc846c37fcc720c4a5c2e2075102c1957433e703 Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Mon, 12 Oct 2020 00:06:21 +0200 Subject: [PATCH 163/446] manual_unwrap_or / use consts::constant_simple helper --- clippy_lints/src/manual_unwrap_or.rs | 11 +++++++---- tests/ui/manual_unwrap_or.fixed | 2 +- tests/ui/manual_unwrap_or.stderr | 4 ++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/manual_unwrap_or.rs b/clippy_lints/src/manual_unwrap_or.rs index 9d8fc863424..ced941fac1a 100644 --- a/clippy_lints/src/manual_unwrap_or.rs +++ b/clippy_lints/src/manual_unwrap_or.rs @@ -1,3 +1,4 @@ +use crate::consts::constant_simple; use crate::utils; use if_chain::if_chain; use rustc_errors::Applicability; @@ -18,15 +19,17 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust - /// match int_option { + /// let foo: Option = None; + /// match foo { /// Some(v) => v, /// None => 1, - /// } + /// }; /// ``` /// /// Use instead: /// ```rust - /// int_option.unwrap_or(1) + /// let foo: Option = None; + /// foo.unwrap_or(1); /// ``` pub MANUAL_UNWRAP_OR, complexity, @@ -84,7 +87,7 @@ fn lint_option_unwrap_or_case<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tc then { let reindented_none_body = utils::reindent_multiline(none_body_snippet.into(), true, Some(indent)); - let eager_eval = utils::eager_or_lazy::is_eagerness_candidate(cx, none_arm.body); + let eager_eval = constant_simple(cx, cx.typeck_results(), none_arm.body).is_some(); let method = if eager_eval { "unwrap_or" } else { diff --git a/tests/ui/manual_unwrap_or.fixed b/tests/ui/manual_unwrap_or.fixed index 99d30360db1..a9cc8678c9d 100644 --- a/tests/ui/manual_unwrap_or.fixed +++ b/tests/ui/manual_unwrap_or.fixed @@ -9,7 +9,7 @@ fn unwrap_or() { Some(1).unwrap_or(42); // richer none expr - Some(1).unwrap_or_else(|| 1 + 42); + Some(1).unwrap_or(1 + 42); // multiline case Some(1).unwrap_or_else(|| { diff --git a/tests/ui/manual_unwrap_or.stderr b/tests/ui/manual_unwrap_or.stderr index 03da118a0c4..8f6835ed78d 100644 --- a/tests/ui/manual_unwrap_or.stderr +++ b/tests/ui/manual_unwrap_or.stderr @@ -18,14 +18,14 @@ LL | | Some(i) => i, LL | | }; | |_____^ help: replace with: `Some(1).unwrap_or(42)` -error: this pattern reimplements `Option::unwrap_or_else` +error: this pattern reimplements `Option::unwrap_or` --> $DIR/manual_unwrap_or.rs:18:5 | LL | / match Some(1) { LL | | Some(i) => i, LL | | None => 1 + 42, LL | | }; - | |_____^ help: replace with: `Some(1).unwrap_or_else(|| 1 + 42)` + | |_____^ help: replace with: `Some(1).unwrap_or(1 + 42)` error: this pattern reimplements `Option::unwrap_or_else` --> $DIR/manual_unwrap_or.rs:24:5 From a8fb69f065a427f5d3fc7222b834cad9a2a7a712 Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Tue, 13 Oct 2020 10:24:00 +0200 Subject: [PATCH 164/446] manual-unwrap-or / more pr remarks --- clippy_lints/src/manual_unwrap_or.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/manual_unwrap_or.rs b/clippy_lints/src/manual_unwrap_or.rs index ced941fac1a..719a8b91f66 100644 --- a/clippy_lints/src/manual_unwrap_or.rs +++ b/clippy_lints/src/manual_unwrap_or.rs @@ -47,7 +47,7 @@ impl LateLintPass<'_> for ManualUnwrapOr { } } -fn lint_option_unwrap_or_case<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { +fn lint_option_unwrap_or_case<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { fn applicable_none_arm<'a>(arms: &'a [Arm<'a>]) -> Option<&'a Arm<'a>> { if_chain! { if arms.len() == 2; @@ -69,8 +69,7 @@ fn lint_option_unwrap_or_case<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tc if !utils::usage::contains_return_break_continue_macro(none_arm.body); then { Some(none_arm) - } - else { + } else { None } } @@ -102,14 +101,11 @@ fn lint_option_unwrap_or_case<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tc "{}.{}({}{})", scrutinee_snippet, method, - if eager_eval { ""} else { "|| " }, + if eager_eval { "" } else { "|| " }, reindented_none_body ), Applicability::MachineApplicable, ); - true - } else { - false } } } From 690a6a6c0eff1a3edeb5f4c2dcbf9994760c3184 Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Wed, 14 Oct 2020 22:09:28 +0200 Subject: [PATCH 165/446] manual-unwrap-or / remove unwrap_or_else suggestion due to ownership issues --- clippy_lints/src/manual_unwrap_or.rs | 17 +++++---------- src/lintlist/mod.rs | 2 +- tests/ui/manual_unwrap_or.fixed | 31 ++++++++++++++++++++++++---- tests/ui/manual_unwrap_or.rs | 31 ++++++++++++++++++++++++---- tests/ui/manual_unwrap_or.stderr | 18 ++++++++-------- 5 files changed, 69 insertions(+), 30 deletions(-) diff --git a/clippy_lints/src/manual_unwrap_or.rs b/clippy_lints/src/manual_unwrap_or.rs index 719a8b91f66..ddb8cc25077 100644 --- a/clippy_lints/src/manual_unwrap_or.rs +++ b/clippy_lints/src/manual_unwrap_or.rs @@ -33,7 +33,7 @@ declare_clippy_lint! { /// ``` pub MANUAL_UNWRAP_OR, complexity, - "finds patterns that can be encoded more concisely with `Option::unwrap_or(_else)`" + "finds patterns that can be encoded more concisely with `Option::unwrap_or`" } declare_lint_pass!(ManualUnwrapOr => [MANUAL_UNWRAP_OR]); @@ -83,26 +83,19 @@ fn lint_option_unwrap_or_case<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tc if let Some(scrutinee_snippet) = utils::snippet_opt(cx, scrutinee.span); if let Some(none_body_snippet) = utils::snippet_opt(cx, none_arm.body.span); if let Some(indent) = utils::indent_of(cx, expr.span); + if constant_simple(cx, cx.typeck_results(), none_arm.body).is_some(); then { let reindented_none_body = utils::reindent_multiline(none_body_snippet.into(), true, Some(indent)); - let eager_eval = constant_simple(cx, cx.typeck_results(), none_arm.body).is_some(); - let method = if eager_eval { - "unwrap_or" - } else { - "unwrap_or_else" - }; utils::span_lint_and_sugg( cx, MANUAL_UNWRAP_OR, expr.span, - &format!("this pattern reimplements `Option::{}`", &method), + "this pattern reimplements `Option::unwrap_or`", "replace with", format!( - "{}.{}({}{})", + "{}.unwrap_or({})", scrutinee_snippet, - method, - if eager_eval { "" } else { "|| " }, - reindented_none_body + reindented_none_body, ), Applicability::MachineApplicable, ); diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index debd3c31d8b..6301d623a2b 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1183,7 +1183,7 @@ vec![ Lint { name: "manual_unwrap_or", group: "complexity", - desc: "finds patterns that can be encoded more concisely with `Option::unwrap_or(_else)`", + desc: "finds patterns that can be encoded more concisely with `Option::unwrap_or`", deprecation: None, module: "manual_unwrap_or", }, diff --git a/tests/ui/manual_unwrap_or.fixed b/tests/ui/manual_unwrap_or.fixed index a9cc8678c9d..a8736f1e6ef 100644 --- a/tests/ui/manual_unwrap_or.fixed +++ b/tests/ui/manual_unwrap_or.fixed @@ -12,10 +12,11 @@ fn unwrap_or() { Some(1).unwrap_or(1 + 42); // multiline case - Some(1).unwrap_or_else(|| { - let a = 1 + 42; - let b = a + 42; - b + 42 + #[rustfmt::skip] + Some(1).unwrap_or({ + 42 + 42 + + 42 + 42 + 42 + + 42 + 42 + 42 }); // string case @@ -40,6 +41,28 @@ fn unwrap_or() { None => break, }; } + + // cases where the none arm isn't a constant expression + // are not linted due to potential ownership issues + + // ownership issue example, don't lint + struct NonCopyable; + let mut option: Option = None; + match option { + Some(x) => x, + None => { + option = Some(NonCopyable); + // some more code ... + option.unwrap() + }, + }; + + // ownership issue example, don't lint + let option: Option<&str> = None; + match option { + Some(s) => s, + None => &format!("{} {}!", "hello", "world"), + }; } fn main() {} diff --git a/tests/ui/manual_unwrap_or.rs b/tests/ui/manual_unwrap_or.rs index 5d03d9db163..bede8cffc32 100644 --- a/tests/ui/manual_unwrap_or.rs +++ b/tests/ui/manual_unwrap_or.rs @@ -21,13 +21,14 @@ fn unwrap_or() { }; // multiline case + #[rustfmt::skip] match Some(1) { Some(i) => i, None => { - let a = 1 + 42; - let b = a + 42; - b + 42 - }, + 42 + 42 + + 42 + 42 + 42 + + 42 + 42 + 42 + } }; // string case @@ -55,6 +56,28 @@ fn unwrap_or() { None => break, }; } + + // cases where the none arm isn't a constant expression + // are not linted due to potential ownership issues + + // ownership issue example, don't lint + struct NonCopyable; + let mut option: Option = None; + match option { + Some(x) => x, + None => { + option = Some(NonCopyable); + // some more code ... + option.unwrap() + }, + }; + + // ownership issue example, don't lint + let option: Option<&str> = None; + match option { + Some(s) => s, + None => &format!("{} {}!", "hello", "world"), + }; } fn main() {} diff --git a/tests/ui/manual_unwrap_or.stderr b/tests/ui/manual_unwrap_or.stderr index 8f6835ed78d..674f2952635 100644 --- a/tests/ui/manual_unwrap_or.stderr +++ b/tests/ui/manual_unwrap_or.stderr @@ -27,29 +27,29 @@ LL | | None => 1 + 42, LL | | }; | |_____^ help: replace with: `Some(1).unwrap_or(1 + 42)` -error: this pattern reimplements `Option::unwrap_or_else` - --> $DIR/manual_unwrap_or.rs:24:5 +error: this pattern reimplements `Option::unwrap_or` + --> $DIR/manual_unwrap_or.rs:25:5 | LL | / match Some(1) { LL | | Some(i) => i, LL | | None => { -LL | | let a = 1 + 42; +LL | | 42 + 42 ... | -LL | | }, +LL | | } LL | | }; | |_____^ | help: replace with | -LL | Some(1).unwrap_or_else(|| { -LL | let a = 1 + 42; -LL | let b = a + 42; -LL | b + 42 +LL | Some(1).unwrap_or({ +LL | 42 + 42 +LL | + 42 + 42 + 42 +LL | + 42 + 42 + 42 LL | }); | error: this pattern reimplements `Option::unwrap_or` - --> $DIR/manual_unwrap_or.rs:34:5 + --> $DIR/manual_unwrap_or.rs:35:5 | LL | / match Some("Bob") { LL | | Some(i) => i, From 2da121d97fa2a1839d703e8c584d5bdf989b8117 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Wed, 14 Oct 2020 23:26:48 +0200 Subject: [PATCH 166/446] Fix remark linting on checkboxes --- .github/PULL_REQUEST_TEMPLATE.md | 12 ++++++------ doc/adding_lints.md | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 137a7363094..6c92e10522c 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -12,12 +12,12 @@ your PR is merged. If you added a new lint, here's a checklist for things that will be checked during review or continuous integration. -- [ ] Followed [lint naming conventions][lint_naming] -- [ ] Added passing UI tests (including committed `.stderr` file) -- [ ] `cargo test` passes locally -- [ ] Executed `cargo dev update_lints` -- [ ] Added lint documentation -- [ ] Run `cargo dev fmt` +- \[ ] Followed [lint naming conventions][lint_naming] +- \[ ] Added passing UI tests (including committed `.stderr` file) +- \[ ] `cargo test` passes locally +- \[ ] Executed `cargo dev update_lints` +- \[ ] Added lint documentation +- \[ ] Run `cargo dev fmt` [lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints diff --git a/doc/adding_lints.md b/doc/adding_lints.md index 344bb455aa5..ab8ff711796 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -454,12 +454,12 @@ Before submitting your PR make sure you followed all of the basic requirements: -- [ ] Followed [lint naming conventions][lint_naming] -- [ ] Added passing UI tests (including committed `.stderr` file) -- [ ] `cargo test` passes locally -- [ ] Executed `cargo dev update_lints` -- [ ] Added lint documentation -- [ ] Run `cargo dev fmt` +- \[ ] Followed [lint naming conventions][lint_naming] +- \[ ] Added passing UI tests (including committed `.stderr` file) +- \[ ] `cargo test` passes locally +- \[ ] Executed `cargo dev update_lints` +- \[ ] Added lint documentation +- \[ ] Run `cargo dev fmt` ## Cheatsheet From 86e030391b2e81c44beed94e3070406994caaad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 11 Oct 2020 20:43:38 +0200 Subject: [PATCH 167/446] Make sure cold code is as small as possible --- compiler/rustc_data_structures/src/obligation_forest/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index c0193e9fa0c..adc38a01a9d 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -526,7 +526,6 @@ impl ObligationForest { let node = &self.nodes[index]; let state = node.state.get(); if state == NodeState::Success { - node.state.set(NodeState::Waiting); // This call site is cold. self.uninlined_mark_dependents_as_waiting(node); } else { @@ -538,6 +537,8 @@ impl ObligationForest { // This never-inlined function is for the cold call site. #[inline(never)] fn uninlined_mark_dependents_as_waiting(&self, node: &Node) { + // Mark node Waiting in the cold uninlined code instead of the hot inlined + node.state.set(NodeState::Waiting); self.inlined_mark_dependents_as_waiting(node) } From 5f11e71721e038ebdd9b225eec3e86f1ee7f867b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 11 Oct 2020 22:55:39 +0200 Subject: [PATCH 168/446] Reuse memory for process_cycles --- .../src/obligation_forest/mod.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index adc38a01a9d..aeb926bca3e 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -149,8 +149,8 @@ pub struct ObligationForest { /// comments in `process_obligation` for details. active_cache: FxHashMap, - /// A vector reused in compress(), to avoid allocating new vectors. - node_rewrites: Vec, + /// A vector reused in compress() and find_cycles_from_node(), to avoid allocating new vectors. + reused_node_vec: Vec, obligation_tree_id_generator: ObligationTreeIdGenerator, @@ -289,7 +289,7 @@ impl ObligationForest { nodes: vec![], done_cache: Default::default(), active_cache: Default::default(), - node_rewrites: vec![], + reused_node_vec: vec![], obligation_tree_id_generator: (0..).map(ObligationTreeId), error_cache: Default::default(), } @@ -544,12 +544,11 @@ impl ObligationForest { /// Report cycles between all `Success` nodes, and convert all `Success` /// nodes to `Done`. This must be called after `mark_successes`. - fn process_cycles

(&self, processor: &mut P) + fn process_cycles

(&mut self, processor: &mut P) where P: ObligationProcessor, { - let mut stack = vec![]; - + let mut stack = std::mem::take(&mut self.reused_node_vec); for (index, node) in self.nodes.iter().enumerate() { // For some benchmarks this state test is extremely hot. It's a win // to handle the no-op cases immediately to avoid the cost of the @@ -560,6 +559,7 @@ impl ObligationForest { } debug_assert!(stack.is_empty()); + self.reused_node_vec = stack; } fn find_cycles_from_node

(&self, stack: &mut Vec, processor: &mut P, index: usize) @@ -594,7 +594,7 @@ impl ObligationForest { #[inline(never)] fn compress(&mut self, do_completed: DoCompleted) -> Option> { let orig_nodes_len = self.nodes.len(); - let mut node_rewrites: Vec<_> = std::mem::take(&mut self.node_rewrites); + let mut node_rewrites: Vec<_> = std::mem::take(&mut self.reused_node_vec); debug_assert!(node_rewrites.is_empty()); node_rewrites.extend(0..orig_nodes_len); let mut dead_nodes = 0; @@ -655,7 +655,7 @@ impl ObligationForest { } node_rewrites.truncate(0); - self.node_rewrites = node_rewrites; + self.reused_node_vec = node_rewrites; if do_completed == DoCompleted::Yes { Some(removed_done_obligations) } else { None } } From 608f2600de26a37000e5ba0c76891d7cef13a3c5 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Thu, 15 Oct 2020 10:21:45 +0900 Subject: [PATCH 169/446] Rename some RFC dirs to be sorted alphabetically --- .../allow-hide-behind-direct-unsafe-ptr-embedded.rs | 0 .../allow-hide-behind-direct-unsafe-ptr-param.rs | 0 .../allow-hide-behind-indirect-unsafe-ptr-embedded.rs | 0 .../allow-hide-behind-indirect-unsafe-ptr-param.rs | 0 .../allow-use-behind-cousin-variant.rs | 0 .../cant-hide-behind-direct-struct-embedded.rs | 0 .../cant-hide-behind-direct-struct-embedded.stderr | 0 .../cant-hide-behind-direct-struct-param.rs | 0 .../cant-hide-behind-direct-struct-param.stderr | 0 .../cant-hide-behind-doubly-indirect-embedded.rs | 0 .../cant-hide-behind-doubly-indirect-embedded.stderr | 0 .../cant-hide-behind-doubly-indirect-param.rs | 0 .../cant-hide-behind-doubly-indirect-param.stderr | 0 .../cant-hide-behind-indirect-struct-embedded.rs | 0 .../cant-hide-behind-indirect-struct-embedded.stderr | 0 .../cant-hide-behind-indirect-struct-param.rs | 0 .../cant-hide-behind-indirect-struct-param.stderr | 0 .../feature-gate.no_gate.stderr | 0 .../feature-gate.rs | 0 .../feature-gate.with_gate.stderr | 0 .../fn-ptr-is-structurally-matchable.rs | 0 .../issue-61188-match-slice-forbidden-without-eq.rs | 0 .../issue-61188-match-slice-forbidden-without-eq.stderr | 0 .../issue-62307-match-ref-ref-forbidden-without-eq.rs | 0 .../issue-62307-match-ref-ref-forbidden-without-eq.stderr | 0 .../issue-63479-match-fnptr.rs | 0 .../issue-63479-match-fnptr.stderr | 0 .../match-empty-array-allowed-without-eq-issue-62336.rs | 0 .../match-forbidden-without-eq.rs | 0 .../match-forbidden-without-eq.stderr | 0 .../match-nonempty-array-forbidden-without-eq.rs | 0 .../match-nonempty-array-forbidden-without-eq.stderr | 0 .../match-requires-both-partialeq-and-eq.rs | 0 .../match-requires-both-partialeq-and-eq.stderr | 0 .../phantom-data-is-structurally-matchable.rs | 0 src/test/ui/{rfc1717 => rfc-1717-dllimport}/missing-link-attr.rs | 0 .../ui/{rfc1717 => rfc-1717-dllimport}/missing-link-attr.stderr | 0 src/test/ui/{rfc1717 => rfc-1717-dllimport}/multiple-renames.rs | 0 .../ui/{rfc1717 => rfc-1717-dllimport}/multiple-renames.stderr | 0 src/test/ui/{rfc1717 => rfc-1717-dllimport}/rename-to-empty.rs | 0 .../ui/{rfc1717 => rfc-1717-dllimport}/rename-to-empty.stderr | 0 41 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/allow-hide-behind-direct-unsafe-ptr-embedded.rs (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/allow-hide-behind-direct-unsafe-ptr-param.rs (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/allow-hide-behind-indirect-unsafe-ptr-embedded.rs (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/allow-hide-behind-indirect-unsafe-ptr-param.rs (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/allow-use-behind-cousin-variant.rs (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/cant-hide-behind-direct-struct-embedded.rs (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/cant-hide-behind-direct-struct-embedded.stderr (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/cant-hide-behind-direct-struct-param.rs (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/cant-hide-behind-direct-struct-param.stderr (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/cant-hide-behind-doubly-indirect-embedded.rs (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/cant-hide-behind-doubly-indirect-embedded.stderr (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/cant-hide-behind-doubly-indirect-param.rs (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/cant-hide-behind-doubly-indirect-param.stderr (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/cant-hide-behind-indirect-struct-embedded.rs (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/cant-hide-behind-indirect-struct-embedded.stderr (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/cant-hide-behind-indirect-struct-param.rs (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/cant-hide-behind-indirect-struct-param.stderr (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/feature-gate.no_gate.stderr (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/feature-gate.rs (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/feature-gate.with_gate.stderr (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/fn-ptr-is-structurally-matchable.rs (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/issue-61188-match-slice-forbidden-without-eq.rs (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/issue-61188-match-slice-forbidden-without-eq.stderr (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/issue-62307-match-ref-ref-forbidden-without-eq.rs (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/issue-62307-match-ref-ref-forbidden-without-eq.stderr (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/issue-63479-match-fnptr.rs (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/issue-63479-match-fnptr.stderr (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/match-empty-array-allowed-without-eq-issue-62336.rs (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/match-forbidden-without-eq.rs (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/match-forbidden-without-eq.stderr (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/match-nonempty-array-forbidden-without-eq.rs (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/match-nonempty-array-forbidden-without-eq.stderr (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/match-requires-both-partialeq-and-eq.rs (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/match-requires-both-partialeq-and-eq.stderr (100%) rename src/test/ui/{rfc1445 => rfc-1445-restrict-constants-in-patterns}/phantom-data-is-structurally-matchable.rs (100%) rename src/test/ui/{rfc1717 => rfc-1717-dllimport}/missing-link-attr.rs (100%) rename src/test/ui/{rfc1717 => rfc-1717-dllimport}/missing-link-attr.stderr (100%) rename src/test/ui/{rfc1717 => rfc-1717-dllimport}/multiple-renames.rs (100%) rename src/test/ui/{rfc1717 => rfc-1717-dllimport}/multiple-renames.stderr (100%) rename src/test/ui/{rfc1717 => rfc-1717-dllimport}/rename-to-empty.rs (100%) rename src/test/ui/{rfc1717 => rfc-1717-dllimport}/rename-to-empty.stderr (100%) diff --git a/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-embedded.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-embedded.rs similarity index 100% rename from src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-embedded.rs rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-embedded.rs diff --git a/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-param.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-param.rs similarity index 100% rename from src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-param.rs rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-param.rs diff --git a/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-embedded.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-embedded.rs similarity index 100% rename from src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-embedded.rs rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-embedded.rs diff --git a/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-param.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-param.rs similarity index 100% rename from src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-param.rs rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-param.rs diff --git a/src/test/ui/rfc1445/allow-use-behind-cousin-variant.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-use-behind-cousin-variant.rs similarity index 100% rename from src/test/ui/rfc1445/allow-use-behind-cousin-variant.rs rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-use-behind-cousin-variant.rs diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs similarity index 100% rename from src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.rs rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr similarity index 100% rename from src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.stderr rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs similarity index 100% rename from src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.rs rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr similarity index 100% rename from src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.stderr rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr diff --git a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs similarity index 100% rename from src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.rs rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs diff --git a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr similarity index 100% rename from src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.stderr rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr diff --git a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs similarity index 100% rename from src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.rs rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs diff --git a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr similarity index 100% rename from src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.stderr rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr diff --git a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs similarity index 100% rename from src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.rs rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs diff --git a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr similarity index 100% rename from src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.stderr rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr diff --git a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs similarity index 100% rename from src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.rs rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs diff --git a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr similarity index 100% rename from src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.stderr rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr diff --git a/src/test/ui/rfc1445/feature-gate.no_gate.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr similarity index 100% rename from src/test/ui/rfc1445/feature-gate.no_gate.stderr rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr diff --git a/src/test/ui/rfc1445/feature-gate.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/feature-gate.rs similarity index 100% rename from src/test/ui/rfc1445/feature-gate.rs rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/feature-gate.rs diff --git a/src/test/ui/rfc1445/feature-gate.with_gate.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/feature-gate.with_gate.stderr similarity index 100% rename from src/test/ui/rfc1445/feature-gate.with_gate.stderr rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/feature-gate.with_gate.stderr diff --git a/src/test/ui/rfc1445/fn-ptr-is-structurally-matchable.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.rs similarity index 100% rename from src/test/ui/rfc1445/fn-ptr-is-structurally-matchable.rs rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.rs diff --git a/src/test/ui/rfc1445/issue-61188-match-slice-forbidden-without-eq.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs similarity index 100% rename from src/test/ui/rfc1445/issue-61188-match-slice-forbidden-without-eq.rs rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs diff --git a/src/test/ui/rfc1445/issue-61188-match-slice-forbidden-without-eq.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr similarity index 100% rename from src/test/ui/rfc1445/issue-61188-match-slice-forbidden-without-eq.stderr rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr diff --git a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs similarity index 100% rename from src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs diff --git a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr similarity index 100% rename from src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr diff --git a/src/test/ui/rfc1445/issue-63479-match-fnptr.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.rs similarity index 100% rename from src/test/ui/rfc1445/issue-63479-match-fnptr.rs rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.rs diff --git a/src/test/ui/rfc1445/issue-63479-match-fnptr.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr similarity index 100% rename from src/test/ui/rfc1445/issue-63479-match-fnptr.stderr rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr diff --git a/src/test/ui/rfc1445/match-empty-array-allowed-without-eq-issue-62336.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-empty-array-allowed-without-eq-issue-62336.rs similarity index 100% rename from src/test/ui/rfc1445/match-empty-array-allowed-without-eq-issue-62336.rs rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/match-empty-array-allowed-without-eq-issue-62336.rs diff --git a/src/test/ui/rfc1445/match-forbidden-without-eq.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.rs similarity index 100% rename from src/test/ui/rfc1445/match-forbidden-without-eq.rs rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.rs diff --git a/src/test/ui/rfc1445/match-forbidden-without-eq.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.stderr similarity index 100% rename from src/test/ui/rfc1445/match-forbidden-without-eq.stderr rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.stderr diff --git a/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs similarity index 100% rename from src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.rs rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs diff --git a/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr similarity index 100% rename from src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.stderr rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr diff --git a/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs similarity index 100% rename from src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.rs rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs diff --git a/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr similarity index 100% rename from src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.stderr rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr diff --git a/src/test/ui/rfc1445/phantom-data-is-structurally-matchable.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/phantom-data-is-structurally-matchable.rs similarity index 100% rename from src/test/ui/rfc1445/phantom-data-is-structurally-matchable.rs rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/phantom-data-is-structurally-matchable.rs diff --git a/src/test/ui/rfc1717/missing-link-attr.rs b/src/test/ui/rfc-1717-dllimport/missing-link-attr.rs similarity index 100% rename from src/test/ui/rfc1717/missing-link-attr.rs rename to src/test/ui/rfc-1717-dllimport/missing-link-attr.rs diff --git a/src/test/ui/rfc1717/missing-link-attr.stderr b/src/test/ui/rfc-1717-dllimport/missing-link-attr.stderr similarity index 100% rename from src/test/ui/rfc1717/missing-link-attr.stderr rename to src/test/ui/rfc-1717-dllimport/missing-link-attr.stderr diff --git a/src/test/ui/rfc1717/multiple-renames.rs b/src/test/ui/rfc-1717-dllimport/multiple-renames.rs similarity index 100% rename from src/test/ui/rfc1717/multiple-renames.rs rename to src/test/ui/rfc-1717-dllimport/multiple-renames.rs diff --git a/src/test/ui/rfc1717/multiple-renames.stderr b/src/test/ui/rfc-1717-dllimport/multiple-renames.stderr similarity index 100% rename from src/test/ui/rfc1717/multiple-renames.stderr rename to src/test/ui/rfc-1717-dllimport/multiple-renames.stderr diff --git a/src/test/ui/rfc1717/rename-to-empty.rs b/src/test/ui/rfc-1717-dllimport/rename-to-empty.rs similarity index 100% rename from src/test/ui/rfc1717/rename-to-empty.rs rename to src/test/ui/rfc-1717-dllimport/rename-to-empty.rs diff --git a/src/test/ui/rfc1717/rename-to-empty.stderr b/src/test/ui/rfc-1717-dllimport/rename-to-empty.stderr similarity index 100% rename from src/test/ui/rfc1717/rename-to-empty.stderr rename to src/test/ui/rfc-1717-dllimport/rename-to-empty.stderr From d87c17d22f6e5dce477dbd5d26e35847682f3a9c Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Thu, 15 Oct 2020 10:24:32 +0900 Subject: [PATCH 170/446] Migrate from `associated-const` to `associated-consts` --- .../associated-const-ambiguity-report.rs | 0 .../associated-const-ambiguity-report.stderr | 0 .../associated-const-array-len.rs | 0 .../associated-const-array-len.stderr | 0 .../associated-const-dead-code.rs | 0 .../associated-const-dead-code.stderr | 0 .../associated-const-generic-obligations.rs | 0 .../associated-const-generic-obligations.stderr | 0 .../associated-const-impl-wrong-lifetime.rs | 0 .../associated-const-impl-wrong-lifetime.stderr | 0 .../associated-const-impl-wrong-type.rs | 0 .../associated-const-impl-wrong-type.stderr | 0 .../associated-const-in-trait.rs | 0 .../associated-const-in-trait.stderr | 0 .../associated-const-no-item.rs | 0 .../associated-const-no-item.stderr | 0 .../associated-const-private-impl.rs | 0 .../associated-const-private-impl.stderr | 0 .../associated-const-trait-bound.rs | 0 .../associated-const-type-parameter-arms.rs | 0 .../associated-const-type-parameter-arms.stderr | 0 .../associated-const-type-parameter-arrays-2.rs | 0 .../associated-const-type-parameter-arrays-2.stderr | 0 .../associated-const-type-parameter-arrays.rs | 0 .../associated-const-type-parameter-arrays.stderr | 0 .../defaults-cyclic-fail.rs | 0 .../defaults-cyclic-fail.stderr | 0 .../defaults-cyclic-pass.rs | 0 .../defaults-not-assumed-fail.rs | 0 .../defaults-not-assumed-fail.stderr | 0 .../defaults-not-assumed-pass.rs | 0 .../ui/{associated-const => associated-consts}/issue-63496.rs | 0 .../ui/{associated-const => associated-consts}/issue-63496.stderr | 0 .../issue-69020-assoc-const-arith-overflow.noopt.stderr | 0 .../issue-69020-assoc-const-arith-overflow.opt.stderr | 0 ...020-assoc-const-arith-overflow.opt_with_overflow_checks.stderr | 0 .../issue-69020-assoc-const-arith-overflow.rs | 0 37 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{associated-const => associated-consts}/associated-const-ambiguity-report.rs (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-ambiguity-report.stderr (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-array-len.rs (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-array-len.stderr (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-dead-code.rs (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-dead-code.stderr (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-generic-obligations.rs (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-generic-obligations.stderr (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-impl-wrong-lifetime.rs (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-impl-wrong-lifetime.stderr (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-impl-wrong-type.rs (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-impl-wrong-type.stderr (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-in-trait.rs (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-in-trait.stderr (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-no-item.rs (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-no-item.stderr (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-private-impl.rs (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-private-impl.stderr (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-trait-bound.rs (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-type-parameter-arms.rs (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-type-parameter-arms.stderr (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-type-parameter-arrays-2.rs (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-type-parameter-arrays-2.stderr (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-type-parameter-arrays.rs (100%) rename src/test/ui/{associated-const => associated-consts}/associated-const-type-parameter-arrays.stderr (100%) rename src/test/ui/{associated-const => associated-consts}/defaults-cyclic-fail.rs (100%) rename src/test/ui/{associated-const => associated-consts}/defaults-cyclic-fail.stderr (100%) rename src/test/ui/{associated-const => associated-consts}/defaults-cyclic-pass.rs (100%) rename src/test/ui/{associated-const => associated-consts}/defaults-not-assumed-fail.rs (100%) rename src/test/ui/{associated-const => associated-consts}/defaults-not-assumed-fail.stderr (100%) rename src/test/ui/{associated-const => associated-consts}/defaults-not-assumed-pass.rs (100%) rename src/test/ui/{associated-const => associated-consts}/issue-63496.rs (100%) rename src/test/ui/{associated-const => associated-consts}/issue-63496.stderr (100%) rename src/test/ui/{associated-const => associated-consts}/issue-69020-assoc-const-arith-overflow.noopt.stderr (100%) rename src/test/ui/{associated-const => associated-consts}/issue-69020-assoc-const-arith-overflow.opt.stderr (100%) rename src/test/ui/{associated-const => associated-consts}/issue-69020-assoc-const-arith-overflow.opt_with_overflow_checks.stderr (100%) rename src/test/ui/{associated-const => associated-consts}/issue-69020-assoc-const-arith-overflow.rs (100%) diff --git a/src/test/ui/associated-const/associated-const-ambiguity-report.rs b/src/test/ui/associated-consts/associated-const-ambiguity-report.rs similarity index 100% rename from src/test/ui/associated-const/associated-const-ambiguity-report.rs rename to src/test/ui/associated-consts/associated-const-ambiguity-report.rs diff --git a/src/test/ui/associated-const/associated-const-ambiguity-report.stderr b/src/test/ui/associated-consts/associated-const-ambiguity-report.stderr similarity index 100% rename from src/test/ui/associated-const/associated-const-ambiguity-report.stderr rename to src/test/ui/associated-consts/associated-const-ambiguity-report.stderr diff --git a/src/test/ui/associated-const/associated-const-array-len.rs b/src/test/ui/associated-consts/associated-const-array-len.rs similarity index 100% rename from src/test/ui/associated-const/associated-const-array-len.rs rename to src/test/ui/associated-consts/associated-const-array-len.rs diff --git a/src/test/ui/associated-const/associated-const-array-len.stderr b/src/test/ui/associated-consts/associated-const-array-len.stderr similarity index 100% rename from src/test/ui/associated-const/associated-const-array-len.stderr rename to src/test/ui/associated-consts/associated-const-array-len.stderr diff --git a/src/test/ui/associated-const/associated-const-dead-code.rs b/src/test/ui/associated-consts/associated-const-dead-code.rs similarity index 100% rename from src/test/ui/associated-const/associated-const-dead-code.rs rename to src/test/ui/associated-consts/associated-const-dead-code.rs diff --git a/src/test/ui/associated-const/associated-const-dead-code.stderr b/src/test/ui/associated-consts/associated-const-dead-code.stderr similarity index 100% rename from src/test/ui/associated-const/associated-const-dead-code.stderr rename to src/test/ui/associated-consts/associated-const-dead-code.stderr diff --git a/src/test/ui/associated-const/associated-const-generic-obligations.rs b/src/test/ui/associated-consts/associated-const-generic-obligations.rs similarity index 100% rename from src/test/ui/associated-const/associated-const-generic-obligations.rs rename to src/test/ui/associated-consts/associated-const-generic-obligations.rs diff --git a/src/test/ui/associated-const/associated-const-generic-obligations.stderr b/src/test/ui/associated-consts/associated-const-generic-obligations.stderr similarity index 100% rename from src/test/ui/associated-const/associated-const-generic-obligations.stderr rename to src/test/ui/associated-consts/associated-const-generic-obligations.stderr diff --git a/src/test/ui/associated-const/associated-const-impl-wrong-lifetime.rs b/src/test/ui/associated-consts/associated-const-impl-wrong-lifetime.rs similarity index 100% rename from src/test/ui/associated-const/associated-const-impl-wrong-lifetime.rs rename to src/test/ui/associated-consts/associated-const-impl-wrong-lifetime.rs diff --git a/src/test/ui/associated-const/associated-const-impl-wrong-lifetime.stderr b/src/test/ui/associated-consts/associated-const-impl-wrong-lifetime.stderr similarity index 100% rename from src/test/ui/associated-const/associated-const-impl-wrong-lifetime.stderr rename to src/test/ui/associated-consts/associated-const-impl-wrong-lifetime.stderr diff --git a/src/test/ui/associated-const/associated-const-impl-wrong-type.rs b/src/test/ui/associated-consts/associated-const-impl-wrong-type.rs similarity index 100% rename from src/test/ui/associated-const/associated-const-impl-wrong-type.rs rename to src/test/ui/associated-consts/associated-const-impl-wrong-type.rs diff --git a/src/test/ui/associated-const/associated-const-impl-wrong-type.stderr b/src/test/ui/associated-consts/associated-const-impl-wrong-type.stderr similarity index 100% rename from src/test/ui/associated-const/associated-const-impl-wrong-type.stderr rename to src/test/ui/associated-consts/associated-const-impl-wrong-type.stderr diff --git a/src/test/ui/associated-const/associated-const-in-trait.rs b/src/test/ui/associated-consts/associated-const-in-trait.rs similarity index 100% rename from src/test/ui/associated-const/associated-const-in-trait.rs rename to src/test/ui/associated-consts/associated-const-in-trait.rs diff --git a/src/test/ui/associated-const/associated-const-in-trait.stderr b/src/test/ui/associated-consts/associated-const-in-trait.stderr similarity index 100% rename from src/test/ui/associated-const/associated-const-in-trait.stderr rename to src/test/ui/associated-consts/associated-const-in-trait.stderr diff --git a/src/test/ui/associated-const/associated-const-no-item.rs b/src/test/ui/associated-consts/associated-const-no-item.rs similarity index 100% rename from src/test/ui/associated-const/associated-const-no-item.rs rename to src/test/ui/associated-consts/associated-const-no-item.rs diff --git a/src/test/ui/associated-const/associated-const-no-item.stderr b/src/test/ui/associated-consts/associated-const-no-item.stderr similarity index 100% rename from src/test/ui/associated-const/associated-const-no-item.stderr rename to src/test/ui/associated-consts/associated-const-no-item.stderr diff --git a/src/test/ui/associated-const/associated-const-private-impl.rs b/src/test/ui/associated-consts/associated-const-private-impl.rs similarity index 100% rename from src/test/ui/associated-const/associated-const-private-impl.rs rename to src/test/ui/associated-consts/associated-const-private-impl.rs diff --git a/src/test/ui/associated-const/associated-const-private-impl.stderr b/src/test/ui/associated-consts/associated-const-private-impl.stderr similarity index 100% rename from src/test/ui/associated-const/associated-const-private-impl.stderr rename to src/test/ui/associated-consts/associated-const-private-impl.stderr diff --git a/src/test/ui/associated-const/associated-const-trait-bound.rs b/src/test/ui/associated-consts/associated-const-trait-bound.rs similarity index 100% rename from src/test/ui/associated-const/associated-const-trait-bound.rs rename to src/test/ui/associated-consts/associated-const-trait-bound.rs diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arms.rs b/src/test/ui/associated-consts/associated-const-type-parameter-arms.rs similarity index 100% rename from src/test/ui/associated-const/associated-const-type-parameter-arms.rs rename to src/test/ui/associated-consts/associated-const-type-parameter-arms.rs diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arms.stderr b/src/test/ui/associated-consts/associated-const-type-parameter-arms.stderr similarity index 100% rename from src/test/ui/associated-const/associated-const-type-parameter-arms.stderr rename to src/test/ui/associated-consts/associated-const-type-parameter-arms.stderr diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.rs b/src/test/ui/associated-consts/associated-const-type-parameter-arrays-2.rs similarity index 100% rename from src/test/ui/associated-const/associated-const-type-parameter-arrays-2.rs rename to src/test/ui/associated-consts/associated-const-type-parameter-arrays-2.rs diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr b/src/test/ui/associated-consts/associated-const-type-parameter-arrays-2.stderr similarity index 100% rename from src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr rename to src/test/ui/associated-consts/associated-const-type-parameter-arrays-2.stderr diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arrays.rs b/src/test/ui/associated-consts/associated-const-type-parameter-arrays.rs similarity index 100% rename from src/test/ui/associated-const/associated-const-type-parameter-arrays.rs rename to src/test/ui/associated-consts/associated-const-type-parameter-arrays.rs diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr b/src/test/ui/associated-consts/associated-const-type-parameter-arrays.stderr similarity index 100% rename from src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr rename to src/test/ui/associated-consts/associated-const-type-parameter-arrays.stderr diff --git a/src/test/ui/associated-const/defaults-cyclic-fail.rs b/src/test/ui/associated-consts/defaults-cyclic-fail.rs similarity index 100% rename from src/test/ui/associated-const/defaults-cyclic-fail.rs rename to src/test/ui/associated-consts/defaults-cyclic-fail.rs diff --git a/src/test/ui/associated-const/defaults-cyclic-fail.stderr b/src/test/ui/associated-consts/defaults-cyclic-fail.stderr similarity index 100% rename from src/test/ui/associated-const/defaults-cyclic-fail.stderr rename to src/test/ui/associated-consts/defaults-cyclic-fail.stderr diff --git a/src/test/ui/associated-const/defaults-cyclic-pass.rs b/src/test/ui/associated-consts/defaults-cyclic-pass.rs similarity index 100% rename from src/test/ui/associated-const/defaults-cyclic-pass.rs rename to src/test/ui/associated-consts/defaults-cyclic-pass.rs diff --git a/src/test/ui/associated-const/defaults-not-assumed-fail.rs b/src/test/ui/associated-consts/defaults-not-assumed-fail.rs similarity index 100% rename from src/test/ui/associated-const/defaults-not-assumed-fail.rs rename to src/test/ui/associated-consts/defaults-not-assumed-fail.rs diff --git a/src/test/ui/associated-const/defaults-not-assumed-fail.stderr b/src/test/ui/associated-consts/defaults-not-assumed-fail.stderr similarity index 100% rename from src/test/ui/associated-const/defaults-not-assumed-fail.stderr rename to src/test/ui/associated-consts/defaults-not-assumed-fail.stderr diff --git a/src/test/ui/associated-const/defaults-not-assumed-pass.rs b/src/test/ui/associated-consts/defaults-not-assumed-pass.rs similarity index 100% rename from src/test/ui/associated-const/defaults-not-assumed-pass.rs rename to src/test/ui/associated-consts/defaults-not-assumed-pass.rs diff --git a/src/test/ui/associated-const/issue-63496.rs b/src/test/ui/associated-consts/issue-63496.rs similarity index 100% rename from src/test/ui/associated-const/issue-63496.rs rename to src/test/ui/associated-consts/issue-63496.rs diff --git a/src/test/ui/associated-const/issue-63496.stderr b/src/test/ui/associated-consts/issue-63496.stderr similarity index 100% rename from src/test/ui/associated-const/issue-63496.stderr rename to src/test/ui/associated-consts/issue-63496.stderr diff --git a/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.noopt.stderr b/src/test/ui/associated-consts/issue-69020-assoc-const-arith-overflow.noopt.stderr similarity index 100% rename from src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.noopt.stderr rename to src/test/ui/associated-consts/issue-69020-assoc-const-arith-overflow.noopt.stderr diff --git a/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt.stderr b/src/test/ui/associated-consts/issue-69020-assoc-const-arith-overflow.opt.stderr similarity index 100% rename from src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt.stderr rename to src/test/ui/associated-consts/issue-69020-assoc-const-arith-overflow.opt.stderr diff --git a/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt_with_overflow_checks.stderr b/src/test/ui/associated-consts/issue-69020-assoc-const-arith-overflow.opt_with_overflow_checks.stderr similarity index 100% rename from src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt_with_overflow_checks.stderr rename to src/test/ui/associated-consts/issue-69020-assoc-const-arith-overflow.opt_with_overflow_checks.stderr diff --git a/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.rs b/src/test/ui/associated-consts/issue-69020-assoc-const-arith-overflow.rs similarity index 100% rename from src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.rs rename to src/test/ui/associated-consts/issue-69020-assoc-const-arith-overflow.rs From 3113c077c042cdcbc0a071c11452118e7711a1c4 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Thu, 15 Oct 2020 10:25:23 +0900 Subject: [PATCH 171/446] Migrate from `associated-type` to `associated-types` --- ...ciated-type-projection-ambig-between-bound-and-where-clause.rs | 0 ...ed-type-projection-ambig-between-bound-and-where-clause.stderr | 0 .../associated-type-projection-from-multiple-supertraits.rs | 0 .../associated-type-projection-from-multiple-supertraits.stderr | 0 .../associated-type-projection-from-supertrait.rs | 0 .../associated-type-projection-from-supertrait.stderr | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{associated-type => associated-types}/associated-type-projection-ambig-between-bound-and-where-clause.rs (100%) rename src/test/ui/{associated-type => associated-types}/associated-type-projection-ambig-between-bound-and-where-clause.stderr (100%) rename src/test/ui/{associated-type => associated-types}/associated-type-projection-from-multiple-supertraits.rs (100%) rename src/test/ui/{associated-type => associated-types}/associated-type-projection-from-multiple-supertraits.stderr (100%) rename src/test/ui/{associated-type => associated-types}/associated-type-projection-from-supertrait.rs (100%) rename src/test/ui/{associated-type => associated-types}/associated-type-projection-from-supertrait.stderr (100%) diff --git a/src/test/ui/associated-type/associated-type-projection-ambig-between-bound-and-where-clause.rs b/src/test/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.rs similarity index 100% rename from src/test/ui/associated-type/associated-type-projection-ambig-between-bound-and-where-clause.rs rename to src/test/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.rs diff --git a/src/test/ui/associated-type/associated-type-projection-ambig-between-bound-and-where-clause.stderr b/src/test/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.stderr similarity index 100% rename from src/test/ui/associated-type/associated-type-projection-ambig-between-bound-and-where-clause.stderr rename to src/test/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.stderr diff --git a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.rs b/src/test/ui/associated-types/associated-type-projection-from-multiple-supertraits.rs similarity index 100% rename from src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.rs rename to src/test/ui/associated-types/associated-type-projection-from-multiple-supertraits.rs diff --git a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr b/src/test/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr similarity index 100% rename from src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr rename to src/test/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr diff --git a/src/test/ui/associated-type/associated-type-projection-from-supertrait.rs b/src/test/ui/associated-types/associated-type-projection-from-supertrait.rs similarity index 100% rename from src/test/ui/associated-type/associated-type-projection-from-supertrait.rs rename to src/test/ui/associated-types/associated-type-projection-from-supertrait.rs diff --git a/src/test/ui/associated-type/associated-type-projection-from-supertrait.stderr b/src/test/ui/associated-types/associated-type-projection-from-supertrait.stderr similarity index 100% rename from src/test/ui/associated-type/associated-type-projection-from-supertrait.stderr rename to src/test/ui/associated-types/associated-type-projection-from-supertrait.stderr From 72b3807a09fd46a8650915dd4118eee4369ae6b8 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Thu, 15 Oct 2020 10:49:43 +0900 Subject: [PATCH 172/446] Clarify the `mod` dir name not to make confusion with the `modules` --- src/test/ui/{mod => modules_and_files_visibility}/mod_file_aux.rs | 0 .../mod_file_correct_spans.rs | 0 .../mod_file_correct_spans.stderr | 0 .../ui/{mod => modules_and_files_visibility}/mod_file_disambig.rs | 0 .../mod_file_disambig.stderr | 0 .../mod_file_disambig_aux.rs | 0 .../mod_file_disambig_aux/mod.rs | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{mod => modules_and_files_visibility}/mod_file_aux.rs (100%) rename src/test/ui/{mod => modules_and_files_visibility}/mod_file_correct_spans.rs (100%) rename src/test/ui/{mod => modules_and_files_visibility}/mod_file_correct_spans.stderr (100%) rename src/test/ui/{mod => modules_and_files_visibility}/mod_file_disambig.rs (100%) rename src/test/ui/{mod => modules_and_files_visibility}/mod_file_disambig.stderr (100%) rename src/test/ui/{mod => modules_and_files_visibility}/mod_file_disambig_aux.rs (100%) rename src/test/ui/{mod => modules_and_files_visibility}/mod_file_disambig_aux/mod.rs (100%) diff --git a/src/test/ui/mod/mod_file_aux.rs b/src/test/ui/modules_and_files_visibility/mod_file_aux.rs similarity index 100% rename from src/test/ui/mod/mod_file_aux.rs rename to src/test/ui/modules_and_files_visibility/mod_file_aux.rs diff --git a/src/test/ui/mod/mod_file_correct_spans.rs b/src/test/ui/modules_and_files_visibility/mod_file_correct_spans.rs similarity index 100% rename from src/test/ui/mod/mod_file_correct_spans.rs rename to src/test/ui/modules_and_files_visibility/mod_file_correct_spans.rs diff --git a/src/test/ui/mod/mod_file_correct_spans.stderr b/src/test/ui/modules_and_files_visibility/mod_file_correct_spans.stderr similarity index 100% rename from src/test/ui/mod/mod_file_correct_spans.stderr rename to src/test/ui/modules_and_files_visibility/mod_file_correct_spans.stderr diff --git a/src/test/ui/mod/mod_file_disambig.rs b/src/test/ui/modules_and_files_visibility/mod_file_disambig.rs similarity index 100% rename from src/test/ui/mod/mod_file_disambig.rs rename to src/test/ui/modules_and_files_visibility/mod_file_disambig.rs diff --git a/src/test/ui/mod/mod_file_disambig.stderr b/src/test/ui/modules_and_files_visibility/mod_file_disambig.stderr similarity index 100% rename from src/test/ui/mod/mod_file_disambig.stderr rename to src/test/ui/modules_and_files_visibility/mod_file_disambig.stderr diff --git a/src/test/ui/mod/mod_file_disambig_aux.rs b/src/test/ui/modules_and_files_visibility/mod_file_disambig_aux.rs similarity index 100% rename from src/test/ui/mod/mod_file_disambig_aux.rs rename to src/test/ui/modules_and_files_visibility/mod_file_disambig_aux.rs diff --git a/src/test/ui/mod/mod_file_disambig_aux/mod.rs b/src/test/ui/modules_and_files_visibility/mod_file_disambig_aux/mod.rs similarity index 100% rename from src/test/ui/mod/mod_file_disambig_aux/mod.rs rename to src/test/ui/modules_and_files_visibility/mod_file_disambig_aux/mod.rs From 3156310eb342bfe441d49bad5249b18ead651cdc Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Thu, 15 Oct 2020 10:53:09 +0900 Subject: [PATCH 173/446] Migrate from `generic` to `generics` --- src/test/ui/{generic => generics}/generic-arg-mismatch-recover.rs | 0 .../ui/{generic => generics}/generic-arg-mismatch-recover.stderr | 0 src/test/ui/{generic => generics}/generic-extern-lifetime.rs | 0 src/test/ui/{generic => generics}/generic-extern-lifetime.stderr | 0 src/test/ui/{generic => generics}/generic-extern.rs | 0 src/test/ui/{generic => generics}/generic-extern.stderr | 0 .../generic-impl-less-params-with-defaults.rs | 0 .../generic-impl-less-params-with-defaults.stderr | 0 .../generic-impl-more-params-with-defaults.rs | 0 .../generic-impl-more-params-with-defaults.stderr | 0 src/test/ui/{generic => generics}/generic-lifetime-trait-impl.rs | 0 .../ui/{generic => generics}/generic-lifetime-trait-impl.stderr | 0 src/test/ui/{generic => generics}/generic-no-mangle.fixed | 0 src/test/ui/{generic => generics}/generic-no-mangle.rs | 0 src/test/ui/{generic => generics}/generic-no-mangle.stderr | 0 .../ui/{generic => generics}/generic-non-trailing-defaults.rs | 0 .../ui/{generic => generics}/generic-non-trailing-defaults.stderr | 0 src/test/ui/{generic => generics}/generic-param-attrs.rs | 0 .../generic-type-less-params-with-defaults.rs | 0 .../generic-type-less-params-with-defaults.stderr | 0 .../generic-type-more-params-with-defaults.rs | 0 .../generic-type-more-params-with-defaults.stderr | 0 .../{generic => generics}/generic-type-params-forward-mention.rs | 0 .../generic-type-params-forward-mention.stderr | 0 .../ui/{generic => generics}/generic-type-params-name-repr.rs | 0 .../ui/{generic => generics}/generic-type-params-name-repr.stderr | 0 .../ui/{generic => generics}/param-in-ct-in-ty-param-default.rs | 0 .../{generic => generics}/param-in-ct-in-ty-param-default.stderr | 0 28 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{generic => generics}/generic-arg-mismatch-recover.rs (100%) rename src/test/ui/{generic => generics}/generic-arg-mismatch-recover.stderr (100%) rename src/test/ui/{generic => generics}/generic-extern-lifetime.rs (100%) rename src/test/ui/{generic => generics}/generic-extern-lifetime.stderr (100%) rename src/test/ui/{generic => generics}/generic-extern.rs (100%) rename src/test/ui/{generic => generics}/generic-extern.stderr (100%) rename src/test/ui/{generic => generics}/generic-impl-less-params-with-defaults.rs (100%) rename src/test/ui/{generic => generics}/generic-impl-less-params-with-defaults.stderr (100%) rename src/test/ui/{generic => generics}/generic-impl-more-params-with-defaults.rs (100%) rename src/test/ui/{generic => generics}/generic-impl-more-params-with-defaults.stderr (100%) rename src/test/ui/{generic => generics}/generic-lifetime-trait-impl.rs (100%) rename src/test/ui/{generic => generics}/generic-lifetime-trait-impl.stderr (100%) rename src/test/ui/{generic => generics}/generic-no-mangle.fixed (100%) rename src/test/ui/{generic => generics}/generic-no-mangle.rs (100%) rename src/test/ui/{generic => generics}/generic-no-mangle.stderr (100%) rename src/test/ui/{generic => generics}/generic-non-trailing-defaults.rs (100%) rename src/test/ui/{generic => generics}/generic-non-trailing-defaults.stderr (100%) rename src/test/ui/{generic => generics}/generic-param-attrs.rs (100%) rename src/test/ui/{generic => generics}/generic-type-less-params-with-defaults.rs (100%) rename src/test/ui/{generic => generics}/generic-type-less-params-with-defaults.stderr (100%) rename src/test/ui/{generic => generics}/generic-type-more-params-with-defaults.rs (100%) rename src/test/ui/{generic => generics}/generic-type-more-params-with-defaults.stderr (100%) rename src/test/ui/{generic => generics}/generic-type-params-forward-mention.rs (100%) rename src/test/ui/{generic => generics}/generic-type-params-forward-mention.stderr (100%) rename src/test/ui/{generic => generics}/generic-type-params-name-repr.rs (100%) rename src/test/ui/{generic => generics}/generic-type-params-name-repr.stderr (100%) rename src/test/ui/{generic => generics}/param-in-ct-in-ty-param-default.rs (100%) rename src/test/ui/{generic => generics}/param-in-ct-in-ty-param-default.stderr (100%) diff --git a/src/test/ui/generic/generic-arg-mismatch-recover.rs b/src/test/ui/generics/generic-arg-mismatch-recover.rs similarity index 100% rename from src/test/ui/generic/generic-arg-mismatch-recover.rs rename to src/test/ui/generics/generic-arg-mismatch-recover.rs diff --git a/src/test/ui/generic/generic-arg-mismatch-recover.stderr b/src/test/ui/generics/generic-arg-mismatch-recover.stderr similarity index 100% rename from src/test/ui/generic/generic-arg-mismatch-recover.stderr rename to src/test/ui/generics/generic-arg-mismatch-recover.stderr diff --git a/src/test/ui/generic/generic-extern-lifetime.rs b/src/test/ui/generics/generic-extern-lifetime.rs similarity index 100% rename from src/test/ui/generic/generic-extern-lifetime.rs rename to src/test/ui/generics/generic-extern-lifetime.rs diff --git a/src/test/ui/generic/generic-extern-lifetime.stderr b/src/test/ui/generics/generic-extern-lifetime.stderr similarity index 100% rename from src/test/ui/generic/generic-extern-lifetime.stderr rename to src/test/ui/generics/generic-extern-lifetime.stderr diff --git a/src/test/ui/generic/generic-extern.rs b/src/test/ui/generics/generic-extern.rs similarity index 100% rename from src/test/ui/generic/generic-extern.rs rename to src/test/ui/generics/generic-extern.rs diff --git a/src/test/ui/generic/generic-extern.stderr b/src/test/ui/generics/generic-extern.stderr similarity index 100% rename from src/test/ui/generic/generic-extern.stderr rename to src/test/ui/generics/generic-extern.stderr diff --git a/src/test/ui/generic/generic-impl-less-params-with-defaults.rs b/src/test/ui/generics/generic-impl-less-params-with-defaults.rs similarity index 100% rename from src/test/ui/generic/generic-impl-less-params-with-defaults.rs rename to src/test/ui/generics/generic-impl-less-params-with-defaults.rs diff --git a/src/test/ui/generic/generic-impl-less-params-with-defaults.stderr b/src/test/ui/generics/generic-impl-less-params-with-defaults.stderr similarity index 100% rename from src/test/ui/generic/generic-impl-less-params-with-defaults.stderr rename to src/test/ui/generics/generic-impl-less-params-with-defaults.stderr diff --git a/src/test/ui/generic/generic-impl-more-params-with-defaults.rs b/src/test/ui/generics/generic-impl-more-params-with-defaults.rs similarity index 100% rename from src/test/ui/generic/generic-impl-more-params-with-defaults.rs rename to src/test/ui/generics/generic-impl-more-params-with-defaults.rs diff --git a/src/test/ui/generic/generic-impl-more-params-with-defaults.stderr b/src/test/ui/generics/generic-impl-more-params-with-defaults.stderr similarity index 100% rename from src/test/ui/generic/generic-impl-more-params-with-defaults.stderr rename to src/test/ui/generics/generic-impl-more-params-with-defaults.stderr diff --git a/src/test/ui/generic/generic-lifetime-trait-impl.rs b/src/test/ui/generics/generic-lifetime-trait-impl.rs similarity index 100% rename from src/test/ui/generic/generic-lifetime-trait-impl.rs rename to src/test/ui/generics/generic-lifetime-trait-impl.rs diff --git a/src/test/ui/generic/generic-lifetime-trait-impl.stderr b/src/test/ui/generics/generic-lifetime-trait-impl.stderr similarity index 100% rename from src/test/ui/generic/generic-lifetime-trait-impl.stderr rename to src/test/ui/generics/generic-lifetime-trait-impl.stderr diff --git a/src/test/ui/generic/generic-no-mangle.fixed b/src/test/ui/generics/generic-no-mangle.fixed similarity index 100% rename from src/test/ui/generic/generic-no-mangle.fixed rename to src/test/ui/generics/generic-no-mangle.fixed diff --git a/src/test/ui/generic/generic-no-mangle.rs b/src/test/ui/generics/generic-no-mangle.rs similarity index 100% rename from src/test/ui/generic/generic-no-mangle.rs rename to src/test/ui/generics/generic-no-mangle.rs diff --git a/src/test/ui/generic/generic-no-mangle.stderr b/src/test/ui/generics/generic-no-mangle.stderr similarity index 100% rename from src/test/ui/generic/generic-no-mangle.stderr rename to src/test/ui/generics/generic-no-mangle.stderr diff --git a/src/test/ui/generic/generic-non-trailing-defaults.rs b/src/test/ui/generics/generic-non-trailing-defaults.rs similarity index 100% rename from src/test/ui/generic/generic-non-trailing-defaults.rs rename to src/test/ui/generics/generic-non-trailing-defaults.rs diff --git a/src/test/ui/generic/generic-non-trailing-defaults.stderr b/src/test/ui/generics/generic-non-trailing-defaults.stderr similarity index 100% rename from src/test/ui/generic/generic-non-trailing-defaults.stderr rename to src/test/ui/generics/generic-non-trailing-defaults.stderr diff --git a/src/test/ui/generic/generic-param-attrs.rs b/src/test/ui/generics/generic-param-attrs.rs similarity index 100% rename from src/test/ui/generic/generic-param-attrs.rs rename to src/test/ui/generics/generic-param-attrs.rs diff --git a/src/test/ui/generic/generic-type-less-params-with-defaults.rs b/src/test/ui/generics/generic-type-less-params-with-defaults.rs similarity index 100% rename from src/test/ui/generic/generic-type-less-params-with-defaults.rs rename to src/test/ui/generics/generic-type-less-params-with-defaults.rs diff --git a/src/test/ui/generic/generic-type-less-params-with-defaults.stderr b/src/test/ui/generics/generic-type-less-params-with-defaults.stderr similarity index 100% rename from src/test/ui/generic/generic-type-less-params-with-defaults.stderr rename to src/test/ui/generics/generic-type-less-params-with-defaults.stderr diff --git a/src/test/ui/generic/generic-type-more-params-with-defaults.rs b/src/test/ui/generics/generic-type-more-params-with-defaults.rs similarity index 100% rename from src/test/ui/generic/generic-type-more-params-with-defaults.rs rename to src/test/ui/generics/generic-type-more-params-with-defaults.rs diff --git a/src/test/ui/generic/generic-type-more-params-with-defaults.stderr b/src/test/ui/generics/generic-type-more-params-with-defaults.stderr similarity index 100% rename from src/test/ui/generic/generic-type-more-params-with-defaults.stderr rename to src/test/ui/generics/generic-type-more-params-with-defaults.stderr diff --git a/src/test/ui/generic/generic-type-params-forward-mention.rs b/src/test/ui/generics/generic-type-params-forward-mention.rs similarity index 100% rename from src/test/ui/generic/generic-type-params-forward-mention.rs rename to src/test/ui/generics/generic-type-params-forward-mention.rs diff --git a/src/test/ui/generic/generic-type-params-forward-mention.stderr b/src/test/ui/generics/generic-type-params-forward-mention.stderr similarity index 100% rename from src/test/ui/generic/generic-type-params-forward-mention.stderr rename to src/test/ui/generics/generic-type-params-forward-mention.stderr diff --git a/src/test/ui/generic/generic-type-params-name-repr.rs b/src/test/ui/generics/generic-type-params-name-repr.rs similarity index 100% rename from src/test/ui/generic/generic-type-params-name-repr.rs rename to src/test/ui/generics/generic-type-params-name-repr.rs diff --git a/src/test/ui/generic/generic-type-params-name-repr.stderr b/src/test/ui/generics/generic-type-params-name-repr.stderr similarity index 100% rename from src/test/ui/generic/generic-type-params-name-repr.stderr rename to src/test/ui/generics/generic-type-params-name-repr.stderr diff --git a/src/test/ui/generic/param-in-ct-in-ty-param-default.rs b/src/test/ui/generics/param-in-ct-in-ty-param-default.rs similarity index 100% rename from src/test/ui/generic/param-in-ct-in-ty-param-default.rs rename to src/test/ui/generics/param-in-ct-in-ty-param-default.rs diff --git a/src/test/ui/generic/param-in-ct-in-ty-param-default.stderr b/src/test/ui/generics/param-in-ct-in-ty-param-default.stderr similarity index 100% rename from src/test/ui/generic/param-in-ct-in-ty-param-default.stderr rename to src/test/ui/generics/param-in-ct-in-ty-param-default.stderr From 684d142e700cf52ee2fe0405e43568ddd324c57c Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Thu, 15 Oct 2020 14:04:57 +0900 Subject: [PATCH 174/446] Set .llvmbc and .llvmcmd sections as allocatable --- compiler/rustc_codegen_llvm/src/back/write.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index f35c1016f86..7236784853e 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -936,8 +936,8 @@ unsafe fn embed_bitcode( llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); } else { let asm = " - .section .llvmbc,\"e\" - .section .llvmcmd,\"e\" + .section .llvmbc,\"a\" + .section .llvmcmd,\"a\" "; llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); } From 8c7a8a62ddffe8bd9c144a8647a31c8138366f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 14 Oct 2020 02:46:21 +0200 Subject: [PATCH 175/446] Turn Outcome into an opaque type to remove some runtime checks --- .../src/obligation_forest/mod.rs | 97 +-- .../src/obligation_forest/tests.rs | 559 ++++++++---------- .../src/traits/fulfill.rs | 10 +- 3 files changed, 319 insertions(+), 347 deletions(-) diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index aeb926bca3e..a5b2df1da5d 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -251,12 +251,22 @@ enum NodeState { Error, } +/// This trait allows us to have two different Outcome types: +/// - the normal one that does as little as possible +/// - one for tests that does some additional work and checking +pub trait OutcomeTrait { + type Error; + type Obligation; + + fn new() -> Self; + fn mark_not_stalled(&mut self); + fn is_stalled(&self) -> bool; + fn record_completed(&mut self, outcome: &Self::Obligation); + fn record_error(&mut self, error: Self::Error); +} + #[derive(Debug)] pub struct Outcome { - /// Obligations that were completely evaluated, including all - /// (transitive) subobligations. Only computed if requested. - pub completed: Option>, - /// Backtrace of obligations that were found to be in error. pub errors: Vec>, @@ -269,12 +279,29 @@ pub struct Outcome { pub stalled: bool, } -/// Should `process_obligations` compute the `Outcome::completed` field of its -/// result? -#[derive(PartialEq)] -pub enum DoCompleted { - No, - Yes, +impl OutcomeTrait for Outcome { + type Error = Error; + type Obligation = O; + + fn new() -> Self { + Self { stalled: true, errors: vec![] } + } + + fn mark_not_stalled(&mut self) { + self.stalled = false; + } + + fn is_stalled(&self) -> bool { + self.stalled + } + + fn record_completed(&mut self, _outcome: &Self::Obligation) { + // do nothing + } + + fn record_error(&mut self, error: Self::Error) { + self.errors.push(error) + } } #[derive(Debug, PartialEq, Eq)] @@ -363,8 +390,7 @@ impl ObligationForest { .map(|(index, _node)| Error { error: error.clone(), backtrace: self.error_at(index) }) .collect(); - let successful_obligations = self.compress(DoCompleted::Yes); - assert!(successful_obligations.unwrap().is_empty()); + self.compress(|_| assert!(false)); errors } @@ -392,16 +418,12 @@ impl ObligationForest { /// be called in a loop until `outcome.stalled` is false. /// /// This _cannot_ be unrolled (presently, at least). - pub fn process_obligations

( - &mut self, - processor: &mut P, - do_completed: DoCompleted, - ) -> Outcome + pub fn process_obligations(&mut self, processor: &mut P) -> OUT where P: ObligationProcessor, + OUT: OutcomeTrait>, { - let mut errors = vec![]; - let mut stalled = true; + let mut outcome = OUT::new(); // Note that the loop body can append new nodes, and those new nodes // will then be processed by subsequent iterations of the loop. @@ -429,7 +451,7 @@ impl ObligationForest { } ProcessResult::Changed(children) => { // We are not (yet) stalled. - stalled = false; + outcome.mark_not_stalled(); node.state.set(NodeState::Success); for child in children { @@ -442,28 +464,22 @@ impl ObligationForest { } } ProcessResult::Error(err) => { - stalled = false; - errors.push(Error { error: err, backtrace: self.error_at(index) }); + outcome.mark_not_stalled(); + outcome.record_error(Error { error: err, backtrace: self.error_at(index) }); } } index += 1; } - if stalled { - // There's no need to perform marking, cycle processing and compression when nothing - // changed. - return Outcome { - completed: if do_completed == DoCompleted::Yes { Some(vec![]) } else { None }, - errors, - stalled, - }; + // There's no need to perform marking, cycle processing and compression when nothing + // changed. + if !outcome.is_stalled() { + self.mark_successes(); + self.process_cycles(processor); + self.compress(|obl| outcome.record_completed(obl)); } - self.mark_successes(); - self.process_cycles(processor); - let completed = self.compress(do_completed); - - Outcome { completed, errors, stalled } + outcome } /// Returns a vector of obligations for `p` and all of its @@ -592,13 +608,12 @@ impl ObligationForest { /// indices and hence invalidates any outstanding indices. `process_cycles` /// must be run beforehand to remove any cycles on `Success` nodes. #[inline(never)] - fn compress(&mut self, do_completed: DoCompleted) -> Option> { + fn compress(&mut self, mut outcome_cb: impl FnMut(&O)) { let orig_nodes_len = self.nodes.len(); let mut node_rewrites: Vec<_> = std::mem::take(&mut self.reused_node_vec); debug_assert!(node_rewrites.is_empty()); node_rewrites.extend(0..orig_nodes_len); let mut dead_nodes = 0; - let mut removed_done_obligations: Vec = vec![]; // Move removable nodes to the end, preserving the order of the // remaining nodes. @@ -628,10 +643,8 @@ impl ObligationForest { } else { self.done_cache.insert(node.obligation.as_cache_key().clone()); } - if do_completed == DoCompleted::Yes { - // Extract the success stories. - removed_done_obligations.push(node.obligation.clone()); - } + // Extract the success stories. + outcome_cb(&node.obligation); node_rewrites[index] = orig_nodes_len; dead_nodes += 1; } @@ -656,8 +669,6 @@ impl ObligationForest { node_rewrites.truncate(0); self.reused_node_vec = node_rewrites; - - if do_completed == DoCompleted::Yes { Some(removed_done_obligations) } else { None } } fn apply_rewrites(&mut self, node_rewrites: &[usize]) { diff --git a/compiler/rustc_data_structures/src/obligation_forest/tests.rs b/compiler/rustc_data_structures/src/obligation_forest/tests.rs index 01652465eea..371c62c063f 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/tests.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/tests.rs @@ -17,6 +17,40 @@ struct ClosureObligationProcessor { marker: PhantomData<(O, E)>, } +struct TestOutcome { + pub completed: Vec, + pub errors: Vec>, + pub stalled: bool, +} + +impl OutcomeTrait for TestOutcome +where + O: Clone, +{ + type Error = Error; + type Obligation = O; + + fn new() -> Self { + Self { errors: vec![], stalled: false, completed: vec![] } + } + + fn mark_not_stalled(&mut self) { + self.stalled = false; + } + + fn is_stalled(&self) -> bool { + self.stalled + } + + fn record_completed(&mut self, outcome: &Self::Obligation) { + self.completed.push(outcome.clone()) + } + + fn record_error(&mut self, error: Self::Error) { + self.errors.push(error) + } +} + #[allow(non_snake_case)] fn C(of: OF, bf: BF) -> ClosureObligationProcessor where @@ -65,20 +99,17 @@ fn push_pop() { // A |-> A.1 // |-> A.2 // |-> A.3 - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), - "B" => ProcessResult::Error("B is for broken"), - "C" => ProcessResult::Changed(vec![]), - "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap(), vec!["C"]); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), + "B" => ProcessResult::Error("B is for broken"), + "C" => ProcessResult::Changed(vec![]), + "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged, + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok, vec!["C"]); assert_eq!(err, vec![Error { error: "B is for broken", backtrace: vec!["B"] }]); // second round: two delays, one success, creating an uneven set of subtasks: @@ -88,60 +119,51 @@ fn push_pop() { // D |-> D.1 // |-> D.2 forest.register_obligation("D"); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A.1" => ProcessResult::Unchanged, - "A.2" => ProcessResult::Unchanged, - "A.3" => ProcessResult::Changed(vec!["A.3.i"]), - "D" => ProcessResult::Changed(vec!["D.1", "D.2"]), - "A.3.i" | "D.1" | "D.2" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap(), Vec::<&'static str>::new()); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A.1" => ProcessResult::Unchanged, + "A.2" => ProcessResult::Unchanged, + "A.3" => ProcessResult::Changed(vec!["A.3.i"]), + "D" => ProcessResult::Changed(vec!["D.1", "D.2"]), + "A.3.i" | "D.1" | "D.2" => ProcessResult::Unchanged, + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok, Vec::<&'static str>::new()); assert_eq!(err, Vec::new()); // third round: ok in A.1 but trigger an error in A.2. Check that it // propagates to A, but not D.1 or D.2. // D |-> D.1 |-> D.1.i // |-> D.2 |-> D.2.i - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A.1" => ProcessResult::Changed(vec![]), - "A.2" => ProcessResult::Error("A is for apple"), - "A.3.i" => ProcessResult::Changed(vec![]), - "D.1" => ProcessResult::Changed(vec!["D.1.i"]), - "D.2" => ProcessResult::Changed(vec!["D.2.i"]), - "D.1.i" | "D.2.i" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - let mut ok = ok.unwrap(); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A.1" => ProcessResult::Changed(vec![]), + "A.2" => ProcessResult::Error("A is for apple"), + "A.3.i" => ProcessResult::Changed(vec![]), + "D.1" => ProcessResult::Changed(vec!["D.1.i"]), + "D.2" => ProcessResult::Changed(vec!["D.2.i"]), + "D.1.i" | "D.2.i" => ProcessResult::Unchanged, + _ => unreachable!(), + }, + |_| {}, + )); + let mut ok = ok; ok.sort(); assert_eq!(ok, vec!["A.1", "A.3", "A.3.i"]); assert_eq!(err, vec![Error { error: "A is for apple", backtrace: vec!["A.2", "A"] }]); // fourth round: error in D.1.i - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "D.1.i" => ProcessResult::Error("D is for dumb"), - "D.2.i" => ProcessResult::Changed(vec![]), - _ => panic!("unexpected obligation {:?}", obligation), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - let mut ok = ok.unwrap(); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "D.1.i" => ProcessResult::Error("D is for dumb"), + "D.2.i" => ProcessResult::Changed(vec![]), + _ => panic!("unexpected obligation {:?}", obligation), + }, + |_| {}, + )); + let mut ok = ok; ok.sort(); assert_eq!(ok, vec!["D.2", "D.2.i"]); assert_eq!(err, vec![Error { error: "D is for dumb", backtrace: vec!["D.1.i", "D.1", "D"] }]); @@ -160,72 +182,60 @@ fn success_in_grandchildren() { let mut forest = ObligationForest::new(); forest.register_obligation("A"); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), - "A.1" => ProcessResult::Changed(vec![]), - "A.2" => ProcessResult::Changed(vec!["A.2.i", "A.2.ii"]), - "A.3" => ProcessResult::Changed(vec![]), - "A.2.i" | "A.2.ii" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - let mut ok = ok.unwrap(); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), + "A.1" => ProcessResult::Changed(vec![]), + "A.2" => ProcessResult::Changed(vec!["A.2.i", "A.2.ii"]), + "A.3" => ProcessResult::Changed(vec![]), + "A.2.i" | "A.2.ii" => ProcessResult::Unchanged, + _ => unreachable!(), + }, + |_| {}, + )); + let mut ok = ok; ok.sort(); assert_eq!(ok, vec!["A.1", "A.3"]); assert!(err.is_empty()); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A.2.i" => ProcessResult::Unchanged, - "A.2.ii" => ProcessResult::Changed(vec![]), - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap(), vec!["A.2.ii"]); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A.2.i" => ProcessResult::Unchanged, + "A.2.ii" => ProcessResult::Changed(vec![]), + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok, vec!["A.2.ii"]); assert!(err.is_empty()); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A.2.i" => ProcessResult::Changed(vec!["A.2.i.a"]), - "A.2.i.a" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert!(ok.unwrap().is_empty()); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A.2.i" => ProcessResult::Changed(vec!["A.2.i.a"]), + "A.2.i.a" => ProcessResult::Unchanged, + _ => unreachable!(), + }, + |_| {}, + )); + assert!(ok.is_empty()); assert!(err.is_empty()); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A.2.i.a" => ProcessResult::Changed(vec![]), - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - let mut ok = ok.unwrap(); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A.2.i.a" => ProcessResult::Changed(vec![]), + _ => unreachable!(), + }, + |_| {}, + )); + let mut ok = ok; ok.sort(); assert_eq!(ok, vec!["A", "A.2", "A.2.i", "A.2.i.a"]); assert!(err.is_empty()); - let Outcome { completed: ok, errors: err, .. } = - forest.process_obligations(&mut C(|_| unreachable!(), |_| {}), DoCompleted::Yes); + let TestOutcome { completed: ok, errors: err, .. } = + forest.process_obligations(&mut C(|_| unreachable!(), |_| {})); - assert!(ok.unwrap().is_empty()); + assert!(ok.is_empty()); assert!(err.is_empty()); } @@ -235,18 +245,15 @@ fn to_errors_no_throw() { // yields to correct errors (and does not panic, in particular). let mut forest = ObligationForest::new(); forest.register_obligation("A"); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), - "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap().len(), 0); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), + "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged, + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok.len(), 0); assert_eq!(err.len(), 0); let errors = forest.to_errors(()); assert_eq!(errors[0].backtrace, vec!["A.1", "A"]); @@ -260,51 +267,42 @@ fn diamond() { // check that diamond dependencies are handled correctly let mut forest = ObligationForest::new(); forest.register_obligation("A"); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A" => ProcessResult::Changed(vec!["A.1", "A.2"]), - "A.1" | "A.2" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap().len(), 0); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A" => ProcessResult::Changed(vec!["A.1", "A.2"]), + "A.1" | "A.2" => ProcessResult::Unchanged, + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok.len(), 0); assert_eq!(err.len(), 0); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A.1" => ProcessResult::Changed(vec!["D"]), - "A.2" => ProcessResult::Changed(vec!["D"]), - "D" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap().len(), 0); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A.1" => ProcessResult::Changed(vec!["D"]), + "A.2" => ProcessResult::Changed(vec!["D"]), + "D" => ProcessResult::Unchanged, + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok.len(), 0); assert_eq!(err.len(), 0); let mut d_count = 0; - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "D" => { - d_count += 1; - ProcessResult::Changed(vec![]) - } - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "D" => { + d_count += 1; + ProcessResult::Changed(vec![]) + } + _ => unreachable!(), + }, + |_| {}, + )); assert_eq!(d_count, 1); - let mut ok = ok.unwrap(); + let mut ok = ok; ok.sort(); assert_eq!(ok, vec!["A", "A.1", "A.2", "D"]); assert_eq!(err.len(), 0); @@ -313,51 +311,42 @@ fn diamond() { assert_eq!(errors.len(), 0); forest.register_obligation("A'"); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A'" => ProcessResult::Changed(vec!["A'.1", "A'.2"]), - "A'.1" | "A'.2" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap().len(), 0); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A'" => ProcessResult::Changed(vec!["A'.1", "A'.2"]), + "A'.1" | "A'.2" => ProcessResult::Unchanged, + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok.len(), 0); assert_eq!(err.len(), 0); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A'.1" => ProcessResult::Changed(vec!["D'", "A'"]), - "A'.2" => ProcessResult::Changed(vec!["D'"]), - "D'" | "A'" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap().len(), 0); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A'.1" => ProcessResult::Changed(vec!["D'", "A'"]), + "A'.2" => ProcessResult::Changed(vec!["D'"]), + "D'" | "A'" => ProcessResult::Unchanged, + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok.len(), 0); assert_eq!(err.len(), 0); let mut d_count = 0; - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "D'" => { - d_count += 1; - ProcessResult::Error("operation failed") - } - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "D'" => { + d_count += 1; + ProcessResult::Error("operation failed") + } + _ => unreachable!(), + }, + |_| {}, + )); assert_eq!(d_count, 1); - assert_eq!(ok.unwrap().len(), 0); + assert_eq!(ok.len(), 0); assert_eq!( err, vec![super::Error { error: "operation failed", backtrace: vec!["D'", "A'.1", "A'"] }] @@ -375,35 +364,27 @@ fn done_dependency() { forest.register_obligation("B: Sized"); forest.register_obligation("C: Sized"); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(vec![]), - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - let mut ok = ok.unwrap(); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(vec![]), + _ => unreachable!(), + }, + |_| {}, + )); + let mut ok = ok; ok.sort(); assert_eq!(ok, vec!["A: Sized", "B: Sized", "C: Sized"]); assert_eq!(err.len(), 0); forest.register_obligation("(A,B,C): Sized"); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "(A,B,C): Sized" => { - ProcessResult::Changed(vec!["A: Sized", "B: Sized", "C: Sized"]) - } - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap(), vec!["(A,B,C): Sized"]); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "(A,B,C): Sized" => ProcessResult::Changed(vec!["A: Sized", "B: Sized", "C: Sized"]), + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok, vec!["(A,B,C): Sized"]); assert_eq!(err.len(), 0); } @@ -416,64 +397,52 @@ fn orphan() { forest.register_obligation("C1"); forest.register_obligation("C2"); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A" => ProcessResult::Changed(vec!["D", "E"]), - "B" => ProcessResult::Unchanged, - "C1" => ProcessResult::Changed(vec![]), - "C2" => ProcessResult::Changed(vec![]), - "D" | "E" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - let mut ok = ok.unwrap(); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A" => ProcessResult::Changed(vec!["D", "E"]), + "B" => ProcessResult::Unchanged, + "C1" => ProcessResult::Changed(vec![]), + "C2" => ProcessResult::Changed(vec![]), + "D" | "E" => ProcessResult::Unchanged, + _ => unreachable!(), + }, + |_| {}, + )); + let mut ok = ok; ok.sort(); assert_eq!(ok, vec!["C1", "C2"]); assert_eq!(err.len(), 0); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "D" | "E" => ProcessResult::Unchanged, - "B" => ProcessResult::Changed(vec!["D"]), - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap().len(), 0); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "D" | "E" => ProcessResult::Unchanged, + "B" => ProcessResult::Changed(vec!["D"]), + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok.len(), 0); assert_eq!(err.len(), 0); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "D" => ProcessResult::Unchanged, - "E" => ProcessResult::Error("E is for error"), - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap().len(), 0); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "D" => ProcessResult::Unchanged, + "E" => ProcessResult::Error("E is for error"), + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok.len(), 0); assert_eq!(err, vec![super::Error { error: "E is for error", backtrace: vec!["E", "A"] }]); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "D" => ProcessResult::Error("D is dead"), - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap().len(), 0); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "D" => ProcessResult::Error("D is dead"), + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok.len(), 0); assert_eq!(err, vec![super::Error { error: "D is dead", backtrace: vec!["D"] }]); let errors = forest.to_errors(()); @@ -487,35 +456,29 @@ fn simultaneous_register_and_error() { forest.register_obligation("A"); forest.register_obligation("B"); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A" => ProcessResult::Error("An error"), - "B" => ProcessResult::Changed(vec!["A"]), - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap().len(), 0); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A" => ProcessResult::Error("An error"), + "B" => ProcessResult::Changed(vec!["A"]), + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok.len(), 0); assert_eq!(err, vec![super::Error { error: "An error", backtrace: vec!["A"] }]); let mut forest = ObligationForest::new(); forest.register_obligation("B"); forest.register_obligation("A"); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A" => ProcessResult::Error("An error"), - "B" => ProcessResult::Changed(vec!["A"]), - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap().len(), 0); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A" => ProcessResult::Error("An error"), + "B" => ProcessResult::Changed(vec!["A"]), + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok.len(), 0); assert_eq!(err, vec![super::Error { error: "An error", backtrace: vec!["A"] }]); } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 97dd180b27b..88424d449ed 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -1,6 +1,6 @@ use crate::infer::{InferCtxt, TyOrConstInferVar}; use rustc_data_structures::obligation_forest::ProcessResult; -use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation}; +use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome}; use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; use rustc_errors::ErrorReported; use rustc_infer::traits::{TraitEngine, TraitEngineExt as _, TraitObligation}; @@ -129,13 +129,11 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { debug!("select: starting another iteration"); // Process pending obligations. - let outcome = self.predicates.process_obligations( - &mut FulfillProcessor { + let outcome: Outcome<_, _> = + self.predicates.process_obligations(&mut FulfillProcessor { selcx, register_region_obligations: self.register_region_obligations, - }, - DoCompleted::No, - ); + }); debug!("select: outcome={:#?}", outcome); // FIXME: if we kept the original cache key, we could mark projection From 2c1e8cfc622652ebfb1f0256aa8d2afae91bf416 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 14 Oct 2020 18:42:13 +0200 Subject: [PATCH 176/446] Remove rustc_session::config::Config The wrapper type led to tons of target.target across the compiler. Its ptr_width field isn't required any more, as target_pointer_width is already present in parsed form. --- clippy_lints/src/trivially_copy_pass_by_ref.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/trivially_copy_pass_by_ref.rs b/clippy_lints/src/trivially_copy_pass_by_ref.rs index 1f06d2dbe91..d92eb86fb2e 100644 --- a/clippy_lints/src/trivially_copy_pass_by_ref.rs +++ b/clippy_lints/src/trivially_copy_pass_by_ref.rs @@ -9,10 +9,10 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, HirId, ItemKind, MutTy, Mutability, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::config::Config as SessionConfig; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; use rustc_target::abi::LayoutOf; +use rustc_target::spec::Target; use rustc_target::spec::abi::Abi; declare_clippy_lint! { @@ -60,9 +60,9 @@ pub struct TriviallyCopyPassByRef { } impl<'tcx> TriviallyCopyPassByRef { - pub fn new(limit: Option, target: &SessionConfig) -> Self { + pub fn new(limit: Option, target: &Target) -> Self { let limit = limit.unwrap_or_else(|| { - let bit_width = u64::from(target.ptr_width); + let bit_width = u64::from(target.pointer_width); // Cap the calculated bit width at 32-bits to reduce // portability problems between 32 and 64-bit targets let bit_width = cmp::min(bit_width, 32); From 000ec5e2f8e7bf3f5da59f6f219fe02dff42d116 Mon Sep 17 00:00:00 2001 From: Ryan Scott Date: Wed, 14 Oct 2020 16:50:00 +1100 Subject: [PATCH 177/446] Made slice sort documentation consistent between stable and unstable versions --- library/alloc/src/slice.rs | 14 +++++++------- library/core/src/slice/mod.rs | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 79403cf8687..706d563f8fb 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -169,7 +169,7 @@ mod hack { impl [T] { /// Sorts the slice. /// - /// This sort is stable (i.e., does not reorder equal elements) and `O(n * log(n))` worst-case. + /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*)) worst-case. /// /// When applicable, unstable sorting is preferred because it is generally faster than stable /// sorting and it doesn't allocate auxiliary memory. @@ -204,7 +204,7 @@ impl [T] { /// Sorts the slice with a comparator function. /// - /// This sort is stable (i.e., does not reorder equal elements) and `O(n * log(n))` worst-case. + /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*)) worst-case. /// /// The comparator function must define a total ordering for the elements in the slice. If /// the ordering is not total, the order of the elements is unspecified. An order is a @@ -258,8 +258,8 @@ impl [T] { /// Sorts the slice with a key extraction function. /// - /// This sort is stable (i.e., does not reorder equal elements) and `O(m * n * log(n))` - /// worst-case, where the key function is `O(m)`. + /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* \* log(*n*)) + /// worst-case, where the key function is *O*(*m*). /// /// For expensive key functions (e.g. functions that are not simple property accesses or /// basic operations), [`sort_by_cached_key`](#method.sort_by_cached_key) is likely to be @@ -301,8 +301,8 @@ impl [T] { /// /// During sorting, the key function is called only once per element. /// - /// This sort is stable (i.e., does not reorder equal elements) and `O(m * n + n * log(n))` - /// worst-case, where the key function is `O(m)`. + /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* + *n* \* log(*n*)) + /// worst-case, where the key function is *O*(*m*). /// /// For simple key functions (e.g., functions that are property accesses or /// basic operations), [`sort_by_key`](#method.sort_by_key) is likely to be @@ -946,7 +946,7 @@ where /// 1. for every `i` in `1..runs.len()`: `runs[i - 1].len > runs[i].len` /// 2. for every `i` in `2..runs.len()`: `runs[i - 2].len > runs[i - 1].len + runs[i].len` /// -/// The invariants ensure that the total running time is `O(n * log(n))` worst-case. +/// The invariants ensure that the total running time is *O*(*n* \* log(*n*)) worst-case. fn merge_sort(v: &mut [T], mut is_less: F) where F: FnMut(&T, &T) -> bool, diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index d0d88c01f5b..3b428eba131 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1948,10 +1948,10 @@ impl [T] { /// /// The comparator function must define a total ordering for the elements in the slice. If /// the ordering is not total, the order of the elements is unspecified. An order is a - /// total order if it is (for all a, b and c): + /// total order if it is (for all `a`, `b` and `c`): /// - /// * total and antisymmetric: exactly one of a < b, a == b or a > b is true; and - /// * transitive, a < b and b < c implies a < c. The same must hold for both == and >. + /// * total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true, and + /// * transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. /// /// For example, while [`f64`] doesn't implement [`Ord`] because `NaN != NaN`, we can use /// `partial_cmp` as our sort function when we know the slice doesn't contain a `NaN`. From 8446d949f1d53b2c7ee4155f8fbf3d1390e3f203 Mon Sep 17 00:00:00 2001 From: Ryan Scott Date: Wed, 14 Oct 2020 16:58:59 +1100 Subject: [PATCH 178/446] Following #74010 by converting some newer cases of backticked O notations to be italicized --- library/alloc/src/raw_vec.rs | 2 +- library/alloc/src/vec.rs | 2 +- library/core/src/str/traits.rs | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 1844d3ae004..7c834f034c1 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -259,7 +259,7 @@ impl RawVec { /// Ensures that the buffer contains at least enough space to hold `len + /// additional` elements. If it doesn't already have enough capacity, will /// reallocate enough space plus comfortable slack space to get amortized - /// `O(1)` behavior. Will limit this behavior if it would needlessly cause + /// *O*(1) behavior. Will limit this behavior if it would needlessly cause /// itself to panic. /// /// If `len` exceeds `self.capacity()`, this may fail to actually allocate diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 5e68f76693f..808adb5d47c 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -259,7 +259,7 @@ use crate::raw_vec::RawVec; /// `Vec` does not guarantee any particular growth strategy when reallocating /// when full, nor when [`reserve`] is called. The current strategy is basic /// and it may prove desirable to use a non-constant growth factor. Whatever -/// strategy is used will of course guarantee `O(1)` amortized [`push`]. +/// strategy is used will of course guarantee *O*(1) amortized [`push`]. /// /// `vec![x; n]`, `vec![a, b, c, d]`, and /// [`Vec::with_capacity(n)`][`Vec::with_capacity`], will all produce a `Vec` diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index 4f8aa246e52..af1ce007e8b 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -89,7 +89,7 @@ fn str_index_overflow_fail() -> ! { /// self`. Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`. Unlike /// other indexing operations, this can never panic. /// -/// This operation is `O(1)`. +/// This operation is *O*(1). /// /// Prior to 1.20.0, these indexing operations were still supported by /// direct implementation of `Index` and `IndexMut`. @@ -130,7 +130,7 @@ unsafe impl SliceIndex for ops::RangeFull { /// Returns a slice of the given string from the byte range /// [`begin`, `end`). /// -/// This operation is `O(1)`. +/// This operation is *O*(1). /// /// Prior to 1.20.0, these indexing operations were still supported by /// direct implementation of `Index` and `IndexMut`. @@ -237,7 +237,7 @@ unsafe impl SliceIndex for ops::Range { /// Returns a slice of the given string from the byte range [`0`, `end`). /// Equivalent to `&self[0 .. end]` or `&mut self[0 .. end]`. /// -/// This operation is `O(1)`. +/// This operation is *O*(1). /// /// Prior to 1.20.0, these indexing operations were still supported by /// direct implementation of `Index` and `IndexMut`. @@ -308,7 +308,7 @@ unsafe impl SliceIndex for ops::RangeTo { /// `len`). Equivalent to `&self[begin .. len]` or `&mut self[begin .. /// len]`. /// -/// This operation is `O(1)`. +/// This operation is *O*(1). /// /// Prior to 1.20.0, these indexing operations were still supported by /// direct implementation of `Index` and `IndexMut`. @@ -385,7 +385,7 @@ unsafe impl SliceIndex for ops::RangeFrom { /// self[begin .. end + 1]`, except if `end` has the maximum value for /// `usize`. /// -/// This operation is `O(1)`. +/// This operation is *O*(1). /// /// # Panics /// @@ -441,7 +441,7 @@ unsafe impl SliceIndex for ops::RangeInclusive { /// Equivalent to `&self [0 .. end + 1]`, except if `end` has the maximum /// value for `usize`. /// -/// This operation is `O(1)`. +/// This operation is *O*(1). /// /// # Panics /// From e2efec89764f4ee68cc9f537eda722d2fb830bba Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 15 Oct 2020 09:28:27 -0400 Subject: [PATCH 179/446] Prevent miscompilation in trivial loop {} Ideally, we would want to handle a broader set of cases to fully fix the underlying bug here. That is currently relatively expensive at compile and runtime, so we don't do that for now. --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 10 +++++----- compiler/rustc_codegen_ssa/src/mir/block.rs | 20 +++++++++++++++++-- compiler/rustc_codegen_ssa/src/mir/mod.rs | 2 +- .../rustc_codegen_ssa/src/traits/intrinsic.rs | 4 +++- src/test/codegen/loop.rs | 15 ++++++++++++++ 5 files changed, 42 insertions(+), 9 deletions(-) create mode 100644 src/test/codegen/loop.rs diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index e76e86f5651..368aba6eae0 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -334,8 +334,8 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { self.call(expect, &[cond, self.const_bool(expected)], None) } - fn sideeffect(&mut self) { - if self.tcx.sess.opts.debugging_opts.insert_sideeffect { + fn sideeffect(&mut self, unconditional: bool) { + if unconditional || self.tcx.sess.opts.debugging_opts.insert_sideeffect { let fnname = self.get_intrinsic(&("llvm.sideeffect")); self.call(fnname, &[], None); } @@ -390,7 +390,7 @@ fn codegen_msvc_try( ) { let llfn = get_rust_try_fn(bx, &mut |mut bx| { bx.set_personality_fn(bx.eh_personality()); - bx.sideeffect(); + bx.sideeffect(false); let mut normal = bx.build_sibling_block("normal"); let mut catchswitch = bx.build_sibling_block("catchswitch"); @@ -553,7 +553,7 @@ fn codegen_gnu_try( // call %catch_func(%data, %ptr) // ret 1 - bx.sideeffect(); + bx.sideeffect(false); let mut then = bx.build_sibling_block("then"); let mut catch = bx.build_sibling_block("catch"); @@ -615,7 +615,7 @@ fn codegen_emcc_try( // call %catch_func(%data, %catch_data) // ret 1 - bx.sideeffect(); + bx.sideeffect(false); let mut then = bx.build_sibling_block("then"); let mut catch = bx.build_sibling_block("catch"); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 353189ae1f0..1e61f3ba2df 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -163,7 +163,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { target <= self.bb && target.start_location().is_predecessor_of(self.bb.start_location(), mir) }) { - bx.sideeffect(); + bx.sideeffect(false); } } } @@ -964,7 +964,23 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::TerminatorKind::Goto { target } => { - helper.maybe_sideeffect(self.mir, &mut bx, &[target]); + if bb == target { + // This is an unconditional branch back to this same basic + // block. That means we have something like a `loop {}` + // statement. Currently LLVM miscompiles this because it + // assumes forward progress. We want to prevent this in all + // cases, but that has a fairly high cost to compile times + // currently. Instead, try to handle this specific case + // which comes up commonly in practice (e.g., in embedded + // code). + // + // The `true` here means we insert side effects regardless + // of -Zinsert-sideeffect being passed on unconditional + // branching to the same basic block. + bx.sideeffect(true); + } else { + helper.maybe_sideeffect(self.mir, &mut bx, &[target]); + } helper.funclet_br(self, &mut bx, target); } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 64d456fb7aa..bff263567bf 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -153,7 +153,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx.set_personality_fn(cx.eh_personality()); } - bx.sideeffect(); + bx.sideeffect(false); let cleanup_kinds = analyze::cleanup_kinds(&mir); // Allocate a `Block` for every basic block, except diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs index ccd294d92b2..ac3c99f9c90 100644 --- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs @@ -20,7 +20,9 @@ pub trait IntrinsicCallMethods<'tcx>: BackendTypes { fn abort(&mut self); fn assume(&mut self, val: Self::Value); fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value; - fn sideeffect(&mut self); + /// Normally, sideeffect is only emitted if -Zinsert-sideeffect is passed; + /// in some cases though we want to emit it regardless. + fn sideeffect(&mut self, unconditional: bool); /// Trait method used to inject `va_start` on the "spoofed" `VaListImpl` in /// Rust defined C-variadic functions. fn va_start(&mut self, val: Self::Value) -> Self::Value; diff --git a/src/test/codegen/loop.rs b/src/test/codegen/loop.rs new file mode 100644 index 00000000000..e54298eed05 --- /dev/null +++ b/src/test/codegen/loop.rs @@ -0,0 +1,15 @@ +// compile-flags: -C opt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @check_loop +#[no_mangle] +pub fn check_loop() -> u8 { + // CHECK-NOT: unreachable + call_looper() +} + +#[no_mangle] +fn call_looper() -> ! { + loop {} +} From 59f9cf2ac1872866a9a2d4b83f56b96f131a6a5e Mon Sep 17 00:00:00 2001 From: nasso Date: Thu, 15 Oct 2020 18:03:25 +0200 Subject: [PATCH 180/446] Set preferred-dark-theme to the last dark theme If the user doesn't have a preferred dark theme but is already using a dark theme, set the preferred dark theme to be that theme --- src/librustdoc/html/static/storage.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/librustdoc/html/static/storage.js b/src/librustdoc/html/static/storage.js index cf8b806501f..a027d6845ea 100644 --- a/src/librustdoc/html/static/storage.js +++ b/src/librustdoc/html/static/storage.js @@ -1,8 +1,10 @@ // From rust: /* global resourcesSuffix */ +var darkThemes = ["dark", "ayu"]; var currentTheme = document.getElementById("themeStyle"); var mainTheme = document.getElementById("mainThemeStyle"); +var localStoredTheme = getCurrentValue("rustdoc-theme"); var savedHref = []; @@ -179,6 +181,14 @@ var updateSystemTheme = (function() { })(); if (getCurrentValue("rustdoc-use-system-theme") !== "false" && window.matchMedia) { + // update the preferred dark theme if the user is already using a dark theme + // See https://github.com/rust-lang/rust/pull/77809#issuecomment-707875732 + if (getCurrentValue("rustdoc-use-system-theme") === null + && getCurrentValue("rustdoc-preferred-dark-theme") === null + && darkThemes.indexOf(localStoredTheme) >= 0) { + updateLocalStorage("rustdoc-preferred-dark-theme", localStoredTheme); + } + // call the function to initialize the theme at least once! updateSystemTheme(); } else { From adf31e95e44ff0b7fbc798fe2b8cc5a42a3abf4b Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 12 Oct 2020 16:43:49 +0100 Subject: [PATCH 181/446] resolve: suggest variants with placeholders This commit improves the diagnostic modified in rust-lang/rust#77341 to suggest not only those variants which do not have fields, but those with fields (by suggesting with placeholders). Signed-off-by: David Wood --- .../rustc_resolve/src/late/diagnostics.rs | 146 +++++++++++------- ...issue-43871-enum-instead-of-variant.stderr | 21 +++ src/test/ui/glob-resolve1.stderr | 12 +- src/test/ui/issues/issue-73427.stderr | 98 +++++++++++- src/test/ui/resolve/privacy-enum-ctor.stderr | 112 ++++++++++++-- 5 files changed, 311 insertions(+), 78 deletions(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index bee05e77382..8ef99f36a04 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1330,58 +1330,32 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let suggest_only_tuple_variants = matches!(source, PathSource::TupleStruct(..)) || source.is_call(); - let mut suggestable_variants = if suggest_only_tuple_variants { + if suggest_only_tuple_variants { // Suggest only tuple variants regardless of whether they have fields and do not // suggest path with added parenthesis. - variants + let mut suggestable_variants = variants .iter() .filter(|(.., kind)| *kind == CtorKind::Fn) .map(|(variant, ..)| path_names_to_string(variant)) - .collect::>() - } else { - variants - .iter() - .filter(|(_, def_id, kind)| { - // Suggest only variants that have no fields (these can definitely - // be constructed). - let has_fields = - self.r.field_names.get(&def_id).map(|f| f.is_empty()).unwrap_or(false); - match kind { - CtorKind::Const => true, - CtorKind::Fn | CtorKind::Fictive if has_fields => true, - _ => false, - } - }) - .map(|(variant, _, kind)| (path_names_to_string(variant), kind)) - .map(|(variant_str, kind)| { - // Add constructor syntax where appropriate. - match kind { - CtorKind::Const => variant_str, - CtorKind::Fn => format!("({}())", variant_str), - CtorKind::Fictive => format!("({} {{}})", variant_str), - } - }) - .collect::>() - }; + .collect::>(); - let non_suggestable_variant_count = variants.len() - suggestable_variants.len(); + let non_suggestable_variant_count = variants.len() - suggestable_variants.len(); - if !suggestable_variants.is_empty() { - let msg = if non_suggestable_variant_count == 0 && suggestable_variants.len() == 1 { - "try using the enum's variant" - } else { - "try using one of the enum's variants" - }; + if !suggestable_variants.is_empty() { + let msg = if non_suggestable_variant_count == 0 && suggestable_variants.len() == 1 { + "try using the enum's variant" + } else { + "try using one of the enum's variants" + }; - err.span_suggestions( - span, - msg, - suggestable_variants.drain(..), - Applicability::MaybeIncorrect, - ); - } + err.span_suggestions( + span, + msg, + suggestable_variants.drain(..), + Applicability::MaybeIncorrect, + ); + } - if suggest_only_tuple_variants { let source_msg = if source.is_call() { "to construct" } else if matches!(source, PathSource::TupleStruct(..)) { @@ -1408,24 +1382,76 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { )); } } else { - let made_suggestion = non_suggestable_variant_count != variants.len(); - if made_suggestion { - if non_suggestable_variant_count == 1 { - err.help( - "you might have meant to use the enum's other variant that has fields", - ); - } else if non_suggestable_variant_count >= 1 { - err.help( - "you might have meant to use one of the enum's other variants that \ - have fields", - ); - } - } else { - if non_suggestable_variant_count == 1 { - err.help("you might have meant to use the enum's variant"); - } else if non_suggestable_variant_count >= 1 { - err.help("you might have meant to use one of the enum's variants"); + let needs_placeholder = |def_id: DefId, kind: CtorKind| { + let has_no_fields = + self.r.field_names.get(&def_id).map(|f| f.is_empty()).unwrap_or(false); + match kind { + CtorKind::Const => false, + CtorKind::Fn | CtorKind::Fictive if has_no_fields => false, + _ => true, } + }; + + let mut suggestable_variants = variants + .iter() + .filter(|(_, def_id, kind)| !needs_placeholder(*def_id, *kind)) + .map(|(variant, _, kind)| (path_names_to_string(variant), kind)) + .map(|(variant, kind)| match kind { + CtorKind::Const => variant, + CtorKind::Fn => format!("({}())", variant), + CtorKind::Fictive => format!("({} {{}})", variant), + }) + .collect::>(); + + if !suggestable_variants.is_empty() { + let msg = if suggestable_variants.len() == 1 { + "you might have meant to use the following enum variant" + } else { + "you might have meant to use one of the following enum variants" + }; + + err.span_suggestions( + span, + msg, + suggestable_variants.drain(..), + Applicability::MaybeIncorrect, + ); + } + + let mut suggestable_variants_with_placeholders = variants + .iter() + .filter(|(_, def_id, kind)| needs_placeholder(*def_id, *kind)) + .map(|(variant, _, kind)| (path_names_to_string(variant), kind)) + .filter_map(|(variant, kind)| match kind { + CtorKind::Fn => Some(format!("({}(/* fields */))", variant)), + CtorKind::Fictive => Some(format!("({} {{ /* fields */ }})", variant)), + _ => None, + }) + .collect::>(); + + if !suggestable_variants_with_placeholders.is_empty() { + let msg = match ( + suggestable_variants.is_empty(), + suggestable_variants_with_placeholders.len(), + ) { + (true, 1) => "the following enum variant is available", + (true, _) => "the following enum variants are available", + (false, 1) => "alternatively, the following enum variant is available", + (false, _) => "alternatively, the following enum variants are also available", + }; + + err.span_suggestions( + span, + msg, + suggestable_variants_with_placeholders.drain(..), + Applicability::HasPlaceholders, + ); + } + }; + + if def_id.is_local() { + if let Some(span) = self.def_span(def_id) { + err.span_note(span, "the enum is defined here"); } } } diff --git a/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr b/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr index e1325b789d2..62a7649e2ad 100644 --- a/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr +++ b/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr @@ -21,6 +21,11 @@ LL | if let Example(_) = y { | ^^^^^^^ help: try using one of the enum's variants: `Example::Ex` | = help: you might have meant to match against the enum's non-tuple variant +note: the enum is defined here + --> $DIR/issue-43871-enum-instead-of-variant.rs:1:1 + | +LL | enum Example { Ex(String), NotEx } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0423]: expected function, tuple struct or tuple variant, found enum `Void` --> $DIR/issue-43871-enum-instead-of-variant.rs:31:13 @@ -29,6 +34,11 @@ LL | let y = Void(); | ^^^^ | = help: the enum has no tuple variants to construct +note: the enum is defined here + --> $DIR/issue-43871-enum-instead-of-variant.rs:3:1 + | +LL | enum Void {} + | ^^^^^^^^^^^^ error[E0423]: expected function, tuple struct or tuple variant, found enum `ManyVariants` --> $DIR/issue-43871-enum-instead-of-variant.rs:33:13 @@ -38,6 +48,17 @@ LL | let z = ManyVariants(); | = help: the enum has no tuple variants to construct = help: you might have meant to construct one of the enum's non-tuple variants +note: the enum is defined here + --> $DIR/issue-43871-enum-instead-of-variant.rs:5:1 + | +LL | / enum ManyVariants { +LL | | One, +LL | | Two, +LL | | Three, +... | +LL | | Ten, +LL | | } + | |_^ error: aborting due to 5 previous errors diff --git a/src/test/ui/glob-resolve1.stderr b/src/test/ui/glob-resolve1.stderr index 3c818f3ae48..cd128c1ea0b 100644 --- a/src/test/ui/glob-resolve1.stderr +++ b/src/test/ui/glob-resolve1.stderr @@ -24,7 +24,17 @@ error[E0423]: expected value, found enum `B` --> $DIR/glob-resolve1.rs:24:5 | LL | B; - | ^ help: try using the enum's variant: `B::B1` + | ^ + | +note: the enum is defined here + --> $DIR/glob-resolve1.rs:12:5 + | +LL | pub enum B { B1 } + | ^^^^^^^^^^^^^^^^^ +help: you might have meant to use the following enum variant + | +LL | B::B1; + | ^^^^^ error[E0425]: cannot find value `C` in this scope --> $DIR/glob-resolve1.rs:25:5 diff --git a/src/test/ui/issues/issue-73427.stderr b/src/test/ui/issues/issue-73427.stderr index 88d19943f02..4da5305e687 100644 --- a/src/test/ui/issues/issue-73427.stderr +++ b/src/test/ui/issues/issue-73427.stderr @@ -4,8 +4,18 @@ error[E0423]: expected value, found enum `A` LL | A.foo(); | ^ | - = help: you might have meant to use one of the enum's other variants that have fields -help: try using one of the enum's variants +note: the enum is defined here + --> $DIR/issue-73427.rs:1:1 + | +LL | / enum A { +LL | | StructWithFields { x: () }, +LL | | TupleWithFields(()), +LL | | Struct {}, +LL | | Tuple(), +LL | | Unit, +LL | | } + | |_^ +help: you might have meant to use one of the following enum variants | LL | (A::Struct {}).foo(); | ^^^^^^^^^^^^^^ @@ -13,6 +23,12 @@ LL | (A::Tuple()).foo(); | ^^^^^^^^^^^^ LL | A::Unit.foo(); | ^^^^^^^ +help: the following enum variants are available + | +LL | (A::StructWithFields { /* fields */ }).foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | (A::TupleWithFields(/* fields */)).foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0423]: expected value, found enum `B` --> $DIR/issue-73427.rs:31:5 @@ -20,23 +36,69 @@ error[E0423]: expected value, found enum `B` LL | B.foo(); | ^ | - = help: you might have meant to use one of the enum's variants +note: the enum is defined here + --> $DIR/issue-73427.rs:9:1 + | +LL | / enum B { +LL | | StructWithFields { x: () }, +LL | | TupleWithFields(()), +LL | | } + | |_^ +help: the following enum variants are available + | +LL | (B::StructWithFields { /* fields */ }).foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | (B::TupleWithFields(/* fields */)).foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0423]: expected value, found enum `C` --> $DIR/issue-73427.rs:33:5 | LL | C.foo(); - | ^ help: try using one of the enum's variants: `C::Unit` + | ^ | - = help: you might have meant to use one of the enum's other variants that have fields +note: the enum is defined here + --> $DIR/issue-73427.rs:14:1 + | +LL | / enum C { +LL | | StructWithFields { x: () }, +LL | | TupleWithFields(()), +LL | | Unit, +LL | | } + | |_^ +help: you might have meant to use the following enum variant + | +LL | C::Unit.foo(); + | ^^^^^^^ +help: the following enum variants are available + | +LL | (C::StructWithFields { /* fields */ }).foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | (C::TupleWithFields(/* fields */)).foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0423]: expected value, found enum `D` --> $DIR/issue-73427.rs:35:5 | LL | D.foo(); - | ^ help: try using one of the enum's variants: `D::Unit` + | ^ | - = help: you might have meant to use the enum's other variant that has fields +note: the enum is defined here + --> $DIR/issue-73427.rs:20:1 + | +LL | / enum D { +LL | | TupleWithFields(()), +LL | | Unit, +LL | | } + | |_^ +help: you might have meant to use the following enum variant + | +LL | D::Unit.foo(); + | ^^^^^^^ +help: the following enum variant is available + | +LL | (D::TupleWithFields(/* fields */)).foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0423]: expected function, tuple struct or tuple variant, found enum `A` --> $DIR/issue-73427.rs:40:13 @@ -45,6 +107,17 @@ LL | let x = A(3); | ^ | = help: you might have meant to construct one of the enum's non-tuple variants +note: the enum is defined here + --> $DIR/issue-73427.rs:1:1 + | +LL | / enum A { +LL | | StructWithFields { x: () }, +LL | | TupleWithFields(()), +LL | | Struct {}, +LL | | Tuple(), +LL | | Unit, +LL | | } + | |_^ help: try using one of the enum's variants | LL | let x = A::TupleWithFields(3); @@ -59,6 +132,17 @@ LL | if let A(3) = x { } | ^ | = help: you might have meant to match against one of the enum's non-tuple variants +note: the enum is defined here + --> $DIR/issue-73427.rs:1:1 + | +LL | / enum A { +LL | | StructWithFields { x: () }, +LL | | TupleWithFields(()), +LL | | Struct {}, +LL | | Tuple(), +LL | | Unit, +LL | | } + | |_^ help: try using one of the enum's variants | LL | if let A::TupleWithFields(3) = x { } diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr index 77429f800f1..807dadf417b 100644 --- a/src/test/ui/resolve/privacy-enum-ctor.stderr +++ b/src/test/ui/resolve/privacy-enum-ctor.stderr @@ -2,17 +2,57 @@ error[E0423]: expected value, found enum `n::Z` --> $DIR/privacy-enum-ctor.rs:23:9 | LL | n::Z; - | ^^^^ help: try using one of the enum's variants: `m::Z::Unit` + | ^^^^ | - = help: you might have meant to use one of the enum's other variants that have fields +note: the enum is defined here + --> $DIR/privacy-enum-ctor.rs:11:9 + | +LL | / pub(in m) enum Z { +LL | | Fn(u8), +LL | | Struct { +LL | | s: u8, +LL | | }, +LL | | Unit, +LL | | } + | |_________^ +help: you might have meant to use the following enum variant + | +LL | m::Z::Unit; + | ^^^^^^^^^^ +help: the following enum variants are available + | +LL | (m::Z::Fn(/* fields */)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | (m::Z::Struct { /* fields */ }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0423]: expected value, found enum `Z` --> $DIR/privacy-enum-ctor.rs:25:9 | LL | Z; - | ^ help: try using one of the enum's variants: `m::Z::Unit` + | ^ | - = help: you might have meant to use one of the enum's other variants that have fields +note: the enum is defined here + --> $DIR/privacy-enum-ctor.rs:11:9 + | +LL | / pub(in m) enum Z { +LL | | Fn(u8), +LL | | Struct { +LL | | s: u8, +LL | | }, +LL | | Unit, +LL | | } + | |_________^ +help: you might have meant to use the following enum variant + | +LL | m::Z::Unit; + | ^^^^^^^^^^ +help: the following enum variants are available + | +LL | (m::Z::Fn(/* fields */)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | (m::Z::Struct { /* fields */ }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0423]: expected value, found struct variant `Z::Struct` --> $DIR/privacy-enum-ctor.rs:29:20 @@ -34,11 +74,27 @@ LL | fn f() { LL | let _: E = m::E; | ^^^^ | - = help: you might have meant to use one of the enum's other variants that have fields -help: try using one of the enum's variants +note: the enum is defined here + --> $DIR/privacy-enum-ctor.rs:2:5 + | +LL | / pub enum E { +LL | | Fn(u8), +LL | | Struct { +LL | | s: u8, +LL | | }, +LL | | Unit, +LL | | } + | |_____^ +help: you might have meant to use the following enum variant | LL | let _: E = E::Unit; | ^^^^^^^ +help: the following enum variants are available + | +LL | let _: E = (E::Fn(/* fields */)); + | ^^^^^^^^^^^^^^^^^^^^^ +LL | let _: E = (E::Struct { /* fields */ }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: a function with a similar name exists | LL | let _: E = m::f; @@ -67,11 +123,27 @@ error[E0423]: expected value, found enum `E` LL | let _: E = E; | ^ | - = help: you might have meant to use one of the enum's other variants that have fields -help: try using one of the enum's variants +note: the enum is defined here + --> $DIR/privacy-enum-ctor.rs:2:5 + | +LL | / pub enum E { +LL | | Fn(u8), +LL | | Struct { +LL | | s: u8, +LL | | }, +LL | | Unit, +LL | | } + | |_____^ +help: you might have meant to use the following enum variant | LL | let _: E = E::Unit; | ^^^^^^^ +help: the following enum variants are available + | +LL | let _: E = (E::Fn(/* fields */)); + | ^^^^^^^^^^^^^^^^^^^^^ +LL | let _: E = (E::Struct { /* fields */ }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider importing one of these items instead | LL | use std::f32::consts::E; @@ -112,9 +184,29 @@ error[E0423]: expected value, found enum `m::n::Z` --> $DIR/privacy-enum-ctor.rs:57:16 | LL | let _: Z = m::n::Z; - | ^^^^^^^ help: try using one of the enum's variants: `m::Z::Unit` + | ^^^^^^^ | - = help: you might have meant to use one of the enum's other variants that have fields +note: the enum is defined here + --> $DIR/privacy-enum-ctor.rs:11:9 + | +LL | / pub(in m) enum Z { +LL | | Fn(u8), +LL | | Struct { +LL | | s: u8, +LL | | }, +LL | | Unit, +LL | | } + | |_________^ +help: you might have meant to use the following enum variant + | +LL | let _: Z = m::Z::Unit; + | ^^^^^^^^^^ +help: the following enum variants are available + | +LL | let _: Z = (m::Z::Fn(/* fields */)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _: Z = (m::Z::Struct { /* fields */ }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0412]: cannot find type `Z` in this scope --> $DIR/privacy-enum-ctor.rs:61:12 From f897162f3efc841461adce9510bb627cea9bac45 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 12 Oct 2020 16:52:51 +0100 Subject: [PATCH 182/446] resolve: improve "try using tuple struct" message This commit improves the tuple struct case added in rust-lang/rust#77341 so that the context is mentioned in more of the message. Signed-off-by: David Wood --- .../rustc_resolve/src/late/diagnostics.rs | 30 +++++++++---------- ...issue-43871-enum-instead-of-variant.stderr | 6 ++-- src/test/ui/issues/issue-73427.stderr | 4 +-- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 8ef99f36a04..c24b383f3b8 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1341,21 +1341,6 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let non_suggestable_variant_count = variants.len() - suggestable_variants.len(); - if !suggestable_variants.is_empty() { - let msg = if non_suggestable_variant_count == 0 && suggestable_variants.len() == 1 { - "try using the enum's variant" - } else { - "try using one of the enum's variants" - }; - - err.span_suggestions( - span, - msg, - suggestable_variants.drain(..), - Applicability::MaybeIncorrect, - ); - } - let source_msg = if source.is_call() { "to construct" } else if matches!(source, PathSource::TupleStruct(..)) { @@ -1364,6 +1349,21 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { unreachable!() }; + if !suggestable_variants.is_empty() { + let msg = if non_suggestable_variant_count == 0 && suggestable_variants.len() == 1 { + format!("try {} the enum's variant", source_msg) + } else { + format!("try {} one of the enum's variants", source_msg) + }; + + err.span_suggestions( + span, + &msg, + suggestable_variants.drain(..), + Applicability::MaybeIncorrect, + ); + } + // If the enum has no tuple variants.. if non_suggestable_variant_count == variants.len() { err.help(&format!("the enum has no tuple variants {}", source_msg)); diff --git a/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr b/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr index 62a7649e2ad..bca493e67d5 100644 --- a/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr +++ b/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr @@ -2,7 +2,7 @@ error[E0423]: expected function, tuple struct or tuple variant, found enum `Opti --> $DIR/issue-43871-enum-instead-of-variant.rs:19:13 | LL | let x = Option(1); - | ^^^^^^ help: try using one of the enum's variants: `std::option::Option::Some` + | ^^^^^^ help: try to construct one of the enum's variants: `std::option::Option::Some` | = help: you might have meant to construct the enum's non-tuple variant @@ -10,7 +10,7 @@ error[E0532]: expected tuple struct or tuple variant, found enum `Option` --> $DIR/issue-43871-enum-instead-of-variant.rs:21:12 | LL | if let Option(_) = x { - | ^^^^^^ help: try using one of the enum's variants: `std::option::Option::Some` + | ^^^^^^ help: try to match against one of the enum's variants: `std::option::Option::Some` | = help: you might have meant to match against the enum's non-tuple variant @@ -18,7 +18,7 @@ error[E0532]: expected tuple struct or tuple variant, found enum `Example` --> $DIR/issue-43871-enum-instead-of-variant.rs:27:12 | LL | if let Example(_) = y { - | ^^^^^^^ help: try using one of the enum's variants: `Example::Ex` + | ^^^^^^^ help: try to match against one of the enum's variants: `Example::Ex` | = help: you might have meant to match against the enum's non-tuple variant note: the enum is defined here diff --git a/src/test/ui/issues/issue-73427.stderr b/src/test/ui/issues/issue-73427.stderr index 4da5305e687..4b5f65b3461 100644 --- a/src/test/ui/issues/issue-73427.stderr +++ b/src/test/ui/issues/issue-73427.stderr @@ -118,7 +118,7 @@ LL | | Tuple(), LL | | Unit, LL | | } | |_^ -help: try using one of the enum's variants +help: try to construct one of the enum's variants | LL | let x = A::TupleWithFields(3); | ^^^^^^^^^^^^^^^^^^ @@ -143,7 +143,7 @@ LL | | Tuple(), LL | | Unit, LL | | } | |_^ -help: try using one of the enum's variants +help: try to match against one of the enum's variants | LL | if let A::TupleWithFields(3) = x { } | ^^^^^^^^^^^^^^^^^^ From 1588e34bccde88aeeb090449691adda1fa34ca4b Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 15 Oct 2020 11:23:07 -0700 Subject: [PATCH 183/446] llvm: backport SystemZ fix for AGR clobbers --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index 3c5d47c81d7..77a0125981b 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 3c5d47c81d78e9316e971c9870e8bc7c2c449d24 +Subproject commit 77a0125981b293260c9aec6355dff46ec707ab59 From 865c30d52ac19481ad7714979ef49c1bd5b1f663 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 15 Oct 2020 15:21:12 -0400 Subject: [PATCH 184/446] Bump backtrace-rs This pulls in https://github.com/rust-lang/backtrace-rs/pull/376, which fixes Miri support for `std::backtrace::Backtrace`. --- library/backtrace | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/backtrace b/library/backtrace index 893fbb23688..a6dd47bd588 160000 --- a/library/backtrace +++ b/library/backtrace @@ -1 +1 @@ -Subproject commit 893fbb23688e98376e54c26b59432a2966a8cc96 +Subproject commit a6dd47bd588c882e735675a1379d2b61719fa380 From b9db54b3a238124b19856a03eccef7ae3ae86d91 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 15 Oct 2020 21:30:28 +0200 Subject: [PATCH 185/446] Bump nzint_try_from_nzint_conv stabilization version to 1.49. Missed the 1.48 cycle. --- library/core/src/convert/num.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 173d824d390..2dd5e813d6f 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -488,7 +488,7 @@ nzint_impl_try_from_int! { isize, NonZeroIsize, #[stable(feature = "nzint_try_fr macro_rules! nzint_impl_try_from_nzint { ($From:ty => $To:ty, $doc: expr) => { - #[stable(feature = "nzint_try_from_nzint_conv", since = "1.48.0")] + #[stable(feature = "nzint_try_from_nzint_conv", since = "1.49.0")] #[doc = $doc] impl TryFrom<$From> for $To { type Error = TryFromIntError; From df95dcebf5f98cefdc60c9b9d818fb285ac07d5b Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 15 Oct 2020 21:45:09 +0200 Subject: [PATCH 186/446] Add missing `mut`. Co-authored-by: David Tolnay --- library/core/src/pin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 633e96eb7d8..b73cd046e5a 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -795,7 +795,7 @@ impl Pin<&'static T> { } } -impl Pin<&'static T> { +impl Pin<&'static mut T> { /// Get a pinned mutable reference from a static mutable reference. /// /// This is safe, because `T` is borrowed for the `'static` lifetime, which From 65835d1059b91fb6458942ea1dc4273990b035e2 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 15 Oct 2020 09:25:30 -0400 Subject: [PATCH 187/446] Deny broken intra-doc links in linkchecker Since rustdoc isn't warning about these links, check for them manually. --- Cargo.lock | 4 ++ .../src/error_codes/E0660.md | 2 +- .../src/error_codes/E0661.md | 2 +- .../src/error_codes/E0662.md | 2 +- .../src/error_codes/E0663.md | 2 +- .../src/error_codes/E0664.md | 2 +- library/core/src/alloc/mod.rs | 12 +--- library/core/src/convert/mod.rs | 1 + library/core/src/iter/traits/double_ended.rs | 3 + library/core/src/iter/traits/iterator.rs | 6 +- library/core/src/option.rs | 1 + library/std/src/ffi/c_str.rs | 3 +- .../src/library-features/default-free-fn.md | 2 + src/tools/linkchecker/Cargo.toml | 4 ++ src/tools/linkchecker/main.rs | 62 +++++++++++++++++++ 15 files changed, 90 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 45904a52456..23c7c4bcb35 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1744,6 +1744,10 @@ dependencies = [ [[package]] name = "linkchecker" version = "0.1.0" +dependencies = [ + "once_cell", + "regex", +] [[package]] name = "linked-hash-map" diff --git a/compiler/rustc_error_codes/src/error_codes/E0660.md b/compiler/rustc_error_codes/src/error_codes/E0660.md index fccd1b96f60..26d35f2620c 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0660.md +++ b/compiler/rustc_error_codes/src/error_codes/E0660.md @@ -9,4 +9,4 @@ llvm_asm!("nop" "nop"); Considering that this would be a long explanation, we instead recommend you take a look at the [`llvm_asm`] chapter of the Unstable book: -[llvm_asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html +[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0661.md b/compiler/rustc_error_codes/src/error_codes/E0661.md index f1debee7a18..0b8ba7fbbed 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0661.md +++ b/compiler/rustc_error_codes/src/error_codes/E0661.md @@ -10,4 +10,4 @@ llvm_asm!("nop" : "r"(a)); Considering that this would be a long explanation, we instead recommend you take a look at the [`llvm_asm`] chapter of the Unstable book: -[llvm_asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html +[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0662.md b/compiler/rustc_error_codes/src/error_codes/E0662.md index d4765f078b0..8c1bab8d041 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0662.md +++ b/compiler/rustc_error_codes/src/error_codes/E0662.md @@ -13,4 +13,4 @@ llvm_asm!("xor %eax, %eax" Considering that this would be a long explanation, we instead recommend you take a look at the [`llvm_asm`] chapter of the Unstable book: -[llvm_asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html +[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0663.md b/compiler/rustc_error_codes/src/error_codes/E0663.md index d5a85b275db..53ffd3373a5 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0663.md +++ b/compiler/rustc_error_codes/src/error_codes/E0663.md @@ -13,4 +13,4 @@ llvm_asm!("xor %eax, %eax" Considering that this would be a long explanation, we instead recommend you take a look at the [`llvm_asm`] chapter of the Unstable book: -[llvm_asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html +[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0664.md b/compiler/rustc_error_codes/src/error_codes/E0664.md index ce9c9491df3..f8e72cd330a 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0664.md +++ b/compiler/rustc_error_codes/src/error_codes/E0664.md @@ -13,4 +13,4 @@ llvm_asm!("mov $$0x200, %eax" Considering that this would be a long explanation, we instead recommend you take a look at the [`llvm_asm`] chapter of the Unstable book: -[llvm_asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html +[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index 6d09b4f0263..c61c19cc7d1 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -89,13 +89,11 @@ impl fmt::Display for AllocError { pub unsafe trait AllocRef { /// Attempts to allocate a block of memory. /// - /// On success, returns a [`NonNull<[u8]>`] meeting the size and alignment guarantees of `layout`. + /// On success, returns a [`NonNull<[u8]>`][NonNull] meeting the size and alignment guarantees of `layout`. /// /// The returned block may have a larger size than specified by `layout.size()`, and may or may /// not have its contents initialized. /// - /// [`NonNull<[u8]>`]: NonNull - /// /// # Errors /// /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet @@ -146,7 +144,7 @@ pub unsafe trait AllocRef { /// Attempts to extend the memory block. /// - /// Returns a new [`NonNull<[u8]>`] containing a pointer and the actual size of the allocated + /// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish /// this, the allocator may extend the allocation referenced by `ptr` to fit the new layout. /// @@ -158,8 +156,6 @@ pub unsafe trait AllocRef { /// If this method returns `Err`, then ownership of the memory block has not been transferred to /// this allocator, and the contents of the memory block are unaltered. /// - /// [`NonNull<[u8]>`]: NonNull - /// /// # Safety /// /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. @@ -271,7 +267,7 @@ pub unsafe trait AllocRef { /// Attempts to shrink the memory block. /// - /// Returns a new [`NonNull<[u8]>`] containing a pointer and the actual size of the allocated + /// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish /// this, the allocator may shrink the allocation referenced by `ptr` to fit the new layout. /// @@ -283,8 +279,6 @@ pub unsafe trait AllocRef { /// If this method returns `Err`, then ownership of the memory block has not been transferred to /// this allocator, and the contents of the memory block are unaltered. /// - /// [`NonNull<[u8]>`]: NonNull - /// /// # Safety /// /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 2bfeb49b5fa..3f7110b34cc 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -134,6 +134,7 @@ pub const fn identity(x: T) -> T { /// want to accept all references that can be converted to [`&str`] as an argument. /// Since both [`String`] and [`&str`] implement `AsRef` we can accept both as input argument. /// +/// [`&str`]: primitive@str /// [`Option`]: Option /// [`Result`]: Result /// [`Borrow`]: crate::borrow::Borrow diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index 16bee0e2eee..2253648ac2e 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -122,6 +122,9 @@ pub trait DoubleEndedIterator: Iterator { /// assert_eq!(iter.advance_back_by(0), Ok(())); /// assert_eq!(iter.advance_back_by(100), Err(1)); // only `&3` was skipped /// ``` + /// + /// [`Ok(())`]: Ok + /// [`Err(k)`]: Err #[inline] #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 813afcc0ec6..4af61111128 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -289,12 +289,12 @@ pub trait Iterator { /// This method will eagerly skip `n` elements by calling [`next`] up to `n` /// times until [`None`] is encountered. /// - /// `advance_by(n)` will return [`Ok(())`] if the iterator successfully advances by - /// `n` elements, or [`Err(k)`] if [`None`] is encountered, where `k` is the number + /// `advance_by(n)` will return [`Ok(())`][Ok] if the iterator successfully advances by + /// `n` elements, or [`Err(k)`][Err] if [`None`] is encountered, where `k` is the number /// of elements the iterator is advanced by before running out of elements (i.e. the /// length of the iterator). Note that `k` is always less than `n`. /// - /// Calling `advance_by(0)` does not consume any elements and always returns [`Ok(())`]. + /// Calling `advance_by(0)` does not consume any elements and always returns [`Ok(())`][Ok]. /// /// [`next`]: Iterator::next /// diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 9cb20a0afdc..825144e5a6f 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -687,6 +687,7 @@ impl Option { /// assert_eq!(Some(4).filter(is_even), Some(4)); /// ``` /// + /// [`Some(t)`]: Some #[inline] #[stable(feature = "option_filter", since = "1.27.0")] pub fn filter bool>(self, predicate: P) -> Self { diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 13021738af1..6df4eb99259 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -1383,7 +1383,8 @@ impl CStr { /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a /// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result. /// - /// [`str`]: prim@str + /// [`str`]: primitive@str + /// [`&str`]: primitive@str /// [`Borrowed`]: Cow::Borrowed /// [`Owned`]: Cow::Owned /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER diff --git a/src/doc/unstable-book/src/library-features/default-free-fn.md b/src/doc/unstable-book/src/library-features/default-free-fn.md index 5dff73a94dd..d40a27dddf3 100644 --- a/src/doc/unstable-book/src/library-features/default-free-fn.md +++ b/src/doc/unstable-book/src/library-features/default-free-fn.md @@ -10,6 +10,8 @@ Adds a free `default()` function to the `std::default` module. This function just forwards to [`Default::default()`], but may remove repetition of the word "default" from the call site. +[`Default::default()`]: https://doc.rust-lang.org/nightly/std/default/trait.Default.html#tymethod.default + Here is an example: ```rust diff --git a/src/tools/linkchecker/Cargo.toml b/src/tools/linkchecker/Cargo.toml index 0994cd20662..e5d870c039d 100644 --- a/src/tools/linkchecker/Cargo.toml +++ b/src/tools/linkchecker/Cargo.toml @@ -7,3 +7,7 @@ edition = "2018" [[bin]] name = "linkchecker" path = "main.rs" + +[dependencies] +regex = "1" +once_cell = "1" diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 4fe493a850d..f213944e0ab 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -21,6 +21,9 @@ use std::fs; use std::path::{Component, Path, PathBuf}; use std::rc::Rc; +use once_cell::sync::Lazy; +use regex::Regex; + use crate::Redirect::*; // Add linkcheck exceptions here @@ -50,6 +53,44 @@ const LINKCHECK_EXCEPTIONS: &[(&str, &[&str])] = &[ ("alloc/collections/btree_set/struct.BTreeSet.html", &["#insert-and-complex-keys"]), ]; +#[rustfmt::skip] +const INTRA_DOC_LINK_EXCEPTIONS: &[(&str, &[&str])] = &[ + // This will never have links that are not in other pages. + // To avoid repeating the exceptions twice, an empty list means all broken links are allowed. + ("reference/print.html", &[]), + // All the reference 'links' are actually ENBF highlighted as code + ("reference/comments.html", &[ + "/ !", + "* !", + ]), + ("reference/identifiers.html", &[ + "a-z A-Z", + "a-z A-Z 0-9 _", + "a-z A-Z] [a-z A-Z 0-9 _", + ]), + ("reference/tokens.html", &[ + "0-1", + "0-7", + "0-9", + "0-9", + "0-9 a-f A-F", + ]), + ("reference/notation.html", &[ + "b B", + "a-z", + ]), + // This is being used in the sense of 'inclusive range', not a markdown link + ("core/ops/struct.RangeInclusive.html", &["begin, end"]), + ("std/ops/struct.RangeInclusive.html", &["begin, end"]), + ("core/slice/trait.SliceIndex.html", &["begin, end"]), + ("alloc/slice/trait.SliceIndex.html", &["begin, end"]), + ("std/slice/trait.SliceIndex.html", &["begin, end"]), + +]; + +static BROKEN_INTRA_DOC_LINK: Lazy = + Lazy::new(|| Regex::new(r#"\[(.*)\]"#).unwrap()); + macro_rules! t { ($e:expr) => { match $e { @@ -138,6 +179,14 @@ fn walk(cache: &mut Cache, root: &Path, dir: &Path, errors: &mut bool) { } } +fn is_intra_doc_exception(file: &Path, link: &str) -> bool { + if let Some(entry) = INTRA_DOC_LINK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) { + entry.1.is_empty() || entry.1.contains(&link) + } else { + false + } +} + fn is_exception(file: &Path, link: &str) -> bool { if let Some(entry) = LINKCHECK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) { entry.1.contains(&link) @@ -292,6 +341,19 @@ fn check(cache: &mut Cache, root: &Path, file: &Path, errors: &mut bool) -> Opti } } }); + + // Search for intra-doc links that rustdoc didn't warn about + // FIXME(#77199, 77200) Rustdoc should just warn about these directly. + // NOTE: only looks at one line at a time; in practice this should find most links + for (i, line) in contents.lines().enumerate() { + for broken_link in BROKEN_INTRA_DOC_LINK.captures_iter(line) { + if !is_intra_doc_exception(file, &broken_link[1]) { + *errors = true; + print!("{}:{}: broken intra-doc link - ", pretty_file.display(), i + 1); + println!("{}", &broken_link[0]); + } + } + } Some(pretty_file) } From b221819ff7b2d53b25714635dc72d68d732c491e Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 15 Oct 2020 20:29:21 -0400 Subject: [PATCH 188/446] Update submodules for link fixes - [rust-embedded](https://github.com/rust-embedded/book/compare/79ab7776929c66db83203397958fa7037d5d9a30...ca8169e69b479f615855d0eece7e318138fcfc00) - [cargo](https://github.com/rust-lang/cargo/compare/12db56cdedbc2c26a9aa18f994c0188cdcc67df5...79b397d72c557eb6444a2ba0dc00a211a226a35a) --- src/doc/embedded-book | 2 +- src/tools/cargo | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/embedded-book b/src/doc/embedded-book index 79ab7776929..ca8169e69b4 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit 79ab7776929c66db83203397958fa7037d5d9a30 +Subproject commit ca8169e69b479f615855d0eece7e318138fcfc00 diff --git a/src/tools/cargo b/src/tools/cargo index 12db56cdedb..79b397d72c5 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 12db56cdedbc2c26a9aa18f994c0188cdcc67df5 +Subproject commit 79b397d72c557eb6444a2ba0dc00a211a226a35a From b8dcd2fbce4550b1ef46d270546bd8480098cdca Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 19:01:27 +0200 Subject: [PATCH 189/446] Take sys/vxworks/mutex from sys/unix instead. --- library/std/src/sys/vxworks/mod.rs | 1 + library/std/src/sys/vxworks/mutex.rs | 133 --------------------------- 2 files changed, 1 insertion(+), 133 deletions(-) delete mode 100644 library/std/src/sys/vxworks/mutex.rs diff --git a/library/std/src/sys/vxworks/mod.rs b/library/std/src/sys/vxworks/mod.rs index 1132a849e2f..3f47c7bda60 100644 --- a/library/std/src/sys/vxworks/mod.rs +++ b/library/std/src/sys/vxworks/mod.rs @@ -17,6 +17,7 @@ pub mod fd; pub mod fs; pub mod io; pub mod memchr; +#[path = "../unix/mutex.rs"] pub mod mutex; pub mod net; pub mod os; diff --git a/library/std/src/sys/vxworks/mutex.rs b/library/std/src/sys/vxworks/mutex.rs deleted file mode 100644 index dd7582c21a7..00000000000 --- a/library/std/src/sys/vxworks/mutex.rs +++ /dev/null @@ -1,133 +0,0 @@ -use crate::cell::UnsafeCell; -use crate::mem::MaybeUninit; - -pub struct Mutex { - inner: UnsafeCell, -} - -pub type MovableMutex = Box; - -#[inline] -pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t { - m.inner.get() -} - -unsafe impl Send for Mutex {} -unsafe impl Sync for Mutex {} - -#[allow(dead_code)] // sys isn't exported yet -impl Mutex { - pub const fn new() -> Mutex { - // Might be moved to a different address, so it is better to avoid - // initialization of potentially opaque OS data before it landed. - // Be very careful using this newly constructed `Mutex`, reentrant - // locking is undefined behavior until `init` is called! - Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) } - } - #[inline] - pub unsafe fn init(&mut self) { - // Issue #33770 - // - // A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have - // a type of PTHREAD_MUTEX_DEFAULT, which has undefined behavior if you - // try to re-lock it from the same thread when you already hold a lock. - // - // In practice, glibc takes advantage of this undefined behavior to - // implement hardware lock elision, which uses hardware transactional - // memory to avoid acquiring the lock. While a transaction is in - // progress, the lock appears to be unlocked. This isn't a problem for - // other threads since the transactional memory will abort if a conflict - // is detected, however no abort is generated if re-locking from the - // same thread. - // - // Since locking the same mutex twice will result in two aliasing &mut - // references, we instead create the mutex with type - // PTHREAD_MUTEX_NORMAL which is guaranteed to deadlock if we try to - // re-lock it from the same thread, thus avoiding undefined behavior. - let mut attr = MaybeUninit::::uninit(); - let r = libc::pthread_mutexattr_init(attr.as_mut_ptr()); - debug_assert_eq!(r, 0); - let r = libc::pthread_mutexattr_settype(attr.as_mut_ptr(), libc::PTHREAD_MUTEX_NORMAL); - debug_assert_eq!(r, 0); - let r = libc::pthread_mutex_init(self.inner.get(), attr.as_ptr()); - debug_assert_eq!(r, 0); - let r = libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); - debug_assert_eq!(r, 0); - } - #[inline] - pub unsafe fn lock(&self) { - let r = libc::pthread_mutex_lock(self.inner.get()); - debug_assert_eq!(r, 0); - } - #[inline] - pub unsafe fn unlock(&self) { - let r = libc::pthread_mutex_unlock(self.inner.get()); - debug_assert_eq!(r, 0); - } - #[inline] - pub unsafe fn try_lock(&self) -> bool { - libc::pthread_mutex_trylock(self.inner.get()) == 0 - } - #[inline] - #[cfg(not(target_os = "dragonfly"))] - pub unsafe fn destroy(&self) { - let r = libc::pthread_mutex_destroy(self.inner.get()); - debug_assert_eq!(r, 0); - } - #[inline] - #[cfg(target_os = "dragonfly")] - pub unsafe fn destroy(&self) { - let r = libc::pthread_mutex_destroy(self.inner.get()); - // On DragonFly pthread_mutex_destroy() returns EINVAL if called on a - // mutex that was just initialized with libc::PTHREAD_MUTEX_INITIALIZER. - // Once it is used (locked/unlocked) or pthread_mutex_init() is called, - // this behaviour no longer occurs. - debug_assert!(r == 0 || r == libc::EINVAL); - } -} - -pub struct ReentrantMutex { - inner: UnsafeCell, -} - -unsafe impl Send for ReentrantMutex {} -unsafe impl Sync for ReentrantMutex {} - -impl ReentrantMutex { - pub const unsafe fn uninitialized() -> ReentrantMutex { - ReentrantMutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) } - } - - pub unsafe fn init(&self) { - let mut attr = MaybeUninit::::uninit(); - let result = libc::pthread_mutexattr_init(attr.as_mut_ptr()); - debug_assert_eq!(result, 0); - let result = - libc::pthread_mutexattr_settype(attr.as_mut_ptr(), libc::PTHREAD_MUTEX_RECURSIVE); - debug_assert_eq!(result, 0); - let result = libc::pthread_mutex_init(self.inner.get(), attr.as_ptr()); - debug_assert_eq!(result, 0); - let result = libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); - debug_assert_eq!(result, 0); - } - - pub unsafe fn lock(&self) { - let result = libc::pthread_mutex_lock(self.inner.get()); - debug_assert_eq!(result, 0); - } - - #[inline] - pub unsafe fn try_lock(&self) -> bool { - libc::pthread_mutex_trylock(self.inner.get()) == 0 - } - - pub unsafe fn unlock(&self) { - let result = libc::pthread_mutex_unlock(self.inner.get()); - debug_assert_eq!(result, 0); - } - - pub unsafe fn destroy(&self) { - let result = libc::pthread_mutex_destroy(self.inner.get()); - debug_assert_eq!(result, 0); - } -} From f3f30c7132c20825833074044b00c7e02016ca25 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 19:01:56 +0200 Subject: [PATCH 190/446] Take sys/vxworks/condvar from sys/unix instead. --- library/std/src/sys/vxworks/condvar.rs | 91 -------------------------- library/std/src/sys/vxworks/mod.rs | 1 + 2 files changed, 1 insertion(+), 91 deletions(-) delete mode 100644 library/std/src/sys/vxworks/condvar.rs diff --git a/library/std/src/sys/vxworks/condvar.rs b/library/std/src/sys/vxworks/condvar.rs deleted file mode 100644 index b4724be7c7c..00000000000 --- a/library/std/src/sys/vxworks/condvar.rs +++ /dev/null @@ -1,91 +0,0 @@ -use crate::cell::UnsafeCell; -use crate::sys::mutex::{self, Mutex}; -use crate::time::Duration; - -pub struct Condvar { - inner: UnsafeCell, -} - -pub type MovableCondvar = Box; - -unsafe impl Send for Condvar {} -unsafe impl Sync for Condvar {} - -const TIMESPEC_MAX: libc::timespec = - libc::timespec { tv_sec: ::MAX, tv_nsec: 1_000_000_000 - 1 }; - -fn saturating_cast_to_time_t(value: u64) -> libc::time_t { - if value > ::MAX as u64 { ::MAX } else { value as libc::time_t } -} - -impl Condvar { - pub const fn new() -> Condvar { - // Might be moved and address is changing it is better to avoid - // initialization of potentially opaque OS data before it landed - Condvar { inner: UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER) } - } - - pub unsafe fn init(&mut self) { - use crate::mem::MaybeUninit; - let mut attr = MaybeUninit::::uninit(); - let r = libc::pthread_condattr_init(attr.as_mut_ptr()); - assert_eq!(r, 0); - let r = libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC); - assert_eq!(r, 0); - let r = libc::pthread_cond_init(self.inner.get(), attr.as_ptr()); - assert_eq!(r, 0); - let r = libc::pthread_condattr_destroy(attr.as_mut_ptr()); - assert_eq!(r, 0); - } - - #[inline] - pub unsafe fn notify_one(&self) { - let r = libc::pthread_cond_signal(self.inner.get()); - debug_assert_eq!(r, 0); - } - - #[inline] - pub unsafe fn notify_all(&self) { - let r = libc::pthread_cond_broadcast(self.inner.get()); - debug_assert_eq!(r, 0); - } - - #[inline] - pub unsafe fn wait(&self, mutex: &Mutex) { - let r = libc::pthread_cond_wait(self.inner.get(), mutex::raw(mutex)); - debug_assert_eq!(r, 0); - } - - // This implementation is used on systems that support pthread_condattr_setclock - // where we configure condition variable to use monotonic clock (instead of - // default system clock). This approach avoids all problems that result - // from changes made to the system time. - pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - use crate::mem; - - let mut now: libc::timespec = mem::zeroed(); - let r = libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now); - assert_eq!(r, 0); - - // Nanosecond calculations can't overflow because both values are below 1e9. - let nsec = dur.subsec_nanos() + now.tv_nsec as u32; - - let sec = saturating_cast_to_time_t(dur.as_secs()) - .checked_add((nsec / 1_000_000_000) as libc::time_t) - .and_then(|s| s.checked_add(now.tv_sec)); - let nsec = nsec % 1_000_000_000; - - let timeout = - sec.map(|s| libc::timespec { tv_sec: s, tv_nsec: nsec as _ }).unwrap_or(TIMESPEC_MAX); - - let r = libc::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex), &timeout); - assert!(r == libc::ETIMEDOUT || r == 0); - r == 0 - } - - #[inline] - pub unsafe fn destroy(&self) { - let r = libc::pthread_cond_destroy(self.inner.get()); - debug_assert_eq!(r, 0); - } -} diff --git a/library/std/src/sys/vxworks/mod.rs b/library/std/src/sys/vxworks/mod.rs index 3f47c7bda60..1763ed50547 100644 --- a/library/std/src/sys/vxworks/mod.rs +++ b/library/std/src/sys/vxworks/mod.rs @@ -10,6 +10,7 @@ pub use libc::strlen; pub mod alloc; pub mod args; pub mod cmath; +#[path = "../unix/condvar.rs"] pub mod condvar; pub mod env; pub mod ext; From f875c8be5ddfc734558a1f5d4cb9800477c3f1a1 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 19:01:56 +0200 Subject: [PATCH 191/446] Take sys/vxworks/rwlock from sys/unix instead. --- library/std/src/sys/vxworks/mod.rs | 1 + library/std/src/sys/vxworks/rwlock.rs | 114 -------------------------- 2 files changed, 1 insertion(+), 114 deletions(-) delete mode 100644 library/std/src/sys/vxworks/rwlock.rs diff --git a/library/std/src/sys/vxworks/mod.rs b/library/std/src/sys/vxworks/mod.rs index 1763ed50547..def23c70456 100644 --- a/library/std/src/sys/vxworks/mod.rs +++ b/library/std/src/sys/vxworks/mod.rs @@ -26,6 +26,7 @@ pub mod path; pub mod pipe; pub mod process; pub mod rand; +#[path = "../unix/rwlock.rs"] pub mod rwlock; pub mod stack_overflow; pub mod stdio; diff --git a/library/std/src/sys/vxworks/rwlock.rs b/library/std/src/sys/vxworks/rwlock.rs deleted file mode 100644 index c90304c2b4a..00000000000 --- a/library/std/src/sys/vxworks/rwlock.rs +++ /dev/null @@ -1,114 +0,0 @@ -use crate::cell::UnsafeCell; -use crate::sync::atomic::{AtomicUsize, Ordering}; - -pub struct RWLock { - inner: UnsafeCell, - write_locked: UnsafeCell, - num_readers: AtomicUsize, -} - -unsafe impl Send for RWLock {} -unsafe impl Sync for RWLock {} - -impl RWLock { - pub const fn new() -> RWLock { - RWLock { - inner: UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER), - write_locked: UnsafeCell::new(false), - num_readers: AtomicUsize::new(0), - } - } - - #[inline] - pub unsafe fn read(&self) { - let r = libc::pthread_rwlock_rdlock(self.inner.get()); - if r == libc::EAGAIN { - panic!("rwlock maximum reader count exceeded"); - } else if r == libc::EDEADLK || (r == 0 && *self.write_locked.get()) { - if r == 0 { - self.raw_unlock(); - } - panic!("rwlock read lock would result in deadlock"); - } else { - debug_assert_eq!(r, 0); - self.num_readers.fetch_add(1, Ordering::Relaxed); - } - } - - #[inline] - pub unsafe fn try_read(&self) -> bool { - let r = libc::pthread_rwlock_tryrdlock(self.inner.get()); - if r == 0 { - if *self.write_locked.get() { - self.raw_unlock(); - false - } else { - self.num_readers.fetch_add(1, Ordering::Relaxed); - true - } - } else { - false - } - } - - #[inline] - pub unsafe fn write(&self) { - let r = libc::pthread_rwlock_wrlock(self.inner.get()); - // See comments above for why we check for EDEADLK and write_locked. We - // also need to check that num_readers is 0. - if r == libc::EDEADLK - || *self.write_locked.get() - || self.num_readers.load(Ordering::Relaxed) != 0 - { - if r == 0 { - self.raw_unlock(); - } - panic!("rwlock write lock would result in deadlock"); - } else { - debug_assert_eq!(r, 0); - } - *self.write_locked.get() = true; - } - - #[inline] - pub unsafe fn try_write(&self) -> bool { - let r = libc::pthread_rwlock_trywrlock(self.inner.get()); - if r == 0 { - if *self.write_locked.get() || self.num_readers.load(Ordering::Relaxed) != 0 { - self.raw_unlock(); - false - } else { - *self.write_locked.get() = true; - true - } - } else { - false - } - } - - #[inline] - unsafe fn raw_unlock(&self) { - let r = libc::pthread_rwlock_unlock(self.inner.get()); - debug_assert_eq!(r, 0); - } - - #[inline] - pub unsafe fn read_unlock(&self) { - debug_assert!(!*self.write_locked.get()); - self.num_readers.fetch_sub(1, Ordering::Relaxed); - self.raw_unlock(); - } - - #[inline] - pub unsafe fn write_unlock(&self) { - debug_assert_eq!(self.num_readers.load(Ordering::Relaxed), 0); - debug_assert!(*self.write_locked.get()); - *self.write_locked.get() = false; - self.raw_unlock(); - } - #[inline] - pub unsafe fn destroy(&self) { - let r = libc::pthread_rwlock_destroy(self.inner.get()); - debug_assert_eq!(r, 0); - } -} From d1947628b568c1d59048288486e68d917709f4d4 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 19:01:56 +0200 Subject: [PATCH 192/446] Take sys/vxworks/time from sys/unix instead. --- library/std/src/sys/vxworks/mod.rs | 1 + library/std/src/sys/vxworks/time.rs | 197 ---------------------------- 2 files changed, 1 insertion(+), 197 deletions(-) delete mode 100644 library/std/src/sys/vxworks/time.rs diff --git a/library/std/src/sys/vxworks/mod.rs b/library/std/src/sys/vxworks/mod.rs index def23c70456..fee0a83e353 100644 --- a/library/std/src/sys/vxworks/mod.rs +++ b/library/std/src/sys/vxworks/mod.rs @@ -33,6 +33,7 @@ pub mod stdio; pub mod thread; pub mod thread_local_dtor; pub mod thread_local_key; +#[path = "../unix/time.rs"] pub mod time; pub use crate::sys_common::os_str_bytes as os_str; diff --git a/library/std/src/sys/vxworks/time.rs b/library/std/src/sys/vxworks/time.rs deleted file mode 100644 index 8f46f4d284f..00000000000 --- a/library/std/src/sys/vxworks/time.rs +++ /dev/null @@ -1,197 +0,0 @@ -use crate::cmp::Ordering; -use crate::time::Duration; -use core::hash::{Hash, Hasher}; - -pub use self::inner::{Instant, SystemTime, UNIX_EPOCH}; -use crate::convert::TryInto; - -const NSEC_PER_SEC: u64 = 1_000_000_000; - -#[derive(Copy, Clone)] -struct Timespec { - t: libc::timespec, -} - -impl Timespec { - const fn zero() -> Timespec { - Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } } - } - fn sub_timespec(&self, other: &Timespec) -> Result { - if self >= other { - Ok(if self.t.tv_nsec >= other.t.tv_nsec { - Duration::new( - (self.t.tv_sec - other.t.tv_sec) as u64, - (self.t.tv_nsec - other.t.tv_nsec) as u32, - ) - } else { - Duration::new( - (self.t.tv_sec - 1 - other.t.tv_sec) as u64, - self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.t.tv_nsec as u32, - ) - }) - } else { - match other.sub_timespec(self) { - Ok(d) => Err(d), - Err(d) => Ok(d), - } - } - } - - fn checked_add_duration(&self, other: &Duration) -> Option { - let mut secs = other - .as_secs() - .try_into() // <- target type would be `libc::time_t` - .ok() - .and_then(|secs| self.t.tv_sec.checked_add(secs))?; - - // Nano calculations can't overflow because nanos are <1B which fit - // in a u32. - let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32; - if nsec >= NSEC_PER_SEC as u32 { - nsec -= NSEC_PER_SEC as u32; - secs = secs.checked_add(1)?; - } - Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } }) - } - - fn checked_sub_duration(&self, other: &Duration) -> Option { - let mut secs = other - .as_secs() - .try_into() // <- target type would be `libc::time_t` - .ok() - .and_then(|secs| self.t.tv_sec.checked_sub(secs))?; - - // Similar to above, nanos can't overflow. - let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32; - if nsec < 0 { - nsec += NSEC_PER_SEC as i32; - secs = secs.checked_sub(1)?; - } - Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } }) - } -} - -impl PartialEq for Timespec { - fn eq(&self, other: &Timespec) -> bool { - self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec - } -} - -impl Eq for Timespec {} - -impl PartialOrd for Timespec { - fn partial_cmp(&self, other: &Timespec) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Timespec { - fn cmp(&self, other: &Timespec) -> Ordering { - let me = (self.t.tv_sec, self.t.tv_nsec); - let other = (other.t.tv_sec, other.t.tv_nsec); - me.cmp(&other) - } -} - -impl Hash for Timespec { - fn hash(&self, state: &mut H) { - self.t.tv_sec.hash(state); - self.t.tv_nsec.hash(state); - } -} -mod inner { - use crate::fmt; - use crate::sys::cvt; - use crate::time::Duration; - - use super::Timespec; - - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub struct Instant { - t: Timespec, - } - - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub struct SystemTime { - t: Timespec, - } - - pub const UNIX_EPOCH: SystemTime = - SystemTime { t: Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } } }; - - impl Instant { - pub fn now() -> Instant { - Instant { t: now(libc::CLOCK_MONOTONIC) } - } - - pub const fn zero() -> Instant { - Instant { t: Timespec::zero() } - } - - pub fn actually_monotonic() -> bool { - true - } - - pub fn checked_sub_instant(&self, other: &Instant) -> Option { - self.t.sub_timespec(&other.t).ok() - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(Instant { t: self.t.checked_add_duration(other)? }) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(Instant { t: self.t.checked_sub_duration(other)? }) - } - } - - impl fmt::Debug for Instant { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Instant") - .field("tv_sec", &self.t.t.tv_sec) - .field("tv_nsec", &self.t.t.tv_nsec) - .finish() - } - } - - impl SystemTime { - pub fn now() -> SystemTime { - SystemTime { t: now(libc::CLOCK_REALTIME) } - } - - pub fn sub_time(&self, other: &SystemTime) -> Result { - self.t.sub_timespec(&other.t) - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(SystemTime { t: self.t.checked_add_duration(other)? }) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(SystemTime { t: self.t.checked_sub_duration(other)? }) - } - } - - impl From for SystemTime { - fn from(t: libc::timespec) -> SystemTime { - SystemTime { t: Timespec { t: t } } - } - } - - impl fmt::Debug for SystemTime { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SystemTime") - .field("tv_sec", &self.t.t.tv_sec) - .field("tv_nsec", &self.t.t.tv_nsec) - .finish() - } - } - - pub type clock_t = libc::c_int; - - fn now(clock: clock_t) -> Timespec { - let mut t = Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } }; - cvt(unsafe { libc::clock_gettime(clock, &mut t.t) }).unwrap(); - t - } -} From c8628f43bfe9df8b06283fdc1d8acb4643f74194 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 19:01:56 +0200 Subject: [PATCH 193/446] Take sys/vxworks/stack_overflow from sys/unix instead. --- library/std/src/sys/unix/stack_overflow.rs | 2 +- library/std/src/sys/vxworks/mod.rs | 1 + library/std/src/sys/vxworks/stack_overflow.rs | 38 ------------------- 3 files changed, 2 insertions(+), 39 deletions(-) delete mode 100644 library/std/src/sys/vxworks/stack_overflow.rs diff --git a/library/std/src/sys/unix/stack_overflow.rs b/library/std/src/sys/unix/stack_overflow.rs index c74fc2b5903..d8474205352 100644 --- a/library/std/src/sys/unix/stack_overflow.rs +++ b/library/std/src/sys/unix/stack_overflow.rs @@ -219,7 +219,7 @@ mod imp { target_os = "solaris", target_os = "illumos", all(target_os = "netbsd", not(target_vendor = "rumprun")), - target_os = "openbsd" + target_os = "openbsd", )))] mod imp { pub unsafe fn init() {} diff --git a/library/std/src/sys/vxworks/mod.rs b/library/std/src/sys/vxworks/mod.rs index fee0a83e353..362c2a4cc02 100644 --- a/library/std/src/sys/vxworks/mod.rs +++ b/library/std/src/sys/vxworks/mod.rs @@ -28,6 +28,7 @@ pub mod process; pub mod rand; #[path = "../unix/rwlock.rs"] pub mod rwlock; +#[path = "../unix/stack_overflow.rs"] pub mod stack_overflow; pub mod stdio; pub mod thread; diff --git a/library/std/src/sys/vxworks/stack_overflow.rs b/library/std/src/sys/vxworks/stack_overflow.rs deleted file mode 100644 index 7b58c83193b..00000000000 --- a/library/std/src/sys/vxworks/stack_overflow.rs +++ /dev/null @@ -1,38 +0,0 @@ -#![cfg_attr(test, allow(dead_code))] - -use self::imp::{drop_handler, make_handler}; - -pub use self::imp::cleanup; -pub use self::imp::init; - -pub struct Handler { - _data: *mut libc::c_void, -} - -impl Handler { - pub unsafe fn new() -> Handler { - make_handler() - } -} - -impl Drop for Handler { - fn drop(&mut self) { - unsafe { - drop_handler(self); - } - } -} - -mod imp { - use crate::ptr; - - pub unsafe fn init() {} - - pub unsafe fn cleanup() {} - - pub unsafe fn make_handler() -> super::Handler { - super::Handler { _data: ptr::null_mut() } - } - - pub unsafe fn drop_handler(_handler: &mut super::Handler) {} -} From 5d526f6eee0e700084a28dad482b66891038a8f5 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 19:01:56 +0200 Subject: [PATCH 194/446] Take sys/vxworks/thread from sys/unix instead. --- library/std/src/sys/unix/thread.rs | 9 +- library/std/src/sys/vxworks/mod.rs | 1 + library/std/src/sys/vxworks/thread.rs | 155 -------------------------- 3 files changed, 7 insertions(+), 158 deletions(-) delete mode 100644 library/std/src/sys/vxworks/thread.rs diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 652219e28f6..fdf114d6df6 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -6,10 +6,12 @@ use crate::ptr; use crate::sys::{os, stack_overflow}; use crate::time::Duration; -#[cfg(not(target_os = "l4re"))] +#[cfg(not(any(target_os = "l4re", target_os = "vxworks")))] pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; #[cfg(target_os = "l4re")] pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024; +#[cfg(target_os = "vxworks")] +pub const DEFAULT_MIN_STACK_SIZE: usize = 256 * 1024; pub struct Thread { id: libc::pthread_t, @@ -152,10 +154,11 @@ impl Thread { target_os = "haiku", target_os = "l4re", target_os = "emscripten", - target_os = "redox" + target_os = "redox", + target_os = "vxworks" ))] pub fn set_name(_name: &CStr) { - // Newlib, Haiku, and Emscripten have no way to set a thread name. + // Newlib, Haiku, Emscripten, and VxWorks have no way to set a thread name. } #[cfg(target_os = "fuchsia")] pub fn set_name(_name: &CStr) { diff --git a/library/std/src/sys/vxworks/mod.rs b/library/std/src/sys/vxworks/mod.rs index 362c2a4cc02..142d70ebb5c 100644 --- a/library/std/src/sys/vxworks/mod.rs +++ b/library/std/src/sys/vxworks/mod.rs @@ -31,6 +31,7 @@ pub mod rwlock; #[path = "../unix/stack_overflow.rs"] pub mod stack_overflow; pub mod stdio; +#[path = "../unix/thread.rs"] pub mod thread; pub mod thread_local_dtor; pub mod thread_local_key; diff --git a/library/std/src/sys/vxworks/thread.rs b/library/std/src/sys/vxworks/thread.rs deleted file mode 100644 index 24a2e0f965d..00000000000 --- a/library/std/src/sys/vxworks/thread.rs +++ /dev/null @@ -1,155 +0,0 @@ -use crate::cmp; -use crate::ffi::CStr; -use crate::io; -use crate::mem; -use crate::ptr; -use crate::sys::{os, stack_overflow}; -use crate::time::Duration; - -pub const DEFAULT_MIN_STACK_SIZE: usize = 0x40000; // 256K - -pub struct Thread { - id: libc::pthread_t, -} - -// Some platforms may have pthread_t as a pointer in which case we still want -// a thread to be Send/Sync -unsafe impl Send for Thread {} -unsafe impl Sync for Thread {} - -// The pthread_attr_setstacksize symbol doesn't exist in the emscripten libc, -// so we have to not link to it to satisfy emcc's ERROR_ON_UNDEFINED_SYMBOLS. -unsafe fn pthread_attr_setstacksize( - attr: *mut libc::pthread_attr_t, - stack_size: libc::size_t, -) -> libc::c_int { - libc::pthread_attr_setstacksize(attr, stack_size) -} - -impl Thread { - // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(stack: usize, p: Box) -> io::Result { - let p = Box::into_raw(box p); - let mut native: libc::pthread_t = mem::zeroed(); - let mut attr: libc::pthread_attr_t = mem::zeroed(); - assert_eq!(libc::pthread_attr_init(&mut attr), 0); - - let stack_size = cmp::max(stack, min_stack_size(&attr)); - - match pthread_attr_setstacksize(&mut attr, stack_size) { - 0 => {} - n => { - assert_eq!(n, libc::EINVAL); - // EINVAL means |stack_size| is either too small or not a - // multiple of the system page size. Because it's definitely - // >= PTHREAD_STACK_MIN, it must be an alignment issue. - // Round up to the nearest page and try again. - let page_size = os::page_size(); - let stack_size = - (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1); - assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0); - } - }; - - let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _); - // Note: if the thread creation fails and this assert fails, then p will - // be leaked. However, an alternative design could cause double-free - // which is clearly worse. - assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); - - return if ret != 0 { - // The thread failed to start and as a result p was not consumed. Therefore, it is - // safe to reconstruct the box so that it gets deallocated. - drop(Box::from_raw(p)); - Err(io::Error::from_raw_os_error(ret)) - } else { - Ok(Thread { id: native }) - }; - - extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void { - unsafe { - // Next, set up our stack overflow handler which may get triggered if we run - // out of stack. - let _handler = stack_overflow::Handler::new(); - // Finally, let's run some code. - Box::from_raw(main as *mut Box)(); - } - ptr::null_mut() - } - } - - pub fn yield_now() { - let ret = unsafe { libc::sched_yield() }; - debug_assert_eq!(ret, 0); - } - - pub fn set_name(_name: &CStr) { - // VxWorks does not provide a way to set the task name except at creation time - } - - pub fn sleep(dur: Duration) { - let mut secs = dur.as_secs(); - let mut nsecs = dur.subsec_nanos() as _; - - // If we're awoken with a signal then the return value will be -1 and - // nanosleep will fill in `ts` with the remaining time. - unsafe { - while secs > 0 || nsecs > 0 { - let mut ts = libc::timespec { - tv_sec: cmp::min(libc::time_t::MAX as u64, secs) as libc::time_t, - tv_nsec: nsecs, - }; - secs -= ts.tv_sec as u64; - if libc::nanosleep(&ts, &mut ts) == -1 { - assert_eq!(os::errno(), libc::EINTR); - secs += ts.tv_sec as u64; - nsecs = ts.tv_nsec; - } else { - nsecs = 0; - } - } - } - } - - pub fn join(self) { - unsafe { - let ret = libc::pthread_join(self.id, ptr::null_mut()); - mem::forget(self); - assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret)); - } - } - - pub fn id(&self) -> libc::pthread_t { - self.id - } - - pub fn into_id(self) -> libc::pthread_t { - let id = self.id; - mem::forget(self); - id - } -} - -impl Drop for Thread { - fn drop(&mut self) { - let ret = unsafe { libc::pthread_detach(self.id) }; - debug_assert_eq!(ret, 0); - } -} - -#[cfg_attr(test, allow(dead_code))] -pub mod guard { - use crate::ops::Range; - pub type Guard = Range; - pub unsafe fn current() -> Option { - None - } - pub unsafe fn init() -> Option { - None - } - pub unsafe fn deinit() {} -} - -fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { - libc::PTHREAD_STACK_MIN -} From 4853a6e78e7ad6ec2ad63c3f23929ed027255b3f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 19:01:56 +0200 Subject: [PATCH 195/446] Take sys/vxworks/stdio from sys/unix instead. --- library/std/src/sys/vxworks/mod.rs | 1 + library/std/src/sys/vxworks/stdio.rs | 69 ---------------------------- 2 files changed, 1 insertion(+), 69 deletions(-) delete mode 100644 library/std/src/sys/vxworks/stdio.rs diff --git a/library/std/src/sys/vxworks/mod.rs b/library/std/src/sys/vxworks/mod.rs index 142d70ebb5c..3b5f2f8561f 100644 --- a/library/std/src/sys/vxworks/mod.rs +++ b/library/std/src/sys/vxworks/mod.rs @@ -30,6 +30,7 @@ pub mod rand; pub mod rwlock; #[path = "../unix/stack_overflow.rs"] pub mod stack_overflow; +#[path = "../unix/stdio.rs"] pub mod stdio; #[path = "../unix/thread.rs"] pub mod thread; diff --git a/library/std/src/sys/vxworks/stdio.rs b/library/std/src/sys/vxworks/stdio.rs deleted file mode 100644 index 92e9f205b4e..00000000000 --- a/library/std/src/sys/vxworks/stdio.rs +++ /dev/null @@ -1,69 +0,0 @@ -use crate::io; -use crate::sys::fd::FileDesc; - -pub struct Stdin(()); -pub struct Stdout(()); -pub struct Stderr(()); - -impl Stdin { - pub const fn new() -> Stdin { - Stdin(()) - } -} - -impl io::Read for Stdin { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let fd = FileDesc::new(libc::STDIN_FILENO); - let ret = fd.read(buf); - fd.into_raw(); // do not close this FD - ret - } -} - -impl Stdout { - pub const fn new() -> Stdout { - Stdout(()) - } -} - -impl io::Write for Stdout { - fn write(&mut self, buf: &[u8]) -> io::Result { - let fd = FileDesc::new(libc::STDOUT_FILENO); - let ret = fd.write(buf); - fd.into_raw(); // do not close this FD - ret - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl Stderr { - pub const fn new() -> Stderr { - Stderr(()) - } -} - -impl io::Write for Stderr { - fn write(&mut self, buf: &[u8]) -> io::Result { - let fd = FileDesc::new(libc::STDERR_FILENO); - let ret = fd.write(buf); - fd.into_raw(); // do not close this FD - ret - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -pub fn is_ebadf(err: &io::Error) -> bool { - err.raw_os_error() == Some(libc::EBADF as i32) -} - -pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; - -pub fn panic_output() -> Option { - Some(Stderr::new()) -} From 678d078950b1a6a822545db44fe3f87ac302f8f3 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 19:01:56 +0200 Subject: [PATCH 196/446] Take sys/vxworks/thread_local_key from sys/unix instead. --- library/std/src/sys/vxworks/mod.rs | 1 + .../std/src/sys/vxworks/thread_local_key.rs | 34 ------------------- 2 files changed, 1 insertion(+), 34 deletions(-) delete mode 100644 library/std/src/sys/vxworks/thread_local_key.rs diff --git a/library/std/src/sys/vxworks/mod.rs b/library/std/src/sys/vxworks/mod.rs index 3b5f2f8561f..2ccdc80e403 100644 --- a/library/std/src/sys/vxworks/mod.rs +++ b/library/std/src/sys/vxworks/mod.rs @@ -35,6 +35,7 @@ pub mod stdio; #[path = "../unix/thread.rs"] pub mod thread; pub mod thread_local_dtor; +#[path = "../unix/thread_local_key.rs"] pub mod thread_local_key; #[path = "../unix/time.rs"] pub mod time; diff --git a/library/std/src/sys/vxworks/thread_local_key.rs b/library/std/src/sys/vxworks/thread_local_key.rs deleted file mode 100644 index 2c5b94b1e61..00000000000 --- a/library/std/src/sys/vxworks/thread_local_key.rs +++ /dev/null @@ -1,34 +0,0 @@ -#![allow(dead_code)] // not used on all platforms - -use crate::mem; - -pub type Key = libc::pthread_key_t; - -#[inline] -pub unsafe fn create(dtor: Option) -> Key { - let mut key = 0; - assert_eq!(libc::pthread_key_create(&mut key, mem::transmute(dtor)), 0); - key -} - -#[inline] -pub unsafe fn set(key: Key, value: *mut u8) { - let r = libc::pthread_setspecific(key, value as *mut _); - debug_assert_eq!(r, 0); -} - -#[inline] -pub unsafe fn get(key: Key) -> *mut u8 { - libc::pthread_getspecific(key) as *mut u8 -} - -#[inline] -pub unsafe fn destroy(key: Key) { - let r = libc::pthread_key_delete(key); - debug_assert_eq!(r, 0); -} - -#[inline] -pub fn requires_synchronized_create() -> bool { - false -} From 66c9b04e947996c9ac3c573228ed2a641fb6f249 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 19:09:07 +0200 Subject: [PATCH 197/446] Take sys/vxworks/alloc from sys/unix instead. --- library/std/src/sys/vxworks/alloc.rs | 49 ---------------------------- library/std/src/sys/vxworks/mod.rs | 1 + 2 files changed, 1 insertion(+), 49 deletions(-) delete mode 100644 library/std/src/sys/vxworks/alloc.rs diff --git a/library/std/src/sys/vxworks/alloc.rs b/library/std/src/sys/vxworks/alloc.rs deleted file mode 100644 index 97a191d7232..00000000000 --- a/library/std/src/sys/vxworks/alloc.rs +++ /dev/null @@ -1,49 +0,0 @@ -use crate::alloc::{GlobalAlloc, Layout, System}; -use crate::ptr; -use crate::sys_common::alloc::{realloc_fallback, MIN_ALIGN}; - -#[stable(feature = "alloc_system_type", since = "1.28.0")] -unsafe impl GlobalAlloc for System { - #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::malloc(layout.size()) as *mut u8 - } else { - aligned_malloc(&layout) - } - } - - #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { - if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::calloc(layout.size(), 1) as *mut u8 - } else { - let ptr = self.alloc(layout.clone()); - if !ptr.is_null() { - ptr::write_bytes(ptr, 0, layout.size()); - } - ptr - } - } - - #[inline] - unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { - libc::free(ptr as *mut libc::c_void) - } - - #[inline] - unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { - if layout.align() <= MIN_ALIGN && layout.align() <= new_size { - libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 - } else { - realloc_fallback(self, ptr, layout, new_size) - } - } -} - -#[inline] -unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { - let mut out = ptr::null_mut(); - let ret = libc::posix_memalign(&mut out, layout.align(), layout.size()); - if ret != 0 { ptr::null_mut() } else { out as *mut u8 } -} diff --git a/library/std/src/sys/vxworks/mod.rs b/library/std/src/sys/vxworks/mod.rs index 2ccdc80e403..ed82122e727 100644 --- a/library/std/src/sys/vxworks/mod.rs +++ b/library/std/src/sys/vxworks/mod.rs @@ -7,6 +7,7 @@ pub use self::rand::hashmap_random_keys; pub use crate::os::vxworks as platform; pub use libc::strlen; +#[path = "../unix/alloc.rs"] pub mod alloc; pub mod args; pub mod cmath; From c909ff957752104e1c52d20d7e0e98cf50781a25 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 20:38:25 +0200 Subject: [PATCH 198/446] Add weak macro to vxworks. --- library/std/src/sys/vxworks/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/std/src/sys/vxworks/mod.rs b/library/std/src/sys/vxworks/mod.rs index ed82122e727..c1e8bc79b6c 100644 --- a/library/std/src/sys/vxworks/mod.rs +++ b/library/std/src/sys/vxworks/mod.rs @@ -7,6 +7,10 @@ pub use self::rand::hashmap_random_keys; pub use crate::os::vxworks as platform; pub use libc::strlen; +#[macro_use] +#[path = "../unix/weak.rs"] +pub mod weak; + #[path = "../unix/alloc.rs"] pub mod alloc; pub mod args; From a489c33bebaee645efa8be0c9455bed89ef6dd41 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 20:38:25 +0200 Subject: [PATCH 199/446] Take sys/vxworks/ext/* from sys/unix instead. --- library/std/src/sys/vxworks/ext/ffi.rs | 38 - library/std/src/sys/vxworks/ext/fs.rs | 817 --------------------- library/std/src/sys/vxworks/ext/io.rs | 208 ------ library/std/src/sys/vxworks/ext/mod.rs | 24 - library/std/src/sys/vxworks/ext/process.rs | 229 ------ library/std/src/sys/vxworks/ext/raw.rs | 5 - library/std/src/sys/vxworks/mod.rs | 1 + 7 files changed, 1 insertion(+), 1321 deletions(-) delete mode 100644 library/std/src/sys/vxworks/ext/ffi.rs delete mode 100644 library/std/src/sys/vxworks/ext/fs.rs delete mode 100644 library/std/src/sys/vxworks/ext/io.rs delete mode 100644 library/std/src/sys/vxworks/ext/mod.rs delete mode 100644 library/std/src/sys/vxworks/ext/process.rs delete mode 100644 library/std/src/sys/vxworks/ext/raw.rs diff --git a/library/std/src/sys/vxworks/ext/ffi.rs b/library/std/src/sys/vxworks/ext/ffi.rs deleted file mode 100644 index 76b34a6b5d8..00000000000 --- a/library/std/src/sys/vxworks/ext/ffi.rs +++ /dev/null @@ -1,38 +0,0 @@ -//! Unix-specific extension to the primitives in the `std::ffi` module -//! -//! # Examples -//! -//! ``` -//! use std::ffi::OsString; -//! use std::os::unix::ffi::OsStringExt; -//! -//! let bytes = b"foo".to_vec(); -//! -//! // OsStringExt::from_vec -//! let os_string = OsString::from_vec(bytes); -//! assert_eq!(os_string.to_str(), Some("foo")); -//! -//! // OsStringExt::into_vec -//! let bytes = os_string.into_vec(); -//! assert_eq!(bytes, b"foo"); -//! ``` -//! -//! ``` -//! use std::ffi::OsStr; -//! use std::os::unix::ffi::OsStrExt; -//! -//! let bytes = b"foo"; -//! -//! // OsStrExt::from_bytes -//! let os_str = OsStr::from_bytes(bytes); -//! assert_eq!(os_str.to_str(), Some("foo")); -//! -//! // OsStrExt::as_bytes -//! let bytes = os_str.as_bytes(); -//! assert_eq!(bytes, b"foo"); -//! ``` - -#![stable(feature = "rust1", since = "1.0.0")] - -#[stable(feature = "rust1", since = "1.0.0")] -pub use crate::sys_common::os_str_bytes::*; diff --git a/library/std/src/sys/vxworks/ext/fs.rs b/library/std/src/sys/vxworks/ext/fs.rs deleted file mode 100644 index 68dc21b806c..00000000000 --- a/library/std/src/sys/vxworks/ext/fs.rs +++ /dev/null @@ -1,817 +0,0 @@ -#![stable(feature = "rust1", since = "1.0.0")] - -use crate::fs::{self, Permissions}; -use crate::io; -use crate::path::Path; -use crate::sys; -use crate::sys::platform::fs::MetadataExt as UnixMetadataExt; -use crate::sys_common::{AsInner, AsInnerMut, FromInner}; - -/// Unix-specific extensions to [`fs::File`]. -#[stable(feature = "file_offset", since = "1.15.0")] -pub trait FileExt { - /// Reads a number of bytes starting from a given offset. - /// - /// Returns the number of bytes read. - /// - /// The offset is relative to the start of the file and thus independent - /// from the current cursor. - /// - /// The current file cursor is not affected by this function. - /// - /// Note that similar to [`File::read`], it is not an error to return with a - /// short read. - /// - /// [`File::read`]: fs::File::read - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::fs::File; - /// use std::os::unix::prelude::FileExt; - /// - /// fn main() -> io::Result<()> { - /// let mut buf = [0u8; 8]; - /// let file = File::open("foo.txt")?; - /// - /// // We now read 8 bytes from the offset 10. - /// let num_bytes_read = file.read_at(&mut buf, 10)?; - /// println!("read {} bytes: {:?}", num_bytes_read, buf); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_offset", since = "1.15.0")] - fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result; - - /// Reads the exact number of byte required to fill `buf` from the given offset. - /// - /// The offset is relative to the start of the file and thus independent - /// from the current cursor. - /// - /// The current file cursor is not affected by this function. - /// - /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`. - /// - /// [`Read::read_exact`]: io::Read::read_exact - /// [`read_at`]: FileExt::read_at - /// - /// # Errors - /// - /// If this function encounters an error of the kind - /// [`ErrorKind::Interrupted`] then the error is ignored and the operation - /// will continue. - /// - /// If this function encounters an "end of file" before completely filling - /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`]. - /// The contents of `buf` are unspecified in this case. - /// - /// If any other read error is encountered then this function immediately - /// returns. The contents of `buf` are unspecified in this case. - /// - /// If this function returns an error, it is unspecified how many bytes it - /// has read, but it will never read more than would be necessary to - /// completely fill the buffer. - /// - /// [`ErrorKind::Interrupted`]: io::ErrorKind::Interrupted - /// [`ErrorKind::UnexpectedEof`]: io::ErrorKind::UnexpectedEof - /// - /// # Examples - /// - /// ```no_run - /// #![feature(rw_exact_all_at)] - /// use std::io; - /// use std::fs::File; - /// use std::os::unix::prelude::FileExt; - /// - /// fn main() -> io::Result<()> { - /// let mut buf = [0u8; 8]; - /// let file = File::open("foo.txt")?; - /// - /// // We now read exactly 8 bytes from the offset 10. - /// file.read_exact_at(&mut buf, 10)?; - /// println!("read {} bytes: {:?}", buf.len(), buf); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rw_exact_all_at", since = "1.33.0")] - fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> { - while !buf.is_empty() { - match self.read_at(buf, offset) { - Ok(0) => break, - Ok(n) => { - let tmp = buf; - buf = &mut tmp[n..]; - offset += n as u64; - } - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} - Err(e) => return Err(e), - } - } - if !buf.is_empty() { - Err(io::Error::new(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer")) - } else { - Ok(()) - } - } - - /// Writes a number of bytes starting from a given offset. - /// - /// Returns the number of bytes written. - /// - /// The offset is relative to the start of the file and thus independent - /// from the current cursor. - /// - /// The current file cursor is not affected by this function. - /// - /// When writing beyond the end of the file, the file is appropriately - /// extended and the intermediate bytes are initialized with the value 0. - /// - /// Note that similar to [`File::write`], it is not an error to return a - /// short write. - /// - /// [`File::write`]: fs::File::write - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io; - /// use std::os::unix::prelude::FileExt; - /// - /// fn main() -> io::Result<()> { - /// let file = File::open("foo.txt")?; - /// - /// // We now write at the offset 10. - /// file.write_at(b"sushi", 10)?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_offset", since = "1.15.0")] - fn write_at(&self, buf: &[u8], offset: u64) -> io::Result; - - /// Attempts to write an entire buffer starting from a given offset. - /// - /// The offset is relative to the start of the file and thus independent - /// from the current cursor. - /// - /// The current file cursor is not affected by this function. - /// - /// This method will continuously call [`write_at`] until there is no more data - /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is - /// returned. This method will not return until the entire buffer has been - /// successfully written or such an error occurs. The first error that is - /// not of [`ErrorKind::Interrupted`] kind generated from this method will be - /// returned. - /// - /// # Errors - /// - /// This function will return the first error of - /// non-[`ErrorKind::Interrupted`] kind that [`write_at`] returns. - /// - /// [`ErrorKind::Interrupted`]: io::ErrorKind::Interrupted - /// [`write_at`]: FileExt::write_at - /// - /// # Examples - /// - /// ```no_run - /// #![feature(rw_exact_all_at)] - /// use std::fs::File; - /// use std::io; - /// use std::os::unix::prelude::FileExt; - /// - /// fn main() -> io::Result<()> { - /// let file = File::open("foo.txt")?; - /// - /// // We now write at the offset 10. - /// file.write_all_at(b"sushi", 10)?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rw_exact_all_at", since = "1.33.0")] - fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> { - while !buf.is_empty() { - match self.write_at(buf, offset) { - Ok(0) => { - return Err(io::Error::new( - io::ErrorKind::WriteZero, - "failed to write whole buffer", - )); - } - Ok(n) => { - buf = &buf[n..]; - offset += n as u64 - } - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} - Err(e) => return Err(e), - } - } - Ok(()) - } -} - -#[stable(feature = "file_offset", since = "1.15.0")] -impl FileExt for fs::File { - fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { - self.as_inner().read_at(buf, offset) - } - fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { - self.as_inner().write_at(buf, offset) - } -} - -/// Unix-specific extensions to [`fs::Permissions`]. -#[stable(feature = "fs_ext", since = "1.1.0")] -pub trait PermissionsExt { - /// Returns the underlying raw `st_mode` bits that contain the standard - /// Unix permissions for this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::os::unix::fs::PermissionsExt; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let permissions = metadata.permissions(); - /// - /// println!("permissions: {}", permissions.mode()); - /// Ok(()) } - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn mode(&self) -> u32; - - /// Sets the underlying raw bits for this set of permissions. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::os::unix::fs::PermissionsExt; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let mut permissions = metadata.permissions(); - /// - /// permissions.set_mode(0o644); // Read/write for owner and read for others. - /// assert_eq!(permissions.mode(), 0o644); - /// Ok(()) } - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn set_mode(&mut self, mode: u32); - - /// Creates a new instance of `Permissions` from the given set of Unix - /// permission bits. - /// - /// # Examples - /// - /// ``` - /// use std::fs::Permissions; - /// use std::os::unix::fs::PermissionsExt; - /// - /// // Read/write for owner and read for others. - /// let permissions = Permissions::from_mode(0o644); - /// assert_eq!(permissions.mode(), 0o644); - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn from_mode(mode: u32) -> Self; -} - -#[stable(feature = "fs_ext", since = "1.1.0")] -impl PermissionsExt for Permissions { - fn mode(&self) -> u32 { - self.as_inner().mode() - } - - fn set_mode(&mut self, mode: u32) { - *self = Permissions::from_inner(FromInner::from_inner(mode)); - } - - fn from_mode(mode: u32) -> Permissions { - Permissions::from_inner(FromInner::from_inner(mode)) - } -} - -/// Unix-specific extensions to [`fs::OpenOptions`]. -#[stable(feature = "fs_ext", since = "1.1.0")] -pub trait OpenOptionsExt { - /// Sets the mode bits that a new file will be created with. - /// - /// If a new file is created as part of an `OpenOptions::open` call then this - /// specified `mode` will be used as the permission bits for the new file. - /// If no `mode` is set, the default of `0o666` will be used. - /// The operating system masks out bits with the system's `umask`, to produce - /// the final permissions. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// use std::os::unix::fs::OpenOptionsExt; - /// - /// # fn main() { - /// let mut options = OpenOptions::new(); - /// options.mode(0o644); // Give read/write for owner and read for others. - /// let file = options.open("foo.txt"); - /// # } - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn mode(&mut self, mode: u32) -> &mut Self; - - /// Pass custom flags to the `flags` argument of `open`. - /// - /// The bits that define the access mode are masked out with `O_ACCMODE`, to - /// ensure they do not interfere with the access mode set by Rusts options. - /// - /// Custom flags can only set flags, not remove flags set by Rusts options. - /// This options overwrites any previously set custom flags. - /// - /// # Examples - /// - /// ```no_run - /// # #![feature(libc)] - /// extern crate libc; - /// use std::fs::OpenOptions; - /// use std::os::unix::fs::OpenOptionsExt; - /// - /// # fn main() { - /// let mut options = OpenOptions::new(); - /// options.write(true); - /// if cfg!(unix) { - /// options.custom_flags(libc::O_NOFOLLOW); - /// } - /// let file = options.open("foo.txt"); - /// # } - /// ``` - #[stable(feature = "open_options_ext", since = "1.10.0")] - fn custom_flags(&mut self, flags: i32) -> &mut Self; -} - -/*#[stable(feature = "fs_ext", since = "1.1.0")] -impl OpenOptionsExt for OpenOptions { - fn mode(&mut self, mode: u32) -> &mut OpenOptions { - self.as_inner_mut().mode(mode); self - } - - fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions { - self.as_inner_mut().custom_flags(flags); self - } -} -*/ - -/// Unix-specific extensions to [`fs::Metadata`]. -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Returns the ID of the device containing the file. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let dev_id = meta.dev(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn dev(&self) -> u64; - /// Returns the inode number. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let inode = meta.ino(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn ino(&self) -> u64; - /// Returns the rights applied to this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let mode = meta.mode(); - /// let user_has_write_access = mode & 0o200; - /// let user_has_read_write_access = mode & 0o600; - /// let group_has_read_access = mode & 0o040; - /// let others_have_exec_access = mode & 0o001; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn mode(&self) -> u32; - /// Returns the number of hard links pointing to this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nb_hard_links = meta.nlink(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn nlink(&self) -> u64; - /// Returns the user ID of the owner of this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let user_id = meta.uid(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn uid(&self) -> u32; - /// Returns the group ID of the owner of this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let group_id = meta.gid(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn gid(&self) -> u32; - /// Returns the device ID of this file (if it is a special one). - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let device_id = meta.rdev(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn rdev(&self) -> u64; - /// Returns the total size of this file in bytes. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let file_size = meta.size(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn size(&self) -> u64; - /// Returns the time of the last access to the file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let last_access_time = meta.atime(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn atime(&self) -> i64; - /// Returns the time of the last access to the file in nanoseconds. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nano_last_access_time = meta.atime_nsec(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn mtime(&self) -> i64; - /// Returns the time of the last modification of the file in nanoseconds. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nano_last_modification_time = meta.mtime_nsec(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn ctime(&self) -> i64; - /// Returns the time of the last status change of the file in nanoseconds. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nano_last_status_change_time = meta.ctime_nsec(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn blksize(&self) -> u64; - /// Returns the number of blocks allocated to the file, in 512-byte units. - /// - /// Please note that this may be smaller than `st_size / 512` when the file has holes. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let blocks = meta.blocks(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn blocks(&self) -> u64; - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn attrib(&self) -> u8; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for fs::Metadata { - fn dev(&self) -> u64 { - self.st_dev() - } - fn ino(&self) -> u64 { - self.st_ino() - } - fn mode(&self) -> u32 { - self.st_mode() - } - fn nlink(&self) -> u64 { - self.st_nlink() - } - fn uid(&self) -> u32 { - self.st_uid() - } - fn gid(&self) -> u32 { - self.st_gid() - } - fn rdev(&self) -> u64 { - self.st_rdev() - } - fn size(&self) -> u64 { - self.st_size() - } - fn atime(&self) -> i64 { - self.st_atime() - } - fn mtime(&self) -> i64 { - self.st_mtime() - } - fn ctime(&self) -> i64 { - self.st_ctime() - } - fn blksize(&self) -> u64 { - self.st_blksize() - } - fn blocks(&self) -> u64 { - self.st_blocks() - } - fn attrib(&self) -> u8 { - self.st_attrib() - } -} - -/// Unix-specific extensions for [`fs::FileType`]. -/// -/// Adds support for special Unix file types such as block/character devices, -/// pipes, and sockets. -#[stable(feature = "file_type_ext", since = "1.5.0")] -pub trait FileTypeExt { - /// Returns whether this file type is a block device. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::FileTypeExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("block_device_file")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_block_device()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_block_device(&self) -> bool; - /// Returns whether this file type is a char device. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::FileTypeExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("char_device_file")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_char_device()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_char_device(&self) -> bool; - /// Returns whether this file type is a fifo. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::FileTypeExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("fifo_file")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_fifo()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_fifo(&self) -> bool; - /// Returns whether this file type is a socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::FileTypeExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("unix.socket")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_socket()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_socket(&self) -> bool; -} - -#[stable(feature = "file_type_ext", since = "1.5.0")] -impl FileTypeExt for fs::FileType { - fn is_block_device(&self) -> bool { - self.as_inner().is(libc::S_IFBLK) - } - fn is_char_device(&self) -> bool { - self.as_inner().is(libc::S_IFCHR) - } - fn is_fifo(&self) -> bool { - self.as_inner().is(libc::S_IFIFO) - } - fn is_socket(&self) -> bool { - self.as_inner().is(libc::S_IFSOCK) - } -} - -/// Unix-specific extension methods for [`fs::DirEntry`]. -#[stable(feature = "dir_entry_ext", since = "1.1.0")] -pub trait DirEntryExt { - /// Returns the underlying `d_ino` field in the contained `dirent` - /// structure. - /// - /// # Examples - /// - /// ``` - /// use std::fs; - /// use std::os::unix::fs::DirEntryExt; - /// - /// if let Ok(entries) = fs::read_dir(".") { - /// for entry in entries { - /// if let Ok(entry) = entry { - /// // Here, `entry` is a `DirEntry`. - /// println!("{:?}: {}", entry.file_name(), entry.ino()); - /// } - /// } - /// } - /// ``` - #[stable(feature = "dir_entry_ext", since = "1.1.0")] - fn ino(&self) -> u64; -} - -#[stable(feature = "dir_entry_ext", since = "1.1.0")] -impl DirEntryExt for fs::DirEntry { - fn ino(&self) -> u64 { - self.as_inner().ino() - } -} - -/// Creates a new symbolic link on the filesystem. -/// -/// The `dst` path will be a symbolic link pointing to the `src` path. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::unix::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::symlink("a.txt", "b.txt")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "symlink", since = "1.1.0")] -pub fn symlink, Q: AsRef>(src: P, dst: Q) -> io::Result<()> { - sys::fs::symlink(src.as_ref(), dst.as_ref()) -} - -/// Unix-specific extensions to [`fs::DirBuilder`]. -#[stable(feature = "dir_builder", since = "1.6.0")] -pub trait DirBuilderExt { - /// Sets the mode to create new directories with. This option defaults to - /// 0o777. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::DirBuilder; - /// use std::os::unix::fs::DirBuilderExt; - /// - /// let mut builder = DirBuilder::new(); - /// builder.mode(0o755); - /// ``` - #[stable(feature = "dir_builder", since = "1.6.0")] - fn mode(&mut self, mode: u32) -> &mut Self; -} - -#[stable(feature = "dir_builder", since = "1.6.0")] -impl DirBuilderExt for fs::DirBuilder { - fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder { - self.as_inner_mut().set_mode(mode); - self - } -} diff --git a/library/std/src/sys/vxworks/ext/io.rs b/library/std/src/sys/vxworks/ext/io.rs deleted file mode 100644 index 8b5a2d12af7..00000000000 --- a/library/std/src/sys/vxworks/ext/io.rs +++ /dev/null @@ -1,208 +0,0 @@ -//! Unix-specific extensions to general I/O primitives - -#![stable(feature = "rust1", since = "1.0.0")] - -use crate::fs; -use crate::io; -use crate::net; -use crate::os::raw; -use crate::sys; -use crate::sys_common::{self, AsInner, FromInner, IntoInner}; - -/// Raw file descriptors. -#[stable(feature = "rust1", since = "1.0.0")] -pub type RawFd = raw::c_int; - -/// A trait to extract the raw unix file descriptor from an underlying -/// object. -/// -/// This is only available on unix platforms and must be imported in order -/// to call the method. Windows platforms have a corresponding `AsRawHandle` -/// and `AsRawSocket` set of traits. -#[stable(feature = "rust1", since = "1.0.0")] -pub trait AsRawFd { - /// Extracts the raw file descriptor. - /// - /// This method does **not** pass ownership of the raw file descriptor - /// to the caller. The descriptor is only guaranteed to be valid while - /// the original object has not yet been destroyed. - #[stable(feature = "rust1", since = "1.0.0")] - fn as_raw_fd(&self) -> RawFd; -} - -/// A trait to express the ability to construct an object from a raw file -/// descriptor. -#[stable(feature = "from_raw_os", since = "1.1.0")] -pub trait FromRawFd { - /// Constructs a new instance of `Self` from the given raw file - /// descriptor. - /// - /// This function **consumes ownership** of the specified file - /// descriptor. The returned object will take responsibility for closing - /// it when the object goes out of scope. - /// - /// This function is also unsafe as the primitives currently returned - /// have the contract that they are the sole owner of the file - /// descriptor they are wrapping. Usage of this function could - /// accidentally allow violating this contract which can cause memory - /// unsafety in code that relies on it being true. - #[stable(feature = "from_raw_os", since = "1.1.0")] - unsafe fn from_raw_fd(fd: RawFd) -> Self; -} - -/// A trait to express the ability to consume an object and acquire ownership of -/// its raw file descriptor. -#[stable(feature = "into_raw_os", since = "1.4.0")] -pub trait IntoRawFd { - /// Consumes this object, returning the raw underlying file descriptor. - /// - /// This function **transfers ownership** of the underlying file descriptor - /// to the caller. Callers are then the unique owners of the file descriptor - /// and must close the descriptor once it's no longer needed. - #[stable(feature = "into_raw_os", since = "1.4.0")] - fn into_raw_fd(self) -> RawFd; -} - -#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] -impl AsRawFd for RawFd { - fn as_raw_fd(&self) -> RawFd { - *self - } -} -#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] -impl IntoRawFd for RawFd { - fn into_raw_fd(self) -> RawFd { - self - } -} -#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] -impl FromRawFd for RawFd { - unsafe fn from_raw_fd(fd: RawFd) -> RawFd { - fd - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for fs::File { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() - } -} -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for fs::File { - unsafe fn from_raw_fd(fd: RawFd) -> fs::File { - fs::File::from_inner(sys::fs::File::from_inner(fd)) - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for fs::File { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawFd for io::Stdin { - fn as_raw_fd(&self) -> RawFd { - libc::STDIN_FILENO - } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawFd for io::Stdout { - fn as_raw_fd(&self) -> RawFd { - libc::STDOUT_FILENO - } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawFd for io::Stderr { - fn as_raw_fd(&self) -> RawFd { - libc::STDERR_FILENO - } -} - -#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] -impl<'a> AsRawFd for io::StdinLock<'a> { - fn as_raw_fd(&self) -> RawFd { - libc::STDIN_FILENO - } -} - -#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] -impl<'a> AsRawFd for io::StdoutLock<'a> { - fn as_raw_fd(&self) -> RawFd { - libc::STDOUT_FILENO - } -} - -#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] -impl<'a> AsRawFd for io::StderrLock<'a> { - fn as_raw_fd(&self) -> RawFd { - libc::STDERR_FILENO - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpStream { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpListener { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::UdpSocket { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpStream { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { - let socket = sys::net::Socket::from_inner(fd); - net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(socket)) - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpListener { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { - let socket = sys::net::Socket::from_inner(fd); - net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(socket)) - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::UdpSocket { - unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { - let socket = sys::net::Socket::from_inner(fd); - net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket)) - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpStream { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpListener { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::UdpSocket { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} diff --git a/library/std/src/sys/vxworks/ext/mod.rs b/library/std/src/sys/vxworks/ext/mod.rs deleted file mode 100644 index 8fa9bd9d1e2..00000000000 --- a/library/std/src/sys/vxworks/ext/mod.rs +++ /dev/null @@ -1,24 +0,0 @@ -#![stable(feature = "rust1", since = "1.0.0")] -#![allow(missing_docs)] - -pub mod ffi; -pub mod fs; -pub mod io; -pub mod process; -pub mod raw; - -#[stable(feature = "rust1", since = "1.0.0")] -pub mod prelude { - #[doc(no_inline)] - #[stable(feature = "rust1", since = "1.0.0")] - pub use super::ffi::{OsStrExt, OsStringExt}; - #[doc(no_inline)] - #[stable(feature = "rust1", since = "1.0.0")] - pub use super::fs::{FileTypeExt, MetadataExt, OpenOptionsExt, PermissionsExt}; - #[doc(no_inline)] - #[stable(feature = "rust1", since = "1.0.0")] - pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; - #[doc(no_inline)] - #[stable(feature = "rust1", since = "1.0.0")] - pub use super::process::ExitStatusExt; -} diff --git a/library/std/src/sys/vxworks/ext/process.rs b/library/std/src/sys/vxworks/ext/process.rs deleted file mode 100644 index 3ffa5be1b3b..00000000000 --- a/library/std/src/sys/vxworks/ext/process.rs +++ /dev/null @@ -1,229 +0,0 @@ -//! Unix-specific extensions to primitives in the `std::process` module. - -#![stable(feature = "rust1", since = "1.0.0")] - -use crate::ffi::OsStr; -use crate::io; -use crate::process; -use crate::sys; -use crate::sys::vxworks::ext::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; -use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; - -/// Unix-specific extensions to the [`process::Command`] builder. -#[stable(feature = "rust1", since = "1.0.0")] -pub trait CommandExt { - /// Sets the child process's user ID. This translates to a - /// `setuid` call in the child process. Failure in the `setuid` - /// call will cause the spawn to fail. - #[stable(feature = "rust1", since = "1.0.0")] - fn uid(&mut self, id: u16) -> &mut process::Command; - - /// Similar to `uid`, but sets the group ID of the child process. This has - /// the same semantics as the `uid` field. - #[stable(feature = "rust1", since = "1.0.0")] - fn gid(&mut self, id: u16) -> &mut process::Command; - - /// Schedules a closure to be run just before the `exec` function is - /// invoked. - /// - /// The closure is allowed to return an I/O error whose OS error code will - /// be communicated back to the parent and returned as an error from when - /// the spawn was requested. - /// - /// Multiple closures can be registered and they will be called in order of - /// their registration. If a closure returns `Err` then no further closures - /// will be called and the spawn operation will immediately return with a - /// failure. - /// - /// # Notes and Safety - /// - /// This closure will be run in the context of the child process after a - /// `fork`. This primarily means that any modifications made to memory on - /// behalf of this closure will **not** be visible to the parent process. - /// This is often a very constrained environment where normal operations - /// like `malloc` or acquiring a mutex are not guaranteed to work (due to - /// other threads perhaps still running when the `fork` was run). - /// - /// This also means that all resources such as file descriptors and - /// memory-mapped regions got duplicated. It is your responsibility to make - /// sure that the closure does not violate library invariants by making - /// invalid use of these duplicates. - /// - /// When this closure is run, aspects such as the stdio file descriptors and - /// working directory have successfully been changed, so output to these - /// locations may not appear where intended. - #[stable(feature = "process_pre_exec", since = "1.34.0")] - unsafe fn pre_exec(&mut self, f: F) -> &mut process::Command - where - F: FnMut() -> io::Result<()> + Send + Sync + 'static; - - /// Schedules a closure to be run just before the `exec` function is - /// invoked. - /// - /// This method is stable and usable, but it should be unsafe. To fix - /// that, it got deprecated in favor of the unsafe [`pre_exec`]. - /// - /// [`pre_exec`]: CommandExt::pre_exec - #[stable(feature = "process_exec", since = "1.15.0")] - #[rustc_deprecated(since = "1.37.0", reason = "should be unsafe, use `pre_exec` instead")] - fn before_exec(&mut self, f: F) -> &mut process::Command - where - F: FnMut() -> io::Result<()> + Send + Sync + 'static, - { - unsafe { self.pre_exec(f) } - } - - /// Performs all the required setup by this `Command`, followed by calling - /// the `execvp` syscall. - /// - /// On success this function will not return, and otherwise it will return - /// an error indicating why the exec (or another part of the setup of the - /// `Command`) failed. - /// - /// `exec` not returning has the same implications as calling - /// [`process::exit`] – no destructors on the current stack or any other - /// thread’s stack will be run. Therefore, it is recommended to only call - /// `exec` at a point where it is fine to not run any destructors. Note, - /// that the `execvp` syscall independently guarantees that all memory is - /// freed and all file descriptors with the `CLOEXEC` option (set by default - /// on all file descriptors opened by the standard library) are closed. - /// - /// This function, unlike `spawn`, will **not** `fork` the process to create - /// a new child. Like spawn, however, the default behavior for the stdio - /// descriptors will be to inherited from the current process. - /// - /// - /// # Notes - /// - /// The process may be in a "broken state" if this function returns in - /// error. For example the working directory, environment variables, signal - /// handling settings, various user/group information, or aspects of stdio - /// file descriptors may have changed. If a "transactional spawn" is - /// required to gracefully handle errors it is recommended to use the - /// cross-platform `spawn` instead. - #[stable(feature = "process_exec2", since = "1.9.0")] - fn exec(&mut self) -> io::Error; - - /// Set executable argument - /// - /// Set the first process argument, `argv[0]`, to something other than the - /// default executable path. - #[stable(feature = "process_set_argv0", since = "1.45.0")] - fn arg0(&mut self, arg: S) -> &mut process::Command - where - S: AsRef; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl CommandExt for process::Command { - fn uid(&mut self, id: u16) -> &mut process::Command { - self.as_inner_mut().uid(id); - self - } - - fn gid(&mut self, id: u16) -> &mut process::Command { - self.as_inner_mut().gid(id); - self - } - - unsafe fn pre_exec(&mut self, f: F) -> &mut process::Command - where - F: FnMut() -> io::Result<()> + Send + Sync + 'static, - { - self.as_inner_mut().pre_exec(Box::new(f)); - self - } - - fn exec(&mut self) -> io::Error { - self.as_inner_mut().exec(sys::process::Stdio::Inherit) - } - - fn arg0(&mut self, arg: S) -> &mut process::Command - where - S: AsRef, - { - self.as_inner_mut().set_arg_0(arg.as_ref()); - self - } -} - -/// Unix-specific extensions to [`process::ExitStatus`]. -#[stable(feature = "rust1", since = "1.0.0")] -pub trait ExitStatusExt { - /// Creates a new `ExitStatus` from the raw underlying `i32` return value of - /// a process. - #[stable(feature = "exit_status_from", since = "1.12.0")] - fn from_raw(raw: i32) -> Self; - - /// If the process was terminated by a signal, returns that signal. - #[stable(feature = "rust1", since = "1.0.0")] - fn signal(&self) -> Option; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExitStatusExt for process::ExitStatus { - fn from_raw(raw: i32) -> Self { - process::ExitStatus::from_inner(From::from(raw)) - } - - fn signal(&self) -> Option { - self.as_inner().signal() - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl FromRawFd for process::Stdio { - unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio { - let fd = sys::fd::FileDesc::new(fd); - let io = sys::process::Stdio::Fd(fd); - process::Stdio::from_inner(io) - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl AsRawFd for process::ChildStdin { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl AsRawFd for process::ChildStdout { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl AsRawFd for process::ChildStderr { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for process::ChildStdin { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for process::ChildStdout { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for process::ChildStderr { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -/// Returns the OS-assigned process identifier associated with this process's parent. -#[stable(feature = "unix_ppid", since = "1.27.0")] -pub fn parent_id() -> u32 { - crate::sys::os::getppid() -} diff --git a/library/std/src/sys/vxworks/ext/raw.rs b/library/std/src/sys/vxworks/ext/raw.rs deleted file mode 100644 index 1f134f4e2d1..00000000000 --- a/library/std/src/sys/vxworks/ext/raw.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![stable(feature = "raw_ext", since = "1.1.0")] - -#[doc(inline)] -#[stable(feature = "pthread_t", since = "1.8.0")] -pub use crate::sys::platform::raw::pthread_t; diff --git a/library/std/src/sys/vxworks/mod.rs b/library/std/src/sys/vxworks/mod.rs index c1e8bc79b6c..1354c0802e8 100644 --- a/library/std/src/sys/vxworks/mod.rs +++ b/library/std/src/sys/vxworks/mod.rs @@ -18,6 +18,7 @@ pub mod cmath; #[path = "../unix/condvar.rs"] pub mod condvar; pub mod env; +#[path = "../unix/ext/mod.rs"] pub mod ext; pub mod fd; pub mod fs; From dce405ae3dd5996a3f97f13f40f87f23261f8ccd Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 20:38:25 +0200 Subject: [PATCH 200/446] Take sys/vxworks/net from sys/unix instead. --- library/std/src/sys/unix/net.rs | 10 +- library/std/src/sys/vxworks/mod.rs | 1 + library/std/src/sys/vxworks/net.rs | 335 ----------------------- library/std/src/sys/vxworks/net/tests.rs | 23 -- 4 files changed, 9 insertions(+), 360 deletions(-) delete mode 100644 library/std/src/sys/vxworks/net.rs delete mode 100644 library/std/src/sys/vxworks/net/tests.rs diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 011325fddc5..74c7db27226 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -77,6 +77,7 @@ impl Socket { } } + #[cfg(not(target_os = "vxworks"))] pub fn new_pair(fam: c_int, ty: c_int) -> io::Result<(Socket, Socket)> { unsafe { let mut fds = [0, 0]; @@ -98,6 +99,11 @@ impl Socket { } } + #[cfg(target_os = "vxworks")] + pub fn new_pair(_fam: c_int, _ty: c_int) -> io::Result<(Socket, Socket)> { + unimplemented!() + } + pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { self.set_nonblocking(true)?; let r = unsafe { @@ -366,7 +372,7 @@ impl IntoInner for Socket { // res_init unconditionally, we call it only when we detect we're linking // against glibc version < 2.26. (That is, when we both know its needed and // believe it's thread-safe). -#[cfg(target_env = "gnu")] +#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))] fn on_resolver_failure() { use crate::sys; @@ -378,5 +384,5 @@ fn on_resolver_failure() { } } -#[cfg(not(target_env = "gnu"))] +#[cfg(any(not(target_env = "gnu"), target_os = "vxworks"))] fn on_resolver_failure() {} diff --git a/library/std/src/sys/vxworks/mod.rs b/library/std/src/sys/vxworks/mod.rs index 1354c0802e8..27e53fa9854 100644 --- a/library/std/src/sys/vxworks/mod.rs +++ b/library/std/src/sys/vxworks/mod.rs @@ -26,6 +26,7 @@ pub mod io; pub mod memchr; #[path = "../unix/mutex.rs"] pub mod mutex; +#[path = "../unix/net.rs"] pub mod net; pub mod os; pub mod path; diff --git a/library/std/src/sys/vxworks/net.rs b/library/std/src/sys/vxworks/net.rs deleted file mode 100644 index 7613fbec46f..00000000000 --- a/library/std/src/sys/vxworks/net.rs +++ /dev/null @@ -1,335 +0,0 @@ -#[cfg(all(test, taget_env = "gnu"))] -mod tests; - -use crate::cmp; -use crate::ffi::CStr; -use crate::io; -use crate::io::{IoSlice, IoSliceMut}; -use crate::mem; -use crate::net::{Shutdown, SocketAddr}; -use crate::str; -use crate::sys::fd::FileDesc; -use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}; -use crate::sys_common::{AsInner, FromInner, IntoInner}; -use crate::time::{Duration, Instant}; -use libc::{self, c_int, c_void, size_t, sockaddr, socklen_t, EAI_SYSTEM, MSG_PEEK}; - -pub use crate::sys::{cvt, cvt_r}; - -#[allow(unused_extern_crates)] -pub extern crate libc as netc; - -pub type wrlen_t = size_t; - -pub struct Socket(FileDesc); - -pub fn init() {} - -pub fn cvt_gai(err: c_int) -> io::Result<()> { - if err == 0 { - return Ok(()); - } - - // We may need to trigger a glibc workaround. See on_resolver_failure() for details. - on_resolver_failure(); - - if err == EAI_SYSTEM { - return Err(io::Error::last_os_error()); - } - - let detail = unsafe { - str::from_utf8(CStr::from_ptr(libc::gai_strerror(err)).to_bytes()).unwrap().to_owned() - }; - Err(io::Error::new( - io::ErrorKind::Other, - &format!("failed to lookup address information: {}", detail)[..], - )) -} - -impl Socket { - pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result { - let fam = match *addr { - SocketAddr::V4(..) => libc::AF_INET, - SocketAddr::V6(..) => libc::AF_INET6, - }; - Socket::new_raw(fam, ty) - } - - pub fn new_raw(fam: c_int, ty: c_int) -> io::Result { - unsafe { - let fd = cvt(libc::socket(fam, ty, 0))?; - let fd = FileDesc::new(fd); - fd.set_cloexec()?; - let socket = Socket(fd); - Ok(socket) - } - } - - pub fn new_pair(_fam: c_int, _ty: c_int) -> io::Result<(Socket, Socket)> { - unimplemented!(); - } - - pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { - self.set_nonblocking(true)?; - let r = unsafe { - let (addrp, len) = addr.into_inner(); - cvt(libc::connect(self.0.raw(), addrp, len)) - }; - self.set_nonblocking(false)?; - - match r { - Ok(_) => return Ok(()), - // there's no ErrorKind for EINPROGRESS :( - Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {} - Err(e) => return Err(e), - } - - let mut pollfd = libc::pollfd { fd: self.0.raw(), events: libc::POLLOUT, revents: 0 }; - - if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout", - )); - } - - let start = Instant::now(); - - loop { - let elapsed = start.elapsed(); - if elapsed >= timeout { - return Err(io::Error::new(io::ErrorKind::TimedOut, "connection timed out")); - } - - let timeout = timeout - elapsed; - let mut timeout = timeout - .as_secs() - .saturating_mul(1_000) - .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000); - if timeout == 0 { - timeout = 1; - } - - let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int; - - match unsafe { libc::poll(&mut pollfd, 1, timeout) } { - -1 => { - let err = io::Error::last_os_error(); - if err.kind() != io::ErrorKind::Interrupted { - return Err(err); - } - } - 0 => {} - _ => { - // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look - // for POLLHUP rather than read readiness - if pollfd.revents & libc::POLLHUP != 0 { - let e = self.take_error()?.unwrap_or_else(|| { - io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP") - }); - return Err(e); - } - - return Ok(()); - } - } - } - } - - pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) -> io::Result { - let fd = cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })?; - let fd = FileDesc::new(fd); - fd.set_cloexec()?; - Ok(Socket(fd)) - } - - pub fn duplicate(&self) -> io::Result { - self.0.duplicate().map(Socket) - } - - fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result { - let ret = cvt(unsafe { - libc::recv(self.0.raw(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags) - })?; - Ok(ret as usize) - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result { - self.recv_with_flags(buf, 0) - } - - pub fn peek(&self, buf: &mut [u8]) -> io::Result { - self.recv_with_flags(buf, MSG_PEEK) - } - - pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.0.read_vectored(bufs) - } - - #[inline] - pub fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - - fn recv_from_with_flags( - &self, - buf: &mut [u8], - flags: c_int, - ) -> io::Result<(usize, SocketAddr)> { - let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; - let mut addrlen = mem::size_of_val(&storage) as libc::socklen_t; - - let n = cvt(unsafe { - libc::recvfrom( - self.0.raw(), - buf.as_mut_ptr() as *mut c_void, - buf.len(), - flags, - &mut storage as *mut _ as *mut _, - &mut addrlen, - ) - })?; - Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?)) - } - - pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_with_flags(buf, 0) - } - - pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_with_flags(buf, MSG_PEEK) - } - - pub fn write(&self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { - self.0.write_vectored(bufs) - } - - #[inline] - pub fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } - - pub fn set_timeout(&self, dur: Option, kind: libc::c_int) -> io::Result<()> { - let timeout = match dur { - Some(dur) => { - if dur.as_secs() == 0 && dur.subsec_nanos() == 0 { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout", - )); - } - - let secs = if dur.as_secs() > libc::time_t::MAX as u64 { - libc::time_t::MAX - } else { - dur.as_secs() as libc::time_t - }; - let mut timeout = libc::timeval { - tv_sec: secs, - tv_usec: (dur.subsec_nanos() / 1000) as libc::suseconds_t, - }; - if timeout.tv_sec == 0 && timeout.tv_usec == 0 { - timeout.tv_usec = 1; - } - timeout - } - None => libc::timeval { tv_sec: 0, tv_usec: 0 }, - }; - setsockopt(self, libc::SOL_SOCKET, kind, timeout) - } - - pub fn timeout(&self, kind: libc::c_int) -> io::Result> { - let raw: libc::timeval = getsockopt(self, libc::SOL_SOCKET, kind)?; - if raw.tv_sec == 0 && raw.tv_usec == 0 { - Ok(None) - } else { - let sec = raw.tv_sec as u64; - let nsec = (raw.tv_usec as u32) * 1000; - Ok(Some(Duration::new(sec, nsec))) - } - } - - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - let how = match how { - Shutdown::Write => libc::SHUT_WR, - Shutdown::Read => libc::SHUT_RD, - Shutdown::Both => libc::SHUT_RDWR, - }; - cvt(unsafe { libc::shutdown(self.0.raw(), how) })?; - Ok(()) - } - - pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - setsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) - } - - pub fn nodelay(&self) -> io::Result { - let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY)?; - Ok(raw != 0) - } - - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - let mut nonblocking = nonblocking as libc::c_int; - cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO, &mut nonblocking) }).map(drop) - } - - pub fn take_error(&self) -> io::Result> { - let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?; - if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } - } -} - -impl AsInner for Socket { - fn as_inner(&self) -> &c_int { - self.0.as_inner() - } -} - -impl FromInner for Socket { - fn from_inner(fd: c_int) -> Socket { - Socket(FileDesc::new(fd)) - } -} - -impl IntoInner for Socket { - fn into_inner(self) -> c_int { - self.0.into_raw() - } -} - -// In versions of glibc prior to 2.26, there's a bug where the DNS resolver -// will cache the contents of /etc/resolv.conf, so changes to that file on disk -// can be ignored by a long-running program. That can break DNS lookups on e.g. -// laptops where the network comes and goes. See -// https://sourceware.org/bugzilla/show_bug.cgi?id=984. Note however that some -// distros including Debian have patched glibc to fix this for a long time. -// -// A workaround for this bug is to call the res_init libc function, to clear -// the cached configs. Unfortunately, while we believe glibc's implementation -// of res_init is thread-safe, we know that other implementations are not -// (https://github.com/rust-lang/rust/issues/43592). Code here in libstd could -// try to synchronize its res_init calls with a Mutex, but that wouldn't -// protect programs that call into libc in other ways. So instead of calling -// res_init unconditionally, we call it only when we detect we're linking -// against glibc version < 2.26. (That is, when we both know its needed and -// believe it's thread-safe). -#[cfg(target_env = "gnu")] -fn on_resolver_failure() { - /* - use crate::sys; - - // If the version fails to parse, we treat it the same as "not glibc". - if let Some(version) = sys::os::glibc_version() { - if version < (2, 26) { - unsafe { libc::res_init() }; - } - } - */ -} - -#[cfg(not(target_env = "gnu"))] -fn on_resolver_failure() {} diff --git a/library/std/src/sys/vxworks/net/tests.rs b/library/std/src/sys/vxworks/net/tests.rs deleted file mode 100644 index e7c6e348f8e..00000000000 --- a/library/std/src/sys/vxworks/net/tests.rs +++ /dev/null @@ -1,23 +0,0 @@ -use super::*; - -#[test] -fn test_res_init() { - // This mostly just tests that the weak linkage doesn't panic wildly... - res_init_if_glibc_before_2_26().unwrap(); -} - -#[test] -fn test_parse_glibc_version() { - let cases = [ - ("0.0", Some((0, 0))), - ("01.+2", Some((1, 2))), - ("3.4.5.six", Some((3, 4))), - ("1", None), - ("1.-2", None), - ("1.foo", None), - ("foo.1", None), - ]; - for &(version_str, parsed) in cases.iter() { - assert_eq!(parsed, parse_glibc_version(version_str)); - } -} From 08bcaac0913a8efe0a6b21255d9c850dc1229894 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 20:38:25 +0200 Subject: [PATCH 201/446] Take sys/vxworks/memchar from sys/unix instead. --- library/std/src/sys/vxworks/memchr.rs | 21 --------------------- library/std/src/sys/vxworks/mod.rs | 1 + 2 files changed, 1 insertion(+), 21 deletions(-) delete mode 100644 library/std/src/sys/vxworks/memchr.rs diff --git a/library/std/src/sys/vxworks/memchr.rs b/library/std/src/sys/vxworks/memchr.rs deleted file mode 100644 index 928100c92ff..00000000000 --- a/library/std/src/sys/vxworks/memchr.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Original implementation taken from rust-memchr. -// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch - -pub fn memchr(needle: u8, haystack: &[u8]) -> Option { - let p = unsafe { - libc::memchr( - haystack.as_ptr() as *const libc::c_void, - needle as libc::c_int, - haystack.len(), - ) - }; - if p.is_null() { None } else { Some(p as usize - (haystack.as_ptr() as usize)) } -} - -pub fn memrchr(needle: u8, haystack: &[u8]) -> Option { - fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option { - core::slice::memchr::memrchr(needle, haystack) - } - - memrchr_specific(needle, haystack) -} diff --git a/library/std/src/sys/vxworks/mod.rs b/library/std/src/sys/vxworks/mod.rs index 27e53fa9854..9853eb3bf3d 100644 --- a/library/std/src/sys/vxworks/mod.rs +++ b/library/std/src/sys/vxworks/mod.rs @@ -23,6 +23,7 @@ pub mod ext; pub mod fd; pub mod fs; pub mod io; +#[path = "../unix/memchr.rs"] pub mod memchr; #[path = "../unix/mutex.rs"] pub mod mutex; From ba483c51dfc1d17c75dc4502397ad92c78a53e77 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 20:38:25 +0200 Subject: [PATCH 202/446] Take sys/vxworks/args from sys/unix instead. --- library/std/src/sys/unix/args.rs | 3 +- library/std/src/sys/vxworks/args.rs | 95 ----------------------------- library/std/src/sys/vxworks/mod.rs | 1 + 3 files changed, 3 insertions(+), 96 deletions(-) delete mode 100644 library/std/src/sys/vxworks/args.rs diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs index f7c3f163718..69676472493 100644 --- a/library/std/src/sys/unix/args.rs +++ b/library/std/src/sys/unix/args.rs @@ -70,7 +70,8 @@ impl DoubleEndedIterator for Args { target_os = "haiku", target_os = "l4re", target_os = "fuchsia", - target_os = "redox" + target_os = "redox", + target_os = "vxworks" ))] mod imp { use super::Args; diff --git a/library/std/src/sys/vxworks/args.rs b/library/std/src/sys/vxworks/args.rs deleted file mode 100644 index 30cf7a707c7..00000000000 --- a/library/std/src/sys/vxworks/args.rs +++ /dev/null @@ -1,95 +0,0 @@ -#![allow(dead_code)] // runtime init functions not used during testing -use crate::ffi::OsString; -use crate::marker::PhantomData; -use crate::vec; - -/// One-time global initialization. -pub unsafe fn init(argc: isize, argv: *const *const u8) { - imp::init(argc, argv) -} - -/// One-time global cleanup. -pub unsafe fn cleanup() { - imp::cleanup() -} - -/// Returns the command line arguments -pub fn args() -> Args { - imp::args() -} - -pub struct Args { - iter: vec::IntoIter, - _dont_send_or_sync_me: PhantomData<*mut ()>, -} - -impl Args { - pub fn inner_debug(&self) -> &[OsString] { - self.iter.as_slice() - } -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.iter.next_back() - } -} - -mod imp { - use super::Args; - use crate::ffi::{CStr, OsString}; - use crate::marker::PhantomData; - use crate::ptr; - - use crate::sys_common::mutex::StaticMutex; - - static mut ARGC: isize = 0; - static mut ARGV: *const *const u8 = ptr::null(); - static LOCK: StaticMutex = StaticMutex::new(); - - pub unsafe fn init(argc: isize, argv: *const *const u8) { - let _guard = LOCK.lock(); - ARGC = argc; - ARGV = argv; - } - - pub unsafe fn cleanup() { - let _guard = LOCK.lock(); - ARGC = 0; - ARGV = ptr::null(); - } - - pub fn args() -> Args { - Args { iter: clone().into_iter(), _dont_send_or_sync_me: PhantomData } - } - - fn clone() -> Vec { - unsafe { - let _guard = LOCK.lock(); - let ret = (0..ARGC) - .map(|i| { - let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char); - use crate::sys::vxworks::ext::ffi::OsStringExt; - OsStringExt::from_vec(cstr.to_bytes().to_vec()) - }) - .collect(); - return ret; - } - } -} diff --git a/library/std/src/sys/vxworks/mod.rs b/library/std/src/sys/vxworks/mod.rs index 9853eb3bf3d..f4a811074ca 100644 --- a/library/std/src/sys/vxworks/mod.rs +++ b/library/std/src/sys/vxworks/mod.rs @@ -13,6 +13,7 @@ pub mod weak; #[path = "../unix/alloc.rs"] pub mod alloc; +#[path = "../unix/args.rs"] pub mod args; pub mod cmath; #[path = "../unix/condvar.rs"] From 3f196dc137c378e727c6626e5a38b37e15fbbf70 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 20:38:25 +0200 Subject: [PATCH 203/446] Take sys/vxworks/cmath from sys/unix instead. --- library/std/src/sys/vxworks/cmath.rs | 32 ---------------------------- library/std/src/sys/vxworks/mod.rs | 1 + 2 files changed, 1 insertion(+), 32 deletions(-) delete mode 100644 library/std/src/sys/vxworks/cmath.rs diff --git a/library/std/src/sys/vxworks/cmath.rs b/library/std/src/sys/vxworks/cmath.rs deleted file mode 100644 index f327b69fc75..00000000000 --- a/library/std/src/sys/vxworks/cmath.rs +++ /dev/null @@ -1,32 +0,0 @@ -#![cfg(not(test))] - -use libc::{c_double, c_float}; - -extern "C" { - pub fn acos(n: c_double) -> c_double; - pub fn acosf(n: c_float) -> c_float; - pub fn asin(n: c_double) -> c_double; - pub fn asinf(n: c_float) -> c_float; - pub fn atan(n: c_double) -> c_double; - pub fn atan2(a: c_double, b: c_double) -> c_double; - pub fn atan2f(a: c_float, b: c_float) -> c_float; - pub fn atanf(n: c_float) -> c_float; - pub fn cbrt(n: c_double) -> c_double; - pub fn cbrtf(n: c_float) -> c_float; - pub fn cosh(n: c_double) -> c_double; - pub fn coshf(n: c_float) -> c_float; - pub fn expm1(n: c_double) -> c_double; - pub fn expm1f(n: c_float) -> c_float; - pub fn fdim(a: c_double, b: c_double) -> c_double; - pub fn fdimf(a: c_float, b: c_float) -> c_float; - pub fn hypot(x: c_double, y: c_double) -> c_double; - pub fn hypotf(x: c_float, y: c_float) -> c_float; - pub fn log1p(n: c_double) -> c_double; - pub fn log1pf(n: c_float) -> c_float; - pub fn sinh(n: c_double) -> c_double; - pub fn sinhf(n: c_float) -> c_float; - pub fn tan(n: c_double) -> c_double; - pub fn tanf(n: c_float) -> c_float; - pub fn tanh(n: c_double) -> c_double; - pub fn tanhf(n: c_float) -> c_float; -} diff --git a/library/std/src/sys/vxworks/mod.rs b/library/std/src/sys/vxworks/mod.rs index f4a811074ca..2d25efbd7e3 100644 --- a/library/std/src/sys/vxworks/mod.rs +++ b/library/std/src/sys/vxworks/mod.rs @@ -15,6 +15,7 @@ pub mod weak; pub mod alloc; #[path = "../unix/args.rs"] pub mod args; +#[path = "../unix/cmath.rs"] pub mod cmath; #[path = "../unix/condvar.rs"] pub mod condvar; From 71bb1dc2a09ffc7334f07248669a42faf2a784eb Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 20:38:25 +0200 Subject: [PATCH 204/446] Take sys/vxworks/{fd,fs,io} from sys/unix instead. --- library/std/src/os/vxworks/fs.rs | 15 + library/std/src/os/vxworks/raw.rs | 3 + library/std/src/sys/unix/ext/fs.rs | 7 + library/std/src/sys/unix/fd.rs | 6 +- library/std/src/sys/unix/fs.rs | 56 ++- library/std/src/sys/vxworks/fd.rs | 201 ---------- library/std/src/sys/vxworks/fs.rs | 624 ----------------------------- library/std/src/sys/vxworks/io.rs | 75 ---- library/std/src/sys/vxworks/mod.rs | 3 + 9 files changed, 81 insertions(+), 909 deletions(-) delete mode 100644 library/std/src/sys/vxworks/fd.rs delete mode 100644 library/std/src/sys/vxworks/fs.rs delete mode 100644 library/std/src/sys/vxworks/io.rs diff --git a/library/std/src/os/vxworks/fs.rs b/library/std/src/os/vxworks/fs.rs index 5a7e5bcaa76..77e6238ca1f 100644 --- a/library/std/src/os/vxworks/fs.rs +++ b/library/std/src/os/vxworks/fs.rs @@ -26,10 +26,16 @@ pub trait MetadataExt { #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_atime(&self) -> i64; #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_mtime(&self) -> i64; #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_ctime(&self) -> i64; #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_blksize(&self) -> u64; #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_blocks(&self) -> u64; @@ -66,12 +72,21 @@ impl MetadataExt for Metadata { fn st_atime(&self) -> i64 { self.as_inner().as_inner().st_atime as i64 } + fn st_atime_nsec(&self) -> i64 { + 0 + } fn st_mtime(&self) -> i64 { self.as_inner().as_inner().st_mtime as i64 } + fn st_mtime_nsec(&self) -> i64 { + 0 + } fn st_ctime(&self) -> i64 { self.as_inner().as_inner().st_ctime as i64 } + fn st_ctime_nsec(&self) -> i64 { + 0 + } fn st_blksize(&self) -> u64 { self.as_inner().as_inner().st_blksize as u64 } diff --git a/library/std/src/os/vxworks/raw.rs b/library/std/src/os/vxworks/raw.rs index 29a0af5645e..cb41ddfe2a9 100644 --- a/library/std/src/os/vxworks/raw.rs +++ b/library/std/src/os/vxworks/raw.rs @@ -5,3 +5,6 @@ use crate::os::raw::c_ulong; #[stable(feature = "pthread_t", since = "1.8.0")] pub type pthread_t = c_ulong; + +#[stable(feature = "raw_ext", since = "1.1.0")] +pub use libc::{blkcnt_t, blksize_t, dev_t, ino_t, mode_t, nlink_t, off_t, time_t}; diff --git a/library/std/src/sys/unix/ext/fs.rs b/library/std/src/sys/unix/ext/fs.rs index 4b9f4ceb29c..66bbc1c5854 100644 --- a/library/std/src/sys/unix/ext/fs.rs +++ b/library/std/src/sys/unix/ext/fs.rs @@ -650,6 +650,9 @@ pub trait MetadataExt { /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn blocks(&self) -> u64; + #[cfg(target_os = "vxworks")] + #[stable(feature = "metadata_ext", since = "1.1.0")] + fn attrib(&self) -> u8; } #[stable(feature = "metadata_ext", since = "1.1.0")] @@ -702,6 +705,10 @@ impl MetadataExt for fs::Metadata { fn blocks(&self) -> u64 { self.st_blocks() } + #[cfg(target_os = "vxworks")] + fn attrib(&self) -> u8 { + self.st_attrib() + } } /// Unix-specific extensions for [`fs::FileType`]. diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 2224a055d6d..d3a279a2355 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -200,7 +200,8 @@ impl FileDesc { target_os = "l4re", target_os = "linux", target_os = "haiku", - target_os = "redox" + target_os = "redox", + target_os = "vxworks" )))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { @@ -217,7 +218,8 @@ impl FileDesc { target_os = "l4re", target_os = "linux", target_os = "haiku", - target_os = "redox" + target_os = "redox", + target_os = "vxworks" ))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 8184c25afcf..819e8ef1841 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -297,6 +297,7 @@ impl FileAttr { #[cfg(not(target_os = "netbsd"))] impl FileAttr { + #[cfg(not(target_os = "vxworks"))] pub fn modified(&self) -> io::Result { Ok(SystemTime::from(libc::timespec { tv_sec: self.stat.st_mtime as libc::time_t, @@ -304,6 +305,15 @@ impl FileAttr { })) } + #[cfg(target_os = "vxworks")] + pub fn modified(&self) -> io::Result { + Ok(SystemTime::from(libc::timespec { + tv_sec: self.stat.st_mtime as libc::time_t, + tv_nsec: 0, + })) + } + + #[cfg(not(target_os = "vxworks"))] pub fn accessed(&self) -> io::Result { Ok(SystemTime::from(libc::timespec { tv_sec: self.stat.st_atime as libc::time_t, @@ -311,6 +321,14 @@ impl FileAttr { })) } + #[cfg(target_os = "vxworks")] + pub fn accessed(&self) -> io::Result { + Ok(SystemTime::from(libc::timespec { + tv_sec: self.stat.st_atime as libc::time_t, + tv_nsec: 0, + })) + } + #[cfg(any( target_os = "freebsd", target_os = "openbsd", @@ -535,12 +553,22 @@ impl DirEntry { lstat(&self.path()) } - #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "haiku"))] + #[cfg(any( + target_os = "solaris", + target_os = "illumos", + target_os = "haiku", + target_os = "vxworks" + ))] pub fn file_type(&self) -> io::Result { lstat(&self.path()).map(|m| m.file_type()) } - #[cfg(not(any(target_os = "solaris", target_os = "illumos", target_os = "haiku")))] + #[cfg(not(any( + target_os = "solaris", + target_os = "illumos", + target_os = "haiku", + target_os = "vxworks" + )))] pub fn file_type(&self) -> io::Result { match self.entry.d_type { libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }), @@ -565,7 +593,8 @@ impl DirEntry { target_os = "haiku", target_os = "l4re", target_os = "fuchsia", - target_os = "redox" + target_os = "redox", + target_os = "vxworks" ))] pub fn ino(&self) -> u64 { self.entry.d_ino as u64 @@ -603,7 +632,8 @@ impl DirEntry { target_os = "linux", target_os = "emscripten", target_os = "l4re", - target_os = "haiku" + target_os = "haiku", + target_os = "vxworks" ))] fn name_bytes(&self) -> &[u8] { unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes() } @@ -901,13 +931,25 @@ impl fmt::Debug for File { Some(PathBuf::from(OsString::from_vec(buf))) } - #[cfg(not(any(target_os = "linux", target_os = "macos")))] + #[cfg(target_os = "vxworks")] + fn get_path(fd: c_int) -> Option { + let mut buf = vec![0; libc::PATH_MAX as usize]; + let n = unsafe { libc::ioctl(fd, libc::FIOGETNAME, buf.as_ptr()) }; + if n == -1 { + return None; + } + let l = buf.iter().position(|&c| c == 0).unwrap(); + buf.truncate(l as usize); + Some(PathBuf::from(OsString::from_vec(buf))) + } + + #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "vxworks")))] fn get_path(_fd: c_int) -> Option { // FIXME(#24570): implement this for other Unix platforms None } - #[cfg(any(target_os = "linux", target_os = "macos"))] + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "vxworks"))] fn get_mode(fd: c_int) -> Option<(bool, bool)> { let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) }; if mode == -1 { @@ -921,7 +963,7 @@ impl fmt::Debug for File { } } - #[cfg(not(any(target_os = "linux", target_os = "macos")))] + #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "vxworks")))] fn get_mode(_fd: c_int) -> Option<(bool, bool)> { // FIXME(#24570): implement this for other Unix platforms None diff --git a/library/std/src/sys/vxworks/fd.rs b/library/std/src/sys/vxworks/fd.rs deleted file mode 100644 index d58468ad539..00000000000 --- a/library/std/src/sys/vxworks/fd.rs +++ /dev/null @@ -1,201 +0,0 @@ -#![unstable(reason = "not public", issue = "none", feature = "fd")] - -use crate::cmp; -use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read}; -use crate::mem; -use crate::sys::cvt; -use crate::sys_common::AsInner; - -use libc::{self, c_int, c_void, ssize_t}; - -#[derive(Debug)] -pub struct FileDesc { - fd: c_int, -} - -// The maximum read limit on most POSIX-like systems is `SSIZE_MAX`, -// with the man page quoting that if the count of bytes to read is -// greater than `SSIZE_MAX` the result is "unspecified". -const READ_LIMIT: usize = ssize_t::MAX as usize; - -impl FileDesc { - pub fn new(fd: c_int) -> FileDesc { - FileDesc { fd: fd } - } - - pub fn raw(&self) -> c_int { - self.fd - } - - /// Extracts the actual file descriptor without closing it. - pub fn into_raw(self) -> c_int { - let fd = self.fd; - mem::forget(self); - fd - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result { - let ret = cvt(unsafe { - libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT)) - })?; - Ok(ret as usize) - } - - pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - let ret = cvt(unsafe { - libc::readv( - self.fd, - bufs.as_ptr() as *const libc::iovec, - cmp::min(bufs.len(), c_int::MAX as usize) as c_int, - ) - })?; - Ok(ret as usize) - } - - #[inline] - pub fn is_read_vectored(&self) -> bool { - true - } - - pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { - let mut me = self; - (&mut me).read_to_end(buf) - } - - pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { - unsafe fn cvt_pread( - fd: c_int, - buf: *mut c_void, - count: usize, - offset: i64, - ) -> io::Result { - use libc::pread; - cvt(pread(fd, buf, count, offset)) - } - - unsafe { - cvt_pread( - self.fd, - buf.as_mut_ptr() as *mut c_void, - cmp::min(buf.len(), READ_LIMIT), - offset as i64, - ) - .map(|n| n as usize) - } - } - - pub fn write(&self, buf: &[u8]) -> io::Result { - let ret = cvt(unsafe { - libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT)) - })?; - Ok(ret as usize) - } - - pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { - let ret = cvt(unsafe { - libc::writev( - self.fd, - bufs.as_ptr() as *const libc::iovec, - cmp::min(bufs.len(), c_int::MAX as usize) as c_int, - ) - })?; - Ok(ret as usize) - } - - #[inline] - pub fn is_write_vectored(&self) -> bool { - true - } - - pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { - unsafe fn cvt_pwrite( - fd: c_int, - buf: *const c_void, - count: usize, - offset: i64, - ) -> io::Result { - use libc::pwrite; - cvt(pwrite(fd, buf, count, offset)) - } - - unsafe { - cvt_pwrite( - self.fd, - buf.as_ptr() as *const c_void, - cmp::min(buf.len(), READ_LIMIT), - offset as i64, - ) - .map(|n| n as usize) - } - } - - pub fn get_cloexec(&self) -> io::Result { - unsafe { Ok((cvt(libc::fcntl(self.fd, libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) } - } - - pub fn set_cloexec(&self) -> io::Result<()> { - unsafe { - let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?; - let new = previous | libc::FD_CLOEXEC; - if new != previous { - cvt(libc::fcntl(self.fd, libc::F_SETFD, new))?; - } - Ok(()) - } - } - - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - unsafe { - let v = nonblocking as c_int; - cvt(libc::ioctl(self.fd, libc::FIONBIO, &v))?; - Ok(()) - } - } - - // refer to pxPipeDrv library documentation. - // VxWorks uses fcntl to set O_NONBLOCK to the pipes - pub fn set_nonblocking_pipe(&self, nonblocking: bool) -> io::Result<()> { - unsafe { - let mut flags = cvt(libc::fcntl(self.fd, libc::F_GETFL, 0))?; - flags = if nonblocking { flags | libc::O_NONBLOCK } else { flags & !libc::O_NONBLOCK }; - cvt(libc::fcntl(self.fd, libc::F_SETFL, flags))?; - Ok(()) - } - } - - pub fn duplicate(&self) -> io::Result { - let fd = self.raw(); - match cvt(unsafe { libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, 0) }) { - Ok(newfd) => Ok(FileDesc::new(newfd)), - Err(e) => return Err(e), - } - } -} - -impl<'a> Read for &'a FileDesc { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - (**self).read(buf) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -impl AsInner for FileDesc { - fn as_inner(&self) -> &c_int { - &self.fd - } -} - -impl Drop for FileDesc { - fn drop(&mut self) { - // Note that errors are ignored when closing a file descriptor. The - // reason for this is that if an error occurs we don't actually know if - // the file descriptor was closed or not, and if we retried (for - // something like EINTR), we might close another valid file descriptor - // (opened after we closed ours. - let _ = unsafe { libc::close(self.fd) }; - } -} diff --git a/library/std/src/sys/vxworks/fs.rs b/library/std/src/sys/vxworks/fs.rs deleted file mode 100644 index cb761af1a25..00000000000 --- a/library/std/src/sys/vxworks/fs.rs +++ /dev/null @@ -1,624 +0,0 @@ -// copies from linuxx -use crate::ffi::{CStr, CString, OsStr, OsString}; -use crate::fmt; -use crate::io::{self, Error, ErrorKind, IoSlice, IoSliceMut, SeekFrom}; -use crate::mem; -use crate::path::{Path, PathBuf}; -use crate::ptr; -use crate::sync::Arc; -use crate::sys::fd::FileDesc; -use crate::sys::time::SystemTime; -use crate::sys::vxworks::ext::ffi::OsStrExt; -use crate::sys::vxworks::ext::ffi::OsStringExt; -use crate::sys::{cvt, cvt_r}; -use crate::sys_common::{AsInner, FromInner}; -use libc::{self, c_int, mode_t, off_t, stat64}; -use libc::{dirent, ftruncate, lseek, open, readdir_r as readdir64_r}; -pub struct File(FileDesc); - -#[derive(Clone)] -pub struct FileAttr { - stat: stat64, -} - -// all DirEntry's will have a reference to this struct -struct InnerReadDir { - dirp: Dir, - root: PathBuf, -} - -pub struct ReadDir { - inner: Arc, - end_of_stream: bool, -} - -struct Dir(*mut libc::DIR); - -unsafe impl Send for Dir {} -unsafe impl Sync for Dir {} - -pub struct DirEntry { - entry: dirent, - dir: Arc, -} - -#[derive(Clone, Debug)] -pub struct OpenOptions { - // generic - read: bool, - write: bool, - append: bool, - truncate: bool, - create: bool, - create_new: bool, - // system-specific - custom_flags: i32, - mode: mode_t, -} - -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct FilePermissions { - mode: mode_t, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct FileType { - mode: mode_t, -} - -#[derive(Debug)] -pub struct DirBuilder { - mode: mode_t, -} - -impl FileAttr { - pub fn size(&self) -> u64 { - self.stat.st_size as u64 - } - pub fn perm(&self) -> FilePermissions { - FilePermissions { mode: (self.stat.st_mode as mode_t) } - } - - pub fn file_type(&self) -> FileType { - FileType { mode: self.stat.st_mode as mode_t } - } - - pub fn modified(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_mtime as libc::time_t, - tv_nsec: 0, // hack 2.0; - })) - } - - pub fn accessed(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_atime as libc::time_t, - tv_nsec: 0, // hack - a proper fix would be better - })) - } - - pub fn created(&self) -> io::Result { - Err(io::Error::new( - io::ErrorKind::Other, - "creation time is not available on this platform currently", - )) - } -} - -impl AsInner for FileAttr { - fn as_inner(&self) -> &stat64 { - &self.stat - } -} - -impl FilePermissions { - pub fn readonly(&self) -> bool { - // check if any class (owner, group, others) has write permission - self.mode & 0o222 == 0 - } - - pub fn set_readonly(&mut self, readonly: bool) { - if readonly { - // remove write permission for all classes; equivalent to `chmod a-w ` - self.mode &= !0o222; - } else { - // add write permission for all classes; equivalent to `chmod a+w ` - self.mode |= 0o222; - } - } - pub fn mode(&self) -> u32 { - self.mode as u32 - } -} - -impl FileType { - pub fn is_dir(&self) -> bool { - self.is(libc::S_IFDIR) - } - pub fn is_file(&self) -> bool { - self.is(libc::S_IFREG) - } - pub fn is_symlink(&self) -> bool { - self.is(libc::S_IFLNK) - } - - pub fn is(&self, mode: mode_t) -> bool { - self.mode & libc::S_IFMT == mode - } -} - -impl FromInner for FilePermissions { - fn from_inner(mode: u32) -> FilePermissions { - FilePermissions { mode: mode as mode_t } - } -} - -impl fmt::Debug for ReadDir { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. - // Thus the result will be e g 'ReadDir("/home")' - fmt::Debug::fmt(&*self.inner.root, f) - } -} - -impl Iterator for ReadDir { - type Item = io::Result; - fn next(&mut self) -> Option> { - if self.end_of_stream { - return None; - } - - unsafe { - let mut ret = DirEntry { entry: mem::zeroed(), dir: Arc::clone(&self.inner) }; - let mut entry_ptr = ptr::null_mut(); - loop { - if readdir64_r(self.inner.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 { - if entry_ptr.is_null() { - // We encountered an error (which will be returned in this iteration), but - // we also reached the end of the directory stream. The `end_of_stream` - // flag is enabled to make sure that we return `None` in the next iteration - // (instead of looping forever) - self.end_of_stream = true; - } - return Some(Err(Error::last_os_error())); - } - if entry_ptr.is_null() { - return None; - } - if ret.name_bytes() != b"." && ret.name_bytes() != b".." { - return Some(Ok(ret)); - } - } - } - } -} - -impl Drop for Dir { - fn drop(&mut self) { - let r = unsafe { libc::closedir(self.0) }; - debug_assert_eq!(r, 0); - } -} - -impl DirEntry { - pub fn path(&self) -> PathBuf { - use crate::sys::vxworks::ext::ffi::OsStrExt; - self.dir.root.join(OsStr::from_bytes(self.name_bytes())) - } - - pub fn file_name(&self) -> OsString { - OsStr::from_bytes(self.name_bytes()).to_os_string() - } - - pub fn metadata(&self) -> io::Result { - lstat(&self.path()) - } - - pub fn file_type(&self) -> io::Result { - lstat(&self.path()).map(|m| m.file_type()) - } - - pub fn ino(&self) -> u64 { - self.entry.d_ino as u64 - } - - fn name_bytes(&self) -> &[u8] { - unsafe { - //&*self.name - CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes() - } - } -} - -impl OpenOptions { - pub fn new() -> OpenOptions { - OpenOptions { - // generic - read: false, - write: false, - append: false, - truncate: false, - create: false, - create_new: false, - // system-specific - custom_flags: 0, - mode: 0o666, - } - } - - pub fn read(&mut self, read: bool) { - self.read = read; - } - pub fn write(&mut self, write: bool) { - self.write = write; - } - pub fn append(&mut self, append: bool) { - self.append = append; - } - pub fn truncate(&mut self, truncate: bool) { - self.truncate = truncate; - } - pub fn create(&mut self, create: bool) { - self.create = create; - } - pub fn create_new(&mut self, create_new: bool) { - self.create_new = create_new; - } - pub fn mode(&mut self, mode: u32) { - self.mode = mode as mode_t; - } - - fn get_access_mode(&self) -> io::Result { - match (self.read, self.write, self.append) { - (true, false, false) => Ok(libc::O_RDONLY), - (false, true, false) => Ok(libc::O_WRONLY), - (true, true, false) => Ok(libc::O_RDWR), - (false, _, true) => Ok(libc::O_WRONLY | libc::O_APPEND), - (true, _, true) => Ok(libc::O_RDWR | libc::O_APPEND), - (false, false, false) => Err(Error::from_raw_os_error(libc::EINVAL)), - } - } - - fn get_creation_mode(&self) -> io::Result { - match (self.write, self.append) { - (true, false) => {} - (false, false) => { - if self.truncate || self.create || self.create_new { - return Err(Error::from_raw_os_error(libc::EINVAL)); - } - } - (_, true) => { - if self.truncate && !self.create_new { - return Err(Error::from_raw_os_error(libc::EINVAL)); - } - } - } - - Ok(match (self.create, self.truncate, self.create_new) { - (false, false, false) => 0, - (true, false, false) => libc::O_CREAT, - (false, true, false) => libc::O_TRUNC, - (true, true, false) => libc::O_CREAT | libc::O_TRUNC, - (_, _, true) => libc::O_CREAT | libc::O_EXCL, - }) - } -} - -impl File { - pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { - let path = cstr(path)?; - File::open_c(&path, opts) - } - - pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result { - let flags = libc::O_CLOEXEC - | opts.get_access_mode()? - | opts.get_creation_mode()? - | (opts.custom_flags as c_int & !libc::O_ACCMODE); - let fd = cvt_r(|| unsafe { open(path.as_ptr(), flags, opts.mode as c_int) })?; - Ok(File(FileDesc::new(fd))) - } - - pub fn file_attr(&self) -> io::Result { - let mut stat: stat64 = unsafe { mem::zeroed() }; - cvt(unsafe { ::libc::fstat(self.0.raw(), &mut stat) })?; - Ok(FileAttr { stat: stat }) - } - - pub fn fsync(&self) -> io::Result<()> { - cvt_r(|| unsafe { libc::fsync(self.0.raw()) })?; - Ok(()) - } - - pub fn datasync(&self) -> io::Result<()> { - cvt_r(|| unsafe { os_datasync(self.0.raw()) })?; - return Ok(()); - unsafe fn os_datasync(fd: c_int) -> c_int { - libc::fsync(fd) - } //not supported - } - - pub fn truncate(&self, size: u64) -> io::Result<()> { - return cvt_r(|| unsafe { ftruncate(self.0.raw(), size as off_t) }).map(drop); - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.0.read_vectored(bufs) - } - - #[inline] - pub fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - - pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { - self.0.read_at(buf, offset) - } - - pub fn write(&self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { - self.0.write_vectored(bufs) - } - - #[inline] - pub fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } - - pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { - self.0.write_at(buf, offset) - } - - pub fn flush(&self) -> io::Result<()> { - Ok(()) - } - - pub fn seek(&self, pos: SeekFrom) -> io::Result { - let (whence, pos) = match pos { - // Casting to `i64` is fine, too large values will end up as - // negative which will cause an error in `"lseek64"`. - SeekFrom::Start(off) => (libc::SEEK_SET, off as i64), - SeekFrom::End(off) => (libc::SEEK_END, off), - SeekFrom::Current(off) => (libc::SEEK_CUR, off), - }; - let n = cvt(unsafe { lseek(self.0.raw(), pos, whence) })?; - Ok(n as u64) - } - - pub fn duplicate(&self) -> io::Result { - self.0.duplicate().map(File) - } - - pub fn fd(&self) -> &FileDesc { - &self.0 - } - - pub fn into_fd(self) -> FileDesc { - self.0 - } - - pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> { - cvt_r(|| unsafe { libc::fchmod(self.0.raw(), perm.mode) })?; - Ok(()) - } - - pub fn diverge(&self) -> ! { - panic!() - } -} - -impl DirBuilder { - pub fn new() -> DirBuilder { - DirBuilder { mode: 0o777 } - } - - pub fn mkdir(&self, p: &Path) -> io::Result<()> { - let p = cstr(p)?; - cvt(unsafe { libc::mkdir(p.as_ptr(), self.mode) })?; - Ok(()) - } - - pub fn set_mode(&mut self, mode: u32) { - self.mode = mode as mode_t; - } -} - -fn cstr(path: &Path) -> io::Result { - use crate::sys::vxworks::ext::ffi::OsStrExt; - Ok(CString::new(path.as_os_str().as_bytes())?) -} - -impl FromInner for File { - fn from_inner(fd: c_int) -> File { - File(FileDesc::new(fd)) - } -} - -impl fmt::Debug for File { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fn get_path(fd: c_int) -> Option { - let mut buf = vec![0; libc::PATH_MAX as usize]; - let n = unsafe { libc::ioctl(fd, libc::FIOGETNAME, buf.as_ptr()) }; - if n == -1 { - return None; - } - let l = buf.iter().position(|&c| c == 0).unwrap(); - buf.truncate(l as usize); - Some(PathBuf::from(OsString::from_vec(buf))) - } - fn get_mode(fd: c_int) -> Option<(bool, bool)> { - let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) }; - if mode == -1 { - return None; - } - match mode & libc::O_ACCMODE { - libc::O_RDONLY => Some((true, false)), - libc::O_RDWR => Some((true, true)), - libc::O_WRONLY => Some((false, true)), - _ => None, - } - } - - let fd = self.0.raw(); - let mut b = f.debug_struct("File"); - b.field("fd", &fd); - if let Some(path) = get_path(fd) { - b.field("path", &path); - } - if let Some((read, write)) = get_mode(fd) { - b.field("read", &read).field("write", &write); - } - b.finish() - } -} - -pub fn readdir(p: &Path) -> io::Result { - let root = p.to_path_buf(); - let p = cstr(p)?; - unsafe { - let ptr = libc::opendir(p.as_ptr()); - if ptr.is_null() { - Err(Error::last_os_error()) - } else { - let inner = InnerReadDir { dirp: Dir(ptr), root }; - Ok(ReadDir { inner: Arc::new(inner), end_of_stream: false }) - } - } -} - -pub fn unlink(p: &Path) -> io::Result<()> { - let p = cstr(p)?; - cvt(unsafe { libc::unlink(p.as_ptr()) })?; - Ok(()) -} - -pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - let old = cstr(old)?; - let new = cstr(new)?; - cvt(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) })?; - Ok(()) -} - -pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { - let p = cstr(p)?; - cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) })?; - Ok(()) -} - -pub fn rmdir(p: &Path) -> io::Result<()> { - let p = cstr(p)?; - cvt(unsafe { libc::rmdir(p.as_ptr()) })?; - Ok(()) -} - -pub fn remove_dir_all(path: &Path) -> io::Result<()> { - let filetype = lstat(path)?.file_type(); - if filetype.is_symlink() { unlink(path) } else { remove_dir_all_recursive(path) } -} - -fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { - for child in readdir(path)? { - let child = child?; - if child.file_type()?.is_dir() { - remove_dir_all_recursive(&child.path())?; - } else { - unlink(&child.path())?; - } - } - rmdir(path) -} - -pub fn readlink(p: &Path) -> io::Result { - let c_path = cstr(p)?; - let p = c_path.as_ptr(); - - let mut buf = Vec::with_capacity(256); - - loop { - let buf_read = - cvt(unsafe { libc::readlink(p, buf.as_mut_ptr() as *mut _, buf.capacity()) })? as usize; - - unsafe { - buf.set_len(buf_read); - } - - if buf_read != buf.capacity() { - buf.shrink_to_fit(); - - return Ok(PathBuf::from(OsString::from_vec(buf))); - } - - // Trigger the internal buffer resizing logic of `Vec` by requiring - // more space than the current capacity. The length is guaranteed to be - // the same as the capacity due to the if statement above. - buf.reserve(1); - } -} - -pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { - let src = cstr(src)?; - let dst = cstr(dst)?; - cvt(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) })?; - Ok(()) -} - -pub fn link(src: &Path, dst: &Path) -> io::Result<()> { - let src = cstr(src)?; - let dst = cstr(dst)?; - cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })?; - Ok(()) -} - -pub fn stat(p: &Path) -> io::Result { - let p = cstr(p)?; - let mut stat: stat64 = unsafe { mem::zeroed() }; - cvt(unsafe { libc::stat(p.as_ptr(), &mut stat as *mut _ as *mut _) })?; - Ok(FileAttr { stat }) -} - -pub fn lstat(p: &Path) -> io::Result { - let p = cstr(p)?; - let mut stat: stat64 = unsafe { mem::zeroed() }; - cvt(unsafe { ::libc::lstat(p.as_ptr(), &mut stat as *mut _ as *mut _) })?; - Ok(FileAttr { stat }) -} - -pub fn canonicalize(p: &Path) -> io::Result { - use crate::sys::vxworks::ext::ffi::OsStrExt; - let path = CString::new(p.as_os_str().as_bytes())?; - let buf; - unsafe { - let r = libc::realpath(path.as_ptr(), ptr::null_mut()); - if r.is_null() { - return Err(io::Error::last_os_error()); - } - buf = CStr::from_ptr(r).to_bytes().to_vec(); - libc::free(r as *mut _); - } - Ok(PathBuf::from(OsString::from_vec(buf))) -} - -pub fn copy(from: &Path, to: &Path) -> io::Result { - use crate::fs::File; - if !from.is_file() { - return Err(Error::new( - ErrorKind::InvalidInput, - "the source path is not an existing regular file", - )); - } - - let mut reader = File::open(from)?; - let mut writer = File::create(to)?; - let perm = reader.metadata()?.permissions(); - - let ret = io::copy(&mut reader, &mut writer)?; - writer.set_permissions(perm)?; - Ok(ret) -} diff --git a/library/std/src/sys/vxworks/io.rs b/library/std/src/sys/vxworks/io.rs deleted file mode 100644 index 0f68ebf8da9..00000000000 --- a/library/std/src/sys/vxworks/io.rs +++ /dev/null @@ -1,75 +0,0 @@ -use crate::marker::PhantomData; -use crate::slice; - -use libc::{c_void, iovec}; - -#[derive(Copy, Clone)] -#[repr(transparent)] -pub struct IoSlice<'a> { - vec: iovec, - _p: PhantomData<&'a [u8]>, -} - -impl<'a> IoSlice<'a> { - #[inline] - pub fn new(buf: &'a [u8]) -> IoSlice<'a> { - IoSlice { - vec: iovec { iov_base: buf.as_ptr() as *mut u8 as *mut c_void, iov_len: buf.len() }, - _p: PhantomData, - } - } - - #[inline] - pub fn advance(&mut self, n: usize) { - if self.vec.iov_len < n { - panic!("advancing IoSlice beyond its length"); - } - - unsafe { - self.vec.iov_len -= n; - self.vec.iov_base = self.vec.iov_base.add(n); - } - } - - #[inline] - pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } - } -} - -pub struct IoSliceMut<'a> { - vec: iovec, - _p: PhantomData<&'a mut [u8]>, -} - -impl<'a> IoSliceMut<'a> { - #[inline] - pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { - IoSliceMut { - vec: iovec { iov_base: buf.as_mut_ptr() as *mut c_void, iov_len: buf.len() }, - _p: PhantomData, - } - } - - #[inline] - pub fn advance(&mut self, n: usize) { - if self.vec.iov_len < n { - panic!("advancing IoSliceMut beyond its length"); - } - - unsafe { - self.vec.iov_len -= n; - self.vec.iov_base = self.vec.iov_base.add(n); - } - } - - #[inline] - pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } - } - - #[inline] - pub fn as_mut_slice(&mut self) -> &mut [u8] { - unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) } - } -} diff --git a/library/std/src/sys/vxworks/mod.rs b/library/std/src/sys/vxworks/mod.rs index 2d25efbd7e3..fb90f4b0c1a 100644 --- a/library/std/src/sys/vxworks/mod.rs +++ b/library/std/src/sys/vxworks/mod.rs @@ -22,8 +22,11 @@ pub mod condvar; pub mod env; #[path = "../unix/ext/mod.rs"] pub mod ext; +#[path = "../unix/fd.rs"] pub mod fd; +#[path = "../unix/fs.rs"] pub mod fs; +#[path = "../unix/io.rs"] pub mod io; #[path = "../unix/memchr.rs"] pub mod memchr; From 408db0da85943bde9b83d128f997bf4ad4df5d42 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 20:38:25 +0200 Subject: [PATCH 205/446] Take sys/vxworks/{os,path,pipe} from sys/unix instead. --- library/std/src/sys/unix/os.rs | 35 +++- library/std/src/sys/vxworks/mod.rs | 3 + library/std/src/sys/vxworks/os.rs | 315 ---------------------------- library/std/src/sys/vxworks/path.rs | 19 -- library/std/src/sys/vxworks/pipe.rs | 107 ---------- 5 files changed, 33 insertions(+), 446 deletions(-) delete mode 100644 library/std/src/sys/vxworks/os.rs delete mode 100644 library/std/src/sys/vxworks/path.rs delete mode 100644 library/std/src/sys/vxworks/pipe.rs diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index 2392238d0a1..d5e14bec765 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -37,7 +37,7 @@ cfg_if::cfg_if! { } extern "C" { - #[cfg(not(target_os = "dragonfly"))] + #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))] #[cfg_attr( any( target_os = "linux", @@ -67,18 +67,28 @@ extern "C" { } /// Returns the platform-specific value of errno -#[cfg(not(target_os = "dragonfly"))] +#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))] pub fn errno() -> i32 { unsafe { (*errno_location()) as i32 } } /// Sets the platform-specific value of errno -#[cfg(all(not(target_os = "linux"), not(target_os = "dragonfly")))] // needed for readdir and syscall! +#[cfg(all(not(target_os = "linux"), not(target_os = "dragonfly"), not(target_os = "vxworks")))] // needed for readdir and syscall! #[allow(dead_code)] // but not all target cfgs actually end up using it pub fn set_errno(e: i32) { unsafe { *errno_location() = e as c_int } } +#[cfg(target_os = "vxworks")] +pub fn errno() -> i32 { + unsafe { libc::errnoGet() } +} + +#[cfg(target_os = "vxworks")] +pub fn set_errno(e: i32) { + unsafe { libc::errnoSet(e as c_int) }; +} + #[cfg(target_os = "dragonfly")] pub fn errno() -> i32 { extern "C" { @@ -439,6 +449,19 @@ pub fn current_exe() -> io::Result { Err(io::Error::new(ErrorKind::Other, "Not yet implemented!")) } +#[cfg(target_os = "vxworks")] +pub fn current_exe() -> io::Result { + #[cfg(test)] + use realstd::env; + + #[cfg(not(test))] + use crate::env; + + let exe_path = env::args().next().unwrap(); + let path = path::Path::new(&exe_path); + path.canonicalize() +} + pub struct Env { iter: vec::IntoIter<(OsString, OsString)>, _dont_send_or_sync_me: PhantomData<*mut ()>, @@ -568,7 +591,8 @@ pub fn home_dir() -> Option { target_os = "android", target_os = "ios", target_os = "emscripten", - target_os = "redox" + target_os = "redox", + target_os = "vxworks" ))] unsafe fn fallback() -> Option { None @@ -577,7 +601,8 @@ pub fn home_dir() -> Option { target_os = "android", target_os = "ios", target_os = "emscripten", - target_os = "redox" + target_os = "redox", + target_os = "vxworks" )))] unsafe fn fallback() -> Option { let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) { diff --git a/library/std/src/sys/vxworks/mod.rs b/library/std/src/sys/vxworks/mod.rs index fb90f4b0c1a..c20edaa1a47 100644 --- a/library/std/src/sys/vxworks/mod.rs +++ b/library/std/src/sys/vxworks/mod.rs @@ -34,8 +34,11 @@ pub mod memchr; pub mod mutex; #[path = "../unix/net.rs"] pub mod net; +#[path = "../unix/os.rs"] pub mod os; +#[path = "../unix/path.rs"] pub mod path; +#[path = "../unix/pipe.rs"] pub mod pipe; pub mod process; pub mod rand; diff --git a/library/std/src/sys/vxworks/os.rs b/library/std/src/sys/vxworks/os.rs deleted file mode 100644 index 6eaec6f1e50..00000000000 --- a/library/std/src/sys/vxworks/os.rs +++ /dev/null @@ -1,315 +0,0 @@ -use crate::error::Error as StdError; -use crate::ffi::{CStr, CString, OsStr, OsString}; -use crate::fmt; -use crate::io; -use crate::iter; -use crate::marker::PhantomData; -use crate::mem; -use crate::memchr; -use crate::path::{self, Path, PathBuf}; -use crate::slice; -use crate::str; -use crate::sys::cvt; -use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard}; -use libc::{self, c_char /*,c_void */, c_int}; -/*use sys::fd; this one is probably important */ -use crate::vec; - -const TMPBUF_SZ: usize = 128; - -// This is a terrible fix -use crate::sys::os_str::Buf; -use crate::sys_common::{AsInner, FromInner, IntoInner}; - -pub trait OsStringExt { - fn from_vec(vec: Vec) -> Self; - fn into_vec(self) -> Vec; -} - -impl OsStringExt for OsString { - fn from_vec(vec: Vec) -> OsString { - FromInner::from_inner(Buf { inner: vec }) - } - fn into_vec(self) -> Vec { - self.into_inner().inner - } -} - -pub trait OsStrExt { - fn from_bytes(slice: &[u8]) -> &Self; - fn as_bytes(&self) -> &[u8]; -} - -impl OsStrExt for OsStr { - fn from_bytes(slice: &[u8]) -> &OsStr { - unsafe { mem::transmute(slice) } - } - fn as_bytes(&self) -> &[u8] { - &self.as_inner().inner - } -} - -pub fn errno() -> i32 { - unsafe { libc::errnoGet() } -} - -pub fn set_errno(e: i32) { - unsafe { - libc::errnoSet(e as c_int); - } -} - -/// Gets a detailed string description for the given error number. -pub fn error_string(errno: i32) -> String { - let mut buf = [0 as c_char; TMPBUF_SZ]; - extern "C" { - fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t) -> c_int; - } - - let p = buf.as_mut_ptr(); - unsafe { - if strerror_r(errno as c_int, p, buf.len()) < 0 { - panic!("strerror_r failure"); - } - let p = p as *const _; - str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned() - } -} - -pub fn getcwd() -> io::Result { - let mut buf = Vec::with_capacity(512); - loop { - unsafe { - let ptr = buf.as_mut_ptr() as *mut libc::c_char; - if !libc::getcwd(ptr, buf.capacity() as libc::size_t).is_null() { - let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len(); - buf.set_len(len); - buf.shrink_to_fit(); - return Ok(PathBuf::from(OsString::from_vec(buf))); - } else { - let error = io::Error::last_os_error(); - if error.raw_os_error() != Some(libc::ERANGE) { - return Err(error); - } - } - // Trigger the internal buffer resizing logic of `Vec` by requiring - // more space than the current capacity. - let cap = buf.capacity(); - buf.set_len(cap); - buf.reserve(1); - } - } -} - -pub fn chdir(p: &path::Path) -> io::Result<()> { - let p: &OsStr = p.as_ref(); - let p = CString::new(p.as_bytes())?; - unsafe { - match libc::chdir(p.as_ptr()) == (0 as c_int) { - true => Ok(()), - false => Err(io::Error::last_os_error()), - } - } -} - -pub struct SplitPaths<'a> { - iter: iter::Map bool>, fn(&'a [u8]) -> PathBuf>, -} - -pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> { - fn bytes_to_path(b: &[u8]) -> PathBuf { - PathBuf::from(::from_bytes(b)) - } - fn is_colon(b: &u8) -> bool { - *b == b':' - } - let unparsed = unparsed.as_bytes(); - SplitPaths { - iter: unparsed - .split(is_colon as fn(&u8) -> bool) - .map(bytes_to_path as fn(&[u8]) -> PathBuf), - } -} - -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -#[derive(Debug)] -pub struct JoinPathsError; - -pub fn join_paths(paths: I) -> Result -where - I: Iterator, - T: AsRef, -{ - let mut joined = Vec::new(); - let sep = b':'; - - for (i, path) in paths.enumerate() { - let path = path.as_ref().as_bytes(); - if i > 0 { - joined.push(sep) - } - if path.contains(&sep) { - return Err(JoinPathsError); - } - joined.extend_from_slice(path); - } - Ok(OsStringExt::from_vec(joined)) -} - -impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - "path segment contains separator `:`".fmt(f) - } -} - -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "failed to join paths" - } -} - -pub fn current_exe() -> io::Result { - #[cfg(test)] - use realstd::env; - - #[cfg(not(test))] - use crate::env; - - let exe_path = env::args().next().unwrap(); - let path = Path::new(&exe_path); - path.canonicalize() -} - -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, - _dont_send_or_sync_me: PhantomData<*mut ()>, -} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -pub unsafe fn environ() -> *mut *const *const c_char { - extern "C" { - static mut environ: *const *const c_char; - } - &mut environ -} - -pub unsafe fn env_lock() -> StaticMutexGuard { - // It is UB to attempt to acquire this mutex reentrantly! - static ENV_LOCK: StaticMutex = StaticMutex::new(); - ENV_LOCK.lock() -} - -/// Returns a vector of (variable, value) byte-vector pairs for all the -/// environment variables of the current process. -pub fn env() -> Env { - unsafe { - let _guard = env_lock(); - let mut environ = *environ(); - if environ.is_null() { - panic!("os::env() failure getting env string from OS: {}", io::Error::last_os_error()); - } - let mut result = Vec::new(); - while !(*environ).is_null() { - if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { - result.push(key_value); - } - environ = environ.add(1); - } - return Env { iter: result.into_iter(), _dont_send_or_sync_me: PhantomData }; - } - - fn parse(input: &[u8]) -> Option<(OsString, OsString)> { - // Strategy (copied from glibc): Variable name and value are separated - // by an ASCII equals sign '='. Since a variable name must not be - // empty, allow variable names starting with an equals sign. Skip all - // malformed lines. - if input.is_empty() { - return None; - } - let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); - pos.map(|p| { - ( - OsStringExt::from_vec(input[..p].to_vec()), - OsStringExt::from_vec(input[p + 1..].to_vec()), - ) - }) - } -} - -pub fn getenv(k: &OsStr) -> io::Result> { - // environment variables with a nul byte can't be set, so their value is - // always None as well - let k = CString::new(k.as_bytes())?; - unsafe { - let _guard = env_lock(); - let s = libc::getenv(k.as_ptr()) as *const libc::c_char; - let ret = if s.is_null() { - None - } else { - Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec())) - }; - Ok(ret) - } -} - -pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - let k = CString::new(k.as_bytes())?; - let v = CString::new(v.as_bytes())?; - - unsafe { - let _guard = env_lock(); - cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop) - } -} - -pub fn unsetenv(n: &OsStr) -> io::Result<()> { - let nbuf = CString::new(n.as_bytes())?; - - unsafe { - let _guard = env_lock(); - cvt(libc::unsetenv(nbuf.as_ptr())).map(drop) - } -} - -pub fn page_size() -> usize { - unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize } -} - -pub fn temp_dir() -> PathBuf { - crate::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| PathBuf::from("/tmp")) -} - -pub fn home_dir() -> Option { - crate::env::var_os("HOME").or_else(|| None).map(PathBuf::from) -} - -pub fn exit(code: i32) -> ! { - unsafe { libc::exit(code as c_int) } -} - -pub fn getpid() -> u32 { - unsafe { libc::getpid() as u32 } -} - -pub fn getppid() -> u32 { - unsafe { libc::getppid() as u32 } -} diff --git a/library/std/src/sys/vxworks/path.rs b/library/std/src/sys/vxworks/path.rs deleted file mode 100644 index 840a7ae0426..00000000000 --- a/library/std/src/sys/vxworks/path.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::ffi::OsStr; -use crate::path::Prefix; - -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' -} - -#[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'/' -} - -pub fn parse_prefix(_: &OsStr) -> Option> { - None -} - -pub const MAIN_SEP_STR: &str = "/"; -pub const MAIN_SEP: char = '/'; diff --git a/library/std/src/sys/vxworks/pipe.rs b/library/std/src/sys/vxworks/pipe.rs deleted file mode 100644 index a18376212af..00000000000 --- a/library/std/src/sys/vxworks/pipe.rs +++ /dev/null @@ -1,107 +0,0 @@ -use crate::io::{self, IoSlice, IoSliceMut}; -use crate::mem; -use crate::sync::atomic::AtomicBool; -use crate::sys::fd::FileDesc; -use crate::sys::{cvt, cvt_r}; -use libc::{self /*, c_int apparently not used? */}; - -pub struct AnonPipe(FileDesc); - -pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { - static INVALID: AtomicBool = AtomicBool::new(false); - - let mut fds = [0; 2]; - cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?; - - let fd0 = FileDesc::new(fds[0]); - let fd1 = FileDesc::new(fds[1]); - fd0.set_cloexec()?; - fd1.set_cloexec()?; - Ok((AnonPipe(fd0), AnonPipe(fd1))) -} - -impl AnonPipe { - pub fn read(&self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.0.read_vectored(bufs) - } - - #[inline] - pub fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - - pub fn write(&self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { - self.0.write_vectored(bufs) - } - - #[inline] - pub fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } - - pub fn fd(&self) -> &FileDesc { - &self.0 - } - pub fn into_fd(self) -> FileDesc { - self.0 - } - pub fn diverge(&self) -> ! { - panic!() - } -} - -pub fn read2(p1: AnonPipe, v1: &mut Vec, p2: AnonPipe, v2: &mut Vec) -> io::Result<()> { - // Set both pipes into nonblocking mode as we're gonna be reading from both - // in the `select` loop below, and we wouldn't want one to block the other! - let p1 = p1.into_fd(); - let p2 = p2.into_fd(); - p1.set_nonblocking_pipe(true)?; - p2.set_nonblocking_pipe(true)?; - - let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() }; - fds[0].fd = p1.raw(); - fds[0].events = libc::POLLIN; - fds[1].fd = p2.raw(); - fds[1].events = libc::POLLIN; - loop { - // wait for either pipe to become readable using `poll` - cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?; - - if fds[0].revents != 0 && read(&p1, v1)? { - p2.set_nonblocking_pipe(false)?; - return p2.read_to_end(v2).map(drop); - } - if fds[1].revents != 0 && read(&p2, v2)? { - p1.set_nonblocking_pipe(false)?; - return p1.read_to_end(v1).map(drop); - } - } - - // Read as much as we can from each pipe, ignoring EWOULDBLOCK or - // EAGAIN. If we hit EOF, then this will happen because the underlying - // reader will return Ok(0), in which case we'll see `Ok` ourselves. In - // this case we flip the other fd back into blocking mode and read - // whatever's leftover on that file descriptor. - fn read(fd: &FileDesc, dst: &mut Vec) -> Result { - match fd.read_to_end(dst) { - Ok(_) => Ok(true), - Err(e) => { - if e.raw_os_error() == Some(libc::EWOULDBLOCK) - || e.raw_os_error() == Some(libc::EAGAIN) - { - Ok(false) - } else { - Err(e) - } - } - } - } -} From 0f0257be101281d65462bd5bfe92325f636e1950 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 20:38:25 +0200 Subject: [PATCH 206/446] Take some of sys/vxworks/process/* from sys/unix instead. --- library/std/src/sys/unix/ext/process.rs | 24 +- .../src/sys/unix/process/process_common.rs | 4 +- .../std/src/sys/unix/process/process_unix.rs | 4 + library/std/src/sys/vxworks/process/mod.rs | 6 +- .../src/sys/vxworks/process/process_common.rs | 399 ------------------ .../sys/vxworks/process/process_vxworks.rs | 47 ++- 6 files changed, 77 insertions(+), 407 deletions(-) delete mode 100644 library/std/src/sys/vxworks/process/process_common.rs diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs index 82527c40e91..3615a8a5ee8 100644 --- a/library/std/src/sys/unix/ext/process.rs +++ b/library/std/src/sys/unix/ext/process.rs @@ -16,12 +16,20 @@ pub trait CommandExt { /// `setuid` call in the child process. Failure in the `setuid` /// call will cause the spawn to fail. #[stable(feature = "rust1", since = "1.0.0")] - fn uid(&mut self, id: u32) -> &mut process::Command; + fn uid( + &mut self, + #[cfg(not(target_os = "vxworks"))] id: u32, + #[cfg(target_os = "vxworks")] id: u16, + ) -> &mut process::Command; /// Similar to `uid`, but sets the group ID of the child process. This has /// the same semantics as the `uid` field. #[stable(feature = "rust1", since = "1.0.0")] - fn gid(&mut self, id: u32) -> &mut process::Command; + fn gid( + &mut self, + #[cfg(not(target_os = "vxworks"))] id: u32, + #[cfg(target_os = "vxworks")] id: u16, + ) -> &mut process::Command; /// Schedules a closure to be run just before the `exec` function is /// invoked. @@ -115,12 +123,20 @@ pub trait CommandExt { #[stable(feature = "rust1", since = "1.0.0")] impl CommandExt for process::Command { - fn uid(&mut self, id: u32) -> &mut process::Command { + fn uid( + &mut self, + #[cfg(not(target_os = "vxworks"))] id: u32, + #[cfg(target_os = "vxworks")] id: u16, + ) -> &mut process::Command { self.as_inner_mut().uid(id); self } - fn gid(&mut self, id: u32) -> &mut process::Command { + fn gid( + &mut self, + #[cfg(not(target_os = "vxworks"))] id: u32, + #[cfg(target_os = "vxworks")] id: u16, + ) -> &mut process::Command { self.as_inner_mut().gid(id); self } diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index 9ddd4ad4000..4b29b7020eb 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -24,6 +24,8 @@ cfg_if::cfg_if! { // fuchsia doesn't have /dev/null } else if #[cfg(target_os = "redox")] { const DEV_NULL: &str = "null:\0"; + } else if #[cfg(target_os = "vxworks")] { + const DEV_NULL: &str = "/null\0"; } else { const DEV_NULL: &str = "/dev/null\0"; } @@ -48,7 +50,7 @@ cfg_if::cfg_if! { raw[bit / 8] |= 1 << (bit % 8); return 0; } - } else { + } else if #[cfg(not(target_os = "vxworks"))] { pub use libc::{sigemptyset, sigaddset}; } } diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 5e55f97705d..b5be92e3eae 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -6,6 +6,10 @@ use crate::sys; use crate::sys::cvt; use crate::sys::process::process_common::*; +#[cfg(target_os = "vxworks")] +use libc::RTP_ID as pid_t; + +#[cfg(not(target_os = "vxworks"))] use libc::{c_int, gid_t, pid_t, uid_t}; //////////////////////////////////////////////////////////////////////////////// diff --git a/library/std/src/sys/vxworks/process/mod.rs b/library/std/src/sys/vxworks/process/mod.rs index c59782ff44b..dc6130eaa24 100644 --- a/library/std/src/sys/vxworks/process/mod.rs +++ b/library/std/src/sys/vxworks/process/mod.rs @@ -1,7 +1,9 @@ -pub use self::process_common::{Command, ExitCode, ExitStatus, Stdio, StdioPipes}; -pub use self::process_inner::Process; +pub use self::process_common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes}; +pub use self::process_inner::{ExitStatus, Process}; pub use crate::ffi::OsString as EnvKey; +pub use crate::sys_common::process::CommandEnvs; +#[path = "../../unix/process/process_common.rs"] mod process_common; #[path = "process_vxworks.rs"] mod process_inner; diff --git a/library/std/src/sys/vxworks/process/process_common.rs b/library/std/src/sys/vxworks/process/process_common.rs deleted file mode 100644 index 6473a0c3cec..00000000000 --- a/library/std/src/sys/vxworks/process/process_common.rs +++ /dev/null @@ -1,399 +0,0 @@ -use crate::os::unix::prelude::*; - -use crate::collections::BTreeMap; -use crate::ffi::{CStr, CString, OsStr, OsString}; -use crate::fmt; -use crate::io; -use crate::ptr; -use crate::sys::fd::FileDesc; -use crate::sys::fs::{File, OpenOptions}; -use crate::sys::pipe::{self, AnonPipe}; -use crate::sys_common::process::CommandEnv; - -use libc::{c_char, c_int, gid_t, uid_t, EXIT_FAILURE, EXIT_SUCCESS}; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -pub struct Command { - // Currently we try hard to ensure that the call to `.exec()` doesn't - // actually allocate any memory. While many platforms try to ensure that - // memory allocation works after a fork in a multithreaded process, it's - // been observed to be buggy and somewhat unreliable, so we do our best to - // just not do it at all! - // - // Along those lines, the `argv` and `envp` raw pointers here are exactly - // what's gonna get passed to `execvp`. The `argv` array starts with the - // `program` and ends with a NULL, and the `envp` pointer, if present, is - // also null-terminated. - // - // Right now we don't support removing arguments, so there's no much fancy - // support there, but we support adding and removing environment variables, - // so a side table is used to track where in the `envp` array each key is - // located. Whenever we add a key we update it in place if it's already - // present, and whenever we remove a key we update the locations of all - // other keys. - program: CString, - args: Vec, - argv: Argv, - env: CommandEnv, - - cwd: Option, - uid: Option, - gid: Option, - saw_nul: bool, - closures: Vec io::Result<()> + Send + Sync>>, - stdin: Option, - stdout: Option, - stderr: Option, -} - -// Create a new type for `Argv`, so that we can make it `Send` and `Sync` -struct Argv(Vec<*const c_char>); - -// It is safe to make `Argv` `Send` and `Sync`, because it contains -// pointers to memory owned by `Command.args` -unsafe impl Send for Argv {} -unsafe impl Sync for Argv {} - -// passed back to std::process with the pipes connected to the child, if any -// were requested -pub struct StdioPipes { - pub stdin: Option, - pub stdout: Option, - pub stderr: Option, -} - -// passed to do_exec() with configuration of what the child stdio should look -// like -pub struct ChildPipes { - pub stdin: ChildStdio, - pub stdout: ChildStdio, - pub stderr: ChildStdio, -} - -pub enum ChildStdio { - Inherit, - Explicit(c_int), - Owned(FileDesc), -} - -pub enum Stdio { - Inherit, - Null, - MakePipe, - Fd(FileDesc), -} - -impl Command { - pub fn new(program: &OsStr) -> Command { - let mut saw_nul = false; - let program = os2c(program, &mut saw_nul); - Command { - argv: Argv(vec![program.as_ptr(), ptr::null()]), - args: vec![program.clone()], - program, - env: Default::default(), - cwd: None, - uid: None, - gid: None, - saw_nul, - closures: Vec::new(), - stdin: None, - stdout: None, - stderr: None, - } - } - - pub fn set_arg_0(&mut self, arg: &OsStr) { - // Set a new arg0 - let arg = os2c(arg, &mut self.saw_nul); - debug_assert!(self.argv.0.len() > 1); - self.argv.0[0] = arg.as_ptr(); - self.args[0] = arg; - } - - pub fn arg(&mut self, arg: &OsStr) { - // Overwrite the trailing NULL pointer in `argv` and then add a new null - // pointer. - let arg = os2c(arg, &mut self.saw_nul); - self.argv.0[self.args.len()] = arg.as_ptr(); - self.argv.0.push(ptr::null()); - - // Also make sure we keep track of the owned value to schedule a - // destructor for this memory. - self.args.push(arg); - } - - pub fn cwd(&mut self, dir: &OsStr) { - self.cwd = Some(os2c(dir, &mut self.saw_nul)); - } - pub fn uid(&mut self, id: uid_t) { - self.uid = Some(id); - } - pub fn gid(&mut self, id: gid_t) { - self.gid = Some(id); - } - - pub fn saw_nul(&self) -> bool { - self.saw_nul - } - pub fn get_argv(&self) -> &Vec<*const c_char> { - &self.argv.0 - } - - pub fn get_program(&self) -> &CStr { - &*self.program - } - - #[allow(dead_code)] - pub fn get_cwd(&self) -> &Option { - &self.cwd - } - #[allow(dead_code)] - pub fn get_uid(&self) -> Option { - self.uid - } - #[allow(dead_code)] - pub fn get_gid(&self) -> Option { - self.gid - } - - pub fn get_closures(&mut self) -> &mut Vec io::Result<()> + Send + Sync>> { - &mut self.closures - } - - pub unsafe fn pre_exec(&mut self, _f: Box io::Result<()> + Send + Sync>) { - // Fork() is not supported in vxWorks so no way to run the closure in the new procecss. - unimplemented!(); - } - - pub fn stdin(&mut self, stdin: Stdio) { - self.stdin = Some(stdin); - } - - pub fn stdout(&mut self, stdout: Stdio) { - self.stdout = Some(stdout); - } - - pub fn stderr(&mut self, stderr: Stdio) { - self.stderr = Some(stderr); - } - - pub fn env_mut(&mut self) -> &mut CommandEnv { - &mut self.env - } - - pub fn capture_env(&mut self) -> Option { - let maybe_env = self.env.capture_if_changed(); - maybe_env.map(|env| construct_envp(env, &mut self.saw_nul)) - } - #[allow(dead_code)] - pub fn env_saw_path(&self) -> bool { - self.env.have_changed_path() - } - - pub fn setup_io( - &self, - default: Stdio, - needs_stdin: bool, - ) -> io::Result<(StdioPipes, ChildPipes)> { - let null = Stdio::Null; - let default_stdin = if needs_stdin { &default } else { &null }; - let stdin = self.stdin.as_ref().unwrap_or(default_stdin); - let stdout = self.stdout.as_ref().unwrap_or(&default); - let stderr = self.stderr.as_ref().unwrap_or(&default); - let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?; - let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?; - let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?; - let ours = StdioPipes { stdin: our_stdin, stdout: our_stdout, stderr: our_stderr }; - let theirs = ChildPipes { stdin: their_stdin, stdout: their_stdout, stderr: their_stderr }; - Ok((ours, theirs)) - } -} - -fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString { - CString::new(s.as_bytes()).unwrap_or_else(|_e| { - *saw_nul = true; - CString::new("").unwrap() - }) -} - -// Helper type to manage ownership of the strings within a C-style array. -pub struct CStringArray { - items: Vec, - ptrs: Vec<*const c_char>, -} - -impl CStringArray { - pub fn with_capacity(capacity: usize) -> Self { - let mut result = CStringArray { - items: Vec::with_capacity(capacity), - ptrs: Vec::with_capacity(capacity + 1), - }; - result.ptrs.push(ptr::null()); - result - } - pub fn push(&mut self, item: CString) { - let l = self.ptrs.len(); - self.ptrs[l - 1] = item.as_ptr(); - self.ptrs.push(ptr::null()); - self.items.push(item); - } - pub fn as_ptr(&self) -> *const *const c_char { - self.ptrs.as_ptr() - } -} - -fn construct_envp(env: BTreeMap, saw_nul: &mut bool) -> CStringArray { - let mut result = CStringArray::with_capacity(env.len()); - for (k, v) in env { - let mut k: OsString = k.into(); - - // Reserve additional space for '=' and null terminator - k.reserve_exact(v.len() + 2); - k.push("="); - k.push(&v); - - // Add the new entry into the array - if let Ok(item) = CString::new(k.into_vec()) { - result.push(item); - } else { - *saw_nul = true; - } - } - - result -} - -impl Stdio { - pub fn to_child_stdio(&self, readable: bool) -> io::Result<(ChildStdio, Option)> { - match *self { - Stdio::Inherit => Ok((ChildStdio::Inherit, None)), - - // Make sure that the source descriptors are not an stdio - // descriptor, otherwise the order which we set the child's - // descriptors may blow away a descriptor which we are hoping to - // save. For example, suppose we want the child's stderr to be the - // parent's stdout, and the child's stdout to be the parent's - // stderr. No matter which we dup first, the second will get - // overwritten prematurely. - Stdio::Fd(ref fd) => { - if fd.raw() >= 0 && fd.raw() <= libc::STDERR_FILENO { - Ok((ChildStdio::Owned(fd.duplicate()?), None)) - } else { - Ok((ChildStdio::Explicit(fd.raw()), None)) - } - } - - Stdio::MakePipe => { - let (reader, writer) = pipe::anon_pipe()?; - let (ours, theirs) = if readable { (writer, reader) } else { (reader, writer) }; - Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours))) - } - - Stdio::Null => { - let mut opts = OpenOptions::new(); - opts.read(readable); - opts.write(!readable); - let path = unsafe { CStr::from_ptr("/null\0".as_ptr() as *const _) }; - let fd = File::open_c(&path, &opts)?; - Ok((ChildStdio::Owned(fd.into_fd()), None)) - } - } - } -} - -impl From for Stdio { - fn from(pipe: AnonPipe) -> Stdio { - Stdio::Fd(pipe.into_fd()) - } -} - -impl From for Stdio { - fn from(file: File) -> Stdio { - Stdio::Fd(file.into_fd()) - } -} - -impl ChildStdio { - pub fn fd(&self) -> Option { - match *self { - ChildStdio::Inherit => None, - ChildStdio::Explicit(fd) => Some(fd), - ChildStdio::Owned(ref fd) => Some(fd.raw()), - } - } -} - -impl fmt::Debug for Command { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.program != self.args[0] { - write!(f, "[{:?}] ", self.program)?; - } - write!(f, "{:?}", self.args[0])?; - - for arg in &self.args[1..] { - write!(f, " {:?}", arg)?; - } - Ok(()) - } -} - -/// Unix exit statuses -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitStatus(c_int); - -impl ExitStatus { - pub fn new(status: c_int) -> ExitStatus { - ExitStatus(status) - } - - fn exited(&self) -> bool { - libc::WIFEXITED(self.0) - } - - pub fn success(&self) -> bool { - self.code() == Some(0) - } - - pub fn code(&self) -> Option { - if self.exited() { Some(libc::WEXITSTATUS(self.0)) } else { None } - } - - pub fn signal(&self) -> Option { - if !self.exited() { Some(libc::WTERMSIG(self.0)) } else { None } - } -} - -/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying. -impl From for ExitStatus { - fn from(a: c_int) -> ExitStatus { - ExitStatus(a) - } -} - -impl fmt::Display for ExitStatus { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(code) = self.code() { - write!(f, "exit code: {}", code) - } else { - let signal = self.signal().unwrap(); - write!(f, "signal: {}", signal) - } - } -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitCode(u8); - -impl ExitCode { - pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _); - pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _); - - #[inline] - pub fn as_i32(&self) -> i32 { - self.0 as i32 - } -} diff --git a/library/std/src/sys/vxworks/process/process_vxworks.rs b/library/std/src/sys/vxworks/process/process_vxworks.rs index f7e84ae3de9..69adbcdddc9 100644 --- a/library/std/src/sys/vxworks/process/process_vxworks.rs +++ b/library/std/src/sys/vxworks/process/process_vxworks.rs @@ -1,3 +1,4 @@ +use crate::fmt; use crate::io::{self, Error, ErrorKind}; use crate::sys; use crate::sys::cvt; @@ -67,7 +68,7 @@ impl Command { let _lock = sys::os::env_lock(); let ret = libc::rtpSpawn( - self.get_program().as_ptr(), + self.get_program_cstr().as_ptr(), self.get_argv().as_ptr() as *mut *const c_char, // argv c_envp as *mut *const c_char, 100 as c_int, // initial priority @@ -167,3 +168,47 @@ impl Process { } } } + +/// Unix exit statuses +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitStatus(c_int); + +impl ExitStatus { + pub fn new(status: c_int) -> ExitStatus { + ExitStatus(status) + } + + fn exited(&self) -> bool { + libc::WIFEXITED(self.0) + } + + pub fn success(&self) -> bool { + self.code() == Some(0) + } + + pub fn code(&self) -> Option { + if self.exited() { Some(libc::WEXITSTATUS(self.0)) } else { None } + } + + pub fn signal(&self) -> Option { + if !self.exited() { Some(libc::WTERMSIG(self.0)) } else { None } + } +} + +/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying. +impl From for ExitStatus { + fn from(a: c_int) -> ExitStatus { + ExitStatus(a) + } +} + +impl fmt::Display for ExitStatus { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(code) = self.code() { + write!(f, "exit code: {}", code) + } else { + let signal = self.signal().unwrap(); + write!(f, "signal: {}", signal) + } + } +} From ef91de640294e6d0fbf881082196ba83379ea447 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Thu, 15 Oct 2020 22:37:53 -0700 Subject: [PATCH 207/446] Run cargo dev fmt Signed-off-by: Joe Richey --- clippy_lints/src/future_not_send.rs | 9 ++------- clippy_lints/src/trivially_copy_pass_by_ref.rs | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index d2a322e1223..71a30d1c33d 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -92,13 +92,8 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { |db| { cx.tcx.infer_ctxt().enter(|infcx| { for FulfillmentError { obligation, .. } in send_errors { - infcx.maybe_note_obligation_cause_for_async_await( - db, - &obligation, - ); - if let Trait(trait_pred, _) = - obligation.predicate.skip_binders() - { + infcx.maybe_note_obligation_cause_for_async_await(db, &obligation); + if let Trait(trait_pred, _) = obligation.predicate.skip_binders() { db.note(&format!( "`{}` doesn't implement `{}`", trait_pred.self_ty(), diff --git a/clippy_lints/src/trivially_copy_pass_by_ref.rs b/clippy_lints/src/trivially_copy_pass_by_ref.rs index d92eb86fb2e..e90ea0fc200 100644 --- a/clippy_lints/src/trivially_copy_pass_by_ref.rs +++ b/clippy_lints/src/trivially_copy_pass_by_ref.rs @@ -12,8 +12,8 @@ use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; use rustc_target::abi::LayoutOf; -use rustc_target::spec::Target; use rustc_target::spec::abi::Abi; +use rustc_target::spec::Target; declare_clippy_lint! { /// **What it does:** Checks for functions taking arguments by reference, where From 7b652d341e9a476658af8a9186972ce73ec38c3c Mon Sep 17 00:00:00 2001 From: Niels Sascha Reedijk Date: Sat, 19 Sep 2020 09:17:53 +0100 Subject: [PATCH 208/446] Haiku: explicitly set CMAKE_SYSTEM_NAME when cross-compiling This resolves issues where the cross-build of LLVM fails because it tries to link to the host's system libraries instead of the target's system libraries. --- src/bootstrap/native.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 6bba00ee85e..37d6fab070b 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -378,6 +378,8 @@ fn configure_cmake( cfg.define("CMAKE_SYSTEM_NAME", "FreeBSD"); } else if target.contains("windows") { cfg.define("CMAKE_SYSTEM_NAME", "Windows"); + } else if target.contains("haiku") { + cfg.define("CMAKE_SYSTEM_NAME", "Haiku"); } // When cross-compiling we should also set CMAKE_SYSTEM_VERSION, but in // that case like CMake we cannot easily determine system version either. From 0b062887db9be8fe05791411dd08ca35683cedc8 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 15 Oct 2020 23:36:26 +0200 Subject: [PATCH 209/446] Remove shrink_to_fit from default ToString::to_string implementation. Co-authored-by: scottmcm --- library/alloc/src/string.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index d3598ccfce8..dc67d903a1d 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2200,7 +2200,6 @@ impl ToString for T { let mut buf = String::new(); buf.write_fmt(format_args!("{}", self)) .expect("a Display implementation returned an error unexpectedly"); - buf.shrink_to_fit(); buf } } From 6a32e794c2180a514ad80d3a481300b9afe0b536 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Oct 2020 22:24:14 +0200 Subject: [PATCH 210/446] stabilize union with 'ManuallyDrop' fields and 'impl Drop for Union' --- compiler/rustc_passes/src/stability.rs | 52 +++++++++++-------- compiler/rustc_typeck/src/check/check.rs | 3 +- src/test/ui/did_you_mean/bad-assoc-ty.rs | 1 - src/test/ui/did_you_mean/bad-assoc-ty.stderr | 21 ++------ src/test/ui/drop/dynamic-drop.rs | 2 +- src/test/ui/dropck/dropck-union.rs | 2 - src/test/ui/dropck/dropck-union.stderr | 2 +- .../feature-gate-untagged_unions.rs | 16 ++++-- .../feature-gate-untagged_unions.stderr | 42 ++++----------- .../ui/reject-specialized-drops-8142.stderr | 24 ++++----- src/test/ui/self/self-in-typedefs.rs | 3 -- src/test/ui/transmute/main.rs | 3 -- src/test/ui/transmute/main.stderr | 8 +-- src/test/ui/union/union-align.rs | 3 +- src/test/ui/union/union-copy.rs | 4 +- src/test/ui/union/union-copy.stderr | 6 +-- src/test/ui/union/union-derive-clone.rs | 2 - src/test/ui/union/union-derive-clone.stderr | 4 +- src/test/ui/union/union-derive-eq.rs | 4 +- src/test/ui/union/union-derive-eq.stderr | 2 +- src/test/ui/union/union-derive-rpass.rs | 2 - src/test/ui/union/union-drop-assign.rs | 2 - src/test/ui/union/union-drop.rs | 3 +- src/test/ui/union/union-generic-rpass.rs | 4 +- src/test/ui/union/union-manuallydrop-rpass.rs | 1 - src/test/ui/union/union-nodrop.rs | 2 - src/test/ui/union/union-overwrite.rs | 1 - src/test/ui/union/union-packed.rs | 3 +- src/test/ui/union/union-unsafe.rs | 1 - src/test/ui/union/union-unsafe.stderr | 22 ++++---- 30 files changed, 97 insertions(+), 148 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 1378b0d5705..c9497f2a5b2 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -13,15 +13,13 @@ use rustc_hir::{Generics, HirId, Item, StructField, TraitRef, Ty, TyKind, Varian use rustc_middle::hir::map::Map; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::middle::stability::{DeprecationEntry, Index}; -use rustc_middle::ty::query::Providers; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{self, query::Providers, TyCtxt}; use rustc_session::lint; use rustc_session::lint::builtin::INEFFECTIVE_UNSTABLE_TRAIT_IMPL; use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; -use rustc_span::Span; -use rustc_trait_selection::traits::misc::can_type_implement_copy; +use rustc_span::{Span, DUMMY_SP}; use std::cmp::Ordering; use std::mem::replace; @@ -711,27 +709,35 @@ impl Visitor<'tcx> for Checker<'tcx> { // so semi-randomly perform it here in stability.rs hir::ItemKind::Union(..) if !self.tcx.features().untagged_unions => { let def_id = self.tcx.hir().local_def_id(item.hir_id); - let adt_def = self.tcx.adt_def(def_id); let ty = self.tcx.type_of(def_id); + let (adt_def, substs) = match ty.kind() { + ty::Adt(adt_def, substs) => (adt_def, substs), + _ => bug!(), + }; - if adt_def.has_dtor(self.tcx) { - feature_err( - &self.tcx.sess.parse_sess, - sym::untagged_unions, - item.span, - "unions with `Drop` implementations are unstable", - ) - .emit(); - } else { - let param_env = self.tcx.param_env(def_id); - if can_type_implement_copy(self.tcx, param_env, ty).is_err() { - feature_err( - &self.tcx.sess.parse_sess, - sym::untagged_unions, - item.span, - "unions with non-`Copy` fields are unstable", - ) - .emit(); + // Non-`Copy` fields are unstable, except for `ManuallyDrop`. + let param_env = self.tcx.param_env(def_id); + for field in &adt_def.non_enum_variant().fields { + let field_ty = field.ty(self.tcx, substs); + if !field_ty.ty_adt_def().map_or(false, |adt_def| adt_def.is_manually_drop()) + && !field_ty.is_copy_modulo_regions(self.tcx.at(DUMMY_SP), param_env) + { + if field_ty.needs_drop(self.tcx, param_env) { + // Avoid duplicate error: This will error later anyway because fields + // that need drop are not allowed. + self.tcx.sess.delay_span_bug( + item.span, + "union should have been rejected due to potentially dropping field", + ); + } else { + feature_err( + &self.tcx.sess.parse_sess, + sym::untagged_unions, + self.tcx.def_span(field.did), + "unions with non-`Copy` fields other than `ManuallyDrop` are unstable", + ) + .emit(); + } } } } diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index b9a5db47855..3d8653b4a6a 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -348,8 +348,7 @@ pub(super) fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) { check_packed(tcx, span, def); } -/// When the `#![feature(untagged_unions)]` gate is active, -/// check that the fields of the `union` does not contain fields that need dropping. +/// Check that the fields of the `union` do not need dropping. pub(super) fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool { let item_type = tcx.type_of(item_def_id); if let ty::Adt(def, substs) = item_type.kind() { diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.rs b/src/test/ui/did_you_mean/bad-assoc-ty.rs index e66b432ede2..99ebe84cd9d 100644 --- a/src/test/ui/did_you_mean/bad-assoc-ty.rs +++ b/src/test/ui/did_you_mean/bad-assoc-ty.rs @@ -68,7 +68,6 @@ enum N where F: Fn() -> _ { union O where F: Fn() -> _ { //~^ ERROR the type placeholder `_` is not allowed within types on item signatures -//~| ERROR unions with non-`Copy` fields are unstable foo: F, } diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.stderr b/src/test/ui/did_you_mean/bad-assoc-ty.stderr index 4835d9ab107..ebc0883370b 100644 --- a/src/test/ui/did_you_mean/bad-assoc-ty.stderr +++ b/src/test/ui/did_you_mean/bad-assoc-ty.stderr @@ -57,19 +57,6 @@ LL | type J = ty!(u8); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0658]: unions with non-`Copy` fields are unstable - --> $DIR/bad-assoc-ty.rs:69:1 - | -LL | / union O where F: Fn() -> _ { -LL | | -LL | | -LL | | foo: F, -LL | | } - | |_^ - | - = note: see issue #55149 for more information - = help: add `#![feature(untagged_unions)]` to the crate attributes to enable - error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:1:10 | @@ -215,7 +202,7 @@ LL | union O where F: Fn() -> T { | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/bad-assoc-ty.rs:75:29 + --> $DIR/bad-assoc-ty.rs:74:29 | LL | trait P where F: Fn() -> _ { | ^ not allowed in type signatures @@ -226,7 +213,7 @@ LL | trait P where F: Fn() -> T { | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/bad-assoc-ty.rs:80:38 + --> $DIR/bad-assoc-ty.rs:79:38 | LL | fn foo(_: F) where F: Fn() -> _ {} | ^ not allowed in type signatures @@ -236,7 +223,7 @@ help: use type parameters instead LL | fn foo(_: F) where F: Fn() -> T {} | ^^^ ^ -error: aborting due to 29 previous errors +error: aborting due to 28 previous errors -Some errors have detailed explanations: E0121, E0223, E0658. +Some errors have detailed explanations: E0121, E0223. For more information about an error, try `rustc --explain E0121`. diff --git a/src/test/ui/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs index ada61bf0df0..6d0cd101dbc 100644 --- a/src/test/ui/drop/dynamic-drop.rs +++ b/src/test/ui/drop/dynamic-drop.rs @@ -1,7 +1,7 @@ // run-pass // ignore-wasm32-bare compiled with panic=abort by default -#![feature(generators, generator_trait, untagged_unions)] +#![feature(generators, generator_trait)] #![feature(bindings_after_at)] #![allow(unused_assignments)] diff --git a/src/test/ui/dropck/dropck-union.rs b/src/test/ui/dropck/dropck-union.rs index ef4d1b360b8..5a9965db5ed 100644 --- a/src/test/ui/dropck/dropck-union.rs +++ b/src/test/ui/dropck/dropck-union.rs @@ -1,5 +1,3 @@ -#![feature(untagged_unions)] - use std::cell::Cell; use std::ops::Deref; use std::mem::ManuallyDrop; diff --git a/src/test/ui/dropck/dropck-union.stderr b/src/test/ui/dropck/dropck-union.stderr index 228744326f9..854e29385a8 100644 --- a/src/test/ui/dropck/dropck-union.stderr +++ b/src/test/ui/dropck/dropck-union.stderr @@ -1,5 +1,5 @@ error[E0597]: `v` does not live long enough - --> $DIR/dropck-union.rs:39:18 + --> $DIR/dropck-union.rs:37:18 | LL | v.0.set(Some(&v)); | ^^ borrowed value does not live long enough diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs index 9ee0e6f681d..f5f9631c3bc 100644 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs +++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs @@ -1,3 +1,5 @@ +// ignore-tidy-linelength + union U1 { // OK a: u8, } @@ -6,15 +8,23 @@ union U2 { // OK a: T, } -union U3 { //~ ERROR unions with non-`Copy` fields are unstable +union U22 { // OK + a: std::mem::ManuallyDrop, +} + +union U3 { a: String, //~ ERROR unions may not contain fields that need dropping } -union U4 { //~ ERROR unions with non-`Copy` fields are unstable +union U32 { // field that does not drop but is not `Copy`, either -- this is the real feature gate test! + a: std::cell::RefCell, //~ ERROR unions with non-`Copy` fields other than `ManuallyDrop` are unstable +} + +union U4 { a: T, //~ ERROR unions may not contain fields that need dropping } -union U5 { //~ ERROR unions with `Drop` implementations are unstable +union U5 { // Having a drop impl is OK a: u8, } diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr index 3a123ea1c93..ed973871b3f 100644 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr +++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr @@ -1,61 +1,37 @@ -error[E0658]: unions with non-`Copy` fields are unstable - --> $DIR/feature-gate-untagged_unions.rs:9:1 +error[E0658]: unions with non-`Copy` fields other than `ManuallyDrop` are unstable + --> $DIR/feature-gate-untagged_unions.rs:20:5 | -LL | / union U3 { -LL | | a: String, -LL | | } - | |_^ - | - = note: see issue #55149 for more information - = help: add `#![feature(untagged_unions)]` to the crate attributes to enable - -error[E0658]: unions with non-`Copy` fields are unstable - --> $DIR/feature-gate-untagged_unions.rs:13:1 - | -LL | / union U4 { -LL | | a: T, -LL | | } - | |_^ - | - = note: see issue #55149 for more information - = help: add `#![feature(untagged_unions)]` to the crate attributes to enable - -error[E0658]: unions with `Drop` implementations are unstable - --> $DIR/feature-gate-untagged_unions.rs:17:1 - | -LL | / union U5 { -LL | | a: u8, -LL | | } - | |_^ +LL | a: std::cell::RefCell, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #55149 for more information = help: add `#![feature(untagged_unions)]` to the crate attributes to enable error[E0740]: unions may not contain fields that need dropping - --> $DIR/feature-gate-untagged_unions.rs:10:5 + --> $DIR/feature-gate-untagged_unions.rs:16:5 | LL | a: String, | ^^^^^^^^^ | note: `std::mem::ManuallyDrop` can be used to wrap the type - --> $DIR/feature-gate-untagged_unions.rs:10:5 + --> $DIR/feature-gate-untagged_unions.rs:16:5 | LL | a: String, | ^^^^^^^^^ error[E0740]: unions may not contain fields that need dropping - --> $DIR/feature-gate-untagged_unions.rs:14:5 + --> $DIR/feature-gate-untagged_unions.rs:24:5 | LL | a: T, | ^^^^ | note: `std::mem::ManuallyDrop` can be used to wrap the type - --> $DIR/feature-gate-untagged_unions.rs:14:5 + --> $DIR/feature-gate-untagged_unions.rs:24:5 | LL | a: T, | ^^^^ -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0658, E0740. For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/reject-specialized-drops-8142.stderr b/src/test/ui/reject-specialized-drops-8142.stderr index f819faa2789..eac24617533 100644 --- a/src/test/ui/reject-specialized-drops-8142.stderr +++ b/src/test/ui/reject-specialized-drops-8142.stderr @@ -1,15 +1,3 @@ -error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the union it is implemented for does not - --> $DIR/reject-specialized-drops-8142.rs:67:21 - | -LL | impl Drop for Union { fn drop(&mut self) { } } // REJECT - | ^^^^^ - | -note: the implementor must specify the same requirement - --> $DIR/reject-specialized-drops-8142.rs:21:1 - | -LL | union Union { f: T } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0367]: `Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not --> $DIR/reject-specialized-drops-8142.rs:23:20 | @@ -145,6 +133,18 @@ note: the implementor must specify the same requirement LL | struct TupleStruct(T); | ^^^^^^^^^^^^^^^^^^^^^^^^^ +error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the union it is implemented for does not + --> $DIR/reject-specialized-drops-8142.rs:67:21 + | +LL | impl Drop for Union { fn drop(&mut self) { } } // REJECT + | ^^^^^ + | +note: the implementor must specify the same requirement + --> $DIR/reject-specialized-drops-8142.rs:21:1 + | +LL | union Union { f: T } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: aborting due to 11 previous errors Some errors have detailed explanations: E0308, E0366, E0367, E0495. diff --git a/src/test/ui/self/self-in-typedefs.rs b/src/test/ui/self/self-in-typedefs.rs index 3b1eb9e1dfa..81e557d53a6 100644 --- a/src/test/ui/self/self-in-typedefs.rs +++ b/src/test/ui/self/self-in-typedefs.rs @@ -1,7 +1,4 @@ // build-pass (FIXME(62277): could be check-pass?) - -#![feature(untagged_unions)] - #![allow(dead_code)] use std::mem::ManuallyDrop; diff --git a/src/test/ui/transmute/main.rs b/src/test/ui/transmute/main.rs index ea233a47a78..cb46fc5ec46 100644 --- a/src/test/ui/transmute/main.rs +++ b/src/test/ui/transmute/main.rs @@ -1,9 +1,6 @@ // normalize-stderr-32bit: "`&str` \(64 bits\)" -> "`&str` ($$STR bits)" // normalize-stderr-64bit: "`&str` \(128 bits\)" -> "`&str` ($$STR bits)" - - -#![feature(untagged_unions)] use std::mem::transmute; pub trait TypeConstructor<'a> { diff --git a/src/test/ui/transmute/main.stderr b/src/test/ui/transmute/main.stderr index 4e781318329..f48562094a4 100644 --- a/src/test/ui/transmute/main.stderr +++ b/src/test/ui/transmute/main.stderr @@ -1,5 +1,5 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/main.rs:16:5 + --> $DIR/main.rs:13:5 | LL | transmute(x) | ^^^^^^^^^ @@ -7,7 +7,7 @@ LL | transmute(x) = note: `::T` does not have a fixed size error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/main.rs:20:17 + --> $DIR/main.rs:17:17 | LL | let x: u8 = transmute(10u16); | ^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let x: u8 = transmute(10u16); = note: target type: `u8` (8 bits) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/main.rs:24:17 + --> $DIR/main.rs:21:17 | LL | let x: u8 = transmute("test"); | ^^^^^^^^^ @@ -25,7 +25,7 @@ LL | let x: u8 = transmute("test"); = note: target type: `u8` (8 bits) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/main.rs:29:18 + --> $DIR/main.rs:26:18 | LL | let x: Foo = transmute(10); | ^^^^^^^^^ diff --git a/src/test/ui/union/union-align.rs b/src/test/ui/union/union-align.rs index edd83a51169..1340ae43cd6 100644 --- a/src/test/ui/union/union-align.rs +++ b/src/test/ui/union/union-align.rs @@ -1,8 +1,6 @@ // run-pass #![allow(dead_code)] -#![feature(untagged_unions)] - use std::mem::{size_of, size_of_val, align_of, align_of_val}; #[repr(align(16))] @@ -35,6 +33,7 @@ mod hybrid { use std::mem::{size_of, align_of}; #[repr(align(16))] + #[derive(Copy, Clone)] struct S1 { a: u16, b: u8, diff --git a/src/test/ui/union/union-copy.rs b/src/test/ui/union/union-copy.rs index 8318f96940e..5c3f8d90898 100644 --- a/src/test/ui/union/union-copy.rs +++ b/src/test/ui/union/union-copy.rs @@ -1,5 +1,3 @@ -#![feature(untagged_unions)] - #[derive(Clone)] union U { a: u8 @@ -7,7 +5,7 @@ union U { #[derive(Clone)] union W { - a: String + a: std::mem::ManuallyDrop } impl Copy for U {} // OK diff --git a/src/test/ui/union/union-copy.stderr b/src/test/ui/union/union-copy.stderr index a875ff660f9..0f47bae7f0f 100644 --- a/src/test/ui/union/union-copy.stderr +++ b/src/test/ui/union/union-copy.stderr @@ -1,8 +1,8 @@ error[E0204]: the trait `Copy` may not be implemented for this type - --> $DIR/union-copy.rs:14:6 + --> $DIR/union-copy.rs:12:6 | -LL | a: String - | --------- this field does not implement `Copy` +LL | a: std::mem::ManuallyDrop + | --------------------------------- this field does not implement `Copy` ... LL | impl Copy for W {} | ^^^^ diff --git a/src/test/ui/union/union-derive-clone.rs b/src/test/ui/union/union-derive-clone.rs index 8126980604a..753a9f74d03 100644 --- a/src/test/ui/union/union-derive-clone.rs +++ b/src/test/ui/union/union-derive-clone.rs @@ -1,5 +1,3 @@ -#![feature(untagged_unions)] - use std::mem::ManuallyDrop; #[derive(Clone)] //~ ERROR the trait bound `U1: Copy` is not satisfied diff --git a/src/test/ui/union/union-derive-clone.stderr b/src/test/ui/union/union-derive-clone.stderr index 7a59f539c37..e18f457a8b6 100644 --- a/src/test/ui/union/union-derive-clone.stderr +++ b/src/test/ui/union/union-derive-clone.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `U1: Copy` is not satisfied - --> $DIR/union-derive-clone.rs:5:10 + --> $DIR/union-derive-clone.rs:3:10 | LL | #[derive(Clone)] | ^^^^^ the trait `Copy` is not implemented for `U1` @@ -12,7 +12,7 @@ LL | pub struct AssertParamIsCopy { = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no method named `clone` found for union `U5` in the current scope - --> $DIR/union-derive-clone.rs:37:15 + --> $DIR/union-derive-clone.rs:35:15 | LL | union U5 { | ----------- diff --git a/src/test/ui/union/union-derive-eq.rs b/src/test/ui/union/union-derive-eq.rs index ac5808e4361..e689f8c27d7 100644 --- a/src/test/ui/union/union-derive-eq.rs +++ b/src/test/ui/union/union-derive-eq.rs @@ -1,5 +1,3 @@ -#![feature(untagged_unions)] - #[derive(Eq)] // OK union U1 { a: u8, @@ -7,7 +5,7 @@ union U1 { impl PartialEq for U1 { fn eq(&self, rhs: &Self) -> bool { true } } -#[derive(PartialEq)] +#[derive(PartialEq, Copy, Clone)] struct PartialEqNotEq; #[derive(Eq)] diff --git a/src/test/ui/union/union-derive-eq.stderr b/src/test/ui/union/union-derive-eq.stderr index c4d437c6cdd..0591d12d598 100644 --- a/src/test/ui/union/union-derive-eq.stderr +++ b/src/test/ui/union/union-derive-eq.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `PartialEqNotEq: Eq` is not satisfied - --> $DIR/union-derive-eq.rs:15:5 + --> $DIR/union-derive-eq.rs:13:5 | LL | a: PartialEqNotEq, | ^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `PartialEqNotEq` diff --git a/src/test/ui/union/union-derive-rpass.rs b/src/test/ui/union/union-derive-rpass.rs index b2f7ae679fd..db18a81c1f6 100644 --- a/src/test/ui/union/union-derive-rpass.rs +++ b/src/test/ui/union/union-derive-rpass.rs @@ -4,8 +4,6 @@ // Some traits can be derived for unions. -#![feature(untagged_unions)] - #[derive( Copy, Clone, diff --git a/src/test/ui/union/union-drop-assign.rs b/src/test/ui/union/union-drop-assign.rs index f1511b0a601..215666bdd9d 100644 --- a/src/test/ui/union/union-drop-assign.rs +++ b/src/test/ui/union/union-drop-assign.rs @@ -3,8 +3,6 @@ // Drop works for union itself. -#![feature(untagged_unions)] - use std::mem::ManuallyDrop; struct S; diff --git a/src/test/ui/union/union-drop.rs b/src/test/ui/union/union-drop.rs index 4df3ed50282..9edf5827511 100644 --- a/src/test/ui/union/union-drop.rs +++ b/src/test/ui/union/union-drop.rs @@ -4,8 +4,7 @@ // Drop works for union itself. -#![feature(untagged_unions)] - +#[derive(Copy, Clone)] struct S; union U { diff --git a/src/test/ui/union/union-generic-rpass.rs b/src/test/ui/union/union-generic-rpass.rs index eb169c516d2..69837f31cab 100644 --- a/src/test/ui/union/union-generic-rpass.rs +++ b/src/test/ui/union/union-generic-rpass.rs @@ -1,8 +1,6 @@ // run-pass #![allow(dead_code)] -#![feature(untagged_unions)] - use std::mem::ManuallyDrop; union MaybeItem { @@ -16,7 +14,7 @@ union U where A: Copy, B: Copy { } unsafe fn union_transmute(a: A) -> B where A: Copy, B: Copy { - U { a: a }.b + U { a }.b } fn main() { diff --git a/src/test/ui/union/union-manuallydrop-rpass.rs b/src/test/ui/union/union-manuallydrop-rpass.rs index a43a5050865..977d12f1086 100644 --- a/src/test/ui/union/union-manuallydrop-rpass.rs +++ b/src/test/ui/union/union-manuallydrop-rpass.rs @@ -1,4 +1,3 @@ -#![feature(untagged_unions)] #![allow(dead_code)] // run-pass diff --git a/src/test/ui/union/union-nodrop.rs b/src/test/ui/union/union-nodrop.rs index 59282bec59b..bc58c5995cb 100644 --- a/src/test/ui/union/union-nodrop.rs +++ b/src/test/ui/union/union-nodrop.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(untagged_unions)] - #![allow(dead_code)] use std::mem::needs_drop; diff --git a/src/test/ui/union/union-overwrite.rs b/src/test/ui/union/union-overwrite.rs index 8234beb74a8..399ed9ae458 100644 --- a/src/test/ui/union/union-overwrite.rs +++ b/src/test/ui/union/union-overwrite.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(untagged_unions)] #[repr(C)] #[derive(Copy, Clone)] diff --git a/src/test/ui/union/union-packed.rs b/src/test/ui/union/union-packed.rs index ceb35d94656..9cde44c06bd 100644 --- a/src/test/ui/union/union-packed.rs +++ b/src/test/ui/union/union-packed.rs @@ -2,8 +2,6 @@ #![allow(dead_code)] #![allow(non_snake_case)] -#![feature(untagged_unions)] - use std::mem::{size_of, size_of_val, align_of, align_of_val}; struct S { @@ -118,6 +116,7 @@ mod hybrid { use std::mem::{size_of, align_of}; #[repr(packed)] + #[derive(Copy, Clone)] struct S1 { a: u16, b: u8, diff --git a/src/test/ui/union/union-unsafe.rs b/src/test/ui/union/union-unsafe.rs index 8535cbd019c..10f0c467560 100644 --- a/src/test/ui/union/union-unsafe.rs +++ b/src/test/ui/union/union-unsafe.rs @@ -1,4 +1,3 @@ -#![feature(untagged_unions)] use std::mem::ManuallyDrop; union U1 { diff --git a/src/test/ui/union/union-unsafe.stderr b/src/test/ui/union/union-unsafe.stderr index e020dab63f8..b50d9e17506 100644 --- a/src/test/ui/union/union-unsafe.stderr +++ b/src/test/ui/union/union-unsafe.stderr @@ -1,5 +1,5 @@ error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:22:5 + --> $DIR/union-unsafe.rs:21:5 | LL | u3.a = ManuallyDrop::new(T::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field @@ -7,7 +7,7 @@ LL | u3.a = ManuallyDrop::new(T::default()); = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:23:6 + --> $DIR/union-unsafe.rs:22:6 | LL | *u3.a = T::default(); | ^^^^ access to union field @@ -15,7 +15,7 @@ LL | *u3.a = T::default(); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:29:6 + --> $DIR/union-unsafe.rs:28:6 | LL | *u3.a = T::default(); | ^^^^ access to union field @@ -23,7 +23,7 @@ LL | *u3.a = T::default(); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:37:13 + --> $DIR/union-unsafe.rs:36:13 | LL | let a = u1.a; | ^^^^ access to union field @@ -31,7 +31,7 @@ LL | let a = u1.a; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:40:14 + --> $DIR/union-unsafe.rs:39:14 | LL | let U1 { a } = u1; | ^ access to union field @@ -39,7 +39,7 @@ LL | let U1 { a } = u1; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:41:20 + --> $DIR/union-unsafe.rs:40:20 | LL | if let U1 { a: 12 } = u1 {} | ^^ access to union field @@ -47,7 +47,7 @@ LL | if let U1 { a: 12 } = u1 {} = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:45:5 + --> $DIR/union-unsafe.rs:44:5 | LL | u2.a = ManuallyDrop::new(String::from("new")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field @@ -55,7 +55,7 @@ LL | u2.a = ManuallyDrop::new(String::from("new")); = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:46:6 + --> $DIR/union-unsafe.rs:45:6 | LL | *u2.a = String::from("new"); | ^^^^ access to union field @@ -63,7 +63,7 @@ LL | *u2.a = String::from("new"); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:50:6 + --> $DIR/union-unsafe.rs:49:6 | LL | *u3.a = 1; | ^^^^ access to union field @@ -71,7 +71,7 @@ LL | *u3.a = 1; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:53:5 + --> $DIR/union-unsafe.rs:52:5 | LL | u3.a = ManuallyDrop::new(String::from("new")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field @@ -79,7 +79,7 @@ LL | u3.a = ManuallyDrop::new(String::from("new")); = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:54:6 + --> $DIR/union-unsafe.rs:53:6 | LL | *u3.a = String::from("new"); | ^^^^ access to union field From defcd7ff47d81f184eb3ba5c1d44bbb9e3658de0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Oct 2020 09:20:39 +0200 Subject: [PATCH 211/446] stop relying on feature(untagged_unions) in stdlib --- library/core/src/lib.rs | 2 +- library/core/src/ptr/mod.rs | 10 ++++++++++ library/std/src/lib.rs | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 97f27566eb0..737a95b603b 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -131,7 +131,7 @@ #![feature(transparent_unions)] #![feature(unboxed_closures)] #![feature(unsized_locals)] -#![feature(untagged_unions)] +#![cfg_attr(bootstrap, feature(untagged_unions))] #![feature(unwind_attributes)] #![feature(variant_count)] #![feature(tbm_target_feature)] diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 92c4f2ccfe8..bca3be56ba5 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -229,6 +229,16 @@ pub(crate) struct FatPtr { pub(crate) len: usize, } +// Manual impl needed to avoid `T: Clone` bound. +impl Clone for FatPtr { + fn clone(&self) -> Self { + *self + } +} + +// Manual impl needed to avoid `T: Copy` bound. +impl Copy for FatPtr {} + /// Forms a raw slice from a pointer and a length. /// /// The `len` argument is the number of **elements**, not the number of bytes. diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 5224672adb2..30e7a7f3c3b 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -319,7 +319,7 @@ #![feature(unsafe_block_in_unsafe_fn)] #![feature(unsafe_cell_get_mut)] #![feature(unsafe_cell_raw_get)] -#![feature(untagged_unions)] +#![cfg_attr(bootstrap, feature(untagged_unions))] #![feature(unwind_attributes)] #![feature(vec_into_raw_parts)] #![feature(wake_trait)] From 6d358d29b0eb4e6f21526ccfb29636dea20d8993 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 16 Oct 2020 14:23:17 +0200 Subject: [PATCH 212/446] Update semver 0.10 -> 0.11 --- Cargo.toml | 2 +- clippy_lints/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c7a3099b8ab..e67aba19b7e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ path = "src/driver.rs" # begin automatic update clippy_lints = { version = "0.0.212", path = "clippy_lints" } # end automatic update -semver = "0.10" +semver = "0.11" rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util"} tempfile = { version = "3.1.0", optional = true } lazy_static = "1.0" diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index fcf817b82c8..cd9363a8572 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -27,7 +27,7 @@ serde = { version = "1.0", features = ["derive"] } smallvec = { version = "1", features = ["union"] } toml = "0.5.3" unicode-normalization = "0.1" -semver = "0.10.0" +semver = "0.11" # NOTE: cargo requires serde feat in its url dep # see url = { version = "2.1.0", features = ["serde"] } From a577942a8f398a516a1156be8e3e672cd28edf3d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 16 Oct 2020 15:01:17 +0200 Subject: [PATCH 213/446] Fix sidebar scroll on mobile devices --- src/librustdoc/html/static/main.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 1b3eb2011af..67e50bba1f2 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -2716,10 +2716,6 @@ function defocusSearchBar() { }; } - window.onresize = function() { - hideSidebar(); - }; - if (main) { onEachLazy(main.getElementsByClassName("loading-content"), function(e) { e.remove(); From e0506d1e9a21d0c6791978576a04c22e70b75bb1 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Fri, 16 Oct 2020 18:17:55 +0200 Subject: [PATCH 214/446] liballoc: VecDeque: Add tracking issue for binary search fns --- library/alloc/src/collections/vec_deque.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/collections/vec_deque.rs b/library/alloc/src/collections/vec_deque.rs index 1560263684a..6ba0a463da4 100644 --- a/library/alloc/src/collections/vec_deque.rs +++ b/library/alloc/src/collections/vec_deque.rs @@ -2471,7 +2471,7 @@ impl VecDeque { /// deque.insert(idx, num); /// assert_eq!(deque, &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); /// ``` - #[unstable(feature = "vecdeque_binary_search", issue = "1")] + #[unstable(feature = "vecdeque_binary_search", issue = "78021")] #[inline] pub fn binary_search(&self, x: &T) -> Result where @@ -2511,7 +2511,7 @@ impl VecDeque { /// let r = deque.binary_search_by(|x| x.cmp(&1)); /// assert!(matches!(r, Ok(1..=4))); /// ``` - #[unstable(feature = "vecdeque_binary_search", issue = "1")] + #[unstable(feature = "vecdeque_binary_search", issue = "78021")] pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result where F: FnMut(&'a T) -> Ordering, @@ -2569,7 +2569,7 @@ impl VecDeque { /// let r = deque.binary_search_by_key(&1, |&(a,b)| b); /// assert!(matches!(r, Ok(1..=4))); /// ``` - #[unstable(feature = "vecdeque_binary_search", issue = "1")] + #[unstable(feature = "vecdeque_binary_search", issue = "78021")] #[inline] pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result where From 2ce11afbec1dc1279360063fee0135a09b7fc11b Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Fri, 16 Oct 2020 00:52:49 +0800 Subject: [PATCH 215/446] Use double quote for rustdoc html --- src/librustdoc/html/render/mod.rs | 259 +++++++++++++++--------------- 1 file changed, 133 insertions(+), 126 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 0608c4e32e0..b43ae9a46af 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -540,11 +540,11 @@ impl FormatRenderer for Context { }; let sidebar = if let Some(ref version) = cache.crate_version { format!( - "

Crate {}

\ -
\ + "

Crate {}

\ +
\

Version {}

\
\ -

Back to index

", +

Back to index

", crate_name, Escape(version), ) @@ -567,7 +567,7 @@ impl FormatRenderer for Context { page.root_path = "./"; let mut style_files = self.shared.style_files.clone(); - let sidebar = "

Settings

"; + let sidebar = "

Settings

"; style_files.push(StylePath { path: PathBuf::from("settings.css"), disabled: false }); let v = layout::render( &self.shared.layout, @@ -808,7 +808,7 @@ function handleThemeButtonsBlur(e) {{ themePicker.onclick = switchThemeButtonState; themePicker.onblur = handleThemeButtonsBlur; {}.forEach(function(item) {{ - var but = document.createElement('button'); + var but = document.createElement(\"button\"); but.textContent = item; but.onclick = function(el) {{ switchTheme(currentTheme, mainTheme, item, true); @@ -1031,11 +1031,11 @@ themePicker.onblur = handleThemeButtonsBlur; // with rustdoc running in parallel. all_indexes.sort(); { - let mut v = String::from("var searchIndex = JSON.parse('{\\\n"); + let mut v = String::from("var searchIndex = JSON.parse(\"{\\n"); v.push_str(&all_indexes.join(",\\\n")); // "addSearchOptions" has to be called first so the crate filtering can be set before the // search might start (if it's set into the URL for example). - v.push_str("\\\n}');\naddSearchOptions(searchIndex);initSearch(searchIndex);"); + v.push_str("\\\n}\");\naddSearchOptions(searchIndex);initSearch(searchIndex);"); cx.shared.fs.write(&dst, &v)?; } if options.enable_index_page { @@ -1064,10 +1064,9 @@ themePicker.onblur = handleThemeButtonsBlur; krates.dedup(); let content = format!( - "

\ - List of all crates\ -

\ -
    {}
", + "

\ + List of all crates\ +

    {}
", krates .iter() .map(|s| { @@ -1211,7 +1210,7 @@ impl ItemEntry { impl ItemEntry { crate fn print(&self) -> impl fmt::Display + '_ { crate::html::format::display_fn(move |f| { - write!(f, "{}", self.url, Escape(&self.name)) + write!(f, "{}", self.url, Escape(&self.name)) }) } } @@ -1302,7 +1301,7 @@ fn print_entries(f: &mut Buffer, e: &FxHashSet, title: &str, class: & e.sort(); write!( f, - "

{}

    {}
", + "

{}

    {}
", title, Escape(title), class, @@ -1315,16 +1314,16 @@ impl AllTypes { fn print(self, f: &mut Buffer) { write!( f, - "

\ - \ - \ + "

\ + \ + \ \ - []\ + []\ \ - List of all items\ + List of all items\

" ); print_entries(f, &self.structs, "Structs", "structs"); @@ -1367,18 +1366,18 @@ impl Setting { fn display(&self, root_path: &str, suffix: &str) -> String { match *self { Setting::Section { description, ref sub_settings } => format!( - "
\ -
{}
\ -
{}
+ "
\ +
{}
\ +
{}
", description, sub_settings.iter().map(|s| s.display(root_path, suffix)).collect::() ), Setting::Toggle { js_data_name, description, default_value } => format!( - "
\ -