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 b6300a40b0d8d..3e7d370c0af43 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 7e178e054cc4e..5a75c94c42f0b 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 a9f10dfec994a..0000000000000 --- 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 501a5bcddb3f2..cb94994fef2f8 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 045dda2d4cb4c..82a4e415b8d86 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 589be26dc27ed..62cfa85577f98 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 36c9e58eb9a87..e1525f8e1bf23 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 65cfe9a9b4996..0cb8d7a891a0d 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 7881c101f9f60..002c770277970 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 79403cf86873e..93501ef40852a 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 2b0ce5ede5630..26124e301115a 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 9dbea0dc9e68b..e668b17c46c0e 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 2eaf7601e54de..6ad55786176c1 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 16fcb6231dc09..f1f21c1d24b0b 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 8e9d1eb98a86b..5ad57b23c4a40 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 0000000000000..47a1bd8dff1b8 --- /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 83e5738cf5412..0000000000000 --- 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 6ad55786176c1..378aad5cb9e97 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 378aad5cb9e97..d9420616b4bc6 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 0cb8d7a891a0d..4d6c681e44c1c 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 002c770277970..512a4a1cc1b44 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 26124e301115a..7b0ec1c43c0a4 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 e668b17c46c0e..90c2708b9c9b2 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 d9420616b4bc6..16d86c8197803 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 5ad57b23c4a40..43185bae3daec 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 0000000000000..0e95d5ded9296 --- /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 47a1bd8dff1b8..0000000000000 --- 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 c9a4022330a7a..e116f650c8d14 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 56746666e2f1f..b66c65f3b6468 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 e116f650c8d14..8b97a87f214b8 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 7f998c63f497b..9f3be26e67236 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 9f3be26e67236..a59d3ef8708b6 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 a59d3ef8708b6..20e75546d7104 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 20e75546d7104..61f0059cca47e 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 61f0059cca47e..2b7830e7cadb2 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 2b7830e7cadb2..bf067c70a7ec6 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 92cb31fcf8544..a0ddcce111e1c 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 bf067c70a7ec6..1c316c00f4337 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 1c316c00f4337..d9896f7fd6b14 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 d9896f7fd6b14..157dff59d4491 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 157dff59d4491..c036d63c33514 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 c036d63c33514..bd2ae47b72347 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 ec8b7e59b5976..50d48650a0938 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 bd2ae47b72347..2aee3b93e8251 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 2aee3b93e8251..98c411f5ae60e 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 0083f94798fe4..87bfb4fdd163b 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 bad84a5890081..a5698b08103b6 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 a5698b08103b6..e6bef9981a3dc 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 87bfb4fdd163b..4846ab5eaaa38 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 e6bef9981a3dc..d189bde0508e1 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 | 55 ++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 50d48650a0938..aada4122e78a4 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; -impl std::ops::Sub for Sugg<'_> { - type Output = Sugg<'static>; - fn sub(self, rhs: Sugg<'_>) -> Sugg<'static> { - make_binop(ast::BinOpKind::Sub, &self, &rhs) - } -} + fn $method(self, other: $t) -> $o { + $imp::$method(self, &other) + } + } -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 $imp<&$t> for $t { + type Output = $o; -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) + 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::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 aada4122e78a4..8f2aa724d20ba 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 4846ab5eaaa38..8318fd898112b 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 98c411f5ae60e..5928d12f30bec 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 8f2aa724d20ba..1f448f86d72e3 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 5928d12f30bec..f684e7de8f83f 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 1f448f86d72e3..062b273c0f40f 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 f684e7de8f83f..4ff567ffb0ec5 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 4ff567ffb0ec5..647537933f722 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 647537933f722..f2df53aee4f68 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 8318fd898112b..84758275dd747 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 d189bde0508e1..464b18984fbc5 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 f2df53aee4f68..7c8b6f483bcbf 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 464b18984fbc5..db62ed90d97d6 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 7c8b6f483bcbf..215700fed8cd2 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 maybe_par(self) -> Self { - Self(self.0.maybe_par()) + fn into_sugg(self) -> Sugg<'a> { + self.0 } +} - 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 062b273c0f40f..0b2cb667bf413 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 0000000000000..a49ba9eb10afa --- /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 0000000000000..24393ad9b4d42 --- /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 84758275dd747..0083f94798fe4 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 db62ed90d97d6..54b966f6e5419 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 2a4c42ea0a456..b600074c19770 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 724ec101b23b7..9e60253106b8d 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 247bbf637ceaf..cd7b692c58847 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 b2599410f05e4..dfe7e4da22db8 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 31fcd4b1c2e33..f290c0e632d92 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 b8502768e1d42..8b541e6de065b 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 68258a8888a40..e99554ec68423 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 d39b0a3207763..35080716f28d5 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 dba6c723829dc..c0469f74d457b 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 3f900062cbb6e..fc9124be2a76b 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 47be817b78908..6523f31edbf74 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 cc1aa72d21451..3c78ea9e08ab9 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 00f6e1abe43cb..890686f7737b6 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 69f8ffa581bc1..4dc969e76ed4c 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 c6c7ba2679410..4f36357598d27 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 efe947daa2866..758b4639811bc 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 a0b82375e777d..8965decc37989 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 82d80d8d0b173..42f65625a466f 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 2cfca1724c81b..2f90d4d0baa5e 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 0000000000000..d92a4e8cc8df1 --- /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 0000000000000..1b176579bbbcf --- /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 45eb5e4008089..f56c6ea565685 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 20534e1ae82c5..03e2f931c847b 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 b80907560c385..4b3a0269baea2 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 37e56168c1d64..f1205d447e4ba 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 982f8ef02538b..e3e400c79d658 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 08fe415513d0d..12f5a3b27bb30 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 f82eb338f4c68..aa8f578adf61e 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 a01c3827bb5a5..1b58cf9c4ede5 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[E0737]: `#[track_caller]` requires Rust ABI - --> $DIR/issue-68060.rs:8:13 - | -LL | #[track_caller] - | ^^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors +error: aborting due to previous error -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 0000000000000..90cad7e647b05 --- /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 0000000000000..70b45e393fcf1 --- /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 308634651a384..870eda89c20d7 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 4c542c5f0da64..9af929d409473 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 c3d772f6266c0..e537e3e1a6365 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 03df3569b42bc..14e6f13e1ae44 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 336c0b26bc7d7..173d824d39083 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 cd7b692c58847..1081b3a229ba3 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 dfe7e4da22db8..618225274f104 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 f290c0e632d92..ac1ff99b8f819 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 8b541e6de065b..642e0c3944cf9 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 e99554ec68423..2e7e42f1667e6 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 33e8282c9d2c5..3f4dda813470b 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 35080716f28d5..7dc686c8e7b7d 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 d7f18e19b41bd..94ff4623c60f0 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 c0469f74d457b..946a4de4245f5 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 fc9124be2a76b..9409ce1ed0eab 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 6523f31edbf74..c0f784309b9f8 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 3c78ea9e08ab9..ea2f87232adf1 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 890686f7737b6..a62956ee8da8d 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 70e992a4f7044..5df0ac417f8cd 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 c27bdf09a8ddf..ceda640214808 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 f717cc7addb6b..b391cd4beb479 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 7521c253545e1..61ea852a8c462 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 4dc969e76ed4c..24049c2c58798 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 08c79519dfe16..1816c5245f792 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 4f36357598d27..5cea9f9fea8ac 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 c1274bd0ea6bc..6a7aac25cdea2 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 1081b3a229ba3..7c1d4fc41294f 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 618225274f104..0881258aca1ac 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 ac1ff99b8f819..3152dec30a0e6 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 642e0c3944cf9..bfb47515823a3 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 2e7e42f1667e6..115b471e96b46 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 3f4dda813470b..82660a7c41693 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 7dc686c8e7b7d..e608cd99af238 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 94ff4623c60f0..5a275d5d089b1 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 946a4de4245f5..79b38b0698631 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 9409ce1ed0eab..858990fe59bd5 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 c0f784309b9f8..cb051aa123021 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 ea2f87232adf1..ffd6368bac15f 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 5df0ac417f8cd..4064c5b3819ec 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 ceda640214808..63b70f7fcd95c 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 24049c2c58798..cff0991072103 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 1816c5245f792..edb48b6625ee2 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 5cea9f9fea8ac..f9974acfb7071 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 6a7aac25cdea2..5498dae718f1e 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 612bc3e74911c..42af8a2fb0edb 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 8e3e06896ee78..700f6616af40f 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 f31b75238dffe..02ddc391f6e3c 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 3c0c0450774e9..843dee2478b3f 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 f021943da32da..22b4dbce54a1a 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 74fb519cc82ff..888fb913fb71c 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 711e249d2bca1..ced062269df68 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 f82f49aa77526..6aff0cb8e9ca5 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 a617319faea80..8073fafb0d8f8 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 42af8a2fb0edb..0ad057822b36e 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 22b4dbce54a1a..f021943da32da 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 6aff0cb8e9ca5..f82f49aa77526 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 8073fafb0d8f8..a617319faea80 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 25ed7859d2187..8eaa8fb7e1db0 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 ab63fd03a336e..462fafcf1b58c 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 fe9188cb4904c..3788088b810b9 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 1d9a325b0c2a0..ec2dac5a7d16f 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 f8506d70b2498..40d1882d7d2ad 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 4d9d1d79284a8..facc566513c28 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 215700fed8cd2..9a1ba4907cda0 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 9a1ba4907cda0..2ae5a9acb75cf 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 2ae5a9acb75cf..ea40c2af4f717 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 a49ba9eb10afa..70873c9e99447 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 24393ad9b4d42..598c881b4d6cd 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 ea40c2af4f717..4f279cc5ef7bc 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 4f279cc5ef7bc..d3a1683cc0cbb 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 70873c9e99447..ba388a05a2859 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 598c881b4d6cd..2547b19f5d1d4 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 d3a1683cc0cbb..3e9265c121530 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 9ddd4ad4000ef..2a384d8817c80 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 ea7ea6f067c30..6be719808101f 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 62bb70af06e93..07f604cf71472 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 | 499 +++++++++++------- .../rustc_data_structures/src/sip128/tests.rs | 45 ++ 3 files changed, 349 insertions(+), 196 deletions(-) diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 90b0f25475181..20c68227bd967 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 2c4eff618c685..4acb0e69e9951 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 + + unsafe { + // Initialize spill because we read from it in short_write_process_buffer. + *hasher.buf.get_unchecked_mut(BUFFER_SPILL_INDEX) = MaybeUninit::zeroed(); + } + + hasher } + // A specialized write function for values with size <= 8. #[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; - - // This is only done in the 128 bit version: - self.state.v1 ^= 0xee; + fn short_write(&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_SPILL); + + 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); + } + + self.nbuf = nbuf + size; + + return; + } + + unsafe { self.short_write_process_buffer(x) } } - // 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. + // A specialized write function for values with size <= 8 that should only + // be called when the write would cause the buffer to fill. // - // 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) { + // 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::(); - self.length += size; - - // The original number must be zero-extended, not sign-extended. - debug_assert!(if size < 8 { x >> (8 * size) == 0 } else { true }); - - // The number of bytes needed to fill `self.tail`. - let needed = 8 - self.ntail; - - // 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; + 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; } - // `self.tail` is full, process it. - self.state.v3 ^= self.tail; - Sip24Rounds::c_rounds(&mut self.state); - self.state.v0 ^= self.tail; - - // 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 }; + 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); + + // Process full elements in buffer. + let last = self.nbuf / 8; + + // Since we're consuming self, avoid updating members for a potential + // performance gain. + let mut state = self.state; - self.state.v3 ^= b; - Sip24Rounds::c_rounds(&mut self.state); - self.state.v0 ^= b; + 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; - self.state.v2 ^= 0xee; - Sip24Rounds::d_rounds(&mut self.state); - let _0 = self.state.v0 ^ self.state.v1 ^ self.state.v2 ^ self.state.v3; + 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 2e2274a7b775e..eda7ddc4f6d3b 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 89f7531b3a7ff..32c18c80b2402 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 8daac75837734..30bb9917bf7ad 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 efe921b601104..6ca7a4c273ee2 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 4acb0e69e9951..8b91407acffa9 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 8b91407acffa9..5bbc53945edc6 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 dd7ea55cc1043..753d64d6115f6 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 bec1eb790478c..e0bd4e8b68bec 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 753d64d6115f6..05e6c4804ff65 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 0000000000000..4d083bf232155 --- /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 0000000000000..88b80bc3333c1 --- /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 0000000000000..a346d450586bb --- /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 5d5088de31b97..d7a1d30b0e48b 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 a28d022c66139..64c034f7ec935 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 0000000000000..3593a1d5c8d10 --- /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 0000000000000..3cfce459e37dc --- /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 64c034f7ec935..41e1aafd9bdad 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 d6869ab88751a..516c9b6752b97 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 24695f5cdfa04..7d4bafc10896f 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 41e1aafd9bdad..6e60191892f21 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 636f67a77c890..52d24a2eb4821 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 b867798c76cf7..a877dfcfcb753 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 6e60191892f21..a70309b64c1e9 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 52d24a2eb4821..befdfdbd7cf9c 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 7d4bafc10896f..6d1a5fcc10b0f 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 a877dfcfcb753..3bfb2d3f1b0f9 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 826a059f92abe..d11eeff80323d 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 0000000000000..a05cb6270b762 --- /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 0000000000000..209081e6e8011 --- /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 0000000000000..69162870807a2 --- /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 0000000000000..45d8c60382b59 --- /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 617bf32f4639e..552a0e96ceb44 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 0dba5a71c502d..3cba9867600d6 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 53c3d084dbc98..27d4f1b03d77c 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 27d4f1b03d77c..d56079a4ab735 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 a05cb6270b762..3be792ce5e4fa 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 e34277d5af04c..1b17c2c278f9a 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 f4f2259cefd51..377f6d2244635 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 9f0284d5d9542..cc93f0fa5fc6f 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 cc93f0fa5fc6f..3f058124d2bde 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 99e371631b149..0cbe73affda32 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 fd0cd7a1890bd..a5c00b3418e5e 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 ec3b43c2f43bc..5ee157cf23b86 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 f542f9b02c17b..5b7252532c21c 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 cc175e8bf247f..4f25a86b2e4df 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 391952ea6b14f..eaa6a9af277d2 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 4a3eb9c983a11..383a62da821e9 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 0cbe73affda32..cf4aa39e49b90 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 a5c00b3418e5e..f83861950f8c7 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 5b7252532c21c..15aeaf907dc6b 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 f83861950f8c7..7509d90c6c2fc 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 d1dfe36ffd825..0bd13320dc952 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 a2984d7364169..62a8be0abf22c 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 c861efc8afb50..b8a4a20114bb8 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 5baa31d5cde0c..43cb2954b74b3 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 281037ae37c97..7a8cbd5251da9 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 0000000000000..a46c0e4d3f0a1 --- /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 341d9e601ee6f..fcf817b82c89e 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 0000000000000..ef1f1a14afcac --- /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 c8f153e7201cb..f6eadbdef0bb0 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 0000000000000..581c3242e3745 --- /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 82549c12d0a20..8b0229125738a 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 70efdaeb9c669..93b5d9e178c23 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 4df6827d77f94..d7043e7bd8f71 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) + } + + if input_visitor.abort() || output_visitor.abort() { + return false; + } - 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 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 a36fdca5d5de6..c54103b25c20e 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 3410341a1e3c5..61b63597b1633 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 065c7c042d367..b4b4b3dc18d51 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 e0651f9ab5d6c..c0824bacbc735 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 80da04fb7de9d..25245b3dbf08e 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 38bdd0f7ed23b..7687962bdd9bf 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 bb44eeb6adc51..7b662eae7753e 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 dfc158661cbf6..95594e38c9ec1 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 15b66684eab70..3783bd78de25e 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 a29a199b8c3aa..5e83b6c81ec8f 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 d8c57f0e7ae7f..93d59cc7fcd17 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 9b6a9075a2954..1307237dbc70a 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 9c5a12ea9c8e1..dd2fd0bb445fe 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 247effde19b9c..790ac4f7dd8aa 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 5e8800d38eb52..52d3c2c1daf09 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 be837a61dc07e..277da9d3f3a27 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 19d890b4554af..1b4f20342729a 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 fac63bcb99378..d9d60fffcd7ae 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 0000000000000..3507168a3a964 --- /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 21e0f6f4fc766..2869c3bf7d44b 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 c81e7f6e0692b..38959e2331b40 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 f6d529de9a3a2..ce3d0efab3aa7 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 3c385343f7010..a8f3e3145f64d 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 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 +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); } - }; -} + 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 697823712bf05..0e8f7683103d6 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 81af3d3033b23..48e0478f16992 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 0000000000000..a1f515e443dc5 --- /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 0000000000000..3d3f0729abd85 --- /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 0000000000000..ed91b5a6796d8 --- /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 6fbba01416a8d..103ec27e7d755 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 0000000000000..658cae397e149 --- /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 0000000000000..27b51166eacb8 --- /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 32685038067d6..8df6e19421ec5 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 4324984dd60eb..df4e9e20b649c 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 e6626d57a7722..de670cdfc31f1 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 05ffb55f6207e..3df8be6c23230 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 0000000000000..d055f17526b9b --- /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 0000000000000..537557f8b0af0 --- /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 4bb833795bb16..948deba3ea6e3 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 086548e58ed67..619d11cefc46d 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 c48c7e9e6c6ba..98588be9cf829 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 db1fa871afe00..dca32aa3b5615 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 15d0f705b367f..b0a3d11bce463 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 1ca6b6976b38f..81af88962a64d 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 837ec9df31ab1..96a8fe6c24d56 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 ffef1631775ee..45b3b1869dde6 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 ac19f1976e912..3f3986b6fc692 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 d832c2860332d..56024abc8f58d 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 9e5e299c336a5..f1a229f3f4faf 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 47f8e3b18eeaa..d44b0fae82001 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 0000000000000..0c2d48f938fcb --- /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 47324ce183169..8326e3663b054 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 c4f6c0fed6820..6b1ceb5056933 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 ffad2d06b56e2..fef4d7db84ddf 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 95c7dff9be36b..7d62e315da2fc 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 a548415da62bd..1253ddcfaeb3b 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 d0b44ebafeeb2..cdf018cbc88d8 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 cdb59caec67ed..2a4bc83f58a55 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 ead67d5ed1b1e..08b06961760ff 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 b06df83d51a5b..0cbceedbd6bdb 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 e02eb28ab8650..30e4b11ec0bd4 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 4ef992b05e761..2f913292995ea 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 3d4a88ab3c4e5..05696e3d7d56f 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 c4acd5cda1b0a..bb238c81ebc05 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 848f0ea52ca5e..94c939665e616 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 d8fbaa5414664..a238e7896fc6b 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 48507efe1e98b..4f61c76828db8 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 bd1fa4a0b1ef2..676564b2445d5 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 0000000000000..d68bbe7880213 --- /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 f79d9ab6460b8..c7468493380c8 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 3d5063d1a3a7d..a41bcb33b4460 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 f2153efc38800..8021ed4607dde 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 3a4bbe310ccaa..1ba7ac082132f 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 2bb95c18a3912..60105a8213feb 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 265017c51d924..6d2124c12fe98 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 c0a52d832c00a..07004489610d0 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 aa6ef162fe401..81d8221bd13e0 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 b75f10917df18..dd683e7f746a4 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 79ce38be19bd3..d5d27c853c28d 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 baee773573038..70cdb067d9138 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 6de447f40214b..729990af3998d 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 48a7ae904948c..b338b8aa6228d 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 0000000000000..a39d96109f17d --- /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 0000000000000..44a0e6ddeace6 --- /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 913cd004f19f4..d482d466e4499 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 d3a360ed8b576..c8a2e8b81c019 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 a82b115916190..7633316e0f877 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 5fb568672d356..2045ffdb5f09d 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 737b0f7e55bc7..522f31b72d01f 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 b8a436993f329..bc5978b538f16 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 0000000000000..997ebef8a6992 --- /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 9767e5bf76a85..f7f3b195ccc18 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 27db9594f3b33..1f596c312fe39 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 4575a132e5b2c..3fca463c620b5 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 ad0d0387db03c..b45b27d8f23b1 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 9746f6e6849dd..be2abe7f7014d 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 70c6cf0a3b631..50607933e18f7 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: 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 7 previous errors +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 259696658eaba..15f3d1f080604 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 f4f2259cefd51..c88dffc88f422 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 c88dffc88f422..0b324775b0d1a 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 a9a65a38c109d..784ab9e5c7078 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 784ab9e5c7078..87cdb7a8b99dd 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 0b324775b0d1a..bf9110b43492f 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 ff9b1553bf2fc..1560263684acb 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 cff8ff9ac7ad9..b7cc03f8eb999 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 46d8a3c4cb493..05cb3a2c03d79 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 d6541010bca23..26da058598e4f 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 306514769990d..740a22a07d747 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 9734492154e80..96df7f37f7792 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 062c9bd2d9e6c..c5e33b288a9c7 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 9fa0e5f5c079b..586784b73e697 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 f7c380fc915c0..bb4051c466201 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 0000000000000..f3966e47f5e80 --- /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 5e83b6c81ec8f..a982b92bb2b3f 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 dcfb9fd673421..9eb2dc84e0830 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 8a2dbdc50eaea..4525b12689fa7 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 a982b92bb2b3f..9a948af8bfc4e 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 0000000000000..9f73f39f10d79 --- /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 1b4f20342729a..7cb7d0a26b65e 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 3d4813209cbc4..511a5100ac625 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 ec4f3091d2da2..493c184313cb1 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 c08828bc0cde9..98d955efb2899 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 511a5100ac625..bd9a9023396b4 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 bd9a9023396b4..1bf142ec683d5 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 1bf142ec683d5..c3f88ada0f4bc 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 c3f88ada0f4bc..e9222f34b89b4 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 7b5fac922d08a..b4628b649117e 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 2869c3bf7d44b..344bb455aa539 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 50d42678734e9..2ab51168bcaa6 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 50d42678734e9..2ab51168bcaa6 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 2c13c327d7980..e16ed600ef814 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 1e07f8e2eac24..f81c6c3df76af 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 6fb6cf75d96fe..f21768c449880 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 50b39cf4ea7c0..212a310063707 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 097eca0af578c..26a727687b1d1 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 96c9d12d75fbb..d0fc8f0c8a907 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 445fc8d31d77a..f47b81a450ea9 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 f44d6693d303b..c7b616e289708 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 a48e675e4ea23..05e087b08bc14 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 bc37785294fca..8290ece1cad18 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 0000000000000..a66f581b2159f --- /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 0000000000000..986d9718acdbf --- /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 212a310063707..fd45a6da61ca6 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 986d9718acdbf..b8230032491b6 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 54ce0e7b831f4..c76f9b923cd0f 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 82ccab1462ba8..829d4c943f11b 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 4702e5c549228..0000000000000 --- 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 8eaf07e52d69a..af05310a8d3ab 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 e9222f34b89b4..e12c2f4e00c50 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 5bbc53945edc6..53062b9c20da8 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 eda7ddc4f6d3b..5fe967c4158fe 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 c76f9b923cd0f..a4bbb18da5983 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 501891da573a6..4bbf5edeaf348 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 0000000000000..6d50325fed550 --- /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 5e68f76693fcf..805e1085cf319 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 606bf94f99867..92cbce96054b8 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 0000000000000..73a0ca21f6733 --- /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 f3fa3634026fd..76c7b8f1253ca 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 549056570f9bc..423b1fab143bf 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 a9a7092994269..556b67e0b3742 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 377f6d2244635..c9b07855af10d 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 d0fc8f0c8a907..624223ff70620 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 c7a3099b8ab0a..13db35f4b0ef0 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 c9b07855af10d..e32ba116939b2 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 e32ba116939b2..e5d740cecd31c 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 3f058124d2bde..9e2d64a866fbb 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 9e2d64a866fbb..b27167a7e7c66 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 e16ec783fab79..7126c98a0b438 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 fc4afde9d9e6d..dd99b6b9040c9 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 3df8be6c23230..e369f62f8bfea 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 9c7590c7dd632..ff1dc76ab63b1 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 0000000000000..cf5660ea98da0 --- /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 0000000000000..9206e9026e95b --- /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 8e0243c49aaa0..d8bda7e8f48a7 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 38fb74372db18..2e070d7122442 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 ddb1aaebc1f3e..35adb4f69d854 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 a78da369c241b..60ac3524e6696 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 1e520b62f77c4..ba66ba2912f67 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 9f34aee1947cd..cd8ab11cb8426 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 16bee0e2eee18..465b427624ddd 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 813afcc0ec6e4..de671ec13d1e8 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 c9a80b5bc7722..ff2696bb0a4cc 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 38959e2331b40..f25edb793e26d 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 7126c98a0b438..a95d71042ee27 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 cf5660ea98da0..25e1c6ac6b75b 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 9206e9026e95b..1df094fae1802 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 9ebc991d638cb..cfb06827be40b 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 | 53 ++++++++---- src/librustdoc/html/static/storage.js | 72 +++++++++++++++-- 4 files changed, 232 insertions(+), 36 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 76334f0213d15..a9d4c2cc813df 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 7c91f6b7d18ed..4bacd7b245bbc 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 67dc77330eeca..00a01ac30bcfa 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 3ee693d6eacab..cf8b806501f36 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 10a64769585e5..6c969c3ead0f0 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 686867cf5c6f6..7f28f02579045 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 4646d4a833525..850451bb29e12 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 850451bb29e12..1ea34be71dd3b 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 b27167a7e7c66..633e96eb7d811 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 566ac0920dc8f..576cc24cc0f64 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 ba66ba2912f67..bf30dcb7689fa 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 98b4dfa9c749b..d90adecab7866 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 65a29076fefa8..38fd470a1c322 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 658369f79aa75..fbed3d32d451a 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 76334f0213d15..97d0a4d4e7dcd 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 0000000000000..aa48644918d9a --- /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 e12c2f4e00c50..f988a019cfedb 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 aa48644918d9a..90dafd8b3480d 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 a95d71042ee27..9653e62cad078 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 dd99b6b9040c9..fc4afde9d9e6d 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 272b0900a31c6..3ab4dfc439bca 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 5b80e6078eed7..21a63aec7a171 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 25e1c6ac6b75b..0000000000000 --- 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 1df094fae1802..0000000000000 --- 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 63de87128340f..549192c9d30fc 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 f01a7b72a6559..4ff12da883236 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 4ff12da883236..6bf71d28bb666 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 3abd9a6325d6e..51ec599493399 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 c9dec395580f1..9c144324f2f7e 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 884bb4d2e99b6..4fd9cabb3b0b2 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 1abf47c8af521..9eae7da90047e 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 6bf71d28bb666..eb054b081175d 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 eb054b081175d..8089d7a8ba6f1 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 4fa97ff053e60..6864cd06cb7bb 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 b2d343fd7af6a..eec3027085c91 100644 --- a/src/etc/gdb_providers.py +++ b/src/etc/gdb_providers.py @@ -229,8 +229,8 @@ def cast_to_internal(node): 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 @@ def to_string(self): 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 @@ def to_string(self): 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 c6d2090759ff2..cc2a3a345102a 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 c75adb62f2575..47c650ac27d4c 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 62a8be0abf22c..e1b3c84d6917d 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 87cdb7a8b99dd..a1b8e2ee162cf 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 3ab4dfc439bca..20613ac6afe96 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 | 46 +++++----- 12 files changed, 345 insertions(+), 76 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 f21768c449880..93ce6bb85d8a3 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 0000000000000..097aff4b1786d --- /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 26a727687b1d1..2e9900815d9ad 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 383a62da821e9..eb7624b25a3c9 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 6938d9971d96d..30e812c284b00 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 ea1dc3be29ba0..2fd6046ebcf5a 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 624223ff70620..6dc95fcfdb289 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 0000000000000..52b69ebba3ec5 --- /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 0000000000000..bb2a8f2050a93 --- /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 0000000000000..e3e8a406db104 --- /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 bd91ae4e9340c..e7441293d4572 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 8a831375b412d..7c1ad2949e91b 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 + --> $DIR/shadow.rs:28:5 | LL | let x = { x }; | ^^^^^^^^^^^^^^ | note: previous binding is here - --> $DIR/shadow.rs:26:9 + --> $DIR/shadow.rs:27:9 | LL | let x = &mut x; | ^ error: `x` is shadowed by itself in `(&*x)` - --> $DIR/shadow.rs:28:5 + --> $DIR/shadow.rs:29:5 | LL | let x = (&*x); | ^^^^^^^^^^^^^^ | note: previous binding is here - --> $DIR/shadow.rs:27:9 + --> $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 + --> $DIR/shadow.rs:31:9 | LL | let x = id(x); | ^ | note: initialization happens here - --> $DIR/shadow.rs:30:13 + --> $DIR/shadow.rs:31:13 | LL | let x = id(x); | ^^^^^ note: previous binding is here - --> $DIR/shadow.rs:29:9 + --> $DIR/shadow.rs:30:9 | LL | let x = { *x + 1 }; | ^ error: `x` is shadowed by `(1, x)` which reuses the original value - --> $DIR/shadow.rs:31:9 + --> $DIR/shadow.rs:32:9 | LL | let x = (1, x); | ^ | note: initialization happens here - --> $DIR/shadow.rs:31:13 + --> $DIR/shadow.rs:32:13 | LL | let x = (1, x); | ^^^^^^ note: previous binding is here - --> $DIR/shadow.rs:30:9 + --> $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:32:9 + --> $DIR/shadow.rs:33:9 | LL | let x = first(x); | ^ | note: initialization happens here - --> $DIR/shadow.rs:32:13 + --> $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 93ce6bb85d8a3..d82f970b8bf20 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 2e9900815d9ad..d4d2f92a6a695 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 097aff4b1786d..9d8fc863424c9 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 6dc95fcfdb289..debd3c31d8bff 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 52b69ebba3ec5..99d30360db1a1 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 bb2a8f2050a93..5d03d9db16392 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 e3e8a406db104..03da118a0c420 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 e7441293d4572..e366c75335c20 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 9d8fc863424c9..ced941fac1a48 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 99d30360db1a1..a9cc8678c9d17 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 03da118a0c420..8f6835ed78d29 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 ced941fac1a48..719a8b91f6690 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 719a8b91f6690..ddb8cc25077e1 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 debd3c31d8bff..6301d623a2b12 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 a9cc8678c9d17..a8736f1e6efe1 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 5d03d9db16392..bede8cffc326e 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 8f6835ed78d29..674f2952635f6 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 137a73630940a..6c92e10522c99 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 344bb455aa539..ab8ff7117967b 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 c0193e9fa0c4e..adc38a01a9dab 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 adc38a01a9dab..aeb926bca3e4c 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 f35c1016f86be..7236784853e16 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 aeb926bca3e4c..a5b2df1da5d6d 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 01652465eea2c..371c62c063fa7 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 97dd180b27b04..88424d449edc5 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 1f06d2dbe9144..d92eb86fb2eb6 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 79403cf86873e..706d563f8fba1 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 d0d88c01f5b2c..3b428eba13148 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 1844d3ae004f4..7c834f034c1f1 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 5e68f76693fcf..808adb5d47cc7 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 4f8aa246e5232..af1ce007e8b7c 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 e76e86f56510b..368aba6eae0d7 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 353189ae1f0d4..1e61f3ba2df07 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 64d456fb7aa67..bff263567bf6b 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 ccd294d92b2f4..ac3c99f9c908d 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 0000000000000..e54298eed059e --- /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 cf8b806501f36..a027d6845ea21 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 bee05e7738280..8ef99f36a04af 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 e1325b789d2e9..62a7649e2adf7 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 3c818f3ae48ea..cd128c1ea0b48 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 88d19943f0226..4da5305e6870f 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` + | ^ + | +note: the enum is defined here + --> $DIR/issue-73427.rs:14:1 | - = help: you might have meant to use one of the enum's other variants that have fields +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` + | ^ + | +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 | - = help: you might have meant to use the enum's other variant that has fields +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 77429f800f1a3..807dadf417bf5 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` + | ^ + | +note: the enum is defined here + --> $DIR/privacy-enum-ctor.rs:11:9 | - = help: you might have meant to use one of the enum's other variants that have fields +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` + | ^^^^^^^ + | +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 | - = help: you might have meant to use one of the enum's other variants that have fields +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 | 22 +++++++++---------- ...issue-43871-enum-instead-of-variant.stderr | 6 ++--- src/test/ui/issues/issue-73427.stderr | 4 ++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 8ef99f36a04af..c24b383f3b811 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1341,29 +1341,29 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let non_suggestable_variant_count = variants.len() - suggestable_variants.len(); + let source_msg = if source.is_call() { + "to construct" + } else if matches!(source, PathSource::TupleStruct(..)) { + "to match against" + } else { + unreachable!() + }; + if !suggestable_variants.is_empty() { let msg = if non_suggestable_variant_count == 0 && suggestable_variants.len() == 1 { - "try using the enum's variant" + format!("try {} the enum's variant", source_msg) } else { - "try using one of the enum's variants" + format!("try {} one of the enum's variants", source_msg) }; err.span_suggestions( span, - msg, + &msg, suggestable_variants.drain(..), Applicability::MaybeIncorrect, ); } - let source_msg = if source.is_call() { - "to construct" - } else if matches!(source, PathSource::TupleStruct(..)) { - "to match against" - } else { - unreachable!() - }; - // 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 62a7649e2adf7..bca493e67d543 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 4da5305e6870f..4b5f65b346174 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 3c5d47c81d78e..77a0125981b29 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 893fbb23688e9..a6dd47bd588c8 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 173d824d39083..2dd5e813d6fb7 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 633e96eb7d811..b73cd046e5a65 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 45904a524561b..23c7c4bcb354e 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 fccd1b96f60db..26d35f2620cb2 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 f1debee7a18f1..0b8ba7fbbedac 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 d4765f078b0e6..8c1bab8d0410d 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 d5a85b275db63..53ffd3373a51c 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 ce9c9491df3d7..f8e72cd330a31 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 6d09b4f02635b..c61c19cc7d1d1 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 2bfeb49b5fab7..3f7110b34cc67 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 16bee0e2eee18..2253648ac2e04 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 813afcc0ec6e4..4af61111128e9 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 9cb20a0afdc6e..825144e5a6fbe 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 13021738af139..6df4eb992594f 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 5dff73a94dd87..d40a27dddf362 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 0994cd2066246..e5d870c039dc1 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 4fe493a850d48..f213944e0ab67 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 79ab7776929c6..ca8169e69b479 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 12db56cdedbc2..79b397d72c557 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 1132a849e2f18..3f47c7bda6053 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 dd7582c21a727..0000000000000 --- 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 b4724be7c7c3b..0000000000000 --- 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 3f47c7bda6053..1763ed505473b 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 1763ed505473b..def23c70456b0 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 c90304c2b4a6a..0000000000000 --- 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 def23c70456b0..fee0a83e353c6 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 8f46f4d284f0b..0000000000000 --- 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 c74fc2b590316..d84742053524e 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 fee0a83e353c6..362c2a4cc02e1 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 7b58c83193bf3..0000000000000 --- 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 652219e28f6e0..fdf114d6df6fe 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 362c2a4cc02e1..142d70ebb5c10 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 24a2e0f965d28..0000000000000 --- 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 142d70ebb5c10..3b5f2f8561ff6 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 92e9f205b4e6e..0000000000000 --- 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 3b5f2f8561ff6..2ccdc80e403c6 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 2c5b94b1e61e5..0000000000000 --- 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 97a191d7232e0..0000000000000 --- 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 2ccdc80e403c6..ed82122e72741 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 ed82122e72741..c1e8bc79b6c30 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 76b34a6b5d84a..0000000000000 --- 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 68dc21b806c0f..0000000000000 --- 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 8b5a2d12af74f..0000000000000 --- 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 8fa9bd9d1e27f..0000000000000 --- 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 3ffa5be1b3bf1..0000000000000 --- 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 1f134f4e2d1bd..0000000000000 --- 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 c1e8bc79b6c30..1354c0802e85e 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 011325fddc5b9..74c7db27226ef 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 1354c0802e85e..27e53fa9854c0 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 7613fbec46f39..0000000000000 --- 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 e7c6e348f8e5a..0000000000000 --- 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 928100c92ffad..0000000000000 --- 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 27e53fa9854c0..9853eb3bf3dc3 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 f7c3f16371818..6967647249390 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 30cf7a707c7af..0000000000000 --- 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 9853eb3bf3dc3..f4a811074ca25 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 f327b69fc7541..0000000000000 --- 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 f4a811074ca25..2d25efbd7e335 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 5a7e5bcaa7600..77e6238ca1f52 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 29a0af5645ee1..cb41ddfe2a9bf 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 4b9f4ceb29c49..66bbc1c585413 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 2224a055d6d87..d3a279a23553e 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 8184c25afcfb8..819e8ef18415b 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 d58468ad539ff..0000000000000 --- 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 cb761af1a25c2..0000000000000 --- 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 0f68ebf8da9cc..0000000000000 --- 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 2d25efbd7e335..fb90f4b0c1acb 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 2392238d0a194..d5e14bec76572 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 fb90f4b0c1acb..c20edaa1a4778 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 6eaec6f1e50df..0000000000000 --- 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 840a7ae042625..0000000000000 --- 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 a18376212af51..0000000000000 --- 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 82527c40e9138..3615a8a5ee8b0 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 9ddd4ad4000ef..4b29b7020eb85 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 5e55f97705db6..b5be92e3eae00 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 c59782ff44b0b..dc6130eaa24a8 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 6473a0c3cec41..0000000000000 --- 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 f7e84ae3de9c7..69adbcdddc971 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 d2a322e1223c6..71a30d1c33d4f 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 d92eb86fb2eb6..e90ea0fc200a9 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 6bba00ee85e14..37d6fab070b8e 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 d3598ccfce81f..dc67d903a1dcc 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 1378b0d57053e..c9497f2a5b2b0 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 b9a5db478552e..3d8653b4a6a47 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 e66b432ede20c..99ebe84cd9d83 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 4835d9ab10723..ebc0883370b7d 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 ada61bf0df04c..6d0cd101dbc80 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 ef4d1b360b83c..5a9965db5ed47 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 228744326f947..854e29385a81b 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 9ee0e6f681dcc..f5f9631c3bcf9 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 3a123ea1c9398..ed973871b3f06 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 f819faa278995..eac2461753355 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 3b1eb9e1dfa16..81e557d53a660 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 ea233a47a78c1..cb46fc5ec467d 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 4e781318329bf..f48562094a4bc 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 edd83a5116993..1340ae43cd6af 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 8318f96940e93..5c3f8d9089819 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 a875ff660f979..0f47bae7f0fed 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 8126980604aab..753a9f74d03e4 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 7a59f539c37e7..e18f457a8b6f5 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 ac5808e4361eb..e689f8c27d772 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 c4d437c6cdd3a..0591d12d598ba 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 b2f7ae679fd68..db18a81c1f665 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 f1511b0a60180..215666bdd9d98 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 4df3ed502827e..9edf582751152 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 eb169c516d2a8..69837f31cab27 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 a43a505086569..977d12f108602 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 59282bec59b84..bc58c5995cb80 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 8234beb74a826..399ed9ae458b8 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 ceb35d94656bb..9cde44c06bd47 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 8535cbd019ce8..10f0c467560f4 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 e020dab63f8f4..b50d9e1750657 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 97f27566eb0f4..737a95b603b2a 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 92c4f2ccfe8a0..bca3be56ba5f5 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 5224672adb28b..30e7a7f3c3b10 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 c7a3099b8ab0a..e67aba19b7e8a 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 fcf817b82c89e..cd9363a857243 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 1b3eb2011afdc..67e50bba1f2e0 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 1560263684acb..6ba0a463da462 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 0608c4e32e00b..b43ae9a46af33 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!( - "
\ -