diff --git a/Cargo.lock b/Cargo.lock index 905f523aa53d6..5309c03ee23ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -94,6 +94,12 @@ dependencies = [ "nodrop", ] +[[package]] +name = "arrayvec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" + [[package]] name = "atty" version = "0.2.14" @@ -164,7 +170,7 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" dependencies = [ - "arrayvec", + "arrayvec 0.4.7", "constant_time_eq", ] @@ -714,7 +720,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" dependencies = [ - "arrayvec", + "arrayvec 0.4.7", "cfg-if", "crossbeam-utils 0.6.5", "lazy_static", @@ -3494,8 +3500,8 @@ dependencies = [ name = "rustc_index" version = "0.0.0" dependencies = [ + "arrayvec 0.5.1", "rustc_serialize", - "smallvec 1.4.0", ] [[package]] @@ -3996,6 +4002,7 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_hir", + "rustc_hir_pretty", "rustc_index", "rustc_infer", "rustc_middle", diff --git a/RELEASES.md b/RELEASES.md index 006682f505936..977796c66132e 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,166 @@ +Version 1.45.0 (2020-07-16) +========================== + +Language +-------- +- [Out of range float to int conversions using `as` has been defined as a saturating + conversion.][71269] This was previously undefined behaviour, but you can use the + `{f64, f32}::to_int_unchecked` methods to continue using the current behaviour, which + may be desirable in rare performance sensitive situations. +- [`mem::Discriminant` now uses `T`'s discriminant type instead of always + using `u64`.][70705] +- [Function like procedural macros can now be used in expression, pattern, and statement + positions.][68717] This means you can now use a function-like procedural macro + anywhere you can use a declarative (`macro_rules!`) macro. + +Compiler +-------- +- [You can now override individual target features through the `target-feature` + flag.][72094] E.g. `-C target-feature=+avx2 -C target-feature=+fma` is now + equivalent to `-C target-feature=+avx2,+fma`. +- [Added the `force-unwind-tables` flag.][69984] This option allows + rustc to always generate unwind tables regardless of panic strategy. +- [Added the `embed-bitcode` flag.][71716] This codegen flag allows rustc + to include LLVM bitcode into generated `rlib`s (this is on by default). +- [Added the `tiny` value to the `code-model` codegen flag.][72397] +- [Added tier 3 support\* for the `mipsel-sony-psp` target.][72062] +- [Added tier 3 support for the `thumbv7a-uwp-windows-msvc` target.][72133] + +\* Refer to Rust's [platform support page][forge-platform-support] for more +information on Rust's tiered platform support. + + +Libraries +--------- +- [`net::{SocketAddr, SocketAddrV4, SocketAddrV6}` now implements `PartialOrd` + and `Ord`.][72239] +- [`proc_macro::TokenStream` now implements `Default`.][72234] +- [You can now use `char` with + `ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo}` to iterate over + a range of codepoints.][72413] E.g. + you can now write the following; + ```rust + for ch in 'a'..='z' { + print!("{}", ch); + } + println!(); + // Prints "abcdefghijklmnopqrstuvwxyz" + ``` +- [`OsString` now implements `FromStr`.][71662] +- [The `saturating_neg` method as been added to all signed integer primitive + types, and the `saturating_abs` method has been added for all integer + primitive types.][71886] +- [`Arc`, `Rc` now implement `From>`, and `Box` now + implements `From` when `T` is `[T: Copy]`, `str`, `CStr`, `OsStr`, + or `Path`.][71447] +- [`Box<[T]>` now implements `From<[T; N]>`.][71095] +- [`BitOr` and `BitOrAssign` are implemented for all `NonZero` + integer types.][69813] +- [The `fetch_min`, and `fetch_max` methods have been added to all atomic + integer types.][72324] +- [The `fetch_update` method has been added to all atomic integer types.][71843] + +Stabilized APIs +--------------- +- [`Arc::as_ptr`] +- [`BTreeMap::remove_entry`] +- [`Rc::as_ptr`] +- [`rc::Weak::as_ptr`] +- [`rc::Weak::from_raw`] +- [`rc::Weak::into_raw`] +- [`str::strip_prefix`] +- [`str::strip_suffix`] +- [`sync::Weak::as_ptr`] +- [`sync::Weak::from_raw`] +- [`sync::Weak::into_raw`] +- [`char::UNICODE_VERSION`] +- [`Span::resolved_at`] +- [`Span::located_at`] +- [`Span::mixed_site`] +- [`unix::process::CommandExt::arg0`] + +Cargo +----- + +Misc +---- +- [Rustdoc now supports strikethrough text in Markdown.][71928] E.g. + `~~outdated information~~` becomes "~~outdated information~~". +- [Added an emoji to Rustdoc's deprecated API message.][72014] + +Compatibility Notes +------------------- +- [Trying to self initialize a static value (that is creating a value using + itself) is unsound and now causes a compile error.][71140] +- [`{f32, f64}::powi` now returns a slightly different value on Windows.][73420] + This is due to changes in LLVM's intrinsics which `{f32, f64}::powi` uses. +- [Rustdoc's CLI's extra error exit codes have been removed.][71900] These were + previously undocumented and not intended for public use. Rustdoc still provides + a non-zero exit code on errors. + +Internals Only +-------------- +- [Make clippy a git subtree instead of a git submodule][70655] +- [Unify the undo log of all snapshot types][69464] + +[73420]: https://github.com/rust-lang/rust/issues/73420/ +[72324]: https://github.com/rust-lang/rust/pull/72324/ +[71843]: https://github.com/rust-lang/rust/pull/71843/ +[71886]: https://github.com/rust-lang/rust/pull/71886/ +[72234]: https://github.com/rust-lang/rust/pull/72234/ +[72239]: https://github.com/rust-lang/rust/pull/72239/ +[72397]: https://github.com/rust-lang/rust/pull/72397/ +[72413]: https://github.com/rust-lang/rust/pull/72413/ +[72014]: https://github.com/rust-lang/rust/pull/72014/ +[72062]: https://github.com/rust-lang/rust/pull/72062/ +[72094]: https://github.com/rust-lang/rust/pull/72094/ +[72133]: https://github.com/rust-lang/rust/pull/72133/ +[71900]: https://github.com/rust-lang/rust/pull/71900/ +[71928]: https://github.com/rust-lang/rust/pull/71928/ +[71662]: https://github.com/rust-lang/rust/pull/71662/ +[71716]: https://github.com/rust-lang/rust/pull/71716/ +[71447]: https://github.com/rust-lang/rust/pull/71447/ +[71269]: https://github.com/rust-lang/rust/pull/71269/ +[71095]: https://github.com/rust-lang/rust/pull/71095/ +[71140]: https://github.com/rust-lang/rust/pull/71140/ +[70655]: https://github.com/rust-lang/rust/pull/70655/ +[70705]: https://github.com/rust-lang/rust/pull/70705/ +[69984]: https://github.com/rust-lang/rust/pull/69984/ +[69813]: https://github.com/rust-lang/rust/pull/69813/ +[69464]: https://github.com/rust-lang/rust/pull/69464/ +[68717]: https://github.com/rust-lang/rust/pull/68717/ +[`Arc::as_ptr`]: https://doc.rust-lang.org/stable/std/sync/struct.Arc.html#method.as_ptr +[`BTreeMap::remove_entry`]: https://doc.rust-lang.org/stable/std/collections/struct.BTreeMap.html#method.remove_entry +[`Rc::as_ptr`]: https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.as_ptr +[`rc::Weak::as_ptr`]: https://doc.rust-lang.org/stable/std/rc/struct.Weak.html#method.as_ptr +[`rc::Weak::from_raw`]: https://doc.rust-lang.org/stable/std/rc/struct.Weak.html#method.from_raw +[`rc::Weak::into_raw`]: https://doc.rust-lang.org/stable/std/rc/struct.Weak.html#method.into_raw +[`sync::Weak::as_ptr`]: https://doc.rust-lang.org/stable/std/sync/struct.Weak.html#method.as_ptr +[`sync::Weak::from_raw`]: https://doc.rust-lang.org/stable/std/sync/struct.Weak.html#method.from_raw +[`sync::Weak::into_raw`]: https://doc.rust-lang.org/stable/std/sync/struct.Weak.html#method.into_raw +[`str::strip_prefix`]: https://doc.rust-lang.org/stable/std/primitive.str.html#method.strip_prefix +[`str::strip_suffix`]: https://doc.rust-lang.org/stable/std/primitive.str.html#method.strip_suffix +[`char::UNICODE_VERSION`]: https://doc.rust-lang.org/stable/std/char/constant.UNICODE_VERSION.html +[`Span::resolved_at`]: https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.resolved_at +[`Span::located_at`]: https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.located_at +[`Span::mixed_site`]: https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.mixed_site +[`unix::process::CommandExt::arg0`]: https://doc.rust-lang.org/std/os/unix/process/trait.CommandExt.html#tymethod.arg0 + + +Version 1.44.1 (2020-06-18) +=========================== + +* [rustfmt accepts rustfmt_skip in cfg_attr again.][73078] +* [Don't hash executable filenames on apple platforms, fixing backtraces.][cargo/8329] +* [Fix crashes when finding backtrace on macOS.][71397] +* [Clippy applies lint levels into different files.][clippy/5356] + +[71397]: https://github.com/rust-lang/rust/issues/71397 +[73078]: https://github.com/rust-lang/rust/issues/73078 +[cargo/8329]: https://github.com/rust-lang/cargo/pull/8329 +[clippy/5356]: https://github.com/rust-lang/rust-clippy/issues/5356 + + Version 1.44.0 (2020-06-04) ========================== diff --git a/config.toml.example b/config.toml.example index 79e4e46d85ba3..01952b21ba4b1 100644 --- a/config.toml.example +++ b/config.toml.example @@ -391,8 +391,7 @@ # desired in distributions, for example. #rpath = true -# Emits extraneous output from tests to ensure that failures of the test -# harness are debuggable just from logfiles. +# Emits extra output from tests so test failures are debuggable just from logfiles. #verbose-tests = false # Flag indicating whether tests are compiled with optimizations (the -O flag). diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 3072a4a1ae7c0..fd36cd9bd8beb 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -76,6 +76,10 @@ fn main() { cmd.env("RUST_BACKTRACE", "1"); } + if let Ok(lint_flags) = env::var("RUSTC_LINT_FLAGS") { + cmd.args(lint_flags.split_whitespace()); + } + if target.is_some() { // The stage0 compiler has a special sysroot distinct from what we // actually downloaded, so we just always pass the `--sysroot` option, diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 3cbecbbaa06cb..557fb1aa550a5 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -1130,22 +1130,32 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_VERBOSE", self.verbosity.to_string()); if source_type == SourceType::InTree { + let mut lint_flags = Vec::new(); // When extending this list, add the new lints to the RUSTFLAGS of the // build_bootstrap function of src/bootstrap/bootstrap.py as well as // some code doesn't go through this `rustc` wrapper. - rustflags.arg("-Wrust_2018_idioms"); - rustflags.arg("-Wunused_lifetimes"); + lint_flags.push("-Wrust_2018_idioms"); + lint_flags.push("-Wunused_lifetimes"); if self.config.deny_warnings { - rustflags.arg("-Dwarnings"); + lint_flags.push("-Dwarnings"); } // FIXME(#58633) hide "unused attribute" errors in incremental // builds of the standard library, as the underlying checks are // not yet properly integrated with incremental recompilation. if mode == Mode::Std && compiler.stage == 0 && self.config.incremental { - rustflags.arg("-Aunused-attributes"); + lint_flags.push("-Aunused-attributes"); } + // This does not use RUSTFLAGS due to caching issues with Cargo. + // Clippy is treated as an "in tree" tool, but shares the same + // cache as other "submodule" tools. With these options set in + // RUSTFLAGS, that causes *every* shared dependency to be rebuilt. + // By injecting this into the rustc wrapper, this circumvents + // Cargo's fingerprint detection. This is fine because lint flags + // are always ignored in dependencies. Eventually this should be + // fixed via better support from Cargo. + cargo.env("RUSTC_LINT_FLAGS", lint_flags.join(" ")); } if let Mode::Rustc | Mode::Codegen = mode { diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index e8ec575ea3746..ca0b3ddc920ed 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -347,6 +347,11 @@ fn configure_cmake( // LLVM and LLD builds can produce a lot of those and hit CI limits on log size. cfg.define("CMAKE_INSTALL_MESSAGE", "LAZY"); + // Do not allow the user's value of DESTDIR to influence where + // LLVM will install itself. LLVM must always be installed in our + // own build directories. + cfg.env("DESTDIR", ""); + if builder.config.ninja { cfg.generator("Ninja"); } diff --git a/src/liballoc/task.rs b/src/liballoc/task.rs index 0d1cc99df47c5..252e04a410548 100644 --- a/src/liballoc/task.rs +++ b/src/liballoc/task.rs @@ -69,14 +69,13 @@ fn raw_waker(waker: Arc) -> RawWaker { // Wake by value, moving the Arc into the Wake::wake function unsafe fn wake(waker: *const ()) { - let waker: Arc = unsafe { Arc::from_raw(waker as *const W) }; + let waker = unsafe { Arc::from_raw(waker as *const W) }; ::wake(waker); } // Wake by reference, wrap the waker in ManuallyDrop to avoid dropping it unsafe fn wake_by_ref(waker: *const ()) { - let waker: ManuallyDrop> = - unsafe { ManuallyDrop::new(Arc::from_raw(waker as *const W)) }; + let waker = unsafe { ManuallyDrop::new(Arc::from_raw(waker as *const W)) }; ::wake_by_ref(&waker); } diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index ee53b6a13f837..9f55f378a5cc1 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -504,9 +504,6 @@ impl Iterator for ops::Range { fn next(&mut self) -> Option { if self.start < self.end { // SAFETY: just checked precondition - // We use the unchecked version here, because - // this helps LLVM vectorize loops for some ranges - // that don't get vectorized otherwise. let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) }; Some(mem::replace(&mut self.start, n)) } else { @@ -528,7 +525,8 @@ impl Iterator for ops::Range { fn nth(&mut self, n: usize) -> Option { if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) { if plus_n < self.end { - self.start = Step::forward(plus_n.clone(), 1); + // SAFETY: just checked precondition + self.start = unsafe { Step::forward_unchecked(plus_n.clone(), 1) }; return Some(plus_n); } } @@ -589,7 +587,8 @@ impl DoubleEndedIterator for ops::Range { #[inline] fn next_back(&mut self) -> Option { if self.start < self.end { - self.end = Step::backward(self.end.clone(), 1); + // SAFETY: just checked precondition + self.end = unsafe { Step::backward_unchecked(self.end.clone(), 1) }; Some(self.end.clone()) } else { None @@ -600,7 +599,8 @@ impl DoubleEndedIterator for ops::Range { fn nth_back(&mut self, n: usize) -> Option { if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) { if minus_n > self.start { - self.end = Step::backward(minus_n, 1); + // SAFETY: just checked precondition + self.end = unsafe { Step::backward_unchecked(minus_n, 1) }; return Some(self.end.clone()); } } @@ -657,9 +657,6 @@ impl Iterator for ops::RangeInclusive { let is_iterating = self.start < self.end; Some(if is_iterating { // SAFETY: just checked precondition - // We use the unchecked version here, because - // otherwise `for _ in '\0'..=char::MAX` - // does not successfully remove panicking code. let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) }; mem::replace(&mut self.start, n) } else { @@ -722,7 +719,8 @@ impl Iterator for ops::RangeInclusive { let mut accum = init; while self.start < self.end { - let n = Step::forward(self.start.clone(), 1); + // SAFETY: just checked precondition + let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) }; let n = mem::replace(&mut self.start, n); accum = f(accum, n)?; } @@ -775,7 +773,8 @@ impl DoubleEndedIterator for ops::RangeInclusive { } let is_iterating = self.start < self.end; Some(if is_iterating { - let n = Step::backward(self.end.clone(), 1); + // SAFETY: just checked precondition + let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) }; mem::replace(&mut self.end, n) } else { self.exhausted = true; @@ -825,7 +824,8 @@ impl DoubleEndedIterator for ops::RangeInclusive { let mut accum = init; while self.start < self.end { - let n = Step::backward(self.end.clone(), 1); + // SAFETY: just checked precondition + let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) }; let n = mem::replace(&mut self.end, n); accum = f(accum, n)?; } diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 820c0a49e7f03..c7496c209bcb0 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -148,6 +148,7 @@ #![feature(associated_type_bounds)] #![feature(const_type_id)] #![feature(const_caller_location)] +#![feature(slice_ptr_get)] #![feature(no_niche)] // rust-lang/rust#68303 #![feature(unsafe_block_in_unsafe_fn)] #![deny(unsafe_op_in_unsafe_fn)] diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index fdcfae8530a3b..6ddd41a26f122 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -84,11 +84,8 @@ impl !Send for *mut T {} #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sized"] #[rustc_on_unimplemented( - on(parent_trait = "std::path::Path", label = "borrow the `Path` instead"), message = "the size for values of type `{Self}` cannot be known at compilation time", - label = "doesn't have a size known at compile-time", - note = "to learn more, visit " + label = "doesn't have a size known at compile-time" )] #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable #[rustc_specialization_trait] diff --git a/src/libcore/ptr/const_ptr.rs b/src/libcore/ptr/const_ptr.rs index d1d7a71523822..39d4aca636a05 100644 --- a/src/libcore/ptr/const_ptr.rs +++ b/src/libcore/ptr/const_ptr.rs @@ -2,6 +2,7 @@ use super::*; use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::intrinsics; use crate::mem; +use crate::slice::SliceIndex; #[lang = "const_ptr"] impl *const T { @@ -826,6 +827,55 @@ impl *const [T] { // Only `std` can make this guarantee. unsafe { Repr { rust: self }.raw }.len } + + /// Returns a raw pointer to the slice's buffer. + /// + /// This is equivalent to casting `self` to `*const T`, but more type-safe. + /// + /// # Examples + /// + /// ```rust + /// #![feature(slice_ptr_get)] + /// use std::ptr; + /// + /// let slice: *const [i8] = ptr::slice_from_raw_parts(ptr::null(), 3); + /// assert_eq!(slice.as_ptr(), 0 as *const i8); + /// ``` + #[inline] + #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")] + pub const fn as_ptr(self) -> *const T { + self as *const T + } + + /// Returns a raw pointer to an element or subslice, without doing bounds + /// checking. + /// + /// Calling this method with an out-of-bounds index or when `self` is not dereferencable + /// is *[undefined behavior]* even if the resulting pointer is not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_ptr_get)] + /// + /// let x = &[1, 2, 4] as *const [i32]; + /// + /// unsafe { + /// assert_eq!(x.get_unchecked(1), x.as_ptr().add(1)); + /// } + /// ``` + #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[inline] + pub unsafe fn get_unchecked(self, index: I) -> *const I::Output + where + I: SliceIndex<[T]>, + { + // SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds. + unsafe { index.get_unchecked(self) } + } } // Equality for pointers diff --git a/src/libcore/ptr/mut_ptr.rs b/src/libcore/ptr/mut_ptr.rs index 7d4b6339b511f..644465d7d17f8 100644 --- a/src/libcore/ptr/mut_ptr.rs +++ b/src/libcore/ptr/mut_ptr.rs @@ -1,6 +1,7 @@ use super::*; use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::intrinsics; +use crate::slice::SliceIndex; #[lang = "mut_ptr"] impl *mut T { @@ -1014,7 +1015,6 @@ impl *mut [T] { /// /// ```rust /// #![feature(slice_ptr_len)] - /// /// use std::ptr; /// /// let slice: *mut [i8] = ptr::slice_from_raw_parts_mut(ptr::null_mut(), 3); @@ -1028,6 +1028,55 @@ impl *mut [T] { // Only `std` can make this guarantee. unsafe { Repr { rust_mut: self }.raw }.len } + + /// Returns a raw pointer to the slice's buffer. + /// + /// This is equivalent to casting `self` to `*mut T`, but more type-safe. + /// + /// # Examples + /// + /// ```rust + /// #![feature(slice_ptr_get)] + /// use std::ptr; + /// + /// let slice: *mut [i8] = ptr::slice_from_raw_parts_mut(ptr::null_mut(), 3); + /// assert_eq!(slice.as_mut_ptr(), 0 as *mut i8); + /// ``` + #[inline] + #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")] + pub const fn as_mut_ptr(self) -> *mut T { + self as *mut T + } + + /// Returns a raw pointer to an element or subslice, without doing bounds + /// checking. + /// + /// Calling this method with an out-of-bounds index or when `self` is not dereferencable + /// is *[undefined behavior]* even if the resulting pointer is not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_ptr_get)] + /// + /// let x = &mut [1, 2, 4] as *mut [i32]; + /// + /// unsafe { + /// assert_eq!(x.get_unchecked_mut(1), x.as_mut_ptr().add(1)); + /// } + /// ``` + #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[inline] + pub unsafe fn get_unchecked_mut(self, index: I) -> *mut I::Output + where + I: SliceIndex<[T]>, + { + // SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds. + unsafe { index.get_unchecked_mut(self) } + } } // Equality for pointers diff --git a/src/libcore/ptr/non_null.rs b/src/libcore/ptr/non_null.rs index c2d31bfb6a4ee..b362a49d604e7 100644 --- a/src/libcore/ptr/non_null.rs +++ b/src/libcore/ptr/non_null.rs @@ -6,6 +6,7 @@ use crate::marker::Unsize; use crate::mem; use crate::ops::{CoerceUnsized, DispatchFromDyn}; use crate::ptr::Unique; +use crate::slice::SliceIndex; /// `*mut T` but non-zero and covariant. /// @@ -192,7 +193,6 @@ impl NonNull<[T]> { /// /// ```rust /// #![feature(slice_ptr_len, nonnull_slice_from_raw_parts)] - /// /// use std::ptr::NonNull; /// /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3); @@ -204,6 +204,57 @@ impl NonNull<[T]> { pub const fn len(self) -> usize { self.as_ptr().len() } + + /// Returns a non-null pointer to the slice's buffer. + /// + /// # Examples + /// + /// ```rust + /// #![feature(slice_ptr_get, nonnull_slice_from_raw_parts)] + /// use std::ptr::NonNull; + /// + /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3); + /// assert_eq!(slice.as_non_null_ptr(), NonNull::new(1 as *mut i8).unwrap()); + /// ``` + #[inline] + #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")] + pub const fn as_non_null_ptr(self) -> NonNull { + // SAFETY: We know `self` is non-null. + unsafe { NonNull::new_unchecked(self.as_ptr().as_mut_ptr()) } + } + + /// Returns a raw pointer to an element or subslice, without doing bounds + /// checking. + /// + /// Calling this method with an out-of-bounds index or when `self` is not dereferencable + /// is *[undefined behavior]* even if the resulting pointer is not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_ptr_get, nonnull_slice_from_raw_parts)] + /// use std::ptr::NonNull; + /// + /// let x = &mut [1, 2, 4]; + /// let x = NonNull::slice_from_raw_parts(NonNull::new(x.as_mut_ptr()).unwrap(), x.len()); + /// + /// unsafe { + /// assert_eq!(x.get_unchecked_mut(1).as_ptr(), x.as_non_null_ptr().as_ptr().add(1)); + /// } + /// ``` + #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[inline] + pub unsafe fn get_unchecked_mut(self, index: I) -> NonNull + where + I: SliceIndex<[T]>, + { + // SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds. + // As a consequence, the resulting pointer cannot be NULL. + unsafe { NonNull::new_unchecked(self.as_ptr().get_unchecked_mut(index)) } + } } #[stable(feature = "nonnull", since = "1.25.0")] diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index bed8495993f43..0e202bb7801cf 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -310,8 +310,10 @@ impl [T] { where I: SliceIndex, { - // SAFETY: the caller must uphold the safety requirements for `get_unchecked`. - unsafe { index.get_unchecked(self) } + // SAFETY: the caller must uphold most of the safety requirements for `get_unchecked`; + // the slice is dereferencable because `self` is a safe reference. + // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is. + unsafe { &*index.get_unchecked(self) } } /// Returns a mutable reference to an element or subslice, without doing @@ -342,8 +344,10 @@ impl [T] { where I: SliceIndex, { - // SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`. - unsafe { index.get_unchecked_mut(self) } + // SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`; + // the slice is dereferencable because `self` is a safe reference. + // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is. + unsafe { &mut *index.get_unchecked_mut(self) } } /// Returns a raw pointer to the slice's buffer. @@ -3010,6 +3014,9 @@ mod private_slice_index { } /// A helper trait used for indexing operations. +/// +/// Implementations of this trait have to promise that if the argument +/// to `get_(mut_)unchecked` is a safe reference, then so is the result. #[stable(feature = "slice_get_slice", since = "1.28.0")] #[rustc_on_unimplemented( on(T = "str", label = "string indices are ranges of `usize`",), @@ -3021,7 +3028,7 @@ see chapter in The Book : private_slice_index::Sealed { +pub unsafe trait SliceIndex: private_slice_index::Sealed { /// The output type returned by methods. #[stable(feature = "slice_get_slice", since = "1.28.0")] type Output: ?Sized; @@ -3038,21 +3045,21 @@ pub trait SliceIndex: private_slice_index::Sealed { /// Returns a shared reference to the output at this location, without /// performing any bounds checking. - /// Calling this method with an out-of-bounds index is *[undefined behavior]* - /// even if the resulting reference is not used. + /// Calling this method with an out-of-bounds index or a dangling `slice` pointer + /// is *[undefined behavior]* even if the resulting reference is not used. /// /// [undefined behavior]: ../../reference/behavior-considered-undefined.html #[unstable(feature = "slice_index_methods", issue = "none")] - unsafe fn get_unchecked(self, slice: &T) -> &Self::Output; + unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output; /// Returns a mutable reference to the output at this location, without /// performing any bounds checking. - /// Calling this method with an out-of-bounds index is *[undefined behavior]* - /// even if the resulting reference is not used. + /// Calling this method with an out-of-bounds index or a dangling `slice` pointer + /// is *[undefined behavior]* even if the resulting reference is not used. /// /// [undefined behavior]: ../../reference/behavior-considered-undefined.html #[unstable(feature = "slice_index_methods", issue = "none")] - unsafe fn get_unchecked_mut(self, slice: &mut T) -> &mut Self::Output; + unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output; /// Returns a shared reference to the output at this location, panicking /// if out of bounds. @@ -3068,33 +3075,32 @@ pub trait SliceIndex: private_slice_index::Sealed { } #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -impl SliceIndex<[T]> for usize { +unsafe impl SliceIndex<[T]> for usize { type Output = T; #[inline] fn get(self, slice: &[T]) -> Option<&T> { - if self < slice.len() { unsafe { Some(self.get_unchecked(slice)) } } else { None } + if self < slice.len() { unsafe { Some(&*self.get_unchecked(slice)) } } else { None } } #[inline] fn get_mut(self, slice: &mut [T]) -> Option<&mut T> { - if self < slice.len() { unsafe { Some(self.get_unchecked_mut(slice)) } } else { None } + if self < slice.len() { unsafe { Some(&mut *self.get_unchecked_mut(slice)) } } else { None } } #[inline] - unsafe fn get_unchecked(self, slice: &[T]) -> &T { - // SAFETY: `slice` cannot be longer than `isize::MAX` and - // the caller guarantees that `self` is in bounds of `slice` - // so `self` cannot overflow an `isize`, so the call to `add` is safe. - // The obtained pointer comes from a reference which is guaranteed - // to be valid. - unsafe { &*slice.as_ptr().add(self) } + unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { + // SAFETY: the caller guarantees that `slice` is not dangling, so it + // cannot be longer than `isize::MAX`. They also guarantee that + // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, + // so the call to `add` is safe. + unsafe { slice.as_ptr().add(self) } } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut T { + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T { // SAFETY: see comments for `get_unchecked` above. - unsafe { &mut *slice.as_mut_ptr().add(self) } + unsafe { slice.as_mut_ptr().add(self) } } #[inline] @@ -3111,7 +3117,7 @@ impl SliceIndex<[T]> for usize { } #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -impl SliceIndex<[T]> for ops::Range { +unsafe impl SliceIndex<[T]> for ops::Range { type Output = [T]; #[inline] @@ -3119,7 +3125,7 @@ impl SliceIndex<[T]> for ops::Range { if self.start > self.end || self.end > slice.len() { None } else { - unsafe { Some(self.get_unchecked(slice)) } + unsafe { Some(&*self.get_unchecked(slice)) } } } @@ -3128,24 +3134,25 @@ impl SliceIndex<[T]> for ops::Range { if self.start > self.end || self.end > slice.len() { None } else { - unsafe { Some(self.get_unchecked_mut(slice)) } + unsafe { Some(&mut *self.get_unchecked_mut(slice)) } } } #[inline] - unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { - // SAFETY: `slice` cannot be longer than `isize::MAX` and - // the caller guarantees that `self` is in bounds of `slice` - // so `self` cannot overflow an `isize`, so the call to `add` is safe. - // Also, since the caller guarantees that `self` is in bounds of `slice`, - // `from_raw_parts` will give a subslice of `slice` which is always safe. - unsafe { from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) } + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + // SAFETY: the caller guarantees that `slice` is not dangling, so it + // cannot be longer than `isize::MAX`. They also guarantee that + // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, + // so the call to `add` is safe. + unsafe { ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) } } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { // SAFETY: see comments for `get_unchecked` above. - unsafe { from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start) } + unsafe { + ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start) + } } #[inline] @@ -3155,7 +3162,7 @@ impl SliceIndex<[T]> for ops::Range { } else if self.end > slice.len() { slice_index_len_fail(self.end, slice.len()); } - unsafe { self.get_unchecked(slice) } + unsafe { &*self.get_unchecked(slice) } } #[inline] @@ -3165,12 +3172,12 @@ impl SliceIndex<[T]> for ops::Range { } else if self.end > slice.len() { slice_index_len_fail(self.end, slice.len()); } - unsafe { self.get_unchecked_mut(slice) } + unsafe { &mut *self.get_unchecked_mut(slice) } } } #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -impl SliceIndex<[T]> for ops::RangeTo { +unsafe impl SliceIndex<[T]> for ops::RangeTo { type Output = [T]; #[inline] @@ -3184,13 +3191,13 @@ impl SliceIndex<[T]> for ops::RangeTo { } #[inline] - unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. unsafe { (0..self.end).get_unchecked(slice) } } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. unsafe { (0..self.end).get_unchecked_mut(slice) } } @@ -3207,7 +3214,7 @@ impl SliceIndex<[T]> for ops::RangeTo { } #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -impl SliceIndex<[T]> for ops::RangeFrom { +unsafe impl SliceIndex<[T]> for ops::RangeFrom { type Output = [T]; #[inline] @@ -3221,13 +3228,13 @@ impl SliceIndex<[T]> for ops::RangeFrom { } #[inline] - unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. unsafe { (self.start..slice.len()).get_unchecked(slice) } } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. unsafe { (self.start..slice.len()).get_unchecked_mut(slice) } } @@ -3244,7 +3251,7 @@ impl SliceIndex<[T]> for ops::RangeFrom { } #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -impl SliceIndex<[T]> for ops::RangeFull { +unsafe impl SliceIndex<[T]> for ops::RangeFull { type Output = [T]; #[inline] @@ -3258,12 +3265,12 @@ impl SliceIndex<[T]> for ops::RangeFull { } #[inline] - unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { slice } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { slice } @@ -3279,7 +3286,7 @@ impl SliceIndex<[T]> for ops::RangeFull { } #[stable(feature = "inclusive_range", since = "1.26.0")] -impl SliceIndex<[T]> for ops::RangeInclusive { +unsafe impl SliceIndex<[T]> for ops::RangeInclusive { type Output = [T]; #[inline] @@ -3297,13 +3304,13 @@ impl SliceIndex<[T]> for ops::RangeInclusive { } #[inline] - unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) } } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) } } @@ -3326,7 +3333,7 @@ impl SliceIndex<[T]> for ops::RangeInclusive { } #[stable(feature = "inclusive_range", since = "1.26.0")] -impl SliceIndex<[T]> for ops::RangeToInclusive { +unsafe impl SliceIndex<[T]> for ops::RangeToInclusive { type Output = [T]; #[inline] @@ -3340,13 +3347,13 @@ impl SliceIndex<[T]> for ops::RangeToInclusive { } #[inline] - unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. unsafe { (0..=self.end).get_unchecked(slice) } } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. unsafe { (0..=self.end).get_unchecked_mut(slice) } } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 003ed7df36e2a..393911675c73e 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1731,7 +1731,8 @@ Section: Trait implementations mod traits { use crate::cmp::Ordering; use crate::ops; - use crate::slice::{self, SliceIndex}; + use crate::ptr; + use crate::slice::SliceIndex; /// Implements ordering of strings. /// @@ -1822,7 +1823,7 @@ mod traits { /// /// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] - impl SliceIndex for ops::RangeFull { + unsafe impl SliceIndex for ops::RangeFull { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -1833,11 +1834,11 @@ mod traits { Some(slice) } #[inline] - unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { slice } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { slice } #[inline] @@ -1886,7 +1887,7 @@ mod traits { /// // &s[3 .. 100]; /// ``` #[stable(feature = "str_checked_slicing", since = "1.20.0")] - impl SliceIndex for ops::Range { + unsafe impl SliceIndex for ops::Range { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -1894,8 +1895,10 @@ mod traits { && slice.is_char_boundary(self.start) && slice.is_char_boundary(self.end) { - // SAFETY: just checked that `start` and `end` are on a char boundary. - Some(unsafe { self.get_unchecked(slice) }) + // SAFETY: just checked that `start` and `end` are on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + // We also checked char boundaries, so this is valid UTF-8. + Some(unsafe { &*self.get_unchecked(slice) }) } else { None } @@ -1907,34 +1910,28 @@ mod traits { && slice.is_char_boundary(self.end) { // SAFETY: just checked that `start` and `end` are on a char boundary. - Some(unsafe { self.get_unchecked_mut(slice) }) + // We know the pointer is unique because we got it from `slice`. + Some(unsafe { &mut *self.get_unchecked_mut(slice) }) } else { None } } #[inline] - unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { + let slice = slice as *const [u8]; // SAFETY: the caller guarantees that `self` is in bounds of `slice` // which satisfies all the conditions for `add`. let ptr = unsafe { slice.as_ptr().add(self.start) }; let len = self.end - self.start; - // SAFETY: as the caller guarantees that `self` is in bounds of `slice`, - // we can safely construct a subslice with `from_raw_parts` and use it - // since we return a shared thus immutable reference. - // The call to `from_utf8_unchecked` is safe since the data comes from - // a `str` which is guaranteed to be valid utf8, since the caller - // must guarantee that `self.start` and `self.end` are char boundaries. - unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) } + ptr::slice_from_raw_parts(ptr, len) as *const str } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { + let slice = slice as *mut [u8]; // SAFETY: see comments for `get_unchecked`. let ptr = unsafe { slice.as_mut_ptr().add(self.start) }; let len = self.end - self.start; - // SAFETY: mostly identical to the comments for `get_unchecked`, except that we - // can return a mutable reference since the caller passed a mutable reference - // and is thus guaranteed to have exclusive write access to `slice`. - unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len)) } + ptr::slice_from_raw_parts_mut(ptr, len) as *mut str } #[inline] fn index(self, slice: &str) -> &Self::Output { @@ -1949,8 +1946,9 @@ mod traits { && slice.is_char_boundary(self.start) && slice.is_char_boundary(self.end) { - // SAFETY: just checked that `start` and `end` are on a char boundary. - unsafe { self.get_unchecked_mut(slice) } + // SAFETY: just checked that `start` and `end` are on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + unsafe { &mut *self.get_unchecked_mut(slice) } } else { super::slice_error_fail(slice, self.start, self.end) } @@ -1973,13 +1971,14 @@ mod traits { /// Panics if `end` does not point to the starting byte offset of a /// character (as defined by `is_char_boundary`), or if `end > len`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] - impl SliceIndex for ops::RangeTo { + unsafe impl SliceIndex for ops::RangeTo { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { if slice.is_char_boundary(self.end) { - // SAFETY: just checked that `end` is on a char boundary. - Some(unsafe { self.get_unchecked(slice) }) + // SAFETY: just checked that `end` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + Some(unsafe { &*self.get_unchecked(slice) }) } else { None } @@ -1987,30 +1986,24 @@ mod traits { #[inline] fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { if slice.is_char_boundary(self.end) { - // SAFETY: just checked that `end` is on a char boundary. - Some(unsafe { self.get_unchecked_mut(slice) }) + // SAFETY: just checked that `end` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + Some(unsafe { &mut *self.get_unchecked_mut(slice) }) } else { None } } #[inline] - unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { + let slice = slice as *const [u8]; let ptr = slice.as_ptr(); - // SAFETY: as the caller guarantees that `self` is in bounds of `slice`, - // we can safely construct a subslice with `from_raw_parts` and use it - // since we return a shared thus immutable reference. - // The call to `from_utf8_unchecked` is safe since the data comes from - // a `str` which is guaranteed to be valid utf8, since the caller - // must guarantee that `self.end` is a char boundary. - unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, self.end)) } + ptr::slice_from_raw_parts(ptr, self.end) as *const str } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { + let slice = slice as *mut [u8]; let ptr = slice.as_mut_ptr(); - // SAFETY: mostly identical to `get_unchecked`, except that we can safely - // return a mutable reference since the caller passed a mutable reference - // and is thus guaranteed to have exclusive write access to `slice`. - unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, self.end)) } + ptr::slice_from_raw_parts_mut(ptr, self.end) as *mut str } #[inline] fn index(self, slice: &str) -> &Self::Output { @@ -2020,8 +2013,9 @@ mod traits { #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { if slice.is_char_boundary(self.end) { - // SAFETY: just checked that `end` is on a char boundary. - unsafe { self.get_unchecked_mut(slice) } + // SAFETY: just checked that `end` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + unsafe { &mut *self.get_unchecked_mut(slice) } } else { super::slice_error_fail(slice, 0, self.end) } @@ -2045,13 +2039,14 @@ mod traits { /// Panics if `begin` does not point to the starting byte offset of /// a character (as defined by `is_char_boundary`), or if `begin >= len`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] - impl SliceIndex for ops::RangeFrom { + unsafe impl SliceIndex for ops::RangeFrom { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { if slice.is_char_boundary(self.start) { - // SAFETY: just checked that `start` is on a char boundary. - Some(unsafe { self.get_unchecked(slice) }) + // SAFETY: just checked that `start` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + Some(unsafe { &*self.get_unchecked(slice) }) } else { None } @@ -2059,35 +2054,29 @@ mod traits { #[inline] fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { if slice.is_char_boundary(self.start) { - // SAFETY: just checked that `start` is on a char boundary. - Some(unsafe { self.get_unchecked_mut(slice) }) + // SAFETY: just checked that `start` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + Some(unsafe { &mut *self.get_unchecked_mut(slice) }) } else { None } } #[inline] - unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { + let slice = slice as *const [u8]; // SAFETY: the caller guarantees that `self` is in bounds of `slice` // which satisfies all the conditions for `add`. let ptr = unsafe { slice.as_ptr().add(self.start) }; let len = slice.len() - self.start; - // SAFETY: as the caller guarantees that `self` is in bounds of `slice`, - // we can safely construct a subslice with `from_raw_parts` and use it - // since we return a shared thus immutable reference. - // The call to `from_utf8_unchecked` is safe since the data comes from - // a `str` which is guaranteed to be valid utf8, since the caller - // must guarantee that `self.start` is a char boundary. - unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) } + ptr::slice_from_raw_parts(ptr, len) as *const str } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { + let slice = slice as *mut [u8]; // SAFETY: identical to `get_unchecked`. let ptr = unsafe { slice.as_mut_ptr().add(self.start) }; let len = slice.len() - self.start; - // SAFETY: mostly identical to `get_unchecked`, except that we can safely - // return a mutable reference since the caller passed a mutable reference - // and is thus guaranteed to have exclusive write access to `slice`. - unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len)) } + ptr::slice_from_raw_parts_mut(ptr, len) as *mut str } #[inline] fn index(self, slice: &str) -> &Self::Output { @@ -2097,8 +2086,9 @@ mod traits { #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { if slice.is_char_boundary(self.start) { - // SAFETY: just checked that `start` is on a char boundary. - unsafe { self.get_unchecked_mut(slice) } + // SAFETY: just checked that `start` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + unsafe { &mut *self.get_unchecked_mut(slice) } } else { super::slice_error_fail(slice, self.start, slice.len()) } @@ -2122,7 +2112,7 @@ mod traits { /// to the ending byte offset of a character (`end + 1` is either a starting /// byte offset or equal to `len`), if `begin > end`, or if `end >= len`. #[stable(feature = "inclusive_range", since = "1.26.0")] - impl SliceIndex for ops::RangeInclusive { + unsafe impl SliceIndex for ops::RangeInclusive { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -2141,12 +2131,12 @@ mod traits { } } #[inline] - unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { // SAFETY: the caller must uphold the safety contract for `get_unchecked`. unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) } } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`. unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) } } @@ -2181,7 +2171,7 @@ mod traits { /// (`end + 1` is either a starting byte offset as defined by /// `is_char_boundary`, or equal to `len`), or if `end >= len`. #[stable(feature = "inclusive_range", since = "1.26.0")] - impl SliceIndex for ops::RangeToInclusive { + unsafe impl SliceIndex for ops::RangeToInclusive { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -2192,12 +2182,12 @@ mod traits { if self.end == usize::MAX { None } else { (..self.end + 1).get_mut(slice) } } #[inline] - unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { // SAFETY: the caller must uphold the safety contract for `get_unchecked`. unsafe { (..self.end + 1).get_unchecked(slice) } } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`. unsafe { (..self.end + 1).get_unchecked_mut(slice) } } @@ -2560,8 +2550,10 @@ impl str { #[stable(feature = "str_checked_slicing", since = "1.20.0")] #[inline] pub unsafe fn get_unchecked>(&self, i: I) -> &I::Output { - // SAFETY: the caller must uphold the safety contract for `get_unchecked`. - unsafe { i.get_unchecked(self) } + // SAFETY: the caller must uphold the safety contract for `get_unchecked`; + // the slice is dereferencable because `self` is a safe reference. + // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is. + unsafe { &*i.get_unchecked(self) } } /// Returns a mutable, unchecked subslice of `str`. @@ -2593,8 +2585,10 @@ impl str { #[stable(feature = "str_checked_slicing", since = "1.20.0")] #[inline] pub unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output { - // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`. - unsafe { i.get_unchecked_mut(self) } + // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`; + // the slice is dereferencable because `self` is a safe reference. + // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is. + unsafe { &mut *i.get_unchecked_mut(self) } } /// Creates a string slice from another string slice, bypassing safety @@ -2644,8 +2638,10 @@ impl str { #[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked(begin..end)` instead")] #[inline] pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str { - // SAFETY: the caller must uphold the safety contract for `get_unchecked`. - unsafe { (begin..end).get_unchecked(self) } + // SAFETY: the caller must uphold the safety contract for `get_unchecked`; + // the slice is dereferencable because `self` is a safe reference. + // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is. + unsafe { &*(begin..end).get_unchecked(self) } } /// Creates a string slice from another string slice, bypassing safety @@ -2676,8 +2672,10 @@ impl str { #[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked_mut(begin..end)` instead")] #[inline] pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { - // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`. - unsafe { (begin..end).get_unchecked_mut(self) } + // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`; + // the slice is dereferencable because `self` is a safe reference. + // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is. + unsafe { &mut *(begin..end).get_unchecked_mut(self) } } /// Divide one string slice into two at an index. @@ -3158,11 +3156,11 @@ impl str { /// Simple patterns: /// /// ``` - /// let s = "Löwe 老虎 Léopard"; + /// let s = "Löwe 老虎 Léopard Gepardi"; /// /// assert_eq!(s.find('L'), Some(0)); /// assert_eq!(s.find('é'), Some(14)); - /// assert_eq!(s.find("Léopard"), Some(13)); + /// assert_eq!(s.find("pard"), Some(17)); /// ``` /// /// More complex patterns using point-free style and closures: @@ -3190,8 +3188,8 @@ impl str { pat.into_searcher(self).next_match().map(|(i, _)| i) } - /// Returns the byte index of the last character of this string slice that - /// matches the pattern. + /// Returns the byte index for the first character of the rightmost match of the pattern in + /// this string slice. /// /// Returns [`None`] if the pattern doesn't match. /// @@ -3207,10 +3205,11 @@ impl str { /// Simple patterns: /// /// ``` - /// let s = "Löwe 老虎 Léopard"; + /// let s = "Löwe 老虎 Léopard Gepardi"; /// /// assert_eq!(s.rfind('L'), Some(13)); /// assert_eq!(s.rfind('é'), Some(14)); + /// assert_eq!(s.rfind("pard"), Some(24)); /// ``` /// /// More complex patterns with closures: diff --git a/src/librustc_ast/expand/allocator.rs b/src/librustc_ast/expand/allocator.rs index fbeeb47c23e9d..7c67f029f382d 100644 --- a/src/librustc_ast/expand/allocator.rs +++ b/src/librustc_ast/expand/allocator.rs @@ -9,7 +9,7 @@ pub enum AllocatorKind { } impl AllocatorKind { - pub fn fn_name(&self, base: &str) -> String { + pub fn fn_name(&self, base: Symbol) -> String { match *self { AllocatorKind::Global => format!("__rg_{}", base), AllocatorKind::Default => format!("__rdl_{}", base), @@ -26,29 +26,29 @@ pub enum AllocatorTy { } pub struct AllocatorMethod { - pub name: &'static str, + pub name: Symbol, pub inputs: &'static [AllocatorTy], pub output: AllocatorTy, } pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[ AllocatorMethod { - name: "alloc", + name: sym::alloc, inputs: &[AllocatorTy::Layout], output: AllocatorTy::ResultPtr, }, AllocatorMethod { - name: "dealloc", + name: sym::dealloc, inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout], output: AllocatorTy::Unit, }, AllocatorMethod { - name: "realloc", + name: sym::realloc, inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Usize], output: AllocatorTy::ResultPtr, }, AllocatorMethod { - name: "alloc_zeroed", + name: sym::alloc_zeroed, inputs: &[AllocatorTy::Layout], output: AllocatorTy::ResultPtr, }, @@ -70,7 +70,7 @@ pub fn global_allocator_spans(krate: &ast::Crate) -> Vec { } } - let name = Symbol::intern(&AllocatorKind::Global.fn_name("alloc")); + let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::alloc)); let mut f = Finder { name, spans: Vec::new() }; visit::walk_crate(&mut f, krate); f.spans diff --git a/src/librustc_ast/util/comments.rs b/src/librustc_ast/util/comments.rs index 9874754fcd2f7..39921b2022606 100644 --- a/src/librustc_ast/util/comments.rs +++ b/src/librustc_ast/util/comments.rs @@ -2,7 +2,7 @@ pub use CommentStyle::*; use crate::ast; use rustc_span::source_map::SourceMap; -use rustc_span::{BytePos, CharPos, FileName, Pos}; +use rustc_span::{BytePos, CharPos, FileName, Pos, Symbol}; use log::debug; @@ -52,7 +52,8 @@ pub fn is_doc_comment(s: &str) -> bool { || s.starts_with("/*!") } -pub fn doc_comment_style(comment: &str) -> ast::AttrStyle { +pub fn doc_comment_style(comment: Symbol) -> ast::AttrStyle { + let comment = &comment.as_str(); assert!(is_doc_comment(comment)); if comment.starts_with("//!") || comment.starts_with("/*!") { ast::AttrStyle::Inner @@ -61,7 +62,9 @@ pub fn doc_comment_style(comment: &str) -> ast::AttrStyle { } } -pub fn strip_doc_comment_decoration(comment: &str) -> String { +pub fn strip_doc_comment_decoration(comment: Symbol) -> String { + let comment = &comment.as_str(); + /// remove whitespace-only lines from the start/end of lines fn vertical_trim(lines: Vec) -> Vec { let mut i = 0; diff --git a/src/librustc_ast/util/comments/tests.rs b/src/librustc_ast/util/comments/tests.rs index f9cd69fb50d74..f08011fe4f862 100644 --- a/src/librustc_ast/util/comments/tests.rs +++ b/src/librustc_ast/util/comments/tests.rs @@ -1,47 +1,58 @@ use super::*; +use crate::with_default_session_globals; #[test] fn test_block_doc_comment_1() { - let comment = "/**\n * Test \n ** Test\n * Test\n*/"; - let stripped = strip_doc_comment_decoration(comment); - assert_eq!(stripped, " Test \n* Test\n Test"); + with_default_session_globals(|| { + let comment = "/**\n * Test \n ** Test\n * Test\n*/"; + let stripped = strip_doc_comment_decoration(Symbol::intern(comment)); + assert_eq!(stripped, " Test \n* Test\n Test"); + }) } #[test] fn test_block_doc_comment_2() { - let comment = "/**\n * Test\n * Test\n*/"; - let stripped = strip_doc_comment_decoration(comment); - assert_eq!(stripped, " Test\n Test"); + with_default_session_globals(|| { + let comment = "/**\n * Test\n * Test\n*/"; + let stripped = strip_doc_comment_decoration(Symbol::intern(comment)); + assert_eq!(stripped, " Test\n Test"); + }) } #[test] fn test_block_doc_comment_3() { - let comment = "/**\n let a: *i32;\n *a = 5;\n*/"; - let stripped = strip_doc_comment_decoration(comment); - assert_eq!(stripped, " let a: *i32;\n *a = 5;"); + with_default_session_globals(|| { + let comment = "/**\n let a: *i32;\n *a = 5;\n*/"; + let stripped = strip_doc_comment_decoration(Symbol::intern(comment)); + assert_eq!(stripped, " let a: *i32;\n *a = 5;"); + }) } #[test] fn test_block_doc_comment_4() { - let comment = "/*******************\n test\n *********************/"; - let stripped = strip_doc_comment_decoration(comment); - assert_eq!(stripped, " test"); + with_default_session_globals(|| { + let comment = "/*******************\n test\n *********************/"; + let stripped = strip_doc_comment_decoration(Symbol::intern(comment)); + assert_eq!(stripped, " test"); + }) } #[test] fn test_line_doc_comment() { - let stripped = strip_doc_comment_decoration("/// test"); - assert_eq!(stripped, " test"); - let stripped = strip_doc_comment_decoration("///! test"); - assert_eq!(stripped, " test"); - let stripped = strip_doc_comment_decoration("// test"); - assert_eq!(stripped, " test"); - let stripped = strip_doc_comment_decoration("// test"); - assert_eq!(stripped, " test"); - let stripped = strip_doc_comment_decoration("///test"); - assert_eq!(stripped, "test"); - let stripped = strip_doc_comment_decoration("///!test"); - assert_eq!(stripped, "test"); - let stripped = strip_doc_comment_decoration("//test"); - assert_eq!(stripped, "test"); + with_default_session_globals(|| { + let stripped = strip_doc_comment_decoration(Symbol::intern("/// test")); + assert_eq!(stripped, " test"); + let stripped = strip_doc_comment_decoration(Symbol::intern("///! test")); + assert_eq!(stripped, " test"); + let stripped = strip_doc_comment_decoration(Symbol::intern("// test")); + assert_eq!(stripped, " test"); + let stripped = strip_doc_comment_decoration(Symbol::intern("// test")); + assert_eq!(stripped, " test"); + let stripped = strip_doc_comment_decoration(Symbol::intern("///test")); + assert_eq!(stripped, "test"); + let stripped = strip_doc_comment_decoration(Symbol::intern("///!test")); + assert_eq!(stripped, "test"); + let stripped = strip_doc_comment_decoration(Symbol::intern("//test")); + assert_eq!(stripped, "test"); + }) } diff --git a/src/librustc_ast/util/lev_distance.rs b/src/librustc_ast/util/lev_distance.rs index cce86fed9891c..d4e0e3ba051c9 100644 --- a/src/librustc_ast/util/lev_distance.rs +++ b/src/librustc_ast/util/lev_distance.rs @@ -47,12 +47,13 @@ pub fn lev_distance(a: &str, b: &str) -> usize { /// a lower(upper)case letters mismatch. pub fn find_best_match_for_name<'a, T>( iter_names: T, - lookup: &str, + lookup: Symbol, dist: Option, ) -> Option where T: Iterator, { + let lookup = &lookup.as_str(); let max_dist = dist.map_or_else(|| cmp::max(lookup.len(), 3) / 3, |d| d); let name_vec: Vec<&Symbol> = iter_names.collect(); diff --git a/src/librustc_ast/util/lev_distance/tests.rs b/src/librustc_ast/util/lev_distance/tests.rs index e9b6c9759b644..94d56a3d7b4ae 100644 --- a/src/librustc_ast/util/lev_distance/tests.rs +++ b/src/librustc_ast/util/lev_distance/tests.rs @@ -25,31 +25,34 @@ fn test_find_best_match_for_name() { with_default_session_globals(|| { let input = vec![Symbol::intern("aaab"), Symbol::intern("aaabc")]; assert_eq!( - find_best_match_for_name(input.iter(), "aaaa", None), + find_best_match_for_name(input.iter(), Symbol::intern("aaaa"), None), Some(Symbol::intern("aaab")) ); - assert_eq!(find_best_match_for_name(input.iter(), "1111111111", None), None); + assert_eq!( + find_best_match_for_name(input.iter(), Symbol::intern("1111111111"), None), + None + ); let input = vec![Symbol::intern("aAAA")]; assert_eq!( - find_best_match_for_name(input.iter(), "AAAA", None), + find_best_match_for_name(input.iter(), Symbol::intern("AAAA"), None), Some(Symbol::intern("aAAA")) ); let input = vec![Symbol::intern("AAAA")]; // Returns None because `lev_distance > max_dist / 3` - assert_eq!(find_best_match_for_name(input.iter(), "aaaa", None), None); + assert_eq!(find_best_match_for_name(input.iter(), Symbol::intern("aaaa"), None), None); let input = vec![Symbol::intern("AAAA")]; assert_eq!( - find_best_match_for_name(input.iter(), "aaaa", Some(4)), + find_best_match_for_name(input.iter(), Symbol::intern("aaaa"), Some(4)), Some(Symbol::intern("AAAA")) ); let input = vec![Symbol::intern("a_longer_variable_name")]; assert_eq!( - find_best_match_for_name(input.iter(), "a_variable_longer_name", None), + find_best_match_for_name(input.iter(), Symbol::intern("a_variable_longer_name"), None), Some(Symbol::intern("a_longer_variable_name")) ); }) diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index 90a3a5ec64e0e..201972fcf264b 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -526,7 +526,7 @@ impl<'hir> LoweringContext<'_, 'hir> { Ident::with_dummy_span(sym::_task_context), hir::BindingAnnotation::Mutable, ); - let param = hir::Param { attrs: &[], hir_id: self.next_id(), pat, span }; + let param = hir::Param { attrs: &[], hir_id: self.next_id(), pat, ty_span: span, span }; let params = arena_vec![self; param]; let body_id = self.lower_body(move |this| { diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 00665c4cafb6b..dd5e658102fac 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -972,6 +972,7 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: self.lower_attrs(¶m.attrs), hir_id: self.lower_node_id(param.id), pat: self.lower_pat(¶m.pat), + ty_span: param.ty.span, span: param.span, } } @@ -1098,6 +1099,7 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: parameter.attrs, hir_id: parameter.hir_id, pat: new_parameter_pat, + ty_span: parameter.ty_span, span: parameter.span, }; diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 2d803262f79e1..b0edb1ca41d20 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -450,9 +450,20 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere fn print_comment(&mut self, cmnt: &comments::Comment) { match cmnt.style { comments::Mixed => { - assert_eq!(cmnt.lines.len(), 1); self.zerobreak(); - self.word(cmnt.lines[0].clone()); + if let Some((last, lines)) = cmnt.lines.split_last() { + self.ibox(0); + + for line in lines { + self.word(line.clone()); + self.hardbreak() + } + + self.word(last.clone()); + self.space(); + + self.end(); + } self.zerobreak() } comments::Isolated => { @@ -522,6 +533,10 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere self.word(st) } + fn print_symbol(&mut self, sym: Symbol, style: ast::StrStyle) { + self.print_string(&sym.as_str(), style); + } + fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) { self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true) } @@ -2050,7 +2065,7 @@ impl<'a> State<'a> { let print_reg_or_class = |s: &mut Self, r: &InlineAsmRegOrRegClass| match r { InlineAsmRegOrRegClass::Reg(r) => { - s.print_string(&r.as_str(), ast::StrStyle::Cooked) + s.print_symbol(*r, ast::StrStyle::Cooked) } InlineAsmRegOrRegClass::RegClass(r) => s.word(r.to_string()), }; @@ -2144,7 +2159,7 @@ impl<'a> State<'a> { ast::ExprKind::LlvmInlineAsm(ref a) => { self.s.word("llvm_asm!"); self.popen(); - self.print_string(&a.asm.as_str(), a.asm_str_style); + self.print_symbol(a.asm, a.asm_str_style); self.word_space(":"); self.commasep(Inconsistent, &a.outputs, |s, out| { @@ -2164,7 +2179,7 @@ impl<'a> State<'a> { self.word_space(":"); self.commasep(Inconsistent, &a.inputs, |s, &(co, ref o)| { - s.print_string(&co.as_str(), ast::StrStyle::Cooked); + s.print_symbol(co, ast::StrStyle::Cooked); s.popen(); s.print_expr(o); s.pclose(); @@ -2172,8 +2187,8 @@ impl<'a> State<'a> { self.s.space(); self.word_space(":"); - self.commasep(Inconsistent, &a.clobbers, |s, co| { - s.print_string(&co.as_str(), ast::StrStyle::Cooked); + self.commasep(Inconsistent, &a.clobbers, |s, &co| { + s.print_symbol(co, ast::StrStyle::Cooked); }); let mut options = vec![]; diff --git a/src/librustc_attr/builtin.rs b/src/librustc_attr/builtin.rs index af09779d072c3..0606fac2fe748 100644 --- a/src/librustc_attr/builtin.rs +++ b/src/librustc_attr/builtin.rs @@ -1041,10 +1041,10 @@ pub fn find_transparency( break; } else if let Some(value) = attr.value_str() { transparency = Some(( - match &*value.as_str() { - "transparent" => Transparency::Transparent, - "semitransparent" => Transparency::SemiTransparent, - "opaque" => Transparency::Opaque, + match value { + sym::transparent => Transparency::Transparent, + sym::semitransparent => Transparency::SemiTransparent, + sym::opaque => Transparency::Opaque, _ => { error = Some(TransparencyError::UnknownTransparency(value, attr.span)); continue; diff --git a/src/librustc_builtin_macros/deriving/clone.rs b/src/librustc_builtin_macros/deriving/clone.rs index 5dbf3825ce693..5a8648f2aaa4c 100644 --- a/src/librustc_builtin_macros/deriving/clone.rs +++ b/src/librustc_builtin_macros/deriving/clone.rs @@ -84,7 +84,7 @@ pub fn expand_deriving_clone( is_unsafe: false, supports_unions: true, methods: vec![MethodDef { - name: "clone", + name: sym::clone, generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), args: Vec::new(), diff --git a/src/librustc_builtin_macros/deriving/cmp/eq.rs b/src/librustc_builtin_macros/deriving/cmp/eq.rs index b3b15b897828a..e1677ae70ccab 100644 --- a/src/librustc_builtin_macros/deriving/cmp/eq.rs +++ b/src/librustc_builtin_macros/deriving/cmp/eq.rs @@ -28,7 +28,7 @@ pub fn expand_deriving_eq( is_unsafe: false, supports_unions: true, methods: vec![MethodDef { - name: "assert_receiver_is_total_eq", + name: sym::assert_receiver_is_total_eq, generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), args: vec![], diff --git a/src/librustc_builtin_macros/deriving/cmp/ord.rs b/src/librustc_builtin_macros/deriving/cmp/ord.rs index 030d2c837428b..a9bc03db8b706 100644 --- a/src/librustc_builtin_macros/deriving/cmp/ord.rs +++ b/src/librustc_builtin_macros/deriving/cmp/ord.rs @@ -26,7 +26,7 @@ pub fn expand_deriving_ord( is_unsafe: false, supports_unions: false, methods: vec![MethodDef { - name: "cmp", + name: sym::cmp, generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), args: vec![(borrowed_self(), "other")], diff --git a/src/librustc_builtin_macros/deriving/cmp/partial_eq.rs b/src/librustc_builtin_macros/deriving/cmp/partial_eq.rs index d3f1a9c15f49e..e7d8f78118098 100644 --- a/src/librustc_builtin_macros/deriving/cmp/partial_eq.rs +++ b/src/librustc_builtin_macros/deriving/cmp/partial_eq.rs @@ -92,9 +92,9 @@ pub fn expand_deriving_partial_eq( // avoid defining `ne` if we can // c-like enums, enums without any fields and structs without fields // can safely define only `eq`. - let mut methods = vec![md!("eq", cs_eq)]; + let mut methods = vec![md!(sym::eq, cs_eq)]; if !is_type_without_fields(item) { - methods.push(md!("ne", cs_ne)); + methods.push(md!(sym::ne, cs_ne)); } let trait_def = TraitDef { diff --git a/src/librustc_builtin_macros/deriving/cmp/partial_ord.rs b/src/librustc_builtin_macros/deriving/cmp/partial_ord.rs index f29f91e82312b..a3eb96fb782e5 100644 --- a/src/librustc_builtin_macros/deriving/cmp/partial_ord.rs +++ b/src/librustc_builtin_macros/deriving/cmp/partial_ord.rs @@ -49,7 +49,7 @@ pub fn expand_deriving_partial_ord( let attrs = vec![cx.attribute(inline)]; let partial_cmp_def = MethodDef { - name: "partial_cmp", + name: sym::partial_cmp, generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), args: vec![(borrowed_self(), "other")], @@ -70,10 +70,10 @@ pub fn expand_deriving_partial_ord( } else { vec![ partial_cmp_def, - md!("lt", true, false), - md!("le", true, true), - md!("gt", false, false), - md!("ge", false, true), + md!(sym::lt, true, false), + md!(sym::le, true, true), + md!(sym::gt, false, false), + md!(sym::ge, false, true), ] }; @@ -108,14 +108,14 @@ pub fn some_ordering_collapsed( ) -> P { let lft = cx.expr_ident(span, self_arg_tags[0]); let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1])); - let op_str = match op { - PartialCmpOp => "partial_cmp", - LtOp => "lt", - LeOp => "le", - GtOp => "gt", - GeOp => "ge", + let op_sym = match op { + PartialCmpOp => sym::partial_cmp, + LtOp => sym::lt, + LeOp => sym::le, + GtOp => sym::gt, + GeOp => sym::ge, }; - cx.expr_method_call(span, lft, cx.ident_of(op_str, span), vec![rgt]) + cx.expr_method_call(span, lft, Ident::new(op_sym, span), vec![rgt]) } pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P { diff --git a/src/librustc_builtin_macros/deriving/debug.rs b/src/librustc_builtin_macros/deriving/debug.rs index 99c2b6f8a4eac..6befeb746bd6d 100644 --- a/src/librustc_builtin_macros/deriving/debug.rs +++ b/src/librustc_builtin_macros/deriving/debug.rs @@ -29,7 +29,7 @@ pub fn expand_deriving_debug( is_unsafe: false, supports_unions: false, methods: vec![MethodDef { - name: "fmt", + name: sym::fmt, generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), args: vec![(fmtr, "f")], diff --git a/src/librustc_builtin_macros/deriving/decodable.rs b/src/librustc_builtin_macros/deriving/decodable.rs index 64a810bdcf687..0792be7326331 100644 --- a/src/librustc_builtin_macros/deriving/decodable.rs +++ b/src/librustc_builtin_macros/deriving/decodable.rs @@ -8,7 +8,7 @@ use rustc_ast::ast; use rustc_ast::ast::{Expr, MetaItem, Mutability}; use rustc_ast::ptr::P; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; pub fn expand_deriving_rustc_decodable( @@ -30,7 +30,7 @@ pub fn expand_deriving_rustc_decodable( is_unsafe: false, supports_unions: false, methods: vec![MethodDef { - name: "decode", + name: sym::decode, generics: LifetimeBounds { lifetimes: Vec::new(), bounds: vec![( diff --git a/src/librustc_builtin_macros/deriving/default.rs b/src/librustc_builtin_macros/deriving/default.rs index 27d5263320041..5dfb0e8f37c63 100644 --- a/src/librustc_builtin_macros/deriving/default.rs +++ b/src/librustc_builtin_macros/deriving/default.rs @@ -27,7 +27,7 @@ pub fn expand_deriving_default( is_unsafe: false, supports_unions: false, methods: vec![MethodDef { - name: "default", + name: kw::Default, generics: LifetimeBounds::empty(), explicit_self: None, args: Vec::new(), diff --git a/src/librustc_builtin_macros/deriving/encodable.rs b/src/librustc_builtin_macros/deriving/encodable.rs index 54926ec3fd502..4a90b7a193886 100644 --- a/src/librustc_builtin_macros/deriving/encodable.rs +++ b/src/librustc_builtin_macros/deriving/encodable.rs @@ -92,7 +92,7 @@ use crate::deriving::pathvec_std; use rustc_ast::ast::{Expr, ExprKind, MetaItem, Mutability}; use rustc_ast::ptr::P; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; pub fn expand_deriving_rustc_encodable( @@ -114,7 +114,7 @@ pub fn expand_deriving_rustc_encodable( is_unsafe: false, supports_unions: false, methods: vec![MethodDef { - name: "encode", + name: sym::encode, generics: LifetimeBounds { lifetimes: Vec::new(), bounds: vec![( diff --git a/src/librustc_builtin_macros/deriving/generic/mod.rs b/src/librustc_builtin_macros/deriving/generic/mod.rs index a9567f20d6925..050774aa24c96 100644 --- a/src/librustc_builtin_macros/deriving/generic/mod.rs +++ b/src/librustc_builtin_macros/deriving/generic/mod.rs @@ -226,7 +226,7 @@ pub struct TraitDef<'a> { pub struct MethodDef<'a> { /// name of the method - pub name: &'a str, + pub name: Symbol, /// List of generics, e.g., `R: rand::Rng` pub generics: LifetimeBounds<'a>, @@ -681,7 +681,7 @@ impl<'a> TraitDef<'a> { let opt_trait_ref = Some(trait_ref); let unused_qual = { let word = rustc_ast::attr::mk_nested_word_item(Ident::new( - Symbol::intern("unused_qualifications"), + sym::unused_qualifications, self.span, )); let list = rustc_ast::attr::mk_list_item(Ident::new(sym::allow, self.span), vec![word]); @@ -818,7 +818,7 @@ impl<'a> MethodDef<'a> { ) -> P { let substructure = Substructure { type_ident, - method_ident: cx.ident_of(self.name, trait_.span), + method_ident: Ident::new(self.name, trait_.span), self_args, nonself_args, fields, @@ -913,7 +913,7 @@ impl<'a> MethodDef<'a> { let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident); - let method_ident = cx.ident_of(self.name, trait_.span); + let method_ident = Ident::new(self.name, trait_.span); let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type)); let body_block = cx.block_expr(body); @@ -1315,7 +1315,7 @@ impl<'a> MethodDef<'a> { // Since we know that all the arguments will match if we reach // the match expression we add the unreachable intrinsics as the // result of the catch all which should help llvm in optimizing it - Some(deriving::call_intrinsic(cx, sp, "unreachable", vec![])) + Some(deriving::call_intrinsic(cx, sp, sym::unreachable, vec![])) } _ => None, }; @@ -1363,7 +1363,7 @@ impl<'a> MethodDef<'a> { for (&ident, self_arg) in vi_idents.iter().zip(&self_args) { let self_addr = cx.expr_addr_of(sp, self_arg.clone()); let variant_value = - deriving::call_intrinsic(cx, sp, "discriminant_value", vec![self_addr]); + deriving::call_intrinsic(cx, sp, sym::discriminant_value, vec![self_addr]); let let_stmt = cx.stmt_let(sp, false, ident, variant_value); index_let_stmts.push(let_stmt); @@ -1464,7 +1464,7 @@ impl<'a> MethodDef<'a> { // derive Debug on such a type could here generate code // that needs the feature gate enabled.) - deriving::call_intrinsic(cx, sp, "unreachable", vec![]) + deriving::call_intrinsic(cx, sp, sym::unreachable, vec![]) } else { // Final wrinkle: the self_args are expressions that deref // down to desired places, but we cannot actually deref diff --git a/src/librustc_builtin_macros/deriving/hash.rs b/src/librustc_builtin_macros/deriving/hash.rs index 8776e7ef50790..f975b75f0be13 100644 --- a/src/librustc_builtin_macros/deriving/hash.rs +++ b/src/librustc_builtin_macros/deriving/hash.rs @@ -29,7 +29,7 @@ pub fn expand_deriving_hash( is_unsafe: false, supports_unions: false, methods: vec![MethodDef { - name: "hash", + name: sym::hash, generics: LifetimeBounds { lifetimes: Vec::new(), bounds: vec![(typaram, vec![path_std!(cx, hash::Hasher)])], @@ -73,7 +73,7 @@ fn hash_substructure(cx: &mut ExtCtxt<'_>, trait_span: Span, substr: &Substructu let variant_value = deriving::call_intrinsic( cx, trait_span, - "discriminant_value", + sym::discriminant_value, vec![cx.expr_self(trait_span)], ); diff --git a/src/librustc_builtin_macros/deriving/mod.rs b/src/librustc_builtin_macros/deriving/mod.rs index dc21be3b296aa..6cee21fc6e69d 100644 --- a/src/librustc_builtin_macros/deriving/mod.rs +++ b/src/librustc_builtin_macros/deriving/mod.rs @@ -62,11 +62,11 @@ impl MultiItemModifier for BuiltinDerive { fn call_intrinsic( cx: &ExtCtxt<'_>, span: Span, - intrinsic: &str, + intrinsic: Symbol, args: Vec>, ) -> P { let span = cx.with_def_site_ctxt(span); - let path = cx.std_path(&[sym::intrinsics, Symbol::intern(intrinsic)]); + let path = cx.std_path(&[sym::intrinsics, intrinsic]); let call = cx.expr_call_global(span, path, args); cx.expr_block(P(ast::Block { diff --git a/src/librustc_builtin_macros/global_allocator.rs b/src/librustc_builtin_macros/global_allocator.rs index feda17c1812cb..f8a9a97b2a50e 100644 --- a/src/librustc_builtin_macros/global_allocator.rs +++ b/src/librustc_builtin_macros/global_allocator.rs @@ -79,12 +79,8 @@ impl AllocFnFactory<'_, '_> { self.cx.stmt_item(self.span, item) } - fn call_allocator(&self, method: &str, mut args: Vec>) -> P { - let method = self.cx.std_path(&[ - Symbol::intern("alloc"), - Symbol::intern("GlobalAlloc"), - Symbol::intern(method), - ]); + fn call_allocator(&self, method: Symbol, mut args: Vec>) -> P { + let method = self.cx.std_path(&[sym::alloc, sym::GlobalAlloc, method]); let method = self.cx.expr_path(self.cx.path(self.span, method)); let allocator = self.cx.path_ident(self.span, self.global); let allocator = self.cx.expr_path(allocator); @@ -115,11 +111,8 @@ impl AllocFnFactory<'_, '_> { args.push(self.cx.param(self.span, size, ty_usize.clone())); args.push(self.cx.param(self.span, align, ty_usize)); - let layout_new = self.cx.std_path(&[ - Symbol::intern("alloc"), - Symbol::intern("Layout"), - Symbol::intern("from_size_align_unchecked"), - ]); + let layout_new = + self.cx.std_path(&[sym::alloc, sym::Layout, sym::from_size_align_unchecked]); let layout_new = self.cx.expr_path(self.cx.path(self.span, layout_new)); let size = self.cx.expr_ident(self.span, size); let align = self.cx.expr_ident(self.span, align); diff --git a/src/librustc_builtin_macros/test_harness.rs b/src/librustc_builtin_macros/test_harness.rs index da8bf2b8b5169..98e42ebf46f2a 100644 --- a/src/librustc_builtin_macros/test_harness.rs +++ b/src/librustc_builtin_macros/test_harness.rs @@ -164,10 +164,8 @@ impl MutVisitor for EntryPointCleaner { EntryPointType::MainNamed | EntryPointType::MainAttr | EntryPointType::Start => item .map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| { let allow_ident = Ident::new(sym::allow, self.def_site); - let dc_nested = attr::mk_nested_word_item(Ident::from_str_and_span( - "dead_code", - self.def_site, - )); + let dc_nested = + attr::mk_nested_word_item(Ident::new(sym::dead_code, self.def_site)); let allow_dead_code_item = attr::mk_list_item(allow_ident, vec![dc_nested]); let allow_dead_code = attr::mk_attr_outer(allow_dead_code_item); let attrs = attrs diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs index 89b70dce52c66..6a38323f7ca9e 100644 --- a/src/librustc_codegen_llvm/builder.rs +++ b/src/librustc_codegen_llvm/builder.rs @@ -658,7 +658,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // `nontrapping-fptoint` target feature is activated. We'll use those if // they are available. if self.sess().target.target.arch == "wasm32" - && self.sess().target_features.contains(&sym::nontrapping_fptoint) + && self.sess().target_features.contains(&sym::nontrapping_dash_fptoint) { let src_ty = self.cx.val_ty(val); let float_width = self.cx.float_width(src_ty); @@ -683,7 +683,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // `nontrapping-fptoint` target feature is activated. We'll use those if // they are available. if self.sess().target.target.arch == "wasm32" - && self.sess().target_features.contains(&sym::nontrapping_fptoint) + && self.sess().target_features.contains(&sym::nontrapping_dash_fptoint) { let src_ty = self.cx.val_ty(val); let float_width = self.cx.float_width(src_ty); diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index de90ac0bac1d3..153f0232f3a6c 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -25,59 +25,59 @@ use rustc_middle::mir::Operand; use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt}; use rustc_middle::ty::{self, Ty}; use rustc_middle::{bug, span_bug}; -use rustc_span::Span; +use rustc_span::{sym, symbol::kw, Span, Symbol}; use rustc_target::abi::{self, HasDataLayout, LayoutOf, Primitive}; use rustc_target::spec::PanicStrategy; use std::cmp::Ordering; use std::iter; -fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: &str) -> Option<&'ll Value> { +fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: Symbol) -> Option<&'ll Value> { let llvm_name = match name { - "sqrtf32" => "llvm.sqrt.f32", - "sqrtf64" => "llvm.sqrt.f64", - "powif32" => "llvm.powi.f32", - "powif64" => "llvm.powi.f64", - "sinf32" => "llvm.sin.f32", - "sinf64" => "llvm.sin.f64", - "cosf32" => "llvm.cos.f32", - "cosf64" => "llvm.cos.f64", - "powf32" => "llvm.pow.f32", - "powf64" => "llvm.pow.f64", - "expf32" => "llvm.exp.f32", - "expf64" => "llvm.exp.f64", - "exp2f32" => "llvm.exp2.f32", - "exp2f64" => "llvm.exp2.f64", - "logf32" => "llvm.log.f32", - "logf64" => "llvm.log.f64", - "log10f32" => "llvm.log10.f32", - "log10f64" => "llvm.log10.f64", - "log2f32" => "llvm.log2.f32", - "log2f64" => "llvm.log2.f64", - "fmaf32" => "llvm.fma.f32", - "fmaf64" => "llvm.fma.f64", - "fabsf32" => "llvm.fabs.f32", - "fabsf64" => "llvm.fabs.f64", - "minnumf32" => "llvm.minnum.f32", - "minnumf64" => "llvm.minnum.f64", - "maxnumf32" => "llvm.maxnum.f32", - "maxnumf64" => "llvm.maxnum.f64", - "copysignf32" => "llvm.copysign.f32", - "copysignf64" => "llvm.copysign.f64", - "floorf32" => "llvm.floor.f32", - "floorf64" => "llvm.floor.f64", - "ceilf32" => "llvm.ceil.f32", - "ceilf64" => "llvm.ceil.f64", - "truncf32" => "llvm.trunc.f32", - "truncf64" => "llvm.trunc.f64", - "rintf32" => "llvm.rint.f32", - "rintf64" => "llvm.rint.f64", - "nearbyintf32" => "llvm.nearbyint.f32", - "nearbyintf64" => "llvm.nearbyint.f64", - "roundf32" => "llvm.round.f32", - "roundf64" => "llvm.round.f64", - "assume" => "llvm.assume", - "abort" => "llvm.trap", + sym::sqrtf32 => "llvm.sqrt.f32", + sym::sqrtf64 => "llvm.sqrt.f64", + sym::powif32 => "llvm.powi.f32", + sym::powif64 => "llvm.powi.f64", + sym::sinf32 => "llvm.sin.f32", + sym::sinf64 => "llvm.sin.f64", + sym::cosf32 => "llvm.cos.f32", + sym::cosf64 => "llvm.cos.f64", + sym::powf32 => "llvm.pow.f32", + sym::powf64 => "llvm.pow.f64", + sym::expf32 => "llvm.exp.f32", + sym::expf64 => "llvm.exp.f64", + sym::exp2f32 => "llvm.exp2.f32", + sym::exp2f64 => "llvm.exp2.f64", + sym::logf32 => "llvm.log.f32", + sym::logf64 => "llvm.log.f64", + sym::log10f32 => "llvm.log10.f32", + sym::log10f64 => "llvm.log10.f64", + sym::log2f32 => "llvm.log2.f32", + sym::log2f64 => "llvm.log2.f64", + sym::fmaf32 => "llvm.fma.f32", + sym::fmaf64 => "llvm.fma.f64", + sym::fabsf32 => "llvm.fabs.f32", + sym::fabsf64 => "llvm.fabs.f64", + sym::minnumf32 => "llvm.minnum.f32", + sym::minnumf64 => "llvm.minnum.f64", + sym::maxnumf32 => "llvm.maxnum.f32", + sym::maxnumf64 => "llvm.maxnum.f64", + sym::copysignf32 => "llvm.copysign.f32", + sym::copysignf64 => "llvm.copysign.f64", + sym::floorf32 => "llvm.floor.f32", + sym::floorf64 => "llvm.floor.f64", + sym::ceilf32 => "llvm.ceil.f32", + sym::ceilf64 => "llvm.ceil.f64", + sym::truncf32 => "llvm.trunc.f32", + sym::truncf64 => "llvm.trunc.f64", + sym::rintf32 => "llvm.rint.f32", + sym::rintf64 => "llvm.rint.f64", + sym::nearbyintf32 => "llvm.nearbyint.f32", + sym::nearbyintf64 => "llvm.nearbyint.f64", + sym::roundf32 => "llvm.round.f32", + sym::roundf64 => "llvm.round.f64", + sym::assume => "llvm.assume", + sym::abort => "llvm.trap", _ => return None, }; Some(cx.get_intrinsic(&llvm_name)) @@ -86,12 +86,12 @@ fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: &str) -> Option<&'ll Valu impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { fn is_codegen_intrinsic( &mut self, - intrinsic: &str, + intrinsic: Symbol, args: &Vec>, caller_instance: ty::Instance<'tcx>, ) -> bool { match intrinsic { - "count_code_region" => { + sym::count_code_region => { use coverage::count_code_region_args::*; self.add_counter_region( caller_instance, @@ -101,13 +101,13 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { ); true // Also inject the counter increment in the backend } - "coverage_counter_add" | "coverage_counter_subtract" => { + sym::coverage_counter_add | sym::coverage_counter_subtract => { use coverage::coverage_counter_expression_args::*; self.add_counter_expression_region( caller_instance, op_to_u32(&args[COUNTER_EXPRESSION_INDEX]), op_to_u32(&args[LEFT_INDEX]), - if intrinsic == "coverage_counter_add" { + if intrinsic == sym::coverage_counter_add { CounterOp::Add } else { CounterOp::Subtract @@ -118,7 +118,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { ); false // Does not inject backend code } - "coverage_unreachable" => { + sym::coverage_unreachable => { use coverage::coverage_unreachable_args::*; self.add_unreachable_region( caller_instance, @@ -152,7 +152,8 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); let arg_tys = sig.inputs(); let ret_ty = sig.output(); - let name = &*tcx.item_name(def_id).as_str(); + let name = tcx.item_name(def_id); + let name_str = &*name.as_str(); let llret_ty = self.layout_of(ret_ty).llvm_type(self); let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); @@ -164,18 +165,18 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { &args.iter().map(|arg| arg.immediate()).collect::>(), None, ), - "unreachable" => { + sym::unreachable => { return; } - "likely" => { + sym::likely => { let expect = self.get_intrinsic(&("llvm.expect.i1")); self.call(expect, &[args[0].immediate(), self.const_bool(true)], None) } - "unlikely" => { + sym::unlikely => { let expect = self.get_intrinsic(&("llvm.expect.i1")); self.call(expect, &[args[0].immediate(), self.const_bool(false)], None) } - "try" => { + kw::Try => { try_intrinsic( self, args[0].immediate(), @@ -185,11 +186,11 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { ); return; } - "breakpoint" => { + sym::breakpoint => { let llfn = self.get_intrinsic(&("llvm.debugtrap")); self.call(llfn, &[], None) } - "count_code_region" => { + sym::count_code_region => { // FIXME(richkadel): The current implementation assumes the MIR for the given // caller_instance represents a single function. Validate and/or correct if inlining // and/or monomorphization invalidates these assumptions. @@ -206,13 +207,13 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { ); self.instrprof_increment(mangled_fn_name, hash, num_counters, index) } - "va_start" => self.va_start(args[0].immediate()), - "va_end" => self.va_end(args[0].immediate()), - "va_copy" => { + sym::va_start => self.va_start(args[0].immediate()), + sym::va_end => self.va_end(args[0].immediate()), + sym::va_copy => { let intrinsic = self.cx().get_intrinsic(&("llvm.va_copy")); self.call(intrinsic, &[args[0].immediate(), args[1].immediate()], None) } - "va_arg" => { + sym::va_arg => { match fn_abi.ret.layout.abi { abi::Abi::Scalar(ref scalar) => { match scalar.value { @@ -238,7 +239,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { _ => bug!("the va_arg intrinsic does not work with non-scalar types"), } } - "size_of_val" => { + sym::size_of_val => { let tp_ty = substs.type_at(0); if let OperandValue::Pair(_, meta) = args[0].val { let (llsize, _) = glue::size_and_align_of_dst(self, tp_ty, Some(meta)); @@ -247,7 +248,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { self.const_usize(self.size_of(tp_ty).bytes()) } } - "min_align_of_val" => { + sym::min_align_of_val => { let tp_ty = substs.type_at(0); if let OperandValue::Pair(_, meta) = args[0].val { let (_, llalign) = glue::size_and_align_of_dst(self, tp_ty, Some(meta)); @@ -256,8 +257,13 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { self.const_usize(self.align_of(tp_ty).bytes()) } } - "size_of" | "pref_align_of" | "min_align_of" | "needs_drop" | "type_id" - | "type_name" | "variant_count" => { + sym::size_of + | sym::pref_align_of + | sym::min_align_of + | sym::needs_drop + | sym::type_id + | sym::type_name + | sym::variant_count => { let value = self .tcx .const_eval_instance(ty::ParamEnv::reveal_all(), instance, None) @@ -265,21 +271,21 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { OperandRef::from_const(self, value, ret_ty).immediate_or_packed_pair(self) } // Effectively no-op - "forget" => { + sym::forget => { return; } - "offset" => { + sym::offset => { let ptr = args[0].immediate(); let offset = args[1].immediate(); self.inbounds_gep(ptr, &[offset]) } - "arith_offset" => { + sym::arith_offset => { let ptr = args[0].immediate(); let offset = args[1].immediate(); self.gep(ptr, &[offset]) } - "copy_nonoverlapping" => { + sym::copy_nonoverlapping => { copy_intrinsic( self, false, @@ -291,7 +297,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { ); return; } - "copy" => { + sym::copy => { copy_intrinsic( self, true, @@ -303,7 +309,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { ); return; } - "write_bytes" => { + sym::write_bytes => { memset_intrinsic( self, false, @@ -315,7 +321,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { return; } - "volatile_copy_nonoverlapping_memory" => { + sym::volatile_copy_nonoverlapping_memory => { copy_intrinsic( self, false, @@ -327,7 +333,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { ); return; } - "volatile_copy_memory" => { + sym::volatile_copy_memory => { copy_intrinsic( self, true, @@ -339,7 +345,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { ); return; } - "volatile_set_memory" => { + sym::volatile_set_memory => { memset_intrinsic( self, true, @@ -350,14 +356,14 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { ); return; } - "volatile_load" | "unaligned_volatile_load" => { + sym::volatile_load | sym::unaligned_volatile_load => { let tp_ty = substs.type_at(0); let mut ptr = args[0].immediate(); if let PassMode::Cast(ty) = fn_abi.ret.mode { ptr = self.pointercast(ptr, self.type_ptr_to(ty.llvm_type(self))); } let load = self.volatile_load(ptr); - let align = if name == "unaligned_volatile_load" { + let align = if name == sym::unaligned_volatile_load { 1 } else { self.align_of(tp_ty).bytes() as u32 @@ -367,26 +373,26 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { } to_immediate(self, load, self.layout_of(tp_ty)) } - "volatile_store" => { + sym::volatile_store => { let dst = args[0].deref(self.cx()); args[1].val.volatile_store(self, dst); return; } - "unaligned_volatile_store" => { + sym::unaligned_volatile_store => { let dst = args[0].deref(self.cx()); args[1].val.unaligned_volatile_store(self, dst); return; } - "prefetch_read_data" - | "prefetch_write_data" - | "prefetch_read_instruction" - | "prefetch_write_instruction" => { + sym::prefetch_read_data + | sym::prefetch_write_data + | sym::prefetch_read_instruction + | sym::prefetch_write_instruction => { let expect = self.get_intrinsic(&("llvm.prefetch")); let (rw, cache_type) = match name { - "prefetch_read_data" => (0, 1), - "prefetch_write_data" => (1, 1), - "prefetch_read_instruction" => (0, 0), - "prefetch_write_instruction" => (1, 0), + sym::prefetch_read_data => (0, 1), + sym::prefetch_write_data => (1, 1), + sym::prefetch_read_instruction => (0, 0), + sym::prefetch_write_instruction => (1, 0), _ => bug!(), }; self.call( @@ -400,32 +406,51 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { None, ) } - "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "ctpop" | "bswap" - | "bitreverse" | "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" - | "wrapping_add" | "wrapping_sub" | "wrapping_mul" | "unchecked_div" - | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" | "unchecked_add" - | "unchecked_sub" | "unchecked_mul" | "exact_div" | "rotate_left" | "rotate_right" - | "saturating_add" | "saturating_sub" => { + sym::ctlz + | sym::ctlz_nonzero + | sym::cttz + | sym::cttz_nonzero + | sym::ctpop + | sym::bswap + | sym::bitreverse + | sym::add_with_overflow + | sym::sub_with_overflow + | sym::mul_with_overflow + | sym::wrapping_add + | sym::wrapping_sub + | sym::wrapping_mul + | sym::unchecked_div + | sym::unchecked_rem + | sym::unchecked_shl + | sym::unchecked_shr + | sym::unchecked_add + | sym::unchecked_sub + | sym::unchecked_mul + | sym::exact_div + | sym::rotate_left + | sym::rotate_right + | sym::saturating_add + | sym::saturating_sub => { let ty = arg_tys[0]; match int_type_width_signed(ty, self) { Some((width, signed)) => match name { - "ctlz" | "cttz" => { + sym::ctlz | sym::cttz => { let y = self.const_bool(false); let llfn = self.get_intrinsic(&format!("llvm.{}.i{}", name, width)); self.call(llfn, &[args[0].immediate(), y], None) } - "ctlz_nonzero" | "cttz_nonzero" => { + sym::ctlz_nonzero | sym::cttz_nonzero => { let y = self.const_bool(true); - let llvm_name = &format!("llvm.{}.i{}", &name[..4], width); + let llvm_name = &format!("llvm.{}.i{}", &name_str[..4], width); let llfn = self.get_intrinsic(llvm_name); self.call(llfn, &[args[0].immediate(), y], None) } - "ctpop" => self.call( + sym::ctpop => self.call( self.get_intrinsic(&format!("llvm.ctpop.i{}", width)), &[args[0].immediate()], None, ), - "bswap" => { + sym::bswap => { if width == 8 { args[0].immediate() // byte swap a u8/i8 is just a no-op } else { @@ -436,16 +461,18 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { ) } } - "bitreverse" => self.call( + sym::bitreverse => self.call( self.get_intrinsic(&format!("llvm.bitreverse.i{}", width)), &[args[0].immediate()], None, ), - "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => { + sym::add_with_overflow + | sym::sub_with_overflow + | sym::mul_with_overflow => { let intrinsic = format!( "llvm.{}{}.with.overflow.i{}", if signed { 's' } else { 'u' }, - &name[..3], + &name_str[..3], width ); let llfn = self.get_intrinsic(&intrinsic); @@ -464,61 +491,61 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { return; } - "wrapping_add" => self.add(args[0].immediate(), args[1].immediate()), - "wrapping_sub" => self.sub(args[0].immediate(), args[1].immediate()), - "wrapping_mul" => self.mul(args[0].immediate(), args[1].immediate()), - "exact_div" => { + sym::wrapping_add => self.add(args[0].immediate(), args[1].immediate()), + sym::wrapping_sub => self.sub(args[0].immediate(), args[1].immediate()), + sym::wrapping_mul => self.mul(args[0].immediate(), args[1].immediate()), + sym::exact_div => { if signed { self.exactsdiv(args[0].immediate(), args[1].immediate()) } else { self.exactudiv(args[0].immediate(), args[1].immediate()) } } - "unchecked_div" => { + sym::unchecked_div => { if signed { self.sdiv(args[0].immediate(), args[1].immediate()) } else { self.udiv(args[0].immediate(), args[1].immediate()) } } - "unchecked_rem" => { + sym::unchecked_rem => { if signed { self.srem(args[0].immediate(), args[1].immediate()) } else { self.urem(args[0].immediate(), args[1].immediate()) } } - "unchecked_shl" => self.shl(args[0].immediate(), args[1].immediate()), - "unchecked_shr" => { + sym::unchecked_shl => self.shl(args[0].immediate(), args[1].immediate()), + sym::unchecked_shr => { if signed { self.ashr(args[0].immediate(), args[1].immediate()) } else { self.lshr(args[0].immediate(), args[1].immediate()) } } - "unchecked_add" => { + sym::unchecked_add => { if signed { self.unchecked_sadd(args[0].immediate(), args[1].immediate()) } else { self.unchecked_uadd(args[0].immediate(), args[1].immediate()) } } - "unchecked_sub" => { + sym::unchecked_sub => { if signed { self.unchecked_ssub(args[0].immediate(), args[1].immediate()) } else { self.unchecked_usub(args[0].immediate(), args[1].immediate()) } } - "unchecked_mul" => { + sym::unchecked_mul => { if signed { self.unchecked_smul(args[0].immediate(), args[1].immediate()) } else { self.unchecked_umul(args[0].immediate(), args[1].immediate()) } } - "rotate_left" | "rotate_right" => { - let is_left = name == "rotate_left"; + sym::rotate_left | sym::rotate_right => { + let is_left = name == sym::rotate_left; let val = args[0].immediate(); let raw_shift = args[1].immediate(); // rotate = funnel shift with first two args the same @@ -527,8 +554,8 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { let llfn = self.get_intrinsic(llvm_name); self.call(llfn, &[val, val, raw_shift], None) } - "saturating_add" | "saturating_sub" => { - let is_add = name == "saturating_add"; + sym::saturating_add | sym::saturating_sub => { + let is_add = name == sym::saturating_add; let lhs = args[0].immediate(); let rhs = args[1].immediate(); let llvm_name = &format!( @@ -556,14 +583,14 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { } } } - "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { + sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => { match float_type_width(arg_tys[0]) { Some(_width) => match name { - "fadd_fast" => self.fadd_fast(args[0].immediate(), args[1].immediate()), - "fsub_fast" => self.fsub_fast(args[0].immediate(), args[1].immediate()), - "fmul_fast" => self.fmul_fast(args[0].immediate(), args[1].immediate()), - "fdiv_fast" => self.fdiv_fast(args[0].immediate(), args[1].immediate()), - "frem_fast" => self.frem_fast(args[0].immediate(), args[1].immediate()), + sym::fadd_fast => self.fadd_fast(args[0].immediate(), args[1].immediate()), + sym::fsub_fast => self.fsub_fast(args[0].immediate(), args[1].immediate()), + sym::fmul_fast => self.fmul_fast(args[0].immediate(), args[1].immediate()), + sym::fdiv_fast => self.fdiv_fast(args[0].immediate(), args[1].immediate()), + sym::frem_fast => self.frem_fast(args[0].immediate(), args[1].immediate()), _ => bug!(), }, None => { @@ -581,7 +608,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { } } - "float_to_int_unchecked" => { + sym::float_to_int_unchecked => { if float_type_width(arg_tys[0]).is_none() { span_invalid_monomorphization_error( tcx.sess, @@ -619,7 +646,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { } } - "discriminant_value" => { + sym::discriminant_value => { if ret_ty.is_integral() { args[0].deref(self.cx()).codegen_get_discr(self, ret_ty) } else { @@ -627,7 +654,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { } } - name if name.starts_with("simd_") => { + _ if name_str.starts_with("simd_") => { match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) { Ok(llval) => llval, Err(()) => return, @@ -635,11 +662,11 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { } // This requires that atomic intrinsics follow a specific naming pattern: // "atomic_[_]", and no ordering means SeqCst - name if name.starts_with("atomic_") => { + name if name_str.starts_with("atomic_") => { use rustc_codegen_ssa::common::AtomicOrdering::*; use rustc_codegen_ssa::common::{AtomicRmwBinOp, SynchronizationScope}; - let split: Vec<&str> = name.split('_').collect(); + let split: Vec<&str> = name_str.split('_').collect(); let is_cxchg = split[1] == "cxchg" || split[1] == "cxchgweak"; let (order, failorder) = match split.len() { @@ -769,23 +796,23 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { } } - "nontemporal_store" => { + sym::nontemporal_store => { let dst = args[0].deref(self.cx()); args[1].val.nontemporal_store(self, dst); return; } - "ptr_guaranteed_eq" | "ptr_guaranteed_ne" => { + sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => { let a = args[0].immediate(); let b = args[1].immediate(); - if name == "ptr_guaranteed_eq" { + if name == sym::ptr_guaranteed_eq { self.icmp(IntPredicate::IntEQ, a, b) } else { self.icmp(IntPredicate::IntNE, a, b) } } - "ptr_offset_from" => { + sym::ptr_offset_from => { let ty = substs.type_at(0); let pointee_size = self.size_of(ty); @@ -1172,7 +1199,7 @@ fn get_rust_try_fn<'ll, 'tcx>( fn generic_simd_intrinsic( bx: &mut Builder<'a, 'll, 'tcx>, - name: &str, + name: Symbol, callee_ty: Ty<'tcx>, args: &[OperandRef<'tcx, &'ll Value>], ret_ty: Ty<'tcx>, @@ -1219,8 +1246,9 @@ fn generic_simd_intrinsic( let sig = tcx .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &callee_ty.fn_sig(tcx)); let arg_tys = sig.inputs(); + let name_str = &*name.as_str(); - if name == "simd_select_bitmask" { + if name == sym::simd_select_bitmask { let in_ty = arg_tys[0]; let m_len = match in_ty.kind { // Note that this `.unwrap()` crashes for isize/usize, that's sort @@ -1250,12 +1278,12 @@ fn generic_simd_intrinsic( let in_len = arg_tys[0].simd_size(tcx); let comparison = match name { - "simd_eq" => Some(hir::BinOpKind::Eq), - "simd_ne" => Some(hir::BinOpKind::Ne), - "simd_lt" => Some(hir::BinOpKind::Lt), - "simd_le" => Some(hir::BinOpKind::Le), - "simd_gt" => Some(hir::BinOpKind::Gt), - "simd_ge" => Some(hir::BinOpKind::Ge), + sym::simd_eq => Some(hir::BinOpKind::Eq), + sym::simd_ne => Some(hir::BinOpKind::Ne), + sym::simd_lt => Some(hir::BinOpKind::Lt), + sym::simd_le => Some(hir::BinOpKind::Le), + sym::simd_gt => Some(hir::BinOpKind::Gt), + sym::simd_ge => Some(hir::BinOpKind::Ge), _ => None, }; @@ -1289,8 +1317,8 @@ fn generic_simd_intrinsic( )); } - if name.starts_with("simd_shuffle") { - let n: u64 = name["simd_shuffle".len()..].parse().unwrap_or_else(|_| { + if name_str.starts_with("simd_shuffle") { + let n: u64 = name_str["simd_shuffle".len()..].parse().unwrap_or_else(|_| { span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?") }); @@ -1351,7 +1379,7 @@ fn generic_simd_intrinsic( )); } - if name == "simd_insert" { + if name == sym::simd_insert { require!( in_elem == arg_tys[2], "expected inserted type `{}` (element of input `{}`), found `{}`", @@ -1365,7 +1393,7 @@ fn generic_simd_intrinsic( args[1].immediate(), )); } - if name == "simd_extract" { + if name == sym::simd_extract { require!( ret_ty == in_elem, "expected return type `{}` (element of input `{}`), found `{}`", @@ -1376,7 +1404,7 @@ fn generic_simd_intrinsic( return Ok(bx.extract_element(args[0].immediate(), args[1].immediate())); } - if name == "simd_select" { + if name == sym::simd_select { let m_elem_ty = in_elem; let m_len = in_len; require_simd!(arg_tys[1], "argument"); @@ -1398,7 +1426,7 @@ fn generic_simd_intrinsic( return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate())); } - if name == "simd_bitmask" { + if name == sym::simd_bitmask { // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a // vector mask and returns an unsigned integer containing the most // significant bit (MSB) of each lane. @@ -1513,46 +1541,46 @@ fn generic_simd_intrinsic( } match name { - "simd_fsqrt" => { + sym::simd_fsqrt => { return simd_simple_float_intrinsic("sqrt", in_elem, in_ty, in_len, bx, span, args); } - "simd_fsin" => { + sym::simd_fsin => { return simd_simple_float_intrinsic("sin", in_elem, in_ty, in_len, bx, span, args); } - "simd_fcos" => { + sym::simd_fcos => { return simd_simple_float_intrinsic("cos", in_elem, in_ty, in_len, bx, span, args); } - "simd_fabs" => { + sym::simd_fabs => { return simd_simple_float_intrinsic("fabs", in_elem, in_ty, in_len, bx, span, args); } - "simd_floor" => { + sym::simd_floor => { return simd_simple_float_intrinsic("floor", in_elem, in_ty, in_len, bx, span, args); } - "simd_ceil" => { + sym::simd_ceil => { return simd_simple_float_intrinsic("ceil", in_elem, in_ty, in_len, bx, span, args); } - "simd_fexp" => { + sym::simd_fexp => { return simd_simple_float_intrinsic("exp", in_elem, in_ty, in_len, bx, span, args); } - "simd_fexp2" => { + sym::simd_fexp2 => { return simd_simple_float_intrinsic("exp2", in_elem, in_ty, in_len, bx, span, args); } - "simd_flog10" => { + sym::simd_flog10 => { return simd_simple_float_intrinsic("log10", in_elem, in_ty, in_len, bx, span, args); } - "simd_flog2" => { + sym::simd_flog2 => { return simd_simple_float_intrinsic("log2", in_elem, in_ty, in_len, bx, span, args); } - "simd_flog" => { + sym::simd_flog => { return simd_simple_float_intrinsic("log", in_elem, in_ty, in_len, bx, span, args); } - "simd_fpowi" => { + sym::simd_fpowi => { return simd_simple_float_intrinsic("powi", in_elem, in_ty, in_len, bx, span, args); } - "simd_fpow" => { + sym::simd_fpow => { return simd_simple_float_intrinsic("pow", in_elem, in_ty, in_len, bx, span, args); } - "simd_fma" => { + sym::simd_fma => { return simd_simple_float_intrinsic("fma", in_elem, in_ty, in_len, bx, span, args); } _ => { /* fallthrough */ } @@ -1591,7 +1619,7 @@ fn generic_simd_intrinsic( cx.type_vector(elem_ty, vec_len) } - if name == "simd_gather" { + if name == sym::simd_gather { // simd_gather(values: , pointers: , // mask: ) -> // * N: number of elements in the input vectors @@ -1718,7 +1746,7 @@ fn generic_simd_intrinsic( return Ok(v); } - if name == "simd_scatter" { + if name == sym::simd_scatter { // simd_scatter(values: , pointers: , // mask: ) -> () // * N: number of elements in the input vectors @@ -1841,8 +1869,9 @@ fn generic_simd_intrinsic( } macro_rules! arith_red { - ($name:tt : $integer_reduce:ident, $float_reduce:ident, $ordered:expr) => { - if name == $name { + ($name:ident : $integer_reduce:ident, $float_reduce:ident, $ordered:expr, $op:ident, + $identity:expr) => { + if name == sym::$name { require!( ret_ty == in_elem, "expected return type `{}` (element of input `{}`), found `{}`", @@ -1856,11 +1885,7 @@ fn generic_simd_intrinsic( if $ordered { // if overflow occurs, the result is the // mathematical result modulo 2^n: - if name.contains("mul") { - Ok(bx.mul(args[1].immediate(), r)) - } else { - Ok(bx.add(args[1].immediate(), r)) - } + Ok(bx.$op(args[1].immediate(), r)) } else { Ok(bx.$integer_reduce(args[0].immediate())) } @@ -1871,14 +1896,13 @@ fn generic_simd_intrinsic( args[1].immediate() } else { // unordered arithmetic reductions use the identity accumulator - let identity_acc = if $name.contains("mul") { 1.0 } else { 0.0 }; match f.bit_width() { - 32 => bx.const_real(bx.type_f32(), identity_acc), - 64 => bx.const_real(bx.type_f64(), identity_acc), + 32 => bx.const_real(bx.type_f32(), $identity), + 64 => bx.const_real(bx.type_f64(), $identity), v => return_error!( r#" unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, - $name, + sym::$name, in_ty, in_elem, v, @@ -1890,7 +1914,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, } _ => return_error!( "unsupported {} from `{}` with element `{}` to `{}`", - $name, + sym::$name, in_ty, in_elem, ret_ty @@ -1900,14 +1924,26 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, }; } - arith_red!("simd_reduce_add_ordered": vector_reduce_add, vector_reduce_fadd, true); - arith_red!("simd_reduce_mul_ordered": vector_reduce_mul, vector_reduce_fmul, true); - arith_red!("simd_reduce_add_unordered": vector_reduce_add, vector_reduce_fadd_fast, false); - arith_red!("simd_reduce_mul_unordered": vector_reduce_mul, vector_reduce_fmul_fast, false); + arith_red!(simd_reduce_add_ordered: vector_reduce_add, vector_reduce_fadd, true, add, 0.0); + arith_red!(simd_reduce_mul_ordered: vector_reduce_mul, vector_reduce_fmul, true, mul, 1.0); + arith_red!( + simd_reduce_add_unordered: vector_reduce_add, + vector_reduce_fadd_fast, + false, + add, + 0.0 + ); + arith_red!( + simd_reduce_mul_unordered: vector_reduce_mul, + vector_reduce_fmul_fast, + false, + mul, + 1.0 + ); macro_rules! minmax_red { - ($name:tt: $int_red:ident, $float_red:ident) => { - if name == $name { + ($name:ident: $int_red:ident, $float_red:ident) => { + if name == sym::$name { require!( ret_ty == in_elem, "expected return type `{}` (element of input `{}`), found `{}`", @@ -1921,7 +1957,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, ty::Float(_f) => Ok(bx.$float_red(args[0].immediate())), _ => return_error!( "unsupported {} from `{}` with element `{}` to `{}`", - $name, + sym::$name, in_ty, in_elem, ret_ty @@ -1931,15 +1967,15 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, }; } - minmax_red!("simd_reduce_min": vector_reduce_min, vector_reduce_fmin); - minmax_red!("simd_reduce_max": vector_reduce_max, vector_reduce_fmax); + minmax_red!(simd_reduce_min: vector_reduce_min, vector_reduce_fmin); + minmax_red!(simd_reduce_max: vector_reduce_max, vector_reduce_fmax); - minmax_red!("simd_reduce_min_nanless": vector_reduce_min, vector_reduce_fmin_fast); - minmax_red!("simd_reduce_max_nanless": vector_reduce_max, vector_reduce_fmax_fast); + minmax_red!(simd_reduce_min_nanless: vector_reduce_min, vector_reduce_fmin_fast); + minmax_red!(simd_reduce_max_nanless: vector_reduce_max, vector_reduce_fmax_fast); macro_rules! bitwise_red { - ($name:tt : $red:ident, $boolean:expr) => { - if name == $name { + ($name:ident : $red:ident, $boolean:expr) => { + if name == sym::$name { let input = if !$boolean { require!( ret_ty == in_elem, @@ -1954,7 +1990,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, ty::Int(_) | ty::Uint(_) => {} _ => return_error!( "unsupported {} from `{}` with element `{}` to `{}`", - $name, + sym::$name, in_ty, in_elem, ret_ty @@ -1973,7 +2009,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, } _ => return_error!( "unsupported {} from `{}` with element `{}` to `{}`", - $name, + sym::$name, in_ty, in_elem, ret_ty @@ -1983,13 +2019,13 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, }; } - bitwise_red!("simd_reduce_and": vector_reduce_and, false); - bitwise_red!("simd_reduce_or": vector_reduce_or, false); - bitwise_red!("simd_reduce_xor": vector_reduce_xor, false); - bitwise_red!("simd_reduce_all": vector_reduce_and, true); - bitwise_red!("simd_reduce_any": vector_reduce_or, true); + bitwise_red!(simd_reduce_and: vector_reduce_and, false); + bitwise_red!(simd_reduce_or: vector_reduce_or, false); + bitwise_red!(simd_reduce_xor: vector_reduce_xor, false); + bitwise_red!(simd_reduce_all: vector_reduce_and, true); + bitwise_red!(simd_reduce_any: vector_reduce_or, true); - if name == "simd_cast" { + if name == sym::simd_cast { require_simd!(ret_ty, "return"); let out_len = ret_ty.simd_size(tcx); require!( @@ -2077,7 +2113,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, } macro_rules! arith { ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => { - $(if name == stringify!($name) { + $(if name == sym::$name { match in_elem.kind { $($(ty::$p(_))|* => { return Ok(bx.$call(args[0].immediate(), args[1].immediate())) @@ -2107,10 +2143,10 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, } - if name == "simd_saturating_add" || name == "simd_saturating_sub" { + if name == sym::simd_saturating_add || name == sym::simd_saturating_sub { let lhs = args[0].immediate(); let rhs = args[1].immediate(); - let is_add = name == "simd_saturating_add"; + let is_add = name == sym::simd_saturating_add; let ptr_bits = bx.tcx().data_layout.pointer_size.bits() as _; let (signed, elem_width, elem_ty) = match in_elem.kind { ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_int_from_ty(i)), diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs index 2efbfcb995027..faf6809f35b1c 100644 --- a/src/librustc_codegen_ssa/back/symbol_export.rs +++ b/src/librustc_codegen_ssa/back/symbol_export.rs @@ -16,6 +16,7 @@ use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::Instance; use rustc_middle::ty::{SymbolName, TyCtxt}; use rustc_session::config::{CrateType, SanitizerSet}; +use rustc_span::symbol::sym; pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel { crates_export_threshold(&tcx.sess.crate_types()) @@ -107,7 +108,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap< }) .map(|def_id| { let export_level = if special_runtime_crate { - let name = tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())).name.as_str(); + let name = tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())).name; // We can probably do better here by just ensuring that // it has hidden visibility rather than public // visibility, as this is primarily here to ensure it's @@ -115,13 +116,12 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap< // // In general though we won't link right if these // symbols are stripped, and LTO currently strips them. - if name == "rust_eh_personality" - || name == "rust_eh_register_frames" - || name == "rust_eh_unregister_frames" - { - SymbolExportLevel::C - } else { - SymbolExportLevel::Rust + match name { + sym::rust_eh_personality + | sym::rust_eh_register_frames + | sym::rust_eh_unregister_frames => + SymbolExportLevel::C, + _ => SymbolExportLevel::Rust, } } else { symbol_export_level(tcx, def_id.to_def_id()) diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 7514eb8e889a8..7116bb8c92517 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -17,7 +17,8 @@ use rustc_middle::mir::interpret::{AllocId, ConstValue, Pointer, Scalar}; use rustc_middle::mir::AssertKind; use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt}; use rustc_middle::ty::{self, Instance, Ty, TypeFoldable}; -use rustc_span::{source_map::Span, symbol::Symbol}; +use rustc_span::source_map::Span; +use rustc_span::{sym, Symbol}; use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; use rustc_target::abi::{self, LayoutOf}; use rustc_target::spec::abi::Abi; @@ -445,7 +446,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &mut self, helper: &TerminatorCodegenHelper<'tcx>, bx: &mut Bx, - intrinsic: Option<&str>, + intrinsic: Option, instance: Option>, span: Span, destination: &Option<(mir::Place<'tcx>, mir::BasicBlock)>, @@ -461,10 +462,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { UninitValid, }; let panic_intrinsic = intrinsic.and_then(|i| match i { - // FIXME: Move to symbols instead of strings. - "assert_inhabited" => Some(AssertIntrinsic::Inhabited), - "assert_zero_valid" => Some(AssertIntrinsic::ZeroValid), - "assert_uninit_valid" => Some(AssertIntrinsic::UninitValid), + sym::assert_inhabited => Some(AssertIntrinsic::Inhabited), + sym::assert_zero_valid => Some(AssertIntrinsic::ZeroValid), + sym::assert_uninit_valid => Some(AssertIntrinsic::UninitValid), _ => None, }); if let Some(intrinsic) = panic_intrinsic { @@ -568,10 +568,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Handle intrinsics old codegen wants Expr's for, ourselves. let intrinsic = match def { - Some(ty::InstanceDef::Intrinsic(def_id)) => Some(bx.tcx().item_name(def_id).as_str()), + Some(ty::InstanceDef::Intrinsic(def_id)) => Some(bx.tcx().item_name(def_id)), _ => None, }; - let intrinsic = intrinsic.as_ref().map(|s| &s[..]); let extra_args = &args[sig.inputs().skip_binder().len()..]; let extra_args = extra_args @@ -587,7 +586,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { None => FnAbi::of_fn_ptr(&bx, sig, &extra_args), }; - if intrinsic == Some("transmute") { + if intrinsic == Some(sym::transmute) { if let Some(destination_ref) = destination.as_ref() { let &(dest, target) = destination_ref; self.codegen_transmute(&mut bx, &args[0], dest); @@ -607,7 +606,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } // For normal codegen, this Miri-specific intrinsic should never occur. - if intrinsic == Some("miri_start_panic") { + if intrinsic == Some(sym::miri_start_panic) { bug!("`miri_start_panic` should never end up in compiled code"); } @@ -635,7 +634,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ReturnDest::Nothing }; - if intrinsic == Some("caller_location") { + if intrinsic == Some(sym::caller_location) { if let Some((_, target)) = destination.as_ref() { let location = self.get_caller_location(&mut bx, fn_span); @@ -650,7 +649,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } - if intrinsic.is_some() && intrinsic != Some("drop_in_place") { + if intrinsic.is_some() && intrinsic != Some(sym::drop_in_place) { let intrinsic = intrinsic.unwrap(); // `is_codegen_intrinsic()` allows the backend implementation to perform compile-time @@ -682,7 +681,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // third argument must be constant. This is // checked by const-qualification, which also // promotes any complex rvalues to constants. - if i == 2 && intrinsic.starts_with("simd_shuffle") { + if i == 2 && intrinsic.as_str().starts_with("simd_shuffle") { if let mir::Operand::Constant(constant) = arg { let c = self.eval_mir_constant(constant); let (llval, ty) = self.simd_shuffle_indices( diff --git a/src/librustc_codegen_ssa/traits/intrinsic.rs b/src/librustc_codegen_ssa/traits/intrinsic.rs index e713cc948c10d..425bea4cb1986 100644 --- a/src/librustc_codegen_ssa/traits/intrinsic.rs +++ b/src/librustc_codegen_ssa/traits/intrinsic.rs @@ -2,7 +2,7 @@ use super::BackendTypes; use crate::mir::operand::OperandRef; use rustc_middle::mir::Operand; use rustc_middle::ty::{self, Ty}; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use rustc_target::abi::call::FnAbi; pub trait IntrinsicCallMethods<'tcx>: BackendTypes { @@ -24,7 +24,7 @@ pub trait IntrinsicCallMethods<'tcx>: BackendTypes { /// the intrinsic does not need code generation. fn is_codegen_intrinsic( &mut self, - intrinsic: &str, + intrinsic: Symbol, args: &Vec>, caller_instance: ty::Instance<'tcx>, ) -> bool; diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index c2c19b6b4056b..be11e29cb2575 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -698,7 +698,7 @@ impl RustcDefaultCalls { .parse_sess .config .iter() - .filter_map(|&(name, ref value)| { + .filter_map(|&(name, value)| { // Note that crt-static is a specially recognized cfg // directive that's printed out here as part of // rust-lang/rust#37406, but in general the @@ -707,9 +707,7 @@ impl RustcDefaultCalls { // specifically allowing the crt-static cfg and that's // it, this is intended to get into Cargo and then go // through to build scripts. - let value = value.as_ref().map(|s| s.as_str()); - let value = value.as_ref().map(|s| s.as_ref()); - if (name != sym::target_feature || value != Some("crt-static")) + if (name != sym::target_feature || value != Some(sym::crt_dash_static)) && !allow_unstable_cfg && find_gated_cfg(|cfg_sym| cfg_sym == name).is_some() { diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index f687221d78e03..60aa12b0511c7 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -383,6 +383,7 @@ E0669: include_str!("./error_codes/E0669.md"), E0670: include_str!("./error_codes/E0670.md"), E0671: include_str!("./error_codes/E0671.md"), E0687: include_str!("./error_codes/E0687.md"), +E0688: include_str!("./error_codes/E0688.md"), E0689: include_str!("./error_codes/E0689.md"), E0690: include_str!("./error_codes/E0690.md"), E0691: include_str!("./error_codes/E0691.md"), @@ -450,6 +451,7 @@ E0765: include_str!("./error_codes/E0765.md"), E0766: include_str!("./error_codes/E0766.md"), E0767: include_str!("./error_codes/E0767.md"), E0768: include_str!("./error_codes/E0768.md"), +E0769: include_str!("./error_codes/E0769.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard @@ -616,7 +618,6 @@ E0768: include_str!("./error_codes/E0768.md"), E0640, // infer outlives requirements // E0645, // trait aliases not finished E0667, // `impl Trait` in projections - E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders // E0694, // an unknown tool name found in scoped attributes // E0702, // replaced with a generic attribute input check // E0707, // multiple elided lifetimes used in arguments of `async fn` diff --git a/src/librustc_error_codes/error_codes/E0688.md b/src/librustc_error_codes/error_codes/E0688.md new file mode 100644 index 0000000000000..db50f490208f4 --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0688.md @@ -0,0 +1,36 @@ +In-band lifetimes were mixed with explicit lifetime binders. + +Erroneous code example: + +```compile_fail,E0688 +#![feature(in_band_lifetimes)] + +fn foo<'a>(x: &'a u32, y: &'b u32) {} // error! + +struct Foo<'a> { x: &'a u32 } + +impl Foo<'a> { + fn bar<'b>(x: &'a u32, y: &'b u32, z: &'c u32) {} // error! +} + +impl<'b> Foo<'a> { // error! + fn baz() {} +} +``` + +In-band lifetimes cannot be mixed with explicit lifetime binders. +For example: + +``` +fn foo<'a, 'b>(x: &'a u32, y: &'b u32) {} // ok! + +struct Foo<'a> { x: &'a u32 } + +impl<'a> Foo<'a> { + fn bar<'b,'c>(x: &'a u32, y: &'b u32, z: &'c u32) {} // ok! +} + +impl<'a> Foo<'a> { // ok! + fn baz() {} +} +``` diff --git a/src/librustc_error_codes/error_codes/E0704.md b/src/librustc_error_codes/error_codes/E0704.md index cde46f52c27d7..c22b274fb223e 100644 --- a/src/librustc_error_codes/error_codes/E0704.md +++ b/src/librustc_error_codes/error_codes/E0704.md @@ -1,6 +1,6 @@ -This error indicates that a incorrect visibility restriction was specified. +An incorrect visibility restriction was specified. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0704 mod foo { @@ -12,6 +12,7 @@ mod foo { To make struct `Bar` only visible in module `foo` the `in` keyword should be used: + ``` mod foo { pub(in crate::foo) struct Bar { diff --git a/src/librustc_error_codes/error_codes/E0718.md b/src/librustc_error_codes/error_codes/E0718.md index e7ae51ca58835..1fe62ecf1f4e0 100644 --- a/src/librustc_error_codes/error_codes/E0718.md +++ b/src/librustc_error_codes/error_codes/E0718.md @@ -1,7 +1,6 @@ -This error indicates that a `#[lang = ".."]` attribute was placed -on the wrong type of item. +A `#[lang = ".."]` attribute was placed on the wrong item type. -Examples of erroneous code: +Erroneous code example: ```compile_fail,E0718 #![feature(lang_items)] diff --git a/src/librustc_error_codes/error_codes/E0769.md b/src/librustc_error_codes/error_codes/E0769.md new file mode 100644 index 0000000000000..d1995be9899b1 --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0769.md @@ -0,0 +1,39 @@ +A tuple struct or tuple variant was used in a pattern as if it were a +struct or struct variant. + +Erroneous code example: + +```compile_fail,E0769 +enum E { + A(i32), +} +let e = E::A(42); +match e { + E::A { number } => println!("{}", x), +} +``` + +To fix this error, you can use the tuple pattern: + +``` +# enum E { +# A(i32), +# } +# let e = E::A(42); +match e { + E::A(number) => println!("{}", number), +} +``` + +Alternatively, you can also use the struct pattern by using the correct +field names and binding them to new identifiers: + +``` +# enum E { +# A(i32), +# } +# let e = E::A(42); +match e { + E::A { 0: number } => println!("{}", number), +} +``` diff --git a/src/librustc_expand/proc_macro_server.rs b/src/librustc_expand/proc_macro_server.rs index ce53b9c0b66c8..2805b4203f928 100644 --- a/src/librustc_expand/proc_macro_server.rs +++ b/src/librustc_expand/proc_macro_server.rs @@ -149,8 +149,8 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec)> } Literal(lit) => tt!(Literal { lit }), DocComment(c) => { - let style = comments::doc_comment_style(&c.as_str()); - let stripped = comments::strip_doc_comment_decoration(&c.as_str()); + let style = comments::doc_comment_style(c); + let stripped = comments::strip_doc_comment_decoration(c); let mut escaped = String::new(); for ch in stripped.chars() { escaped.extend(ch.escape_debug()); diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index f3dfec7ca7215..07b489a756267 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -2148,6 +2148,7 @@ pub struct Param<'hir> { pub attrs: &'hir [Attribute], pub hir_id: HirId, pub pat: &'hir Pat<'hir>, + pub ty_span: Span, pub span: Span, } diff --git a/src/librustc_hir/lang_items.rs b/src/librustc_hir/lang_items.rs index 5aaf219b315bd..1c8a56e5d80e7 100644 --- a/src/librustc_hir/lang_items.rs +++ b/src/librustc_hir/lang_items.rs @@ -16,7 +16,7 @@ use rustc_ast::ast; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::HashStable_Generic; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; use lazy_static::lazy_static; @@ -52,10 +52,10 @@ macro_rules! language_item_table { } impl LangItem { - /// Returns the `name` in `#[lang = "$name"]`. + /// Returns the `name` symbol in `#[lang = "$name"]`. /// For example, `LangItem::EqTraitLangItem`, - /// that is `#[lang = "eq"]` would result in `"eq"`. - pub fn name(self) -> &'static str { + /// that is `#[lang = "eq"]` would result in `sym::eq`. + pub fn name(self) -> Symbol { match self { $( $variant => $name, )* } @@ -110,9 +110,8 @@ macro_rules! language_item_table { } $( - /// Returns the corresponding `DefId` for the lang item - #[doc = $name] - /// if it exists. + /// Returns the corresponding `DefId` for the lang item if it + /// exists. #[allow(dead_code)] pub fn $method(&self) -> Option { self.items[$variant as usize] @@ -122,7 +121,7 @@ macro_rules! language_item_table { lazy_static! { /// A mapping from the name of the lang item to its order and the form it must be of. - pub static ref ITEM_REFS: FxHashMap<&'static str, (usize, Target)> = { + pub static ref ITEM_REFS: FxHashMap = { let mut item_refs = FxHashMap::default(); $( item_refs.insert($name, ($variant as usize, $target)); )* item_refs @@ -154,100 +153,100 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> { } language_item_table! { -// Variant name, Name, Method name, Target; - BoolImplItem, "bool", bool_impl, Target::Impl; - CharImplItem, "char", char_impl, Target::Impl; - StrImplItem, "str", str_impl, Target::Impl; - SliceImplItem, "slice", slice_impl, Target::Impl; - SliceU8ImplItem, "slice_u8", slice_u8_impl, Target::Impl; - StrAllocImplItem, "str_alloc", str_alloc_impl, Target::Impl; - SliceAllocImplItem, "slice_alloc", slice_alloc_impl, Target::Impl; - SliceU8AllocImplItem, "slice_u8_alloc", slice_u8_alloc_impl, Target::Impl; - ConstPtrImplItem, "const_ptr", const_ptr_impl, Target::Impl; - MutPtrImplItem, "mut_ptr", mut_ptr_impl, Target::Impl; - ConstSlicePtrImplItem, "const_slice_ptr", const_slice_ptr_impl, Target::Impl; - MutSlicePtrImplItem, "mut_slice_ptr", mut_slice_ptr_impl, Target::Impl; - I8ImplItem, "i8", i8_impl, Target::Impl; - I16ImplItem, "i16", i16_impl, Target::Impl; - I32ImplItem, "i32", i32_impl, Target::Impl; - I64ImplItem, "i64", i64_impl, Target::Impl; - I128ImplItem, "i128", i128_impl, Target::Impl; - IsizeImplItem, "isize", isize_impl, Target::Impl; - U8ImplItem, "u8", u8_impl, Target::Impl; - U16ImplItem, "u16", u16_impl, Target::Impl; - U32ImplItem, "u32", u32_impl, Target::Impl; - U64ImplItem, "u64", u64_impl, Target::Impl; - U128ImplItem, "u128", u128_impl, Target::Impl; - UsizeImplItem, "usize", usize_impl, Target::Impl; - F32ImplItem, "f32", f32_impl, Target::Impl; - F64ImplItem, "f64", f64_impl, Target::Impl; - F32RuntimeImplItem, "f32_runtime", f32_runtime_impl, Target::Impl; - F64RuntimeImplItem, "f64_runtime", f64_runtime_impl, Target::Impl; - - SizedTraitLangItem, "sized", sized_trait, Target::Trait; - UnsizeTraitLangItem, "unsize", unsize_trait, Target::Trait; +// Variant name, Name, Method name, Target; + BoolImplItem, sym::bool, bool_impl, Target::Impl; + CharImplItem, sym::char, char_impl, Target::Impl; + StrImplItem, sym::str, str_impl, Target::Impl; + SliceImplItem, sym::slice, slice_impl, Target::Impl; + SliceU8ImplItem, sym::slice_u8, slice_u8_impl, Target::Impl; + StrAllocImplItem, sym::str_alloc, str_alloc_impl, Target::Impl; + SliceAllocImplItem, sym::slice_alloc, slice_alloc_impl, Target::Impl; + SliceU8AllocImplItem, sym::slice_u8_alloc, slice_u8_alloc_impl, Target::Impl; + ConstPtrImplItem, sym::const_ptr, const_ptr_impl, Target::Impl; + MutPtrImplItem, sym::mut_ptr, mut_ptr_impl, Target::Impl; + ConstSlicePtrImplItem, sym::const_slice_ptr, const_slice_ptr_impl, Target::Impl; + MutSlicePtrImplItem, sym::mut_slice_ptr, mut_slice_ptr_impl, Target::Impl; + I8ImplItem, sym::i8, i8_impl, Target::Impl; + I16ImplItem, sym::i16, i16_impl, Target::Impl; + I32ImplItem, sym::i32, i32_impl, Target::Impl; + I64ImplItem, sym::i64, i64_impl, Target::Impl; + I128ImplItem, sym::i128, i128_impl, Target::Impl; + IsizeImplItem, sym::isize, isize_impl, Target::Impl; + U8ImplItem, sym::u8, u8_impl, Target::Impl; + U16ImplItem, sym::u16, u16_impl, Target::Impl; + U32ImplItem, sym::u32, u32_impl, Target::Impl; + U64ImplItem, sym::u64, u64_impl, Target::Impl; + U128ImplItem, sym::u128, u128_impl, Target::Impl; + UsizeImplItem, sym::usize, usize_impl, Target::Impl; + F32ImplItem, sym::f32, f32_impl, Target::Impl; + F64ImplItem, sym::f64, f64_impl, Target::Impl; + F32RuntimeImplItem, sym::f32_runtime, f32_runtime_impl, Target::Impl; + F64RuntimeImplItem, sym::f64_runtime, f64_runtime_impl, Target::Impl; + + SizedTraitLangItem, sym::sized, sized_trait, Target::Trait; + UnsizeTraitLangItem, sym::unsize, unsize_trait, Target::Trait; // trait injected by #[derive(PartialEq)], (i.e. "Partial EQ"). - StructuralPeqTraitLangItem, "structural_peq", structural_peq_trait, Target::Trait; + StructuralPeqTraitLangItem, sym::structural_peq, structural_peq_trait, Target::Trait; // trait injected by #[derive(Eq)], (i.e. "Total EQ"; no, I will not apologize). - StructuralTeqTraitLangItem, "structural_teq", structural_teq_trait, Target::Trait; - CopyTraitLangItem, "copy", copy_trait, Target::Trait; - CloneTraitLangItem, "clone", clone_trait, Target::Trait; - SyncTraitLangItem, "sync", sync_trait, Target::Trait; - DiscriminantKindTraitLangItem,"discriminant_kind", discriminant_kind_trait, Target::Trait; - FreezeTraitLangItem, "freeze", freeze_trait, Target::Trait; - - DropTraitLangItem, "drop", drop_trait, Target::Trait; - - CoerceUnsizedTraitLangItem, "coerce_unsized", coerce_unsized_trait, Target::Trait; - DispatchFromDynTraitLangItem,"dispatch_from_dyn", dispatch_from_dyn_trait, Target::Trait; - - AddTraitLangItem(Op), "add", add_trait, Target::Trait; - SubTraitLangItem(Op), "sub", sub_trait, Target::Trait; - MulTraitLangItem(Op), "mul", mul_trait, Target::Trait; - DivTraitLangItem(Op), "div", div_trait, Target::Trait; - RemTraitLangItem(Op), "rem", rem_trait, Target::Trait; - NegTraitLangItem(Op), "neg", neg_trait, Target::Trait; - NotTraitLangItem(Op), "not", not_trait, Target::Trait; - BitXorTraitLangItem(Op), "bitxor", bitxor_trait, Target::Trait; - BitAndTraitLangItem(Op), "bitand", bitand_trait, Target::Trait; - BitOrTraitLangItem(Op), "bitor", bitor_trait, Target::Trait; - ShlTraitLangItem(Op), "shl", shl_trait, Target::Trait; - ShrTraitLangItem(Op), "shr", shr_trait, Target::Trait; - AddAssignTraitLangItem(Op), "add_assign", add_assign_trait, Target::Trait; - SubAssignTraitLangItem(Op), "sub_assign", sub_assign_trait, Target::Trait; - MulAssignTraitLangItem(Op), "mul_assign", mul_assign_trait, Target::Trait; - DivAssignTraitLangItem(Op), "div_assign", div_assign_trait, Target::Trait; - RemAssignTraitLangItem(Op), "rem_assign", rem_assign_trait, Target::Trait; - BitXorAssignTraitLangItem(Op),"bitxor_assign", bitxor_assign_trait, Target::Trait; - BitAndAssignTraitLangItem(Op),"bitand_assign", bitand_assign_trait, Target::Trait; - BitOrAssignTraitLangItem(Op),"bitor_assign", bitor_assign_trait, Target::Trait; - ShlAssignTraitLangItem(Op), "shl_assign", shl_assign_trait, Target::Trait; - ShrAssignTraitLangItem(Op), "shr_assign", shr_assign_trait, Target::Trait; - IndexTraitLangItem(Op), "index", index_trait, Target::Trait; - IndexMutTraitLangItem(Op), "index_mut", index_mut_trait, Target::Trait; - - UnsafeCellTypeLangItem, "unsafe_cell", unsafe_cell_type, Target::Struct; - VaListTypeLangItem, "va_list", va_list, Target::Struct; - - DerefTraitLangItem, "deref", deref_trait, Target::Trait; - DerefMutTraitLangItem, "deref_mut", deref_mut_trait, Target::Trait; - ReceiverTraitLangItem, "receiver", receiver_trait, Target::Trait; - - FnTraitLangItem, "fn", fn_trait, Target::Trait; - FnMutTraitLangItem, "fn_mut", fn_mut_trait, Target::Trait; - FnOnceTraitLangItem, "fn_once", fn_once_trait, Target::Trait; - - FnOnceOutputLangItem, "fn_once_output", fn_once_output, Target::AssocTy; - - FutureTraitLangItem, "future_trait", future_trait, Target::Trait; - GeneratorStateLangItem, "generator_state", gen_state, Target::Enum; - GeneratorTraitLangItem, "generator", gen_trait, Target::Trait; - UnpinTraitLangItem, "unpin", unpin_trait, Target::Trait; - PinTypeLangItem, "pin", pin_type, Target::Struct; + StructuralTeqTraitLangItem, sym::structural_teq, structural_teq_trait, Target::Trait; + CopyTraitLangItem, sym::copy, copy_trait, Target::Trait; + CloneTraitLangItem, sym::clone, clone_trait, Target::Trait; + SyncTraitLangItem, sym::sync, sync_trait, Target::Trait; + DiscriminantKindTraitLangItem, sym::discriminant_kind, discriminant_kind_trait, Target::Trait; + FreezeTraitLangItem, sym::freeze, freeze_trait, Target::Trait; + + DropTraitLangItem, sym::drop, drop_trait, Target::Trait; + + CoerceUnsizedTraitLangItem, sym::coerce_unsized, coerce_unsized_trait, Target::Trait; + DispatchFromDynTraitLangItem, sym::dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait; + + AddTraitLangItem(Op), sym::add, add_trait, Target::Trait; + SubTraitLangItem(Op), sym::sub, sub_trait, Target::Trait; + MulTraitLangItem(Op), sym::mul, mul_trait, Target::Trait; + DivTraitLangItem(Op), sym::div, div_trait, Target::Trait; + RemTraitLangItem(Op), sym::rem, rem_trait, Target::Trait; + NegTraitLangItem(Op), sym::neg, neg_trait, Target::Trait; + NotTraitLangItem(Op), sym::not, not_trait, Target::Trait; + BitXorTraitLangItem(Op), sym::bitxor, bitxor_trait, Target::Trait; + BitAndTraitLangItem(Op), sym::bitand, bitand_trait, Target::Trait; + BitOrTraitLangItem(Op), sym::bitor, bitor_trait, Target::Trait; + ShlTraitLangItem(Op), sym::shl, shl_trait, Target::Trait; + ShrTraitLangItem(Op), sym::shr, shr_trait, Target::Trait; + AddAssignTraitLangItem(Op), sym::add_assign, add_assign_trait, Target::Trait; + SubAssignTraitLangItem(Op), sym::sub_assign, sub_assign_trait, Target::Trait; + MulAssignTraitLangItem(Op), sym::mul_assign, mul_assign_trait, Target::Trait; + DivAssignTraitLangItem(Op), sym::div_assign, div_assign_trait, Target::Trait; + RemAssignTraitLangItem(Op), sym::rem_assign, rem_assign_trait, Target::Trait; + BitXorAssignTraitLangItem(Op), sym::bitxor_assign, bitxor_assign_trait, Target::Trait; + BitAndAssignTraitLangItem(Op), sym::bitand_assign, bitand_assign_trait, Target::Trait; + BitOrAssignTraitLangItem(Op), sym::bitor_assign, bitor_assign_trait, Target::Trait; + ShlAssignTraitLangItem(Op), sym::shl_assign, shl_assign_trait, Target::Trait; + ShrAssignTraitLangItem(Op), sym::shr_assign, shr_assign_trait, Target::Trait; + IndexTraitLangItem(Op), sym::index, index_trait, Target::Trait; + IndexMutTraitLangItem(Op), sym::index_mut, index_mut_trait, Target::Trait; + + UnsafeCellTypeLangItem, sym::unsafe_cell, unsafe_cell_type, Target::Struct; + VaListTypeLangItem, sym::va_list, va_list, Target::Struct; + + DerefTraitLangItem, sym::deref, deref_trait, Target::Trait; + DerefMutTraitLangItem, sym::deref_mut, deref_mut_trait, Target::Trait; + ReceiverTraitLangItem, sym::receiver, receiver_trait, Target::Trait; + + FnTraitLangItem, kw::Fn, fn_trait, Target::Trait; + FnMutTraitLangItem, sym::fn_mut, fn_mut_trait, Target::Trait; + FnOnceTraitLangItem, sym::fn_once, fn_once_trait, Target::Trait; + + FnOnceOutputLangItem, sym::fn_once_output, fn_once_output, Target::AssocTy; + + FutureTraitLangItem, sym::future_trait, future_trait, Target::Trait; + GeneratorStateLangItem, sym::generator_state, gen_state, Target::Enum; + GeneratorTraitLangItem, sym::generator, gen_trait, Target::Trait; + UnpinTraitLangItem, sym::unpin, unpin_trait, Target::Trait; + PinTypeLangItem, sym::pin, pin_type, Target::Struct; // Don't be fooled by the naming here: this lang item denotes `PartialEq`, not `Eq`. - EqTraitLangItem, "eq", eq_trait, Target::Trait; - PartialOrdTraitLangItem, "partial_ord", partial_ord_trait, Target::Trait; + EqTraitLangItem, sym::eq, eq_trait, Target::Trait; + PartialOrdTraitLangItem, sym::partial_ord, partial_ord_trait, Target::Trait; // A number of panic-related lang items. The `panic` item corresponds to // divide-by-zero and various panic cases with `match`. The @@ -258,39 +257,39 @@ language_item_table! { // defined to use it, but a final product is required to define it // somewhere. Additionally, there are restrictions on crates that use a weak // lang item, but do not have it defined. - PanicFnLangItem, "panic", panic_fn, Target::Fn; - PanicBoundsCheckFnLangItem, "panic_bounds_check", panic_bounds_check_fn, Target::Fn; - PanicInfoLangItem, "panic_info", panic_info, Target::Struct; - PanicLocationLangItem, "panic_location", panic_location, Target::Struct; - PanicImplLangItem, "panic_impl", panic_impl, Target::Fn; + PanicFnLangItem, sym::panic, panic_fn, Target::Fn; + PanicBoundsCheckFnLangItem, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn; + PanicInfoLangItem, sym::panic_info, panic_info, Target::Struct; + PanicLocationLangItem, sym::panic_location, panic_location, Target::Struct; + PanicImplLangItem, sym::panic_impl, panic_impl, Target::Fn; // Libstd panic entry point. Necessary for const eval to be able to catch it - BeginPanicFnLangItem, "begin_panic", begin_panic_fn, Target::Fn; + BeginPanicFnLangItem, sym::begin_panic, begin_panic_fn, Target::Fn; - ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn, Target::Fn; - BoxFreeFnLangItem, "box_free", box_free_fn, Target::Fn; - DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn, Target::Fn; - OomLangItem, "oom", oom, Target::Fn; - AllocLayoutLangItem, "alloc_layout", alloc_layout, Target::Struct; + ExchangeMallocFnLangItem, sym::exchange_malloc, exchange_malloc_fn, Target::Fn; + BoxFreeFnLangItem, sym::box_free, box_free_fn, Target::Fn; + DropInPlaceFnLangItem, sym::drop_in_place, drop_in_place_fn, Target::Fn; + OomLangItem, sym::oom, oom, Target::Fn; + AllocLayoutLangItem, sym::alloc_layout, alloc_layout, Target::Struct; - StartFnLangItem, "start", start_fn, Target::Fn; + StartFnLangItem, sym::start, start_fn, Target::Fn; - CountCodeRegionFnLangItem, "count_code_region", count_code_region_fn, Target::Fn; + CountCodeRegionFnLangItem, sym::count_code_region, count_code_region_fn, Target::Fn; - EhPersonalityLangItem, "eh_personality", eh_personality, Target::Fn; - EhCatchTypeinfoLangItem, "eh_catch_typeinfo", eh_catch_typeinfo, Target::Static; + EhPersonalityLangItem, sym::eh_personality, eh_personality, Target::Fn; + EhCatchTypeinfoLangItem, sym::eh_catch_typeinfo, eh_catch_typeinfo, Target::Static; - OwnedBoxLangItem, "owned_box", owned_box, Target::Struct; + OwnedBoxLangItem, sym::owned_box, owned_box, Target::Struct; - PhantomDataItem, "phantom_data", phantom_data, Target::Struct; + PhantomDataItem, sym::phantom_data, phantom_data, Target::Struct; - ManuallyDropItem, "manually_drop", manually_drop, Target::Struct; + ManuallyDropItem, sym::manually_drop, manually_drop, Target::Struct; - MaybeUninitLangItem, "maybe_uninit", maybe_uninit, Target::Union; + MaybeUninitLangItem, sym::maybe_uninit, maybe_uninit, Target::Union; // Align offset for stride != 1; must not panic. - AlignOffsetLangItem, "align_offset", align_offset_fn, Target::Fn; + AlignOffsetLangItem, sym::align_offset, align_offset_fn, Target::Fn; - TerminationTraitLangItem, "termination", termination, Target::Trait; + TerminationTraitLangItem, sym::termination, termination, Target::Trait; - TryTraitLangItem, "try", try_trait, Target::Trait; + TryTraitLangItem, kw::Try, try_trait, Target::Trait; } diff --git a/src/librustc_hir_pretty/lib.rs b/src/librustc_hir_pretty/lib.rs index c16b7c63e3147..2298a80ae4f1f 100644 --- a/src/librustc_hir_pretty/lib.rs +++ b/src/librustc_hir_pretty/lib.rs @@ -1557,7 +1557,7 @@ impl<'a> State<'a> { let i = &a.inner; self.s.word("llvm_asm!"); self.popen(); - self.print_string(&i.asm.as_str(), i.asm_str_style); + self.print_symbol(i.asm, i.asm_str_style); self.word_space(":"); let mut out_idx = 0; @@ -1579,8 +1579,8 @@ impl<'a> State<'a> { self.word_space(":"); let mut in_idx = 0; - self.commasep(Inconsistent, &i.inputs, |s, co| { - s.print_string(&co.as_str(), ast::StrStyle::Cooked); + self.commasep(Inconsistent, &i.inputs, |s, &co| { + s.print_symbol(co, ast::StrStyle::Cooked); s.popen(); s.print_expr(&a.inputs_exprs[in_idx]); s.pclose(); @@ -1589,8 +1589,8 @@ impl<'a> State<'a> { self.s.space(); self.word_space(":"); - self.commasep(Inconsistent, &i.clobbers, |s, co| { - s.print_string(&co.as_str(), ast::StrStyle::Cooked); + self.commasep(Inconsistent, &i.clobbers, |s, &co| { + s.print_symbol(co, ast::StrStyle::Cooked); }); let mut options = vec![]; diff --git a/src/librustc_incremental/assert_module_sources.rs b/src/librustc_incremental/assert_module_sources.rs index eee6e73ed1073..cd5da7a67685c 100644 --- a/src/librustc_incremental/assert_module_sources.rs +++ b/src/librustc_incremental/assert_module_sources.rs @@ -62,11 +62,11 @@ impl AssertModuleSource<'tcx> { } else if attr.check_name(sym::rustc_partition_codegened) { (CguReuse::No, ComparisonKind::Exact) } else if attr.check_name(sym::rustc_expected_cgu_reuse) { - match &*self.field(attr, sym::kind).as_str() { - "no" => (CguReuse::No, ComparisonKind::Exact), - "pre-lto" => (CguReuse::PreLto, ComparisonKind::Exact), - "post-lto" => (CguReuse::PostLto, ComparisonKind::Exact), - "any" => (CguReuse::PreLto, ComparisonKind::AtLeast), + match self.field(attr, sym::kind) { + sym::no => (CguReuse::No, ComparisonKind::Exact), + sym::pre_dash_lto => (CguReuse::PreLto, ComparisonKind::Exact), + sym::post_dash_lto => (CguReuse::PostLto, ComparisonKind::Exact), + sym::any => (CguReuse::PreLto, ComparisonKind::AtLeast), other => { self.tcx.sess.span_fatal( attr.span, @@ -139,7 +139,7 @@ impl AssertModuleSource<'tcx> { } self.tcx.sess.cgu_reuse_tracker.set_expectation( - &cgu_name.as_str(), + cgu_name, &user_path, attr.span, expected_reuse, diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 043aff90ce404..ddc1def6e9367 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -234,7 +234,7 @@ impl DirtyCleanVisitor<'tcx> { for item in attr.meta_item_list().unwrap_or_else(Vec::new) { if item.check_name(LABEL) { let value = expect_associated_value(self.tcx, &item); - return Some(self.resolve_labels(&item, &value.as_str())); + return Some(self.resolve_labels(&item, value)); } } None @@ -245,7 +245,7 @@ impl DirtyCleanVisitor<'tcx> { for item in attr.meta_item_list().unwrap_or_else(Vec::new) { if item.check_name(EXCEPT) { let value = expect_associated_value(self.tcx, &item); - return self.resolve_labels(&item, &value.as_str()); + return self.resolve_labels(&item, value); } } // if no `label` or `except` is given, only the node's group are asserted @@ -347,9 +347,9 @@ impl DirtyCleanVisitor<'tcx> { (name, labels) } - fn resolve_labels(&self, item: &NestedMetaItem, value: &str) -> Labels { + fn resolve_labels(&self, item: &NestedMetaItem, value: Symbol) -> Labels { let mut out = Labels::default(); - for label in value.split(',') { + for label in value.as_str().split(',') { let label = label.trim(); if DepNode::has_label_string(label) { if out.contains(label) { diff --git a/src/librustc_index/Cargo.toml b/src/librustc_index/Cargo.toml index f0422b1af1b97..00b23760182a2 100644 --- a/src/librustc_index/Cargo.toml +++ b/src/librustc_index/Cargo.toml @@ -11,4 +11,4 @@ doctest = false [dependencies] rustc_serialize = { path = "../librustc_serialize" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } +arrayvec = "0.5.1" diff --git a/src/librustc_index/bit_set.rs b/src/librustc_index/bit_set.rs index cb8b30830c5de..3e1d4b68c6fa1 100644 --- a/src/librustc_index/bit_set.rs +++ b/src/librustc_index/bit_set.rs @@ -1,5 +1,5 @@ use crate::vec::{Idx, IndexVec}; -use smallvec::SmallVec; +use arrayvec::ArrayVec; use std::fmt; use std::iter; use std::marker::PhantomData; @@ -355,20 +355,19 @@ where const SPARSE_MAX: usize = 8; /// A fixed-size bitset type with a sparse representation and a maximum of -/// `SPARSE_MAX` elements. The elements are stored as a sorted `SmallVec` with -/// no duplicates; although `SmallVec` can spill its elements to the heap, that -/// never happens within this type because of the `SPARSE_MAX` limit. +/// `SPARSE_MAX` elements. The elements are stored as a sorted `ArrayVec` with +/// no duplicates. /// /// This type is used by `HybridBitSet`; do not use directly. #[derive(Clone, Debug)] pub struct SparseBitSet { domain_size: usize, - elems: SmallVec<[T; SPARSE_MAX]>, + elems: ArrayVec<[T; SPARSE_MAX]>, } impl SparseBitSet { fn new_empty(domain_size: usize) -> Self { - SparseBitSet { domain_size, elems: SmallVec::new() } + SparseBitSet { domain_size, elems: ArrayVec::new() } } fn len(&self) -> usize { diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index 0c8c713c4cf0c..c83f1171735ef 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -53,7 +53,7 @@ pub fn add_configuration( cfg.extend(target_features.into_iter().map(|feat| (tf, Some(feat)))); if sess.crt_static(None) { - cfg.insert((tf, Some(Symbol::intern("crt-static")))); + cfg.insert((tf, Some(sym::crt_dash_static))); } } @@ -427,11 +427,8 @@ pub(crate) fn check_attr_crate_type(attrs: &[ast::Attribute], lint_buffer: &mut if let ast::MetaItemKind::NameValue(spanned) = a.meta().unwrap().kind { let span = spanned.span; - let lev_candidate = find_best_match_for_name( - CRATE_TYPES.iter().map(|(k, _)| k), - &n.as_str(), - None, - ); + let lev_candidate = + find_best_match_for_name(CRATE_TYPES.iter().map(|(k, _)| k), n, None); if let Some(candidate) = lev_candidate { lint_buffer.buffer_lint_with_diagnostic( lint::builtin::UNKNOWN_CRATE_TYPES, diff --git a/src/librustc_lint/context.rs b/src/librustc_lint/context.rs index edbeea6db41cd..65fd938a11351 100644 --- a/src/librustc_lint/context.rs +++ b/src/librustc_lint/context.rs @@ -394,8 +394,11 @@ impl LintStore { let symbols = self.by_name.keys().map(|name| Symbol::intern(&name)).collect::>(); - let suggestion = - find_best_match_for_name(symbols.iter(), &lint_name.to_lowercase(), None); + let suggestion = find_best_match_for_name( + symbols.iter(), + Symbol::intern(&lint_name.to_lowercase()), + None, + ); CheckLintNameResult::NoLint(suggestion) } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index b3015dcc2aee8..46741fcf2ba0c 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -531,23 +531,23 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match ty.kind { ty::FnPtr(_) => true, ty::Ref(..) => true, - ty::Adt(field_def, substs) if field_def.repr.transparent() && !field_def.is_union() => { - for field in field_def.all_fields() { - let field_ty = self.cx.tcx.normalize_erasing_regions( - self.cx.param_env, - field.ty(self.cx.tcx, substs), - ); - if field_ty.is_zst(self.cx.tcx, field.did) { - continue; - } + ty::Adt(def, substs) if def.repr.transparent() && !def.is_union() => { + let guaranteed_nonnull_optimization = self + .cx + .tcx + .get_attrs(def.did) + .iter() + .any(|a| a.check_name(sym::rustc_nonnull_optimization_guaranteed)); + + if guaranteed_nonnull_optimization { + return true; + } - let attrs = self.cx.tcx.get_attrs(field_def.did); - if attrs - .iter() - .any(|a| a.check_name(sym::rustc_nonnull_optimization_guaranteed)) - || self.ty_is_known_nonnull(field_ty) - { - return true; + for variant in &def.variants { + if let Some(field) = variant.transparent_newtype_field(self.cx.tcx) { + if self.ty_is_known_nonnull(field.ty(self.cx.tcx, substs)) { + return true; + } } } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 2c80c846681a6..0563894e6348d 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -679,8 +679,8 @@ impl<'a> CrateLoader<'a> { // in terms of everyone has a compatible panic runtime format, that's // performed later as part of the `dependency_format` module. let name = match desired_strategy { - PanicStrategy::Unwind => Symbol::intern("panic_unwind"), - PanicStrategy::Abort => Symbol::intern("panic_abort"), + PanicStrategy::Unwind => sym::panic_unwind, + PanicStrategy::Abort => sym::panic_abort, }; info!("panic runtime not found -- loading {}", name); @@ -713,7 +713,7 @@ impl<'a> CrateLoader<'a> { { info!("loading profiler"); - let name = Symbol::intern("profiler_builtins"); + let name = sym::profiler_builtins; let cnum = self.resolve_crate(name, DUMMY_SP, DepKind::Implicit, None); let data = self.cstore.get_crate_data(cnum); diff --git a/src/librustc_metadata/link_args.rs b/src/librustc_metadata/link_args.rs index 2dd4a9c9dbcb1..c5a43b91b5e9b 100644 --- a/src/librustc_metadata/link_args.rs +++ b/src/librustc_metadata/link_args.rs @@ -1,7 +1,7 @@ use rustc_hir as hir; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_middle::ty::TyCtxt; -use rustc_span::symbol::sym; +use rustc_span::symbol::{sym, Symbol}; use rustc_target::spec::abi::Abi; crate fn collect(tcx: TyCtxt<'_>) -> Vec { @@ -11,7 +11,7 @@ crate fn collect(tcx: TyCtxt<'_>) -> Vec { for attr in tcx.hir().krate().item.attrs.iter() { if attr.has_name(sym::link_args) { if let Some(linkarg) = attr.value_str() { - collector.add_link_args(&linkarg.as_str()); + collector.add_link_args(linkarg); } } } @@ -36,7 +36,7 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector { // First, add all of the custom #[link_args] attributes for m in it.attrs.iter().filter(|a| a.check_name(sym::link_args)) { if let Some(linkarg) = m.value_str() { - self.add_link_args(&linkarg.as_str()); + self.add_link_args(linkarg); } } } @@ -46,7 +46,7 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector { } impl Collector { - fn add_link_args(&mut self, args: &str) { - self.args.extend(args.split(' ').filter(|s| !s.is_empty()).map(|s| s.to_string())) + fn add_link_args(&mut self, args: Symbol) { + self.args.extend(args.as_str().split(' ').filter(|s| !s.is_empty()).map(|s| s.to_string())) } } diff --git a/src/librustc_middle/mir/mono.rs b/src/librustc_middle/mir/mono.rs index f1c1b962ab997..c9e5a196f9179 100644 --- a/src/librustc_middle/mir/mono.rs +++ b/src/librustc_middle/mir/mono.rs @@ -448,8 +448,7 @@ impl CodegenUnitNameBuilder<'tcx> { if self.tcx.sess.opts.debugging_opts.human_readable_cgu_names { cgu_name } else { - let cgu_name = &cgu_name.as_str(); - Symbol::intern(&CodegenUnit::mangle_name(cgu_name)) + Symbol::intern(&CodegenUnit::mangle_name(&cgu_name.as_str())) } } diff --git a/src/librustc_middle/traits/mod.rs b/src/librustc_middle/traits/mod.rs index fc37cb2504daa..c15c31a53f0c9 100644 --- a/src/librustc_middle/traits/mod.rs +++ b/src/librustc_middle/traits/mod.rs @@ -215,7 +215,7 @@ pub enum ObligationCauseCode<'tcx> { /// Type of each variable must be `Sized`. VariableType(hir::HirId), /// Argument type must be `Sized`. - SizedArgumentType, + SizedArgumentType(Option), /// Return type must be `Sized`. SizedReturnType, /// Yield type must be `Sized`. @@ -229,6 +229,7 @@ pub enum ObligationCauseCode<'tcx> { /// Types of fields (other than the last, except for packed structs) in a struct must be sized. FieldSized { adt_kind: AdtKind, + span: Span, last: bool, }, diff --git a/src/librustc_middle/traits/structural_impls.rs b/src/librustc_middle/traits/structural_impls.rs index faaa576f17903..334462790edbc 100644 --- a/src/librustc_middle/traits/structural_impls.rs +++ b/src/librustc_middle/traits/structural_impls.rs @@ -151,12 +151,14 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::VariableType(id) => Some(super::VariableType(id)), super::ReturnValue(id) => Some(super::ReturnValue(id)), super::ReturnType => Some(super::ReturnType), - super::SizedArgumentType => Some(super::SizedArgumentType), + super::SizedArgumentType(sp) => Some(super::SizedArgumentType(sp)), super::SizedReturnType => Some(super::SizedReturnType), super::SizedYieldType => Some(super::SizedYieldType), super::InlineAsmSized => Some(super::InlineAsmSized), super::RepeatVec(suggest_flag) => Some(super::RepeatVec(suggest_flag)), - super::FieldSized { adt_kind, last } => Some(super::FieldSized { adt_kind, last }), + super::FieldSized { adt_kind, span, last } => { + Some(super::FieldSized { adt_kind, span, last }) + } super::ConstSized => Some(super::ConstSized), super::ConstPatternStructural => Some(super::ConstPatternStructural), super::SharedStatic => Some(super::SharedStatic), diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs index 66ad923b8c007..82daae7d921b2 100644 --- a/src/librustc_middle/ty/layout.rs +++ b/src/librustc_middle/ty/layout.rs @@ -774,12 +774,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { (present_variants.next(), present_variants.next()) }; let present_first = match present_first { - present_first @ Some(_) => present_first, + Some(present_first) => present_first, // Uninhabited because it has no variants, or only absent ones. None if def.is_enum() => return tcx.layout_raw(param_env.and(tcx.types.never)), // If it's a struct, still compute a layout so that we can still compute the // field offsets. - None => Some(VariantIdx::new(0)), + None => VariantIdx::new(0), }; let is_struct = !def.is_enum() || @@ -791,7 +791,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // Struct, or univariant enum equivalent to a struct. // (Typechecking will reject discriminant-sizing attrs.) - let v = present_first.unwrap(); + let v = present_first; let kind = if def.is_enum() || variants[v].is_empty() { StructKind::AlwaysSized } else { diff --git a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs index 4883b08e42442..bd3e20458b078 100644 --- a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs @@ -2,7 +2,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_middle::mir::*; use rustc_middle::ty; use rustc_span::source_map::DesugaringKind; -use rustc_span::{Span, Symbol}; +use rustc_span::{sym, Span}; use crate::borrow_check::diagnostics::UseSpans; use crate::borrow_check::prefixes::PrefixSet; @@ -394,10 +394,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { | ty::Opaque(def_id, _) => def_id, _ => return err, }; - let is_option = - self.infcx.tcx.is_diagnostic_item(Symbol::intern("option_type"), def_id); - let is_result = - self.infcx.tcx.is_diagnostic_item(Symbol::intern("result_type"), def_id); + let is_option = self.infcx.tcx.is_diagnostic_item(sym::option_type, def_id); + let is_result = self.infcx.tcx.is_diagnostic_item(sym::result_type, def_id); if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) { err.span_suggestion( span, @@ -409,7 +407,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { Applicability::MaybeIncorrect, ); } else if matches!(span.desugaring_kind(), Some(DesugaringKind::ForLoop(_))) - && self.infcx.tcx.is_diagnostic_item(Symbol::intern("vec_type"), def_id) + && self.infcx.tcx.is_diagnostic_item(sym::vec_type, def_id) { // FIXME: suggest for anything that implements `IntoIterator`. err.span_suggestion( diff --git a/src/librustc_parse/parser/attr.rs b/src/librustc_parse/parser/attr.rs index 803f14a2a228a..8b67f4743c6b6 100644 --- a/src/librustc_parse/parser/attr.rs +++ b/src/librustc_parse/parser/attr.rs @@ -74,7 +74,7 @@ impl<'a> Parser<'a> { } fn mk_doc_comment(&self, s: Symbol) -> ast::Attribute { - attr::mk_doc_comment(comments::doc_comment_style(&s.as_str()), s, self.token.span) + attr::mk_doc_comment(comments::doc_comment_style(s), s, self.token.span) } /// Matches `attribute = # ! [ meta_item ]`. diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 61c680469f03c..72866468b6560 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -213,7 +213,7 @@ impl TokenCursor { tok => return tok, }; - let stripped = strip_doc_comment_decoration(&name.as_str()); + let stripped = strip_doc_comment_decoration(name); // Searches for the occurrences of `"#*` and returns the minimum number of `#`s // required to wrap the text. @@ -250,7 +250,7 @@ impl TokenCursor { TokenCursorFrame::new( delim_span, token::NoDelim, - &if doc_comment_style(&name.as_str()) == AttrStyle::Inner { + &if doc_comment_style(name) == AttrStyle::Inner { [TokenTree::token(token::Pound, sp), TokenTree::token(token::Not, sp), body] .iter() .cloned() diff --git a/src/librustc_passes/lang_items.rs b/src/librustc_passes/lang_items.rs index 809697134b759..e07c71b41d827 100644 --- a/src/librustc_passes/lang_items.rs +++ b/src/librustc_passes/lang_items.rs @@ -57,7 +57,7 @@ impl LanguageItemCollector<'tcx> { fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId, attrs: &[Attribute]) { if let Some((value, span)) = extract(&attrs) { - match ITEM_REFS.get(&*value.as_str()).cloned() { + match ITEM_REFS.get(&value).cloned() { // Known lang item with attribute on correct target. Some((item_index, expected_target)) if actual_target == expected_target => { let def_id = self.tcx.hir().local_def_id(hir_id); diff --git a/src/librustc_passes/stability.rs b/src/librustc_passes/stability.rs index 5bacab671ec14..76bc6b6c85f02 100644 --- a/src/librustc_passes/stability.rs +++ b/src/librustc_passes/stability.rs @@ -620,7 +620,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { // available as we'd like it to be. // FIXME: only remove `libc` when `stdbuild` is active. // FIXME: remove special casing for `test`. - remaining_lib_features.remove(&Symbol::intern("libc")); + remaining_lib_features.remove(&sym::libc); remaining_lib_features.remove(&sym::test); let check_features = |remaining_lib_features: &mut FxHashMap<_, _>, defined_features: &[_]| { diff --git a/src/librustc_passes/weak_lang_items.rs b/src/librustc_passes/weak_lang_items.rs index 12925af8170f0..d85d8401db676 100644 --- a/src/librustc_passes/weak_lang_items.rs +++ b/src/librustc_passes/weak_lang_items.rs @@ -81,7 +81,7 @@ impl<'a, 'tcx> Context<'a, 'tcx> { // `core::intrinsics::code_count_region()` is (currently) the only `extern` lang item // that is never actually linked. It is not a `weak_lang_item` that can be registered // when used, and should be registered here instead. - if let Some((item_index, _)) = ITEM_REFS.get(&*name.as_str()).cloned() { + if let Some((item_index, _)) = ITEM_REFS.get(&name).cloned() { if self.items.items[item_index].is_none() { let item_def_id = self.tcx.hir().local_def_id(hir_id).to_def_id(); self.items.items[item_index] = Some(item_def_id); diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index bca65c63e9198..8db27babd058b 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -300,9 +300,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } fn insert_field_names(&mut self, def_id: DefId, field_names: Vec>) { - if !field_names.is_empty() { - self.r.field_names.insert(def_id, field_names); - } + self.r.field_names.insert(def_id, field_names); } fn block_needs_anonymous_module(&mut self, block: &Block) -> bool { @@ -1428,6 +1426,8 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { let ctor_kind = CtorKind::from_ast(&variant.data); let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id); self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id)); + // Record field names for error reporting. + self.insert_field_names_local(ctor_def_id, &variant.data); visit::walk_variant(self, variant); } diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 561890723b30b..4f25b948eb66e 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -16,7 +16,7 @@ use rustc_middle::ty::{self, DefIdTree}; use rustc_session::Session; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::SourceMap; -use rustc_span::symbol::{kw, Ident, Symbol}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, MultiSpan, Span}; use crate::imports::{Import, ImportKind, ImportResolver}; @@ -674,7 +674,7 @@ impl<'a> Resolver<'a> { match find_best_match_for_name( suggestions.iter().map(|suggestion| &suggestion.candidate), - &ident.as_str(), + ident.name, None, ) { Some(found) if found != ident.name => { @@ -882,8 +882,7 @@ impl<'a> Resolver<'a> { ); self.add_typo_suggestion(err, suggestion, ident.span); - if macro_kind == MacroKind::Derive && (ident.as_str() == "Send" || ident.as_str() == "Sync") - { + 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); } diff --git a/src/librustc_resolve/imports.rs b/src/librustc_resolve/imports.rs index 4595a96ce24f5..d3f45f962a025 100644 --- a/src/librustc_resolve/imports.rs +++ b/src/librustc_resolve/imports.rs @@ -1034,8 +1034,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let initial_res = source_bindings[ns].get().map(|initial_binding| { all_ns_err = false; if let Some(target_binding) = target_bindings[ns].get() { - // Note that as_str() de-gensyms the Symbol - if target.name.as_str() == "_" + if target.name == kw::Underscore && initial_binding.is_extern_crate() && !initial_binding.is_import() { @@ -1133,7 +1132,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { }); let lev_suggestion = - find_best_match_for_name(names, &ident.as_str(), None).map(|suggestion| { + find_best_match_for_name(names, ident.name, None).map(|suggestion| { ( vec![(ident.span, suggestion.to_string())], String::from("a similar name exists in the module"), diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 679f5637686ff..c165a601408fd 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -184,7 +184,7 @@ crate enum PathSource<'a> { // Paths in struct expressions and patterns `Path { .. }`. Struct, // Paths in tuple struct patterns `Path(..)`. - TupleStruct, + TupleStruct(Span), // `m::A::B` in `::B::C`. TraitItem(Namespace), } @@ -193,7 +193,7 @@ impl<'a> PathSource<'a> { fn namespace(self) -> Namespace { match self { PathSource::Type | PathSource::Trait(_) | PathSource::Struct => TypeNS, - PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct => ValueNS, + PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct(_) => ValueNS, PathSource::TraitItem(ns) => ns, } } @@ -204,7 +204,7 @@ impl<'a> PathSource<'a> { | PathSource::Expr(..) | PathSource::Pat | PathSource::Struct - | PathSource::TupleStruct => true, + | PathSource::TupleStruct(_) => true, PathSource::Trait(_) | PathSource::TraitItem(..) => false, } } @@ -215,7 +215,7 @@ impl<'a> PathSource<'a> { PathSource::Trait(_) => "trait", PathSource::Pat => "unit struct, unit variant or constant", PathSource::Struct => "struct, variant or union type", - PathSource::TupleStruct => "tuple struct or tuple variant", + PathSource::TupleStruct(_) => "tuple struct or tuple variant", PathSource::TraitItem(ns) => match ns { TypeNS => "associated type", ValueNS => "method or associated constant", @@ -301,7 +301,7 @@ impl<'a> PathSource<'a> { | Res::SelfCtor(..) => true, _ => false, }, - PathSource::TupleStruct => match res { + PathSource::TupleStruct(_) => match res { Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..) => true, _ => false, }, @@ -336,8 +336,8 @@ impl<'a> PathSource<'a> { (PathSource::Struct, false) => error_code!(E0422), (PathSource::Expr(..), true) => error_code!(E0423), (PathSource::Expr(..), false) => error_code!(E0425), - (PathSource::Pat | PathSource::TupleStruct, true) => error_code!(E0532), - (PathSource::Pat | PathSource::TupleStruct, false) => error_code!(E0531), + (PathSource::Pat | PathSource::TupleStruct(_), true) => error_code!(E0532), + (PathSource::Pat | PathSource::TupleStruct(_), false) => error_code!(E0531), (PathSource::TraitItem(..), true) => error_code!(E0575), (PathSource::TraitItem(..), false) => error_code!(E0576), } @@ -760,7 +760,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.r.report_error( original_span, ResolutionError::UnreachableLabel { - name: &label.name.as_str(), + name: label.name, definition_span: ident.span, suggestion, }, @@ -777,7 +777,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.r.report_error( original_span, - ResolutionError::UndeclaredLabel { name: &label.name.as_str(), suggestion }, + ResolutionError::UndeclaredLabel { name: label.name, suggestion }, ); None } @@ -1483,7 +1483,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.r.record_partial_res(pat.id, PartialRes::new(res)); } PatKind::TupleStruct(ref path, ..) => { - self.smart_resolve_path(pat.id, None, path, PathSource::TupleStruct); + self.smart_resolve_path(pat.id, None, path, PathSource::TupleStruct(pat.span)); } PatKind::Path(ref qself, ref path) => { self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Pat); @@ -1550,7 +1550,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // `Variant(a, a)`: _ => IdentifierBoundMoreThanOnceInSamePattern, }; - self.r.report_error(ident.span, error(&ident.as_str())); + self.r.report_error(ident.span, error(ident.name)); } // Record as bound if it's valid: diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs index fc41ce5d53511..95888c38ba5e1 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/src/librustc_resolve/late/diagnostics.rs @@ -480,10 +480,12 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { let mut bad_struct_syntax_suggestion = |def_id: DefId| { let (followed_by_brace, closing_brace) = self.followed_by_brace(span); - let mut suggested = false; + match source { - PathSource::Expr(Some(parent)) => { - suggested = path_sep(err, &parent); + PathSource::Expr(Some( + parent @ Expr { kind: ExprKind::Field(..) | ExprKind::MethodCall(..), .. }, + )) => { + path_sep(err, &parent); } PathSource::Expr(None) if followed_by_brace => { if let Some(sp) = closing_brace { @@ -505,15 +507,56 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { ), ); } - suggested = true; } - _ => {} - } - if !suggested { - if let Some(span) = self.r.opt_span(def_id) { - err.span_label(span, &format!("`{}` defined here", path_str)); + PathSource::Expr( + None | Some(Expr { kind: ExprKind::Call(..) | ExprKind::Path(..), .. }), + ) + | PathSource::TupleStruct(_) + | PathSource::Pat => { + let span = match &source { + PathSource::Expr(Some(Expr { + span, kind: ExprKind::Call(_, _), .. + })) + | PathSource::TupleStruct(span) => { + // We want the main underline to cover the suggested code as well for + // cleaner output. + err.set_span(*span); + *span + } + _ => span, + }; + if let Some(span) = self.r.opt_span(def_id) { + err.span_label(span, &format!("`{}` defined here", path_str)); + } + let (tail, descr, applicability) = match source { + PathSource::Pat | PathSource::TupleStruct(_) => { + ("", "pattern", Applicability::MachineApplicable) + } + _ => (": val", "literal", Applicability::HasPlaceholders), + }; + let (fields, applicability) = match self.r.field_names.get(&def_id) { + Some(fields) => ( + fields + .iter() + .map(|f| format!("{}{}", f.node, tail)) + .collect::>() + .join(", "), + applicability, + ), + None => ("/* fields */".to_string(), Applicability::HasPlaceholders), + }; + let pad = match self.r.field_names.get(&def_id) { + Some(fields) if fields.is_empty() => "", + _ => " ", + }; + err.span_suggestion( + span, + &format!("use struct {} syntax instead", descr), + format!("{} {{{pad}{}{pad}}}", path_str, fields, pad = pad), + applicability, + ); } - err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?", path_str)); + _ => {} } }; @@ -546,7 +589,10 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { return false; } } - (Res::Def(DefKind::Enum, def_id), PathSource::TupleStruct | PathSource::Expr(..)) => { + ( + Res::Def(DefKind::Enum, def_id), + PathSource::TupleStruct(_) | PathSource::Expr(..), + ) => { if let Some(variants) = self.collect_enum_variants(def_id) { if !variants.is_empty() { let msg = if variants.len() == 1 { @@ -765,7 +811,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { match find_best_match_for_name( names.iter().map(|suggestion| &suggestion.candidate), - &name.as_str(), + name, None, ) { Some(found) if found != name => { @@ -1008,7 +1054,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { .filter(|(id, _)| id.span.ctxt() == label.span.ctxt()) .map(|(id, _)| &id.name); - find_best_match_for_name(names, &label.as_str(), None).map(|symbol| { + find_best_match_for_name(names, label.name, None).map(|symbol| { // Upon finding a similar name, get the ident that it was from - the span // contained within helps make a useful diagnostic. In addition, determine // whether this candidate is within scope. diff --git a/src/librustc_resolve/late/lifetimes.rs b/src/librustc_resolve/late/lifetimes.rs index 1467bf537eb49..567db8edec9af 100644 --- a/src/librustc_resolve/late/lifetimes.rs +++ b/src/librustc_resolve/late/lifetimes.rs @@ -2364,7 +2364,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { if let Some(params) = error { // If there's no lifetime available, suggest `'static`. if self.report_elision_failure(&mut err, params) && lifetime_names.is_empty() { - lifetime_names.insert(Ident::from_str("'static")); + lifetime_names.insert(Ident::with_dummy_span(kw::StaticLifetime)); } } self.add_missing_lifetime_specifiers_label( diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0f1618031d034..a265c15c18bc9 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -193,11 +193,11 @@ enum ResolutionError<'a> { /// Error E0409: variable `{}` is bound in inconsistent ways within the same match arm. VariableBoundWithDifferentMode(Symbol, Span), /// Error E0415: identifier is bound more than once in this parameter list. - IdentifierBoundMoreThanOnceInParameterList(&'a str), + IdentifierBoundMoreThanOnceInParameterList(Symbol), /// Error E0416: identifier is bound more than once in the same pattern. - IdentifierBoundMoreThanOnceInSamePattern(&'a str), + IdentifierBoundMoreThanOnceInSamePattern(Symbol), /// Error E0426: use of undeclared label. - UndeclaredLabel { name: &'a str, suggestion: Option }, + UndeclaredLabel { name: Symbol, suggestion: Option }, /// Error E0429: `self` imports are only allowed within a `{ }` list. SelfImportsOnlyAllowedWithin { root: bool, span_with_rename: Span }, /// Error E0430: `self` import can only appear once in the list. @@ -211,13 +211,13 @@ enum ResolutionError<'a> { /// Error E0435: attempt to use a non-constant value in a constant. AttemptToUseNonConstantValueInConstant, /// Error E0530: `X` bindings cannot shadow `Y`s. - BindingShadowsSomethingUnacceptable(&'a str, Symbol, &'a NameBinding<'a>), + BindingShadowsSomethingUnacceptable(&'static str, Symbol, &'a NameBinding<'a>), /// Error E0128: type parameters with a default cannot use forward-declared identifiers. ForwardDeclaredTyParam, // FIXME(const_generics:defaults) /// Error E0735: type parameters with a default cannot use `Self` SelfInTyParamDefault, /// Error E0767: use of unreachable label - UnreachableLabel { name: &'a str, definition_span: Span, suggestion: Option }, + UnreachableLabel { name: Symbol, definition_span: Span, suggestion: Option }, } enum VisResolutionError<'a> { diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 5ecb256719f1f..e29bc9f078ddb 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -824,7 +824,7 @@ impl<'tcx> SaveContext<'tcx> { for attr in attrs { if let Some(val) = attr.doc_str() { if attr.is_doc_comment() { - result.push_str(&strip_doc_comment_decoration(&val.as_str())); + result.push_str(&strip_doc_comment_decoration(val)); } else { result.push_str(&val.as_str()); } diff --git a/src/librustc_session/cgu_reuse_tracker.rs b/src/librustc_session/cgu_reuse_tracker.rs index 2f06ff95b1923..ace233611223c 100644 --- a/src/librustc_session/cgu_reuse_tracker.rs +++ b/src/librustc_session/cgu_reuse_tracker.rs @@ -4,7 +4,7 @@ use log::debug; use rustc_data_structures::fx::FxHashMap; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use std::sync::{Arc, Mutex}; #[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] @@ -67,7 +67,7 @@ impl CguReuseTracker { pub fn set_expectation( &self, - cgu_name: &str, + cgu_name: Symbol, cgu_user_name: &str, error_span: Span, expected_reuse: CguReuse, diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index c5a866817cb4a..348fe105a4315 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -717,18 +717,20 @@ pub fn default_configuration(sess: &Session) -> CrateConfig { let mut ret = FxHashSet::default(); ret.reserve(6); // the minimum number of insertions // Target bindings. - ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os)))); + ret.insert((sym::target_os, Some(Symbol::intern(os)))); if let Some(ref fam) = sess.target.target.options.target_family { - ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam)))); - if fam == "windows" || fam == "unix" { - ret.insert((Symbol::intern(fam), None)); + ret.insert((sym::target_family, Some(Symbol::intern(fam)))); + if fam == "windows" { + ret.insert((sym::windows, None)); + } else if fam == "unix" { + ret.insert((sym::unix, None)); } } - ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch)))); - ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end)))); - ret.insert((Symbol::intern("target_pointer_width"), Some(Symbol::intern(wordsz)))); - ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env)))); - ret.insert((Symbol::intern("target_vendor"), Some(Symbol::intern(vendor)))); + ret.insert((sym::target_arch, Some(Symbol::intern(arch)))); + ret.insert((sym::target_endian, Some(Symbol::intern(end)))); + ret.insert((sym::target_pointer_width, Some(Symbol::intern(wordsz)))); + ret.insert((sym::target_env, Some(Symbol::intern(env)))); + ret.insert((sym::target_vendor, Some(Symbol::intern(vendor)))); if sess.target.target.options.has_elf_tls { ret.insert((sym::target_thread_local, None)); } @@ -754,7 +756,7 @@ pub fn default_configuration(sess: &Session) -> CrateConfig { } if sess.opts.debug_assertions { - ret.insert((Symbol::intern("debug_assertions"), None)); + ret.insert((sym::debug_assertions, None)); } if sess.opts.crate_types.contains(&CrateType::ProcMacro) { ret.insert((sym::proc_macro, None)); diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 6b3dbd0bf7a05..0e9df5feb32ba 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -102,16 +102,23 @@ symbols! { Union: "union", } - // Symbols that can be referred to with rustc_span::sym::*. The symbol is - // the stringified identifier unless otherwise specified (e.g. - // `proc_dash_macro` represents "proc-macro"). + // Pre-interned symbols that can be referred to with `rustc_span::sym::*`. + // + // The symbol is the stringified identifier unless otherwise specified, in + // which case the name should mention the non-identifier punctuation. + // E.g. `sym::proc_dash_macro` represents "proc-macro", and it shouldn't be + // called `sym::proc_macro` because then it's easy to mistakenly think it + // represents "proc_macro". // // As well as the symbols listed, there are symbols for the the strings // "0", "1", ..., "9", which are accessible via `sym::integer`. + // + // Keep this list in sorted order, as defined by the Unix `sort` utility. Symbols { aarch64_target_feature, abi, abi_amdgpu_kernel, + abi_avr_interrupt, abi_efiapi, abi_msp430_interrupt, abi_ptx, @@ -120,20 +127,25 @@ symbols! { abi_unadjusted, abi_vectorcall, abi_x86_interrupt, - abi_avr_interrupt, abort, aborts, + add, + add_assign, address, add_with_overflow, advanced_slice_patterns, adx_target_feature, alias, align, + align_offset, alignstack, all, + alloc, allocator, allocator_internals, alloc_error_handler, + alloc_layout, + alloc_zeroed, allow, allowed, allow_fail, @@ -150,15 +162,18 @@ symbols! { ArgumentV1, arith_offset, arm_target_feature, + array, asm, assert, assert_inhabited, + assert_receiver_is_total_eq, assert_uninit_valid, assert_zero_valid, associated_consts, associated_type_bounds, associated_type_defaults, associated_types, + as_str, assume, assume_init, async_await, @@ -177,19 +192,29 @@ symbols! { bin, bind_by_move_pattern_guards, bindings_after_at, + bitand, + bitand_assign, + bitor, + bitor_assign, + bitreverse, + bitxor, + bitxor_assign, block, bool, borrowck_graphviz_format, borrowck_graphviz_postflow, borrowck_graphviz_preflow, + box_free, box_patterns, box_syntax, braced_empty_structs, breakpoint, bswap, - bitreverse, C, + call, caller_location, + call_mut, + call_once, cdylib, ceilf32, ceilf64, @@ -213,6 +238,7 @@ symbols! { closure_to_fn_coercion, cmp, cmpxchg16b_target_feature, + coerce_unsized, cold, column, compile_error, @@ -230,24 +256,26 @@ symbols! { const_fn_union, const_generics, const_if_match, - const_indexing, const_in_array_repeat_expressions, + const_indexing, const_let, const_loop, const_mut_refs, const_panic, const_precise_live_drops, + const_ptr, const_raw_ptr_deref, const_raw_ptr_to_usize_cast, - const_transmute, + const_slice_ptr, const_trait_bound_opt_out, const_trait_impl, + const_transmute, contents, context, convert, + copy, Copy, copy_closures, - copy, copy_nonoverlapping, copysignf32, copysignf64, @@ -265,22 +293,27 @@ symbols! { crate_name, crate_type, crate_visibility_modifier, + crt_dash_static: "crt-static", + ctlz, + ctlz_nonzero, ctpop, cttz, cttz_nonzero, - ctlz, - ctlz_nonzero, custom_attribute, custom_derive, custom_inner_attributes, custom_test_frameworks, c_variadic, + dead_code, + dealloc, + debug, + Debug, + debug_assertions, debug_trait, declare_lint_pass, decl_macro, - debug, - Debug, Decodable, + decode, Default, default_lib_allocator, default_type_parameter_fallback, @@ -293,7 +326,11 @@ symbols! { derive, diagnostic, direct, + discriminant_kind, discriminant_value, + dispatch_from_dyn, + div, + div_assign, doc, doc_alias, doc_cfg, @@ -303,40 +340,44 @@ symbols! { document_private_items, dotdoteq_in_patterns, dotdot_in_tuple_patterns, + double_braced_closure: "{{closure}}", + double_braced_constant: "{{constant}}", + double_braced_constructor: "{{constructor}}", double_braced_crate: "{{crate}}", double_braced_impl: "{{impl}}", double_braced_misc: "{{misc}}", - double_braced_closure: "{{closure}}", - double_braced_constructor: "{{constructor}}", - double_braced_constant: "{{constant}}", double_braced_opaque: "{{opaque}}", + drop, dropck_eyepatch, dropck_parametricity, - drop_types_in_const, drop_in_place, + drop_types_in_const, dylib, dyn_trait, + eh_catch_typeinfo, eh_personality, enable, + enclosing_scope, Encodable, + encode, env, eq, - err, - Err, Eq, Equal, - enclosing_scope, + err, + Err, exact_div, except, + exchange_malloc, exclusive_range_pattern, exhaustive_integer_patterns, exhaustive_patterns, existential_type, - expf32, - expf64, exp2f32, exp2f64, expected, + expf32, + expf64, export_name, expr, extern_absolute_paths, @@ -348,10 +389,12 @@ symbols! { extern_types, f16c_target_feature, f32, + f32_runtime, f64, - fadd_fast, + f64_runtime, fabsf32, fabsf64, + fadd_fast, fdiv_fast, feature, ffi_const, @@ -361,19 +404,23 @@ symbols! { field_init_shorthand, file, float_to_int_unchecked, - floorf64, floorf32, + floorf64, fmaf32, fmaf64, fmt, fmt_internals, fmul_fast, fn_must_use, + fn_mut, + fn_once, + fn_once_output, forbid, forget, format_args, - format_args_nl, format_args_capture, + format_args_nl, + freeze, frem_fast, from, From, @@ -382,28 +429,35 @@ symbols! { from_generator, from_method, from_ok, - from_usize, + from_size_align_unchecked, from_trait, + from_usize, fsub_fast, fundamental, future, Future, - FxHashSet, + future_trait, FxHashMap, - gen_future, - gen_kill, + FxHashSet, + ge, + generator, generators, + generator_state, generic_associated_types, generic_param_attrs, + gen_future, + gen_kill, get_context, + GlobalAlloc, global_allocator, global_asm, globs, + gt, half_open_range_patterns, hash, Hash, - HashSet, HashMap, + HashSet, hexagon_target_feature, hidden, homogeneous_aggregate, @@ -422,22 +476,22 @@ symbols! { if_let, if_while_or_patterns, ignore, - inlateout, - inout, impl_header_lifetime_elision, impl_lint_pass, impl_trait_in_bindings, import_shadowing, - index, - index_mut, in_band_lifetimes, include, include_bytes, include_str, inclusive_range_syntax, + index, + index_mut, infer_outlives_requirements, infer_static_outlives_requirements, + inlateout, inline, + inout, Input, intel, into_iter, @@ -460,11 +514,14 @@ symbols! { label_break_value, lang, lang_items, - lazy_normalization_consts, lateout, + Layout, + lazy_normalization_consts, + le, let_chains, lhs, lib, + libc, lifetime, likely, line, @@ -481,14 +538,15 @@ symbols! { literal, llvm_asm, local_inner_macros, - log_syntax, - logf32, - logf64, log10f32, log10f64, log2f32, log2f64, + logf32, + logf64, + log_syntax, loop_break_value, + lt, macro_at_most_once_rep, macro_escape, macro_export, @@ -500,57 +558,66 @@ symbols! { macro_vis_matcher, main, managed_boxes, + manually_drop, marker, marker_trait_attr, masked, match_beginning_vert, match_default_bindings, - may_dangle, + maxnumf32, + maxnumf64, + maybe_uninit, maybe_uninit_uninit, maybe_uninit_zeroed, - mem_uninitialized, - mem_zeroed, + may_dangle, member_constraints, memory, + mem_uninitialized, + mem_zeroed, message, meta, min_align_of, min_align_of_val, min_const_fn, min_const_unsafe_fn, - min_specialization, minnumf32, minnumf64, - maxnumf32, - maxnumf64, + min_specialization, mips_target_feature, miri_start_panic, mmx_target_feature, module, module_path, more_struct_aliases, + movbe_target_feature, move_ref_pattern, move_val_init, - movbe_target_feature, + mul, + mul_assign, mul_with_overflow, must_use, + mut_ptr, + mut_slice_ptr, naked, naked_functions, name, + ne, nearbyintf32, nearbyintf64, needs_allocator, needs_drop, needs_panic_runtime, + neg, negate_unsigned, negative_impls, never, never_type, never_type_fallback, new, - next, __next, + next, nll, + no, no_builtins, no_core, no_crate_inject, @@ -565,11 +632,11 @@ symbols! { non_ascii_idents, None, non_exhaustive, + no_niche, non_modrs_mods, nontemporal_store, - nontrapping_fptoint: "nontrapping-fptoint", + nontrapping_dash_fptoint: "nontrapping-fptoint", noreturn, - no_niche, no_sanitize, nostack, no_stack_check, @@ -584,6 +651,7 @@ symbols! { on, on_unimplemented, oom, + opaque, ops, optimize, optimize_attribute, @@ -592,30 +660,39 @@ symbols! { Option, option_env, options, + option_type, opt_out_copy, or, - or_patterns, Ord, Ordering, + or_patterns, out, Output, overlapping_marker_traits, + owned_box, packed, panic, + panic_abort, + panic_bounds_check, panic_handler, panic_impl, panic_implementation, + panic_info, + panic_location, panic_runtime, + panic_unwind, + param_attrs, parent_trait, partial_cmp, - param_attrs, PartialEq, + partial_ord, PartialOrd, passes, pat, path, pattern_parentheses, Pending, + phantom_data, pin, Pin, pinned, @@ -623,14 +700,17 @@ symbols! { plugin, plugin_registrar, plugins, + pointer, poll, Poll, + post_dash_lto: "post-lto", powerpc_target_feature, powf32, powf64, powif32, powif64, precise_pointer_size_matching, + pre_dash_lto: "pre-lto", pref_align_of, prefetch_read_data, prefetch_read_instruction, @@ -641,19 +721,19 @@ symbols! { preserves_flags, primitive, proc_dash_macro: "proc-macro", + ProceduralMasqueradeDummyType, proc_macro, proc_macro_attribute, proc_macro_def_site, proc_macro_derive, proc_macro_expr, proc_macro_gen, + ProcMacroHack, proc_macro_hygiene, proc_macro_internals, proc_macro_mod, proc_macro_non_items, proc_macro_path_invoc, - ProceduralMasqueradeDummyType, - ProcMacroHack, profiler_builtins, profiler_runtime, ptr_guaranteed_eq, @@ -677,13 +757,18 @@ symbols! { Rc, readonly, Ready, + realloc, reason, + receiver, recursion_limit, reexport_test_harness_main, + reference, reflect, register_attr, register_tool, relaxed_adts, + rem, + rem_assign, repr, repr128, repr_align, @@ -695,6 +780,7 @@ symbols! { re_rebalance_coherence, result, Result, + result_type, Return, rhs, rintf32, @@ -712,8 +798,6 @@ symbols! { rust_2018_preview, rust_begin_unwind, rustc, - RustcDecodable, - RustcEncodable, rustc_allocator, rustc_allocator_nounwind, rustc_allow_const_fn_ptr, @@ -721,9 +805,10 @@ symbols! { rustc_attrs, rustc_builtin_macro, rustc_clean, - rustc_const_unstable, rustc_const_stable, + rustc_const_unstable, rustc_conversion_suggestion, + RustcDecodable, rustc_def_path, rustc_deprecated, rustc_diagnostic_item, @@ -733,6 +818,7 @@ symbols! { rustc_dump_env_program_clauses, rustc_dump_program_clauses, rustc_dump_user_substs, + RustcEncodable, rustc_error, rustc_expected_cgu_reuse, rustc_if_this_changed, @@ -751,26 +837,28 @@ symbols! { rustc_partition_reused, rustc_peek, rustc_peek_definite_init, + rustc_peek_indirectly_mutable, rustc_peek_liveness, rustc_peek_maybe_init, rustc_peek_maybe_uninit, - rustc_peek_indirectly_mutable, rustc_private, rustc_proc_macro_decls, rustc_promotable, rustc_regions, - rustc_unsafe_specialization_marker, + rustc_reservation_impl, rustc_specialization_trait, rustc_stable, rustc_std_internal_symbol, rustc_symbol_name, rustc_synthetic, - rustc_reservation_impl, rustc_test_marker, rustc_then_this_would_need, + rustc_unsafe_specialization_marker, rustc_variance, - rustfmt, rust_eh_personality, + rust_eh_register_frames, + rust_eh_unregister_frames, + rustfmt, rust_oom, rvalue_static_promotion, sanitize, @@ -780,19 +868,83 @@ symbols! { _Self, self_in_typedefs, self_struct_ctor, + semitransparent, + Send, send_trait, + shl, + shl_assign, should_panic, + shr, + shr_assign, simd, + simd_add, + simd_and, + simd_bitmask, + simd_cast, + simd_ceil, + simd_div, + simd_eq, simd_extract, + simd_fabs, + simd_fcos, + simd_fexp, + simd_fexp2, simd_ffi, + simd_flog, + simd_flog10, + simd_flog2, + simd_floor, + simd_fma, + simd_fmax, + simd_fmin, + simd_fpow, + simd_fpowi, + simd_fsin, + simd_fsqrt, + simd_gather, + simd_ge, + simd_gt, simd_insert, + simd_le, + simd_lt, + simd_mul, + simd_ne, + simd_or, + simd_reduce_add_ordered, + simd_reduce_add_unordered, + simd_reduce_all, + simd_reduce_and, + simd_reduce_any, + simd_reduce_max, + simd_reduce_max_nanless, + simd_reduce_min, + simd_reduce_min_nanless, + simd_reduce_mul_ordered, + simd_reduce_mul_unordered, + simd_reduce_or, + simd_reduce_xor, + simd_rem, + simd_saturating_add, + simd_saturating_sub, + simd_scatter, + simd_select, + simd_select_bitmask, + simd_shl, + simd_shr, + simd_sub, + simd_xor, since, sinf32, sinf64, size, + sized, size_of, size_of_val, + slice, + slice_alloc, slice_patterns, + slice_u8, + slice_u8_alloc, slicing_syntax, soft, Some, @@ -810,28 +962,45 @@ symbols! { static_recursion, std, std_inject, - str, - stringify, stmt, stmt_expr_attributes, stop_after_dataflow, + str, + str_alloc, + stringify, struct_field_attributes, struct_inherit, structural_match, + structural_peq, + structural_teq, struct_variant, sty, + sub, + sub_assign, sub_with_overflow, suggestion, sym, + sync, + Sync, sync_trait, + Target, + target_arch, + target_endian, + target_env, + target_family, target_feature, target_feature_11, target_has_atomic, target_has_atomic_load_store, + target_os, + target_pointer_width, + target_target_vendor, target_thread_local, + target_vendor, task, _task_context, tbm_target_feature, + termination, termination_trait, termination_trait_test, test, @@ -859,19 +1028,20 @@ symbols! { try_blocks, try_trait, tt, + tuple, tuple_indexing, two_phase, - Ty, ty, - type_alias_impl_trait, - type_id, - type_name, + Ty, TyCtxt, TyKind, type_alias_enum_variants, + type_alias_impl_trait, type_ascription, + type_id, type_length_limit, type_macros, + type_name, u128, u16, u32, @@ -891,18 +1061,24 @@ symbols! { underscore_imports, underscore_lifetimes, uniform_paths, + unit, universal_impl_trait, + unix, unlikely, unmarked_api, + unpin, unreachable, unreachable_code, unrestricted_attribute_tokens, unsafe_block_in_unsafe_fn, + unsafe_cell, unsafe_no_drop_flag, + unsize, unsized_locals, unsized_tuple_coercion, unstable, untagged_unions, + unused_qualifications, unwind, unwind_attributes, unwrap_or, @@ -911,15 +1087,17 @@ symbols! { use_nested_groups, usize, v1, - val, - var, - variant_count, va_arg, va_copy, va_end, + val, + va_list, + var, + variant_count, va_start, vec, Vec, + vec_type, version, vis, visible_private_types, @@ -936,8 +1114,8 @@ symbols! { windows, windows_subsystem, wrapping_add, - wrapping_sub, wrapping_mul, + wrapping_sub, write_bytes, Yield, } @@ -1419,7 +1597,7 @@ impl !Sync for SymbolStr {} /// This impl means that if `ss` is a `SymbolStr`: /// - `*ss` is a `str`; -/// - `&*ss` is a `&str`; +/// - `&*ss` is a `&str` (and `match &*ss { ... }` is a common pattern). /// - `&ss as &str` is a `&str`, which means that `&ss` can be passed to a /// function expecting a `&str`. impl std::ops::Deref for SymbolStr { diff --git a/src/librustc_target/spec/linux_kernel_base.rs b/src/librustc_target/spec/linux_kernel_base.rs index 201d6a0fff93b..6d929d1244789 100644 --- a/src/librustc_target/spec/linux_kernel_base.rs +++ b/src/librustc_target/spec/linux_kernel_base.rs @@ -17,7 +17,6 @@ pub fn opts() -> TargetOptions { needs_plt: true, relro_level: RelroLevel::Full, relocation_model: RelocModel::Static, - target_family: Some("unix".to_string()), pre_link_args, ..Default::default() diff --git a/src/librustc_trait_selection/autoderef.rs b/src/librustc_trait_selection/autoderef.rs index d542e16d83f10..cc971440feac5 100644 --- a/src/librustc_trait_selection/autoderef.rs +++ b/src/librustc_trait_selection/autoderef.rs @@ -6,7 +6,7 @@ use rustc_infer::infer::InferCtxt; use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness}; use rustc_middle::ty::{ToPredicate, TypeFoldable}; use rustc_session::DiagnosticMessageId; -use rustc_span::symbol::Ident; +use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; #[derive(Copy, Clone, Debug)] @@ -143,7 +143,11 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { let normalized_ty = fulfillcx.normalize_projection_type( &self.infcx, self.param_env, - ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, Ident::from_str("Target")), + ty::ProjectionTy::from_ref_and_name( + tcx, + trait_ref, + Ident::with_dummy_span(sym::Target), + ), cause, ); if let Err(e) = fulfillcx.select_where_possible(&self.infcx) { diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index ad6e81ed3e889..4ade1ce91632f 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -376,7 +376,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // If it has a custom `#[rustc_on_unimplemented]` // error message, let's display it as the label! err.span_label(span, s.as_str()); - err.help(&explanation); + if !matches!(trait_ref.skip_binder().self_ty().kind, ty::Param(_)) { + // When the self type is a type param We don't need to "the trait + // `std::marker::Sized` is not implemented for `T`" as we will point + // at the type param with a label to suggest constraining it. + err.help(&explanation); + } } else { err.span_label(span, explanation); } @@ -403,7 +408,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } self.suggest_dereferences(&obligation, &mut err, &trait_ref, points_at_arg); - self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err); self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg); self.suggest_remove_reference(&obligation, &mut err, &trait_ref); self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref); diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index d677d84b2ba13..2c6589eb2bdf9 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -43,12 +43,6 @@ pub trait InferCtxtExt<'tcx> { body_id: hir::HirId, ); - fn suggest_borrow_on_unsized_slice( - &self, - code: &ObligationCauseCode<'tcx>, - err: &mut DiagnosticBuilder<'_>, - ); - fn suggest_dereferences( &self, obligation: &PredicateObligation<'tcx>, @@ -515,32 +509,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } - /// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a - /// suggestion to borrow the initializer in order to use have a slice instead. - fn suggest_borrow_on_unsized_slice( - &self, - code: &ObligationCauseCode<'tcx>, - err: &mut DiagnosticBuilder<'_>, - ) { - if let &ObligationCauseCode::VariableType(hir_id) = code { - let parent_node = self.tcx.hir().get_parent_node(hir_id); - if let Some(Node::Local(ref local)) = self.tcx.hir().find(parent_node) { - if let Some(ref expr) = local.init { - if let hir::ExprKind::Index(_, _) = expr.kind { - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(expr.span) { - err.span_suggestion( - expr.span, - "consider borrowing here", - format!("&{}", snippet), - Applicability::MachineApplicable, - ); - } - } - } - } - } - } - /// Given a closure's `DefId`, return the given name of the closure. /// /// This doesn't account for reassignments, but it's only used for suggestions. @@ -1817,15 +1785,56 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } } - ObligationCauseCode::VariableType(_) => { - err.note("all local variables must have a statically known size"); + ObligationCauseCode::VariableType(hir_id) => { + let parent_node = self.tcx.hir().get_parent_node(hir_id); + match self.tcx.hir().find(parent_node) { + Some(Node::Local(hir::Local { + init: Some(hir::Expr { kind: hir::ExprKind::Index(_, _), span, .. }), + .. + })) => { + // When encountering an assignment of an unsized trait, like + // `let x = ""[..];`, provide a suggestion to borrow the initializer in + // order to use have a slice instead. + err.span_suggestion_verbose( + span.shrink_to_lo(), + "consider borrowing here", + "&".to_owned(), + Applicability::MachineApplicable, + ); + err.note("all local variables must have a statically known size"); + } + Some(Node::Param(param)) => { + err.span_suggestion_verbose( + param.ty_span.shrink_to_lo(), + "function arguments must have a statically known size, borrowed types \ + always have a known size", + "&".to_owned(), + Applicability::MachineApplicable, + ); + } + _ => { + err.note("all local variables must have a statically known size"); + } + } if !self.tcx.features().unsized_locals { err.help("unsized locals are gated as an unstable feature"); } } - ObligationCauseCode::SizedArgumentType => { - err.note("all function arguments must have a statically known size"); - if !self.tcx.features().unsized_locals { + ObligationCauseCode::SizedArgumentType(sp) => { + if let Some(span) = sp { + err.span_suggestion_verbose( + span.shrink_to_lo(), + "function arguments must have a statically known size, borrowed types \ + always have a known size", + "&".to_string(), + Applicability::MachineApplicable, + ); + } else { + err.note("all function arguments must have a statically known size"); + } + if tcx.sess.opts.unstable_features.is_nightly_build() + && !self.tcx.features().unsized_locals + { err.help("unsized locals are gated as an unstable feature"); } } @@ -1844,26 +1853,44 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ObligationCauseCode::StructInitializerSized => { err.note("structs must have a statically known size to be initialized"); } - ObligationCauseCode::FieldSized { adt_kind: ref item, last } => match *item { - AdtKind::Struct => { - if last { - err.note( - "the last field of a packed struct may only have a \ - dynamically sized type if it does not need drop to be run", - ); - } else { - err.note( - "only the last field of a struct may have a dynamically sized type", - ); + ObligationCauseCode::FieldSized { adt_kind: ref item, last, span } => { + match *item { + AdtKind::Struct => { + if last { + err.note( + "the last field of a packed struct may only have a \ + dynamically sized type if it does not need drop to be run", + ); + } else { + err.note( + "only the last field of a struct may have a dynamically sized type", + ); + } + } + AdtKind::Union => { + err.note("no field of a union may have a dynamically sized type"); + } + AdtKind::Enum => { + err.note("no field of an enum variant may have a dynamically sized type"); } } - AdtKind::Union => { - err.note("no field of a union may have a dynamically sized type"); - } - AdtKind::Enum => { - err.note("no field of an enum variant may have a dynamically sized type"); - } - }, + err.help("change the field's type to have a statically known size"); + err.span_suggestion( + span.shrink_to_lo(), + "borrowed types always have a statically known size", + "&".to_string(), + Applicability::MachineApplicable, + ); + err.multipart_suggestion( + "the `Box` type always has a statically known size and allocates its contents \ + in the heap", + vec![ + (span.shrink_to_lo(), "Box<".to_string()), + (span.shrink_to_hi(), ">".to_string()), + ], + Applicability::MachineApplicable, + ); + } ObligationCauseCode::ConstSized => { err.note("constant expressions must have a statically known size"); } diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index 9329069c48dd1..93b503c976be4 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -18,6 +18,7 @@ rustc_attr = { path = "../librustc_attr" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_hir = { path = "../librustc_hir" } +rustc_hir_pretty = { path = "../librustc_hir_pretty" } rustc_target = { path = "../librustc_target" } rustc_session = { path = "../librustc_session" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 5d1949626dd84..616f5d90395e1 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1247,7 +1247,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .generic_args() .bindings .iter() - .find_map(|b| match (b.ident.as_str() == "Output", &b.kind) { + .find_map(|b| match (b.ident.name == sym::Output, &b.kind) { (true, hir::TypeBindingKind::Equality { ty }) => { sess.source_map().span_to_snippet(ty.span).ok() } @@ -2254,7 +2254,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .collect(); if let (Some(suggested_name), true) = ( - find_best_match_for_name(all_candidate_names.iter(), &assoc_name.as_str(), None), + find_best_match_for_name(all_candidate_names.iter(), assoc_name.name, None), assoc_name.span != DUMMY_SP, ) { err.span_suggestion( @@ -2354,7 +2354,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT"); if let Some(suggested_name) = find_best_match_for_name( adt_def.variants.iter().map(|variant| &variant.ident.name), - &assoc_ident.as_str(), + assoc_ident.name, None, ) { err.span_suggestion( @@ -3049,14 +3049,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let bare_fn_ty = ty::Binder::bind(tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, unsafety, abi)); - if let (false, Some(ident_span)) = (self.allow_ty_infer(), ident_span) { + if !self.allow_ty_infer() { // We always collect the spans for placeholder types when evaluating `fn`s, but we // only want to emit an error complaining about them if infer types (`_`) are not // allowed. `allow_ty_infer` gates this behavior. We check for the presence of // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`. crate::collect::placeholder_type_error( tcx, - ident_span.shrink_to_hi(), + ident_span.map(|sp| sp.shrink_to_hi()), &generics.params[..], visitor.0, true, diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 308ed5d840202..9930a60032734 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -13,7 +13,7 @@ use rustc_middle::ty::adjustment::{ }; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc_span::symbol::Ident; +use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use rustc_target::spec::abi; use rustc_trait_selection::autoderef::Autoderef; @@ -192,9 +192,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Option<(Option>, MethodCallee<'tcx>)> { // Try the options that are least restrictive on the caller first. for &(opt_trait_def_id, method_name, borrow) in &[ - (self.tcx.lang_items().fn_trait(), Ident::from_str("call"), true), - (self.tcx.lang_items().fn_mut_trait(), Ident::from_str("call_mut"), true), - (self.tcx.lang_items().fn_once_trait(), Ident::from_str("call_once"), false), + (self.tcx.lang_items().fn_trait(), Ident::with_dummy_span(sym::call), true), + (self.tcx.lang_items().fn_mut_trait(), Ident::with_dummy_span(sym::call_mut), true), + (self.tcx.lang_items().fn_once_trait(), Ident::with_dummy_span(sym::call_once), false), ] { let trait_def_id = match opt_trait_def_id { Some(def_id) => def_id, diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 1ea7bf25ef2ed..8948e5a3e00db 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -387,6 +387,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { // Check for infer types because cases like `Option<{integer}>` would // panic otherwise. if !expr_ty.has_infer_types() + && !ty.has_infer_types() && fcx.tcx.type_implements_trait(( from_trait, ty, diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index e6b51f4c2cd2a..b29f66312ef2e 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -487,7 +487,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.require_type_is_sized_deferred( input, expr.span, - traits::SizedArgumentType, + traits::SizedArgumentType(None), ); } } @@ -1336,7 +1336,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // prevent all specified fields from being suggested let skip_fields = skip_fields.iter().map(|ref x| x.ident.name); if let Some(field_name) = - Self::suggest_field_name(variant, &field.ident.as_str(), skip_fields.collect()) + Self::suggest_field_name(variant, field.ident.name, skip_fields.collect()) { err.span_suggestion( field.ident.span, @@ -1377,7 +1377,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Return an hint about the closest match in field names fn suggest_field_name( variant: &'tcx ty::VariantDef, - field: &str, + field: Symbol, skip: Vec, ) -> Option { let names = variant.fields.iter().filter_map(|field| { @@ -1621,7 +1621,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field: Ident, ) { if let Some(suggested_field_name) = - Self::suggest_field_name(def.non_enum_variant(), &field.as_str(), vec![]) + Self::suggest_field_name(def.non_enum_variant(), field.name, vec![]) { err.span_suggestion( field.span, diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 9b3b4a67650a2..944e02acd610a 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -423,70 +423,81 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) }; let def_id = tcx.hir().local_def_id(it.hir_id).to_def_id(); - let name = it.ident.as_str(); + let name = it.ident.name; - let (n_tps, inputs, output) = match &*name { - "simd_eq" | "simd_ne" | "simd_lt" | "simd_le" | "simd_gt" | "simd_ge" => { + let (n_tps, inputs, output) = match name { + sym::simd_eq | sym::simd_ne | sym::simd_lt | sym::simd_le | sym::simd_gt | sym::simd_ge => { (2, vec![param(0), param(0)], param(1)) } - "simd_add" - | "simd_sub" - | "simd_mul" - | "simd_rem" - | "simd_div" - | "simd_shl" - | "simd_shr" - | "simd_and" - | "simd_or" - | "simd_xor" - | "simd_fmin" - | "simd_fmax" - | "simd_fpow" - | "simd_saturating_add" - | "simd_saturating_sub" => (1, vec![param(0), param(0)], param(0)), - "simd_fsqrt" | "simd_fsin" | "simd_fcos" | "simd_fexp" | "simd_fexp2" | "simd_flog2" - | "simd_flog10" | "simd_flog" | "simd_fabs" | "simd_floor" | "simd_ceil" => { - (1, vec![param(0)], param(0)) + sym::simd_add + | sym::simd_sub + | sym::simd_mul + | sym::simd_rem + | sym::simd_div + | sym::simd_shl + | sym::simd_shr + | sym::simd_and + | sym::simd_or + | sym::simd_xor + | sym::simd_fmin + | sym::simd_fmax + | sym::simd_fpow + | sym::simd_saturating_add + | sym::simd_saturating_sub => (1, vec![param(0), param(0)], param(0)), + sym::simd_fsqrt + | sym::simd_fsin + | sym::simd_fcos + | sym::simd_fexp + | sym::simd_fexp2 + | sym::simd_flog2 + | sym::simd_flog10 + | sym::simd_flog + | sym::simd_fabs + | sym::simd_floor + | sym::simd_ceil => (1, vec![param(0)], param(0)), + sym::simd_fpowi => (1, vec![param(0), tcx.types.i32], param(0)), + sym::simd_fma => (1, vec![param(0), param(0), param(0)], param(0)), + sym::simd_gather => (3, vec![param(0), param(1), param(2)], param(0)), + sym::simd_scatter => (3, vec![param(0), param(1), param(2)], tcx.mk_unit()), + sym::simd_insert => (2, vec![param(0), tcx.types.u32, param(1)], param(0)), + sym::simd_extract => (2, vec![param(0), tcx.types.u32], param(1)), + sym::simd_cast => (2, vec![param(0)], param(1)), + sym::simd_bitmask => (2, vec![param(0)], param(1)), + sym::simd_select | sym::simd_select_bitmask => { + (2, vec![param(0), param(1), param(1)], param(1)) } - "simd_fpowi" => (1, vec![param(0), tcx.types.i32], param(0)), - "simd_fma" => (1, vec![param(0), param(0), param(0)], param(0)), - "simd_gather" => (3, vec![param(0), param(1), param(2)], param(0)), - "simd_scatter" => (3, vec![param(0), param(1), param(2)], tcx.mk_unit()), - "simd_insert" => (2, vec![param(0), tcx.types.u32, param(1)], param(0)), - "simd_extract" => (2, vec![param(0), tcx.types.u32], param(1)), - "simd_cast" => (2, vec![param(0)], param(1)), - "simd_bitmask" => (2, vec![param(0)], param(1)), - "simd_select" | "simd_select_bitmask" => (2, vec![param(0), param(1), param(1)], param(1)), - "simd_reduce_all" | "simd_reduce_any" => (1, vec![param(0)], tcx.types.bool), - "simd_reduce_add_ordered" | "simd_reduce_mul_ordered" => { + sym::simd_reduce_all | sym::simd_reduce_any => (1, vec![param(0)], tcx.types.bool), + sym::simd_reduce_add_ordered | sym::simd_reduce_mul_ordered => { (2, vec![param(0), param(1)], param(1)) } - "simd_reduce_add_unordered" - | "simd_reduce_mul_unordered" - | "simd_reduce_and" - | "simd_reduce_or" - | "simd_reduce_xor" - | "simd_reduce_min" - | "simd_reduce_max" - | "simd_reduce_min_nanless" - | "simd_reduce_max_nanless" => (2, vec![param(0)], param(1)), - name if name.starts_with("simd_shuffle") => match name["simd_shuffle".len()..].parse() { - Ok(n) => { - let params = vec![param(0), param(0), tcx.mk_array(tcx.types.u32, n)]; - (2, params, param(1)) - } - Err(_) => { - struct_span_err!( - tcx.sess, - it.span, - E0439, - "invalid `simd_shuffle`, needs length: `{}`", - name - ) - .emit(); - return; + sym::simd_reduce_add_unordered + | sym::simd_reduce_mul_unordered + | sym::simd_reduce_and + | sym::simd_reduce_or + | sym::simd_reduce_xor + | sym::simd_reduce_min + | sym::simd_reduce_max + | sym::simd_reduce_min_nanless + | sym::simd_reduce_max_nanless => (2, vec![param(0)], param(1)), + name if name.as_str().starts_with("simd_shuffle") => { + match name.as_str()["simd_shuffle".len()..].parse() { + Ok(n) => { + let params = vec![param(0), param(0), tcx.mk_array(tcx.types.u32, n)]; + (2, params, param(1)) + } + Err(_) => { + struct_span_err!( + tcx.sess, + it.span, + E0439, + "invalid `simd_shuffle`, needs length: `{}`", + name + ) + .emit(); + return; + } } - }, + } _ => { let msg = format!("unrecognized platform-specific intrinsic function: `{}`", name); tcx.sess.struct_span_err(it.span, &msg).emit(); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index ba952df7e4e28..9c5e3cbc93844 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1536,7 +1536,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } else { let best_name = { let names = applicable_close_candidates.iter().map(|cand| &cand.ident.name); - find_best_match_for_name(names, &self.method_name.unwrap().as_str(), None) + find_best_match_for_name(names, self.method_name.unwrap().name, None) } .unwrap(); Ok(applicable_close_candidates diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 44ffabc4c2662..b8e26fc487140 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::print::with_crate_prefix; use rustc_middle::ty::{ self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, }; -use rustc_span::symbol::{kw, Ident}; +use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{source_map, FileName, Span}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::Obligation; @@ -729,7 +729,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let adt_def = actual.ty_adt_def().expect("enum is not an ADT"); if let Some(suggestion) = lev_distance::find_best_match_for_name( adt_def.variants.iter().map(|s| &s.ident.name), - &item_name.as_str(), + item_name.name, None, ) { err.span_suggestion( @@ -743,7 +743,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut fallback_span = true; let msg = "remove this method call"; - if item_name.as_str() == "as_str" && actual.peel_refs().is_str() { + if item_name.name == sym::as_str && actual.peel_refs().is_str() { if let SelfSource::MethodCall(expr) = source { let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index fa7360ce90051..bc01da324b66f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -103,7 +103,7 @@ use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::lang_items::{ FutureTraitLangItem, PinTypeLangItem, SizedTraitLangItem, VaListTypeLangItem, }; -use rustc_hir::{ExprKind, GenericArg, HirIdMap, Item, ItemKind, Node, PatKind, QPath}; +use rustc_hir::{ExprKind, GenericArg, HirIdMap, ItemKind, Node, PatKind, QPath}; use rustc_index::bit_set::BitSet; use rustc_index::vec::Idx; use rustc_infer::infer; @@ -1342,14 +1342,15 @@ fn check_fn<'a, 'tcx>( let inputs_fn = fn_sig.inputs().iter().copied(); for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() { // Check the pattern. - fcx.check_pat_top(¶m.pat, param_ty, try { inputs_hir?.get(idx)?.span }, false); + let ty_span = try { inputs_hir?.get(idx)?.span }; + fcx.check_pat_top(¶m.pat, param_ty, ty_span, false); // Check that argument is Sized. // The check for a non-trivial pattern is a hack to avoid duplicate warnings // for simple cases like `fn foo(x: Trait)`, // where we would error once on the parameter as a whole, and once on the binding `x`. if param.pat.simple_ident().is_none() && !tcx.features().unsized_locals { - fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType); + fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span)); } fcx.write_ty(param.hir_id, param_ty); @@ -2624,34 +2625,31 @@ fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: &ty::AdtDef) { "packed type cannot transitively contain a `#[repr(align)]` type" ); - let hir = tcx.hir(); - let hir_id = hir.as_local_hir_id(def_spans[0].0.expect_local()); - if let Node::Item(Item { ident, .. }) = hir.get(hir_id) { - err.span_note( - tcx.def_span(def_spans[0].0), - &format!("`{}` has a `#[repr(align)]` attribute", ident), - ); - } + err.span_note( + tcx.def_span(def_spans[0].0), + &format!( + "`{}` has a `#[repr(align)]` attribute", + tcx.item_name(def_spans[0].0) + ), + ); if def_spans.len() > 2 { let mut first = true; for (adt_def, span) in def_spans.iter().skip(1).rev() { - let hir_id = hir.as_local_hir_id(adt_def.expect_local()); - if let Node::Item(Item { ident, .. }) = hir.get(hir_id) { - err.span_note( - *span, - &if first { - format!( - "`{}` contains a field of type `{}`", - tcx.type_of(def.did), - ident - ) - } else { - format!("...which contains a field of type `{}`", ident) - }, - ); - first = false; - } + let ident = tcx.item_name(*adt_def); + err.span_note( + *span, + &if first { + format!( + "`{}` contains a field of type `{}`", + tcx.type_of(def.did), + ident + ) + } else { + format!("...which contains a field of type `{}`", ident) + }, + ); + first = false; } } diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index a1e060b97ad28..b61aa73bb0184 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -13,7 +13,7 @@ use rustc_middle::ty::TyKind::{Adt, Array, Char, FnDef, Never, Ref, Str, Tuple, use rustc_middle::ty::{ self, suggest_constraining_type_param, Ty, TyCtxt, TypeFoldable, TypeVisitor, }; -use rustc_span::symbol::Ident; +use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use rustc_trait_selection::infer::InferCtxtExt; @@ -702,16 +702,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let (opname, trait_did) = if let Op::Binary(op, IsAssign::Yes) = op { match op.node { - hir::BinOpKind::Add => ("add_assign", lang.add_assign_trait()), - hir::BinOpKind::Sub => ("sub_assign", lang.sub_assign_trait()), - hir::BinOpKind::Mul => ("mul_assign", lang.mul_assign_trait()), - hir::BinOpKind::Div => ("div_assign", lang.div_assign_trait()), - hir::BinOpKind::Rem => ("rem_assign", lang.rem_assign_trait()), - hir::BinOpKind::BitXor => ("bitxor_assign", lang.bitxor_assign_trait()), - hir::BinOpKind::BitAnd => ("bitand_assign", lang.bitand_assign_trait()), - hir::BinOpKind::BitOr => ("bitor_assign", lang.bitor_assign_trait()), - hir::BinOpKind::Shl => ("shl_assign", lang.shl_assign_trait()), - hir::BinOpKind::Shr => ("shr_assign", lang.shr_assign_trait()), + hir::BinOpKind::Add => (sym::add_assign, lang.add_assign_trait()), + hir::BinOpKind::Sub => (sym::sub_assign, lang.sub_assign_trait()), + hir::BinOpKind::Mul => (sym::mul_assign, lang.mul_assign_trait()), + hir::BinOpKind::Div => (sym::div_assign, lang.div_assign_trait()), + hir::BinOpKind::Rem => (sym::rem_assign, lang.rem_assign_trait()), + hir::BinOpKind::BitXor => (sym::bitxor_assign, lang.bitxor_assign_trait()), + hir::BinOpKind::BitAnd => (sym::bitand_assign, lang.bitand_assign_trait()), + hir::BinOpKind::BitOr => (sym::bitor_assign, lang.bitor_assign_trait()), + hir::BinOpKind::Shl => (sym::shl_assign, lang.shl_assign_trait()), + hir::BinOpKind::Shr => (sym::shr_assign, lang.shr_assign_trait()), hir::BinOpKind::Lt | hir::BinOpKind::Le | hir::BinOpKind::Ge @@ -725,30 +725,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } else if let Op::Binary(op, IsAssign::No) = op { match op.node { - hir::BinOpKind::Add => ("add", lang.add_trait()), - hir::BinOpKind::Sub => ("sub", lang.sub_trait()), - hir::BinOpKind::Mul => ("mul", lang.mul_trait()), - hir::BinOpKind::Div => ("div", lang.div_trait()), - hir::BinOpKind::Rem => ("rem", lang.rem_trait()), - hir::BinOpKind::BitXor => ("bitxor", lang.bitxor_trait()), - hir::BinOpKind::BitAnd => ("bitand", lang.bitand_trait()), - hir::BinOpKind::BitOr => ("bitor", lang.bitor_trait()), - hir::BinOpKind::Shl => ("shl", lang.shl_trait()), - hir::BinOpKind::Shr => ("shr", lang.shr_trait()), - hir::BinOpKind::Lt => ("lt", lang.partial_ord_trait()), - hir::BinOpKind::Le => ("le", lang.partial_ord_trait()), - hir::BinOpKind::Ge => ("ge", lang.partial_ord_trait()), - hir::BinOpKind::Gt => ("gt", lang.partial_ord_trait()), - hir::BinOpKind::Eq => ("eq", lang.eq_trait()), - hir::BinOpKind::Ne => ("ne", lang.eq_trait()), + hir::BinOpKind::Add => (sym::add, lang.add_trait()), + hir::BinOpKind::Sub => (sym::sub, lang.sub_trait()), + hir::BinOpKind::Mul => (sym::mul, lang.mul_trait()), + hir::BinOpKind::Div => (sym::div, lang.div_trait()), + hir::BinOpKind::Rem => (sym::rem, lang.rem_trait()), + hir::BinOpKind::BitXor => (sym::bitxor, lang.bitxor_trait()), + hir::BinOpKind::BitAnd => (sym::bitand, lang.bitand_trait()), + hir::BinOpKind::BitOr => (sym::bitor, lang.bitor_trait()), + hir::BinOpKind::Shl => (sym::shl, lang.shl_trait()), + hir::BinOpKind::Shr => (sym::shr, lang.shr_trait()), + hir::BinOpKind::Lt => (sym::lt, lang.partial_ord_trait()), + hir::BinOpKind::Le => (sym::le, lang.partial_ord_trait()), + hir::BinOpKind::Ge => (sym::ge, lang.partial_ord_trait()), + hir::BinOpKind::Gt => (sym::gt, lang.partial_ord_trait()), + hir::BinOpKind::Eq => (sym::eq, lang.eq_trait()), + hir::BinOpKind::Ne => (sym::ne, lang.eq_trait()), hir::BinOpKind::And | hir::BinOpKind::Or => { span_bug!(span, "&& and || are not overloadable") } } } else if let Op::Unary(hir::UnOp::UnNot, _) = op { - ("not", lang.not_trait()) + (sym::not, lang.not_trait()) } else if let Op::Unary(hir::UnOp::UnNeg, _) = op { - ("neg", lang.neg_trait()) + (sym::neg, lang.neg_trait()) } else { bug!("lookup_op_method: op not supported: {:?}", op) }; @@ -759,7 +759,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); let method = trait_did.and_then(|trait_did| { - let opname = Ident::from_str(opname); + let opname = Ident::with_dummy_span(opname); self.lookup_method_in_trait(span, opname, trait_did, lhs_ty, Some(other_tys)) }); diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index ea47ae68ce7d3..18fc37df88652 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -1082,20 +1082,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .filter(|ident| !used_fields.contains_key(&ident)) .collect::>(); - if !inexistent_fields.is_empty() && !variant.recovered { - self.error_inexistent_fields( + let inexistent_fields_err = if !inexistent_fields.is_empty() && !variant.recovered { + Some(self.error_inexistent_fields( adt.variant_descr(), &inexistent_fields, &mut unmentioned_fields, variant, - ); - } + )) + } else { + None + }; // Require `..` if struct has non_exhaustive attribute. if variant.is_field_list_non_exhaustive() && !adt.did.is_local() && !etc { self.error_foreign_non_exhaustive_spat(pat, adt.variant_descr(), fields.is_empty()); } + let mut unmentioned_err = None; // Report an error if incorrect number of the fields were specified. if adt.is_union() { if fields.len() != 1 { @@ -1107,7 +1110,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit(); } } else if !etc && !unmentioned_fields.is_empty() { - self.error_unmentioned_fields(pat.span, &unmentioned_fields, variant); + unmentioned_err = Some(self.error_unmentioned_fields(pat.span, &unmentioned_fields)); + } + match (inexistent_fields_err, unmentioned_err) { + (Some(mut i), Some(mut u)) => { + if let Some(mut e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) { + // We don't want to show the inexistent fields error when this was + // `Foo { a, b }` when it should have been `Foo(a, b)`. + i.delay_as_bug(); + u.delay_as_bug(); + e.emit(); + } else { + i.emit(); + u.emit(); + } + } + (None, Some(mut err)) | (Some(mut err), None) => { + err.emit(); + } + (None, None) => {} } no_field_errors } @@ -1154,7 +1175,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { inexistent_fields: &[Ident], unmentioned_fields: &mut Vec, variant: &ty::VariantDef, - ) { + ) -> DiagnosticBuilder<'tcx> { let tcx = self.tcx; let (field_names, t, plural) = if inexistent_fields.len() == 1 { (format!("a field named `{}`", inexistent_fields[0]), "this", "") @@ -1195,7 +1216,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); if plural == "" { let input = unmentioned_fields.iter().map(|field| &field.name); - let suggested_name = find_best_match_for_name(input, &ident.as_str(), None); + let suggested_name = find_best_match_for_name(input, ident.name, None); if let Some(suggested_name) = suggested_name { err.span_suggestion( ident.span, @@ -1221,15 +1242,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { it explicitly.", ); } - err.emit(); + err + } + + fn error_tuple_variant_as_struct_pat( + &self, + pat: &Pat<'_>, + fields: &'tcx [hir::FieldPat<'tcx>], + variant: &ty::VariantDef, + ) -> Option> { + if let (CtorKind::Fn, PatKind::Struct(qpath, ..)) = (variant.ctor_kind, &pat.kind) { + let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| { + s.print_qpath(qpath, false) + }); + let mut err = struct_span_err!( + self.tcx.sess, + pat.span, + E0769, + "tuple variant `{}` written as struct variant", + path + ); + let (sugg, appl) = if fields.len() == variant.fields.len() { + ( + fields + .iter() + .map(|f| match self.tcx.sess.source_map().span_to_snippet(f.pat.span) { + Ok(f) => f, + Err(_) => rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| { + s.print_pat(f.pat) + }), + }) + .collect::>() + .join(", "), + Applicability::MachineApplicable, + ) + } else { + ( + variant.fields.iter().map(|_| "_").collect::>().join(", "), + Applicability::MaybeIncorrect, + ) + }; + err.span_suggestion( + pat.span, + "use the tuple variant pattern syntax instead", + format!("{}({})", path, sugg), + appl, + ); + return Some(err); + } + None } fn error_unmentioned_fields( &self, span: Span, unmentioned_fields: &[Ident], - variant: &ty::VariantDef, - ) { + ) -> DiagnosticBuilder<'tcx> { let field_names = if unmentioned_fields.len() == 1 { format!("field `{}`", unmentioned_fields[0]) } else { @@ -1248,9 +1316,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field_names ); diag.span_label(span, format!("missing {}", field_names)); - if variant.ctor_kind == CtorKind::Fn { - diag.note("trying to match a tuple variant with a struct variant pattern"); - } if self.tcx.sess.teach(&diag.get_code().unwrap()) { diag.note( "This error indicates that a pattern for a struct fails to specify a \ @@ -1259,7 +1324,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ignore unwanted fields.", ); } - diag.emit(); + diag } fn check_pat_box( diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index d1a86a7ee89a8..19c556942afc1 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -394,6 +394,7 @@ fn check_type_defn<'tcx, F>( Some(i) => i, None => bug!(), }, + span: field.span, last, }, ), @@ -1326,10 +1327,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter() .map(|field| { let field_ty = self.tcx.type_of(self.tcx.hir().local_def_id(field.hir_id)); - let field_ty = self.normalize_associated_types_in(field.span, &field_ty); + let field_ty = self.normalize_associated_types_in(field.ty.span, &field_ty); let field_ty = self.resolve_vars_if_possible(&field_ty); debug!("non_enum_variant: type of field {:?} is {:?}", field, field_ty); - AdtField { ty: field_ty, span: field.span } + AdtField { ty: field_ty, span: field.ty.span } }) .collect(); AdtVariant { fields, explicit_discr: None } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 15481660a5218..625b72091a6cc 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -129,7 +129,7 @@ struct CollectItemTypesVisitor<'tcx> { /// all already existing generic type parameters to avoid suggesting a name that is already in use. crate fn placeholder_type_error( tcx: TyCtxt<'tcx>, - span: Span, + span: Option, generics: &[hir::GenericParam<'_>], placeholder_types: Vec, suggest: bool, @@ -137,12 +137,15 @@ crate fn placeholder_type_error( if placeholder_types.is_empty() { return; } - let type_name = generics.next_type_param_name(None); + let type_name = generics.next_type_param_name(None); let mut sugg: Vec<_> = placeholder_types.iter().map(|sp| (*sp, (*type_name).to_string())).collect(); + if generics.is_empty() { - sugg.push((span, format!("<{}>", type_name))); + if let Some(span) = span { + sugg.push((span, format!("<{}>", type_name))); + } } else if let Some(arg) = generics.iter().find(|arg| match arg.name { hir::ParamName::Plain(Ident { name: kw::Underscore, .. }) => true, _ => false, @@ -158,6 +161,7 @@ crate fn placeholder_type_error( format!(", {}", type_name), )); } + let mut err = bad_placeholder_type(tcx, placeholder_types); if suggest { err.multipart_suggestion( @@ -186,7 +190,7 @@ fn reject_placeholder_type_signatures_in_item(tcx: TyCtxt<'tcx>, item: &'tcx hir let mut visitor = PlaceholderHirTyCollector::default(); visitor.visit_item(item); - placeholder_type_error(tcx, generics.span, &generics.params[..], visitor.0, suggest); + placeholder_type_error(tcx, Some(generics.span), &generics.params[..], visitor.0, suggest); } impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { @@ -722,7 +726,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::HirId) { // Account for `const C: _;` and `type T = _;`. let mut visitor = PlaceholderHirTyCollector::default(); visitor.visit_trait_item(trait_item); - placeholder_type_error(tcx, DUMMY_SP, &[], visitor.0, false); + placeholder_type_error(tcx, None, &[], visitor.0, false); } hir::TraitItemKind::Type(_, None) => {} @@ -745,7 +749,7 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::HirId) { // Account for `type T = _;` let mut visitor = PlaceholderHirTyCollector::default(); visitor.visit_impl_item(impl_item); - placeholder_type_error(tcx, DUMMY_SP, &[], visitor.0, false); + placeholder_type_error(tcx, None, &[], visitor.0, false); } hir::ImplItemKind::Const(..) => {} } diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 57d499e38a77b..53979d27052d3 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -162,8 +162,8 @@ impl Cfg { Cfg::Any(ref sub_cfgs) | Cfg::All(ref sub_cfgs) => { sub_cfgs.first().map(Cfg::should_capitalize_first_letter).unwrap_or(false) } - Cfg::Cfg(name, _) => match &*name.as_str() { - "debug_assertions" | "target_endian" => true, + Cfg::Cfg(name, _) => match name { + sym::debug_assertions | sym::target_endian => true, _ => false, }, } @@ -347,12 +347,11 @@ impl<'a> fmt::Display for Html<'a> { Cfg::False => fmt.write_str("nowhere"), Cfg::Cfg(name, value) => { - let n = &*name.as_str(); - let human_readable = match (n, value) { - ("unix", None) => "Unix", - ("windows", None) => "Windows", - ("debug_assertions", None) => "debug-assertions enabled", - ("target_os", Some(os)) => match &*os.as_str() { + let human_readable = match (name, value) { + (sym::unix, None) => "Unix", + (sym::windows, None) => "Windows", + (sym::debug_assertions, None) => "debug-assertions enabled", + (sym::target_os, Some(os)) => match &*os.as_str() { "android" => "Android", "dragonfly" => "DragonFly BSD", "emscripten" => "Emscripten", @@ -372,7 +371,7 @@ impl<'a> fmt::Display for Html<'a> { "windows" => "Windows", _ => "", }, - ("target_arch", Some(arch)) => match &*arch.as_str() { + (sym::target_arch, Some(arch)) => match &*arch.as_str() { "aarch64" => "AArch64", "arm" => "ARM", "asmjs" => "JavaScript", @@ -388,7 +387,7 @@ impl<'a> fmt::Display for Html<'a> { "x86_64" => "x86-64", _ => "", }, - ("target_vendor", Some(vendor)) => match &*vendor.as_str() { + (sym::target_vendor, Some(vendor)) => match &*vendor.as_str() { "apple" => "Apple", "pc" => "PC", "rumprun" => "Rumprun", @@ -396,7 +395,7 @@ impl<'a> fmt::Display for Html<'a> { "fortanix" => "Fortanix", _ => "", }, - ("target_env", Some(env)) => match &*env.as_str() { + (sym::target_env, Some(env)) => match &*env.as_str() { "gnu" => "GNU", "msvc" => "MSVC", "musl" => "musl", @@ -405,9 +404,9 @@ impl<'a> fmt::Display for Html<'a> { "sgx" => "SGX", _ => "", }, - ("target_endian", Some(endian)) => return write!(fmt, "{}-endian", endian), - ("target_pointer_width", Some(bits)) => return write!(fmt, "{}-bit", bits), - ("target_feature", Some(feat)) => { + (sym::target_endian, Some(endian)) => return write!(fmt, "{}-endian", endian), + (sym::target_pointer_width, Some(bits)) => return write!(fmt, "{}-bit", bits), + (sym::target_feature, Some(feat)) => { if self.1 { return write!(fmt, "{}", feat); } else { @@ -419,9 +418,14 @@ impl<'a> fmt::Display for Html<'a> { if !human_readable.is_empty() { fmt.write_str(human_readable) } else if let Some(v) = value { - write!(fmt, "{}=\"{}\"", Escape(n), Escape(&v.as_str())) + write!( + fmt, + "{}=\"{}\"", + Escape(&name.as_str()), + Escape(&v.as_str()) + ) } else { - write!(fmt, "{}", Escape(n)) + write!(fmt, "{}", Escape(&name.as_str())) } } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index bfe8464347d29..03d6853494cfc 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -114,7 +114,7 @@ impl Clean for CrateNum { for attr in attrs.lists(sym::doc) { if let Some(v) = attr.value_str() { if attr.check_name(sym::primitive) { - prim = PrimitiveType::from_str(&v.as_str()); + prim = PrimitiveType::from_symbol(v); if prim.is_some() { break; } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 34f91bfec5a88..c9ae67ded0a3f 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -21,7 +21,7 @@ use rustc_index::vec::IndexVec; use rustc_middle::middle::stability; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::DUMMY_SP; -use rustc_span::symbol::{sym, Ident, Symbol}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{self, FileName}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; @@ -540,7 +540,7 @@ impl Attributes { .filter_map(|attr| { if let Some(value) = attr.doc_str() { let (value, mk_fragment): (_, fn(_, _, _) -> _) = if attr.is_doc_comment() { - (strip_doc_comment_decoration(&value.as_str()), DocFragment::SugaredDoc) + (strip_doc_comment_decoration(value), DocFragment::SugaredDoc) } else { (value.to_string(), DocFragment::RawDoc) }; @@ -1230,33 +1230,33 @@ impl GetDefId for Type { } impl PrimitiveType { - pub fn from_str(s: &str) -> Option { + pub fn from_symbol(s: Symbol) -> Option { match s { - "isize" => Some(PrimitiveType::Isize), - "i8" => Some(PrimitiveType::I8), - "i16" => Some(PrimitiveType::I16), - "i32" => Some(PrimitiveType::I32), - "i64" => Some(PrimitiveType::I64), - "i128" => Some(PrimitiveType::I128), - "usize" => Some(PrimitiveType::Usize), - "u8" => Some(PrimitiveType::U8), - "u16" => Some(PrimitiveType::U16), - "u32" => Some(PrimitiveType::U32), - "u64" => Some(PrimitiveType::U64), - "u128" => Some(PrimitiveType::U128), - "bool" => Some(PrimitiveType::Bool), - "char" => Some(PrimitiveType::Char), - "str" => Some(PrimitiveType::Str), - "f32" => Some(PrimitiveType::F32), - "f64" => Some(PrimitiveType::F64), - "array" => Some(PrimitiveType::Array), - "slice" => Some(PrimitiveType::Slice), - "tuple" => Some(PrimitiveType::Tuple), - "unit" => Some(PrimitiveType::Unit), - "pointer" => Some(PrimitiveType::RawPointer), - "reference" => Some(PrimitiveType::Reference), - "fn" => Some(PrimitiveType::Fn), - "never" => Some(PrimitiveType::Never), + sym::isize => Some(PrimitiveType::Isize), + sym::i8 => Some(PrimitiveType::I8), + sym::i16 => Some(PrimitiveType::I16), + sym::i32 => Some(PrimitiveType::I32), + sym::i64 => Some(PrimitiveType::I64), + sym::i128 => Some(PrimitiveType::I128), + sym::usize => Some(PrimitiveType::Usize), + sym::u8 => Some(PrimitiveType::U8), + sym::u16 => Some(PrimitiveType::U16), + sym::u32 => Some(PrimitiveType::U32), + sym::u64 => Some(PrimitiveType::U64), + sym::u128 => Some(PrimitiveType::U128), + sym::bool => Some(PrimitiveType::Bool), + sym::char => Some(PrimitiveType::Char), + sym::str => Some(PrimitiveType::Str), + sym::f32 => Some(PrimitiveType::F32), + sym::f64 => Some(PrimitiveType::F64), + sym::array => Some(PrimitiveType::Array), + sym::slice => Some(PrimitiveType::Slice), + sym::tuple => Some(PrimitiveType::Tuple), + sym::unit => Some(PrimitiveType::Unit), + sym::pointer => Some(PrimitiveType::RawPointer), + sym::reference => Some(PrimitiveType::Reference), + kw::Fn => Some(PrimitiveType::Fn), + sym::never => Some(PrimitiveType::Never), _ => None, } } diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 14a6f3c89a3c9..39e33da44964e 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -20,6 +20,7 @@ use crate::core::new_handler; use crate::externalfiles::ExternalHtml; use crate::html; use crate::html::markdown::IdMap; +use crate::html::render::StylePath; use crate::html::static_files; use crate::opts; use crate::passes::{self, Condition, DefaultPassOption}; @@ -207,7 +208,7 @@ pub struct RenderOptions { pub sort_modules_alphabetically: bool, /// List of themes to extend the docs with. Original argument name is included to assist in /// displaying errors if it fails a theme check. - pub themes: Vec, + pub themes: Vec, /// If present, CSS file that contains rules to add to the default CSS. pub extension_css: Option, /// A map of crate names to the URL to use instead of querying the crate's `html_root_url`. @@ -410,7 +411,7 @@ impl Options { )) .emit(); } - themes.push(theme_file); + themes.push(StylePath { path: theme_file, disabled: true }); } } diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index ea65b3905272e..cc6b38ebcdb7f 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use crate::externalfiles::ExternalHtml; use crate::html::escape::Escape; use crate::html::format::{Buffer, Print}; -use crate::html::render::ensure_trailing_slash; +use crate::html::render::{ensure_trailing_slash, StylePath}; #[derive(Clone)] pub struct Layout { @@ -36,7 +36,7 @@ pub fn render( page: &Page<'_>, sidebar: S, t: T, - themes: &[PathBuf], + style_files: &[StylePath], ) -> String { let static_root_path = page.static_root_path.unwrap_or(page.root_path); format!( @@ -52,10 +52,7 @@ pub fn render( \ \ - {themes}\ - \ - \ + {style_files}\ \ \ {css_extension}\ @@ -172,13 +169,19 @@ pub fn render( after_content = layout.external_html.after_content, sidebar = Buffer::html().to_display(sidebar), krate = layout.krate, - themes = themes + style_files = style_files .iter() - .filter_map(|t| t.file_stem()) - .filter_map(|t| t.to_str()) + .filter_map(|t| { + if let Some(stem) = t.path.file_stem() { Some((stem, t.disabled)) } else { None } + }) + .filter_map(|t| { + if let Some(path) = t.0.to_str() { Some((path, t.1)) } else { None } + }) .map(|t| format!( - r#""#, - Escape(&format!("{}{}{}", static_root_path, t, page.resource_suffix)) + r#""#, + Escape(&format!("{}{}{}", static_root_path, t.0, page.resource_suffix)), + if t.1 { "disabled" } else { "" }, + if t.0 == "light" { "id=\"themeStyle\"" } else { "" } )) .collect::(), suffix = page.resource_suffix, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 8bba21a2e7ace..8fa581180ef60 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -42,6 +42,7 @@ use std::str; use std::string::ToString; use std::sync::Arc; +use itertools::Itertools; use rustc_ast_pretty::pprust; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -187,8 +188,8 @@ crate struct SharedContext { /// This flag indicates whether listings of modules (in the side bar and documentation itself) /// should be ordered alphabetically or in order of appearance (in the source code). pub sort_modules_alphabetically: bool, - /// Additional themes to be added to the generated docs. - pub themes: Vec, + /// Additional CSS files to be added to the generated docs. + pub style_files: Vec, /// Suffix to be added on resource files (if suffix is "-v2" then "light.css" becomes /// "light-v2.css"). pub resource_suffix: String, @@ -417,6 +418,14 @@ impl Serialize for TypeWithKind { } } +#[derive(Debug, Clone)] +pub struct StylePath { + /// The path to the theme + pub path: PathBuf, + /// What the `disabled` attribute should be set to in the HTML tag + pub disabled: bool, +} + thread_local!(static CACHE_KEY: RefCell> = Default::default()); thread_local!(pub static CURRENT_DEPTH: Cell = Cell::new(0)); @@ -460,7 +469,7 @@ pub fn run( id_map, playground_url, sort_modules_alphabetically, - themes, + themes: style_files, extension_css, extern_html_root_urls, resource_suffix, @@ -530,7 +539,7 @@ pub fn run( layout, created_dirs: Default::default(), sort_modules_alphabetically, - themes, + style_files, resource_suffix, static_root_path, fs: DocFS::new(&errors), @@ -539,6 +548,19 @@ pub fn run( playground, }; + // Add the default themes to the `Vec` of stylepaths + // + // Note that these must be added before `sources::render` is called + // so that the resulting source pages are styled + // + // `light.css` is not disabled because it is the stylesheet that stays loaded + // by the browser as the theme stylesheet. The theme system (hackily) works by + // changing the href to this stylesheet. All other themes are disabled to + // prevent rule conflicts + scx.style_files.push(StylePath { path: PathBuf::from("light.css"), disabled: false }); + scx.style_files.push(StylePath { path: PathBuf::from("dark.css"), disabled: true }); + scx.style_files.push(StylePath { path: PathBuf::from("ayu.css"), disabled: true }); + let dst = output; scx.ensure_dir(&dst)?; krate = sources::render(&dst, &mut scx, krate)?; @@ -615,11 +637,40 @@ fn write_shared( // then we'll run over the "official" styles. let mut themes: FxHashSet = FxHashSet::default(); - for entry in &cx.shared.themes { - let content = try_err!(fs::read(&entry), &entry); - let theme = try_none!(try_none!(entry.file_stem(), &entry).to_str(), &entry); - let extension = try_none!(try_none!(entry.extension(), &entry).to_str(), &entry); - cx.shared.fs.write(cx.path(&format!("{}.{}", theme, extension)), content.as_slice())?; + for entry in &cx.shared.style_files { + let theme = try_none!(try_none!(entry.path.file_stem(), &entry.path).to_str(), &entry.path); + let extension = + try_none!(try_none!(entry.path.extension(), &entry.path).to_str(), &entry.path); + + // Handle the official themes + match theme { + "light" => write_minify( + &cx.shared.fs, + cx.path("light.css"), + static_files::themes::LIGHT, + options.enable_minification, + )?, + "dark" => write_minify( + &cx.shared.fs, + cx.path("dark.css"), + static_files::themes::DARK, + options.enable_minification, + )?, + "ayu" => write_minify( + &cx.shared.fs, + cx.path("ayu.css"), + static_files::themes::AYU, + options.enable_minification, + )?, + _ => { + // Handle added third-party themes + let content = try_err!(fs::read(&entry.path), &entry.path); + cx.shared + .fs + .write(cx.path(&format!("{}.{}", theme, extension)), content.as_slice())?; + } + }; + themes.insert(theme.to_owned()); } @@ -633,20 +684,6 @@ fn write_shared( write(cx.path("brush.svg"), static_files::BRUSH_SVG)?; write(cx.path("wheel.svg"), static_files::WHEEL_SVG)?; write(cx.path("down-arrow.svg"), static_files::DOWN_ARROW_SVG)?; - write_minify( - &cx.shared.fs, - cx.path("light.css"), - static_files::themes::LIGHT, - options.enable_minification, - )?; - themes.insert("light".to_owned()); - write_minify( - &cx.shared.fs, - cx.path("dark.css"), - static_files::themes::DARK, - options.enable_minification, - )?; - themes.insert("dark".to_owned()); let mut themes: Vec<&String> = themes.iter().collect(); themes.sort(); @@ -957,7 +994,7 @@ themePicker.onblur = handleThemeButtonsBlur; }) .collect::() ); - let v = layout::render(&cx.shared.layout, &page, "", content, &cx.shared.themes); + let v = layout::render(&cx.shared.layout, &page, "", content, &cx.shared.style_files); cx.shared.fs.write(&dst, v.as_bytes())?; } } @@ -1375,7 +1412,7 @@ impl Context { &page, sidebar, |buf: &mut Buffer| all.print(buf), - &self.shared.themes, + &self.shared.style_files, ); self.shared.fs.write(&final_file, v.as_bytes())?; @@ -1384,9 +1421,9 @@ impl Context { page.description = "Settings of Rustdoc"; page.root_path = "./"; - let mut themes = self.shared.themes.clone(); + let mut style_files = self.shared.style_files.clone(); let sidebar = "

Settings

"; - themes.push(PathBuf::from("settings.css")); + style_files.push(StylePath { path: PathBuf::from("settings.css"), disabled: false }); let v = layout::render( &self.shared.layout, &page, @@ -1395,7 +1432,7 @@ impl Context { self.shared.static_root_path.as_deref().unwrap_or("./"), &self.shared.resource_suffix, ), - &themes, + &style_files, ); self.shared.fs.write(&settings_file, v.as_bytes())?; @@ -1457,7 +1494,7 @@ impl Context { &page, |buf: &mut _| print_sidebar(self, it, buf), |buf: &mut _| print_item(self, it, buf), - &self.shared.themes, + &self.shared.style_files, ) } else { let mut url = self.root_path(); @@ -3170,15 +3207,19 @@ const ALLOWED_ATTRIBUTES: &[Symbol] = &[ // bar: usize, // } fn render_attributes(w: &mut Buffer, it: &clean::Item, top: bool) { - let mut attrs = String::new(); - - for attr in &it.attrs.other_attrs { - if !ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) { - continue; - } + let attrs = it + .attrs + .other_attrs + .iter() + .filter_map(|attr| { + if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) { + Some(pprust::attribute_to_string(&attr)) + } else { + None + } + }) + .join("\n"); - attrs.push_str(&pprust::attribute_to_string(&attr)); - } if !attrs.is_empty() { write!( w, diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index f0900c34a4ba3..03f79b931868b 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -123,7 +123,7 @@ impl<'a> SourceCollector<'a> { &page, "", |buf: &mut _| print_src(buf, &contents), - &self.scx.themes, + &self.scx.style_files, ); self.scx.fs.write(&cur, v.as_bytes())?; self.scx.local_sources.insert(p, href); diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css new file mode 100644 index 0000000000000..bc21c28750fd8 --- /dev/null +++ b/src/librustdoc/html/static/themes/ayu.css @@ -0,0 +1,561 @@ +/* +Based off of the Ayu theme +Original by Dempfi (https://github.com/dempfi/ayu) +*/ + +/* General structure and fonts */ + +body { + background-color: #0f1419; + color: #c5c5c5; +} + +h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) { + color: white; +} +h1.fqn { + border-bottom-color: #5c6773; +} +h1.fqn a { + color: #fff; +} +h2, h3:not(.impl):not(.method):not(.type):not(.tymethod) { + border-bottom-color: #5c6773; +} +h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) { + border: none; +} + +.in-band { + background-color: #0f1419; +} + +.invisible { + background: rgba(0, 0, 0, 0); +} + +code { + color: #ffb454; +} +h3 > code, h4 > code, h5 > code { + color: #e6e1cf; +} +pre > code { + color: #e6e1cf; +} +span code { + color: #e6e1cf; +} +.docblock a > code { + color: #39AFD7 !important; +} +.docblock code, .docblock-short code { + background-color: #191f26; +} +pre { + color: #e6e1cf; + background-color: #191f26; +} + +.sidebar { + background-color: #14191f; +} + +/* Improve the scrollbar display on firefox */ +* { + scrollbar-color: #5c6773 transparent; +} + +.sidebar { + scrollbar-color: #5c6773 transparent; +} + +/* Improve the scrollbar display on webkit-based browsers */ +::-webkit-scrollbar-track { + background-color: transparent; +} +::-webkit-scrollbar-thumb { + background-color: #5c6773; +} +.sidebar::-webkit-scrollbar-track { + background-color: transparent; +} +.sidebar::-webkit-scrollbar-thumb { + background-color: #5c6773; +} + +.sidebar .current { + background-color: transparent; + color: #ffb44c; +} + +.source .sidebar { + background-color: #0f1419; +} + +.sidebar .location { + border-color: #000; + background-color: #0f1419; + color: #fff; +} + +.sidebar-elems .location { + color: #ff7733; +} + +.sidebar-elems .location a { + color: #fff; +} + +.sidebar .version { + border-bottom-color: #DDD; +} + +.sidebar-title { + border-top-color: #5c6773; + border-bottom-color: #5c6773; +} + +.block a:hover { + background: transparent; + color: #ffb44c; +} + +.line-numbers span { color: #5c6773ab; } +.line-numbers .line-highlighted { + background-color: rgba(255, 236, 164, 0.06) !important; + padding-right: 4px; + border-right: 1px solid #ffb44c; +} + +.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { + border-bottom-color: #5c6773; +} + +.docblock table, .docblock table td, .docblock table th { + border-color: #5c6773; +} + +.content .method .where, +.content .fn .where, +.content .where.fmt-newline { + color: #c5c5c5; +} + +.content .highlighted { + color: #000 !important; + background-color: #c6afb3; +} +.content .highlighted a, .content .highlighted span { color: #000 !important; } +.content .highlighted { + background-color: #c6afb3; +} +.search-results a { + color: #0096cf; +} +.search-results a span.desc { + color: #c5c5c5; +} + +.content .stability::before { color: #ccc; } + +.content span.foreigntype, .content a.foreigntype { color: #ef57ff; } +.content span.union, .content a.union { color: #98a01c; } +.content span.constant, .content a.constant, +.content span.static, .content a.static { color: #6380a0; } +.content span.primitive, .content a.primitive { color: #32889b; } +.content span.traitalias, .content a.traitalias { color: #57d399; } +.content span.keyword, .content a.keyword { color: #de5249; } + +.content span.externcrate, .content span.mod, .content a.mod { + color: #acccf9; +} +.content span.struct, .content a.struct { + color: #ffa0a5; +} +.content span.enum, .content a.enum { + color: #99e0c9; +} +.content span.trait, .content a.trait { + color: #39AFD7; +} +.content span.type, .content a.type { + color: #cfbcf5; +} +.content span.fn, .content a.fn, .content span.method, +.content a.method, .content span.tymethod, +.content a.tymethod, .content .fnname { + color: #fdd687; +} +.content span.attr, .content a.attr, .content span.derive, +.content a.derive, .content span.macro, .content a.macro { + color: #a37acc; +} + +pre.rust .comment, pre.rust .doccomment { + color: #788797; + font-style: italic; +} + +nav:not(.sidebar) { + border-bottom-color: #e0e0e0; +} +nav.main .current { + border-top-color: #5c6773; + border-bottom-color: #5c6773; +} +nav.main .separator { + border: 1px solid #5c6773; +} +a { + color: #c5c5c5; +} + +.docblock:not(.type-decl) a:not(.srclink):not(.test-arrow), +.docblock-short a:not(.srclink):not(.test-arrow), .stability a { + color: #39AFD7; +} + +.stab.internal a { + color: #304FFE; +} + +.collapse-toggle { + color: #999; +} + +#crate-search { + color: #c5c5c5; + background-color: #141920; + border-radius: 4px; + box-shadow: none; + border-color: #5c6773; +} + +.search-input { + color: #ffffff; + background-color: #141920; + box-shadow: none; + transition: box-shadow 150ms ease-in-out; + border-radius: 4px; + margin-left: 8px; +} + +#crate-search+.search-input:focus { + box-shadow: 0px 6px 20px 0px black; +} + +.search-focus:disabled { + color: #929292; +} + +.module-item .stab { + color: #000; +} + +.stab.unstable, +.stab.internal, +.stab.deprecated, +.stab.portability { + color: #c5c5c5; + background: #314559 !important; + border-style: none !important; + border-radius: 4px; + padding: 3px 6px 3px 6px; +} + +.stab.portability > code { + color: #e6e1cf; + background-color: transparent; +} + +#help > div { + background: #14191f; + box-shadow: 0px 6px 20px 0px black; + border: none; + border-radius: 4px; +} + +.since { + color: grey; +} + +tr.result span.primitive::after, tr.result span.keyword::after { + color: #788797; +} + +.line-numbers :target { background-color: transparent; } + +/* Code highlighting */ +pre.rust .number, pre.rust .string { color: #b8cc52; } +pre.rust .kw, pre.rust .kw-2, pre.rust .prelude-ty, +pre.rust .bool-val, pre.rust .prelude-val, +pre.rust .op, pre.rust .lifetime { color: #ff7733; } +pre.rust .macro, pre.rust .macro-nonterminal { color: #a37acc; } +pre.rust .question-mark { + color: #ff9011; +} +pre.rust .self { + color: #36a3d9; + font-style: italic; +} +pre.rust .attribute { + color: #e6e1cf; +} +pre.rust .attribute .ident, pre.rust .attribute .op { + color: #e6e1cf; +} + +.example-wrap > pre.line-number { + color: #5c67736e; + border: none; +} + +a.test-arrow { + font-size: 100%; + color: #788797; + border-radius: 4px; + background-color: rgba(255, 255, 255, 0); +} + +a.test-arrow:hover { + background-color: rgba(242, 151, 24, 0.05); + color: #ffb44c; +} + +.toggle-label { + color: #999; +} + +:target > code, :target > .in-band { + background: rgba(255, 236, 164, 0.06); + border-right: 3px solid #ffb44c; +} + +pre.compile_fail { + border-left: 2px solid rgba(255,0,0,.4); +} + +pre.compile_fail:hover, .information:hover + pre.compile_fail { + border-left: 2px solid #f00; +} + +pre.should_panic { + border-left: 2px solid rgba(255,0,0,.4); +} + +pre.should_panic:hover, .information:hover + pre.should_panic { + border-left: 2px solid #f00; +} + +pre.ignore { + border-left: 2px solid rgba(255,142,0,.6); +} + +pre.ignore:hover, .information:hover + pre.ignore { + border-left: 2px solid #ff9200; +} + +.tooltip.compile_fail { + color: rgba(255,0,0,.5); +} + +.information > .compile_fail:hover { + color: #f00; +} + +.tooltip.should_panic { + color: rgba(255,0,0,.5); +} + +.information > .should_panic:hover { + color: #f00; +} + +.tooltip.ignore { + color: rgba(255,142,0,.6); +} + +.information > .ignore:hover { + color: #ff9200; +} + +.search-failed a { + color: #39AFD7; +} + +.tooltip .tooltiptext { + background-color: #314559; + color: #c5c5c5; + border: 1px solid #5c6773; +} + +.tooltip .tooltiptext::after { + border-color: transparent #314559 transparent transparent; +} + +#titles > div.selected { + background-color: #141920 !important; + border-bottom: 1px solid #ffb44c !important; + border-top: none; +} + +#titles > div:not(.selected) { + background-color: transparent !important; + border: none; +} + +#titles > div:hover { + border-bottom: 1px solid rgba(242, 151, 24, 0.3); +} + +#titles > div > div.count { + color: #888; +} + +/* rules that this theme does not need to set, here to satisfy the rule checker */ +/* note that a lot of these are partially set in some way (meaning they are set +individually rather than as a group) */ +/* TODO: these rules should be at the bottom of the file but currently must be +above the `@media (max-width: 700px)` rules due to a bug in the css checker */ +/* see https://github.com/rust-lang/rust/pull/71237#issuecomment-618170143 */ +.content .highlighted.mod, .content .highlighted.externcrate {} +.search-input:focus {} +.content span.attr,.content a.attr,.block a.current.attr,.content span.derive,.content a.derive,.block a.current.derive,.content span.macro,.content a.macro,.block a.current.macro {} +.content .highlighted.trait {} +.content span.struct,.content a.struct,.block a.current.struct {} +#titles>div:hover,#titles>div.selected {} +.content .highlighted.traitalias {} +.content span.type,.content a.type,.block a.current.type {} +.content span.union,.content a.union,.block a.current.union {} +.content .highlighted.foreigntype {} +pre.rust .lifetime {} +.content .highlighted.primitive {} +.content .highlighted.constant,.content .highlighted.static {} +.stab.unstable {} +.content .highlighted.fn,.content .highlighted.method,.content .highlighted.tymethod {} +h2,h3:not(.impl):not(.method):not(.type):not(.tymethod),h4:not(.method):not(.type):not(.tymethod) {} +.content span.enum,.content a.enum,.block a.current.enum {} +.content span.constant,.content a.constant,.block a.current.constant,.content span.static,.content a.static,.block a.current.static {} +.content span.keyword,.content a.keyword,.block a.current.keyword {} +pre.rust .comment {} +.content .highlighted.enum {} +.content .highlighted.struct {} +.content .highlighted.keyword {} +.content span.traitalias,.content a.traitalias,.block a.current.traitalias {} +.content span.fn,.content a.fn,.block a.current.fn,.content span.method,.content a.method,.block a.current.method,.content span.tymethod,.content a.tymethod,.block a.current.tymethod,.content .fnname {} +pre.rust .kw {} +pre.rust .self,pre.rust .bool-val,pre.rust .prelude-val,pre.rust .attribute,pre.rust .attribute .ident {} +.content span.foreigntype,.content a.foreigntype,.block a.current.foreigntype {} +pre.rust .doccomment {} +.stab.deprecated {} +.content .highlighted.attr,.content .highlighted.derive,.content .highlighted.macro {} +.stab.portability {} +.content .highlighted.union {} +.content span.primitive,.content a.primitive,.block a.current.primitive {} +.content span.externcrate,.content span.mod,.content a.mod,.block a.current.mod {} +.content .highlighted.type {} +pre.rust .kw-2,pre.rust .prelude-ty {} +.content span.trait,.content a.trait,.block a.current.trait {} +.stab.internal {} + +@media (max-width: 700px) { + .sidebar-menu { + background-color: #14191f; + border-bottom-color: #5c6773; + border-right-color: #5c6773; + } + + .sidebar-elems { + background-color: #14191f; + border-right-color: #5c6773; + } + + #sidebar-filler { + background-color: #14191f; + border-bottom-color: #5c6773; + } +} + +kbd { + color: #c5c5c5; + background-color: #314559; + border-color: #5c6773; + border-bottom-color: #5c6773; + box-shadow-color: #c6cbd1; +} + +#theme-picker, #settings-menu { + border-color: #5c6773; + background-color: #0f1419; +} + +#theme-picker > img, #settings-menu > img { + filter: invert(100); +} + +#theme-picker:hover, #theme-picker:focus, +#settings-menu:hover, #settings-menu:focus { + border-color: #e0e0e0; +} + +#theme-choices { + border-color: #5c6773; + background-color: #0f1419; +} + +#theme-choices > button:not(:first-child) { + border-top-color: #c5c5c5; +} + +#theme-choices > button:hover, #theme-choices > button:focus { + background-color: rgba(70, 70, 70, 0.33); +} + +@media (max-width: 700px) { + #theme-picker { + background: #0f1419; + } +} + +#all-types { + background-color: #14191f; +} +#all-types:hover { + background-color: rgba(70, 70, 70, 0.33); +} + +.search-results td span.alias { + color: #c5c5c5; +} +.search-results td span.grey { + color: #999; +} + +#sidebar-toggle { + background-color: #14191f; +} +#sidebar-toggle:hover { + background-color: rgba(70, 70, 70, 0.33); +} +#source-sidebar { + background-color: #14191f; +} +#source-sidebar > .title { + color: #fff; + border-bottom-color: #5c6773; +} +div.files > a:hover, div.name:hover { + background-color: #14191f; + color: #ffb44c; +} +div.files > .selected { + background-color: #14191f; + color: #ffb44c; +} +.setting-line > .title { + border-bottom-color: #5c6773; +} +input:checked + .slider { + background-color: #ffb454 !important; +} diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs index 6790f3bd5d0b1..6bd7e53cdfbe2 100644 --- a/src/librustdoc/html/static_files.rs +++ b/src/librustdoc/html/static_files.rs @@ -64,6 +64,9 @@ pub mod themes { /// The "dark" theme. pub static DARK: &str = include_str!("static/themes/dark.css"); + + /// The "ayu" theme. + pub static AYU: &str = include_str!("static/themes/ayu.css"); } /// Files related to the Fira Sans font. diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 4fcf6ceb44d50..f707c1a3e1a10 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -799,6 +799,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { let hir_id = self.cx.tcx.hir().as_local_hir_id(local); if !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_id) + && (item.visibility == Visibility::Public) && !self.cx.render_options.document_private { let item_name = item.name.as_deref().unwrap_or(""); diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index d6b7ad6254a8c..156f555be02d8 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -256,9 +256,23 @@ fn handle_ebadf(r: io::Result, default: T) -> io::Result { /// [`BufRead`]: trait.BufRead.html /// /// ### Note: Windows Portability Consideration +/// /// When operating in a console, the Windows implementation of this stream does not support /// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return /// an error. +/// +/// # Examples +/// +/// ```no_run +/// use std::io::{self, Read}; +/// +/// fn main() -> io::Result<()> { +/// let mut buffer = String::new(); +/// let mut stdin = io::stdin(); // We get `Stdin` here. +/// stdin.read_to_string(&mut buffer)?; +/// Ok(()) +/// } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Stdin { inner: Arc>>>, @@ -274,9 +288,26 @@ pub struct Stdin { /// [`Stdin::lock`]: struct.Stdin.html#method.lock /// /// ### Note: Windows Portability Consideration +/// /// When operating in a console, the Windows implementation of this stream does not support /// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return /// an error. +/// +/// # Examples +/// +/// ```no_run +/// use std::io::{self, Read}; +/// +/// fn main() -> io::Result<()> { +/// let mut buffer = String::new(); +/// let stdin = io::stdin(); // We get `Stdin` here. +/// { +/// let mut stdin_lock = stdin.lock(); // We get `StdinLock` here. +/// stdin_lock.read_to_string(&mut buffer)?; +/// } // `StdinLock` is dropped here. +/// Ok(()) +/// } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct StdinLock<'a> { inner: MutexGuard<'a, BufReader>>, diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index 0b3386c05d54b..a53e7f5cf57aa 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1732,8 +1732,72 @@ mod dyn_keyword {} // /// The [Rust equivalent of a C-style union][union]. /// -/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// A `union` looks like a [`struct`] in terms of declaration, but all of its +/// fields exist in the same memory, superimposed over one another. For instance, +/// if we wanted some bits in memory that we sometimes interpret as a `u32` and +/// sometimes as an `f32`, we could write: +/// +/// ```rust +/// union IntOrFloat { +/// i: u32, +/// f: f32, +/// } +/// +/// let mut u = IntOrFloat { f: 1.0 }; +/// // Reading the fields of an union is always unsafe +/// assert_eq!(unsafe { u.i }, 1065353216); +/// // Updating through any of the field will modify all of them +/// u.i = 1073741824; +/// assert_eq!(unsafe { u.f }, 2.0); +/// ``` +/// +/// # Matching on unions +/// +/// It is possible to use pattern matching on `union`s. A single field name must +/// be used and it must match the name of one of the `union`'s field. +/// Like reading from a `union`, pattern matching on a `union` requires `unsafe`. +/// +/// ```rust +/// union IntOrFloat { +/// i: u32, +/// f: f32, +/// } +/// +/// let u = IntOrFloat { f: 1.0 }; +/// +/// unsafe { +/// match u { +/// IntOrFloat { i: 10 } => println!("Found exactly ten!"), +/// // Matching the field `f` provides an `f32`. +/// IntOrFloat { f } => println!("Found f = {} !", f), +/// } +/// } +/// ``` +/// +/// # References to union fields +/// +/// All fields in a `union` are all at the same place in memory which means +/// borrowing one borrows the entire `union`, for the same lifetime: +/// +/// ```rust,compile_fail,E0502 +/// union IntOrFloat { +/// i: u32, +/// f: f32, +/// } /// +/// let mut u = IntOrFloat { f: 1.0 }; +/// +/// let f = unsafe { &u.f }; +/// // This will not compile because the field has already been borrowed, even +/// // if only immutably +/// let i = unsafe { &mut u.i }; +/// +/// *i = 10; +/// println!("f = {} and i = {}", f, i); +/// ``` +/// +/// See the [Reference][union] for more informations on `union`s. +/// +/// [`struct`]: keyword.struct.html /// [union]: ../reference/items/unions.html -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 mod union_keyword {} diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index bd585d39c242f..5215db7cdb3ce 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -242,8 +242,8 @@ #![feature(atomic_mut_ptr)] #![feature(box_syntax)] #![feature(c_variadic)] -#![feature(cfg_accessible)] #![feature(can_vector)] +#![feature(cfg_accessible)] #![feature(cfg_target_has_atomic)] #![feature(cfg_target_thread_local)] #![feature(char_error_internals)] @@ -276,8 +276,8 @@ #![feature(hashmap_internals)] #![feature(int_error_internals)] #![feature(int_error_matching)] -#![feature(into_future)] #![feature(integer_atomics)] +#![feature(into_future)] #![feature(lang_items)] #![feature(libc)] #![feature(link_args)] @@ -286,6 +286,7 @@ #![feature(log_syntax)] #![feature(maybe_uninit_ref)] #![feature(maybe_uninit_slice)] +#![feature(min_specialization)] #![feature(needs_panic_runtime)] #![feature(negative_impls)] #![feature(never_type)] @@ -305,7 +306,7 @@ #![feature(shrink_to)] #![feature(slice_concat_ext)] #![feature(slice_internals)] -#![feature(min_specialization)] +#![feature(slice_strip)] #![feature(staged_api)] #![feature(std_internals)] #![feature(stdsimd)] diff --git a/src/libstd/sys/cloudabi/mod.rs b/src/libstd/sys/cloudabi/mod.rs index 8dbc31472d637..f7dd2c8d00fd2 100644 --- a/src/libstd/sys/cloudabi/mod.rs +++ b/src/libstd/sys/cloudabi/mod.rs @@ -16,8 +16,8 @@ pub mod rwlock; pub mod stack_overflow; pub mod stdio; pub mod thread; -#[path = "../unix/thread_local.rs"] -pub mod thread_local; +#[path = "../unix/thread_local_key.rs"] +pub mod thread_local_key; pub mod time; pub use crate::sys_common::os_str_bytes as os_str; diff --git a/src/libstd/sys/hermit/mod.rs b/src/libstd/sys/hermit/mod.rs index 7bdc1be3b1702..675b82ceb775f 100644 --- a/src/libstd/sys/hermit/mod.rs +++ b/src/libstd/sys/hermit/mod.rs @@ -22,7 +22,6 @@ pub mod cmath; pub mod condvar; pub mod env; pub mod ext; -pub mod fast_thread_local; pub mod fd; pub mod fs; pub mod io; @@ -37,7 +36,8 @@ pub mod rwlock; pub mod stack_overflow; pub mod stdio; pub mod thread; -pub mod thread_local; +pub mod thread_local_dtor; +pub mod thread_local_key; pub mod time; use crate::io::ErrorKind; diff --git a/src/libstd/sys/hermit/fast_thread_local.rs b/src/libstd/sys/hermit/thread_local_dtor.rs similarity index 100% rename from src/libstd/sys/hermit/fast_thread_local.rs rename to src/libstd/sys/hermit/thread_local_dtor.rs diff --git a/src/libstd/sys/wasm/thread_local.rs b/src/libstd/sys/hermit/thread_local_key.rs similarity index 54% rename from src/libstd/sys/wasm/thread_local.rs rename to src/libstd/sys/hermit/thread_local_key.rs index f8be9863ed56f..bf1b49eb83b7e 100644 --- a/src/libstd/sys/wasm/thread_local.rs +++ b/src/libstd/sys/hermit/thread_local_key.rs @@ -2,25 +2,25 @@ pub type Key = usize; #[inline] pub unsafe fn create(_dtor: Option) -> Key { - panic!("should not be used on the wasm target"); + panic!("should not be used on the hermit target"); } #[inline] pub unsafe fn set(_key: Key, _value: *mut u8) { - panic!("should not be used on the wasm target"); + panic!("should not be used on the hermit target"); } #[inline] pub unsafe fn get(_key: Key) -> *mut u8 { - panic!("should not be used on the wasm target"); + panic!("should not be used on the hermit target"); } #[inline] pub unsafe fn destroy(_key: Key) { - panic!("should not be used on the wasm target"); + panic!("should not be used on the hermit target"); } #[inline] pub fn requires_synchronized_create() -> bool { - panic!("should not be used on the wasm target"); + panic!("should not be used on the hermit target"); } diff --git a/src/libstd/sys/sgx/abi/mod.rs b/src/libstd/sys/sgx/abi/mod.rs index 5ef26d4cc4dc6..b0693b63a48fd 100644 --- a/src/libstd/sys/sgx/abi/mod.rs +++ b/src/libstd/sys/sgx/abi/mod.rs @@ -17,6 +17,9 @@ pub mod usercalls; #[cfg(not(test))] global_asm!(include_str!("entry.S")); +#[repr(C)] +struct EntryReturn(u64, u64); + #[cfg(not(test))] #[no_mangle] unsafe extern "C" fn tcs_init(secondary: bool) { @@ -56,8 +59,7 @@ unsafe extern "C" fn tcs_init(secondary: bool) { // able to specify this #[cfg(not(test))] #[no_mangle] -#[allow(improper_ctypes_definitions)] -extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64) { +extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> EntryReturn { // FIXME: how to support TLS in library mode? let tls = Box::new(tls::Tls::new()); let _tls_guard = unsafe { tls.activate() }; @@ -65,7 +67,7 @@ extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64 if secondary { super::thread::Thread::entry(); - (0, 0) + EntryReturn(0, 0) } else { extern "C" { fn main(argc: isize, argv: *const *const u8) -> isize; diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs index 397dd496ae8af..a4968ff7d4f54 100644 --- a/src/libstd/sys/sgx/mod.rs +++ b/src/libstd/sys/sgx/mod.rs @@ -30,7 +30,7 @@ pub mod rwlock; pub mod stack_overflow; pub mod stdio; pub mod thread; -pub mod thread_local; +pub mod thread_local_key; pub mod time; pub use crate::sys_common::os_str_bytes as os_str; diff --git a/src/libstd/sys/sgx/thread_local.rs b/src/libstd/sys/sgx/thread_local_key.rs similarity index 100% rename from src/libstd/sys/sgx/thread_local.rs rename to src/libstd/sys/sgx/thread_local_key.rs diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index b1688e74173d7..eddf00d3979f5 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -47,7 +47,6 @@ pub mod cmath; pub mod condvar; pub mod env; pub mod ext; -pub mod fast_thread_local; pub mod fd; pub mod fs; pub mod io; @@ -68,7 +67,8 @@ pub mod rwlock; pub mod stack_overflow; pub mod stdio; pub mod thread; -pub mod thread_local; +pub mod thread_local_dtor; +pub mod thread_local_key; pub mod time; pub use crate::sys_common::os_str_bytes as os_str; diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index f389c60615f24..de35fe0521d03 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -1,3 +1,4 @@ +use crate::convert::TryInto; use crate::fmt; use crate::io::{self, Error, ErrorKind}; use crate::ptr; @@ -17,7 +18,7 @@ impl Command { default: Stdio, needs_stdin: bool, ) -> io::Result<(Process, StdioPipes)> { - const CLOEXEC_MSG_FOOTER: &[u8] = b"NOEX"; + const CLOEXEC_MSG_FOOTER: [u8; 4] = *b"NOEX"; let envp = self.capture_env(); @@ -52,11 +53,12 @@ impl Command { drop(input); let Err(err) = self.do_exec(theirs, envp.as_ref()); let errno = err.raw_os_error().unwrap_or(libc::EINVAL) as u32; + let errno = errno.to_be_bytes(); let bytes = [ - (errno >> 24) as u8, - (errno >> 16) as u8, - (errno >> 8) as u8, - (errno >> 0) as u8, + errno[0], + errno[1], + errno[2], + errno[3], CLOEXEC_MSG_FOOTER[0], CLOEXEC_MSG_FOOTER[1], CLOEXEC_MSG_FOOTER[2], @@ -81,12 +83,13 @@ impl Command { match input.read(&mut bytes) { Ok(0) => return Ok((p, ours)), Ok(8) => { + let (errno, footer) = bytes.split_at(4); assert!( - combine(CLOEXEC_MSG_FOOTER) == combine(&bytes[4..8]), + combine(CLOEXEC_MSG_FOOTER) == combine(footer.try_into().unwrap()), "Validation on the CLOEXEC pipe failed: {:?}", bytes ); - let errno = combine(&bytes[0..4]); + let errno = combine(errno.try_into().unwrap()); assert!(p.wait().is_ok(), "wait() should either return Ok or panic"); return Err(Error::from_raw_os_error(errno)); } @@ -103,13 +106,8 @@ impl Command { } } - fn combine(arr: &[u8]) -> i32 { - let a = arr[0] as u32; - let b = arr[1] as u32; - let c = arr[2] as u32; - let d = arr[3] as u32; - - ((a << 24) | (b << 16) | (c << 8) | (d << 0)) as i32 + fn combine(arr: [u8; 4]) -> i32 { + i32::from_be_bytes(arr) } } diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/thread_local_dtor.rs similarity index 94% rename from src/libstd/sys/unix/fast_thread_local.rs rename to src/libstd/sys/unix/thread_local_dtor.rs index 8730b4de8bed2..c3275eb6f0e50 100644 --- a/src/libstd/sys/unix/fast_thread_local.rs +++ b/src/libstd/sys/unix/thread_local_dtor.rs @@ -1,6 +1,9 @@ #![cfg(target_thread_local)] #![unstable(feature = "thread_local_internals", issue = "none")] +//! Provides thread-local destructors without an associated "key", which +//! can be more efficient. + // Since what appears to be glibc 2.18 this symbol has been shipped which // GCC and clang both use to invoke destructors in thread_local globals, so // let's do the same! @@ -16,7 +19,7 @@ ))] pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { use crate::mem; - use crate::sys_common::thread_local::register_dtor_fallback; + use crate::sys_common::thread_local_dtor::register_dtor_fallback; extern "C" { #[linkage = "extern_weak"] diff --git a/src/libstd/sys/unix/thread_local.rs b/src/libstd/sys/unix/thread_local_key.rs similarity index 100% rename from src/libstd/sys/unix/thread_local.rs rename to src/libstd/sys/unix/thread_local_key.rs diff --git a/src/libstd/sys/vxworks/mod.rs b/src/libstd/sys/vxworks/mod.rs index 0787e7098988c..1132a849e2f18 100644 --- a/src/libstd/sys/vxworks/mod.rs +++ b/src/libstd/sys/vxworks/mod.rs @@ -13,7 +13,6 @@ pub mod cmath; pub mod condvar; pub mod env; pub mod ext; -pub mod fast_thread_local; pub mod fd; pub mod fs; pub mod io; @@ -29,7 +28,8 @@ pub mod rwlock; pub mod stack_overflow; pub mod stdio; pub mod thread; -pub mod thread_local; +pub mod thread_local_dtor; +pub mod thread_local_key; pub mod time; pub use crate::sys_common::os_str_bytes as os_str; diff --git a/src/libstd/sys/vxworks/fast_thread_local.rs b/src/libstd/sys/vxworks/thread_local_dtor.rs similarity index 82% rename from src/libstd/sys/vxworks/fast_thread_local.rs rename to src/libstd/sys/vxworks/thread_local_dtor.rs index 098668cf521dd..3f73f6c490326 100644 --- a/src/libstd/sys/vxworks/fast_thread_local.rs +++ b/src/libstd/sys/vxworks/thread_local_dtor.rs @@ -5,7 +5,3 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { use crate::sys_common::thread_local::register_dtor_fallback; register_dtor_fallback(t, dtor); } - -pub fn requires_move_before_drop() -> bool { - false -} diff --git a/src/libstd/sys/vxworks/thread_local.rs b/src/libstd/sys/vxworks/thread_local_key.rs similarity index 100% rename from src/libstd/sys/vxworks/thread_local.rs rename to src/libstd/sys/vxworks/thread_local_key.rs diff --git a/src/libstd/sys/wasi/mod.rs b/src/libstd/sys/wasi/mod.rs index 4fe9661421b03..85f5282034ff1 100644 --- a/src/libstd/sys/wasi/mod.rs +++ b/src/libstd/sys/wasi/mod.rs @@ -36,8 +36,6 @@ pub mod net; pub mod os; pub use crate::sys_common::os_str_bytes as os_str; pub mod ext; -#[path = "../wasm/fast_thread_local.rs"] -pub mod fast_thread_local; pub mod path; pub mod pipe; pub mod process; @@ -47,8 +45,10 @@ pub mod rwlock; pub mod stack_overflow; pub mod stdio; pub mod thread; -#[path = "../wasm/thread_local.rs"] -pub mod thread_local; +#[path = "../wasm/thread_local_dtor.rs"] +pub mod thread_local_dtor; +#[path = "../wasm/thread_local_key.rs"] +pub mod thread_local_key; pub mod time; #[cfg(not(test))] diff --git a/src/libstd/sys/wasm/mod.rs b/src/libstd/sys/wasm/mod.rs index 050e8099af4ba..6939596e52d78 100644 --- a/src/libstd/sys/wasm/mod.rs +++ b/src/libstd/sys/wasm/mod.rs @@ -20,7 +20,6 @@ pub mod alloc; pub mod args; pub mod cmath; pub mod env; -pub mod fast_thread_local; pub mod fs; pub mod io; pub mod memchr; @@ -32,7 +31,8 @@ pub mod process; pub mod stack_overflow; pub mod stdio; pub mod thread; -pub mod thread_local; +pub mod thread_local_dtor; +pub mod thread_local_key; pub mod time; pub use crate::sys_common::os_str_bytes as os_str; diff --git a/src/libstd/sys/wasm/fast_thread_local.rs b/src/libstd/sys/wasm/thread_local_dtor.rs similarity index 100% rename from src/libstd/sys/wasm/fast_thread_local.rs rename to src/libstd/sys/wasm/thread_local_dtor.rs diff --git a/src/libstd/sys/hermit/thread_local.rs b/src/libstd/sys/wasm/thread_local_key.rs similarity index 100% rename from src/libstd/sys/hermit/thread_local.rs rename to src/libstd/sys/wasm/thread_local_key.rs diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 193ab5b47ef13..9a52371280e15 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -20,7 +20,6 @@ pub mod cmath; pub mod condvar; pub mod env; pub mod ext; -pub mod fast_thread_local; pub mod fs; pub mod handle; pub mod io; @@ -35,7 +34,8 @@ pub mod process; pub mod rand; pub mod rwlock; pub mod thread; -pub mod thread_local; +pub mod thread_local_dtor; +pub mod thread_local_key; pub mod time; cfg_if::cfg_if! { if #[cfg(not(target_vendor = "uwp"))] { diff --git a/src/libstd/sys/windows/path.rs b/src/libstd/sys/windows/path.rs index 524f21f889bc2..dda3ed68cfc95 100644 --- a/src/libstd/sys/windows/path.rs +++ b/src/libstd/sys/windows/path.rs @@ -2,6 +2,16 @@ use crate::ffi::OsStr; use crate::mem; use crate::path::Prefix; +#[cfg(test)] +mod tests; + +pub const MAIN_SEP_STR: &str = "\\"; +pub const MAIN_SEP: char = '\\'; + +// The unsafety here stems from converting between `&OsStr` and `&[u8]` +// and back. This is safe to do because (1) we only look at ASCII +// contents of the encoding and (2) new &OsStr values are produced +// only from ASCII-bounded slices of existing &OsStr values. fn os_str_as_u8_slice(s: &OsStr) -> &[u8] { unsafe { mem::transmute(s) } } @@ -19,76 +29,79 @@ pub fn is_verbatim_sep(b: u8) -> bool { b == b'\\' } +// In most DOS systems, it is not possible to have more than 26 drive letters. +// See . +pub fn is_valid_drive_letter(disk: u8) -> bool { + disk.is_ascii_alphabetic() +} + pub fn parse_prefix(path: &OsStr) -> Option> { - use crate::path::Prefix::*; - unsafe { - // The unsafety here stems from converting between &OsStr and &[u8] - // and back. This is safe to do because (1) we only look at ASCII - // contents of the encoding and (2) new &OsStr values are produced - // only from ASCII-bounded slices of existing &OsStr values. - let mut path = os_str_as_u8_slice(path); + use Prefix::{DeviceNS, Disk, Verbatim, VerbatimDisk, VerbatimUNC, UNC}; + + let path = os_str_as_u8_slice(path); - if path.starts_with(br"\\") { - // \\ - path = &path[2..]; - if path.starts_with(br"?\") { - // \\?\ - path = &path[2..]; - if path.starts_with(br"UNC\") { - // \\?\UNC\server\share - path = &path[4..]; - let (server, share) = match parse_two_comps(path, is_verbatim_sep) { - Some((server, share)) => { - (u8_slice_as_os_str(server), u8_slice_as_os_str(share)) - } - None => (u8_slice_as_os_str(path), u8_slice_as_os_str(&[])), - }; - return Some(VerbatimUNC(server, share)); - } else { - // \\?\path - let idx = path.iter().position(|&b| b == b'\\'); - if idx == Some(2) && path[1] == b':' { - let c = path[0]; - if c.is_ascii() && (c as char).is_alphabetic() { - // \\?\C:\ path - return Some(VerbatimDisk(c.to_ascii_uppercase())); - } + // \\ + if let Some(path) = path.strip_prefix(br"\\") { + // \\?\ + if let Some(path) = path.strip_prefix(br"?\") { + // \\?\UNC\server\share + if let Some(path) = path.strip_prefix(br"UNC\") { + let (server, share) = match get_first_two_components(path, is_verbatim_sep) { + Some((server, share)) => unsafe { + (u8_slice_as_os_str(server), u8_slice_as_os_str(share)) + }, + None => (unsafe { u8_slice_as_os_str(path) }, OsStr::new("")), + }; + return Some(VerbatimUNC(server, share)); + } else { + // \\?\path + match path { + // \\?\C:\path + [c, b':', b'\\', ..] if is_valid_drive_letter(*c) => { + return Some(VerbatimDisk(c.to_ascii_uppercase())); + } + // \\?\cat_pics + _ => { + let idx = path.iter().position(|&b| b == b'\\').unwrap_or(path.len()); + let slice = &path[..idx]; + return Some(Verbatim(unsafe { u8_slice_as_os_str(slice) })); } - let slice = &path[..idx.unwrap_or(path.len())]; - return Some(Verbatim(u8_slice_as_os_str(slice))); - } - } else if path.starts_with(b".\\") { - // \\.\path - path = &path[2..]; - let pos = path.iter().position(|&b| b == b'\\'); - let slice = &path[..pos.unwrap_or(path.len())]; - return Some(DeviceNS(u8_slice_as_os_str(slice))); - } - match parse_two_comps(path, is_sep_byte) { - Some((server, share)) if !server.is_empty() && !share.is_empty() => { - // \\server\share - return Some(UNC(u8_slice_as_os_str(server), u8_slice_as_os_str(share))); } - _ => (), } - } else if path.get(1) == Some(&b':') { - // C: - let c = path[0]; - if c.is_ascii() && (c as char).is_alphabetic() { - return Some(Disk(c.to_ascii_uppercase())); + } else if let Some(path) = path.strip_prefix(b".\\") { + // \\.\COM42 + let idx = path.iter().position(|&b| b == b'\\').unwrap_or(path.len()); + let slice = &path[..idx]; + return Some(DeviceNS(unsafe { u8_slice_as_os_str(slice) })); + } + match get_first_two_components(path, is_sep_byte) { + Some((server, share)) if !server.is_empty() && !share.is_empty() => { + // \\server\share + return Some(unsafe { UNC(u8_slice_as_os_str(server), u8_slice_as_os_str(share)) }); } + _ => {} + } + } else if let [c, b':', ..] = path { + // C: + if is_valid_drive_letter(*c) { + return Some(Disk(c.to_ascii_uppercase())); } - return None; - } - - fn parse_two_comps(mut path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> { - let first = &path[..path.iter().position(|x| f(*x))?]; - path = &path[(first.len() + 1)..]; - let idx = path.iter().position(|x| f(*x)); - let second = &path[..idx.unwrap_or(path.len())]; - Some((first, second)) } + None } -pub const MAIN_SEP_STR: &str = "\\"; -pub const MAIN_SEP: char = '\\'; +/// Returns the first two path components with predicate `f`. +/// +/// The two components returned will be use by caller +/// to construct `VerbatimUNC` or `UNC` Windows path prefix. +/// +/// Returns [`None`] if there are no separators in path. +fn get_first_two_components(path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> { + let idx = path.iter().position(|&x| f(x))?; + // Panic safe + // The max `idx+1` is `path.len()` and `path[path.len()..]` is a valid index. + let (first, path) = (&path[..idx], &path[idx + 1..]); + let idx = path.iter().position(|&x| f(x)).unwrap_or(path.len()); + let second = &path[..idx]; + Some((first, second)) +} diff --git a/src/libstd/sys/windows/path/tests.rs b/src/libstd/sys/windows/path/tests.rs new file mode 100644 index 0000000000000..fbac1dc1ca17a --- /dev/null +++ b/src/libstd/sys/windows/path/tests.rs @@ -0,0 +1,21 @@ +use super::*; + +#[test] +fn test_get_first_two_components() { + assert_eq!( + get_first_two_components(br"server\share", is_verbatim_sep), + Some((&b"server"[..], &b"share"[..])), + ); + + assert_eq!( + get_first_two_components(br"server\", is_verbatim_sep), + Some((&b"server"[..], &b""[..])) + ); + + assert_eq!( + get_first_two_components(br"\server\", is_verbatim_sep), + Some((&b""[..], &b"server"[..])) + ); + + assert_eq!(get_first_two_components(br"there are no separators here", is_verbatim_sep), None,); +} diff --git a/src/libstd/sys/windows/fast_thread_local.rs b/src/libstd/sys/windows/thread_local_dtor.rs similarity index 52% rename from src/libstd/sys/windows/fast_thread_local.rs rename to src/libstd/sys/windows/thread_local_dtor.rs index 191fa07f32a55..7be13bc4b2bc7 100644 --- a/src/libstd/sys/windows/fast_thread_local.rs +++ b/src/libstd/sys/windows/thread_local_dtor.rs @@ -1,4 +1,4 @@ #![unstable(feature = "thread_local_internals", issue = "none")] #![cfg(target_thread_local)] -pub use crate::sys_common::thread_local::register_dtor_fallback as register_dtor; +pub use crate::sys_common::thread_local_dtor::register_dtor_fallback as register_dtor; diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local_key.rs similarity index 100% rename from src/libstd/sys/windows/thread_local.rs rename to src/libstd/sys/windows/thread_local_key.rs diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs index e03e0fc83454b..e57bb267cbd0f 100644 --- a/src/libstd/sys_common/mod.rs +++ b/src/libstd/sys_common/mod.rs @@ -65,7 +65,8 @@ pub mod remutex; pub mod rwlock; pub mod thread; pub mod thread_info; -pub mod thread_local; +pub mod thread_local_dtor; +pub mod thread_local_key; pub mod util; pub mod wtf8; diff --git a/src/libstd/sys_common/thread_local_dtor.rs b/src/libstd/sys_common/thread_local_dtor.rs new file mode 100644 index 0000000000000..6f5ebf4a27158 --- /dev/null +++ b/src/libstd/sys_common/thread_local_dtor.rs @@ -0,0 +1,49 @@ +//! Thread-local destructor +//! +//! Besides thread-local "keys" (pointer-sized non-adressable thread-local store +//! with an associated destructor), many platforms also provide thread-local +//! destructors that are not associated with any particular data. These are +//! often more efficient. +//! +//! This module provides a fallback implementation for that interface, based +//! on the less efficient thread-local "keys". Each platform provides +//! a `thread_local_dtor` module which will either re-export the fallback, +//! or implement something more efficient. + +#![unstable(feature = "thread_local_internals", issue = "none")] +#![allow(dead_code)] // sys isn't exported yet + +use crate::ptr; +use crate::sys_common::thread_local_key::StaticKey; + +pub unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { + // The fallback implementation uses a vanilla OS-based TLS key to track + // the list of destructors that need to be run for this thread. The key + // then has its own destructor which runs all the other destructors. + // + // The destructor for DTORS is a little special in that it has a `while` + // loop to continuously drain the list of registered destructors. It + // *should* be the case that this loop always terminates because we + // provide the guarantee that a TLS key cannot be set after it is + // flagged for destruction. + + static DTORS: StaticKey = StaticKey::new(Some(run_dtors)); + type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>; + if DTORS.get().is_null() { + let v: Box = box Vec::new(); + DTORS.set(Box::into_raw(v) as *mut u8); + } + let list: &mut List = &mut *(DTORS.get() as *mut List); + list.push((t, dtor)); + + unsafe extern "C" fn run_dtors(mut ptr: *mut u8) { + while !ptr.is_null() { + let list: Box = Box::from_raw(ptr as *mut List); + for (ptr, dtor) in list.into_iter() { + dtor(ptr); + } + ptr = DTORS.get(); + DTORS.set(ptr::null_mut()); + } + } +} diff --git a/src/libstd/sys_common/thread_local.rs b/src/libstd/sys_common/thread_local_key.rs similarity index 85% rename from src/libstd/sys_common/thread_local.rs rename to src/libstd/sys_common/thread_local_key.rs index 756b8d044a20e..ac5b128298d78 100644 --- a/src/libstd/sys_common/thread_local.rs +++ b/src/libstd/sys_common/thread_local_key.rs @@ -4,7 +4,7 @@ //! using the native OS-provided facilities (think `TlsAlloc` or //! `pthread_setspecific`). The interface of this differs from the other types //! of thread-local-storage provided in this crate in that OS-based TLS can only -//! get/set pointers, +//! get/set pointer-sized data, possibly with an associated destructor. //! //! This module also provides two flavors of TLS. One is intended for static //! initialization, and does not contain a `Drop` implementation to deallocate @@ -14,7 +14,7 @@ //! # Usage //! //! This module should likely not be used directly unless other primitives are -//! being built on. types such as `thread_local::spawn::Key` are likely much +//! being built on. Types such as `thread_local::spawn::Key` are likely much //! more useful in practice than this OS-based version which likely requires //! unsafe code to interoperate with. //! @@ -48,9 +48,8 @@ #![unstable(feature = "thread_local_internals", issue = "none")] #![allow(dead_code)] // sys isn't exported yet -use crate::ptr; use crate::sync::atomic::{self, AtomicUsize, Ordering}; -use crate::sys::thread_local as imp; +use crate::sys::thread_local_key as imp; use crate::sys_common::mutex::Mutex; /// A type for TLS keys that are statically allocated. @@ -233,38 +232,6 @@ impl Drop for Key { } } -pub unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { - // The fallback implementation uses a vanilla OS-based TLS key to track - // the list of destructors that need to be run for this thread. The key - // then has its own destructor which runs all the other destructors. - // - // The destructor for DTORS is a little special in that it has a `while` - // loop to continuously drain the list of registered destructors. It - // *should* be the case that this loop always terminates because we - // provide the guarantee that a TLS key cannot be set after it is - // flagged for destruction. - - static DTORS: StaticKey = StaticKey::new(Some(run_dtors)); - type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>; - if DTORS.get().is_null() { - let v: Box = box Vec::new(); - DTORS.set(Box::into_raw(v) as *mut u8); - } - let list: &mut List = &mut *(DTORS.get() as *mut List); - list.push((t, dtor)); - - unsafe extern "C" fn run_dtors(mut ptr: *mut u8) { - while !ptr.is_null() { - let list: Box = Box::from_raw(ptr as *mut List); - for (ptr, dtor) in list.into_iter() { - dtor(ptr); - } - ptr = DTORS.get(); - DTORS.set(ptr::null_mut()); - } - } -} - #[cfg(test)] mod tests { use super::{Key, StaticKey}; diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index 094c468a6770e..ecd6fbc6b9395 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -363,7 +363,7 @@ pub mod fast { use crate::cell::Cell; use crate::fmt; use crate::mem; - use crate::sys::fast_thread_local::register_dtor; + use crate::sys::thread_local_dtor::register_dtor; #[derive(Copy, Clone)] enum DtorState { @@ -468,7 +468,7 @@ pub mod os { use crate::fmt; use crate::marker; use crate::ptr; - use crate::sys_common::thread_local::StaticKey as OsStaticKey; + use crate::sys_common::thread_local_key::StaticKey as OsStaticKey; pub struct Key { // OS-TLS key that we'll use to key off. diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index d435ca6842518..d354a9b1842c2 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -641,9 +641,8 @@ where #[stable(feature = "rust1", since = "1.0.0")] pub fn current() -> Thread { thread_info::current_thread().expect( - "use of std::thread::current() is not \ - possible after the thread's local \ - data has been destroyed", + "use of std::thread::current() is not possible \ + after the thread's local data has been destroyed", ) } diff --git a/src/llvm-project b/src/llvm-project index d134a53927fa0..86b120e6f302d 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit d134a53927fa033ae7e0f3e8ee872ff2dc71468d +Subproject commit 86b120e6f302d39cd6973b6391fb299d7bc22122 diff --git a/src/test/codegen/intrinsics/nearby.rs b/src/test/codegen/intrinsics/nearby.rs new file mode 100644 index 0000000000000..520fe2f1886eb --- /dev/null +++ b/src/test/codegen/intrinsics/nearby.rs @@ -0,0 +1,18 @@ +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics; + +// CHECK-LABEL: @nearbyintf32 +#[no_mangle] +pub unsafe fn nearbyintf32(a: f32) -> f32 { + // CHECK: llvm.nearbyint.f32 + intrinsics::nearbyintf32(a) +} + +// CHECK-LABEL: @nearbyintf64 +#[no_mangle] +pub unsafe fn nearbyintf64(a: f64) -> f64 { + // CHECK: llvm.nearbyint.f64 + intrinsics::nearbyintf64(a) +} diff --git a/src/test/codegen/intrinsics/volatile.rs b/src/test/codegen/intrinsics/volatile.rs new file mode 100644 index 0000000000000..1970517e73262 --- /dev/null +++ b/src/test/codegen/intrinsics/volatile.rs @@ -0,0 +1,55 @@ +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics; + +// CHECK-LABEL: @volatile_copy_memory +#[no_mangle] +pub unsafe fn volatile_copy_memory(a: *mut u8, b: *const u8) { + // CHECK: llvm.memmove.p0i8.p0i8.{{\w*(.*true)}} + intrinsics::volatile_copy_memory(a, b, 1) +} + +// CHECK-LABEL: @volatile_copy_nonoverlapping_memory +#[no_mangle] +pub unsafe fn volatile_copy_nonoverlapping_memory(a: *mut u8, b: *const u8) { + // CHECK: llvm.memcpy.p0i8.p0i8.{{\w*(.*true)}} + intrinsics::volatile_copy_nonoverlapping_memory(a, b, 1) +} + +// CHECK-LABEL: @volatile_set_memory +#[no_mangle] +pub unsafe fn volatile_set_memory(a: *mut u8, b: u8) { + // CHECK: llvm.memset.p0i8.{{\w*(.*true)}} + intrinsics::volatile_set_memory(a, b, 1) +} + +// CHECK-LABEL: @volatile_load +#[no_mangle] +pub unsafe fn volatile_load(a: *const u8) -> u8 { + // CHECK: load volatile + intrinsics::volatile_load(a) +} + +// CHECK-LABEL: @volatile_store +#[no_mangle] +pub unsafe fn volatile_store(a: *mut u8, b: u8) { + // CHECK: store volatile + intrinsics::volatile_store(a, b) +} + +// CHECK-LABEL: @unaligned_volatile_load +#[no_mangle] +pub unsafe fn unaligned_volatile_load(a: *const u8) -> u8 { + // CHECK: load volatile + intrinsics::unaligned_volatile_load(a) +} + +// CHECK-LABEL: @unaligned_volatile_store +#[no_mangle] +pub unsafe fn unaligned_volatile_store(a: *mut u8, b: u8) { + // CHECK: store volatile + intrinsics::unaligned_volatile_store(a, b) +} diff --git a/src/test/codegen/intrinsics/volatile_order.rs b/src/test/codegen/intrinsics/volatile_order.rs new file mode 100644 index 0000000000000..29331219ba6ee --- /dev/null +++ b/src/test/codegen/intrinsics/volatile_order.rs @@ -0,0 +1,18 @@ +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::*; + +pub unsafe fn test_volatile_order() { + let mut a: Box = Box::new(0); + // CHECK: load volatile + let x = volatile_load(&*a); + // CHECK: load volatile + let x = volatile_load(&*a); + // CHECK: store volatile + volatile_store(&mut *a, 12); + // CHECK: store volatile + unaligned_volatile_store(&mut *a, 12); + // CHECK: llvm.memset.p0i8 + volatile_set_memory(&mut *a, 12, 1) +} diff --git a/src/test/pretty/issue-73626.rs b/src/test/pretty/issue-73626.rs new file mode 100644 index 0000000000000..a002f09be3b4e --- /dev/null +++ b/src/test/pretty/issue-73626.rs @@ -0,0 +1,34 @@ +fn main(/* + --- +*/) { + let x /* this is one line */ = 3; + + let x /* + * this + * is + * multiple + * lines + */ = 3; + + let x = /* + * this + * is + * multiple + * lines + * after + * the + * = + */ 3; + + let x /* + * this + * is + * multiple + * lines + * including + * a + + * blank + * line + */ = 3; +} diff --git a/src/test/rustdoc-ui/issue-74134.public.stderr b/src/test/rustdoc-ui/issue-74134.public.stderr new file mode 100644 index 0000000000000..03f95f19d326e --- /dev/null +++ b/src/test/rustdoc-ui/issue-74134.public.stderr @@ -0,0 +1,10 @@ +warning: `[PrivateType]` public documentation for `public_item` links to a private item + --> $DIR/issue-74134.rs:19:10 + | +LL | /// [`PrivateType`] + | ^^^^^^^^^^^^^ this item is private + | + = note: `#[warn(intra_doc_link_resolution_failure)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/rustdoc-ui/issue-74134.rs b/src/test/rustdoc-ui/issue-74134.rs new file mode 100644 index 0000000000000..d561c2dd89015 --- /dev/null +++ b/src/test/rustdoc-ui/issue-74134.rs @@ -0,0 +1,41 @@ +// revisions: public private +// [private]compile-flags: --document-private-items +// check-pass + +// There are 4 cases here: +// 1. public item -> public type: no warning +// 2. public item -> private type: warning, if --document-private-items is not passed +// 3. private item -> public type: no warning +// 4. private item -> private type: no warning +// All 4 cases are tested with and without --document-private-items. +// +// Case 4 without --document-private-items is the one described in issue #74134. + +struct PrivateType; +pub struct PublicType; + +pub struct Public { + /// [`PublicType`] + /// [`PrivateType`] + //[public]~^ WARNING public documentation for `public_item` links to a private + pub public_item: u32, + + /// [`PublicType`] + /// [`PrivateType`] + private_item: u32, +} + +// The following cases are identical to the ones above, except that they are in a private +// module. Thus they all fall into cases 3 and 4 and should not produce a warning. + +mod private { + pub struct Public { + /// [`super::PublicType`] + /// [`super::PrivateType`] + pub public_item: u32, + + /// [`super::PublicType`] + /// [`super::PrivateType`] + private_item: u32, + } +} diff --git a/src/test/rustdoc/attributes.rs b/src/test/rustdoc/attributes.rs index e9cd3514a07e2..54c5939f908d4 100644 --- a/src/test/rustdoc/attributes.rs +++ b/src/test/rustdoc/attributes.rs @@ -8,8 +8,8 @@ pub extern "C" fn f() {} #[export_name = "bar"] pub extern "C" fn g() {} -// @has foo/enum.Foo.html '//*[@class="docblock attributes top-attr"]' '#[repr(i64)]' -// @has foo/enum.Foo.html '//*[@class="docblock attributes top-attr"]' '#[must_use]' +// @matches foo/enum.Foo.html '//*[@class="docblock attributes top-attr"]' \ +// '(?m)\A#\[repr\(i64\)\]\n#\[must_use\]\Z' #[repr(i64)] #[must_use] pub enum Foo { diff --git a/src/test/ui/asm/type-check-1.stderr b/src/test/ui/asm/type-check-1.stderr index 7c9c041f45784..1f11d19c70ea2 100644 --- a/src/test/ui/asm/type-check-1.stderr +++ b/src/test/ui/asm/type-check-1.stderr @@ -17,7 +17,6 @@ LL | asm!("{}", in(reg) v[..]); | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u64]` - = note: to learn more, visit = note: all inline asm arguments must have a statically known size error[E0277]: the size for values of type `[u64]` cannot be known at compilation time @@ -27,7 +26,6 @@ LL | asm!("{}", out(reg) v[..]); | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u64]` - = note: to learn more, visit = note: all inline asm arguments must have a statically known size error[E0277]: the size for values of type `[u64]` cannot be known at compilation time @@ -37,7 +35,6 @@ LL | asm!("{}", inout(reg) v[..]); | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u64]` - = note: to learn more, visit = note: all inline asm arguments must have a statically known size error: aborting due to 5 previous errors diff --git a/src/test/ui/associated-types/associated-types-unsized.stderr b/src/test/ui/associated-types/associated-types-unsized.stderr index 6daba54ac6969..e96d0e0eff719 100644 --- a/src/test/ui/associated-types/associated-types-unsized.stderr +++ b/src/test/ui/associated-types/associated-types-unsized.stderr @@ -5,7 +5,6 @@ LL | let x = t.get(); | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `::Value` - = note: to learn more, visit = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature help: consider further restricting the associated type diff --git a/src/test/ui/associated-types/defaults-suitability.stderr b/src/test/ui/associated-types/defaults-suitability.stderr index 8676c1fa22319..de0acc88324a5 100644 --- a/src/test/ui/associated-types/defaults-suitability.stderr +++ b/src/test/ui/associated-types/defaults-suitability.stderr @@ -139,7 +139,6 @@ LL | pub struct Vec { | - required by this bound in `std::vec::Vec` | = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit error: aborting due to 11 previous errors diff --git a/src/test/ui/associated-types/defaults-unsound-62211-1.stderr b/src/test/ui/associated-types/defaults-unsound-62211-1.stderr index 69c310766c1cc..2ba854eac4665 100644 --- a/src/test/ui/associated-types/defaults-unsound-62211-1.stderr +++ b/src/test/ui/associated-types/defaults-unsound-62211-1.stderr @@ -21,7 +21,6 @@ LL | trait UncheckedCopy: Sized { LL | + AddAssign<&'static str> | ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str` | - = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `Self` help: consider further restricting `Self` | LL | trait UncheckedCopy: Sized + std::ops::AddAssign<&'static str> { @@ -50,7 +49,6 @@ LL | trait UncheckedCopy: Sized { LL | + Display = Self; | ^^^^^^^ `Self` cannot be formatted with the default formatter | - = help: the trait `std::fmt::Display` is not implemented for `Self` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead help: consider further restricting `Self` | @@ -69,7 +67,6 @@ LL | + Display = Self; LL | impl UncheckedCopy for T {} | ^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter | - = help: the trait `std::fmt::Display` is not implemented for `T` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead help: consider restricting type parameter `T` | @@ -105,7 +102,6 @@ LL | + AddAssign<&'static str> LL | impl UncheckedCopy for T {} | ^^^^^^^^^^^^^ no implementation for `T += &'static str` | - = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `T` help: consider restricting type parameter `T` | LL | impl> UncheckedCopy for T {} diff --git a/src/test/ui/associated-types/defaults-unsound-62211-2.stderr b/src/test/ui/associated-types/defaults-unsound-62211-2.stderr index 84f0ba7529ea2..d4fd0ca98ee54 100644 --- a/src/test/ui/associated-types/defaults-unsound-62211-2.stderr +++ b/src/test/ui/associated-types/defaults-unsound-62211-2.stderr @@ -21,7 +21,6 @@ LL | trait UncheckedCopy: Sized { LL | + AddAssign<&'static str> | ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str` | - = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `Self` help: consider further restricting `Self` | LL | trait UncheckedCopy: Sized + std::ops::AddAssign<&'static str> { @@ -50,7 +49,6 @@ LL | trait UncheckedCopy: Sized { LL | + Display = Self; | ^^^^^^^ `Self` cannot be formatted with the default formatter | - = help: the trait `std::fmt::Display` is not implemented for `Self` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead help: consider further restricting `Self` | @@ -69,7 +67,6 @@ LL | + Display = Self; LL | impl UncheckedCopy for T {} | ^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter | - = help: the trait `std::fmt::Display` is not implemented for `T` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead help: consider restricting type parameter `T` | @@ -105,7 +102,6 @@ LL | + AddAssign<&'static str> LL | impl UncheckedCopy for T {} | ^^^^^^^^^^^^^ no implementation for `T += &'static str` | - = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `T` help: consider restricting type parameter `T` | LL | impl> UncheckedCopy for T {} diff --git a/src/test/ui/associated-types/issue-63593.stderr b/src/test/ui/associated-types/issue-63593.stderr index 82e76ff0b7cb5..be3b61665b11f 100644 --- a/src/test/ui/associated-types/issue-63593.stderr +++ b/src/test/ui/associated-types/issue-63593.stderr @@ -6,8 +6,6 @@ LL | trait MyTrait { LL | type This = Self; | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `Self` - = note: to learn more, visit help: consider further restricting `Self` | LL | trait MyTrait: std::marker::Sized { diff --git a/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr b/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr index a37573dffff44..7813d3b6596bf 100644 --- a/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr +++ b/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr @@ -9,8 +9,6 @@ LL | trait ArithmeticOps: Add + Sub + Mul LL | pub trait Add { | --- required by this bound in `std::ops::Add` | - = help: the trait `std::marker::Sized` is not implemented for `Self` - = note: to learn more, visit help: consider further restricting `Self` | LL | trait ArithmeticOps: Add + Sub + Mul + Div + std::marker::Sized {} diff --git a/src/test/ui/async-await/issue-70818.stderr b/src/test/ui/async-await/issue-70818.stderr index 5fb772fa10acb..2166420070a07 100644 --- a/src/test/ui/async-await/issue-70818.stderr +++ b/src/test/ui/async-await/issue-70818.stderr @@ -7,7 +7,6 @@ LL | LL | async { (ty, ty1) } | ------------------- this returned value is of type `impl std::future::Future` | - = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `U` note: captured value is not `Send` --> $DIR/issue-70818.rs:6:18 | diff --git a/src/test/ui/async-await/issue-72590-type-error-sized.stderr b/src/test/ui/async-await/issue-72590-type-error-sized.stderr index 603895b598c16..762afa6450a95 100644 --- a/src/test/ui/async-await/issue-72590-type-error-sized.stderr +++ b/src/test/ui/async-await/issue-72590-type-error-sized.stderr @@ -17,10 +17,12 @@ LL | async fn frob(self) {} | ^^^^ doesn't have a size known at compile-time | = help: within `Foo`, the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: required because it appears within the type `Foo` - = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | async fn frob(&self) {} + | ^ error: aborting due to 3 previous errors diff --git a/src/test/ui/bad/bad-method-typaram-kind.stderr b/src/test/ui/bad/bad-method-typaram-kind.stderr index 81fc961e3dea0..fd3999ae6fbec 100644 --- a/src/test/ui/bad/bad-method-typaram-kind.stderr +++ b/src/test/ui/bad/bad-method-typaram-kind.stderr @@ -4,7 +4,6 @@ error[E0277]: `T` cannot be sent between threads safely LL | 1.bar::(); | ^^^ `T` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `T` help: consider further restricting this bound | LL | fn foo() { diff --git a/src/test/ui/bad/bad-sized.stderr b/src/test/ui/bad/bad-sized.stderr index 5c169af4eb8ae..47d8cc1f06fd1 100644 --- a/src/test/ui/bad/bad-sized.stderr +++ b/src/test/ui/bad/bad-sized.stderr @@ -21,7 +21,6 @@ LL | pub struct Vec { | - required by this bound in `std::vec::Vec` | = help: the trait `std::marker::Sized` is not implemented for `dyn Trait` - = note: to learn more, visit error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time --> $DIR/bad-sized.rs:4:37 @@ -30,7 +29,6 @@ LL | let x: Vec = Vec::new(); | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `dyn Trait` - = note: to learn more, visit = note: required by `std::vec::Vec::::new` error: aborting due to 3 previous errors diff --git a/src/test/ui/bound-suggestions.stderr b/src/test/ui/bound-suggestions.stderr index b9bc503f5301a..623252a8c1139 100644 --- a/src/test/ui/bound-suggestions.stderr +++ b/src/test/ui/bound-suggestions.stderr @@ -4,7 +4,6 @@ error[E0277]: `impl Sized` doesn't implement `std::fmt::Debug` LL | println!("{:?}", t); | ^ `impl Sized` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | - = help: the trait `std::fmt::Debug` is not implemented for `impl Sized` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting this bound @@ -18,7 +17,6 @@ error[E0277]: `T` doesn't implement `std::fmt::Debug` LL | println!("{:?}", t); | ^ `T` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | - = help: the trait `std::fmt::Debug` is not implemented for `T` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` @@ -32,7 +30,6 @@ error[E0277]: `T` doesn't implement `std::fmt::Debug` LL | println!("{:?}", t); | ^ `T` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | - = help: the trait `std::fmt::Debug` is not implemented for `T` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting this bound @@ -46,7 +43,6 @@ error[E0277]: `Y` doesn't implement `std::fmt::Debug` LL | println!("{:?} {:?}", x, y); | ^ `Y` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | - = help: the trait `std::fmt::Debug` is not implemented for `Y` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting type parameter `Y` @@ -60,7 +56,6 @@ error[E0277]: `X` doesn't implement `std::fmt::Debug` LL | println!("{:?}", x); | ^ `X` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | - = help: the trait `std::fmt::Debug` is not implemented for `X` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting this bound @@ -74,7 +69,6 @@ error[E0277]: `X` doesn't implement `std::fmt::Debug` LL | println!("{:?}", x); | ^ `X` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | - = help: the trait `std::fmt::Debug` is not implemented for `X` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting type parameter `X` diff --git a/src/test/ui/box-into-boxed-slice-fail.stderr b/src/test/ui/box-into-boxed-slice-fail.stderr index dfc4999958a57..b3e7b5b4feea4 100644 --- a/src/test/ui/box-into-boxed-slice-fail.stderr +++ b/src/test/ui/box-into-boxed-slice-fail.stderr @@ -5,7 +5,6 @@ LL | let _ = Box::into_boxed_slice(boxed_slice); | ^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: required by `std::boxed::Box::::into_boxed_slice` error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -15,7 +14,6 @@ LL | let _ = Box::into_boxed_slice(boxed_slice); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: slice and array elements must have `Sized` type error[E0277]: the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time @@ -25,7 +23,6 @@ LL | let _ = Box::into_boxed_slice(boxed_trait); | ^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `dyn std::fmt::Debug` - = note: to learn more, visit = note: required by `std::boxed::Box::::into_boxed_slice` error[E0277]: the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time @@ -35,7 +32,6 @@ LL | let _ = Box::into_boxed_slice(boxed_trait); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `dyn std::fmt::Debug` - = note: to learn more, visit = note: slice and array elements must have `Sized` type error: aborting due to 4 previous errors diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr index 4e7b513629d05..7ff986ec38109 100644 --- a/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr +++ b/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr @@ -7,7 +7,6 @@ LL | LL | impl Foo for (T,) { } | ^^^ `T` cannot be sent between threads safely | - = help: within `(T,)`, the trait `std::marker::Send` is not implemented for `T` = note: required because it appears within the type `(T,)` help: consider further restricting this bound | @@ -23,7 +22,6 @@ LL | trait Foo : Send+Sync { } LL | impl Foo for (T,T) { } | ^^^ `T` cannot be shared between threads safely | - = help: within `(T, T)`, the trait `std::marker::Sync` is not implemented for `T` = note: required because it appears within the type `(T, T)` help: consider further restricting this bound | diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr index 3fb1af3a67cc2..9ee045edfe546 100644 --- a/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr +++ b/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr @@ -9,7 +9,6 @@ LL | impl RequiresRequiresShareAndSend for X { } LL | pub trait RequiresRequiresShareAndSend : RequiresShare + Send { } | ---- required by this bound in `trait_superkinds_in_metadata::RequiresRequiresShareAndSend` | - = help: within `X`, the trait `std::marker::Send` is not implemented for `T` = note: required because it appears within the type `X` help: consider further restricting this bound | diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr index 9c5073a1e49d7..ad80b3fa8d11f 100644 --- a/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr +++ b/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr @@ -7,7 +7,6 @@ LL | LL | impl Foo for T { } | ^^^ `T` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `T` help: consider further restricting this bound | LL | impl Foo for T { } diff --git a/src/test/ui/chalkify/impl_wf.stderr b/src/test/ui/chalkify/impl_wf.stderr index e5d7615e43e31..fb2e0fc1a6169 100644 --- a/src/test/ui/chalkify/impl_wf.stderr +++ b/src/test/ui/chalkify/impl_wf.stderr @@ -8,7 +8,6 @@ LL | impl Foo for str { } | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit error[E0277]: the trait bound `f32: Foo` is not satisfied --> $DIR/impl_wf.rs:27:17 diff --git a/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr b/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr index ffd70fac6b19b..273eae995538a 100644 --- a/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr +++ b/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr @@ -7,7 +7,6 @@ LL | struct X where F: FnOnce() + 'static + Send { LL | fn foo(blk: F) -> X where F: FnOnce() + 'static { | ^^^^ `F` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `F` help: consider further restricting this bound | LL | fn foo(blk: F) -> X where F: FnOnce() + 'static + std::marker::Send { diff --git a/src/test/ui/closures/closure-bounds-subtype.stderr b/src/test/ui/closures/closure-bounds-subtype.stderr index 691864c9e1d45..7df29d5a098a0 100644 --- a/src/test/ui/closures/closure-bounds-subtype.stderr +++ b/src/test/ui/closures/closure-bounds-subtype.stderr @@ -7,7 +7,6 @@ LL | fn take_const_owned(_: F) where F: FnOnce() + Sync + Send { LL | take_const_owned(f); | ^ `F` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `F` help: consider further restricting this bound | LL | fn give_owned(f: F) where F: FnOnce() + Send + std::marker::Sync { diff --git a/src/test/ui/const-generics/array-size-in-generic-struct-param.stderr b/src/test/ui/const-generics/array-size-in-generic-struct-param.stderr index 14cf64eeb7ac6..ad67a87265bd3 100644 --- a/src/test/ui/const-generics/array-size-in-generic-struct-param.stderr +++ b/src/test/ui/const-generics/array-size-in-generic-struct-param.stderr @@ -16,10 +16,10 @@ LL | struct ArithArrayLen([u32; 0 + N]); = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/array-size-in-generic-struct-param.rs:14:5 + --> $DIR/array-size-in-generic-struct-param.rs:14:10 | LL | arr: [u8; CFG.arr_size], - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ | = note: this may fail depending on what value the parameter takes diff --git a/src/test/ui/consts/const-unsized.stderr b/src/test/ui/consts/const-unsized.stderr index beeea87bfb1d3..bf2844cfb70d6 100644 --- a/src/test/ui/consts/const-unsized.stderr +++ b/src/test/ui/consts/const-unsized.stderr @@ -5,7 +5,6 @@ LL | const CONST_0: dyn Debug + Sync = *(&0 as &(dyn Debug + Sync)); | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::fmt::Debug + std::marker::Sync + 'static)` - = note: to learn more, visit error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/const-unsized.rs:6:18 @@ -14,7 +13,6 @@ LL | const CONST_FOO: str = *"foo"; | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit error[E0277]: the size for values of type `(dyn std::fmt::Debug + std::marker::Sync + 'static)` cannot be known at compilation time --> $DIR/const-unsized.rs:9:18 @@ -23,7 +21,6 @@ LL | static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync)); | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::fmt::Debug + std::marker::Sync + 'static)` - = note: to learn more, visit error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/const-unsized.rs:12:20 @@ -32,7 +29,6 @@ LL | static STATIC_BAR: str = *"bar"; | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit error: aborting due to 4 previous errors diff --git a/src/test/ui/dst/dst-bad-assign-2.stderr b/src/test/ui/dst/dst-bad-assign-2.stderr index 4e1e67c7f4809..a5374aedab86b 100644 --- a/src/test/ui/dst/dst-bad-assign-2.stderr +++ b/src/test/ui/dst/dst-bad-assign-2.stderr @@ -5,7 +5,6 @@ LL | f5.ptr = *z; | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `dyn ToBar` - = note: to learn more, visit = note: the left-hand-side of an assignment must have a statically known size error: aborting due to previous error diff --git a/src/test/ui/dst/dst-bad-assign-3.stderr b/src/test/ui/dst/dst-bad-assign-3.stderr index 0b6f9df2d83ee..f8d9300f11a31 100644 --- a/src/test/ui/dst/dst-bad-assign-3.stderr +++ b/src/test/ui/dst/dst-bad-assign-3.stderr @@ -14,7 +14,6 @@ LL | f5.2 = Bar1 {f: 36}; | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `dyn ToBar` - = note: to learn more, visit = note: the left-hand-side of an assignment must have a statically known size error: aborting due to 2 previous errors diff --git a/src/test/ui/dst/dst-bad-assign.stderr b/src/test/ui/dst/dst-bad-assign.stderr index 434c460759fb4..8e3eeefb9ea66 100644 --- a/src/test/ui/dst/dst-bad-assign.stderr +++ b/src/test/ui/dst/dst-bad-assign.stderr @@ -14,7 +14,6 @@ LL | f5.ptr = Bar1 {f: 36}; | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `dyn ToBar` - = note: to learn more, visit = note: the left-hand-side of an assignment must have a statically known size error: aborting due to 2 previous errors diff --git a/src/test/ui/dst/dst-bad-deep-2.stderr b/src/test/ui/dst/dst-bad-deep-2.stderr index cb2735147a35b..d9d6ca3292311 100644 --- a/src/test/ui/dst/dst-bad-deep-2.stderr +++ b/src/test/ui/dst/dst-bad-deep-2.stderr @@ -5,7 +5,6 @@ LL | let h: &(([isize],),) = &(*g,); | ^^^^^ doesn't have a size known at compile-time | = help: within `(([isize],),)`, the trait `std::marker::Sized` is not implemented for `[isize]` - = note: to learn more, visit = note: required because it appears within the type `([isize],)` = note: required because it appears within the type `(([isize],),)` = note: tuples must have a statically known size to be initialized diff --git a/src/test/ui/dst/dst-bad-deep.stderr b/src/test/ui/dst/dst-bad-deep.stderr index 521adf601cc70..1304f04f82062 100644 --- a/src/test/ui/dst/dst-bad-deep.stderr +++ b/src/test/ui/dst/dst-bad-deep.stderr @@ -5,7 +5,6 @@ LL | let h: &Fat> = &Fat { ptr: *g }; | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: within `Fat>`, the trait `std::marker::Sized` is not implemented for `[isize]` - = note: to learn more, visit = note: required because it appears within the type `Fat<[isize]>` = note: required because it appears within the type `Fat>` = note: structs must have a statically known size to be initialized diff --git a/src/test/ui/dst/dst-object-from-unsized-type.stderr b/src/test/ui/dst/dst-object-from-unsized-type.stderr index 80d188bf2f89b..da8ead885c898 100644 --- a/src/test/ui/dst/dst-object-from-unsized-type.stderr +++ b/src/test/ui/dst/dst-object-from-unsized-type.stderr @@ -6,8 +6,6 @@ LL | fn test1(t: &T) { LL | let u: &dyn Foo = t; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `T` - = note: to learn more, visit = note: required for the cast to the object type `dyn Foo` error[E0277]: the size for values of type `T` cannot be known at compilation time @@ -18,8 +16,6 @@ LL | fn test2(t: &T) { LL | let v: &dyn Foo = t as &dyn Foo; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `T` - = note: to learn more, visit = note: required for the cast to the object type `dyn Foo` error[E0277]: the size for values of type `str` cannot be known at compilation time @@ -29,7 +25,6 @@ LL | let _: &[&dyn Foo] = &["hi"]; | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: required for the cast to the object type `dyn Foo` error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -39,7 +34,6 @@ LL | let _: &dyn Foo = x as &dyn Foo; | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: required for the cast to the object type `dyn Foo` error: aborting due to 4 previous errors diff --git a/src/test/ui/dst/dst-sized-trait-param.stderr b/src/test/ui/dst/dst-sized-trait-param.stderr index 006a334021b14..7e90e9ce1792d 100644 --- a/src/test/ui/dst/dst-sized-trait-param.stderr +++ b/src/test/ui/dst/dst-sized-trait-param.stderr @@ -8,7 +8,6 @@ LL | impl Foo<[isize]> for usize { } | ^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[isize]` - = note: to learn more, visit help: consider relaxing the implicit `Sized` restriction | LL | trait Foo : Sized { fn take(self, x: &T) { } } // Note: T is sized @@ -24,7 +23,6 @@ LL | impl Foo for [usize] { } | ^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[usize]` - = note: to learn more, visit error: aborting due to 2 previous errors diff --git a/src/test/ui/empty/empty-struct-braces-expr.stderr b/src/test/ui/empty/empty-struct-braces-expr.stderr index 9da3a5f5bdb3d..c0ba9716fb001 100644 --- a/src/test/ui/empty/empty-struct-braces-expr.stderr +++ b/src/test/ui/empty/empty-struct-braces-expr.stderr @@ -6,14 +6,20 @@ LL | struct Empty1 {} ... LL | let e1 = Empty1; | ^^^^^^ - | | - | did you mean `Empty1 { /* fields */ }`? - | help: a unit struct with a similar name exists: `XEmpty2` | ::: $DIR/auxiliary/empty-struct.rs:2:1 | LL | pub struct XEmpty2; | ------------------- similarly named unit struct `XEmpty2` defined here + | +help: a unit struct with a similar name exists + | +LL | let e1 = XEmpty2; + | ^^^^^^^ +help: use struct literal syntax instead + | +LL | let e1 = Empty1 {}; + | ^^^^^^^^^ error[E0423]: expected function, tuple struct or tuple variant, found struct `Empty1` --> $DIR/empty-struct-braces-expr.rs:16:14 @@ -22,15 +28,16 @@ LL | struct Empty1 {} | ---------------- `Empty1` defined here ... LL | let e1 = Empty1(); - | ^^^^^^ - | | - | did you mean `Empty1 { /* fields */ }`? - | help: a unit struct with a similar name exists: `XEmpty2` - | - ::: $DIR/auxiliary/empty-struct.rs:2:1 + | ^^^^^^^^ | -LL | pub struct XEmpty2; - | ------------------- similarly named unit struct `XEmpty2` defined here +help: a unit struct with a similar name exists + | +LL | let e1 = XEmpty2(); + | ^^^^^^^ +help: use struct literal syntax instead + | +LL | let e1 = Empty1 {}; + | ^^^^^^^^^ error[E0423]: expected value, found struct variant `E::Empty3` --> $DIR/empty-struct-braces-expr.rs:18:14 @@ -39,7 +46,7 @@ LL | Empty3 {} | --------- `E::Empty3` defined here ... LL | let e3 = E::Empty3; - | ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`? + | ^^^^^^^^^ help: use struct literal syntax instead: `E::Empty3 {}` error[E0423]: expected function, tuple struct or tuple variant, found struct variant `E::Empty3` --> $DIR/empty-struct-braces-expr.rs:19:14 @@ -48,35 +55,42 @@ LL | Empty3 {} | --------- `E::Empty3` defined here ... LL | let e3 = E::Empty3(); - | ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`? + | ^^^^^^^^^^^ help: use struct literal syntax instead: `E::Empty3 {}` error[E0423]: expected value, found struct `XEmpty1` --> $DIR/empty-struct-braces-expr.rs:22:15 | LL | let xe1 = XEmpty1; | ^^^^^^^ - | | - | did you mean `XEmpty1 { /* fields */ }`? - | help: a unit struct with a similar name exists: `XEmpty2` | ::: $DIR/auxiliary/empty-struct.rs:2:1 | LL | pub struct XEmpty2; | ------------------- similarly named unit struct `XEmpty2` defined here + | +help: a unit struct with a similar name exists + | +LL | let xe1 = XEmpty2; + | ^^^^^^^ +help: use struct literal syntax instead + | +LL | let xe1 = XEmpty1 {}; + | ^^^^^^^^^^ error[E0423]: expected function, tuple struct or tuple variant, found struct `XEmpty1` --> $DIR/empty-struct-braces-expr.rs:23:15 | LL | let xe1 = XEmpty1(); + | ^^^^^^^^^ + | +help: a unit struct with a similar name exists + | +LL | let xe1 = XEmpty2(); | ^^^^^^^ - | | - | did you mean `XEmpty1 { /* fields */ }`? - | help: a unit struct with a similar name exists: `XEmpty2` - | - ::: $DIR/auxiliary/empty-struct.rs:2:1 +help: use struct literal syntax instead | -LL | pub struct XEmpty2; - | ------------------- similarly named unit struct `XEmpty2` defined here +LL | let xe1 = XEmpty1 {}; + | ^^^^^^^^^^ error[E0599]: no variant or associated item named `Empty3` found for enum `empty_struct::XE` in the current scope --> $DIR/empty-struct-braces-expr.rs:25:19 diff --git a/src/test/ui/empty/empty-struct-braces-pat-1.stderr b/src/test/ui/empty/empty-struct-braces-pat-1.stderr index 0ff21c91b78fd..b027c82f7dd37 100644 --- a/src/test/ui/empty/empty-struct-braces-pat-1.stderr +++ b/src/test/ui/empty/empty-struct-braces-pat-1.stderr @@ -5,21 +5,27 @@ LL | Empty3 {} | --------- `E::Empty3` defined here ... LL | E::Empty3 => () - | ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`? + | ^^^^^^^^^ help: use struct pattern syntax instead: `E::Empty3 {}` error[E0532]: expected unit struct, unit variant or constant, found struct variant `XE::XEmpty3` --> $DIR/empty-struct-braces-pat-1.rs:31:9 | LL | XE::XEmpty3 => () - | ^^^^------- - | | | - | | help: a unit variant with a similar name exists: `XEmpty4` - | did you mean `XE::XEmpty3 { /* fields */ }`? + | ^^^^^^^^^^^ | ::: $DIR/auxiliary/empty-struct.rs:7:5 | LL | XEmpty4, | ------- similarly named unit variant `XEmpty4` defined here + | +help: a unit variant with a similar name exists + | +LL | XE::XEmpty4 => () + | ^^^^^^^ +help: use struct pattern syntax instead + | +LL | XE::XEmpty3 { /* fields */ } => () + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/empty/empty-struct-braces-pat-2.stderr b/src/test/ui/empty/empty-struct-braces-pat-2.stderr index 80c29db8d9b77..a53b88db7d1ed 100644 --- a/src/test/ui/empty/empty-struct-braces-pat-2.stderr +++ b/src/test/ui/empty/empty-struct-braces-pat-2.stderr @@ -5,29 +5,31 @@ LL | struct Empty1 {} | ---------------- `Empty1` defined here ... LL | Empty1() => () - | ^^^^^^ - | | - | did you mean `Empty1 { /* fields */ }`? - | help: a tuple struct with a similar name exists: `XEmpty6` - | - ::: $DIR/auxiliary/empty-struct.rs:3:1 - | -LL | pub struct XEmpty6(); - | --------------------- similarly named tuple struct `XEmpty6` defined here + | ^^^^^^^^ + | +help: a tuple struct with a similar name exists + | +LL | XEmpty6() => () + | ^^^^^^^ +help: use struct pattern syntax instead + | +LL | Empty1 {} => () + | ^^^^^^^^^ error[E0532]: expected tuple struct or tuple variant, found struct `XEmpty1` --> $DIR/empty-struct-braces-pat-2.rs:18:9 | LL | XEmpty1() => () + | ^^^^^^^^^ + | +help: a tuple struct with a similar name exists + | +LL | XEmpty6() => () | ^^^^^^^ - | | - | did you mean `XEmpty1 { /* fields */ }`? - | help: a tuple struct with a similar name exists: `XEmpty6` - | - ::: $DIR/auxiliary/empty-struct.rs:3:1 - | -LL | pub struct XEmpty6(); - | --------------------- similarly named tuple struct `XEmpty6` defined here +help: use struct pattern syntax instead + | +LL | XEmpty1 {} => () + | ^^^^^^^^^^ error[E0532]: expected tuple struct or tuple variant, found struct `Empty1` --> $DIR/empty-struct-braces-pat-2.rs:21:9 @@ -36,29 +38,31 @@ LL | struct Empty1 {} | ---------------- `Empty1` defined here ... LL | Empty1(..) => () - | ^^^^^^ - | | - | did you mean `Empty1 { /* fields */ }`? - | help: a tuple struct with a similar name exists: `XEmpty6` - | - ::: $DIR/auxiliary/empty-struct.rs:3:1 - | -LL | pub struct XEmpty6(); - | --------------------- similarly named tuple struct `XEmpty6` defined here + | ^^^^^^^^^^ + | +help: a tuple struct with a similar name exists + | +LL | XEmpty6(..) => () + | ^^^^^^^ +help: use struct pattern syntax instead + | +LL | Empty1 {} => () + | ^^^^^^^^^ error[E0532]: expected tuple struct or tuple variant, found struct `XEmpty1` --> $DIR/empty-struct-braces-pat-2.rs:24:9 | LL | XEmpty1(..) => () + | ^^^^^^^^^^^ + | +help: a tuple struct with a similar name exists + | +LL | XEmpty6(..) => () | ^^^^^^^ - | | - | did you mean `XEmpty1 { /* fields */ }`? - | help: a tuple struct with a similar name exists: `XEmpty6` - | - ::: $DIR/auxiliary/empty-struct.rs:3:1 - | -LL | pub struct XEmpty6(); - | --------------------- similarly named tuple struct `XEmpty6` defined here +help: use struct pattern syntax instead + | +LL | XEmpty1 {} => () + | ^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/empty/empty-struct-braces-pat-3.stderr b/src/test/ui/empty/empty-struct-braces-pat-3.stderr index 05439b39ea39d..93ace3eccef91 100644 --- a/src/test/ui/empty/empty-struct-braces-pat-3.stderr +++ b/src/test/ui/empty/empty-struct-braces-pat-3.stderr @@ -5,21 +5,22 @@ LL | Empty3 {} | --------- `E::Empty3` defined here ... LL | E::Empty3() => () - | ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`? + | ^^^^^^^^^^^ help: use struct pattern syntax instead: `E::Empty3 {}` error[E0532]: expected tuple struct or tuple variant, found struct variant `XE::XEmpty3` --> $DIR/empty-struct-braces-pat-3.rs:21:9 | LL | XE::XEmpty3() => () - | ^^^^------- - | | | - | | help: a tuple variant with a similar name exists: `XEmpty5` - | did you mean `XE::XEmpty3 { /* fields */ }`? - | - ::: $DIR/auxiliary/empty-struct.rs:8:5 - | -LL | XEmpty5(), - | --------- similarly named tuple variant `XEmpty5` defined here + | ^^^^^^^^^^^^^ + | +help: a tuple variant with a similar name exists + | +LL | XE::XEmpty5() => () + | ^^^^^^^ +help: use struct pattern syntax instead + | +LL | XE::XEmpty3 { /* fields */ } => () + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0532]: expected tuple struct or tuple variant, found struct variant `E::Empty3` --> $DIR/empty-struct-braces-pat-3.rs:25:9 @@ -28,21 +29,22 @@ LL | Empty3 {} | --------- `E::Empty3` defined here ... LL | E::Empty3(..) => () - | ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`? + | ^^^^^^^^^^^^^ help: use struct pattern syntax instead: `E::Empty3 {}` error[E0532]: expected tuple struct or tuple variant, found struct variant `XE::XEmpty3` --> $DIR/empty-struct-braces-pat-3.rs:29:9 | LL | XE::XEmpty3(..) => () - | ^^^^------- - | | | - | | help: a tuple variant with a similar name exists: `XEmpty5` - | did you mean `XE::XEmpty3 { /* fields */ }`? - | - ::: $DIR/auxiliary/empty-struct.rs:8:5 - | -LL | XEmpty5(), - | --------- similarly named tuple variant `XEmpty5` defined here + | ^^^^^^^^^^^^^^^ + | +help: a tuple variant with a similar name exists + | +LL | XE::XEmpty5(..) => () + | ^^^^^^^ +help: use struct pattern syntax instead + | +LL | XE::XEmpty3 { /* fields */ } => () + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/error-codes/E0277.stderr b/src/test/ui/error-codes/E0277.stderr index a9ea85d14cff5..203fc18915647 100644 --- a/src/test/ui/error-codes/E0277.stderr +++ b/src/test/ui/error-codes/E0277.stderr @@ -2,13 +2,15 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> $DIR/E0277.rs:13:6 | LL | fn f(p: Path) { } - | ^ borrow the `Path` instead + | ^ doesn't have a size known at compile-time | = help: within `std::path::Path`, the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: required because it appears within the type `std::path::Path` - = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn f(p: &Path) { } + | ^ error[E0277]: the trait bound `i32: Foo` is not satisfied --> $DIR/E0277.rs:17:15 diff --git a/src/test/ui/error-codes/E0423.stderr b/src/test/ui/error-codes/E0423.stderr index d4860394259b7..077367de9d847 100644 --- a/src/test/ui/error-codes/E0423.stderr +++ b/src/test/ui/error-codes/E0423.stderr @@ -33,13 +33,16 @@ LL | struct Foo { a: bool }; | ---------------------- `Foo` defined here LL | LL | let f = Foo(); + | ^^^^^ + | +help: a function with a similar name exists + | +LL | let f = foo(); | ^^^ - | | - | did you mean `Foo { /* fields */ }`? - | help: a function with a similar name exists (notice the capitalization): `foo` -... -LL | fn foo() { - | -------- similarly named function `foo` defined here +help: use struct literal syntax instead + | +LL | let f = Foo { a: val }; + | ^^^^^^^^^^^^^^ error[E0423]: expected value, found struct `T` --> $DIR/E0423.rs:14:8 diff --git a/src/test/ui/error-codes/E0478.stderr b/src/test/ui/error-codes/E0478.stderr index 1380840e0db2d..38736de8d9ac7 100644 --- a/src/test/ui/error-codes/E0478.stderr +++ b/src/test/ui/error-codes/E0478.stderr @@ -1,8 +1,8 @@ error[E0478]: lifetime bound not satisfied - --> $DIR/E0478.rs:4:5 + --> $DIR/E0478.rs:4:12 | LL | child: Box + 'SnowWhite>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime `'SnowWhite` as defined on the struct at 3:22 --> $DIR/E0478.rs:3:22 diff --git a/src/test/ui/extern/extern-types-unsized.stderr b/src/test/ui/extern/extern-types-unsized.stderr index 0c7995fde3273..8938afd33ffde 100644 --- a/src/test/ui/extern/extern-types-unsized.stderr +++ b/src/test/ui/extern/extern-types-unsized.stderr @@ -8,7 +8,6 @@ LL | assert_sized::
(); | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `A` - = note: to learn more, visit help: consider relaxing the implicit `Sized` restriction | LL | fn assert_sized() { } @@ -24,7 +23,6 @@ LL | assert_sized::(); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: within `Foo`, the trait `std::marker::Sized` is not implemented for `A` - = note: to learn more, visit = note: required because it appears within the type `Foo` help: consider relaxing the implicit `Sized` restriction | @@ -41,7 +39,6 @@ LL | assert_sized::>(); | ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: within `Bar`, the trait `std::marker::Sized` is not implemented for `A` - = note: to learn more, visit = note: required because it appears within the type `Bar` help: consider relaxing the implicit `Sized` restriction | @@ -58,7 +55,6 @@ LL | assert_sized::>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: within `Bar>`, the trait `std::marker::Sized` is not implemented for `A` - = note: to learn more, visit = note: required because it appears within the type `Bar` = note: required because it appears within the type `Bar>` help: consider relaxing the implicit `Sized` restriction diff --git a/src/test/ui/extern/issue-36122-accessing-externed-dst.stderr b/src/test/ui/extern/issue-36122-accessing-externed-dst.stderr index add3a8e79267d..5a58e57d36c70 100644 --- a/src/test/ui/extern/issue-36122-accessing-externed-dst.stderr +++ b/src/test/ui/extern/issue-36122-accessing-externed-dst.stderr @@ -5,7 +5,6 @@ LL | static symbol: [usize]; | ^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[usize]` - = note: to learn more, visit error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr b/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr index 2beeba8184a7d..987cde191cbb9 100644 --- a/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr +++ b/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr @@ -1,10 +1,10 @@ error[E0310]: the parameter type `U` may not live long enough - --> $DIR/feature-gate-infer_static_outlives_requirements.rs:5:5 + --> $DIR/feature-gate-infer_static_outlives_requirements.rs:5:10 | LL | struct Foo { | - help: consider adding an explicit lifetime bound...: `U: 'static` LL | bar: Bar - | ^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds + | ^^^^^^ ...so that the type `U` will meet its required lifetime bounds error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr b/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr index b4d4c992c9086..d4c09ec40fd92 100644 --- a/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr +++ b/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr @@ -95,7 +95,6 @@ LL | struct TwoStrs(str, str) where str: Sized; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = help: see issue #48214 = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable @@ -108,7 +107,6 @@ LL | | } | |_^ doesn't have a size known at compile-time | = help: within `Dst<(dyn A + 'static)>`, the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)` - = note: to learn more, visit = note: required because it appears within the type `Dst<(dyn A + 'static)>` = help: see issue #48214 = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable @@ -122,7 +120,6 @@ LL | | } | |_^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = help: see issue #48214 = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr b/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr index d20b9e2981e8c..0195cc1481e74 100644 --- a/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr +++ b/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr @@ -5,9 +5,11 @@ LL | fn f(f: dyn FnOnce()) {} | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::FnOnce() + 'static)` - = note: to learn more, visit - = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn f(f: &dyn FnOnce()) {} + | ^ error: aborting due to previous error diff --git a/src/test/ui/generator/sized-yield.stderr b/src/test/ui/generator/sized-yield.stderr index 79aeec2ec0280..379bd8ebd1cad 100644 --- a/src/test/ui/generator/sized-yield.stderr +++ b/src/test/ui/generator/sized-yield.stderr @@ -9,7 +9,6 @@ LL | | }; | |____^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: the yield type of a generator must have a statically known size error[E0277]: the size for values of type `str` cannot be known at compilation time @@ -19,7 +18,6 @@ LL | Pin::new(&mut gen).resume(()); | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit error: aborting due to 2 previous errors diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr index 89cc5dfd06018..2fab7ffb66050 100644 --- a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr +++ b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr @@ -16,7 +16,6 @@ LL | type F<'a>: Fn() -> u32; LL | type F<'a> = Self; | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` | - = help: the trait `std::ops::Fn<()>` is not implemented for `T` = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } help: consider restricting type parameter `T` | diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr index efd3287853f03..186e142138be2 100644 --- a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr +++ b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr @@ -16,7 +16,6 @@ LL | type F<'a>: Fn() -> u32; LL | type F<'a> = Self; | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` | - = help: the trait `std::ops::Fn<()>` is not implemented for `T` = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } help: consider restricting type parameter `T` | diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr index 5da924a512f00..d16bdcbbb6b00 100644 --- a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr +++ b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr @@ -16,7 +16,6 @@ LL | type F<'a>: Fn() -> u32; LL | type F<'a> = Self; | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` | - = help: the trait `std::ops::Fn<()>` is not implemented for `T` = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } help: consider restricting type parameter `T` | diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr index 12d84ab6a369b..72c42917c83c9 100644 --- a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr +++ b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr @@ -16,7 +16,6 @@ LL | type F<'a>: Fn() -> u32; LL | type F<'a> = Self; | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` | - = help: the trait `std::ops::Fn<()>` is not implemented for `T` = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } help: consider restricting type parameter `T` | diff --git a/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr b/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr index 95f4aa9e6dbaa..7a6c07d4e082e 100644 --- a/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr +++ b/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr @@ -8,7 +8,6 @@ LL | impl Tsized for () {} | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[()]` - = note: to learn more, visit error: aborting due to previous error diff --git a/src/test/ui/hygiene/unpretty-debug.stdout b/src/test/ui/hygiene/unpretty-debug.stdout index 81164030d8eef..96044a8928946 100644 --- a/src/test/ui/hygiene/unpretty-debug.stdout +++ b/src/test/ui/hygiene/unpretty-debug.stdout @@ -10,7 +10,10 @@ macro_rules! foo /* 0#0 */ { ($ x : ident) => { y + $ x } } -fn bar /* 0#0 */() { let x /* 0#0 */ = 1; y /* 0#1 */ + x /* 0#0 */ } +fn bar /* 0#0 */() { + let x /* 0#0 */ = 1; + y /* 0#1 */ + x /* 0#0 */ +} fn y /* 0#0 */() { } diff --git a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr index c55dbd7d2fafe..96f961a2aaf6b 100644 --- a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr +++ b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr @@ -16,7 +16,6 @@ LL | fn fuz() -> (usize, Trait) { (42, Struct) } | doesn't have a size known at compile-time | = help: within `(usize, (dyn Trait + 'static))`, the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)` - = note: to learn more, visit = note: required because it appears within the type `(usize, (dyn Trait + 'static))` = note: the return type of a function must have a statically known size @@ -38,7 +37,6 @@ LL | fn bar() -> (usize, dyn Trait) { (42, Struct) } | doesn't have a size known at compile-time | = help: within `(usize, (dyn Trait + 'static))`, the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)` - = note: to learn more, visit = note: required because it appears within the type `(usize, (dyn Trait + 'static))` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/in-band-lifetimes/E0688.stderr b/src/test/ui/in-band-lifetimes/E0688.stderr index 0078cd58001e3..afefcd9fc2c66 100644 --- a/src/test/ui/in-band-lifetimes/E0688.stderr +++ b/src/test/ui/in-band-lifetimes/E0688.stderr @@ -24,3 +24,4 @@ LL | impl<'b> Foo<'a> { error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0688`. diff --git a/src/test/ui/intrinsics/intrinsic-nearby.rs b/src/test/ui/intrinsics/intrinsic-nearby.rs new file mode 100644 index 0000000000000..7b1d1eeaadbd0 --- /dev/null +++ b/src/test/ui/intrinsics/intrinsic-nearby.rs @@ -0,0 +1,11 @@ +// run-pass +#![feature(core_intrinsics)] + +use std::intrinsics::*; + +fn main() { + unsafe { + assert_eq!(nearbyintf32(5.234f32), 5f32); + assert_eq!(nearbyintf64(6.777f64), 7f64); + } +} diff --git a/src/test/ui/intrinsics/intrinsic-volatile.rs b/src/test/ui/intrinsics/intrinsic-volatile.rs new file mode 100644 index 0000000000000..7b2c825a2084b --- /dev/null +++ b/src/test/ui/intrinsics/intrinsic-volatile.rs @@ -0,0 +1,44 @@ +// run-pass + +#![feature(core_intrinsics)] + +use std::intrinsics::*; + +pub fn main() { + unsafe { + let mut x: Box = Box::new(0); + let mut y: Box = Box::new(0); + + // test volatile load + assert_eq!(volatile_load(&*x), 0); + *x = 1; + assert_eq!(volatile_load(&*x), 1); + + // test volatile store + volatile_store(&mut *x, 2); + assert_eq!(*x, 2); + + // test volatile copy memory + volatile_copy_memory(&mut *y, &*x, 1); + assert_eq!(*y, 2); + + // test volatile copy non-overlapping memory + *x = 3; + volatile_copy_nonoverlapping_memory(&mut *y, &*x, 1); + assert_eq!(*y, 3); + + // test volatile set memory + volatile_set_memory(&mut *x, 4, 1); + assert_eq!(*x, 4); + + // test unaligned volatile load + let arr: [u8; 3] = [1, 2, 3]; + let ptr = arr[1..].as_ptr() as *const u16; + assert_eq!(unaligned_volatile_load(ptr), u16::from_ne_bytes([arr[1], arr[2]])); + + // test unaligned volatile store + let ptr = arr[1..].as_ptr() as *mut u16; + unaligned_volatile_store(ptr, 0); + assert_eq!(arr, [1, 0, 0]); + } +} diff --git a/src/test/ui/issues/auxiliary/issue-73112.rs b/src/test/ui/issues/auxiliary/issue-73112.rs new file mode 100644 index 0000000000000..6210c29bbdc8c --- /dev/null +++ b/src/test/ui/issues/auxiliary/issue-73112.rs @@ -0,0 +1,10 @@ +#[repr(transparent)] +pub struct PageTableEntry { + entry: u64, +} + +#[repr(align(4096))] +#[repr(C)] +pub struct PageTable { + entries: [PageTableEntry; 512], +} diff --git a/src/test/ui/issues/issue-10412.stderr b/src/test/ui/issues/issue-10412.stderr index d7a4bf4f21f18..d241e6406d579 100644 --- a/src/test/ui/issues/issue-10412.stderr +++ b/src/test/ui/issues/issue-10412.stderr @@ -56,7 +56,6 @@ LL | impl<'self> Serializable for &'self str { | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit help: consider relaxing the implicit `Sized` restriction | LL | trait Serializable<'self, T: ?Sized> { diff --git a/src/test/ui/issues/issue-14366.stderr b/src/test/ui/issues/issue-14366.stderr index 542d8a904c4e3..4e41acf433e59 100644 --- a/src/test/ui/issues/issue-14366.stderr +++ b/src/test/ui/issues/issue-14366.stderr @@ -5,7 +5,6 @@ LL | let _x = "test" as &dyn (::std::any::Any); | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: required for the cast to the object type `dyn std::any::Any` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-15756.stderr b/src/test/ui/issues/issue-15756.stderr index 987bc512163d6..68ceebc5b651d 100644 --- a/src/test/ui/issues/issue-15756.stderr +++ b/src/test/ui/issues/issue-15756.stderr @@ -5,7 +5,6 @@ LL | &mut something | ^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[T]` - = note: to learn more, visit = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/issues/issue-17651.stderr b/src/test/ui/issues/issue-17651.stderr index c3445024c3752..812778911a865 100644 --- a/src/test/ui/issues/issue-17651.stderr +++ b/src/test/ui/issues/issue-17651.stderr @@ -5,7 +5,6 @@ LL | (|| Box::new(*(&[0][..])))(); | ^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[{integer}]` - = note: to learn more, visit = note: required by `std::boxed::Box::::new` error[E0277]: the size for values of type `[{integer}]` cannot be known at compilation time @@ -15,7 +14,6 @@ LL | (|| Box::new(*(&[0][..])))(); | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[{integer}]` - = note: to learn more, visit = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/issues/issue-18919.stderr b/src/test/ui/issues/issue-18919.stderr index 383cdd4979ad9..3b5dfd1ad158c 100644 --- a/src/test/ui/issues/issue-18919.stderr +++ b/src/test/ui/issues/issue-18919.stderr @@ -8,7 +8,6 @@ LL | enum Option { | - required by this bound in `Option` | = help: the trait `std::marker::Sized` is not implemented for `dyn for<'r> std::ops::Fn(&'r isize) -> isize` - = note: to learn more, visit help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/issue-18919.rs:7:13 | diff --git a/src/test/ui/issues/issue-19086.stderr b/src/test/ui/issues/issue-19086.stderr index 27992da0ebd2f..a54f1008e4ba9 100644 --- a/src/test/ui/issues/issue-19086.stderr +++ b/src/test/ui/issues/issue-19086.stderr @@ -5,7 +5,7 @@ LL | FooB { x: i32, y: i32 } | ----------------------- `FooB` defined here ... LL | FooB(a, b) => println!("{} {}", a, b), - | ^^^^ did you mean `FooB { /* fields */ }`? + | ^^^^^^^^^^ help: use struct pattern syntax instead: `FooB { x, y }` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-19380.stderr b/src/test/ui/issues/issue-19380.stderr index 0a080171a7951..63f0701974b8b 100644 --- a/src/test/ui/issues/issue-19380.stderr +++ b/src/test/ui/issues/issue-19380.stderr @@ -1,5 +1,5 @@ error[E0038]: the trait `Qiz` cannot be made into an object - --> $DIR/issue-19380.rs:11:3 + --> $DIR/issue-19380.rs:11:9 | LL | trait Qiz { | --- this trait cannot be made into an object... @@ -7,7 +7,7 @@ LL | fn qiz(); | --- ...because associated function `qiz` has no `self` parameter ... LL | foos: &'static [&'static (dyn Qiz + 'static)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Qiz` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Qiz` cannot be made into an object | help: consider turning `qiz` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects | diff --git a/src/test/ui/issues/issue-20005.stderr b/src/test/ui/issues/issue-20005.stderr index 775f9702401a6..cbaa7507244a3 100644 --- a/src/test/ui/issues/issue-20005.stderr +++ b/src/test/ui/issues/issue-20005.stderr @@ -7,8 +7,6 @@ LL | trait From { LL | ) -> >::Result where Dst: From { | ^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `Self` - = note: to learn more, visit help: consider further restricting `Self` | LL | ) -> >::Result where Dst: From, Self: std::marker::Sized { diff --git a/src/test/ui/issues/issue-20433.stderr b/src/test/ui/issues/issue-20433.stderr index 1dab637e489db..0e96b12066937 100644 --- a/src/test/ui/issues/issue-20433.stderr +++ b/src/test/ui/issues/issue-20433.stderr @@ -10,7 +10,6 @@ LL | pub struct Vec { | - required by this bound in `std::vec::Vec` | = help: the trait `std::marker::Sized` is not implemented for `[i32]` - = note: to learn more, visit error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20605.stderr b/src/test/ui/issues/issue-20605.stderr index 5e050f27ac546..5e06e3bc95c36 100644 --- a/src/test/ui/issues/issue-20605.stderr +++ b/src/test/ui/issues/issue-20605.stderr @@ -5,7 +5,6 @@ LL | for item in *things { *item = 0 } | ^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `dyn std::iter::Iterator` - = note: to learn more, visit = note: required by `std::iter::IntoIterator::into_iter` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-22874.stderr b/src/test/ui/issues/issue-22874.stderr index 229f99f90640b..6f22fe6a99717 100644 --- a/src/test/ui/issues/issue-22874.stderr +++ b/src/test/ui/issues/issue-22874.stderr @@ -1,11 +1,10 @@ error[E0277]: the size for values of type `[std::string::String]` cannot be known at compilation time - --> $DIR/issue-22874.rs:2:5 + --> $DIR/issue-22874.rs:2:11 | LL | rows: [[String]], - | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[std::string::String]` - = note: to learn more, visit = note: slice and array elements must have `Sized` type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23281.stderr b/src/test/ui/issues/issue-23281.stderr index cffa52361696c..46b4be6fd3649 100644 --- a/src/test/ui/issues/issue-23281.stderr +++ b/src/test/ui/issues/issue-23281.stderr @@ -8,7 +8,6 @@ LL | struct Vec { | - required by this bound in `Vec` | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() + 'static)` - = note: to learn more, visit help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/issue-23281.rs:8:12 | diff --git a/src/test/ui/issues/issue-24446.stderr b/src/test/ui/issues/issue-24446.stderr index 344443e783038..d2714408d8a39 100644 --- a/src/test/ui/issues/issue-24446.stderr +++ b/src/test/ui/issues/issue-24446.stderr @@ -5,7 +5,6 @@ LL | static foo: dyn Fn() -> u32 = || -> u32 { | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() -> u32 + 'static)` - = note: to learn more, visit error: aborting due to previous error diff --git a/src/test/ui/issues/issue-27060-2.stderr b/src/test/ui/issues/issue-27060-2.stderr index 1ddea73e00ae0..5dbcc96e87488 100644 --- a/src/test/ui/issues/issue-27060-2.stderr +++ b/src/test/ui/issues/issue-27060-2.stderr @@ -1,14 +1,21 @@ error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/issue-27060-2.rs:3:5 + --> $DIR/issue-27060-2.rs:3:11 | LL | pub struct Bad { | - this type parameter needs to be `std::marker::Sized` LL | data: T, - | ^^^^^^^ doesn't have a size known at compile-time + | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `T` - = note: to learn more, visit = note: the last field of a packed struct may only have a dynamically sized type if it does not need drop to be run + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | data: &T, + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | data: Box, + | ^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-27078.stderr b/src/test/ui/issues/issue-27078.stderr index 3eb9d3c62039f..de1810e99aac6 100644 --- a/src/test/ui/issues/issue-27078.stderr +++ b/src/test/ui/issues/issue-27078.stderr @@ -4,14 +4,15 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation LL | fn foo(self) -> &'static i32 { | ^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `Self` - = note: to learn more, visit - = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature help: consider further restricting `Self` | LL | fn foo(self) -> &'static i32 where Self: std::marker::Sized { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo(&self) -> &'static i32 { + | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-30355.stderr b/src/test/ui/issues/issue-30355.stderr index 48b151c73c956..98de768a5a819 100644 --- a/src/test/ui/issues/issue-30355.stderr +++ b/src/test/ui/issues/issue-30355.stderr @@ -5,7 +5,6 @@ LL | &X(*Y) | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/issues/issue-34334.stderr b/src/test/ui/issues/issue-34334.stderr index c68b271807b99..5f157f6e3c089 100644 --- a/src/test/ui/issues/issue-34334.stderr +++ b/src/test/ui/issues/issue-34334.stderr @@ -23,7 +23,7 @@ error[E0423]: expected value, found struct `Vec` --> $DIR/issue-34334.rs:2:13 | LL | let sr: Vec<(u32, _, _) = vec![]; - | ^^^ did you mean `Vec { /* fields */ }`? + | ^^^ help: use struct literal syntax instead: `Vec { buf: val, len: val }` error[E0308]: mismatched types --> $DIR/issue-34334.rs:2:31 diff --git a/src/test/ui/issues/issue-35988.stderr b/src/test/ui/issues/issue-35988.stderr index 825c0de5e53ea..0f0b80a9ff8d3 100644 --- a/src/test/ui/issues/issue-35988.stderr +++ b/src/test/ui/issues/issue-35988.stderr @@ -5,8 +5,16 @@ LL | V([Box]), | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[std::boxed::Box]` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | V(&[Box]), + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | V(Box<[Box]>), + | ^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-38954.stderr b/src/test/ui/issues/issue-38954.stderr index d3168ef9e4aaf..e96bbe1a99312 100644 --- a/src/test/ui/issues/issue-38954.stderr +++ b/src/test/ui/issues/issue-38954.stderr @@ -5,9 +5,11 @@ LL | fn _test(ref _p: str) {} | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit - = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn _test(ref _p: &str) {} + | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-41229-ref-str.stderr b/src/test/ui/issues/issue-41229-ref-str.stderr index 9d854e4be9ead..35aa1acdc1c9b 100644 --- a/src/test/ui/issues/issue-41229-ref-str.stderr +++ b/src/test/ui/issues/issue-41229-ref-str.stderr @@ -5,9 +5,11 @@ LL | pub fn example(ref s: str) {} | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit - = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | pub fn example(ref s: &str) {} + | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-42312.stderr b/src/test/ui/issues/issue-42312.stderr index 0d4797a7a0673..fbe87aa2dbee5 100644 --- a/src/test/ui/issues/issue-42312.stderr +++ b/src/test/ui/issues/issue-42312.stderr @@ -5,13 +5,15 @@ LL | fn baz(_: Self::Target) where Self: Deref {} | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `::Target` - = note: to learn more, visit - = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature help: consider further restricting the associated type | LL | fn baz(_: Self::Target) where Self: Deref, ::Target: std::marker::Sized {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn baz(_: &Self::Target) where Self: Deref {} + | ^ error[E0277]: the size for values of type `(dyn std::string::ToString + 'static)` cannot be known at compilation time --> $DIR/issue-42312.rs:8:10 @@ -20,9 +22,11 @@ LL | pub fn f(_: dyn ToString) {} | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::string::ToString + 'static)` - = note: to learn more, visit - = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | pub fn f(_: &dyn ToString) {} + | ^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-54410.stderr b/src/test/ui/issues/issue-54410.stderr index 992c691bf21ef..9205a518c8c3a 100644 --- a/src/test/ui/issues/issue-54410.stderr +++ b/src/test/ui/issues/issue-54410.stderr @@ -5,7 +5,6 @@ LL | pub static mut symbol: [i8]; | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[i8]` - = note: to learn more, visit error: aborting due to previous error diff --git a/src/test/ui/issues/issue-5883.stderr b/src/test/ui/issues/issue-5883.stderr index d886ecc11d17b..897984d0ae410 100644 --- a/src/test/ui/issues/issue-5883.stderr +++ b/src/test/ui/issues/issue-5883.stderr @@ -5,9 +5,11 @@ LL | fn new_struct(r: dyn A + 'static) | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)` - = note: to learn more, visit - = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn new_struct(r: &dyn A + 'static) + | ^ error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time --> $DIR/issue-5883.rs:8:8 @@ -19,7 +21,6 @@ LL | Struct { r: r } | --------------- this returned value is of type `Struct` | = help: within `Struct`, the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)` - = note: to learn more, visit = note: required because it appears within the type `Struct` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/issues/issue-63983.stderr b/src/test/ui/issues/issue-63983.stderr index e54466faedde6..771a5c285aff8 100644 --- a/src/test/ui/issues/issue-63983.stderr +++ b/src/test/ui/issues/issue-63983.stderr @@ -14,7 +14,7 @@ LL | Struct{ s: i32 }, | ---------------- `MyEnum::Struct` defined here ... LL | MyEnum::Struct => "", - | ^^^^^^^^^^^^^^ did you mean `MyEnum::Struct { /* fields */ }`? + | ^^^^^^^^^^^^^^ help: use struct pattern syntax instead: `MyEnum::Struct { s }` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-64792-bad-unicode-ctor.stderr b/src/test/ui/issues/issue-64792-bad-unicode-ctor.stderr index 44e5d38abbc54..12053d8a1291c 100644 --- a/src/test/ui/issues/issue-64792-bad-unicode-ctor.stderr +++ b/src/test/ui/issues/issue-64792-bad-unicode-ctor.stderr @@ -5,11 +5,16 @@ LL | struct X {} | ----------- `X` defined here LL | LL | const Y: X = X("ö"); - | -------------^------ - | | | - | | did you mean `X { /* fields */ }`? - | | help: a constant with a similar name exists: `Y` - | similarly named constant `Y` defined here + | ^^^^^^ + | +help: a constant with a similar name exists + | +LL | const Y: X = Y("ö"); + | ^ +help: use struct literal syntax instead + | +LL | const Y: X = X {}; + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-65673.stderr b/src/test/ui/issues/issue-65673.stderr index 114f2d62e561a..fef64ebf2d365 100644 --- a/src/test/ui/issues/issue-65673.stderr +++ b/src/test/ui/issues/issue-65673.stderr @@ -10,7 +10,6 @@ LL | type Ctx = dyn Alias; | ^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)` - = note: to learn more, visit error: aborting due to previous error diff --git a/src/test/ui/issues/issue-73112.rs b/src/test/ui/issues/issue-73112.rs new file mode 100644 index 0000000000000..cc7be9c95aef6 --- /dev/null +++ b/src/test/ui/issues/issue-73112.rs @@ -0,0 +1,13 @@ +// aux-build:issue-73112.rs + +extern crate issue_73112; + +fn main() { + use issue_73112::PageTable; + + #[repr(C, packed)] + struct SomeStruct { + //~^ ERROR packed type cannot transitively contain a `#[repr(align)]` type [E0588] + page_table: PageTable, + } +} diff --git a/src/test/ui/issues/issue-73112.stderr b/src/test/ui/issues/issue-73112.stderr new file mode 100644 index 0000000000000..5a548378c2687 --- /dev/null +++ b/src/test/ui/issues/issue-73112.stderr @@ -0,0 +1,20 @@ +error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type + --> $DIR/issue-73112.rs:9:5 + | +LL | / struct SomeStruct { +LL | | +LL | | page_table: PageTable, +LL | | } + | |_____^ + | +note: `PageTable` has a `#[repr(align)]` attribute + --> $DIR/auxiliary/issue-73112.rs:8:1 + | +LL | / pub struct PageTable { +LL | | entries: [PageTableEntry; 512], +LL | | } + | |_^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0588`. diff --git a/src/test/ui/issues/issue-73886.rs b/src/test/ui/issues/issue-73886.rs new file mode 100644 index 0000000000000..2f1ec8c6d6227 --- /dev/null +++ b/src/test/ui/issues/issue-73886.rs @@ -0,0 +1,6 @@ +fn main() { + let _ = &&[0] as &[_]; + //~^ ERROR non-primitive cast: `&&[i32; 1]` as `&[_]` + let _ = 7u32 as Option<_>; + //~^ ERROR non-primitive cast: `u32` as `std::option::Option<_>` +} diff --git a/src/test/ui/issues/issue-73886.stderr b/src/test/ui/issues/issue-73886.stderr new file mode 100644 index 0000000000000..e8ab7db6b82c2 --- /dev/null +++ b/src/test/ui/issues/issue-73886.stderr @@ -0,0 +1,15 @@ +error[E0605]: non-primitive cast: `&&[i32; 1]` as `&[_]` + --> $DIR/issue-73886.rs:2:13 + | +LL | let _ = &&[0] as &[_]; + | ^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object + +error[E0605]: non-primitive cast: `u32` as `std::option::Option<_>` + --> $DIR/issue-73886.rs:4:13 + | +LL | let _ = 7u32 as Option<_>; + | ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0605`. diff --git a/src/test/ui/issues/issue-74086.rs b/src/test/ui/issues/issue-74086.rs new file mode 100644 index 0000000000000..f68a665b2f38d --- /dev/null +++ b/src/test/ui/issues/issue-74086.rs @@ -0,0 +1,4 @@ +fn main() { + static BUG: fn(_) -> u8 = |_| 8; + //~^ ERROR the type placeholder `_` is not allowed within types on item signatures [E0121] +} diff --git a/src/test/ui/issues/issue-74086.stderr b/src/test/ui/issues/issue-74086.stderr new file mode 100644 index 0000000000000..4127f48a093f4 --- /dev/null +++ b/src/test/ui/issues/issue-74086.stderr @@ -0,0 +1,12 @@ +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/issue-74086.rs:2:20 + | +LL | static BUG: fn(_) -> u8 = |_| 8; + | ^ + | | + | not allowed in type signatures + | help: use type parameters instead: `T` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0121`. diff --git a/src/test/ui/kindck/kindck-impl-type-params.nll.stderr b/src/test/ui/kindck/kindck-impl-type-params.nll.stderr index a2f70a8c24082..eb400cf061547 100644 --- a/src/test/ui/kindck/kindck-impl-type-params.nll.stderr +++ b/src/test/ui/kindck/kindck-impl-type-params.nll.stderr @@ -4,7 +4,6 @@ error[E0277]: `T` cannot be sent between threads safely LL | let a = &t as &dyn Gettable; | ^^ `T` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `T` = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` help: consider restricting type parameter `T` @@ -31,7 +30,6 @@ error[E0277]: `T` cannot be sent between threads safely LL | let a: &dyn Gettable = &t; | ^^ `T` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `T` = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` help: consider restricting type parameter `T` diff --git a/src/test/ui/kindck/kindck-impl-type-params.stderr b/src/test/ui/kindck/kindck-impl-type-params.stderr index cc98f1d9f34b8..ab9dfc9b8a779 100644 --- a/src/test/ui/kindck/kindck-impl-type-params.stderr +++ b/src/test/ui/kindck/kindck-impl-type-params.stderr @@ -4,7 +4,6 @@ error[E0277]: `T` cannot be sent between threads safely LL | let a = &t as &dyn Gettable; | ^^ `T` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `T` = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` help: consider restricting type parameter `T` @@ -31,7 +30,6 @@ error[E0277]: `T` cannot be sent between threads safely LL | let a: &dyn Gettable = &t; | ^^ `T` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `T` = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` help: consider restricting type parameter `T` diff --git a/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr b/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr index 6e19251c72800..98bf9923823d7 100644 --- a/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr +++ b/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr @@ -9,8 +9,6 @@ LL | fn test() { LL | let _: [u8; sof::()]; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `T` - = note: to learn more, visit help: consider relaxing the implicit `Sized` restriction | LL | pub const fn sof() -> usize { diff --git a/src/test/ui/lazy_normalization_consts/issue-57739.stderr b/src/test/ui/lazy_normalization_consts/issue-57739.stderr index 1987f5890c041..ce0495dd8b0cb 100644 --- a/src/test/ui/lazy_normalization_consts/issue-57739.stderr +++ b/src/test/ui/lazy_normalization_consts/issue-57739.stderr @@ -8,10 +8,10 @@ LL | #![feature(lazy_normalization_consts)] = note: see issue #72219 for more information error: constant expression depends on a generic parameter - --> $DIR/issue-57739.rs:12:5 + --> $DIR/issue-57739.rs:12:12 | LL | array: [u8; T::SIZE], - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | = note: this may fail depending on what value the parameter takes diff --git a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr index d682478db0eef..e5083e3a088b6 100644 --- a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr +++ b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr @@ -1,10 +1,10 @@ error[E0310]: the parameter type `T` may not live long enough - --> $DIR/lifetime-doesnt-live-long-enough.rs:19:5 + --> $DIR/lifetime-doesnt-live-long-enough.rs:19:10 | LL | struct Foo { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | foo: &'static T - | ^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at + | ^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at error[E0309]: the parameter type `K` may not live long enough --> $DIR/lifetime-doesnt-live-long-enough.rs:24:19 diff --git a/src/test/ui/lint/lint-ctypes-73747.rs b/src/test/ui/lint/lint-ctypes-73747.rs new file mode 100644 index 0000000000000..293ffd5c28e10 --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73747.rs @@ -0,0 +1,14 @@ +// check-pass + +#[repr(transparent)] +struct NonNullRawComPtr { + inner: std::ptr::NonNull<::VTable>, +} + +trait ComInterface { + type VTable; +} + +extern "C" fn invoke(_: Option>) {} + +fn main() {} diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index 95936de218b8f..71abda520653e 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -209,7 +209,6 @@ LL | let _ = fat_v as *const dyn Foo; | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: required for the cast to the object type `dyn Foo` error[E0277]: the size for values of type `str` cannot be known at compilation time @@ -219,7 +218,6 @@ LL | let _ = a as *const dyn Foo; | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: required for the cast to the object type `dyn Foo` error[E0606]: casting `&{float}` as `f32` is invalid diff --git a/src/test/ui/missing/missing-fields-in-struct-pattern.rs b/src/test/ui/missing/missing-fields-in-struct-pattern.rs index 24b6b55db6692..40304a674a633 100644 --- a/src/test/ui/missing/missing-fields-in-struct-pattern.rs +++ b/src/test/ui/missing/missing-fields-in-struct-pattern.rs @@ -2,8 +2,7 @@ struct S(usize, usize, usize, usize); fn main() { if let S { a, b, c, d } = S(1, 2, 3, 4) { - //~^ ERROR struct `S` does not have fields named `a`, `b`, `c`, `d` [E0026] - //~| ERROR pattern does not mention fields `0`, `1`, `2`, `3` [E0027] + //~^ ERROR tuple variant `S` written as struct variant println!("hi"); } } diff --git a/src/test/ui/missing/missing-fields-in-struct-pattern.stderr b/src/test/ui/missing/missing-fields-in-struct-pattern.stderr index f7037468996f4..6583524aad18f 100644 --- a/src/test/ui/missing/missing-fields-in-struct-pattern.stderr +++ b/src/test/ui/missing/missing-fields-in-struct-pattern.stderr @@ -1,18 +1,9 @@ -error[E0026]: struct `S` does not have fields named `a`, `b`, `c`, `d` - --> $DIR/missing-fields-in-struct-pattern.rs:4:16 - | -LL | if let S { a, b, c, d } = S(1, 2, 3, 4) { - | ^ ^ ^ ^ struct `S` does not have these fields - -error[E0027]: pattern does not mention fields `0`, `1`, `2`, `3` +error[E0769]: tuple variant `S` written as struct variant --> $DIR/missing-fields-in-struct-pattern.rs:4:12 | LL | if let S { a, b, c, d } = S(1, 2, 3, 4) { - | ^^^^^^^^^^^^^^^^ missing fields `0`, `1`, `2`, `3` - | - = note: trying to match a tuple variant with a struct variant pattern + | ^^^^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `S(a, b, c, d)` -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0026, E0027. -For more information about an error, try `rustc --explain E0026`. +For more information about this error, try `rustc --explain E0769`. diff --git a/src/test/ui/namespace/namespace-mix.stderr b/src/test/ui/namespace/namespace-mix.stderr index ee730910ee441..636789c9cc300 100644 --- a/src/test/ui/namespace/namespace-mix.stderr +++ b/src/test/ui/namespace/namespace-mix.stderr @@ -51,12 +51,16 @@ LL | TV(), | ---- similarly named tuple variant `TV` defined here ... LL | check(m7::V); - | ^^^^^ did you mean `m7::V { /* fields */ }`? + | ^^^^^ | help: a tuple variant with a similar name exists | LL | check(m7::TV); | ^^ +help: use struct literal syntax instead + | +LL | check(m7::V {}); + | ^^^^^^^^ help: consider importing one of these items instead | LL | use m8::V; @@ -68,7 +72,7 @@ error[E0423]: expected value, found struct variant `xm7::V` --> $DIR/namespace-mix.rs:106:11 | LL | check(xm7::V); - | ^^^^^^ did you mean `xm7::V { /* fields */ }`? + | ^^^^^^ | ::: $DIR/auxiliary/namespace-mix.rs:7:9 | @@ -79,6 +83,10 @@ help: a tuple variant with a similar name exists | LL | check(xm7::TV); | ^^ +help: use struct literal syntax instead + | +LL | check(xm7::V { /* fields */ }); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider importing one of these items instead | LL | use m8::V; diff --git a/src/test/ui/parser/recover-from-bad-variant.stderr b/src/test/ui/parser/recover-from-bad-variant.stderr index 0272326c7bc4f..6986d966d69ec 100644 --- a/src/test/ui/parser/recover-from-bad-variant.stderr +++ b/src/test/ui/parser/recover-from-bad-variant.stderr @@ -16,7 +16,7 @@ LL | Foo { a: usize, b: usize }, | -------------------------- `Enum::Foo` defined here ... LL | Enum::Foo(a, b) => {} - | ^^^^^^^^^ did you mean `Enum::Foo { /* fields */ }`? + | ^^^^^^^^^^^^^^^ help: use struct pattern syntax instead: `Enum::Foo { a, b }` error: aborting due to 2 previous errors diff --git a/src/test/ui/phantom-oibit.stderr b/src/test/ui/phantom-oibit.stderr index fd0307f15c79a..e143747d637ee 100644 --- a/src/test/ui/phantom-oibit.stderr +++ b/src/test/ui/phantom-oibit.stderr @@ -7,7 +7,6 @@ LL | fn is_zen(_: T) {} LL | is_zen(x) | ^ `T` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `T` = note: required because of the requirements on the impl of `Zen` for `&T` = note: required because it appears within the type `std::marker::PhantomData<&T>` = note: required because it appears within the type `Guard<'_, T>` @@ -25,7 +24,6 @@ LL | fn is_zen(_: T) {} LL | is_zen(x) | ^ `T` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `T` = note: required because of the requirements on the impl of `Zen` for `&T` = note: required because it appears within the type `std::marker::PhantomData<&T>` = note: required because it appears within the type `Guard<'_, T>` diff --git a/src/test/ui/range/range-1.stderr b/src/test/ui/range/range-1.stderr index 05009358106fa..e179feba7a799 100644 --- a/src/test/ui/range/range-1.stderr +++ b/src/test/ui/range/range-1.stderr @@ -19,7 +19,6 @@ LL | let range = *arr..; | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[{integer}]` - = note: to learn more, visit = note: required by `std::ops::RangeFrom` error: aborting due to 3 previous errors diff --git a/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr b/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr index ea9be77a3e8b5..22586b5de91ff 100644 --- a/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr +++ b/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr @@ -5,10 +5,10 @@ LL | z: Box+'b+'c>, | ^^ error[E0478]: lifetime bound not satisfied - --> $DIR/region-bounds-on-objects-and-type-parameters.rs:21:5 + --> $DIR/region-bounds-on-objects-and-type-parameters.rs:21:8 | LL | z: Box+'b+'c>, - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime `'b` as defined on the struct at 11:15 --> $DIR/region-bounds-on-objects-and-type-parameters.rs:11:15 diff --git a/src/test/ui/regions/regions-wf-trait-object.stderr b/src/test/ui/regions/regions-wf-trait-object.stderr index 9f39508604110..1ddbf73a46372 100644 --- a/src/test/ui/regions/regions-wf-trait-object.stderr +++ b/src/test/ui/regions/regions-wf-trait-object.stderr @@ -1,8 +1,8 @@ error[E0478]: lifetime bound not satisfied - --> $DIR/regions-wf-trait-object.rs:7:5 + --> $DIR/regions-wf-trait-object.rs:7:8 | LL | x: Box+'b> - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime `'b` as defined on the struct at 6:15 --> $DIR/regions-wf-trait-object.rs:6:15 diff --git a/src/test/ui/resolve/issue-18252.stderr b/src/test/ui/resolve/issue-18252.stderr index 39b444498102c..13e7a59732db1 100644 --- a/src/test/ui/resolve/issue-18252.stderr +++ b/src/test/ui/resolve/issue-18252.stderr @@ -5,7 +5,7 @@ LL | Variant { x: usize } | -------------------- `Foo::Variant` defined here ... LL | let f = Foo::Variant(42); - | ^^^^^^^^^^^^ did you mean `Foo::Variant { /* fields */ }`? + | ^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `Foo::Variant { x: val }` error: aborting due to previous error diff --git a/src/test/ui/resolve/issue-19452.stderr b/src/test/ui/resolve/issue-19452.stderr index 4d20f1580264c..d1690d4eef7ef 100644 --- a/src/test/ui/resolve/issue-19452.stderr +++ b/src/test/ui/resolve/issue-19452.stderr @@ -5,13 +5,13 @@ LL | Madoka { age: u32 } | ------------------- `Homura::Madoka` defined here ... LL | let homura = Homura::Madoka; - | ^^^^^^^^^^^^^^ did you mean `Homura::Madoka { /* fields */ }`? + | ^^^^^^^^^^^^^^ help: use struct literal syntax instead: `Homura::Madoka { age: val }` error[E0423]: expected value, found struct variant `issue_19452_aux::Homura::Madoka` --> $DIR/issue-19452.rs:13:18 | LL | let homura = issue_19452_aux::Homura::Madoka; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ did you mean `issue_19452_aux::Homura::Madoka { /* fields */ }`? + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `issue_19452_aux::Homura::Madoka { /* fields */ }` error: aborting due to 2 previous errors diff --git a/src/test/ui/resolve/issue-39226.stderr b/src/test/ui/resolve/issue-39226.stderr index d9a28e63dce8b..c9b9aeb45ba42 100644 --- a/src/test/ui/resolve/issue-39226.stderr +++ b/src/test/ui/resolve/issue-39226.stderr @@ -6,9 +6,15 @@ LL | struct Handle {} ... LL | handle: Handle | ^^^^^^ - | | - | did you mean `Handle { /* fields */ }`? - | help: a local variable with a similar name exists: `handle` + | +help: a local variable with a similar name exists + | +LL | handle: handle + | ^^^^^^ +help: use struct literal syntax instead + | +LL | handle: Handle {} + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/resolve/issue-5035-2.stderr b/src/test/ui/resolve/issue-5035-2.stderr index 89eb3d97ce0a5..4ed93ad3279ad 100644 --- a/src/test/ui/resolve/issue-5035-2.stderr +++ b/src/test/ui/resolve/issue-5035-2.stderr @@ -5,9 +5,11 @@ LL | fn foo(_x: K) {} | ^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn I + 'static)` - = note: to learn more, visit - = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo(_x: &K) {} + | ^ error: aborting due to previous error diff --git a/src/test/ui/resolve/issue-6702.stderr b/src/test/ui/resolve/issue-6702.stderr index 252d50c70f8c4..a118f94191df3 100644 --- a/src/test/ui/resolve/issue-6702.stderr +++ b/src/test/ui/resolve/issue-6702.stderr @@ -7,7 +7,7 @@ LL | | } | |_- `Monster` defined here ... LL | let _m = Monster(); - | ^^^^^^^ did you mean `Monster { /* fields */ }`? + | ^^^^^^^^^ help: use struct literal syntax instead: `Monster { damage: val }` error: aborting due to previous error diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr index 16baa6c9b6233..3904a00dde1dd 100644 --- a/src/test/ui/resolve/privacy-enum-ctor.stderr +++ b/src/test/ui/resolve/privacy-enum-ctor.stderr @@ -44,7 +44,7 @@ LL | | }, | |_____________- `Z::Struct` defined here ... LL | let _: Z = Z::Struct; - | ^^^^^^^^^ did you mean `Z::Struct { /* fields */ }`? + | ^^^^^^^^^ help: use struct literal syntax instead: `Z::Struct { s: val }` error[E0423]: expected value, found enum `m::E` --> $DIR/privacy-enum-ctor.rs:41:16 @@ -83,7 +83,7 @@ LL | | }, | |_________- `m::E::Struct` defined here ... LL | let _: E = m::E::Struct; - | ^^^^^^^^^^^^ did you mean `m::E::Struct { /* fields */ }`? + | ^^^^^^^^^^^^ help: use struct literal syntax instead: `m::E::Struct { s: val }` error[E0423]: expected value, found enum `E` --> $DIR/privacy-enum-ctor.rs:49:16 @@ -115,7 +115,7 @@ LL | | }, | |_________- `E::Struct` defined here ... LL | let _: E = E::Struct; - | ^^^^^^^^^ did you mean `E::Struct { /* fields */ }`? + | ^^^^^^^^^ help: use struct literal syntax instead: `E::Struct { s: val }` error[E0412]: cannot find type `Z` in this scope --> $DIR/privacy-enum-ctor.rs:57:12 @@ -195,7 +195,7 @@ LL | | }, | |_____________- `m::n::Z::Struct` defined here ... LL | let _: Z = m::n::Z::Struct; - | ^^^^^^^^^^^^^^^ did you mean `m::n::Z::Struct { /* fields */ }`? + | ^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `m::n::Z::Struct { s: val }` error[E0412]: cannot find type `Z` in this scope --> $DIR/privacy-enum-ctor.rs:68:12 diff --git a/src/test/ui/resolve/privacy-struct-ctor.stderr b/src/test/ui/resolve/privacy-struct-ctor.stderr index e0305b129a881..a72f69cf1cd8d 100644 --- a/src/test/ui/resolve/privacy-struct-ctor.stderr +++ b/src/test/ui/resolve/privacy-struct-ctor.stderr @@ -25,7 +25,7 @@ LL | | } | |_____- `S2` defined here ... LL | S2; - | ^^ did you mean `S2 { /* fields */ }`? + | ^^ help: use struct literal syntax instead: `S2 { s: val }` error[E0423]: expected value, found struct `xcrate::S` --> $DIR/privacy-struct-ctor.rs:43:5 diff --git a/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr b/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr index 2bb51731583a6..a449fac11930d 100644 --- a/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr @@ -1,10 +1,10 @@ error[E0310]: the parameter type `U` may not live long enough - --> $DIR/dont-infer-static.rs:8:5 + --> $DIR/dont-infer-static.rs:8:10 | LL | struct Foo { | - help: consider adding an explicit lifetime bound...: `U: 'static` LL | bar: Bar - | ^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds + | ^^^^^^ ...so that the type `U` will meet its required lifetime bounds error: aborting due to previous error diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr index 7f3c49e753fd7..3da8725d88a0c 100644 --- a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr +++ b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr @@ -24,7 +24,6 @@ LL | type U<'a>: PartialEq<&'a Self>; LL | default type U<'a> = &'a T; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T == T` | - = help: the trait `std::cmp::PartialEq` is not implemented for `T` = note: required because of the requirements on the impl of `std::cmp::PartialEq` for `&'a T` help: consider further restricting this bound | diff --git a/src/test/ui/str/str-array-assignment.stderr b/src/test/ui/str/str-array-assignment.stderr index cc767de3845d2..52d3aefe125c0 100644 --- a/src/test/ui/str/str-array-assignment.stderr +++ b/src/test/ui/str/str-array-assignment.stderr @@ -19,14 +19,15 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t --> $DIR/str-array-assignment.rs:7:7 | LL | let v = s[..2]; - | ^ ------ help: consider borrowing here: `&s[..2]` - | | - | doesn't have a size known at compile-time + | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature +help: consider borrowing here + | +LL | let v = &s[..2]; + | ^ error[E0308]: mismatched types --> $DIR/str-array-assignment.rs:9:17 diff --git a/src/test/ui/str/str-mut-idx.stderr b/src/test/ui/str/str-mut-idx.stderr index 2fd805e646991..7c834165e7f1c 100644 --- a/src/test/ui/str/str-mut-idx.stderr +++ b/src/test/ui/str/str-mut-idx.stderr @@ -8,7 +8,6 @@ LL | s[1..2] = bot(); | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit help: consider relaxing the implicit `Sized` restriction | LL | fn bot() -> T { loop {} } @@ -21,7 +20,6 @@ LL | s[1..2] = bot(); | ^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: the left-hand-side of an assignment must have a statically known size error[E0277]: the type `str` cannot be indexed by `usize` diff --git a/src/test/ui/substs-ppaux.normal.stderr b/src/test/ui/substs-ppaux.normal.stderr index bcdeed262ecba..8dab8add80b8a 100644 --- a/src/test/ui/substs-ppaux.normal.stderr +++ b/src/test/ui/substs-ppaux.normal.stderr @@ -80,7 +80,6 @@ LL | >::bar; | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: required because of the requirements on the impl of `Foo<'_, '_, u8>` for `str` error: aborting due to 5 previous errors diff --git a/src/test/ui/substs-ppaux.verbose.stderr b/src/test/ui/substs-ppaux.verbose.stderr index fb5e6fbcfe712..a40d5e4bf7ba1 100644 --- a/src/test/ui/substs-ppaux.verbose.stderr +++ b/src/test/ui/substs-ppaux.verbose.stderr @@ -80,7 +80,6 @@ LL | >::bar; | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: required because of the requirements on the impl of `Foo<'_#0r, '_#1r, u8>` for `str` error: aborting due to 5 previous errors diff --git a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr index ee08f51f80270..f4c0d0f96c428 100644 --- a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr +++ b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/adt-param-with-implicit-sized-bound.rs:25:5 + --> $DIR/adt-param-with-implicit-sized-bound.rs:25:9 | LL | struct X(T); | - required by this bound in `X` @@ -7,10 +7,8 @@ LL | struct X(T); LL | struct Struct5{ | - this type parameter needs to be `std::marker::Sized` LL | _t: X, - | ^^^^^^^^ doesn't have a size known at compile-time + | ^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `T` - = note: to learn more, visit help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/adt-param-with-implicit-sized-bound.rs:18:10 | @@ -28,8 +26,6 @@ LL | fn func1() -> Struct1; LL | struct Struct1{ | - required by this bound in `Struct1` | - = help: the trait `std::marker::Sized` is not implemented for `Self` - = note: to learn more, visit help: consider further restricting `Self` | LL | fn func1() -> Struct1 where Self: std::marker::Sized; @@ -48,8 +44,6 @@ LL | fn func2<'a>() -> Struct2<'a, Self>; LL | struct Struct2<'a, T>{ | - required by this bound in `Struct2` | - = help: the trait `std::marker::Sized` is not implemented for `Self` - = note: to learn more, visit help: consider further restricting `Self` | LL | fn func2<'a>() -> Struct2<'a, Self> where Self: std::marker::Sized; @@ -68,8 +62,6 @@ LL | fn func3() -> Struct3; LL | struct Struct3{ | - required by this bound in `Struct3` | - = help: the trait `std::marker::Sized` is not implemented for `Self` - = note: to learn more, visit help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/adt-param-with-implicit-sized-bound.rs:14:16 | @@ -91,8 +83,6 @@ LL | fn func4() -> Struct4; LL | struct Struct4{ | - required by this bound in `Struct4` | - = help: the trait `std::marker::Sized` is not implemented for `Self` - = note: to learn more, visit help: consider further restricting `Self` | LL | fn func4() -> Struct4 where Self: std::marker::Sized; diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr index b03bea1eddbf0..45309486db46f 100644 --- a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr +++ b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr @@ -7,10 +7,16 @@ LL | B { a: usize }, | -------------- `E::B` defined here ... LL | let _: E = E::B; - | ^^^- - | | | - | | help: a tuple variant with a similar name exists: `A` - | did you mean `E::B { /* fields */ }`? + | ^^^^ + | +help: a tuple variant with a similar name exists + | +LL | let _: E = E::A; + | ^ +help: use struct literal syntax instead + | +LL | let _: E = E::B { a: val }; + | ^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/fn-or-tuple-struct-without-args.rs:29:20 diff --git a/src/test/ui/suggestions/issue-61226.stderr b/src/test/ui/suggestions/issue-61226.stderr index fbcfba6653f27..7f6f082d7a8d7 100644 --- a/src/test/ui/suggestions/issue-61226.stderr +++ b/src/test/ui/suggestions/issue-61226.stderr @@ -5,7 +5,7 @@ LL | struct X {} | ----------- `X` defined here LL | fn main() { LL | vec![X]; //… - | ^ did you mean `X { /* fields */ }`? + | ^ help: use struct literal syntax instead: `X {}` error: aborting due to previous error diff --git a/src/test/ui/suggestions/path-by-value.stderr b/src/test/ui/suggestions/path-by-value.stderr index b073e10749cc1..2b7c29e20cd31 100644 --- a/src/test/ui/suggestions/path-by-value.stderr +++ b/src/test/ui/suggestions/path-by-value.stderr @@ -2,13 +2,15 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> $DIR/path-by-value.rs:3:6 | LL | fn f(p: Path) { } - | ^ borrow the `Path` instead + | ^ doesn't have a size known at compile-time | = help: within `std::path::Path`, the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: required because it appears within the type `std::path::Path` - = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn f(p: &Path) { } + | ^ error: aborting due to previous error diff --git a/src/test/ui/suggestions/restrict-type-argument.stderr b/src/test/ui/suggestions/restrict-type-argument.stderr index 0c52778b0d886..33af13d943f74 100644 --- a/src/test/ui/suggestions/restrict-type-argument.stderr +++ b/src/test/ui/suggestions/restrict-type-argument.stderr @@ -7,7 +7,6 @@ LL | fn is_send(val: T) {} LL | is_send(val); | ^^^ `impl Sync` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `impl Sync` help: consider further restricting this bound | LL | fn use_impl_sync(val: impl Sync + std::marker::Send) { @@ -22,7 +21,6 @@ LL | fn is_send(val: T) {} LL | is_send(val); | ^^^ `S` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `S` help: consider further restricting this bound | LL | fn use_where(val: S) where S: Sync + std::marker::Send { @@ -37,7 +35,6 @@ LL | fn is_send(val: T) {} LL | is_send(val); | ^^^ `S` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `S` help: consider further restricting this bound | LL | fn use_bound(val: S) { @@ -52,7 +49,6 @@ LL | fn is_send(val: T) {} LL | is_send(val); | ^^^ `S` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `S` help: consider further restricting this bound | LL | Sync + std::marker::Send @@ -67,7 +63,6 @@ LL | fn is_send(val: T) {} LL | is_send(val); | ^^^ `S` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `S` help: consider further restricting this bound | LL | fn use_bound_and_where(val: S) where S: std::fmt::Debug + std::marker::Send { @@ -82,7 +77,6 @@ LL | fn is_send(val: T) {} LL | is_send(val); | ^^^ `S` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `S` help: consider restricting type parameter `S` | LL | fn use_unbound(val: S) { diff --git a/src/test/ui/traits/cycle-cache-err-60010.stderr b/src/test/ui/traits/cycle-cache-err-60010.stderr index 3188ee83e7d39..324316ceaf6ba 100644 --- a/src/test/ui/traits/cycle-cache-err-60010.stderr +++ b/src/test/ui/traits/cycle-cache-err-60010.stderr @@ -1,8 +1,8 @@ error[E0275]: overflow evaluating the requirement `RootDatabase: SourceDatabase` - --> $DIR/cycle-cache-err-60010.rs:27:5 + --> $DIR/cycle-cache-err-60010.rs:27:13 | LL | _parse: >::Data, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: required because of the requirements on the impl of `Query` for `ParseQuery` diff --git a/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr b/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr index 5e685105b45a3..daca91abff843 100644 --- a/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr +++ b/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr @@ -13,9 +13,11 @@ LL | fn foo(_x: Foo + Send) { | ^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn Foo + std::marker::Send + 'static)` - = note: to learn more, visit - = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo(_x: &Foo + Send) { + | ^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr b/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr index 271ed07ce42ab..d7549835a0905 100644 --- a/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr +++ b/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr @@ -13,13 +13,13 @@ LL | impl Foo { | ^^^^^^^ error[E0277]: the trait bound `isize: Trait` is not satisfied - --> $DIR/trait-bounds-on-structs-and-enums.rs:19:5 + --> $DIR/trait-bounds-on-structs-and-enums.rs:19:8 | LL | struct Foo { | ----- required by this bound in `Foo` ... LL | a: Foo, - | ^^^^^^^^^^^^^ the trait `Trait` is not implemented for `isize` + | ^^^^^^^^^^ the trait `Trait` is not implemented for `isize` error[E0277]: the trait bound `usize: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums.rs:23:10 @@ -31,13 +31,13 @@ LL | Quux(Bar), | ^^^^^^^^^^ the trait `Trait` is not implemented for `usize` error[E0277]: the trait bound `U: Trait` is not satisfied - --> $DIR/trait-bounds-on-structs-and-enums.rs:27:5 + --> $DIR/trait-bounds-on-structs-and-enums.rs:27:8 | LL | struct Foo { | ----- required by this bound in `Foo` ... LL | b: Foo, - | ^^^^^^^^^ the trait `Trait` is not implemented for `U` + | ^^^^^^ the trait `Trait` is not implemented for `U` | help: consider restricting type parameter `U` | @@ -68,13 +68,13 @@ LL | Foo, | ^^^^^^^^ the trait `Trait` is not implemented for `i32` error[E0277]: the trait bound `u8: Trait` is not satisfied - --> $DIR/trait-bounds-on-structs-and-enums.rs:39:22 + --> $DIR/trait-bounds-on-structs-and-enums.rs:39:29 | LL | enum Bar { | ----- required by this bound in `Bar` ... LL | DictionaryLike { field: Bar }, - | ^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `u8` + | ^^^^^^^ the trait `Trait` is not implemented for `u8` error: aborting due to 7 previous errors diff --git a/src/test/ui/traits/trait-suggest-where-clause.stderr b/src/test/ui/traits/trait-suggest-where-clause.stderr index 4dddcd68f26c9..86a313baa5c38 100644 --- a/src/test/ui/traits/trait-suggest-where-clause.stderr +++ b/src/test/ui/traits/trait-suggest-where-clause.stderr @@ -11,9 +11,6 @@ LL | mem::size_of::(); | LL | pub const fn size_of() -> usize { | - required by this bound in `std::mem::size_of` - | - = help: the trait `std::marker::Sized` is not implemented for `U` - = note: to learn more, visit error[E0277]: the size for values of type `U` cannot be known at compilation time --> $DIR/trait-suggest-where-clause.rs:10:5 @@ -29,8 +26,6 @@ LL | mem::size_of::>(); LL | pub const fn size_of() -> usize { | - required by this bound in `std::mem::size_of` | - = help: within `Misc`, the trait `std::marker::Sized` is not implemented for `U` - = note: to learn more, visit = note: required because it appears within the type `Misc` error[E0277]: the trait bound `u64: std::convert::From` is not satisfied @@ -69,7 +64,6 @@ LL | pub const fn size_of() -> usize { | - required by this bound in `std::mem::size_of` | = help: the trait `std::marker::Sized` is not implemented for `[T]` - = note: to learn more, visit error[E0277]: the size for values of type `[&U]` cannot be known at compilation time --> $DIR/trait-suggest-where-clause.rs:31:5 @@ -83,7 +77,6 @@ LL | pub const fn size_of() -> usize { | - required by this bound in `std::mem::size_of` | = help: the trait `std::marker::Sized` is not implemented for `[&U]` - = note: to learn more, visit error: aborting due to 7 previous errors diff --git a/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr b/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr index 006fa933d34ca..4f4695612de0b 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr @@ -5,7 +5,6 @@ LL | fn cant_return_str() -> str { | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: the return type of a function must have a statically known size error[E0599]: no method named `test` found for type `i32` in the current scope diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr index 247d68ef2a1f0..28e30cbdd9d96 100644 --- a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr @@ -19,7 +19,6 @@ LL | type Underconstrained = impl 'static; LL | 5u32 | ---- this returned value is of type `u32` | - = help: the trait `std::fmt::Debug` is not implemented for `U` = note: the return type of a function must have a statically known size help: consider restricting type parameter `U` | @@ -35,7 +34,6 @@ LL | type Underconstrained2 = impl 'static; LL | 5u32 | ---- this returned value is of type `u32` | - = help: the trait `std::fmt::Debug` is not implemented for `V` = note: the return type of a function must have a statically known size help: consider restricting type parameter `V` | diff --git a/src/test/ui/type/type-check/issue-41314.rs b/src/test/ui/type/type-check/issue-41314.rs index 856d4ff6334bc..cbd39f5f9e6ed 100644 --- a/src/test/ui/type/type-check/issue-41314.rs +++ b/src/test/ui/type/type-check/issue-41314.rs @@ -4,7 +4,7 @@ enum X { fn main() { match X::Y(0) { - X::Y { number } => {} //~ ERROR does not have a field named `number` - //~^ ERROR pattern does not mention field `0` + X::Y { number } => {} + //~^ ERROR tuple variant `X::Y` written as struct variant } } diff --git a/src/test/ui/type/type-check/issue-41314.stderr b/src/test/ui/type/type-check/issue-41314.stderr index c2bba98d10a83..bd4d2071c2059 100644 --- a/src/test/ui/type/type-check/issue-41314.stderr +++ b/src/test/ui/type/type-check/issue-41314.stderr @@ -1,18 +1,9 @@ -error[E0026]: variant `X::Y` does not have a field named `number` - --> $DIR/issue-41314.rs:7:16 - | -LL | X::Y { number } => {} - | ^^^^^^ variant `X::Y` does not have this field - -error[E0027]: pattern does not mention field `0` +error[E0769]: tuple variant `X::Y` written as struct variant --> $DIR/issue-41314.rs:7:9 | LL | X::Y { number } => {} - | ^^^^^^^^^^^^^^^ missing field `0` - | - = note: trying to match a tuple variant with a struct variant pattern + | ^^^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `X::Y(number)` -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0026, E0027. -For more information about an error, try `rustc --explain E0026`. +For more information about this error, try `rustc --explain E0769`. diff --git a/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr b/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr index 9cba3578449c3..7398b48a238d1 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr @@ -7,7 +7,6 @@ LL | is_send::() LL | fn is_send() { | ---- required by this bound in `is_send` | - = help: the trait `std::marker::Send` is not implemented for `T` help: consider restricting type parameter `T` | LL | fn foo() { diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.rs b/src/test/ui/typeck/typeck_type_placeholder_item.rs index 99a7023089283..133c5231031fd 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.rs +++ b/src/test/ui/typeck/typeck_type_placeholder_item.rs @@ -32,6 +32,7 @@ fn test7(x: _) { let _x: usize = x; } fn test8(_f: fn() -> _) { } //~^ ERROR the type placeholder `_` is not allowed within types on item signatures +//~^^ ERROR the type placeholder `_` is not allowed within types on item signatures struct Test9; @@ -98,6 +99,7 @@ pub fn main() { fn fn_test8(_f: fn() -> _) { } //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + //~^^ ERROR the type placeholder `_` is not allowed within types on item signatures struct FnTest9; diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.stderr b/src/test/ui/typeck/typeck_type_placeholder_item.stderr index 6c0653d5fcb7c..a1945f2b9cf4e 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_item.stderr @@ -1,35 +1,35 @@ error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:152:18 + --> $DIR/typeck_type_placeholder_item.rs:154:18 | LL | struct BadStruct<_>(_); | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:155:16 + --> $DIR/typeck_type_placeholder_item.rs:157:16 | LL | trait BadTrait<_> {} | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:165:19 + --> $DIR/typeck_type_placeholder_item.rs:167:19 | LL | struct BadStruct1<_, _>(_); | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:165:22 + --> $DIR/typeck_type_placeholder_item.rs:167:22 | LL | struct BadStruct1<_, _>(_); | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:170:19 + --> $DIR/typeck_type_placeholder_item.rs:172:19 | LL | struct BadStruct2<_, T>(_, T); | ^ expected identifier, found reserved identifier error: associated constant in `impl` without body - --> $DIR/typeck_type_placeholder_item.rs:201:5 + --> $DIR/typeck_type_placeholder_item.rs:203:5 | LL | const C: _; | ^^^^^^^^^^- @@ -37,7 +37,7 @@ LL | const C: _; | help: provide a definition for the constant: `= ;` error[E0403]: the name `_` is already used for a generic parameter in this item's generic parameters - --> $DIR/typeck_type_placeholder_item.rs:165:22 + --> $DIR/typeck_type_placeholder_item.rs:167:22 | LL | struct BadStruct1<_, _>(_); | - ^ already used @@ -131,6 +131,15 @@ help: use type parameters instead LL | fn test7(x: T) { let _x: usize = x; } | ^^^ ^ +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:33:22 + | +LL | fn test8(_f: fn() -> _) { } + | ^ + | | + | not allowed in type signatures + | help: use type parameters instead: `T` + error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:33:22 | @@ -143,7 +152,7 @@ LL | fn test8(_f: fn() -> T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:46:26 + --> $DIR/typeck_type_placeholder_item.rs:47:26 | LL | fn test11(x: &usize) -> &_ { | -^ @@ -152,7 +161,7 @@ LL | fn test11(x: &usize) -> &_ { | help: replace with the correct return type: `&&usize` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:51:52 + --> $DIR/typeck_type_placeholder_item.rs:52:52 | LL | unsafe fn test12(x: *const usize) -> *const *const _ { | --------------^ @@ -161,7 +170,7 @@ LL | unsafe fn test12(x: *const usize) -> *const *const _ { | help: replace with the correct return type: `*const *const usize` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:65:8 + --> $DIR/typeck_type_placeholder_item.rs:66:8 | LL | a: _, | ^ not allowed in type signatures @@ -180,13 +189,13 @@ LL | b: (T, T), | error: missing type for `static` item - --> $DIR/typeck_type_placeholder_item.rs:71:12 + --> $DIR/typeck_type_placeholder_item.rs:72:12 | LL | static A = 42; | ^ help: provide a type for the item: `A: i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:73:15 + --> $DIR/typeck_type_placeholder_item.rs:74:15 | LL | static B: _ = 42; | ^ @@ -195,13 +204,13 @@ LL | static B: _ = 42; | help: replace `_` with the correct type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:75:15 + --> $DIR/typeck_type_placeholder_item.rs:76:15 | LL | static C: Option<_> = Some(42); | ^^^^^^^^^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:78:21 + --> $DIR/typeck_type_placeholder_item.rs:79:21 | LL | fn fn_test() -> _ { 5 } | ^ @@ -210,7 +219,7 @@ LL | fn fn_test() -> _ { 5 } | help: replace with the correct return type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:81:23 + --> $DIR/typeck_type_placeholder_item.rs:82:23 | LL | fn fn_test2() -> (_, _) { (5, 5) } | -^--^- @@ -220,7 +229,7 @@ LL | fn fn_test2() -> (_, _) { (5, 5) } | help: replace with the correct return type: `(i32, i32)` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:84:22 + --> $DIR/typeck_type_placeholder_item.rs:85:22 | LL | static FN_TEST3: _ = "test"; | ^ @@ -229,7 +238,7 @@ LL | static FN_TEST3: _ = "test"; | help: replace `_` with the correct type: `&str` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:87:22 + --> $DIR/typeck_type_placeholder_item.rs:88:22 | LL | static FN_TEST4: _ = 145; | ^ @@ -238,13 +247,13 @@ LL | static FN_TEST4: _ = 145; | help: replace `_` with the correct type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:90:22 + --> $DIR/typeck_type_placeholder_item.rs:91:22 | LL | static FN_TEST5: (_, _) = (1, 2); | ^^^^^^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:93:20 + --> $DIR/typeck_type_placeholder_item.rs:94:20 | LL | fn fn_test6(_: _) { } | ^ not allowed in type signatures @@ -255,7 +264,7 @@ LL | fn fn_test6(_: T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:96:20 + --> $DIR/typeck_type_placeholder_item.rs:97:20 | LL | fn fn_test7(x: _) { let _x: usize = x; } | ^ not allowed in type signatures @@ -266,7 +275,16 @@ LL | fn fn_test7(x: T) { let _x: usize = x; } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:99:29 + --> $DIR/typeck_type_placeholder_item.rs:100:29 + | +LL | fn fn_test8(_f: fn() -> _) { } + | ^ + | | + | not allowed in type signatures + | help: use type parameters instead: `T` + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:100:29 | LL | fn fn_test8(_f: fn() -> _) { } | ^ not allowed in type signatures @@ -277,7 +295,7 @@ LL | fn fn_test8(_f: fn() -> T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:121:12 + --> $DIR/typeck_type_placeholder_item.rs:123:12 | LL | a: _, | ^ not allowed in type signatures @@ -296,13 +314,13 @@ LL | b: (T, T), | error[E0282]: type annotations needed - --> $DIR/typeck_type_placeholder_item.rs:126:18 + --> $DIR/typeck_type_placeholder_item.rs:128:18 | LL | fn fn_test11(_: _) -> (_, _) { panic!() } | ^ cannot infer type error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:126:28 + --> $DIR/typeck_type_placeholder_item.rs:128:28 | LL | fn fn_test11(_: _) -> (_, _) { panic!() } | ^ ^ not allowed in type signatures @@ -310,7 +328,7 @@ LL | fn fn_test11(_: _) -> (_, _) { panic!() } | not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:130:30 + --> $DIR/typeck_type_placeholder_item.rs:132:30 | LL | fn fn_test12(x: i32) -> (_, _) { (x, x) } | -^--^- @@ -320,7 +338,7 @@ LL | fn fn_test12(x: i32) -> (_, _) { (x, x) } | help: replace with the correct return type: `(i32, i32)` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:133:33 + --> $DIR/typeck_type_placeholder_item.rs:135:33 | LL | fn fn_test13(x: _) -> (i32, _) { (x, x) } | ------^- @@ -329,7 +347,7 @@ LL | fn fn_test13(x: _) -> (i32, _) { (x, x) } | help: replace with the correct return type: `(i32, i32)` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:152:21 + --> $DIR/typeck_type_placeholder_item.rs:154:21 | LL | struct BadStruct<_>(_); | ^ not allowed in type signatures @@ -340,7 +358,7 @@ LL | struct BadStruct(T); | ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:157:15 + --> $DIR/typeck_type_placeholder_item.rs:159:15 | LL | impl BadTrait<_> for BadStruct<_> {} | ^ ^ not allowed in type signatures @@ -353,13 +371,13 @@ LL | impl BadTrait for BadStruct {} | ^^^ ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:160:34 + --> $DIR/typeck_type_placeholder_item.rs:162:34 | LL | fn impl_trait() -> impl BadTrait<_> { | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:165:25 + --> $DIR/typeck_type_placeholder_item.rs:167:25 | LL | struct BadStruct1<_, _>(_); | ^ not allowed in type signatures @@ -370,7 +388,7 @@ LL | struct BadStruct1(T); | ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:170:25 + --> $DIR/typeck_type_placeholder_item.rs:172:25 | LL | struct BadStruct2<_, T>(_, T); | ^ not allowed in type signatures @@ -381,13 +399,13 @@ LL | struct BadStruct2(U, T); | ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:174:14 + --> $DIR/typeck_type_placeholder_item.rs:176:14 | LL | type X = Box<_>; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:42:27 + --> $DIR/typeck_type_placeholder_item.rs:43:27 | LL | fn test10(&self, _x : _) { } | ^ not allowed in type signatures @@ -398,7 +416,7 @@ LL | fn test10(&self, _x : T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:138:31 + --> $DIR/typeck_type_placeholder_item.rs:140:31 | LL | fn method_test1(&self, x: _); | ^ not allowed in type signatures @@ -409,7 +427,7 @@ LL | fn method_test1(&self, x: T); | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:140:31 + --> $DIR/typeck_type_placeholder_item.rs:142:31 | LL | fn method_test2(&self, x: _) -> _; | ^ ^ not allowed in type signatures @@ -422,7 +440,7 @@ LL | fn method_test2(&self, x: T) -> T; | ^^^ ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:142:31 + --> $DIR/typeck_type_placeholder_item.rs:144:31 | LL | fn method_test3(&self) -> _; | ^ not allowed in type signatures @@ -433,7 +451,7 @@ LL | fn method_test3(&self) -> T; | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:144:26 + --> $DIR/typeck_type_placeholder_item.rs:146:26 | LL | fn assoc_fn_test1(x: _); | ^ not allowed in type signatures @@ -444,7 +462,7 @@ LL | fn assoc_fn_test1(x: T); | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:146:26 + --> $DIR/typeck_type_placeholder_item.rs:148:26 | LL | fn assoc_fn_test2(x: _) -> _; | ^ ^ not allowed in type signatures @@ -457,7 +475,7 @@ LL | fn assoc_fn_test2(x: T) -> T; | ^^^ ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:148:28 + --> $DIR/typeck_type_placeholder_item.rs:150:28 | LL | fn assoc_fn_test3() -> _; | ^ not allowed in type signatures @@ -468,7 +486,7 @@ LL | fn assoc_fn_test3() -> T; | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:60:37 + --> $DIR/typeck_type_placeholder_item.rs:61:37 | LL | fn clone_from(&mut self, other: _) { *self = Test9; } | ^ not allowed in type signatures @@ -479,7 +497,7 @@ LL | fn clone_from(&mut self, other: T) { *self = Test9; } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:108:34 + --> $DIR/typeck_type_placeholder_item.rs:110:34 | LL | fn fn_test10(&self, _x : _) { } | ^ not allowed in type signatures @@ -490,7 +508,7 @@ LL | fn fn_test10(&self, _x : T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:116:41 + --> $DIR/typeck_type_placeholder_item.rs:118:41 | LL | fn clone_from(&mut self, other: _) { *self = FnTest9; } | ^ not allowed in type signatures @@ -501,25 +519,25 @@ LL | fn clone_from(&mut self, other: T) { *self = FnTest9; } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:180:21 + --> $DIR/typeck_type_placeholder_item.rs:182:21 | LL | type Y = impl Trait<_>; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:188:14 + --> $DIR/typeck_type_placeholder_item.rs:190:14 | LL | type B = _; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:190:14 + --> $DIR/typeck_type_placeholder_item.rs:192:14 | LL | const C: _; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:192:14 + --> $DIR/typeck_type_placeholder_item.rs:194:14 | LL | const D: _ = 42; | ^ @@ -528,7 +546,7 @@ LL | const D: _ = 42; | help: replace `_` with the correct type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:39:24 + --> $DIR/typeck_type_placeholder_item.rs:40:24 | LL | fn test9(&self) -> _ { () } | ^ @@ -537,7 +555,7 @@ LL | fn test9(&self) -> _ { () } | help: replace with the correct return type: `()` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:57:24 + --> $DIR/typeck_type_placeholder_item.rs:58:24 | LL | fn clone(&self) -> _ { Test9 } | ^ @@ -546,7 +564,7 @@ LL | fn clone(&self) -> _ { Test9 } | help: replace with the correct return type: `Test9` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:105:31 + --> $DIR/typeck_type_placeholder_item.rs:107:31 | LL | fn fn_test9(&self) -> _ { () } | ^ @@ -555,7 +573,7 @@ LL | fn fn_test9(&self) -> _ { () } | help: replace with the correct return type: `()` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:113:28 + --> $DIR/typeck_type_placeholder_item.rs:115:28 | LL | fn clone(&self) -> _ { FnTest9 } | ^ @@ -564,25 +582,25 @@ LL | fn clone(&self) -> _ { FnTest9 } | help: replace with the correct return type: `main::FnTest9` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:197:14 + --> $DIR/typeck_type_placeholder_item.rs:199:14 | LL | type A = _; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:199:14 + --> $DIR/typeck_type_placeholder_item.rs:201:14 | LL | type B = _; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:201:14 + --> $DIR/typeck_type_placeholder_item.rs:203:14 | LL | const C: _; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:204:14 + --> $DIR/typeck_type_placeholder_item.rs:206:14 | LL | const D: _ = 42; | ^ @@ -590,7 +608,7 @@ LL | const D: _ = 42; | not allowed in type signatures | help: replace `_` with the correct type: `i32` -error: aborting due to 64 previous errors +error: aborting due to 66 previous errors Some errors have detailed explanations: E0121, E0282, E0403. For more information about an error, try `rustc --explain E0121`. diff --git a/src/test/ui/union/union-fields-2.stderr b/src/test/ui/union/union-fields-2.stderr index 68cb66d89d218..48654347285d3 100644 --- a/src/test/ui/union/union-fields-2.stderr +++ b/src/test/ui/union/union-fields-2.stderr @@ -48,18 +48,18 @@ error: union patterns should have exactly one field LL | let U { a, b } = u; | ^^^^^^^^^^ -error[E0026]: union `U` does not have a field named `c` - --> $DIR/union-fields-2.rs:18:19 - | -LL | let U { a, b, c } = u; - | ^ union `U` does not have this field - error: union patterns should have exactly one field --> $DIR/union-fields-2.rs:18:9 | LL | let U { a, b, c } = u; | ^^^^^^^^^^^^^ +error[E0026]: union `U` does not have a field named `c` + --> $DIR/union-fields-2.rs:18:19 + | +LL | let U { a, b, c } = u; + | ^ union `U` does not have this field + error: union patterns should have exactly one field --> $DIR/union-fields-2.rs:20:9 | diff --git a/src/test/ui/union/union-sized-field.stderr b/src/test/ui/union/union-sized-field.stderr index 62dacd064bed0..b916bbe8ad10a 100644 --- a/src/test/ui/union/union-sized-field.stderr +++ b/src/test/ui/union/union-sized-field.stderr @@ -1,26 +1,40 @@ error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/union-sized-field.rs:4:5 + --> $DIR/union-sized-field.rs:4:12 | LL | union Foo { | - this type parameter needs to be `std::marker::Sized` LL | value: T, - | ^^^^^^^^ doesn't have a size known at compile-time + | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `T` - = note: to learn more, visit = note: no field of a union may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | value: &T, + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | value: Box, + | ^^^^ ^ error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/union-sized-field.rs:9:5 + --> $DIR/union-sized-field.rs:9:12 | LL | struct Foo2 { | - this type parameter needs to be `std::marker::Sized` LL | value: T, - | ^^^^^^^^ doesn't have a size known at compile-time + | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `T` - = note: to learn more, visit = note: only the last field of a struct may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | value: &T, + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | value: Box, + | ^^^^ ^ error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/union-sized-field.rs:15:11 @@ -30,9 +44,16 @@ LL | enum Foo3 { LL | Value(T), | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `T` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | Value(&T), + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | Value(Box), + | ^^^^ ^ error: aborting due to 3 previous errors diff --git a/src/test/ui/union/union-unsized.stderr b/src/test/ui/union/union-unsized.stderr index e702f2c61bee3..f62a3b4d14b97 100644 --- a/src/test/ui/union/union-unsized.stderr +++ b/src/test/ui/union/union-unsized.stderr @@ -1,22 +1,38 @@ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/union-unsized.rs:4:5 + --> $DIR/union-unsized.rs:4:8 | LL | a: str, - | ^^^^^^ doesn't have a size known at compile-time + | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: no field of a union may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | a: &str, + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | a: Box, + | ^^^^ ^ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/union-unsized.rs:12:5 + --> $DIR/union-unsized.rs:12:8 | LL | b: str, - | ^^^^^^ doesn't have a size known at compile-time + | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: no field of a union may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | b: &str, + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | b: Box, + | ^^^^ ^ error: aborting due to 2 previous errors diff --git a/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr b/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr index 35f63a91b2b53..2ed35dc0e2c12 100644 --- a/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr +++ b/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr @@ -5,7 +5,6 @@ LL | let _x: fn(_) -> Test = Test; | ^^^^ doesn't have a size known at compile-time | = help: within `Test`, the trait `std::marker::Sized` is not implemented for `[i32]` - = note: to learn more, visit = note: required because it appears within the type `Test` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/unsized-locals/issue-30276.stderr b/src/test/ui/unsized-locals/issue-30276.stderr index d42fddb3a4a26..461efcf3dbf29 100644 --- a/src/test/ui/unsized-locals/issue-30276.stderr +++ b/src/test/ui/unsized-locals/issue-30276.stderr @@ -5,7 +5,6 @@ LL | let _x: fn(_) -> Test = Test; | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[i32]` - = note: to learn more, visit = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/unsized-locals/issue-50940-with-feature.stderr b/src/test/ui/unsized-locals/issue-50940-with-feature.stderr index 7b6c2d11ea169..04a8de1b5dc5b 100644 --- a/src/test/ui/unsized-locals/issue-50940-with-feature.stderr +++ b/src/test/ui/unsized-locals/issue-50940-with-feature.stderr @@ -5,7 +5,6 @@ LL | A as fn(str) -> A; | ^ doesn't have a size known at compile-time | = help: within `main::A`, the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: required because it appears within the type `main::A` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/unsized-locals/issue-50940.stderr b/src/test/ui/unsized-locals/issue-50940.stderr index be006c09d6f5c..8e5f753082734 100644 --- a/src/test/ui/unsized-locals/issue-50940.stderr +++ b/src/test/ui/unsized-locals/issue-50940.stderr @@ -5,7 +5,6 @@ LL | A as fn(str) -> A; | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/unsized-locals/unsized-exprs.stderr b/src/test/ui/unsized-locals/unsized-exprs.stderr index 43c35cdd7b5b0..0a9b43dac3344 100644 --- a/src/test/ui/unsized-locals/unsized-exprs.stderr +++ b/src/test/ui/unsized-locals/unsized-exprs.stderr @@ -5,7 +5,6 @@ LL | udrop::<(i32, [u8])>((42, *foo())); | ^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: within `({integer}, [u8])`, the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: required because it appears within the type `({integer}, [u8])` = note: tuples must have a statically known size to be initialized @@ -16,7 +15,6 @@ LL | udrop::>(A { 0: *foo() }); | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: within `A<[u8]>`, the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: required because it appears within the type `A<[u8]>` = note: structs must have a statically known size to be initialized @@ -27,7 +25,6 @@ LL | udrop::>(A(*foo())); | ^ doesn't have a size known at compile-time | = help: within `A<[u8]>`, the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: required because it appears within the type `A<[u8]>` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/unsized-locals/unsized-exprs3.stderr b/src/test/ui/unsized-locals/unsized-exprs3.stderr index f9a7452a5ebf2..11435ec0353bc 100644 --- a/src/test/ui/unsized-locals/unsized-exprs3.stderr +++ b/src/test/ui/unsized-locals/unsized-exprs3.stderr @@ -5,7 +5,6 @@ LL | udrop as fn([u8]); | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/unsized/unsized-bare-typaram.stderr b/src/test/ui/unsized/unsized-bare-typaram.stderr index 3ff6f30db2a84..19978ae24cacb 100644 --- a/src/test/ui/unsized/unsized-bare-typaram.stderr +++ b/src/test/ui/unsized/unsized-bare-typaram.stderr @@ -7,9 +7,6 @@ LL | fn foo() { bar::() } | - ^ doesn't have a size known at compile-time | | | this type parameter needs to be `std::marker::Sized` - | - = help: the trait `std::marker::Sized` is not implemented for `T` - = note: to learn more, visit error: aborting due to previous error diff --git a/src/test/ui/unsized/unsized-enum.stderr b/src/test/ui/unsized/unsized-enum.stderr index 1908aee25ea7b..fdfdb9b4e2a5b 100644 --- a/src/test/ui/unsized/unsized-enum.stderr +++ b/src/test/ui/unsized/unsized-enum.stderr @@ -9,8 +9,6 @@ LL | fn foo2() { not_sized::>() } | | | this type parameter needs to be `std::marker::Sized` | - = help: the trait `std::marker::Sized` is not implemented for `T` - = note: to learn more, visit help: you could relax the implicit `Sized` bound on `U` if it were used through indirection like `&U` or `Box` --> $DIR/unsized-enum.rs:4:10 | diff --git a/src/test/ui/unsized/unsized-enum2.stderr b/src/test/ui/unsized/unsized-enum2.stderr index bc3b3831f3269..988c310167682 100644 --- a/src/test/ui/unsized/unsized-enum2.stderr +++ b/src/test/ui/unsized/unsized-enum2.stderr @@ -7,22 +7,36 @@ LL | // parameter LL | VA(W), | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `W` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VA(&W), + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | VA(Box), + | ^^^^ ^ error[E0277]: the size for values of type `X` cannot be known at compilation time - --> $DIR/unsized-enum2.rs:25:8 + --> $DIR/unsized-enum2.rs:25:11 | LL | enum E { | - this type parameter needs to be `std::marker::Sized` ... LL | VB{x: X}, - | ^^^^ doesn't have a size known at compile-time + | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VB{x: &X}, + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | VB{x: Box}, + | ^^^^ ^ error[E0277]: the size for values of type `Y` cannot be known at compilation time --> $DIR/unsized-enum2.rs:27:15 @@ -33,22 +47,36 @@ LL | enum E { LL | VC(isize, Y), | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `Y` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VC(isize, &Y), + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | VC(isize, Box), + | ^^^^ ^ error[E0277]: the size for values of type `Z` cannot be known at compilation time - --> $DIR/unsized-enum2.rs:29:18 + --> $DIR/unsized-enum2.rs:29:21 | LL | enum E { | - this type parameter needs to be `std::marker::Sized` ... LL | VD{u: isize, x: Z}, - | ^^^^ doesn't have a size known at compile-time + | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `Z` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VD{u: isize, x: &Z}, + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | VD{u: isize, x: Box}, + | ^^^^ ^ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> $DIR/unsized-enum2.rs:33:8 @@ -57,18 +85,34 @@ LL | VE([u8]), | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VE(&[u8]), + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | VE(Box<[u8]>), + | ^^^^ ^ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/unsized-enum2.rs:35:8 + --> $DIR/unsized-enum2.rs:35:11 | LL | VF{x: str}, - | ^^^^^^ doesn't have a size known at compile-time + | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VF{x: &str}, + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | VF{x: Box}, + | ^^^^ ^ error[E0277]: the size for values of type `[f32]` cannot be known at compilation time --> $DIR/unsized-enum2.rs:37:15 @@ -77,18 +121,34 @@ LL | VG(isize, [f32]), | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[f32]` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VG(isize, &[f32]), + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | VG(isize, Box<[f32]>), + | ^^^^ ^ error[E0277]: the size for values of type `[u32]` cannot be known at compilation time - --> $DIR/unsized-enum2.rs:39:18 + --> $DIR/unsized-enum2.rs:39:21 | LL | VH{u: isize, x: [u32]}, - | ^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u32]` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VH{u: isize, x: &[u32]}, + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | VH{u: isize, x: Box<[u32]>}, + | ^^^^ ^ error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time --> $DIR/unsized-enum2.rs:53:8 @@ -97,18 +157,34 @@ LL | VM(dyn Foo), | ^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn Foo + 'static)` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VM(&dyn Foo), + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | VM(Box), + | ^^^^ ^ error[E0277]: the size for values of type `(dyn Bar + 'static)` cannot be known at compilation time - --> $DIR/unsized-enum2.rs:55:8 + --> $DIR/unsized-enum2.rs:55:11 | LL | VN{x: dyn Bar}, - | ^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn Bar + 'static)` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VN{x: &dyn Bar}, + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | VN{x: Box}, + | ^^^^ ^ error[E0277]: the size for values of type `(dyn FooBar + 'static)` cannot be known at compilation time --> $DIR/unsized-enum2.rs:57:15 @@ -117,18 +193,34 @@ LL | VO(isize, dyn FooBar), | ^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn FooBar + 'static)` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VO(isize, &dyn FooBar), + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | VO(isize, Box), + | ^^^^ ^ error[E0277]: the size for values of type `(dyn BarFoo + 'static)` cannot be known at compilation time - --> $DIR/unsized-enum2.rs:59:18 + --> $DIR/unsized-enum2.rs:59:21 | LL | VP{u: isize, x: dyn BarFoo}, - | ^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn BarFoo + 'static)` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VP{u: isize, x: &dyn BarFoo}, + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | VP{u: isize, x: Box}, + | ^^^^ ^ error[E0277]: the size for values of type `[i8]` cannot be known at compilation time --> $DIR/unsized-enum2.rs:63:8 @@ -137,18 +229,34 @@ LL | VQ(<&'static [i8] as Deref>::Target), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[i8]` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VQ(&<&'static [i8] as Deref>::Target), + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | VQ(Box<<&'static [i8] as Deref>::Target>), + | ^^^^ ^ error[E0277]: the size for values of type `[char]` cannot be known at compilation time - --> $DIR/unsized-enum2.rs:65:8 + --> $DIR/unsized-enum2.rs:65:11 | LL | VR{x: <&'static [char] as Deref>::Target}, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[char]` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VR{x: &<&'static [char] as Deref>::Target}, + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | VR{x: Box<<&'static [char] as Deref>::Target>}, + | ^^^^ ^ error[E0277]: the size for values of type `[f64]` cannot be known at compilation time --> $DIR/unsized-enum2.rs:67:15 @@ -157,18 +265,34 @@ LL | VS(isize, <&'static [f64] as Deref>::Target), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[f64]` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VS(isize, &<&'static [f64] as Deref>::Target), + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | VS(isize, Box<<&'static [f64] as Deref>::Target>), + | ^^^^ ^ error[E0277]: the size for values of type `[i32]` cannot be known at compilation time - --> $DIR/unsized-enum2.rs:69:18 + --> $DIR/unsized-enum2.rs:69:21 | LL | VT{u: isize, x: <&'static [i32] as Deref>::Target}, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[i32]` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VT{u: isize, x: &<&'static [i32] as Deref>::Target}, + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | VT{u: isize, x: Box<<&'static [i32] as Deref>::Target>}, + | ^^^^ ^ error[E0277]: the size for values of type `(dyn PathHelper1 + 'static)` cannot be known at compilation time --> $DIR/unsized-enum2.rs:43:8 @@ -177,20 +301,36 @@ LL | VI(Path1), | ^^^^^ doesn't have a size known at compile-time | = help: within `Path1`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper1 + 'static)` - = note: to learn more, visit = note: required because it appears within the type `Path1` = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VI(&Path1), + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | VI(Box), + | ^^^^ ^ error[E0277]: the size for values of type `(dyn PathHelper2 + 'static)` cannot be known at compilation time - --> $DIR/unsized-enum2.rs:45:8 + --> $DIR/unsized-enum2.rs:45:11 | LL | VJ{x: Path2}, - | ^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^ doesn't have a size known at compile-time | = help: within `Path2`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper2 + 'static)` - = note: to learn more, visit = note: required because it appears within the type `Path2` = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VJ{x: &Path2}, + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | VJ{x: Box}, + | ^^^^ ^ error[E0277]: the size for values of type `(dyn PathHelper3 + 'static)` cannot be known at compilation time --> $DIR/unsized-enum2.rs:47:15 @@ -199,20 +339,36 @@ LL | VK(isize, Path3), | ^^^^^ doesn't have a size known at compile-time | = help: within `Path3`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper3 + 'static)` - = note: to learn more, visit = note: required because it appears within the type `Path3` = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VK(isize, &Path3), + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | VK(isize, Box), + | ^^^^ ^ error[E0277]: the size for values of type `(dyn PathHelper4 + 'static)` cannot be known at compilation time - --> $DIR/unsized-enum2.rs:49:18 + --> $DIR/unsized-enum2.rs:49:21 | LL | VL{u: isize, x: Path4}, - | ^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^ doesn't have a size known at compile-time | = help: within `Path4`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper4 + 'static)` - = note: to learn more, visit = note: required because it appears within the type `Path4` = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VL{u: isize, x: &Path4}, + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | VL{u: isize, x: Box}, + | ^^^^ ^ error: aborting due to 20 previous errors diff --git a/src/test/ui/unsized/unsized-fn-param.stderr b/src/test/ui/unsized/unsized-fn-param.stderr index ed2c2e75cbd44..6b54db7148a74 100644 --- a/src/test/ui/unsized/unsized-fn-param.stderr +++ b/src/test/ui/unsized/unsized-fn-param.stderr @@ -5,7 +5,6 @@ LL | foo11("bar", &"baz"); | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: required for the cast to the object type `dyn std::convert::AsRef` error[E0277]: the size for values of type `str` cannot be known at compilation time @@ -15,7 +14,6 @@ LL | foo12(&"bar", "baz"); | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: required for the cast to the object type `dyn std::convert::AsRef` error[E0277]: the size for values of type `str` cannot be known at compilation time @@ -25,7 +23,6 @@ LL | foo21("bar", &"baz"); | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: required for the cast to the object type `dyn std::convert::AsRef` error[E0277]: the size for values of type `str` cannot be known at compilation time @@ -35,7 +32,6 @@ LL | foo22(&"bar", "baz"); | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: required for the cast to the object type `dyn std::convert::AsRef` error: aborting due to 4 previous errors diff --git a/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr b/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr index e0f077d66f99c..50b54593f3aa1 100644 --- a/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr +++ b/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr @@ -9,8 +9,6 @@ LL | impl S5 { | | | this type parameter needs to be `std::marker::Sized` | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box` --> $DIR/unsized-inherent-impl-self-type.rs:5:11 | diff --git a/src/test/ui/unsized/unsized-struct.stderr b/src/test/ui/unsized/unsized-struct.stderr index d92d1d9113e5c..0c8529bf1a9af 100644 --- a/src/test/ui/unsized/unsized-struct.stderr +++ b/src/test/ui/unsized/unsized-struct.stderr @@ -9,8 +9,6 @@ LL | fn foo2() { not_sized::>() } | | | this type parameter needs to be `std::marker::Sized` | - = help: the trait `std::marker::Sized` is not implemented for `T` - = note: to learn more, visit help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/unsized-struct.rs:4:12 | @@ -30,8 +28,6 @@ LL | fn bar2() { is_sized::>() } | | | this type parameter needs to be `std::marker::Sized` | - = help: within `Bar`, the trait `std::marker::Sized` is not implemented for `T` - = note: to learn more, visit = note: required because it appears within the type `Bar` error: aborting due to 2 previous errors diff --git a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr index 73c5439da53b6..4514208a90dc9 100644 --- a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr +++ b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr @@ -9,8 +9,6 @@ LL | impl T3 for S5 { | | | this type parameter needs to be `std::marker::Sized` | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box` --> $DIR/unsized-trait-impl-self-type.rs:8:11 | diff --git a/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr b/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr index e423a9bdeab6f..f48d4ef9f1461 100644 --- a/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr +++ b/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr @@ -9,8 +9,6 @@ LL | impl T2 for S4 { | | | this type parameter needs to be `std::marker::Sized` | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit help: consider relaxing the implicit `Sized` restriction | LL | trait T2 { diff --git a/src/test/ui/unsized3.stderr b/src/test/ui/unsized3.stderr index e0a0389dc4690..ddddae4eaba57 100644 --- a/src/test/ui/unsized3.stderr +++ b/src/test/ui/unsized3.stderr @@ -9,8 +9,6 @@ LL | f2::(x); LL | fn f2(x: &X) { | - required by this bound in `f2` | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit help: consider relaxing the implicit `Sized` restriction | LL | fn f2(x: &X) { @@ -27,8 +25,6 @@ LL | f4::(x); LL | fn f4(x: &X) { | - required by this bound in `f4` | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit help: consider relaxing the implicit `Sized` restriction | LL | fn f4(x: &X) { @@ -45,8 +41,6 @@ LL | fn f8(x1: &S, x2: &S) { LL | f5(x1); | ^^ doesn't have a size known at compile-time | - = help: within `S`, the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: required because it appears within the type `S` help: consider relaxing the implicit `Sized` restriction | @@ -61,8 +55,6 @@ LL | fn f9(x1: Box>) { LL | f5(&(*x1, 34)); | ^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `S`, the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: required because it appears within the type `S` = note: only the last element of a tuple may have a dynamically sized type @@ -74,8 +66,6 @@ LL | fn f10(x1: Box>) { LL | f5(&(32, *x1)); | ^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `({integer}, S)`, the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: required because it appears within the type `S` = note: required because it appears within the type `({integer}, S)` = note: tuples must have a statically known size to be initialized @@ -91,8 +81,6 @@ LL | fn f10(x1: Box>) { LL | f5(&(32, *x1)); | ^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `({integer}, S)`, the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: required because it appears within the type `S` = note: required because it appears within the type `({integer}, S)` help: consider relaxing the implicit `Sized` restriction diff --git a/src/test/ui/unsized5.stderr b/src/test/ui/unsized5.stderr index de4da309791c0..3fd0b429becc1 100644 --- a/src/test/ui/unsized5.stderr +++ b/src/test/ui/unsized5.stderr @@ -1,47 +1,77 @@ error[E0277]: the size for values of type `X` cannot be known at compilation time - --> $DIR/unsized5.rs:4:5 + --> $DIR/unsized5.rs:4:9 | LL | struct S1 { | - this type parameter needs to be `std::marker::Sized` LL | f1: X, - | ^^^^^ doesn't have a size known at compile-time + | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: only the last field of a struct may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | f1: &X, + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | f1: Box, + | ^^^^ ^ error[E0277]: the size for values of type `X` cannot be known at compilation time - --> $DIR/unsized5.rs:10:5 + --> $DIR/unsized5.rs:10:8 | LL | struct S2 { | - this type parameter needs to be `std::marker::Sized` LL | f: isize, LL | g: X, - | ^^^^ doesn't have a size known at compile-time + | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: only the last field of a struct may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | g: &X, + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | g: Box, + | ^^^^ ^ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/unsized5.rs:15:5 + --> $DIR/unsized5.rs:15:8 | LL | f: str, - | ^^^^^^ doesn't have a size known at compile-time + | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: only the last field of a struct may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | f: &str, + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | f: Box, + | ^^^^ ^ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/unsized5.rs:20:5 + --> $DIR/unsized5.rs:20:8 | LL | f: [u8], - | ^^^^^^^ doesn't have a size known at compile-time + | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: only the last field of a struct may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | f: &[u8], + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | f: Box<[u8]>, + | ^^^^ ^ error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized5.rs:25:8 @@ -51,21 +81,35 @@ LL | enum E { LL | V1(X, isize), | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | V1(&X, isize), + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | V1(Box, isize), + | ^^^^ ^ error[E0277]: the size for values of type `X` cannot be known at compilation time - --> $DIR/unsized5.rs:29:8 + --> $DIR/unsized5.rs:29:12 | LL | enum F { | - this type parameter needs to be `std::marker::Sized` LL | V2{f1: X, f: isize}, - | ^^^^^ doesn't have a size known at compile-time + | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | V2{f1: &X, f: isize}, + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | V2{f1: Box, f: isize}, + | ^^^^ ^ error: aborting due to 6 previous errors diff --git a/src/test/ui/unsized6.stderr b/src/test/ui/unsized6.stderr index 337afd2ee7e10..f045bfe2444bc 100644 --- a/src/test/ui/unsized6.stderr +++ b/src/test/ui/unsized6.stderr @@ -7,8 +7,6 @@ LL | fn f1(x: &X) { LL | let y: Y; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `Y` - = note: to learn more, visit = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature @@ -21,8 +19,6 @@ LL | let _: W; // <-- this is OK, no bindings created, no initializer. LL | let _: (isize, (X, isize)); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: only the last element of a tuple may have a dynamically sized type error[E0277]: the size for values of type `Z` cannot be known at compilation time @@ -34,8 +30,6 @@ LL | fn f1(x: &X) { LL | let y: (isize, (Z, usize)); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `Z` - = note: to learn more, visit = note: only the last element of a tuple may have a dynamically sized type error[E0277]: the size for values of type `X` cannot be known at compilation time @@ -46,8 +40,6 @@ LL | fn f2(x: &X) { LL | let y: X; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature @@ -60,8 +52,6 @@ LL | fn f2(x: &X) { LL | let y: (isize, (Y, isize)); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `Y` - = note: to learn more, visit = note: only the last element of a tuple may have a dynamically sized type error[E0277]: the size for values of type `X` cannot be known at compilation time @@ -72,8 +62,6 @@ LL | fn f3(x1: Box, x2: Box, x3: Box) { LL | let y: X = *x1; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature @@ -86,8 +74,6 @@ LL | fn f3(x1: Box, x2: Box, x3: Box) { LL | let y = *x2; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature @@ -100,8 +86,6 @@ LL | fn f3(x1: Box, x2: Box, x3: Box) { LL | let (y, z) = (*x3, 4); | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature @@ -113,8 +97,6 @@ LL | fn f4(x1: Box, x2: Box, x3: Box) { LL | let y: X = *x1; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature @@ -127,8 +109,6 @@ LL | fn f4(x1: Box, x2: Box, x3: Box) { LL | let y = *x2; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature @@ -141,8 +121,6 @@ LL | fn f4(x1: Box, x2: Box, x3: Box) { LL | let (y, z) = (*x3, 4); | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature @@ -154,10 +132,11 @@ LL | fn g1(x: X) {} | | | this type parameter needs to be `std::marker::Sized` | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit - = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn g1(x: &X) {} + | ^ error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized6.rs:40:22 @@ -167,10 +146,11 @@ LL | fn g2(x: X) {} | | | this type parameter needs to be `std::marker::Sized` | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit - = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn g2(x: &X) {} + | ^ error: aborting due to 13 previous errors diff --git a/src/test/ui/unsized7.stderr b/src/test/ui/unsized7.stderr index e616a5cf0f9c2..7dbddd4ed2443 100644 --- a/src/test/ui/unsized7.stderr +++ b/src/test/ui/unsized7.stderr @@ -9,8 +9,6 @@ LL | impl T1 for S3 { | | | this type parameter needs to be `std::marker::Sized` | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit help: consider relaxing the implicit `Sized` restriction | LL | trait T1 { diff --git a/src/test/ui/wf/wf-array-elem-sized.stderr b/src/test/ui/wf/wf-array-elem-sized.stderr index b222d07580eaf..fedec1909fd33 100644 --- a/src/test/ui/wf/wf-array-elem-sized.stderr +++ b/src/test/ui/wf/wf-array-elem-sized.stderr @@ -1,11 +1,10 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/wf-array-elem-sized.rs:7:5 + --> $DIR/wf-array-elem-sized.rs:7:10 | LL | foo: [[u8]], - | ^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: slice and array elements must have `Sized` type error: aborting due to previous error diff --git a/src/test/ui/wf/wf-enum-fields-struct-variant.stderr b/src/test/ui/wf/wf-enum-fields-struct-variant.stderr index 0a3665fcf0436..1eb7010c77a79 100644 --- a/src/test/ui/wf/wf-enum-fields-struct-variant.stderr +++ b/src/test/ui/wf/wf-enum-fields-struct-variant.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied - --> $DIR/wf-enum-fields-struct-variant.rs:13:9 + --> $DIR/wf-enum-fields-struct-variant.rs:13:12 | LL | struct IsCopy { | ---- required by this bound in `IsCopy` ... LL | f: IsCopy - | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A` + | ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A` | help: consider restricting type parameter `A` | diff --git a/src/test/ui/wf/wf-fn-where-clause.stderr b/src/test/ui/wf/wf-fn-where-clause.stderr index 731d31ac34f62..938336d3ace76 100644 --- a/src/test/ui/wf/wf-fn-where-clause.stderr +++ b/src/test/ui/wf/wf-fn-where-clause.stderr @@ -22,7 +22,6 @@ LL | struct Vec { | - required by this bound in `Vec` | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::marker::Copy + 'static)` - = note: to learn more, visit help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/wf-fn-where-clause.rs:16:12 | diff --git a/src/test/ui/wf/wf-in-fn-type-arg.stderr b/src/test/ui/wf/wf-in-fn-type-arg.stderr index c0bb3a50b1f1e..212c61e1e5e07 100644 --- a/src/test/ui/wf/wf-in-fn-type-arg.stderr +++ b/src/test/ui/wf/wf-in-fn-type-arg.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied - --> $DIR/wf-in-fn-type-arg.rs:9:5 + --> $DIR/wf-in-fn-type-arg.rs:9:8 | LL | struct MustBeCopy { | ---- required by this bound in `MustBeCopy` ... LL | x: fn(MustBeCopy) - | ^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` | help: consider restricting type parameter `T` | diff --git a/src/test/ui/wf/wf-in-fn-type-ret.stderr b/src/test/ui/wf/wf-in-fn-type-ret.stderr index e203058250790..3fb05fe81763b 100644 --- a/src/test/ui/wf/wf-in-fn-type-ret.stderr +++ b/src/test/ui/wf/wf-in-fn-type-ret.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied - --> $DIR/wf-in-fn-type-ret.rs:9:5 + --> $DIR/wf-in-fn-type-ret.rs:9:8 | LL | struct MustBeCopy { | ---- required by this bound in `MustBeCopy` ... LL | x: fn() -> MustBeCopy - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` | help: consider restricting type parameter `T` | diff --git a/src/test/ui/wf/wf-in-fn-type-static.stderr b/src/test/ui/wf/wf-in-fn-type-static.stderr index a79c446247794..44cacf4ef4dfe 100644 --- a/src/test/ui/wf/wf-in-fn-type-static.stderr +++ b/src/test/ui/wf/wf-in-fn-type-static.stderr @@ -1,20 +1,20 @@ error[E0310]: the parameter type `T` may not live long enough - --> $DIR/wf-in-fn-type-static.rs:13:5 + --> $DIR/wf-in-fn-type-static.rs:13:8 | LL | struct Foo { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // needs T: 'static LL | x: fn() -> &'static T - | ^^^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at + | ^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at error[E0310]: the parameter type `T` may not live long enough - --> $DIR/wf-in-fn-type-static.rs:18:5 + --> $DIR/wf-in-fn-type-static.rs:18:8 | LL | struct Bar { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // needs T: Copy LL | x: fn(&'static T) - | ^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at + | ^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at error: aborting due to 2 previous errors diff --git a/src/test/ui/wf/wf-in-obj-type-static.stderr b/src/test/ui/wf/wf-in-obj-type-static.stderr index c0057f3c82977..c50a6bb6e4d87 100644 --- a/src/test/ui/wf/wf-in-obj-type-static.stderr +++ b/src/test/ui/wf/wf-in-obj-type-static.stderr @@ -1,11 +1,11 @@ error[E0310]: the parameter type `T` may not live long enough - --> $DIR/wf-in-obj-type-static.rs:14:5 + --> $DIR/wf-in-obj-type-static.rs:14:8 | LL | struct Foo { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // needs T: 'static LL | x: dyn Object<&'static T> - | ^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at + | ^^^^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-obj-type-trait.stderr b/src/test/ui/wf/wf-in-obj-type-trait.stderr index 6d85cdde7f991..129f9484df29b 100644 --- a/src/test/ui/wf/wf-in-obj-type-trait.stderr +++ b/src/test/ui/wf/wf-in-obj-type-trait.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied - --> $DIR/wf-in-obj-type-trait.rs:11:5 + --> $DIR/wf-in-obj-type-trait.rs:11:8 | LL | struct MustBeCopy { | ---- required by this bound in `MustBeCopy` ... LL | x: dyn Object> - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` | help: consider restricting type parameter `T` | diff --git a/src/test/ui/wf/wf-struct-field.stderr b/src/test/ui/wf/wf-struct-field.stderr index cda3b8fe4fddb..d7d0b7a0820a8 100644 --- a/src/test/ui/wf/wf-struct-field.stderr +++ b/src/test/ui/wf/wf-struct-field.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied - --> $DIR/wf-struct-field.rs:12:5 + --> $DIR/wf-struct-field.rs:12:11 | LL | struct IsCopy { | ---- required by this bound in `IsCopy` ... LL | data: IsCopy - | ^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A` + | ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A` | help: consider restricting type parameter `A` | diff --git a/src/test/ui/xcrate/xcrate-unit-struct.stderr b/src/test/ui/xcrate/xcrate-unit-struct.stderr index e4a4b9c580602..813d5d4fdb12b 100644 --- a/src/test/ui/xcrate/xcrate-unit-struct.stderr +++ b/src/test/ui/xcrate/xcrate-unit-struct.stderr @@ -2,7 +2,7 @@ error[E0423]: expected value, found struct `xcrate_unit_struct::StructWithFields --> $DIR/xcrate-unit-struct.rs:9:13 | LL | let _ = xcrate_unit_struct::StructWithFields; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ did you mean `xcrate_unit_struct::StructWithFields { /* fields */ }`? + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `xcrate_unit_struct::StructWithFields { foo: val }` error: aborting due to previous error diff --git a/src/tools/cargo b/src/tools/cargo index 4f74d9b2a771c..43cf77395cad5 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 4f74d9b2a771c58b7ef4906b2668afd075bc8081 +Subproject commit 43cf77395cad5b79887b20b7cf19d418bbd703a9 diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.md b/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.md index 70445d7ef2503..98fd0df685fdb 100644 --- a/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.md +++ b/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.md @@ -12,7 +12,7 @@ labels: L-lint - Kind: *See for list of lint kinds* -*What benefit of this lint over old code?* +*What is the advantage of the recommended code over the original code* For example: - Remove bounce checking inserted by ... diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml index 0c80394f03e3c..fd0cd7a1890bd 100644 --- a/src/tools/clippy/.github/workflows/clippy_bors.yml +++ b/src/tools/clippy/.github/workflows/clippy_bors.yml @@ -240,7 +240,8 @@ jobs: - 'Geal/nom' - 'rust-lang/stdarch' - 'serde-rs/serde' - - 'chronotope/chrono' + # FIXME: chrono currently cannot be compiled with `--all-targets` + # - 'chronotope/chrono' - 'hyperium/hyper' - 'rust-random/rand' - 'rust-lang/futures-rs' diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index adc945a69441d..5d08b44ba404f 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -1352,6 +1352,7 @@ Released 2018-09-13 [`bad_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#bad_bit_mask [`bind_instead_of_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#bind_instead_of_map [`blacklisted_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#blacklisted_name +[`blanket_clippy_restriction_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#blanket_clippy_restriction_lints [`blocks_in_if_conditions`]: https://rust-lang.github.io/rust-clippy/master/index.html#blocks_in_if_conditions [`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison [`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const @@ -1508,9 +1509,11 @@ Released 2018-09-13 [`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 [`map_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_flatten +[`map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_identity [`map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or [`match_as_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_as_ref [`match_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_bool +[`match_like_matches_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro [`match_on_vec_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_on_vec_items [`match_overlapping_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_overlapping_arm [`match_ref_pats`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_ref_pats @@ -1575,6 +1578,7 @@ Released 2018-09-13 [`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref [`option_as_ref_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref [`option_env_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_env_unwrap +[`option_if_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else [`option_map_or_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_none [`option_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unit_fn [`option_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_option @@ -1586,6 +1590,7 @@ Released 2018-09-13 [`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite +[`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma [`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence [`print_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_literal @@ -1612,6 +1617,7 @@ Released 2018-09-13 [`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes [`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro +[`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts [`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 diff --git a/src/tools/clippy/CONTRIBUTING.md b/src/tools/clippy/CONTRIBUTING.md index 9f7bdcb1be7e5..69a734e4ee4c2 100644 --- a/src/tools/clippy/CONTRIBUTING.md +++ b/src/tools/clippy/CONTRIBUTING.md @@ -245,7 +245,7 @@ this to work, you will need the fix of `git subtree` available [here][gitgitgadget-pr]. [gitgitgadget-pr]: https://github.com/gitgitgadget/git/pull/493 -[subtree]: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#external-dependencies-subtree +[subtree]: https://rustc-dev-guide.rust-lang.org/contributing.html#external-dependencies-subtree [`rust-lang/rust`]: https://github.com/rust-lang/rust ## Issue and PR triage diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs index 3f7d6ba646770..c29432bf93384 100644 --- a/src/tools/clippy/clippy_lints/src/attrs.rs +++ b/src/tools/clippy/clippy_lints/src/attrs.rs @@ -2,8 +2,8 @@ use crate::reexport::Name; use crate::utils::{ - first_line_of_span, is_present_in_source, match_def_path, paths, snippet_opt, span_lint, span_lint_and_sugg, - span_lint_and_then, without_block_comments, + first_line_of_span, is_present_in_source, match_def_path, paths, snippet_opt, span_lint, span_lint_and_help, + span_lint_and_sugg, span_lint_and_then, without_block_comments, }; use if_chain::if_chain; use rustc_ast::ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; @@ -17,7 +17,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{Symbol, SymbolStr}; use semver::Version; static UNIX_SYSTEMS: &[&str] = &[ @@ -182,6 +182,29 @@ declare_clippy_lint! { "unknown_lints for scoped Clippy lints" } +declare_clippy_lint! { + /// **What it does:** Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category. + /// + /// **Why is this bad?** Restriction lints sometimes are in contrast with other lints or even go against idiomatic rust. + /// These lints should only be enabled on a lint-by-lint basis and with careful consideration. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// Bad: + /// ```rust + /// #![deny(clippy::restriction)] + /// ``` + /// + /// Good: + /// ```rust + /// #![deny(clippy::as_conversions)] + /// ``` + pub BLANKET_CLIPPY_RESTRICTION_LINTS, + style, + "enabling the complete restriction group" +} + declare_clippy_lint! { /// **What it does:** Checks for `#[cfg_attr(rustfmt, rustfmt_skip)]` and suggests to replace it /// with `#[rustfmt::skip]`. @@ -249,15 +272,17 @@ declare_lint_pass!(Attributes => [ DEPRECATED_SEMVER, USELESS_ATTRIBUTE, UNKNOWN_CLIPPY_LINTS, + BLANKET_CLIPPY_RESTRICTION_LINTS, ]); impl<'tcx> LateLintPass<'tcx> for Attributes { fn check_attribute(&mut self, cx: &LateContext<'tcx>, attr: &'tcx Attribute) { if let Some(items) = &attr.meta_item_list() { if let Some(ident) = attr.ident() { - match &*ident.as_str() { + let ident = &*ident.as_str(); + match ident { "allow" | "warn" | "deny" | "forbid" => { - check_clippy_lint_names(cx, items); + check_clippy_lint_names(cx, ident, items); }, _ => {}, } @@ -363,38 +388,47 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { } } -#[allow(clippy::single_match_else)] -fn check_clippy_lint_names(cx: &LateContext<'_>, items: &[NestedMetaItem]) { - let lint_store = cx.lints(); - for lint in items { +fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMetaItem]) { + fn extract_name(lint: &NestedMetaItem) -> Option { if_chain! { if let Some(meta_item) = lint.meta_item(); if meta_item.path.segments.len() > 1; if let tool_name = meta_item.path.segments[0].ident; if tool_name.as_str() == "clippy"; - let name = meta_item.path.segments.last().unwrap().ident.name; - if let CheckLintNameResult::Tool(Err((None, _))) = lint_store.check_lint_name( - &name.as_str(), - Some(tool_name.name), - ); + let lint_name = meta_item.path.segments.last().unwrap().ident.name; then { + return Some(lint_name.as_str()); + } + } + None + } + + let lint_store = cx.lints(); + for lint in items { + if let Some(lint_name) = extract_name(lint) { + if let CheckLintNameResult::Tool(Err((None, _))) = + lint_store.check_lint_name(&lint_name, Some(sym!(clippy))) + { span_lint_and_then( cx, UNKNOWN_CLIPPY_LINTS, lint.span(), - &format!("unknown clippy lint: clippy::{}", name), + &format!("unknown clippy lint: clippy::{}", lint_name), |diag| { - let name_lower = name.as_str().to_lowercase(); - let symbols = lint_store.get_lints().iter().map( - |l| Symbol::intern(&l.name_lower()) - ).collect::>(); + let name_lower = lint_name.to_lowercase(); + let symbols = lint_store + .get_lints() + .iter() + .map(|l| Symbol::intern(&l.name_lower())) + .collect::>(); let sugg = find_best_match_for_name( symbols.iter(), - &format!("clippy::{}", name_lower), + Symbol::intern(&format!("clippy::{}", name_lower)), None, ); - if name.as_str().chars().any(char::is_uppercase) - && lint_store.find_lints(&format!("clippy::{}", name_lower)).is_ok() { + if lint_name.chars().any(char::is_uppercase) + && lint_store.find_lints(&format!("clippy::{}", name_lower)).is_ok() + { diag.span_suggestion( lint.span(), "lowercase the lint name", @@ -409,10 +443,19 @@ fn check_clippy_lint_names(cx: &LateContext<'_>, items: &[NestedMetaItem]) { Applicability::MachineApplicable, ); } - } + }, + ); + } else if lint_name == "restriction" && ident != "allow" { + span_lint_and_help( + cx, + BLANKET_CLIPPY_RESTRICTION_LINTS, + lint.span(), + "restriction lints are not meant to be all enabled", + None, + "try enabling only the lints you really need", ); } - }; + } } } @@ -442,15 +485,14 @@ fn is_relevant_trait(cx: &LateContext<'_>, item: &TraitItem<'_>) -> bool { } fn is_relevant_block(cx: &LateContext<'_>, tables: &ty::TypeckTables<'_>, block: &Block<'_>) -> bool { - if let Some(stmt) = block.stmts.first() { - match &stmt.kind { + block.stmts.first().map_or( + block.expr.as_ref().map_or(false, |e| is_relevant_expr(cx, tables, e)), + |stmt| match &stmt.kind { StmtKind::Local(_) => true, StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, tables, expr), _ => false, - } - } else { - block.expr.as_ref().map_or(false, |e| is_relevant_expr(cx, tables, e)) - } + }, + ) } fn is_relevant_expr(cx: &LateContext<'_>, tables: &ty::TypeckTables<'_>, expr: &Expr<'_>) -> bool { @@ -460,11 +502,10 @@ fn is_relevant_expr(cx: &LateContext<'_>, tables: &ty::TypeckTables<'_>, expr: & ExprKind::Ret(None) | ExprKind::Break(_, None) => false, ExprKind::Call(path_expr, _) => { if let ExprKind::Path(qpath) = &path_expr.kind { - if let Some(fun_id) = tables.qpath_res(qpath, path_expr.hir_id).opt_def_id() { - !match_def_path(cx, fun_id, &paths::BEGIN_PANIC) - } else { - true - } + tables + .qpath_res(qpath, path_expr.hir_id) + .opt_def_id() + .map_or(true, |fun_id| !match_def_path(cx, fun_id, &paths::BEGIN_PANIC)) } else { true } diff --git a/src/tools/clippy/clippy_lints/src/await_holding_lock.rs b/src/tools/clippy/clippy_lints/src/await_holding_lock.rs index 20b91bc0f1baf..d337262dfa6e2 100644 --- a/src/tools/clippy/clippy_lints/src/await_holding_lock.rs +++ b/src/tools/clippy/clippy_lints/src/await_holding_lock.rs @@ -11,7 +11,7 @@ declare_clippy_lint! { /// non-async-aware MutexGuard. /// /// **Why is this bad?** The Mutex types found in syd::sync and parking_lot - /// are not designed to operator in an async context across await points. + /// are not designed to operate in an async context across await points. /// /// There are two potential solutions. One is to use an asynx-aware Mutex /// type. Many asynchronous foundation crates provide such a Mutex type. The diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs index 8090f4673aae0..42bff564de03d 100644 --- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs +++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs @@ -115,7 +115,7 @@ fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, else_: &ast::Expr) { COLLAPSIBLE_IF, block.span, "this `else { if .. }` block can be collapsed", - "try", + "collapse nested if block", snippet_block_with_applicability(cx, else_.span, "..", Some(block.span), &mut applicability).into_owned(), applicability, ); @@ -142,7 +142,7 @@ fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: & let rhs = Sugg::ast(cx, check_inner, ".."); diag.span_suggestion( expr.span, - "try", + "collapse nested if block", format!( "if {} {}", lhs.and(&rhs), diff --git a/src/tools/clippy/clippy_lints/src/comparison_chain.rs b/src/tools/clippy/clippy_lints/src/comparison_chain.rs index 26476af4cb629..25ccabc1c883e 100644 --- a/src/tools/clippy/clippy_lints/src/comparison_chain.rs +++ b/src/tools/clippy/clippy_lints/src/comparison_chain.rs @@ -122,8 +122,5 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain { } fn kind_is_cmp(kind: BinOpKind) -> bool { - match kind { - BinOpKind::Lt | BinOpKind::Gt | BinOpKind::Eq => true, - _ => false, - } + matches!(kind, BinOpKind::Lt | BinOpKind::Gt | BinOpKind::Eq) } diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs index 6e8ca647dd7ae..818d8188a787a 100644 --- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs +++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs @@ -153,5 +153,13 @@ declare_deprecated_lint! { /// /// **Deprecation reason:** Associated-constants are now preferred. pub REPLACE_CONSTS, - "associated-constants `MIN`/`MAX` of integers are prefer to `{min,max}_value()` and module constants" + "associated-constants `MIN`/`MAX` of integers are prefered to `{min,max}_value()` and module constants" +} + +declare_deprecated_lint! { + /// **What it does:** Nothing. This lint has been deprecated. + /// + /// **Deprecation reason:** The regex! macro does not exist anymore. + pub REGEX_MACRO, + "the regex! macro has been removed from the regex crate in 2018" } diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index d740d88a77d6c..323cad7fa1a8c 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -73,9 +73,10 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { fn lint_deref(cx: &LateContext<'_>, method_name: &str, call_expr: &Expr<'_>, var_span: Span, expr_span: Span) { match method_name { "deref" => { - if cx.tcx.lang_items().deref_trait().map_or(false, |id| { + let impls_deref_trait = cx.tcx.lang_items().deref_trait().map_or(false, |id| { implements_trait(cx, cx.tables().expr_ty(&call_expr), id, &[]) - }) { + }); + if impls_deref_trait { span_lint_and_sugg( cx, EXPLICIT_DEREF_METHODS, @@ -88,9 +89,10 @@ fn lint_deref(cx: &LateContext<'_>, method_name: &str, call_expr: &Expr<'_>, var } }, "deref_mut" => { - if cx.tcx.lang_items().deref_mut_trait().map_or(false, |id| { + let impls_deref_mut_trait = cx.tcx.lang_items().deref_mut_trait().map_or(false, |id| { implements_trait(cx, cx.tables().expr_ty(&call_expr), id, &[]) - }) { + }); + if impls_deref_mut_trait { span_lint_and_sugg( cx, EXPLICIT_DEREF_METHODS, diff --git a/src/tools/clippy/clippy_lints/src/eq_op.rs b/src/tools/clippy/clippy_lints/src/eq_op.rs index cbc93d772dd91..01eff28cb195a 100644 --- a/src/tools/clippy/clippy_lints/src/eq_op.rs +++ b/src/tools/clippy/clippy_lints/src/eq_op.rs @@ -214,20 +214,20 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { } fn is_valid_operator(op: BinOp) -> bool { - match op.node { + matches!( + op.node, BinOpKind::Sub - | BinOpKind::Div - | BinOpKind::Eq - | BinOpKind::Lt - | BinOpKind::Le - | BinOpKind::Gt - | BinOpKind::Ge - | BinOpKind::Ne - | BinOpKind::And - | BinOpKind::Or - | BinOpKind::BitXor - | BinOpKind::BitAnd - | BinOpKind::BitOr => true, - _ => false, - } + | BinOpKind::Div + | BinOpKind::Eq + | BinOpKind::Lt + | BinOpKind::Le + | BinOpKind::Gt + | BinOpKind::Ge + | BinOpKind::Ne + | BinOpKind::And + | BinOpKind::Or + | BinOpKind::BitXor + | BinOpKind::BitAnd + | BinOpKind::BitOr + ) } diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index b10181062ff10..ceb3c40d869a1 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -105,10 +105,7 @@ fn is_argument(map: rustc_middle::hir::map::Map<'_>, id: HirId) -> bool { _ => return false, } - match map.find(map.get_parent_node(id)) { - Some(Node::Param(_)) => true, - _ => false, - } + matches!(map.find(map.get_parent_node(id)), Some(Node::Param(_))) } impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index ceed6a74c4fcc..fb26b9fc27d25 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -175,10 +175,7 @@ fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: def_id::DefId, self_a fn match_borrow_depth(lhs: Ty<'_>, rhs: Ty<'_>) -> bool { match (&lhs.kind, &rhs.kind) { (ty::Ref(_, t1, mut1), ty::Ref(_, t2, mut2)) => mut1 == mut2 && match_borrow_depth(&t1, &t2), - (l, r) => match (l, r) { - (ty::Ref(_, _, _), _) | (_, ty::Ref(_, _, _)) => false, - (_, _) => true, - }, + (l, r) => !matches!((l, r), (ty::Ref(_, _, _), _) | (_, ty::Ref(_, _, _))), } } diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs index 4efd068926796..3087d6a940a86 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs @@ -1,11 +1,11 @@ use crate::consts::{ constant, constant_simple, Constant, - Constant::{F32, F64}, + Constant::{Int, F32, F64}, }; -use crate::utils::{higher, numeric_literal, span_lint_and_sugg, sugg, SpanlessEq}; +use crate::utils::{get_parent_expr, higher, numeric_literal, span_lint_and_sugg, sugg, SpanlessEq}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; +use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -293,6 +293,121 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { } } +fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { + if let Some((value, _)) = constant(cx, cx.tables(), &args[1]) { + if value == Int(2) { + if let Some(parent) = get_parent_expr(cx, expr) { + if let Some(grandparent) = get_parent_expr(cx, parent) { + if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, _, args, _) = grandparent.kind { + if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() { + return; + } + } + } + + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Add, .. + }, + ref lhs, + ref rhs, + ) = parent.kind + { + let other_addend = if lhs.hir_id == expr.hir_id { rhs } else { lhs }; + + span_lint_and_sugg( + cx, + SUBOPTIMAL_FLOPS, + parent.span, + "square can be computed more efficiently", + "consider using", + format!( + "{}.mul_add({}, {})", + Sugg::hir(cx, &args[0], ".."), + Sugg::hir(cx, &args[0], ".."), + Sugg::hir(cx, &other_addend, ".."), + ), + Applicability::MachineApplicable, + ); + + return; + } + } + + span_lint_and_sugg( + cx, + SUBOPTIMAL_FLOPS, + expr.span, + "square can be computed more efficiently", + "consider using", + format!("{} * {}", Sugg::hir(cx, &args[0], ".."), Sugg::hir(cx, &args[0], "..")), + Applicability::MachineApplicable, + ); + } + } +} + +fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option { + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Add, .. + }, + ref add_lhs, + ref add_rhs, + ) = args[0].kind + { + // check if expression of the form x * x + y * y + if_chain! { + if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref lmul_lhs, ref lmul_rhs) = add_lhs.kind; + if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref rmul_lhs, ref rmul_rhs) = add_rhs.kind; + if are_exprs_equal(cx, lmul_lhs, lmul_rhs); + if are_exprs_equal(cx, rmul_lhs, rmul_rhs); + then { + return Some(format!("{}.hypot({})", Sugg::hir(cx, &lmul_lhs, ".."), Sugg::hir(cx, &rmul_lhs, ".."))); + } + } + + // check if expression of the form x.powi(2) + y.powi(2) + if_chain! { + if let ExprKind::MethodCall( + PathSegment { ident: lmethod_name, .. }, + ref _lspan, + ref largs, + _ + ) = add_lhs.kind; + if let ExprKind::MethodCall( + PathSegment { ident: rmethod_name, .. }, + ref _rspan, + ref rargs, + _ + ) = add_rhs.kind; + if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi"; + if let Some((lvalue, _)) = constant(cx, cx.tables(), &largs[1]); + if let Some((rvalue, _)) = constant(cx, cx.tables(), &rargs[1]); + if Int(2) == lvalue && Int(2) == rvalue; + then { + return Some(format!("{}.hypot({})", Sugg::hir(cx, &largs[0], ".."), Sugg::hir(cx, &rargs[0], ".."))); + } + } + } + + None +} + +fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { + if let Some(message) = detect_hypot(cx, args) { + span_lint_and_sugg( + cx, + IMPRECISE_FLOPS, + expr.span, + "hypotenuse can be computed more accurately", + "consider using", + message, + Applicability::MachineApplicable, + ); + } +} + // TODO: Lint expressions of the form `x.exp() - y` where y > 1 // and suggest usage of `x.exp_m1() - (y - 1)` instead fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { @@ -344,6 +459,14 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) { rhs, ) = &expr.kind { + if let Some(parent) = get_parent_expr(cx, expr) { + if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, _, args, _) = parent.kind { + if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() { + return; + } + } + } + let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) { (inner_lhs, inner_rhs, rhs) } else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) { @@ -479,6 +602,100 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) { } } +fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool { + if_chain! { + if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, _, ref args_a, _) = expr_a.kind; + if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, ref args_b, _) = expr_b.kind; + then { + return method_name_a.as_str() == method_name_b.as_str() && + args_a.len() == args_b.len() && + ( + ["ln", "log2", "log10"].contains(&&*method_name_a.as_str()) || + method_name_a.as_str() == "log" && args_a.len() == 2 && are_exprs_equal(cx, &args_a[1], &args_b[1]) + ); + } + } + + false +} + +fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) { + // check if expression of the form x.logN() / y.logN() + if_chain! { + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Div, .. + }, + lhs, + rhs, + ) = &expr.kind; + if are_same_base_logs(cx, lhs, rhs); + if let ExprKind::MethodCall(_, _, ref largs, _) = lhs.kind; + if let ExprKind::MethodCall(_, _, ref rargs, _) = rhs.kind; + then { + span_lint_and_sugg( + cx, + SUBOPTIMAL_FLOPS, + expr.span, + "log base can be expressed more clearly", + "consider using", + format!("{}.log({})", Sugg::hir(cx, &largs[0], ".."), Sugg::hir(cx, &rargs[0], ".."),), + Applicability::MachineApplicable, + ); + } + } +} + +fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { + if_chain! { + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Div, .. + }, + div_lhs, + div_rhs, + ) = &expr.kind; + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Mul, .. + }, + mul_lhs, + mul_rhs, + ) = &div_lhs.kind; + if let Some((rvalue, _)) = constant(cx, cx.tables(), div_rhs); + if let Some((lvalue, _)) = constant(cx, cx.tables(), mul_rhs); + then { + // TODO: also check for constant values near PI/180 or 180/PI + if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) && + (F32(180_f32) == lvalue || F64(180_f64) == lvalue) + { + span_lint_and_sugg( + cx, + SUBOPTIMAL_FLOPS, + expr.span, + "conversion to degrees can be done more accurately", + "consider using", + format!("{}.to_degrees()", Sugg::hir(cx, &mul_lhs, "..")), + Applicability::MachineApplicable, + ); + } else if + (F32(180_f32) == rvalue || F64(180_f64) == rvalue) && + (F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue) + { + span_lint_and_sugg( + cx, + SUBOPTIMAL_FLOPS, + expr.span, + "conversion to radians can be done more accurately", + "consider using", + format!("{}.to_radians()", Sugg::hir(cx, &mul_lhs, "..")), + Applicability::MachineApplicable, + ); + } + } + } +} + impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::MethodCall(ref path, _, args, _) = &expr.kind { @@ -489,6 +706,8 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic { "ln" => check_ln1p(cx, expr, args), "log" => check_log_base(cx, expr, args), "powf" => check_powf(cx, expr, args), + "powi" => check_powi(cx, expr, args), + "sqrt" => check_hypot(cx, expr, args), _ => {}, } } @@ -496,6 +715,8 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic { check_expm1(cx, expr); check_mul_add(cx, expr); check_custom_abs(cx, expr); + check_log_division(cx, expr); + check_radians(cx, expr); } } } diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs index 156246fb8bbb0..1bd16e6cce53a 100644 --- a/src/tools/clippy/clippy_lints/src/formatting.rs +++ b/src/tools/clippy/clippy_lints/src/formatting.rs @@ -305,18 +305,10 @@ fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) { } fn is_block(expr: &Expr) -> bool { - if let ExprKind::Block(..) = expr.kind { - true - } else { - false - } + matches!(expr.kind, ExprKind::Block(..)) } /// Check if the expression is an `if` or `if let` fn is_if(expr: &Expr) -> bool { - if let ExprKind::If(..) = expr.kind { - true - } else { - false - } + matches!(expr.kind, ExprKind::If(..)) } diff --git a/src/tools/clippy/clippy_lints/src/functions.rs b/src/tools/clippy/clippy_lints/src/functions.rs index 3f030dd84225b..63133a4872a3e 100644 --- a/src/tools/clippy/clippy_lints/src/functions.rs +++ b/src/tools/clippy/clippy_lints/src/functions.rs @@ -645,13 +645,7 @@ fn is_mutated_static(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool { use hir::ExprKind::{Field, Index, Path}; match e.kind { - Path(ref qpath) => { - if let Res::Local(_) = qpath_res(cx, qpath, e.hir_id) { - false - } else { - true - } - }, + Path(ref qpath) => !matches!(qpath_res(cx, qpath, e.hir_id), Res::Local(_)), Field(ref inner, _) | Index(ref inner, _) => is_mutated_static(cx, inner), _ => false, } diff --git a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs index f911cb68ea579..fbd2eeacc6ef5 100644 --- a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs +++ b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs @@ -135,13 +135,10 @@ impl<'tcx> Visitor<'tcx> for ArmVisitor<'_, 'tcx> { } } -impl<'tcx> ArmVisitor<'_, 'tcx> { +impl<'tcx, 'l> ArmVisitor<'tcx, 'l> { fn same_mutex(&self, cx: &LateContext<'_>, op_mutex: &Expr<'_>) -> bool { - if let Some(arm_mutex) = self.found_mutex { - SpanlessEq::new(cx).eq_expr(op_mutex, arm_mutex) - } else { - false - } + self.found_mutex + .map_or(false, |arm_mutex| SpanlessEq::new(cx).eq_expr(op_mutex, arm_mutex)) } } diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 26d96428771d6..1b09328ceabb0 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -302,16 +302,12 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let ty = &walk_ptrs_ty(cx.tables().expr_ty(expr)); match ty.kind { - ty::Dynamic(ref tt, ..) => { - if let Some(principal) = tt.principal() { - cx.tcx - .associated_items(principal.def_id()) - .in_definition_order() - .any(|item| is_is_empty(cx, &item)) - } else { - false - } - }, + ty::Dynamic(ref tt, ..) => tt.principal().map_or(false, |principal| { + cx.tcx + .associated_items(principal.def_id()) + .in_definition_order() + .any(|item| is_is_empty(cx, &item)) + }), ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id), ty::Adt(id, _) => has_is_empty_impl(cx, id.did), ty::Array(..) | ty::Slice(..) | ty::Str => true, diff --git a/src/tools/clippy/clippy_lints/src/let_and_return.rs b/src/tools/clippy/clippy_lints/src/let_and_return.rs index ddc41f89f8dec..fa560ffb980c8 100644 --- a/src/tools/clippy/clippy_lints/src/let_and_return.rs +++ b/src/tools/clippy/clippy_lints/src/let_and_return.rs @@ -1,6 +1,5 @@ use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{Block, Expr, ExprKind, PatKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -9,7 +8,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{in_macro, match_qpath, snippet_opt, span_lint_and_then}; +use crate::utils::{fn_def_id, in_macro, match_qpath, snippet_opt, span_lint_and_then}; declare_clippy_lint! { /// **What it does:** Checks for `let`-bindings, which are subsequently @@ -97,22 +96,6 @@ struct BorrowVisitor<'a, 'tcx> { borrows: bool, } -impl BorrowVisitor<'_, '_> { - fn fn_def_id(&self, expr: &Expr<'_>) -> Option { - match &expr.kind { - ExprKind::MethodCall(..) => self.cx.tables().type_dependent_def_id(expr.hir_id), - ExprKind::Call( - Expr { - kind: ExprKind::Path(qpath), - .. - }, - .., - ) => self.cx.qpath_res(qpath, expr.hir_id).opt_def_id(), - _ => None, - } - } -} - impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> { type Map = Map<'tcx>; @@ -121,7 +104,7 @@ impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> { return; } - if let Some(def_id) = self.fn_def_id(expr) { + if let Some(def_id) = fn_def_id(self.cx, expr) { self.borrows = self .cx .tcx diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 501220f28e5db..32e79317f8225 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -229,6 +229,7 @@ mod main_recursion; mod manual_async_fn; mod manual_non_exhaustive; mod map_clone; +mod map_identity; mod map_unit_fn; mod match_on_vec_items; mod matches; @@ -263,10 +264,12 @@ mod non_copy_const; mod non_expressive_names; mod open_options; mod option_env_unwrap; +mod option_if_let_else; mod overflow_check_conditional; mod panic_unimplemented; mod partialeq_ne_impl; mod path_buf_push_overwrite; +mod pattern_type_mismatch; mod precedence; mod ptr; mod ptr_offset_with_cast; @@ -274,11 +277,11 @@ mod question_mark; mod ranges; mod redundant_clone; mod redundant_field_names; -mod redundant_pattern_matching; mod redundant_pub_crate; mod redundant_static_lifetimes; mod reference; mod regex; +mod repeat_once; mod returns; mod serde_api; mod shadow; @@ -459,7 +462,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: ); store.register_removed( "clippy::replace_consts", - "associated-constants `MIN`/`MAX` of integers are prefer to `{min,max}_value()` and module constants", + "associated-constants `MIN`/`MAX` of integers are prefered to `{min,max}_value()` and module constants", + ); + store.register_removed( + "clippy::regex_macro", + "the regex! macro has been removed from the regex crate in 2018", ); // end deprecated lints, do not remove this comment, it’s used in `update_lints` @@ -473,6 +480,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &assign_ops::ASSIGN_OP_PATTERN, &assign_ops::MISREFACTORED_ASSIGN_OP, &atomic_ordering::INVALID_ATOMIC_ORDERING, + &attrs::BLANKET_CLIPPY_RESTRICTION_LINTS, &attrs::DEPRECATED_CFG_ATTR, &attrs::DEPRECATED_SEMVER, &attrs::EMPTY_LINE_AFTER_OUTER_ATTR, @@ -608,17 +616,20 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &manual_async_fn::MANUAL_ASYNC_FN, &manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, &map_clone::MAP_CLONE, + &map_identity::MAP_IDENTITY, &map_unit_fn::OPTION_MAP_UNIT_FN, &map_unit_fn::RESULT_MAP_UNIT_FN, &match_on_vec_items::MATCH_ON_VEC_ITEMS, &matches::INFALLIBLE_DESTRUCTURING_MATCH, &matches::MATCH_AS_REF, &matches::MATCH_BOOL, + &matches::MATCH_LIKE_MATCHES_MACRO, &matches::MATCH_OVERLAPPING_ARM, &matches::MATCH_REF_PATS, &matches::MATCH_SINGLE_BINDING, &matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS, &matches::MATCH_WILD_ERR_ARM, + &matches::REDUNDANT_PATTERN_MATCHING, &matches::REST_PAT_IN_FULLY_BOUND_STRUCTS, &matches::SINGLE_MATCH, &matches::SINGLE_MATCH_ELSE, @@ -726,6 +737,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &non_expressive_names::SIMILAR_NAMES, &open_options::NONSENSICAL_OPEN_OPTIONS, &option_env_unwrap::OPTION_ENV_UNWRAP, + &option_if_let_else::OPTION_IF_LET_ELSE, &overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, &panic_unimplemented::PANIC, &panic_unimplemented::PANIC_PARAMS, @@ -734,6 +746,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &panic_unimplemented::UNREACHABLE, &partialeq_ne_impl::PARTIALEQ_NE_IMPL, &path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE, + &pattern_type_mismatch::PATTERN_TYPE_MISMATCH, &precedence::PRECEDENCE, &ptr::CMP_NULL, &ptr::MUT_FROM_REF, @@ -746,14 +759,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &ranges::REVERSED_EMPTY_RANGES, &redundant_clone::REDUNDANT_CLONE, &redundant_field_names::REDUNDANT_FIELD_NAMES, - &redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING, &redundant_pub_crate::REDUNDANT_PUB_CRATE, &redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES, &reference::DEREF_ADDROF, &reference::REF_IN_DEREF, ®ex::INVALID_REGEX, - ®ex::REGEX_MACRO, ®ex::TRIVIAL_REGEX, + &repeat_once::REPEAT_ONCE, &returns::NEEDLESS_RETURN, &returns::UNUSED_UNIT, &serde_api::SERDE_API_MISUSE, @@ -946,7 +958,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box missing_doc::MissingDoc::new()); store.register_late_pass(|| box missing_inline::MissingInline); store.register_late_pass(|| box if_let_some_result::OkIfLet); - store.register_late_pass(|| box redundant_pattern_matching::RedundantPatternMatching); store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl); store.register_late_pass(|| box unused_io_amount::UnusedIoAmount); let enum_variant_size_threshold = conf.enum_variant_size_threshold; @@ -990,7 +1001,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box checked_conversions::CheckedConversions); store.register_late_pass(|| box integer_division::IntegerDivision); store.register_late_pass(|| box inherent_to_string::InherentToString); - store.register_late_pass(|| box trait_bounds::TraitBounds); + let max_trait_bounds = conf.max_trait_bounds; + store.register_late_pass(move || box trait_bounds::TraitBounds::new(max_trait_bounds)); store.register_late_pass(|| box comparison_chain::ComparisonChain); store.register_late_pass(|| box mut_key::MutableKeyType); store.register_late_pass(|| box modulo_arithmetic::ModuloArithmetic); @@ -1027,7 +1039,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: let array_size_threshold = conf.array_size_threshold; store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold)); store.register_late_pass(move || box large_const_arrays::LargeConstArrays::new(array_size_threshold)); - store.register_late_pass(move || box floating_point_arithmetic::FloatingPointArithmetic); + store.register_late_pass(|| box floating_point_arithmetic::FloatingPointArithmetic); store.register_early_pass(|| box as_conversions::AsConversions); store.register_early_pass(|| box utils::internal_lints::ProduceIce); store.register_late_pass(|| box let_underscore::LetUnderscore); @@ -1043,6 +1055,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default()); store.register_late_pass(|| box unnamed_address::UnnamedAddress); store.register_late_pass(|| box dereference::Dereferencing); + store.register_late_pass(|| box option_if_let_else::OptionIfLetElse); store.register_late_pass(|| box future_not_send::FutureNotSend); store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls); store.register_late_pass(|| box if_let_mutex::IfLetMutex); @@ -1057,6 +1070,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: }); store.register_early_pass(|| box unnested_or_patterns::UnnestedOrPatterns); store.register_late_pass(|| box macro_use::MacroUseImports::default()); + store.register_late_pass(|| box map_identity::MapIdentity); + store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch); + store.register_late_pass(|| box repeat_once::RepeatOnce); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1090,6 +1106,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&panic_unimplemented::TODO), LintId::of(&panic_unimplemented::UNIMPLEMENTED), LintId::of(&panic_unimplemented::UNREACHABLE), + LintId::of(&pattern_type_mismatch::PATTERN_TYPE_MISMATCH), LintId::of(&shadow::SHADOW_REUSE), LintId::of(&shadow::SHADOW_SAME), LintId::of(&strings::STRING_ADD), @@ -1146,6 +1163,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&needless_continue::NEEDLESS_CONTINUE), LintId::of(&needless_pass_by_value::NEEDLESS_PASS_BY_VALUE), LintId::of(&non_expressive_names::SIMILAR_NAMES), + LintId::of(&option_if_let_else::OPTION_IF_LET_ELSE), + LintId::of(&ranges::RANGE_MINUS_ONE), LintId::of(&ranges::RANGE_PLUS_ONE), LintId::of(&shadow::SHADOW_UNRELATED), LintId::of(&strings::STRING_ADD_ASSIGN), @@ -1186,6 +1205,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&assign_ops::ASSIGN_OP_PATTERN), LintId::of(&assign_ops::MISREFACTORED_ASSIGN_OP), LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING), + LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), LintId::of(&attrs::DEPRECATED_CFG_ATTR), LintId::of(&attrs::DEPRECATED_SEMVER), LintId::of(&attrs::MISMATCHED_TARGET_OS), @@ -1273,13 +1293,16 @@ 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(&map_clone::MAP_CLONE), + LintId::of(&map_identity::MAP_IDENTITY), LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN), LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN), LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH), LintId::of(&matches::MATCH_AS_REF), + LintId::of(&matches::MATCH_LIKE_MATCHES_MACRO), LintId::of(&matches::MATCH_OVERLAPPING_ARM), LintId::of(&matches::MATCH_REF_PATS), LintId::of(&matches::MATCH_SINGLE_BINDING), + LintId::of(&matches::REDUNDANT_PATTERN_MATCHING), LintId::of(&matches::SINGLE_MATCH), LintId::of(&matches::WILDCARD_IN_OR_PATTERNS), LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), @@ -1364,18 +1387,16 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&ptr::PTR_ARG), LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), LintId::of(&question_mark::QUESTION_MARK), - LintId::of(&ranges::RANGE_MINUS_ONE), LintId::of(&ranges::RANGE_ZIP_WITH_LEN), LintId::of(&ranges::REVERSED_EMPTY_RANGES), LintId::of(&redundant_clone::REDUNDANT_CLONE), LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES), - LintId::of(&redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING), LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), LintId::of(&reference::DEREF_ADDROF), LintId::of(&reference::REF_IN_DEREF), LintId::of(®ex::INVALID_REGEX), - LintId::of(®ex::REGEX_MACRO), LintId::of(®ex::TRIVIAL_REGEX), + LintId::of(&repeat_once::REPEAT_ONCE), LintId::of(&returns::NEEDLESS_RETURN), LintId::of(&returns::UNUSED_UNIT), LintId::of(&serde_api::SERDE_API_MISUSE), @@ -1437,6 +1458,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(&assertions_on_constants::ASSERTIONS_ON_CONSTANTS), LintId::of(&assign_ops::ASSIGN_OP_PATTERN), + LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS), LintId::of(&bit_mask::VERBOSE_BIT_MASK), LintId::of(&blacklisted_name::BLACKLISTED_NAME), @@ -1470,8 +1492,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), LintId::of(&map_clone::MAP_CLONE), LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH), + LintId::of(&matches::MATCH_LIKE_MATCHES_MACRO), LintId::of(&matches::MATCH_OVERLAPPING_ARM), LintId::of(&matches::MATCH_REF_PATS), + LintId::of(&matches::REDUNDANT_PATTERN_MATCHING), LintId::of(&matches::SINGLE_MATCH), LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE), LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT), @@ -1508,9 +1532,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&ptr::PTR_ARG), LintId::of(&question_mark::QUESTION_MARK), LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES), - LintId::of(&redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING), LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), - LintId::of(®ex::REGEX_MACRO), LintId::of(®ex::TRIVIAL_REGEX), LintId::of(&returns::NEEDLESS_RETURN), LintId::of(&returns::UNUSED_UNIT), @@ -1550,6 +1572,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&loops::EXPLICIT_COUNTER_LOOP), LintId::of(&loops::MUT_RANGE_BOUND), LintId::of(&loops::WHILE_LET_LOOP), + LintId::of(&map_identity::MAP_IDENTITY), LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN), LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN), LintId::of(&matches::MATCH_AS_REF), @@ -1580,10 +1603,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&partialeq_ne_impl::PARTIALEQ_NE_IMPL), LintId::of(&precedence::PRECEDENCE), LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), - LintId::of(&ranges::RANGE_MINUS_ONE), LintId::of(&ranges::RANGE_ZIP_WITH_LEN), LintId::of(&reference::DEREF_ADDROF), LintId::of(&reference::REF_IN_DEREF), + LintId::of(&repeat_once::REPEAT_ONCE), LintId::of(&swap::MANUAL_SWAP), LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT), LintId::of(&transmute::CROSSPOINTER_TRANSMUTE), diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index a79f94855bdab..168f9f953e4d8 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -129,10 +129,10 @@ fn check_fn_inner<'tcx>( } let mut bounds_lts = Vec::new(); - let types = generics.params.iter().filter(|param| match param.kind { - GenericParamKind::Type { .. } => true, - _ => false, - }); + let types = generics + .params + .iter() + .filter(|param| matches!(param.kind, GenericParamKind::Type { .. })); for typ in types { for bound in typ.bounds { let mut visitor = RefVisitor::new(cx); @@ -337,10 +337,10 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> { 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| match arg { - GenericArg::Lifetime(_) => true, - _ => false, - }) + && !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) { diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs index 7ba43562d7d44..a36fdca5d5de6 100644 --- a/src/tools/clippy/clippy_lints/src/literal_representation.rs +++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs @@ -264,10 +264,13 @@ impl LiteralDigitGrouping { let (part, mistyped_suffixes, missing_char) = if let Some((_, exponent)) = &mut num_lit.exponent { (exponent, &["32", "64"][..], 'f') - } else if let Some(fraction) = &mut num_lit.fraction { - (fraction, &["32", "64"][..], 'f') } else { - (&mut num_lit.integer, &["8", "16", "32", "64"][..], 'i') + num_lit + .fraction + .as_mut() + .map_or((&mut num_lit.integer, &["8", "16", "32", "64"][..], 'i'), |fraction| { + (fraction, &["32", "64"][..], 'f') + }) }; let mut split = part.rsplit('_'); diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs index d821b5134841e..396bb65910903 100644 --- a/src/tools/clippy/clippy_lints/src/loops.rs +++ b/src/tools/clippy/clippy_lints/src/loops.rs @@ -686,13 +686,9 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult { NeverLoopResult::AlwaysBreak } }, - ExprKind::Break(_, ref e) | ExprKind::Ret(ref e) => { - if let Some(ref e) = *e { - combine_seq(never_loop_expr(e, main_loop_id), NeverLoopResult::AlwaysBreak) - } else { - NeverLoopResult::AlwaysBreak - } - }, + ExprKind::Break(_, ref e) | ExprKind::Ret(ref e) => e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| { + combine_seq(never_loop_expr(e, main_loop_id), NeverLoopResult::AlwaysBreak) + }), ExprKind::InlineAsm(ref asm) => asm .operands .iter() @@ -1881,13 +1877,9 @@ fn is_ref_iterable_type(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { fn is_iterable_array<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool { // IntoIterator is currently only implemented for array sizes <= 32 in rustc match ty.kind { - ty::Array(_, n) => { - if let Some(val) = n.try_eval_usize(cx.tcx, cx.param_env) { - (0..=32).contains(&val) - } else { - false - } - }, + ty::Array(_, n) => n + .try_eval_usize(cx.tcx, cx.param_env) + .map_or(false, |val| (0..=32).contains(&val)), _ => false, } } @@ -1899,11 +1891,7 @@ fn extract_expr_from_first_stmt<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr< return None; } if let StmtKind::Local(ref local) = block.stmts[0].kind { - if let Some(expr) = local.init { - Some(expr) - } else { - None - } + local.init //.map(|expr| expr) } else { None } @@ -2023,15 +2011,13 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { if let PatKind::Binding(.., ident, _) = local.pat.kind { self.name = Some(ident.name); - self.state = if let Some(ref init) = local.init { + self.state = local.init.as_ref().map_or(VarState::Declared, |init| { if is_integer_const(&self.cx, init, 0) { VarState::Warn } else { VarState::Declared } - } else { - VarState::Declared - } + }) } } } @@ -2105,17 +2091,11 @@ fn var_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { } fn is_loop(expr: &Expr<'_>) -> bool { - match expr.kind { - ExprKind::Loop(..) => true, - _ => false, - } + matches!(expr.kind, ExprKind::Loop(..)) } fn is_conditional(expr: &Expr<'_>) -> bool { - match expr.kind { - ExprKind::Match(..) => true, - _ => false, - } + matches!(expr.kind, ExprKind::Match(..)) } fn is_nested(cx: &LateContext<'_>, match_expr: &Expr<'_>, iter_expr: &Expr<'_>) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/map_identity.rs b/src/tools/clippy/clippy_lints/src/map_identity.rs new file mode 100644 index 0000000000000..24ec78c884647 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/map_identity.rs @@ -0,0 +1,126 @@ +use crate::utils::{ + is_adjusted, is_type_diagnostic_item, match_path, match_trait_method, match_var, paths, remove_blocks, + span_lint_and_sugg, +}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Body, Expr, ExprKind, Pat, PatKind, QPath, StmtKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** Checks for instances of `map(f)` where `f` is the identity function. + /// + /// **Why is this bad?** It can be written more concisely without the call to `map`. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// let x = [1, 2, 3]; + /// let y: Vec<_> = x.iter().map(|x| x).map(|x| 2*x).collect(); + /// ``` + /// Use instead: + /// ```rust + /// let x = [1, 2, 3]; + /// let y: Vec<_> = x.iter().map(|x| 2*x).collect(); + /// ``` + pub MAP_IDENTITY, + complexity, + "using iterator.map(|x| x)" +} + +declare_lint_pass!(MapIdentity => [MAP_IDENTITY]); + +impl<'tcx> LateLintPass<'tcx> for MapIdentity { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if expr.span.from_expansion() { + return; + } + + if_chain! { + if let Some([caller, func]) = get_map_argument(cx, expr); + if is_expr_identity_function(cx, func); + then { + span_lint_and_sugg( + cx, + MAP_IDENTITY, + expr.span.trim_start(caller.span).unwrap(), + "unnecessary map of the identity function", + "remove the call to `map`", + String::new(), + Applicability::MachineApplicable + ) + } + } + } +} + +/// Returns the arguments passed into map() if the expression is a method call to +/// map(). Otherwise, returns None. +fn get_map_argument<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a [Expr<'a>]> { + if_chain! { + if let ExprKind::MethodCall(ref method, _, ref args, _) = expr.kind; + if args.len() == 2 && method.ident.as_str() == "map"; + let caller_ty = cx.tables().expr_ty(&args[0]); + if match_trait_method(cx, expr, &paths::ITERATOR) + || is_type_diagnostic_item(cx, caller_ty, sym!(result_type)) + || is_type_diagnostic_item(cx, caller_ty, sym!(option_type)); + then { + Some(args) + } else { + None + } + } +} + +/// Checks if an expression represents the identity function +/// Only examines closures and `std::convert::identity` +fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + match expr.kind { + ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)), + ExprKind::Path(QPath::Resolved(_, ref path)) => match_path(path, &paths::STD_CONVERT_IDENTITY), + _ => false, + } +} + +/// Checks if a function's body represents the identity function +/// Looks for bodies of the form `|x| x`, `|x| return x`, `|x| { return x }` or `|x| { +/// return x; }` +fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool { + let params = func.params; + let body = remove_blocks(&func.value); + + // if there's less/more than one parameter, then it is not the identity function + if params.len() != 1 { + return false; + } + + match body.kind { + ExprKind::Path(QPath::Resolved(None, _)) => match_expr_param(cx, body, params[0].pat), + ExprKind::Ret(Some(ref ret_val)) => match_expr_param(cx, ret_val, params[0].pat), + ExprKind::Block(ref block, _) => { + if_chain! { + if block.stmts.len() == 1; + if let StmtKind::Semi(ref expr) | StmtKind::Expr(ref expr) = block.stmts[0].kind; + if let ExprKind::Ret(Some(ref ret_val)) = expr.kind; + then { + match_expr_param(cx, ret_val, params[0].pat) + } else { + false + } + } + }, + _ => false, + } +} + +/// Returns true iff an expression returns the same thing as a parameter's pattern +fn match_expr_param(cx: &LateContext<'_>, expr: &Expr<'_>, pat: &Pat<'_>) -> bool { + if let PatKind::Binding(_, _, ident, _) = pat.kind { + match_var(expr, ident.name) && !(cx.tables().hir_owner == expr.hir_id.owner && is_adjusted(cx, expr)) + } else { + false + } +} diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs index b754a45aa404f..bd474c208070c 100644 --- a/src/tools/clippy/clippy_lints/src/matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches.rs @@ -13,14 +13,14 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::CtorKind; use rustc_hir::{ - Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Local, MatchSource, Mutability, Node, Pat, PatKind, - QPath, RangeEnd, + Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Guard, Local, MatchSource, Mutability, Node, Pat, + PatKind, QPath, RangeEnd, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::Span; +use rustc_span::source_map::{Span, Spanned}; use std::cmp::Ordering; use std::collections::Bound; @@ -409,6 +409,74 @@ declare_clippy_lint! { "a match on a struct that binds all fields but still uses the wildcard pattern" } +declare_clippy_lint! { + /// **What it does:** Lint for redundant pattern matching over `Result` or + /// `Option` + /// + /// **Why is this bad?** It's more concise and clear to just use the proper + /// utility function + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// if let Ok(_) = Ok::(42) {} + /// if let Err(_) = Err::(42) {} + /// if let None = None::<()> {} + /// if let Some(_) = Some(42) {} + /// match Ok::(42) { + /// Ok(_) => true, + /// Err(_) => false, + /// }; + /// ``` + /// + /// The more idiomatic use would be: + /// + /// ```rust + /// if Ok::(42).is_ok() {} + /// if Err::(42).is_err() {} + /// if None::<()>.is_none() {} + /// if Some(42).is_some() {} + /// Ok::(42).is_ok(); + /// ``` + pub REDUNDANT_PATTERN_MATCHING, + style, + "use the proper utility function avoiding an `if let`" +} + +declare_clippy_lint! { + /// **What it does:** Checks for `match` or `if let` expressions producing a + /// `bool` that could be written using `matches!` + /// + /// **Why is this bad?** Readability and needless complexity. + /// + /// **Known problems:** None + /// + /// **Example:** + /// ```rust + /// let x = Some(5); + /// + /// // Bad + /// let a = match x { + /// Some(0) => true, + /// _ => false, + /// }; + /// + /// let a = if let Some(0) = x { + /// true + /// } else { + /// false + /// }; + /// + /// // Good + /// let a = matches!(x, Some(0)); + /// ``` + pub MATCH_LIKE_MATCHES_MACRO, + style, + "a match that could be written with the matches! macro" +} + #[derive(Default)] pub struct Matches { infallible_destructuring_match_linted: bool, @@ -427,7 +495,9 @@ impl_lint_pass!(Matches => [ WILDCARD_IN_OR_PATTERNS, MATCH_SINGLE_BINDING, INFALLIBLE_DESTRUCTURING_MATCH, - REST_PAT_IN_FULLY_BOUND_STRUCTS + REST_PAT_IN_FULLY_BOUND_STRUCTS, + REDUNDANT_PATTERN_MATCHING, + MATCH_LIKE_MATCHES_MACRO ]); impl<'tcx> LateLintPass<'tcx> for Matches { @@ -435,6 +505,10 @@ impl<'tcx> LateLintPass<'tcx> for Matches { if in_external_macro(cx.sess(), expr.span) { return; } + + redundant_pattern_match::check(cx, expr); + check_match_like_matches(cx, expr); + if let ExprKind::Match(ref ex, ref arms, MatchSource::Normal) = expr.kind { check_single_match(cx, ex, arms, expr); check_match_bool(cx, ex, arms, expr); @@ -530,16 +604,22 @@ fn check_single_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp // the lint noisy in unnecessary situations return; } - let els = remove_blocks(&arms[1].body); - let els = if is_unit_expr(els) { + let els = arms[1].body; + let els = if is_unit_expr(remove_blocks(els)) { None - } else if let ExprKind::Block(_, _) = els.kind { - // matches with blocks that contain statements are prettier as `if let + else` - Some(els) + } else if let ExprKind::Block(Block { stmts, expr: block_expr, .. }, _) = els.kind { + if stmts.len() == 1 && block_expr.is_none() || stmts.is_empty() && block_expr.is_some() { + // single statement/expr "else" block, don't lint + return; + } else { + // block with 2+ statements or 1 expr and 1+ statement + Some(els) + } } else { - // allow match arms with just expressions - return; + // not a block, don't lint + return; }; + let ty = cx.tables().expr_ty(ex); if ty.kind != ty::Bool || is_allowed(cx, MATCH_BOOL, ex.hir_id) { check_single_match_single_pattern(cx, ex, arms, expr, els); @@ -802,13 +882,8 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) // Some simple checks for exhaustive patterns. // There is a room for improvements to detect more cases, // but it can be more expensive to do so. - let is_pattern_exhaustive = |pat: &&Pat<'_>| { - if let PatKind::Wild | PatKind::Binding(.., None) = pat.kind { - true - } else { - false - } - }; + let is_pattern_exhaustive = + |pat: &&Pat<'_>| matches!(pat.kind, PatKind::Wild | PatKind::Binding(.., None)); if patterns.iter().all(is_pattern_exhaustive) { missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id())); } @@ -989,6 +1064,79 @@ fn check_wild_in_or_pats(cx: &LateContext<'_>, arms: &[Arm<'_>]) { } } +/// Lint a `match` or `if let .. { .. } else { .. }` expr that could be replaced by `matches!` +fn check_match_like_matches<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if let ExprKind::Match(ex, arms, ref match_source) = &expr.kind { + match match_source { + MatchSource::Normal => find_matches_sugg(cx, ex, arms, expr, false), + MatchSource::IfLetDesugar { .. } => find_matches_sugg(cx, ex, arms, expr, true), + _ => return, + } + } +} + +/// Lint a `match` or desugared `if let` for replacement by `matches!` +fn find_matches_sugg(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>, desugared: bool) { + if_chain! { + if arms.len() == 2; + if cx.tables().expr_ty(expr).is_bool(); + if is_wild(&arms[1].pat); + if let Some(first) = find_bool_lit(&arms[0].body.kind, desugared); + if let Some(second) = find_bool_lit(&arms[1].body.kind, desugared); + if first != second; + then { + let mut applicability = Applicability::MachineApplicable; + + let pat_and_guard = if let Some(Guard::If(g)) = arms[0].guard { + format!("{} if {}", snippet_with_applicability(cx, arms[0].pat.span, "..", &mut applicability), snippet_with_applicability(cx, g.span, "..", &mut applicability)) + } else { + format!("{}", snippet_with_applicability(cx, arms[0].pat.span, "..", &mut applicability)) + }; + span_lint_and_sugg( + cx, + MATCH_LIKE_MATCHES_MACRO, + expr.span, + &format!("{} expression looks like `matches!` macro", if desugared { "if let .. else" } else { "match" }), + "try this", + format!( + "{}matches!({}, {})", + if first { "" } else { "!" }, + snippet_with_applicability(cx, ex.span, "..", &mut applicability), + pat_and_guard, + ), + applicability, + ) + } + } +} + +/// Extract a `bool` or `{ bool }` +fn find_bool_lit(ex: &ExprKind<'_>, desugared: bool) -> Option { + match ex { + ExprKind::Lit(Spanned { + node: LitKind::Bool(b), .. + }) => Some(*b), + ExprKind::Block( + rustc_hir::Block { + stmts: &[], + expr: Some(exp), + .. + }, + _, + ) if desugared => { + if let ExprKind::Lit(Spanned { + node: LitKind::Bool(b), .. + }) = exp.kind + { + Some(b) + } else { + None + } + }, + _ => None, + } +} + fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], expr: &Expr<'_>) { if in_macro(expr.span) || arms.len() != 1 || is_refutable(cx, arms[0].pat) { return; @@ -1179,10 +1327,7 @@ fn is_unit_expr(expr: &Expr<'_>) -> bool { // Checks if arm has the form `None => None` fn is_none_arm(arm: &Arm<'_>) -> bool { - match arm.pat.kind { - PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE) => true, - _ => false, - } + matches!(arm.pat.kind, PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE)) } // Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`) @@ -1293,6 +1438,229 @@ where None } +mod redundant_pattern_match { + use super::REDUNDANT_PATTERN_MATCHING; + use crate::utils::{in_constant, match_qpath, match_trait_method, paths, snippet, span_lint_and_then}; + use if_chain::if_chain; + use rustc_ast::ast::LitKind; + use rustc_errors::Applicability; + use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, PatKind, QPath}; + use rustc_lint::LateContext; + use rustc_middle::ty; + use rustc_mir::const_eval::is_const_fn; + use rustc_span::source_map::Symbol; + + pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if let ExprKind::Match(op, arms, ref match_source) = &expr.kind { + match match_source { + MatchSource::Normal => find_sugg_for_match(cx, expr, op, arms), + MatchSource::IfLetDesugar { .. } => find_sugg_for_if_let(cx, expr, op, arms, "if"), + MatchSource::WhileLetDesugar => find_sugg_for_if_let(cx, expr, op, arms, "while"), + _ => {}, + } + } + } + + fn find_sugg_for_if_let<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + op: &Expr<'_>, + arms: &[Arm<'_>], + keyword: &'static str, + ) { + fn find_suggestion(cx: &LateContext<'_>, hir_id: HirId, path: &QPath<'_>) -> Option<&'static str> { + if match_qpath(path, &paths::RESULT_OK) && can_suggest(cx, hir_id, sym!(result_type), "is_ok") { + return Some("is_ok()"); + } + if match_qpath(path, &paths::RESULT_ERR) && can_suggest(cx, hir_id, sym!(result_type), "is_err") { + return Some("is_err()"); + } + if match_qpath(path, &paths::OPTION_SOME) && can_suggest(cx, hir_id, sym!(option_type), "is_some") { + return Some("is_some()"); + } + if match_qpath(path, &paths::OPTION_NONE) && can_suggest(cx, hir_id, sym!(option_type), "is_none") { + return Some("is_none()"); + } + None + } + + let hir_id = expr.hir_id; + let good_method = match arms[0].pat.kind { + PatKind::TupleStruct(ref path, ref patterns, _) if patterns.len() == 1 => { + if let PatKind::Wild = patterns[0].kind { + find_suggestion(cx, hir_id, path) + } else { + None + } + }, + PatKind::Path(ref path) => find_suggestion(cx, hir_id, path), + _ => None, + }; + let good_method = match good_method { + Some(method) => method, + None => return, + }; + + // check that `while_let_on_iterator` lint does not trigger + if_chain! { + if keyword == "while"; + if let ExprKind::MethodCall(method_path, _, _, _) = op.kind; + if method_path.ident.name == sym!(next); + if match_trait_method(cx, op, &paths::ITERATOR); + then { + return; + } + } + + span_lint_and_then( + cx, + REDUNDANT_PATTERN_MATCHING, + arms[0].pat.span, + &format!("redundant pattern matching, consider using `{}`", good_method), + |diag| { + // while let ... = ... { ... } + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + let expr_span = expr.span; + + // while let ... = ... { ... } + // ^^^ + let op_span = op.span.source_callsite(); + + // while let ... = ... { ... } + // ^^^^^^^^^^^^^^^^^^^ + let span = expr_span.until(op_span.shrink_to_hi()); + diag.span_suggestion( + span, + "try this", + format!("{} {}.{}", keyword, snippet(cx, op_span, "_"), good_method), + Applicability::MachineApplicable, // snippet + ); + }, + ); + } + + fn find_sugg_for_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) { + if arms.len() == 2 { + let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind); + + let hir_id = expr.hir_id; + let found_good_method = match node_pair { + ( + PatKind::TupleStruct(ref path_left, ref patterns_left, _), + PatKind::TupleStruct(ref path_right, ref patterns_right, _), + ) if patterns_left.len() == 1 && patterns_right.len() == 1 => { + if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) { + find_good_method_for_match( + arms, + path_left, + path_right, + &paths::RESULT_OK, + &paths::RESULT_ERR, + "is_ok()", + "is_err()", + || can_suggest(cx, hir_id, sym!(result_type), "is_ok"), + || can_suggest(cx, hir_id, sym!(result_type), "is_err"), + ) + } else { + None + } + }, + (PatKind::TupleStruct(ref path_left, ref patterns, _), PatKind::Path(ref path_right)) + | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, ref patterns, _)) + if patterns.len() == 1 => + { + if let PatKind::Wild = patterns[0].kind { + find_good_method_for_match( + arms, + path_left, + path_right, + &paths::OPTION_SOME, + &paths::OPTION_NONE, + "is_some()", + "is_none()", + || can_suggest(cx, hir_id, sym!(option_type), "is_some"), + || can_suggest(cx, hir_id, sym!(option_type), "is_none"), + ) + } else { + None + } + }, + _ => None, + }; + + if let Some(good_method) = found_good_method { + span_lint_and_then( + cx, + REDUNDANT_PATTERN_MATCHING, + expr.span, + &format!("redundant pattern matching, consider using `{}`", good_method), + |diag| { + let span = expr.span.to(op.span); + diag.span_suggestion( + span, + "try this", + format!("{}.{}", snippet(cx, op.span, "_"), good_method), + Applicability::MaybeIncorrect, // snippet + ); + }, + ); + } + } + } + + #[allow(clippy::too_many_arguments)] + fn find_good_method_for_match<'a>( + arms: &[Arm<'_>], + path_left: &QPath<'_>, + path_right: &QPath<'_>, + expected_left: &[&str], + expected_right: &[&str], + should_be_left: &'a str, + should_be_right: &'a str, + can_suggest_left: impl Fn() -> bool, + can_suggest_right: impl Fn() -> bool, + ) -> Option<&'a str> { + let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) { + (&(*arms[0].body).kind, &(*arms[1].body).kind) + } else if match_qpath(path_right, expected_left) && match_qpath(path_left, expected_right) { + (&(*arms[1].body).kind, &(*arms[0].body).kind) + } else { + return None; + }; + + match body_node_pair { + (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) { + (LitKind::Bool(true), LitKind::Bool(false)) if can_suggest_left() => Some(should_be_left), + (LitKind::Bool(false), LitKind::Bool(true)) if can_suggest_right() => Some(should_be_right), + _ => None, + }, + _ => None, + } + } + + fn can_suggest(cx: &LateContext<'_>, hir_id: HirId, diag_item: Symbol, name: &str) -> bool { + if !in_constant(cx, hir_id) { + return true; + } + + // Avoid suggesting calls to non-`const fn`s in const contexts, see #5697. + cx.tcx + .get_diagnostic_item(diag_item) + .and_then(|def_id| { + cx.tcx.inherent_impls(def_id).iter().find_map(|imp| { + cx.tcx + .associated_items(*imp) + .in_definition_order() + .find_map(|item| match item.kind { + ty::AssocKind::Fn if item.ident.name.as_str() == name => Some(item.def_id), + _ => None, + }) + }) + }) + .map_or(false, |def_id| is_const_fn(cx.tcx, def_id)) + } +} + #[test] fn test_overlapping() { use rustc_span::source_map::DUMMY_SP; diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 216db12f0115f..4c595029ff7bc 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -1844,10 +1844,10 @@ fn lint_expect_fun_call( ty::Ref(ty::ReStatic, ..) ) }), - hir::ExprKind::Path(ref p) => match cx.qpath_res(p, arg.hir_id) { - hir::def::Res::Def(hir::def::DefKind::Const | hir::def::DefKind::Static, _) => true, - _ => false, - }, + hir::ExprKind::Path(ref p) => matches!( + cx.qpath_res(p, arg.hir_id), + hir::def::Res::Def(hir::def::DefKind::Const | hir::def::DefKind::Static, _) + ), _ => false, } } @@ -2028,13 +2028,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp .tables() .expr_adjustments(arg) .iter() - .filter(|adj| { - if let ty::adjustment::Adjust::Deref(_) = adj.kind { - true - } else { - false - } - }) + .filter(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(_))) .count(); let derefs: String = iter::repeat('*').take(deref_count).collect(); snip = Some(("try dereferencing it", format!("{}{}", derefs, snippet))); @@ -2044,7 +2038,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp } span_lint_and_then(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type", |diag| { if let Some((text, snip)) = snip { - diag.span_suggestion(expr.span, text, snip, Applicability::Unspecified); + diag.span_suggestion(expr.span, text, snip, Applicability::MachineApplicable); } }); } @@ -2460,13 +2454,9 @@ fn derefs_to_slice<'tcx>( ty::Slice(_) => true, ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()), ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym!(vec_type)), - ty::Array(_, size) => { - if let Some(size) = size.try_eval_usize(cx.tcx, cx.param_env) { - size < 32 - } else { - false - } - }, + ty::Array(_, size) => size + .try_eval_usize(cx.tcx, cx.param_env) + .map_or(false, |size| size < 32), ty::Ref(_, inner, _) => may_slice(cx, inner), _ => false, } diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs index fdcba11054288..75e123eb5939d 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -77,13 +77,10 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc } (true, true) }, - hir::ExprKind::Block(ref block, _) => { - if let Some(expr) = &block.expr { - check_expression(cx, arg_id, &expr) - } else { - (false, false) - } - }, + hir::ExprKind::Block(ref block, _) => block + .expr + .as_ref() + .map_or((false, false), |expr| check_expression(cx, arg_id, &expr)), hir::ExprKind::Match(_, arms, _) => { let mut found_mapping = false; let mut found_filtering = false; diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs index 0a2d577396a5f..c8aa98d348927 100644 --- a/src/tools/clippy/clippy_lints/src/minmax.rs +++ b/src/tools/clippy/clippy_lints/src/minmax.rs @@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for MinMaxPass { } } -#[derive(PartialEq, Eq, Debug)] +#[derive(PartialEq, Eq, Debug, Clone, Copy)] enum MinMax { Min, Max, @@ -86,16 +86,15 @@ fn fetch_const<'a>(cx: &LateContext<'_>, args: &'a [Expr<'a>], m: MinMax) -> Opt if args.len() != 2 { return None; } - if let Some(c) = constant_simple(cx, cx.tables(), &args[0]) { - if constant_simple(cx, cx.tables(), &args[1]).is_none() { - // otherwise ignore - Some((m, c, &args[1])) - } else { - None - } - } else if let Some(c) = constant_simple(cx, cx.tables(), &args[1]) { - Some((m, c, &args[0])) - } else { - None - } + constant_simple(cx, cx.tables(), &args[0]).map_or_else( + || constant_simple(cx, cx.tables(), &args[1]).map(|c| (m, c, &args[0])), + |c| { + if constant_simple(cx, cx.tables(), &args[1]).is_none() { + // otherwise ignore + Some((m, c, &args[1])) + } else { + None + } + }, + ) } diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index d7e1a62a19d52..400f4b609af7f 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -3,11 +3,11 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - def, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, Stmt, StmtKind, Ty, - TyKind, UnOp, + self as hir, def, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, Stmt, + StmtKind, TyKind, UnOp, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::{ExpnKind, Span}; @@ -371,8 +371,8 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { if op.is_comparison() { check_nan(cx, left, expr); check_nan(cx, right, expr); - check_to_owned(cx, left, right); - check_to_owned(cx, right, left); + check_to_owned(cx, left, right, true); + check_to_owned(cx, right, left, false); } if (op == BinOpKind::Eq || op == BinOpKind::Ne) && (is_float(cx, left) || is_float(cx, right)) { if is_allowed(cx, left) || is_allowed(cx, right) { @@ -570,11 +570,30 @@ fn is_array(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { matches!(&walk_ptrs_ty(cx.tables().expr_ty(expr)).kind, ty::Array(_, _)) } -fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>) { +fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) { + #[derive(Default)] + struct EqImpl { + ty_eq_other: bool, + other_eq_ty: bool, + } + + impl EqImpl { + fn is_implemented(&self) -> bool { + self.ty_eq_other || self.other_eq_ty + } + } + + fn symmetric_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx>) -> Option { + cx.tcx.lang_items().eq_trait().map(|def_id| EqImpl { + ty_eq_other: implements_trait(cx, ty, def_id, &[other.into()]), + other_eq_ty: implements_trait(cx, other, def_id, &[ty.into()]), + }) + } + let (arg_ty, snip) = match expr.kind { ExprKind::MethodCall(.., ref args, _) if args.len() == 1 => { if match_trait_method(cx, expr, &paths::TO_STRING) || match_trait_method(cx, expr, &paths::TO_OWNED) { - (cx.tables().expr_ty_adjusted(&args[0]), snippet(cx, args[0].span, "..")) + (cx.tables().expr_ty(&args[0]), snippet(cx, args[0].span, "..")) } else { return; } @@ -582,7 +601,7 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>) { ExprKind::Call(ref path, ref v) if v.len() == 1 => { if let ExprKind::Path(ref path) = path.kind { if match_qpath(path, &["String", "from_str"]) || match_qpath(path, &["String", "from"]) { - (cx.tables().expr_ty_adjusted(&v[0]), snippet(cx, v[0].span, "..")) + (cx.tables().expr_ty(&v[0]), snippet(cx, v[0].span, "..")) } else { return; } @@ -593,28 +612,19 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>) { _ => return, }; - let other_ty = cx.tables().expr_ty_adjusted(other); - let partial_eq_trait_id = match cx.tcx.lang_items().eq_trait() { - Some(id) => id, - None => return, - }; + let other_ty = cx.tables().expr_ty(other); - let deref_arg_impl_partial_eq_other = arg_ty.builtin_deref(true).map_or(false, |tam| { - implements_trait(cx, tam.ty, partial_eq_trait_id, &[other_ty.into()]) - }); - let arg_impl_partial_eq_deref_other = other_ty.builtin_deref(true).map_or(false, |tam| { - implements_trait(cx, arg_ty, partial_eq_trait_id, &[tam.ty.into()]) - }); - let arg_impl_partial_eq_other = implements_trait(cx, arg_ty, partial_eq_trait_id, &[other_ty.into()]); + let without_deref = symmetric_partial_eq(cx, arg_ty, other_ty).unwrap_or_default(); + let with_deref = arg_ty + .builtin_deref(true) + .and_then(|tam| symmetric_partial_eq(cx, tam.ty, other_ty)) + .unwrap_or_default(); - if !deref_arg_impl_partial_eq_other && !arg_impl_partial_eq_deref_other && !arg_impl_partial_eq_other { + if !with_deref.is_implemented() && !without_deref.is_implemented() { return; } - let other_gets_derefed = match other.kind { - ExprKind::Unary(UnOp::UnDeref, _) => true, - _ => false, - }; + let other_gets_derefed = matches!(other.kind, ExprKind::Unary(UnOp::UnDeref, _)); let lint_span = if other_gets_derefed { expr.span.to(other.span) @@ -634,18 +644,34 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>) { return; } - let try_hint = if deref_arg_impl_partial_eq_other { - // suggest deref on the left - format!("*{}", snip) + let expr_snip; + let eq_impl; + if with_deref.is_implemented() { + expr_snip = format!("*{}", snip); + eq_impl = with_deref; } else { - // suggest dropping the to_owned on the left - snip.to_string() + expr_snip = snip.to_string(); + eq_impl = without_deref; }; + let span; + let hint; + if (eq_impl.ty_eq_other && left) || (eq_impl.other_eq_ty && !left) { + span = expr.span; + hint = expr_snip; + } else { + span = expr.span.to(other.span); + if eq_impl.ty_eq_other { + hint = format!("{} == {}", expr_snip, snippet(cx, other.span, "..")); + } else { + hint = format!("{} == {}", snippet(cx, other.span, ".."), expr_snip); + } + } + diag.span_suggestion( - lint_span, + span, "try", - try_hint, + hint, Applicability::MachineApplicable, // snippet ); }, @@ -656,16 +682,10 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>) { /// `unused_variables`'s idea /// of what it means for an expression to be "used". fn is_used(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - if let Some(parent) = get_parent_expr(cx, expr) { - match parent.kind { - ExprKind::Assign(_, ref rhs, _) | ExprKind::AssignOp(_, _, ref rhs) => { - SpanlessEq::new(cx).eq_expr(rhs, expr) - }, - _ => is_used(cx, parent), - } - } else { - true - } + get_parent_expr(cx, expr).map_or(true, |parent| match parent.kind { + ExprKind::Assign(_, ref rhs, _) | ExprKind::AssignOp(_, _, ref rhs) => SpanlessEq::new(cx).eq_expr(rhs, expr), + _ => is_used(cx, parent), + }) } /// Tests whether an expression is in a macro expansion (e.g., something @@ -674,12 +694,7 @@ fn in_attributes_expansion(expr: &Expr<'_>) -> bool { use rustc_span::hygiene::MacroKind; if expr.span.from_expansion() { let data = expr.span.ctxt().outer_expn_data(); - - if let ExpnKind::Macro(MacroKind::Attr, _) = data.kind { - true - } else { - false - } + matches!(data.kind, ExpnKind::Macro(MacroKind::Attr, _)) } else { false } @@ -694,7 +709,7 @@ fn non_macro_local(cx: &LateContext<'_>, res: def::Res) -> bool { } } -fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &Ty<'_>) { +fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>) { if_chain! { if let TyKind::Ptr(ref mut_ty) = ty.kind; if let ExprKind::Lit(ref lit) = e.kind; diff --git a/src/tools/clippy/clippy_lints/src/misc_early.rs b/src/tools/clippy/clippy_lints/src/misc_early.rs index ad39e59d0678a..b84a1a3fe2494 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early.rs @@ -641,28 +641,22 @@ fn check_unneeded_wildcard_pattern(cx: &EarlyContext<'_>, pat: &Pat) { ); } - #[allow(clippy::trivially_copy_pass_by_ref)] - fn is_wild>(pat: &&P) -> bool { - if let PatKind::Wild = pat.kind { - true - } else { - false - } - } - if let Some(rest_index) = patterns.iter().position(|pat| pat.is_rest()) { if let Some((left_index, left_pat)) = patterns[..rest_index] .iter() .rev() - .take_while(is_wild) + .take_while(|pat| matches!(pat.kind, PatKind::Wild)) .enumerate() .last() { span_lint(cx, left_pat.span.until(patterns[rest_index].span), left_index == 0); } - if let Some((right_index, right_pat)) = - patterns[rest_index + 1..].iter().take_while(is_wild).enumerate().last() + if let Some((right_index, right_pat)) = patterns[rest_index + 1..] + .iter() + .take_while(|pat| matches!(pat.kind, PatKind::Wild)) + .enumerate() + .last() { span_lint( cx, diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index bf80b62afe6e0..9c96267353701 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -71,10 +71,11 @@ fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[ast::Attribute], sp fn is_executable(cx: &LateContext<'_>) -> bool { use rustc_session::config::CrateType; - cx.tcx.sess.crate_types().iter().any(|t: &CrateType| match t { - CrateType::Executable => true, - _ => false, - }) + cx.tcx + .sess + .crate_types() + .iter() + .any(|t: &CrateType| matches!(t, CrateType::Executable)) } declare_lint_pass!(MissingInline => [MISSING_INLINE_IN_PUBLIC_ITEMS]); diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs index 2597f5f6f17e2..621ebdef2f0b1 100644 --- a/src/tools/clippy/clippy_lints/src/new_without_default.rs +++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs @@ -80,10 +80,12 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { // can't be implemented for unsafe new return; } - if impl_item.generics.params.iter().any(|gen| match gen.kind { - hir::GenericParamKind::Type { .. } => true, - _ => false, - }) { + if impl_item + .generics + .params + .iter() + .any(|gen| matches!(gen.kind, hir::GenericParamKind::Type { .. })) + { // when the result of `new()` depends on a type parameter we should not require // an // impl of `Default` diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index c11a2ff9ee07e..a3521c31a6be6 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -238,10 +238,10 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { let ty = if needs_check_adjustment { let adjustments = cx.tables().expr_adjustments(dereferenced_expr); - if let Some(i) = adjustments.iter().position(|adj| match adj.kind { - Adjust::Borrow(_) | Adjust::Deref(_) => true, - _ => false, - }) { + if let Some(i) = adjustments + .iter() + .position(|adj| matches!(adj.kind, Adjust::Borrow(_) | Adjust::Deref(_))) + { if i == 0 { cx.tables().expr_ty(dereferenced_expr) } else { diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs new file mode 100644 index 0000000000000..8dbe58763bfb2 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs @@ -0,0 +1,267 @@ +use crate::utils; +use crate::utils::sugg::Sugg; +use crate::utils::{match_type, 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! { + /// **What it does:** + /// 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 simple + /// expression) or `Option::map_or_else` (if the else bit is a longer + /// block). + /// + /// **Why is this bad?** + /// Using the dedicated functions of the Option type is clearer and + /// more concise than an if let expression. + /// + /// **Known problems:** + /// This lint uses whether the block is just an expression or if it has + /// more statements to decide whether to use `Option::map_or` or + /// `Option::map_or_else`. If you have a single expression which calls + /// an expensive function, then it would be more efficient to use + /// `Option::map_or_else`, but this lint would suggest `Option::map_or`. + /// + /// Also, this lint uses a deliberately conservative metric for checking + /// if the inside of either body contains breaks or continues which will + /// cause it to not suggest a fix if either block contains a loop with + /// continues or breaks contained within the loop. + /// + /// **Example:** + /// + /// ```rust + /// # let optional: Option = Some(0); + /// # fn do_complicated_function() -> u32 { 5 }; + /// let _ = if let Some(foo) = optional { + /// foo + /// } else { + /// 5 + /// }; + /// let _ = if let Some(foo) = optional { + /// foo + /// } else { + /// let y = do_complicated_function(); + /// y*y + /// }; + /// ``` + /// + /// should be + /// + /// ```rust + /// # let optional: Option = Some(0); + /// # fn do_complicated_function() -> u32 { 5 }; + /// let _ = optional.map_or(5, |foo| foo); + /// let _ = optional.map_or_else(||{ + /// let y = do_complicated_function(); + /// y*y + /// }, |foo| foo); + /// ``` + pub OPTION_IF_LET_ELSE, + pedantic, + "reimplementation of Option::map_or" +} + +declare_lint_pass!(OptionIfLetElse => [OPTION_IF_LET_ELSE]); + +/// Returns true iff the given expression is the result of calling `Result::ok` +fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool { + if let ExprKind::MethodCall(ref path, _, &[ref receiver], _) = &expr.kind { + path.ident.name.to_ident_string() == "ok" && match_type(cx, &cx.tables().expr_ty(&receiver), &paths::RESULT) + } else { + false + } +} + +/// A struct containing information about occurences of the +/// `if let Some(..) = .. else` construct that this lint detects. +struct OptionIfLetElseOccurence { + option: String, + method_sugg: String, + some_expr: String, + none_expr: String, + 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>> { + if let ExprKind::Block( + Block { + stmts: statements, + expr: Some(expr), + .. + }, + _, + ) = &arm.body.kind + { + if let [] = statements { + Some(&expr) + } else { + Some(&arm.body) + } + } else { + None + } +} + +/// If this is the else body of an if/else expression, then we need to wrap +/// it in curcly braces. Otherwise, we don't. +fn should_wrap_in_braces(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + utils::get_enclosing_block(cx, expr.hir_id).map_or(false, |parent| { + if let Some(Expr { + kind: + ExprKind::Match( + _, + arms, + MatchSource::IfDesugar { + contains_else_clause: true, + } + | MatchSource::IfLetDesugar { + contains_else_clause: true, + }, + ), + .. + }) = parent.expr + { + expr.hir_id == arms[1].body.hir_id + } else { + false + } + }) +} + +fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: bool, as_mut: bool) -> String { + format!( + "{}{}", + Sugg::hir(cx, cond_expr, "..").maybe_par(), + if as_mut { + ".as_mut()" + } else if as_ref { + ".as_ref()" + } else { + "" + } + ) +} + +/// If this expression is the option if let/else construct we're detecting, then +/// this function returns an `OptionIfLetElseOccurence` struct with details if +/// this construct is found, or None if this construct is not found. +fn detect_option_if_let_else(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { + if_chain! { + if !utils::in_macro(expr.span); // Don't lint macros, because it behaves weirdly + if let ExprKind::Match(cond_expr, arms, MatchSource::IfLetDesugar{contains_else_clause: true}) = &expr.kind; + if arms.len() == 2; + if !is_result_ok(cx, cond_expr); // Don't lint on Result::ok because a different lint does it already + 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); + then { + let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" }; + let some_body = extract_body_from_arm(&arms[0])?; + let none_body = extract_body_from_arm(&arms[1])?; + let method_sugg = match &none_body.kind { + ExprKind::Block(..) => "map_or_else", + _ => "map_or", + }; + let capture_name = id.name.to_ident_string(); + let wrap_braces = should_wrap_in_braces(cx, expr); + let (as_ref, as_mut) = match &cond_expr.kind { + ExprKind::AddrOf(_, Mutability::Not, _) => (true, false), + ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true), + _ => (bind_annotation == &BindingAnnotation::Ref, bind_annotation == &BindingAnnotation::RefMut), + }; + let cond_expr = match &cond_expr.kind { + // Pointer dereferencing happens automatically, so we can omit it in the suggestion + ExprKind::Unary(UnOp::UnDeref, expr) | ExprKind::AddrOf(_, _, expr) => expr, + _ => cond_expr, + }; + Some(OptionIfLetElseOccurence { + option: format_option_in_sugg(cx, cond_expr, as_ref, as_mut), + method_sugg: method_sugg.to_string(), + some_expr: format!("|{}{}| {}", capture_mut, capture_name, Sugg::hir(cx, some_body, "..")), + none_expr: format!("{}{}", if method_sugg == "map_or" { "" } else { "|| " }, Sugg::hir(cx, none_body, "..")), + wrap_braces, + }) + } else { + None + } + } +} + +impl<'a> LateLintPass<'a> for OptionIfLetElse { + fn check_expr(&mut self, cx: &LateContext<'a>, expr: &Expr<'_>) { + if let Some(detection) = detect_option_if_let_else(cx, expr) { + span_lint_and_sugg( + cx, + OPTION_IF_LET_ELSE, + expr.span, + format!("use Option::{} instead of an if let/else", detection.method_sugg).as_str(), + "try", + format!( + "{}{}.{}({}, {}){}", + if detection.wrap_braces { "{ " } else { "" }, + detection.option, + detection.method_sugg, + detection.none_expr, + detection.some_expr, + if detection.wrap_braces { " }" } else { "" }, + ), + Applicability::MaybeIncorrect, + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs new file mode 100644 index 0000000000000..a49dc87c0b47f --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs @@ -0,0 +1,311 @@ +use crate::utils::{last_path_segment, span_lint_and_help}; +use rustc_hir::{ + intravisit, Body, Expr, ExprKind, FieldPat, FnDecl, HirId, LocalSource, MatchSource, Mutability, Pat, PatKind, + QPath, Stmt, StmtKind, +}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::{AdtDef, FieldDef, Ty, TyKind, VariantDef}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::source_map::Span; + +declare_clippy_lint! { + /// **What it does:** Checks for patterns that aren't exact representations of the types + /// they are applied to. + /// + /// To satisfy this lint, you will have to adjust either the expression that is matched + /// against or the pattern itself, as well as the bindings that are introduced by the + /// adjusted patterns. For matching you will have to either dereference the expression + /// with the `*` operator, or amend the patterns to explicitly match against `&` + /// or `&mut ` depending on the reference mutability. For the bindings you need + /// to use the inverse. You can leave them as plain bindings if you wish for the value + /// to be copied, but you must use `ref mut ` or `ref ` to construct + /// a reference into the matched structure. + /// + /// If you are looking for a way to learn about ownership semantics in more detail, it + /// is recommended to look at IDE options available to you to highlight types, lifetimes + /// and reference semantics in your code. The available tooling would expose these things + /// in a general way even outside of the various pattern matching mechanics. Of course + /// this lint can still be used to highlight areas of interest and ensure a good understanding + /// of ownership semantics. + /// + /// **Why is this bad?** It isn't bad in general. But in some contexts it can be desirable + /// because it increases ownership hints in the code, and will guard against some changes + /// in ownership. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// This example shows the basic adjustments necessary to satisfy the lint. Note how + /// the matched expression is explicitly dereferenced with `*` and the `inner` variable + /// is bound to a shared borrow via `ref inner`. + /// + /// ```rust,ignore + /// // Bad + /// let value = &Some(Box::new(23)); + /// match value { + /// Some(inner) => println!("{}", inner), + /// None => println!("none"), + /// } + /// + /// // Good + /// let value = &Some(Box::new(23)); + /// match *value { + /// Some(ref inner) => println!("{}", inner), + /// None => println!("none"), + /// } + /// ``` + /// + /// The following example demonstrates one of the advantages of the more verbose style. + /// Note how the second version uses `ref mut a` to explicitly declare `a` a shared mutable + /// borrow, while `b` is simply taken by value. This ensures that the loop body cannot + /// accidentally modify the wrong part of the structure. + /// + /// ```rust,ignore + /// // Bad + /// let mut values = vec![(2, 3), (3, 4)]; + /// for (a, b) in &mut values { + /// *a += *b; + /// } + /// + /// // Good + /// let mut values = vec![(2, 3), (3, 4)]; + /// for &mut (ref mut a, b) in &mut values { + /// *a += b; + /// } + /// ``` + pub PATTERN_TYPE_MISMATCH, + restriction, + "type of pattern does not match the expression type" +} + +declare_lint_pass!(PatternTypeMismatch => [PATTERN_TYPE_MISMATCH]); + +impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch { + fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { + if let StmtKind::Local(ref local) = stmt.kind { + if let Some(init) = &local.init { + if let Some(init_ty) = cx.tables().node_type_opt(init.hir_id) { + let pat = &local.pat; + if in_external_macro(cx.sess(), pat.span) { + return; + } + let deref_possible = match local.source { + LocalSource::Normal => DerefPossible::Possible, + _ => DerefPossible::Impossible, + }; + apply_lint(cx, pat, init_ty, deref_possible); + } + } + } + } + + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if let ExprKind::Match(ref expr, arms, source) = expr.kind { + match source { + MatchSource::Normal | MatchSource::IfLetDesugar { .. } | MatchSource::WhileLetDesugar => { + if let Some(expr_ty) = cx.tables().node_type_opt(expr.hir_id) { + 'pattern_checks: for arm in arms { + let pat = &arm.pat; + if in_external_macro(cx.sess(), pat.span) { + continue 'pattern_checks; + } + if apply_lint(cx, pat, expr_ty, DerefPossible::Possible) { + break 'pattern_checks; + } + } + } + }, + _ => (), + } + } + } + + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + _: intravisit::FnKind<'tcx>, + _: &'tcx FnDecl<'_>, + body: &'tcx Body<'_>, + _: Span, + hir_id: HirId, + ) { + if let Some(fn_sig) = cx.tables().liberated_fn_sigs().get(hir_id) { + for (param, ty) in body.params.iter().zip(fn_sig.inputs().iter()) { + apply_lint(cx, ¶m.pat, ty, DerefPossible::Impossible); + } + } + } +} + +#[derive(Debug, Clone, Copy)] +enum DerefPossible { + Possible, + Impossible, +} + +fn apply_lint<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, expr_ty: Ty<'tcx>, deref_possible: DerefPossible) -> bool { + let maybe_mismatch = find_first_mismatch(cx, pat, expr_ty, Level::Top); + if let Some((span, mutability, level)) = maybe_mismatch { + span_lint_and_help( + cx, + PATTERN_TYPE_MISMATCH, + span, + "type of pattern does not match the expression type", + None, + &format!( + "{}explicitly match against a `{}` pattern and adjust the enclosed variable bindings", + match (deref_possible, level) { + (DerefPossible::Possible, Level::Top) => "use `*` to dereference the match expression or ", + _ => "", + }, + match mutability { + Mutability::Mut => "&mut _", + Mutability::Not => "&_", + }, + ), + ); + true + } else { + false + } +} + +#[derive(Debug, Copy, Clone)] +enum Level { + Top, + Lower, +} + +#[allow(rustc::usage_of_ty_tykind)] +fn find_first_mismatch<'tcx>( + cx: &LateContext<'tcx>, + pat: &Pat<'_>, + ty: Ty<'tcx>, + level: Level, +) -> Option<(Span, Mutability, Level)> { + if let PatKind::Ref(ref sub_pat, _) = pat.kind { + if let TyKind::Ref(_, sub_ty, _) = ty.kind { + return find_first_mismatch(cx, sub_pat, sub_ty, Level::Lower); + } + } + + if let TyKind::Ref(_, _, mutability) = ty.kind { + if is_non_ref_pattern(&pat.kind) { + return Some((pat.span, mutability, level)); + } + } + + if let PatKind::Struct(ref qpath, ref field_pats, _) = pat.kind { + if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind { + if let Some(variant) = get_variant(adt_def, qpath) { + let field_defs = &variant.fields; + return find_first_mismatch_in_struct(cx, field_pats, field_defs, substs_ref); + } + } + } + + if let PatKind::TupleStruct(ref qpath, ref pats, _) = pat.kind { + if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind { + if let Some(variant) = get_variant(adt_def, qpath) { + let field_defs = &variant.fields; + let ty_iter = field_defs.iter().map(|field_def| field_def.ty(cx.tcx, substs_ref)); + return find_first_mismatch_in_tuple(cx, pats, ty_iter); + } + } + } + + if let PatKind::Tuple(ref pats, _) = pat.kind { + if let TyKind::Tuple(..) = ty.kind { + return find_first_mismatch_in_tuple(cx, pats, ty.tuple_fields()); + } + } + + if let PatKind::Or(sub_pats) = pat.kind { + for pat in sub_pats { + let maybe_mismatch = find_first_mismatch(cx, pat, ty, level); + if let Some(mismatch) = maybe_mismatch { + return Some(mismatch); + } + } + } + + None +} + +fn get_variant<'a>(adt_def: &'a AdtDef, qpath: &QPath<'_>) -> Option<&'a VariantDef> { + if adt_def.is_struct() { + if let Some(variant) = adt_def.variants.iter().next() { + return Some(variant); + } + } + + if adt_def.is_enum() { + let pat_ident = last_path_segment(qpath).ident; + for variant in &adt_def.variants { + if variant.ident == pat_ident { + return Some(variant); + } + } + } + + None +} + +fn find_first_mismatch_in_tuple<'tcx, I>( + cx: &LateContext<'tcx>, + pats: &[&Pat<'_>], + ty_iter_src: I, +) -> Option<(Span, Mutability, Level)> +where + I: IntoIterator>, +{ + let mut field_tys = ty_iter_src.into_iter(); + 'fields: for pat in pats { + let field_ty = if let Some(ty) = field_tys.next() { + ty + } else { + break 'fields; + }; + + let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower); + if let Some(mismatch) = maybe_mismatch { + return Some(mismatch); + } + } + + None +} + +fn find_first_mismatch_in_struct<'tcx>( + cx: &LateContext<'tcx>, + field_pats: &[FieldPat<'_>], + field_defs: &[FieldDef], + substs_ref: SubstsRef<'tcx>, +) -> Option<(Span, Mutability, Level)> { + for field_pat in field_pats { + 'definitions: for field_def in field_defs { + if field_pat.ident == field_def.ident { + let field_ty = field_def.ty(cx.tcx, substs_ref); + let pat = &field_pat.pat; + let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower); + if let Some(mismatch) = maybe_mismatch { + return Some(mismatch); + } + break 'definitions; + } + } + } + + None +} + +fn is_non_ref_pattern(pat_kind: &PatKind<'_>) -> bool { + match pat_kind { + PatKind::Struct(..) | PatKind::Tuple(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => true, + PatKind::Or(sub_pats) => sub_pats.iter().any(|pat| is_non_ref_pattern(&pat.kind)), + _ => false, + } +} diff --git a/src/tools/clippy/clippy_lints/src/precedence.rs b/src/tools/clippy/clippy_lints/src/precedence.rs index 23793678fa0e2..4797771e7bdbb 100644 --- a/src/tools/clippy/clippy_lints/src/precedence.rs +++ b/src/tools/clippy/clippy_lints/src/precedence.rs @@ -148,17 +148,11 @@ fn is_arith_expr(expr: &Expr) -> bool { #[must_use] fn is_bit_op(op: BinOpKind) -> bool { use rustc_ast::ast::BinOpKind::{BitAnd, BitOr, BitXor, Shl, Shr}; - match op { - BitXor | BitAnd | BitOr | Shl | Shr => true, - _ => false, - } + matches!(op, BitXor | BitAnd | BitOr | Shl | Shr) } #[must_use] fn is_arith_op(op: BinOpKind) -> bool { use rustc_ast::ast::BinOpKind::{Add, Div, Mul, Rem, Sub}; - match op { - Add | Sub | Mul | Div | Rem => true, - _ => false, - } + matches!(op, Add | Sub | Mul | Div | Rem) } diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index c164ec9aaf173..dd608de5723e2 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -52,6 +52,11 @@ declare_clippy_lint! { /// exclusive ranges, because they essentially add an extra branch that /// LLVM may fail to hoist out of the loop. /// + /// This will cause a warning that cannot be fixed if the consumer of the + /// range only accepts a specific range type, instead of the generic + /// `RangeBounds` trait + /// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)). + /// /// **Example:** /// ```rust,ignore /// for x..(y+1) { .. } @@ -72,7 +77,10 @@ declare_clippy_lint! { /// **Why is this bad?** The code is more readable with an exclusive range /// like `x..y`. /// - /// **Known problems:** None. + /// **Known problems:** This will cause a warning that cannot be fixed if + /// the consumer of the range only accepts a specific range type, instead of + /// the generic `RangeBounds` trait + /// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)). /// /// **Example:** /// ```rust,ignore @@ -83,7 +91,7 @@ declare_clippy_lint! { /// for x..y { .. } /// ``` pub RANGE_MINUS_ONE, - complexity, + pedantic, "`x..=(y-1)` reads better as `x..y`" } diff --git a/src/tools/clippy/clippy_lints/src/redundant_pattern_matching.rs b/src/tools/clippy/clippy_lints/src/redundant_pattern_matching.rs deleted file mode 100644 index d8d16efb978a5..0000000000000 --- a/src/tools/clippy/clippy_lints/src/redundant_pattern_matching.rs +++ /dev/null @@ -1,260 +0,0 @@ -use crate::utils::{in_constant, match_qpath, match_trait_method, paths, snippet, span_lint_and_then}; -use if_chain::if_chain; -use rustc_ast::ast::LitKind; -use rustc_errors::Applicability; -use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, PatKind, QPath}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; -use rustc_mir::const_eval::is_const_fn; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Symbol; - -declare_clippy_lint! { - /// **What it does:** Lint for redundant pattern matching over `Result` or - /// `Option` - /// - /// **Why is this bad?** It's more concise and clear to just use the proper - /// utility function - /// - /// **Known problems:** None. - /// - /// **Example:** - /// - /// ```rust - /// if let Ok(_) = Ok::(42) {} - /// if let Err(_) = Err::(42) {} - /// if let None = None::<()> {} - /// if let Some(_) = Some(42) {} - /// match Ok::(42) { - /// Ok(_) => true, - /// Err(_) => false, - /// }; - /// ``` - /// - /// The more idiomatic use would be: - /// - /// ```rust - /// if Ok::(42).is_ok() {} - /// if Err::(42).is_err() {} - /// if None::<()>.is_none() {} - /// if Some(42).is_some() {} - /// Ok::(42).is_ok(); - /// ``` - pub REDUNDANT_PATTERN_MATCHING, - style, - "use the proper utility function avoiding an `if let`" -} - -declare_lint_pass!(RedundantPatternMatching => [REDUNDANT_PATTERN_MATCHING]); - -impl<'tcx> LateLintPass<'tcx> for RedundantPatternMatching { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Match(op, arms, ref match_source) = &expr.kind { - match match_source { - MatchSource::Normal => find_sugg_for_match(cx, expr, op, arms), - MatchSource::IfLetDesugar { .. } => find_sugg_for_if_let(cx, expr, op, arms, "if"), - MatchSource::WhileLetDesugar => find_sugg_for_if_let(cx, expr, op, arms, "while"), - _ => return, - } - } - } -} - -fn find_sugg_for_if_let<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx Expr<'_>, - op: &Expr<'_>, - arms: &[Arm<'_>], - keyword: &'static str, -) { - fn find_suggestion(cx: &LateContext<'_>, hir_id: HirId, path: &QPath<'_>) -> Option<&'static str> { - if match_qpath(path, &paths::RESULT_OK) && can_suggest(cx, hir_id, sym!(result_type), "is_ok") { - return Some("is_ok()"); - } - if match_qpath(path, &paths::RESULT_ERR) && can_suggest(cx, hir_id, sym!(result_type), "is_err") { - return Some("is_err()"); - } - if match_qpath(path, &paths::OPTION_SOME) && can_suggest(cx, hir_id, sym!(option_type), "is_some") { - return Some("is_some()"); - } - if match_qpath(path, &paths::OPTION_NONE) && can_suggest(cx, hir_id, sym!(option_type), "is_none") { - return Some("is_none()"); - } - None - } - - let hir_id = expr.hir_id; - let good_method = match arms[0].pat.kind { - PatKind::TupleStruct(ref path, ref patterns, _) if patterns.len() == 1 => { - if let PatKind::Wild = patterns[0].kind { - find_suggestion(cx, hir_id, path) - } else { - None - } - }, - PatKind::Path(ref path) => find_suggestion(cx, hir_id, path), - _ => None, - }; - let good_method = match good_method { - Some(method) => method, - None => return, - }; - - // check that `while_let_on_iterator` lint does not trigger - if_chain! { - if keyword == "while"; - if let ExprKind::MethodCall(method_path, _, _, _) = op.kind; - if method_path.ident.name == sym!(next); - if match_trait_method(cx, op, &paths::ITERATOR); - then { - return; - } - } - - span_lint_and_then( - cx, - REDUNDANT_PATTERN_MATCHING, - arms[0].pat.span, - &format!("redundant pattern matching, consider using `{}`", good_method), - |diag| { - // while let ... = ... { ... } - // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - let expr_span = expr.span; - - // while let ... = ... { ... } - // ^^^ - let op_span = op.span.source_callsite(); - - // while let ... = ... { ... } - // ^^^^^^^^^^^^^^^^^^^ - let span = expr_span.until(op_span.shrink_to_hi()); - diag.span_suggestion( - span, - "try this", - format!("{} {}.{}", keyword, snippet(cx, op_span, "_"), good_method), - Applicability::MachineApplicable, // snippet - ); - }, - ); -} - -fn find_sugg_for_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) { - if arms.len() == 2 { - let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind); - - let hir_id = expr.hir_id; - let found_good_method = match node_pair { - ( - PatKind::TupleStruct(ref path_left, ref patterns_left, _), - PatKind::TupleStruct(ref path_right, ref patterns_right, _), - ) if patterns_left.len() == 1 && patterns_right.len() == 1 => { - if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) { - find_good_method_for_match( - arms, - path_left, - path_right, - &paths::RESULT_OK, - &paths::RESULT_ERR, - "is_ok()", - "is_err()", - || can_suggest(cx, hir_id, sym!(result_type), "is_ok"), - || can_suggest(cx, hir_id, sym!(result_type), "is_err"), - ) - } else { - None - } - }, - (PatKind::TupleStruct(ref path_left, ref patterns, _), PatKind::Path(ref path_right)) - | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, ref patterns, _)) - if patterns.len() == 1 => - { - if let PatKind::Wild = patterns[0].kind { - find_good_method_for_match( - arms, - path_left, - path_right, - &paths::OPTION_SOME, - &paths::OPTION_NONE, - "is_some()", - "is_none()", - || can_suggest(cx, hir_id, sym!(option_type), "is_some"), - || can_suggest(cx, hir_id, sym!(option_type), "is_none"), - ) - } else { - None - } - }, - _ => None, - }; - - if let Some(good_method) = found_good_method { - span_lint_and_then( - cx, - REDUNDANT_PATTERN_MATCHING, - expr.span, - &format!("redundant pattern matching, consider using `{}`", good_method), - |diag| { - let span = expr.span.to(op.span); - diag.span_suggestion( - span, - "try this", - format!("{}.{}", snippet(cx, op.span, "_"), good_method), - Applicability::MaybeIncorrect, // snippet - ); - }, - ); - } - } -} - -#[allow(clippy::too_many_arguments)] -fn find_good_method_for_match<'a>( - arms: &[Arm<'_>], - path_left: &QPath<'_>, - path_right: &QPath<'_>, - expected_left: &[&str], - expected_right: &[&str], - should_be_left: &'a str, - should_be_right: &'a str, - can_suggest_left: impl Fn() -> bool, - can_suggest_right: impl Fn() -> bool, -) -> Option<&'a str> { - let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) { - (&(*arms[0].body).kind, &(*arms[1].body).kind) - } else if match_qpath(path_right, expected_left) && match_qpath(path_left, expected_right) { - (&(*arms[1].body).kind, &(*arms[0].body).kind) - } else { - return None; - }; - - match body_node_pair { - (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) { - (LitKind::Bool(true), LitKind::Bool(false)) if can_suggest_left() => Some(should_be_left), - (LitKind::Bool(false), LitKind::Bool(true)) if can_suggest_right() => Some(should_be_right), - _ => None, - }, - _ => None, - } -} - -fn can_suggest(cx: &LateContext<'_>, hir_id: HirId, diag_item: Symbol, name: &str) -> bool { - if !in_constant(cx, hir_id) { - return true; - } - - // Avoid suggesting calls to non-`const fn`s in const contexts, see #5697. - cx.tcx - .get_diagnostic_item(diag_item) - .and_then(|def_id| { - cx.tcx.inherent_impls(def_id).iter().find_map(|imp| { - cx.tcx - .associated_items(*imp) - .in_definition_order() - .find_map(|item| match item.kind { - ty::AssocKind::Fn if item.ident.name.as_str() == name => Some(item.def_id), - _ => None, - }) - }) - }) - .map_or(false, |def_id| is_const_fn(cx.tcx, def_id)) -} diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs index b67abad6ccb8f..f204a0ffb2c7b 100644 --- a/src/tools/clippy/clippy_lints/src/regex.rs +++ b/src/tools/clippy/clippy_lints/src/regex.rs @@ -1,9 +1,9 @@ use crate::consts::{constant, Constant}; -use crate::utils::{is_expn_of, match_def_path, match_type, paths, span_lint, span_lint_and_help}; +use crate::utils::{match_def_path, paths, span_lint, span_lint_and_help}; use if_chain::if_chain; use rustc_ast::ast::{LitKind, StrStyle}; use rustc_data_structures::fx::FxHashSet; -use rustc_hir::{Block, BorrowKind, Crate, Expr, ExprKind, HirId}; +use rustc_hir::{BorrowKind, Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{BytePos, Span}; @@ -46,66 +46,15 @@ declare_clippy_lint! { "trivial regular expressions" } -declare_clippy_lint! { - /// **What it does:** Checks for usage of `regex!(_)` which (as of now) is - /// usually slower than `Regex::new(_)` unless called in a loop (which is a bad - /// idea anyway). - /// - /// **Why is this bad?** Performance, at least for now. The macro version is - /// likely to catch up long-term, but for now the dynamic version is faster. - /// - /// **Known problems:** None. - /// - /// **Example:** - /// ```ignore - /// regex!("foo|bar") - /// ``` - pub REGEX_MACRO, - style, - "use of `regex!(_)` instead of `Regex::new(_)`" -} - #[derive(Clone, Default)] pub struct Regex { spans: FxHashSet, last: Option, } -impl_lint_pass!(Regex => [INVALID_REGEX, REGEX_MACRO, TRIVIAL_REGEX]); +impl_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]); impl<'tcx> LateLintPass<'tcx> for Regex { - fn check_crate(&mut self, _: &LateContext<'tcx>, _: &'tcx Crate<'_>) { - self.spans.clear(); - } - - fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) { - if_chain! { - if self.last.is_none(); - if let Some(ref expr) = block.expr; - if match_type(cx, cx.tables().expr_ty(expr), &paths::REGEX); - if let Some(span) = is_expn_of(expr.span, "regex"); - then { - if !self.spans.contains(&span) { - span_lint( - cx, - REGEX_MACRO, - span, - "`regex!(_)` found. \ - Please use `Regex::new(_)`, which is faster for now." - ); - self.spans.insert(span); - } - self.last = Some(block.hir_id); - } - } - } - - fn check_block_post(&mut self, _: &LateContext<'tcx>, block: &'tcx Block<'_>) { - if self.last.map_or(false, |id| block.hir_id == id) { - self.last = None; - } - } - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { if let ExprKind::Call(ref fun, ref args) = expr.kind; @@ -150,12 +99,7 @@ fn is_trivial_regex(s: ®ex_syntax::hir::Hir) -> Option<&'static str> { use regex_syntax::hir::Anchor::{EndText, StartText}; use regex_syntax::hir::HirKind::{Alternation, Anchor, Concat, Empty, Literal}; - let is_literal = |e: &[regex_syntax::hir::Hir]| { - e.iter().all(|e| match *e.kind() { - Literal(_) => true, - _ => false, - }) - }; + let is_literal = |e: &[regex_syntax::hir::Hir]| e.iter().all(|e| matches!(*e.kind(), Literal(_))); match *s.kind() { Empty | Anchor(_) => Some("the regex is unlikely to be useful as it is"), diff --git a/src/tools/clippy/clippy_lints/src/repeat_once.rs b/src/tools/clippy/clippy_lints/src/repeat_once.rs new file mode 100644 index 0000000000000..a3af369e41e5a --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/repeat_once.rs @@ -0,0 +1,82 @@ +use crate::consts::{constant_context, Constant}; +use crate::utils::{in_macro, is_type_diagnostic_item, snippet, span_lint_and_sugg, walk_ptrs_ty}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** Checks for usage of `.repeat(1)` and suggest the following method for each types. + /// - `.to_string()` for `str` + /// - `.clone()` for `String` + /// - `.to_vec()` for `slice` + /// + /// **Why is this bad?** For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning the string is the intention behind this, `clone()` should be used. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// fn main() { + /// let x = String::from("hello world").repeat(1); + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn main() { + /// let x = String::from("hello world").clone(); + /// } + /// ``` + pub REPEAT_ONCE, + complexity, + "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` " +} + +declare_lint_pass!(RepeatOnce => [REPEAT_ONCE]); + +impl<'tcx> LateLintPass<'tcx> for RepeatOnce { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) { + if_chain! { + if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind; + if path.ident.name == sym!(repeat); + if let Some(Constant::Int(1)) = constant_context(cx, cx.tables()).expr(&args[1]); + if !in_macro(args[0].span); + then { + let ty = walk_ptrs_ty(cx.tables().expr_ty(&args[0])); + if ty.is_str() { + span_lint_and_sugg( + cx, + REPEAT_ONCE, + expr.span, + "calling `repeat(1)` on str", + "consider using `.to_string()` instead", + format!("{}.to_string()", snippet(cx, args[0].span, r#""...""#)), + Applicability::MachineApplicable, + ); + } else if ty.builtin_index().is_some() { + span_lint_and_sugg( + cx, + REPEAT_ONCE, + expr.span, + "calling `repeat(1)` on slice", + "consider using `.to_vec()` instead", + format!("{}.to_vec()", snippet(cx, args[0].span, r#""...""#)), + Applicability::MachineApplicable, + ); + } else if is_type_diagnostic_item(cx, ty, sym!(string_type)) { + span_lint_and_sugg( + cx, + REPEAT_ONCE, + expr.span, + "calling `repeat(1)` on a string literal", + "consider using `.clone()` instead", + format!("{}.clone()", snippet(cx, args[0].span, r#""...""#)), + Applicability::MachineApplicable, + ); + } + } + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index 3c93974417356..faef7e724dd05 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -259,15 +259,15 @@ fn is_unit_expr(expr: &ast::Expr) -> bool { fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) { let (ret_span, appl) = if let Ok(fn_source) = cx.sess().source_map().span_to_snippet(span.with_hi(ty.span.hi())) { - if let Some(rpos) = fn_source.rfind("->") { - #[allow(clippy::cast_possible_truncation)] - ( - ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), - Applicability::MachineApplicable, - ) - } else { - (ty.span, Applicability::MaybeIncorrect) - } + fn_source + .rfind("->") + .map_or((ty.span, Applicability::MaybeIncorrect), |rpos| { + ( + #[allow(clippy::cast_possible_truncation)] + ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), + Applicability::MachineApplicable, + ) + }) } else { (ty.span, Applicability::MaybeIncorrect) }; diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs index 7da47ee4ff94b..194786c5c4145 100644 --- a/src/tools/clippy/clippy_lints/src/shadow.rs +++ b/src/tools/clippy/clippy_lints/src/shadow.rs @@ -165,14 +165,7 @@ fn check_local<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>, bindings: & fn is_binding(cx: &LateContext<'_>, pat_id: HirId) -> bool { let var_ty = cx.tables().node_type_opt(pat_id); - if let Some(var_ty) = var_ty { - match var_ty.kind { - ty::Adt(..) => false, - _ => true, - } - } else { - false - } + var_ty.map_or(false, |var_ty| !matches!(var_ty.kind, ty::Adt(..))) } fn check_pat<'tcx>( diff --git a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs index 509bbfd27c1a5..1aeff1baa362e 100644 --- a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs +++ b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs @@ -25,13 +25,7 @@ declare_clippy_lint! { fn is_temporary(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match &expr.kind { ExprKind::Struct(..) | ExprKind::Tup(..) => true, - ExprKind::Path(qpath) => { - if let Res::Def(DefKind::Const, ..) = cx.qpath_res(qpath, expr.hir_id) { - true - } else { - false - } - }, + ExprKind::Path(qpath) => matches!(cx.qpath_res(qpath, expr.hir_id), Res::Def(DefKind::Const, ..)), _ => false, } } diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index 9eb2079c3ca2d..0ef70311fb1cd 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -1,19 +1,19 @@ use crate::utils::{in_macro, snippet, snippet_with_applicability, span_lint_and_help, SpanlessHash}; +use if_chain::if_chain; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::{GenericBound, Generics, WherePredicate}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -#[derive(Copy, Clone)] -pub struct TraitBounds; - declare_clippy_lint! { /// **What it does:** This lint warns about unnecessary type repetitions in trait bounds /// /// **Why is this bad?** Repeating the type for every bound makes the code /// less readable than combining the bounds /// + /// **Known problems:** None. + /// /// **Example:** /// ```rust /// pub fn foo(t: T) where T: Copy, T: Clone {} @@ -29,6 +29,18 @@ declare_clippy_lint! { "Types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`" } +#[derive(Copy, Clone)] +pub struct TraitBounds { + max_trait_bounds: u64, +} + +impl TraitBounds { + #[must_use] + pub fn new(max_trait_bounds: u64) -> Self { + Self { max_trait_bounds } + } +} + impl_lint_pass!(TraitBounds => [TYPE_REPETITION_IN_BOUNDS]); impl<'tcx> LateLintPass<'tcx> for TraitBounds { @@ -44,9 +56,14 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { let mut map = FxHashMap::default(); let mut applicability = Applicability::MaybeIncorrect; for bound in gen.where_clause.predicates { - if let WherePredicate::BoundPredicate(ref p) = bound { + if_chain! { + if let WherePredicate::BoundPredicate(ref p) = bound; + if p.bounds.len() as u64 <= self.max_trait_bounds; + if !in_macro(p.span); let h = hash(&p.bounded_ty); - if let Some(ref v) = map.insert(h, p.bounds.iter().collect::>()) { + if let Some(ref v) = map.insert(h, p.bounds.iter().collect::>()); + + then { let mut hint_string = format!( "consider combining the bounds: `{}:", snippet(cx, p.bounded_ty.span, "_") diff --git a/src/tools/clippy/clippy_lints/src/types.rs b/src/tools/clippy/clippy_lints/src/types.rs index 68f51f0afdccd..bca388ecdcc38 100644 --- a/src/tools/clippy/clippy_lints/src/types.rs +++ b/src/tools/clippy/clippy_lints/src/types.rs @@ -775,11 +775,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitArg { .iter() .filter(|arg| { if is_unit(cx.tables().expr_ty(arg)) && !is_unit_literal(arg) { - if let ExprKind::Match(.., MatchSource::TryDesugar) = &arg.kind { - false - } else { - true - } + !matches!(&arg.kind, ExprKind::Match(.., MatchSource::TryDesugar)) } else { false } @@ -899,17 +895,11 @@ fn is_questionmark_desugar_marked_call(expr: &Expr<'_>) -> bool { } fn is_unit(ty: Ty<'_>) -> bool { - match ty.kind { - ty::Tuple(slice) if slice.is_empty() => true, - _ => false, - } + matches!(ty.kind, ty::Tuple(slice) if slice.is_empty()) } fn is_unit_literal(expr: &Expr<'_>) -> bool { - match expr.kind { - ExprKind::Tup(ref slice) if slice.is_empty() => true, - _ => false, - } + matches!(expr.kind, ExprKind::Tup(ref slice) if slice.is_empty()) } declare_clippy_lint! { @@ -1154,10 +1144,7 @@ fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 { } fn is_isize_or_usize(typ: Ty<'_>) -> bool { - match typ.kind { - ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => true, - _ => false, - } + matches!(typ.kind, ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize)) } fn span_precision_loss_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to_f64: bool) { @@ -1205,16 +1192,19 @@ fn span_lossless_lint(cx: &LateContext<'_>, expr: &Expr<'_>, op: &Expr<'_>, cast // has parens on the outside, they are no longer needed. let mut applicability = Applicability::MachineApplicable; let opt = snippet_opt(cx, op.span); - let sugg = if let Some(ref snip) = opt { - if should_strip_parens(op, snip) { - &snip[1..snip.len() - 1] - } else { - snip.as_str() - } - } else { - applicability = Applicability::HasPlaceholders; - ".." - }; + let sugg = opt.as_ref().map_or_else( + || { + applicability = Applicability::HasPlaceholders; + ".." + }, + |snip| { + if should_strip_parens(op, snip) { + &snip[1..snip.len() - 1] + } else { + snip.as_str() + } + }, + ); span_lint_and_sugg( cx, @@ -1734,10 +1724,10 @@ impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor { TyKind::TraitObject(ref param_bounds, _) => { let has_lifetime_parameters = param_bounds.iter().any(|bound| { - bound.bound_generic_params.iter().any(|gen| match gen.kind { - GenericParamKind::Lifetime { .. } => true, - _ => false, - }) + bound + .bound_generic_params + .iter() + .any(|gen| matches!(gen.kind, GenericParamKind::Lifetime { .. })) }); if has_lifetime_parameters { // complex trait bounds like A<'a, 'b> diff --git a/src/tools/clippy/clippy_lints/src/unnamed_address.rs b/src/tools/clippy/clippy_lints/src/unnamed_address.rs index b9aa202b328f6..25d136e564d3e 100644 --- a/src/tools/clippy/clippy_lints/src/unnamed_address.rs +++ b/src/tools/clippy/clippy_lints/src/unnamed_address.rs @@ -58,10 +58,10 @@ declare_lint_pass!(UnnamedAddress => [FN_ADDRESS_COMPARISONS, VTABLE_ADDRESS_COM impl LateLintPass<'_> for UnnamedAddress { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { fn is_comparison(binop: BinOpKind) -> bool { - match binop { - BinOpKind::Eq | BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ne | BinOpKind::Ge | BinOpKind::Gt => true, - _ => false, - } + matches!( + binop, + BinOpKind::Eq | BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ne | BinOpKind::Ge | BinOpKind::Gt + ) } fn is_trait_ptr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { @@ -72,11 +72,7 @@ impl LateLintPass<'_> for UnnamedAddress { } fn is_fn_def(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - if let ty::FnDef(..) = cx.tables().expr_ty(expr).kind { - true - } else { - false - } + matches!(cx.tables().expr_ty(expr).kind, ty::FnDef(..)) } if_chain! { diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs index d940776817ca0..91c1789a2ffb1 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs @@ -5,24 +5,23 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, subst::GenericArgKind}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Ident; declare_clippy_lint! { /// **What it does:** - /// Detects when people use `Vec::sort_by` and pass in a function + /// Detects uses of `Vec::sort_by` passing in a closure /// which compares the two arguments, either directly or indirectly. /// /// **Why is this bad?** /// It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if - /// possible) than to use `Vec::sort_by` and and a more complicated + /// possible) than to use `Vec::sort_by` and a more complicated /// closure. /// /// **Known problems:** - /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't - /// imported by a use statement in the current frame, then a `use` - /// statement that imports it will need to be added (which this lint - /// can't do). + /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't already + /// imported by a use statement, then it will need to be added manually. /// /// **Example:** /// @@ -201,28 +200,41 @@ 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 { - Some(LintTrigger::Sort(SortDetection { vec_name, unstable })) - } - else { - Some(LintTrigger::SortByKey(SortByKeyDetection { - vec_name, - unstable, - closure_arg, - closure_body, - reverse - })) + 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 + })) + } } } - } else { - None } } + + 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 } impl LateLintPass<'_> for UnnecessarySortBy { diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index 4d3682263f14f..502bf0c427954 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -72,8 +72,8 @@ impl EarlyLintPass for UnnestedOrPatterns { } fn lint_unnested_or_patterns(cx: &EarlyContext<'_>, pat: &Pat) { - if !cx.sess.opts.unstable_features.is_nightly_build() { - // User cannot do `#![feature(or_patterns)]`, so bail. + if !cx.sess.features_untracked().or_patterns { + // Do not suggest nesting the patterns if the feature `or_patterns` is not enabled. return; } @@ -400,8 +400,8 @@ fn extend_with_matching( /// Are the patterns in `ps1` and `ps2` equal save for `ps1[idx]` compared to `ps2[idx]`? fn eq_pre_post(ps1: &[P], ps2: &[P], idx: usize) -> bool { - ps1[idx].is_rest() == ps2[idx].is_rest() // Avoid `[x, ..] | [x, 0]` => `[x, .. | 0]`. - && ps1.len() == ps2.len() + ps1.len() == ps2.len() + && ps1[idx].is_rest() == ps2[idx].is_rest() // Avoid `[x, ..] | [x, 0]` => `[x, .. | 0]`. && over(&ps1[..idx], &ps2[..idx], |l, r| eq_pat(l, r)) && over(&ps1[idx + 1..], &ps2[idx + 1..], |l, r| eq_pat(l, r)) } diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index f85db1e2006e8..776c6bc57ca6f 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -167,14 +167,11 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { if let TyKind::Path(QPath::Resolved(_, ref item_path)) = item_type.kind; then { let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args; - let should_check = if let Some(ref params) = *parameters { - !params.parenthesized && !params.args.iter().any(|arg| match arg { - GenericArg::Lifetime(_) => true, - _ => false, - }) - } else { - true - }; + let should_check = parameters.as_ref().map_or( + true, + |params| !params.parenthesized + &&!params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))) + ); if should_check { let visitor = &mut UseSelfVisitor { diff --git a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs index e19a79dd8dad1..58c1103da9f7d 100755 --- a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs +++ b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs @@ -387,10 +387,7 @@ pub fn eq_use_tree_kind(l: &UseTreeKind, r: &UseTreeKind) -> bool { } pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool { - match (l, r) { - (Defaultness::Final, Defaultness::Final) | (Defaultness::Default(_), Defaultness::Default(_)) => true, - _ => false, - } + matches!((l, r), (Defaultness::Final, Defaultness::Final) | (Defaultness::Default(_), Defaultness::Default(_))) } pub fn eq_vis(l: &Visibility, r: &Visibility) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/utils/attrs.rs b/src/tools/clippy/clippy_lints/src/utils/attrs.rs index 4dcf6c105ec63..4bb4b087c5566 100644 --- a/src/tools/clippy/clippy_lints/src/utils/attrs.rs +++ b/src/tools/clippy/clippy_lints/src/utils/attrs.rs @@ -65,42 +65,45 @@ pub fn get_attr<'a>( }; let attr_segments = &attr.path.segments; if attr_segments.len() == 2 && attr_segments[0].ident.to_string() == "clippy" { - if let Some(deprecation_status) = - BUILTIN_ATTRIBUTES - .iter() - .find_map(|(builtin_name, deprecation_status)| { - if *builtin_name == attr_segments[1].ident.to_string() { - Some(deprecation_status) - } else { - None - } - }) - { - let mut diag = sess.struct_span_err(attr_segments[1].ident.span, "Usage of deprecated attribute"); - match *deprecation_status { - DeprecationStatus::Deprecated => { - diag.emit(); - false - }, - DeprecationStatus::Replaced(new_name) => { - diag.span_suggestion( - attr_segments[1].ident.span, - "consider using", - new_name.to_string(), - Applicability::MachineApplicable, - ); - diag.emit(); + BUILTIN_ATTRIBUTES + .iter() + .find_map(|(builtin_name, deprecation_status)| { + if *builtin_name == attr_segments[1].ident.to_string() { + Some(deprecation_status) + } else { + None + } + }) + .map_or_else( + || { + sess.span_err(attr_segments[1].ident.span, "Usage of unknown attribute"); false }, - DeprecationStatus::None => { - diag.cancel(); - attr_segments[1].ident.to_string() == name + |deprecation_status| { + let mut diag = + sess.struct_span_err(attr_segments[1].ident.span, "Usage of deprecated attribute"); + match *deprecation_status { + DeprecationStatus::Deprecated => { + diag.emit(); + false + }, + DeprecationStatus::Replaced(new_name) => { + diag.span_suggestion( + attr_segments[1].ident.span, + "consider using", + new_name.to_string(), + Applicability::MachineApplicable, + ); + diag.emit(); + false + }, + DeprecationStatus::None => { + diag.cancel(); + attr_segments[1].ident.to_string() == name + }, + } }, - } - } else { - sess.span_err(attr_segments[1].ident.span, "Usage of unknown attribute"); - false - } + ) } else { false } diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs index c41befbf147b8..de425211e38ef 100644 --- a/src/tools/clippy/clippy_lints/src/utils/conf.rs +++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs @@ -156,6 +156,8 @@ define_Conf! { (array_size_threshold, "array_size_threshold": u64, 512_000), /// Lint: VEC_BOX. The size of the boxed type in bytes, where boxing in a `Vec` is allowed (vec_box_size_threshold, "vec_box_size_threshold": u64, 4096), + /// Lint: TYPE_REPETITION_IN_BOUNDS. The maximum number of bounds a trait can have to be linted + (max_trait_bounds, "max_trait_bounds": u64, 3), /// Lint: STRUCT_EXCESSIVE_BOOLS. The maximum number of bools a struct can have (max_struct_bools, "max_struct_bools": u64, 3), /// Lint: FN_PARAMS_EXCESSIVE_BOOLS. The maximum number of bools function parameters can have diff --git a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs index ae58f0a1521e6..34341594c1985 100644 --- a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs +++ b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs @@ -703,6 +703,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } for segment in path.segments { segment.ident.name.hash(&mut self.s); + self.hash_generic_args(segment.generic_args().args); } }, QPath::TypeRelative(ref ty, ref segment) => { @@ -711,13 +712,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { }, }, TyKind::OpaqueDef(_, arg_list) => { - for arg in *arg_list { - match arg { - GenericArg::Lifetime(ref l) => self.hash_lifetime(l), - GenericArg::Type(ref ty) => self.hash_ty(&ty), - GenericArg::Const(ref ca) => self.hash_body(ca.value.body), - } - } + self.hash_generic_args(arg_list); }, TyKind::TraitObject(_, lifetime) => { self.hash_lifetime(lifetime); @@ -735,4 +730,14 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_expr(&self.cx.tcx.hir().body(body_id).value); self.maybe_typeck_tables = old_maybe_typeck_tables; } + + fn hash_generic_args(&mut self, arg_list: &[GenericArg<'_>]) { + for arg in arg_list { + match arg { + GenericArg::Lifetime(ref l) => self.hash_lifetime(l), + GenericArg::Type(ref ty) => self.hash_ty(&ty), + GenericArg::Const(ref ca) => self.hash_body(ca.value.body), + } + } + } } diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index 99ba7d64331cd..4b7a1c2b537f3 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -102,11 +102,7 @@ pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool { #[must_use] pub fn in_macro(span: Span) -> bool { if span.from_expansion() { - if let ExpnKind::Desugaring(..) = span.ctxt().outer_expn_data().kind { - false - } else { - true - } + !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..)) } else { false } @@ -127,10 +123,7 @@ pub fn is_present_in_source(cx: &T, span: Span) -> bool { /// Checks if given pattern is a wildcard (`_`) pub fn is_wild<'tcx>(pat: &impl std::ops::Deref>) -> bool { - match pat.kind { - PatKind::Wild => true, - _ => false, - } + matches!(pat.kind, PatKind::Wild) } /// Checks if type is struct, enum or union type with the given def path. @@ -153,11 +146,7 @@ pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symb pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool { let def_id = cx.tables().type_dependent_def_id(expr.hir_id).unwrap(); let trt_id = cx.tcx.trait_of_item(def_id); - if let Some(trt_id) = trt_id { - match_def_path(cx, trt_id, path) - } else { - false - } + trt_id.map_or(false, |trt_id| match_def_path(cx, trt_id, path)) } /// Checks if an expression references a variable of the given name. @@ -600,21 +589,15 @@ pub fn snippet_block_with_applicability<'a, T: LintContext>( /// // ^^^^^^^^^^ /// ``` pub fn first_line_of_span(cx: &T, span: Span) -> Span { - if let Some(first_char_pos) = first_char_in_first_line(cx, span) { - span.with_lo(first_char_pos) - } else { - span - } + first_char_in_first_line(cx, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos)) } fn first_char_in_first_line(cx: &T, span: Span) -> Option { let line_span = line_span(cx, span); - if let Some(snip) = snippet_opt(cx, line_span) { + snippet_opt(cx, line_span).and_then(|snip| { snip.find(|c: char| !c.is_whitespace()) .map(|pos| line_span.lo() + BytePos::from_usize(pos)) - } else { - None - } + }) } /// Returns the indentation of the line of a span @@ -626,11 +609,7 @@ fn first_char_in_first_line(cx: &T, span: Span) -> Option(cx: &T, span: Span) -> Option { - if let Some(snip) = snippet_opt(cx, line_span(cx, span)) { - snip.find(|c: char| !c.is_whitespace()) - } else { - None - } + snippet_opt(cx, line_span(cx, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace())) } /// Extends the span to the beginning of the spans line, incl. whitespaces. @@ -738,25 +717,21 @@ pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio let enclosing_node = map .get_enclosing_scope(hir_id) .and_then(|enclosing_id| map.find(enclosing_id)); - if let Some(node) = enclosing_node { - match node { - Node::Block(block) => Some(block), - Node::Item(&Item { - kind: ItemKind::Fn(_, _, eid), - .. - }) - | Node::ImplItem(&ImplItem { - kind: ImplItemKind::Fn(_, eid), - .. - }) => match cx.tcx.hir().body(eid).value.kind { - ExprKind::Block(ref block, _) => Some(block), - _ => None, - }, + enclosing_node.and_then(|node| match node { + Node::Block(block) => Some(block), + Node::Item(&Item { + kind: ItemKind::Fn(_, _, eid), + .. + }) + | Node::ImplItem(&ImplItem { + kind: ImplItemKind::Fn(_, eid), + .. + }) => match cx.tcx.hir().body(eid).value.kind { + ExprKind::Block(ref block, _) => Some(block), _ => None, - } - } else { - None - } + }, + _ => None, + }) } /// Returns the base type for HIR references and pointers. @@ -1328,11 +1303,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { _ => None, }; - if let Some(did) = did { - must_use_attr(&cx.tcx.get_attrs(did)).is_some() - } else { - false - } + did.map_or(false, |did| must_use_attr(&cx.tcx.get_attrs(did)).is_some()) } pub fn is_no_std_crate(krate: &Crate<'_>) -> bool { @@ -1385,6 +1356,21 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool { ) } +/// Returns the `DefId` of the callee if the given expression is a function or method call. +pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { + match &expr.kind { + ExprKind::MethodCall(..) => cx.tables().type_dependent_def_id(expr.hir_id), + ExprKind::Call( + Expr { + kind: ExprKind::Path(qpath), + .. + }, + .., + ) => cx.tables().qpath_res(qpath, expr.hir_id).opt_def_id(), + _ => None, + } +} + pub fn run_lints(cx: &LateContext<'_>, lints: &[&'static Lint], id: HirId) -> bool { lints.iter().any(|lint| { matches!( diff --git a/src/tools/clippy/clippy_lints/src/utils/numeric_literal.rs b/src/tools/clippy/clippy_lints/src/utils/numeric_literal.rs index 99413153d49bb..87cb454f654bc 100644 --- a/src/tools/clippy/clippy_lints/src/utils/numeric_literal.rs +++ b/src/tools/clippy/clippy_lints/src/utils/numeric_literal.rs @@ -51,7 +51,7 @@ impl<'a> NumericLiteral<'a> { pub fn from_lit_kind(src: &'a str, lit_kind: &LitKind) -> Option> { if lit_kind.is_numeric() && src.chars().next().map_or(false, |c| c.is_digit(10)) { let (unsuffixed, suffix) = split_suffix(&src, lit_kind); - let float = if let LitKind::Float(..) = lit_kind { true } else { false }; + let float = matches!(lit_kind, LitKind::Float(..)); Some(NumericLiteral::new(unsuffixed, suffix, float)) } else { None @@ -200,12 +200,10 @@ impl<'a> NumericLiteral<'a> { fn split_suffix<'a>(src: &'a str, lit_kind: &LitKind) -> (&'a str, Option<&'a str>) { debug_assert!(lit_kind.is_numeric()); - if let Some(suffix_length) = lit_suffix_length(lit_kind) { + lit_suffix_length(lit_kind).map_or((src, None), |suffix_length| { let (unsuffixed, suffix) = src.split_at(src.len() - suffix_length); (unsuffixed, Some(suffix)) - } else { - (src, None) - } + }) } fn lit_suffix_length(lit_kind: &LitKind) -> Option { diff --git a/src/tools/clippy/clippy_lints/src/utils/paths.rs b/src/tools/clippy/clippy_lints/src/utils/paths.rs index 3b7e9739211b0..4c3462802e921 100644 --- a/src/tools/clippy/clippy_lints/src/utils/paths.rs +++ b/src/tools/clippy/clippy_lints/src/utils/paths.rs @@ -98,7 +98,6 @@ pub const RANGE_TO_STD: [&str; 3] = ["std", "ops", "RangeTo"]; pub const RC: [&str; 3] = ["alloc", "rc", "Rc"]; pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"]; pub const RECEIVER: [&str; 4] = ["std", "sync", "mpsc", "Receiver"]; -pub const REGEX: [&str; 3] = ["regex", "re_unicode", "Regex"]; pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"]; pub const REGEX_BYTES_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"]; pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"]; diff --git a/src/tools/clippy/clippy_lints/src/utils/sugg.rs b/src/tools/clippy/clippy_lints/src/utils/sugg.rs index d05e81b950579..0ac7714fbeb79 100644 --- a/src/tools/clippy/clippy_lints/src/utils/sugg.rs +++ b/src/tools/clippy/clippy_lints/src/utils/sugg.rs @@ -325,22 +325,22 @@ pub fn make_unop(op: &str, expr: Sugg<'_>) -> Sugg<'static> { /// parenthesis will always be added for a mix of these. pub fn make_assoc(op: AssocOp, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static> { /// Returns `true` if the operator is a shift operator `<<` or `>>`. - fn is_shift(op: &AssocOp) -> bool { - matches!(*op, AssocOp::ShiftLeft | AssocOp::ShiftRight) + fn is_shift(op: AssocOp) -> bool { + matches!(op, AssocOp::ShiftLeft | AssocOp::ShiftRight) } /// Returns `true` if the operator is a arithmetic operator /// (i.e., `+`, `-`, `*`, `/`, `%`). - fn is_arith(op: &AssocOp) -> bool { + fn is_arith(op: AssocOp) -> bool { matches!( - *op, + op, AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | AssocOp::Modulus ) } /// Returns `true` if the operator `op` needs parenthesis with the operator /// `other` in the direction `dir`. - fn needs_paren(op: &AssocOp, other: &AssocOp, dir: Associativity) -> bool { + fn needs_paren(op: AssocOp, other: AssocOp, dir: Associativity) -> bool { other.precedence() < op.precedence() || (other.precedence() == op.precedence() && ((op != other && associativity(op) != dir) @@ -349,14 +349,14 @@ pub fn make_assoc(op: AssocOp, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static> || is_shift(other) && is_arith(op) } - let lhs_paren = if let Sugg::BinOp(ref lop, _) = *lhs { - needs_paren(&op, lop, Associativity::Left) + let lhs_paren = if let Sugg::BinOp(lop, _) = *lhs { + needs_paren(op, lop, Associativity::Left) } else { false }; - let rhs_paren = if let Sugg::BinOp(ref rop, _) = *rhs { - needs_paren(&op, rop, Associativity::Right) + let rhs_paren = if let Sugg::BinOp(rop, _) = *rhs { + needs_paren(op, rop, Associativity::Right) } else { false }; @@ -424,13 +424,13 @@ enum Associativity { /// they are considered /// associative. #[must_use] -fn associativity(op: &AssocOp) -> Associativity { +fn associativity(op: AssocOp) -> Associativity { use rustc_ast::util::parser::AssocOp::{ Add, As, Assign, AssignOp, BitAnd, BitOr, BitXor, Colon, Divide, DotDot, DotDotEq, Equal, Greater, GreaterEqual, LAnd, LOr, Less, LessEqual, Modulus, Multiply, NotEqual, ShiftLeft, ShiftRight, Subtract, }; - match *op { + match op { Assign | AssignOp(_) => Associativity::Right, Add | BitAnd | BitOr | BitXor | LAnd | LOr | Multiply | As | Colon => Associativity::Both, Divide | Equal | Greater | GreaterEqual | Less | LessEqual | Modulus | NotEqual | ShiftLeft | ShiftRight @@ -492,20 +492,20 @@ fn astbinop2assignop(op: ast::BinOp) -> AssocOp { /// before it on its line. fn indentation(cx: &T, span: Span) -> Option { let lo = cx.sess().source_map().lookup_char_pos(span.lo()); - if let Some(line) = lo.file.get_line(lo.line - 1 /* line numbers in `Loc` are 1-based */) { - if let Some((pos, _)) = line.char_indices().find(|&(_, c)| c != ' ' && c != '\t') { - // We can mix char and byte positions here because we only consider `[ \t]`. - if lo.col == CharPos(pos) { - Some(line[..pos].into()) + lo.file + .get_line(lo.line - 1 /* line numbers in `Loc` are 1-based */) + .and_then(|line| { + if let Some((pos, _)) = line.char_indices().find(|&(_, c)| c != ' ' && c != '\t') { + // We can mix char and byte positions here because we only consider `[ \t]`. + if lo.col == CharPos(pos) { + Some(line[..pos].into()) + } else { + None + } } else { None } - } else { - None - } - } else { - None - } + }) } /// Convenience extension trait for `DiagnosticBuilder`. diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index cb769b5a2ce95..063f94582b9d1 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -23,7 +23,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust + /// // Bad /// println!(""); + /// + /// // Good + /// println!(); /// ``` pub PRINTLN_EMPTY_STRING, style, @@ -32,8 +36,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** This lint warns when you use `print!()` with a format - /// string that - /// ends in a newline. + /// string that ends in a newline. /// /// **Why is this bad?** You should use `println!()` instead, which appends the /// newline. @@ -125,7 +128,12 @@ declare_clippy_lint! { /// ```rust /// # use std::fmt::Write; /// # let mut buf = String::new(); + /// + /// // Bad /// writeln!(buf, ""); + /// + /// // Good + /// writeln!(buf); /// ``` pub WRITELN_EMPTY_STRING, style, @@ -147,7 +155,12 @@ declare_clippy_lint! { /// # use std::fmt::Write; /// # let mut buf = String::new(); /// # let name = "World"; + /// + /// // Bad /// write!(buf, "Hello {}!\n", name); + /// + /// // Good + /// writeln!(buf, "Hello {}!", name); /// ``` pub WRITE_WITH_NEWLINE, style, @@ -168,7 +181,12 @@ declare_clippy_lint! { /// ```rust /// # use std::fmt::Write; /// # let mut buf = String::new(); + /// + /// // Bad /// writeln!(buf, "{}", "foo"); + /// + /// // Good + /// writeln!(buf, "foo"); /// ``` pub WRITE_LITERAL, style, @@ -279,13 +297,13 @@ impl EarlyLintPass for Write { if let (Some(fmt_str), expr) = self.check_tts(cx, &mac.args.inner_tokens(), true) { if fmt_str.symbol == Symbol::intern("") { let mut applicability = Applicability::MachineApplicable; - let suggestion = match expr { - Some(expr) => snippet_with_applicability(cx, expr.span, "v", &mut applicability), - None => { + let suggestion = expr.map_or_else( + || { applicability = Applicability::HasPlaceholders; Cow::Borrowed("v") }, - }; + |e| snippet_with_applicability(cx, e.span, "v", &mut Applicability::MachineApplicable), + ); span_lint_and_sugg( cx, diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index decd3a79cce18..47315fa64cd80 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -382,13 +382,8 @@ pub fn main() { let should_describe_lints = || { let args: Vec<_> = env::args().collect(); - args.windows(2).any(|args| { - args[1] == "help" - && match args[0].as_str() { - "-W" | "-A" | "-D" | "-F" => true, - _ => false, - } - }) + args.windows(2) + .any(|args| args[1] == "help" && matches!(args[0].as_str(), "-W" | "-A" | "-D" | "-F")) }; if !wrapper_mode && should_describe_lints() { diff --git a/src/tools/clippy/src/lintlist/mod.rs b/src/tools/clippy/src/lintlist/mod.rs index edceb75518008..b89a87128626b 100644 --- a/src/tools/clippy/src/lintlist/mod.rs +++ b/src/tools/clippy/src/lintlist/mod.rs @@ -80,6 +80,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "blacklisted_name", }, + Lint { + name: "blanket_clippy_restriction_lints", + group: "style", + desc: "enabling the complete restriction group", + deprecation: None, + module: "attrs", + }, Lint { name: "blocks_in_if_conditions", group: "style", @@ -1144,6 +1151,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "methods", }, + Lint { + name: "map_identity", + group: "complexity", + desc: "using iterator.map(|x| x)", + deprecation: None, + module: "map_identity", + }, Lint { name: "map_unwrap_or", group: "pedantic", @@ -1165,6 +1179,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "matches", }, + Lint { + name: "match_like_matches_macro", + group: "style", + desc: "a match that could be written with the matches! macro", + deprecation: None, + module: "matches", + }, Lint { name: "match_on_vec_items", group: "pedantic", @@ -1606,6 +1627,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "option_env_unwrap", }, + Lint { + name: "option_if_let_else", + group: "pedantic", + desc: "reimplementation of Option::map_or", + deprecation: None, + module: "option_if_let_else", + }, Lint { name: "option_map_or_none", group: "style", @@ -1683,6 +1711,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "path_buf_push_overwrite", }, + Lint { + name: "pattern_type_mismatch", + group: "restriction", + desc: "type of pattern does not match the expression type", + deprecation: None, + module: "pattern_type_mismatch", + }, Lint { name: "possible_missing_comma", group: "correctness", @@ -1755,7 +1790,7 @@ pub static ref ALL_LINTS: Vec = vec![ }, Lint { name: "range_minus_one", - group: "complexity", + group: "pedantic", desc: "`x..=(y-1)` reads better as `x..y`", deprecation: None, module: "ranges", @@ -1828,7 +1863,7 @@ pub static ref ALL_LINTS: Vec = vec![ group: "style", desc: "use the proper utility function avoiding an `if let`", deprecation: None, - module: "redundant_pattern_matching", + module: "matches", }, Lint { name: "redundant_pub_crate", @@ -1852,11 +1887,11 @@ pub static ref ALL_LINTS: Vec = vec![ module: "reference", }, Lint { - name: "regex_macro", - group: "style", - desc: "use of `regex!(_)` instead of `Regex::new(_)`", + name: "repeat_once", + group: "complexity", + desc: "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` ", deprecation: None, - module: "regex", + module: "repeat_once", }, Lint { name: "rest_pat_in_fully_bound_structs", diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index 368fa6a98c5d6..26a47d237065a 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -12,19 +12,11 @@ use std::path::{Path, PathBuf}; mod cargo; fn host_lib() -> PathBuf { - if let Some(path) = option_env!("HOST_LIBS") { - PathBuf::from(path) - } else { - cargo::CARGO_TARGET_DIR.join(env!("PROFILE")) - } + option_env!("HOST_LIBS").map_or(cargo::CARGO_TARGET_DIR.join(env!("PROFILE")), PathBuf::from) } fn clippy_driver_path() -> PathBuf { - if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") { - PathBuf::from(path) - } else { - cargo::TARGET_LIB.join("clippy-driver") - } + option_env!("CLIPPY_DRIVER_PATH").map_or(cargo::TARGET_LIB.join("clippy-driver"), PathBuf::from) } // When we'll want to use `extern crate ..` for a dependency that is used diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.lock b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.lock new file mode 100644 index 0000000000000..7e96aa36feb45 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.lock @@ -0,0 +1,109 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi 0.3.9", +] + +[[package]] +name = "bitflags" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "ctrlc" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "653abc99aa905f693d89df4797fadc08085baee379db92be9f2496cefe8a6f2c" +dependencies = [ + "kernel32-sys", + "nix", + "winapi 0.2.8", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + +[[package]] +name = "libc" +version = "0.2.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" + +[[package]] +name = "multiple_crate_versions" +version = "0.1.0" +dependencies = [ + "ansi_term", + "ctrlc", +] + +[[package]] +name = "nix" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2c5afeb0198ec7be8569d666644b574345aad2e95a53baf3a532da3e0f3fb32" +dependencies = [ + "bitflags", + "cfg-if", + "libc", + "void", +] + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr index 4f668599be950..f3113e0936502 100644 --- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr +++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr @@ -1,4 +1,4 @@ -error: multiple versions for dependency `winapi`: 0.2.8, 0.3.8 +error: multiple versions for dependency `winapi`: 0.2.8, 0.3.9 | = note: `-D clippy::multiple-crate-versions` implied by `-D warnings` diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 53970af41079d..6fbba01416a8d 100644 --- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/src/tools/clippy/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-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`, `third-party` at line 5 column 1 error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/attrs.rs b/src/tools/clippy/tests/ui/attrs.rs index 91b65a43be77f..908d063729f45 100644 --- a/src/tools/clippy/tests/ui/attrs.rs +++ b/src/tools/clippy/tests/ui/attrs.rs @@ -1,5 +1,11 @@ #![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)] +#![forbid(clippy::restriction)] +#![allow(clippy::missing_docs_in_private_items, clippy::panic, clippy::unreachable)] + #[inline(always)] fn test_attr_lint() { assert!(true) diff --git a/src/tools/clippy/tests/ui/attrs.stderr b/src/tools/clippy/tests/ui/attrs.stderr index 39ddf6f226d95..ef4b89eaa6dee 100644 --- a/src/tools/clippy/tests/ui/attrs.stderr +++ b/src/tools/clippy/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:3:1 + --> $DIR/attrs.rs:9: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:23:14 + --> $DIR/attrs.rs:29:14 | LL | #[deprecated(since = "forever")] | ^^^^^^^^^^^^^^^^^ @@ -15,10 +15,35 @@ 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:26:14 + --> $DIR/attrs.rs:32:14 | LL | #[deprecated(since = "1")] | ^^^^^^^^^^^ -error: aborting due to 3 previous errors +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: restriction lints are not meant to be all enabled + --> $DIR/attrs.rs:6:11 + | +LL | #![forbid(clippy::restriction)] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: try enabling only the lints you really need + +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/clone_on_copy.fixed b/src/tools/clippy/tests/ui/clone_on_copy.fixed new file mode 100644 index 0000000000000..1f0ca101757ec --- /dev/null +++ b/src/tools/clippy/tests/ui/clone_on_copy.fixed @@ -0,0 +1,40 @@ +// run-rustfix + +#![allow( + unused, + clippy::redundant_clone, + clippy::deref_addrof, + clippy::no_effect, + clippy::unnecessary_operation +)] + +use std::cell::RefCell; +use std::rc::{self, Rc}; +use std::sync::{self, Arc}; + +fn main() {} + +fn is_ascii(ch: char) -> bool { + ch.is_ascii() +} + +fn clone_on_copy() { + 42; + + vec![1].clone(); // ok, not a Copy type + Some(vec![1]).clone(); // ok, not a Copy type + *(&42); + + let rc = RefCell::new(0); + *rc.borrow(); + + // Issue #4348 + let mut x = 43; + let _ = &x.clone(); // ok, getting a ref + 'a'.clone().make_ascii_uppercase(); // ok, clone and then mutate + is_ascii('z'); + + // Issue #5436 + let mut vec = Vec::new(); + vec.push(42); +} diff --git a/src/tools/clippy/tests/ui/clone_on_copy.rs b/src/tools/clippy/tests/ui/clone_on_copy.rs new file mode 100644 index 0000000000000..ca39a654b4fce --- /dev/null +++ b/src/tools/clippy/tests/ui/clone_on_copy.rs @@ -0,0 +1,40 @@ +// run-rustfix + +#![allow( + unused, + clippy::redundant_clone, + clippy::deref_addrof, + clippy::no_effect, + clippy::unnecessary_operation +)] + +use std::cell::RefCell; +use std::rc::{self, Rc}; +use std::sync::{self, Arc}; + +fn main() {} + +fn is_ascii(ch: char) -> bool { + ch.is_ascii() +} + +fn clone_on_copy() { + 42.clone(); + + vec![1].clone(); // ok, not a Copy type + Some(vec![1]).clone(); // ok, not a Copy type + (&42).clone(); + + let rc = RefCell::new(0); + rc.borrow().clone(); + + // Issue #4348 + let mut x = 43; + let _ = &x.clone(); // ok, getting a ref + 'a'.clone().make_ascii_uppercase(); // ok, clone and then mutate + is_ascii('z'.clone()); + + // Issue #5436 + let mut vec = Vec::new(); + vec.push(42.clone()); +} diff --git a/src/tools/clippy/tests/ui/clone_on_copy.stderr b/src/tools/clippy/tests/ui/clone_on_copy.stderr new file mode 100644 index 0000000000000..ec2faf4ab40d2 --- /dev/null +++ b/src/tools/clippy/tests/ui/clone_on_copy.stderr @@ -0,0 +1,34 @@ +error: using `clone` on a `Copy` type + --> $DIR/clone_on_copy.rs:22:5 + | +LL | 42.clone(); + | ^^^^^^^^^^ help: try removing the `clone` call: `42` + | + = note: `-D clippy::clone-on-copy` implied by `-D warnings` + +error: using `clone` on a `Copy` type + --> $DIR/clone_on_copy.rs:26:5 + | +LL | (&42).clone(); + | ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)` + +error: using `clone` on a `Copy` type + --> $DIR/clone_on_copy.rs:29:5 + | +LL | rc.borrow().clone(); + | ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()` + +error: using `clone` on a `Copy` type + --> $DIR/clone_on_copy.rs:35:14 + | +LL | is_ascii('z'.clone()); + | ^^^^^^^^^^^ help: try removing the `clone` call: `'z'` + +error: using `clone` on a `Copy` type + --> $DIR/clone_on_copy.rs:39:14 + | +LL | vec.push(42.clone()); + | ^^^^^^^^^^ help: try removing the `clone` call: `42` + +error: aborting due to 5 previous errors + diff --git a/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.fixed b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.fixed new file mode 100644 index 0000000000000..3305ac9bf8b6c --- /dev/null +++ b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.fixed @@ -0,0 +1,93 @@ +// run-rustfix +#![allow(unused, clippy::redundant_clone)] // See #5700 + +// Define the types in each module to avoid trait impls leaking between modules. +macro_rules! impl_types { + () => { + #[derive(PartialEq)] + pub struct Owned; + + pub struct Borrowed; + + impl ToOwned for Borrowed { + type Owned = Owned; + fn to_owned(&self) -> Owned { + Owned {} + } + } + + impl std::borrow::Borrow for Owned { + fn borrow(&self) -> &Borrowed { + static VALUE: Borrowed = Borrowed {}; + &VALUE + } + } + }; +} + +// Only Borrowed == Owned is implemented +mod borrowed_eq_owned { + impl_types!(); + + impl PartialEq for Borrowed { + fn eq(&self, _: &Owned) -> bool { + true + } + } + + pub fn compare() { + let owned = Owned {}; + let borrowed = Borrowed {}; + + if borrowed == owned {} + if borrowed == owned {} + } +} + +// Only Owned == Borrowed is implemented +mod owned_eq_borrowed { + impl_types!(); + + impl PartialEq for Owned { + fn eq(&self, _: &Borrowed) -> bool { + true + } + } + + fn compare() { + let owned = Owned {}; + let borrowed = Borrowed {}; + + if owned == borrowed {} + if owned == borrowed {} + } +} + +mod issue_4874 { + impl_types!(); + + // NOTE: PartialEq for T can't be implemented due to the orphan rules + impl PartialEq for Borrowed + where + T: AsRef + ?Sized, + { + fn eq(&self, _: &T) -> bool { + true + } + } + + impl std::fmt::Display for Borrowed { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "borrowed") + } + } + + fn compare() { + let borrowed = Borrowed {}; + + if borrowed == "Hi" {} + if borrowed == "Hi" {} + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.rs b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.rs new file mode 100644 index 0000000000000..88bc2f51dd662 --- /dev/null +++ b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.rs @@ -0,0 +1,93 @@ +// run-rustfix +#![allow(unused, clippy::redundant_clone)] // See #5700 + +// Define the types in each module to avoid trait impls leaking between modules. +macro_rules! impl_types { + () => { + #[derive(PartialEq)] + pub struct Owned; + + pub struct Borrowed; + + impl ToOwned for Borrowed { + type Owned = Owned; + fn to_owned(&self) -> Owned { + Owned {} + } + } + + impl std::borrow::Borrow for Owned { + fn borrow(&self) -> &Borrowed { + static VALUE: Borrowed = Borrowed {}; + &VALUE + } + } + }; +} + +// Only Borrowed == Owned is implemented +mod borrowed_eq_owned { + impl_types!(); + + impl PartialEq for Borrowed { + fn eq(&self, _: &Owned) -> bool { + true + } + } + + pub fn compare() { + let owned = Owned {}; + let borrowed = Borrowed {}; + + if borrowed.to_owned() == owned {} + if owned == borrowed.to_owned() {} + } +} + +// Only Owned == Borrowed is implemented +mod owned_eq_borrowed { + impl_types!(); + + impl PartialEq for Owned { + fn eq(&self, _: &Borrowed) -> bool { + true + } + } + + fn compare() { + let owned = Owned {}; + let borrowed = Borrowed {}; + + if owned == borrowed.to_owned() {} + if borrowed.to_owned() == owned {} + } +} + +mod issue_4874 { + impl_types!(); + + // NOTE: PartialEq for T can't be implemented due to the orphan rules + impl PartialEq for Borrowed + where + T: AsRef + ?Sized, + { + fn eq(&self, _: &T) -> bool { + true + } + } + + impl std::fmt::Display for Borrowed { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "borrowed") + } + } + + fn compare() { + let borrowed = Borrowed {}; + + if "Hi" == borrowed.to_string() {} + if borrowed.to_string() == "Hi" {} + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.stderr b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.stderr new file mode 100644 index 0000000000000..43bf8851fc620 --- /dev/null +++ b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.stderr @@ -0,0 +1,46 @@ +error: this creates an owned instance just for comparison + --> $DIR/asymmetric_partial_eq.rs:42:12 + | +LL | if borrowed.to_owned() == owned {} + | ^^^^^^^^^^^^^^^^^^^ help: try: `borrowed` + | + = note: `-D clippy::cmp-owned` implied by `-D warnings` + +error: this creates an owned instance just for comparison + --> $DIR/asymmetric_partial_eq.rs:43:21 + | +LL | if owned == borrowed.to_owned() {} + | ---------^^^^^^^^^^^^^^^^^^^ + | | + | help: try: `borrowed == owned` + +error: this creates an owned instance just for comparison + --> $DIR/asymmetric_partial_eq.rs:61:21 + | +LL | if owned == borrowed.to_owned() {} + | ^^^^^^^^^^^^^^^^^^^ help: try: `borrowed` + +error: this creates an owned instance just for comparison + --> $DIR/asymmetric_partial_eq.rs:62:12 + | +LL | if borrowed.to_owned() == owned {} + | ^^^^^^^^^^^^^^^^^^^--------- + | | + | help: try: `owned == borrowed` + +error: this creates an owned instance just for comparison + --> $DIR/asymmetric_partial_eq.rs:88:20 + | +LL | if "Hi" == borrowed.to_string() {} + | --------^^^^^^^^^^^^^^^^^^^^ + | | + | help: try: `borrowed == "Hi"` + +error: this creates an owned instance just for comparison + --> $DIR/asymmetric_partial_eq.rs:89:12 + | +LL | if borrowed.to_string() == "Hi" {} + | ^^^^^^^^^^^^^^^^^^^^ help: try: `borrowed` + +error: aborting due to 6 previous errors + diff --git a/src/tools/clippy/tests/ui/collapsible_else_if.stderr b/src/tools/clippy/tests/ui/collapsible_else_if.stderr index 28048999e8ec9..3d1c458879e58 100644 --- a/src/tools/clippy/tests/ui/collapsible_else_if.stderr +++ b/src/tools/clippy/tests/ui/collapsible_else_if.stderr @@ -10,7 +10,7 @@ LL | | } | |_____^ | = note: `-D clippy::collapsible-if` implied by `-D warnings` -help: try +help: collapse nested if block | LL | } else if y == "world" { LL | println!("world!") @@ -28,7 +28,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | } else if let Some(42) = Some(42) { LL | println!("world!") @@ -48,7 +48,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | } else if y == "world" { LL | println!("world") @@ -71,7 +71,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | } else if let Some(42) = Some(42) { LL | println!("world") @@ -94,7 +94,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | } else if let Some(42) = Some(42) { LL | println!("world") @@ -117,7 +117,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | } else if x == "hello" { LL | println!("world") @@ -140,7 +140,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | } else if let Some(42) = Some(42) { LL | println!("world") diff --git a/src/tools/clippy/tests/ui/collapsible_if.stderr b/src/tools/clippy/tests/ui/collapsible_if.stderr index 6440ff41be81e..f56dd65b9dd26 100644 --- a/src/tools/clippy/tests/ui/collapsible_if.stderr +++ b/src/tools/clippy/tests/ui/collapsible_if.stderr @@ -9,7 +9,7 @@ LL | | } | |_____^ | = note: `-D clippy::collapsible-if` implied by `-D warnings` -help: try +help: collapse nested if block | LL | if x == "hello" && y == "world" { LL | println!("Hello world!"); @@ -26,7 +26,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | if (x == "hello" || x == "world") && (y == "world" || y == "hello") { LL | println!("Hello world!"); @@ -43,7 +43,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | if x == "hello" && x == "world" && (y == "world" || y == "hello") { LL | println!("Hello world!"); @@ -60,7 +60,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | if (x == "hello" || x == "world") && y == "world" && y == "hello" { LL | println!("Hello world!"); @@ -77,7 +77,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | if x == "hello" && x == "world" && y == "world" && y == "hello" { LL | println!("Hello world!"); @@ -94,7 +94,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | if 42 == 1337 && 'a' != 'A' { LL | println!("world!") @@ -111,7 +111,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | if x == "hello" && y == "world" { // Collapsible LL | println!("Hello world!"); diff --git a/src/tools/clippy/tests/ui/deprecated.rs b/src/tools/clippy/tests/ui/deprecated.rs index 188a641aa1af2..3eefb232780f1 100644 --- a/src/tools/clippy/tests/ui/deprecated.rs +++ b/src/tools/clippy/tests/ui/deprecated.rs @@ -7,5 +7,6 @@ #[warn(clippy::invalid_ref)] #[warn(clippy::into_iter_on_array)] #[warn(clippy::unused_label)] +#[warn(clippy::regex_macro)] fn main() {} diff --git a/src/tools/clippy/tests/ui/deprecated.stderr b/src/tools/clippy/tests/ui/deprecated.stderr index a4efe3d15a952..a80e2bf31feb6 100644 --- a/src/tools/clippy/tests/ui/deprecated.stderr +++ b/src/tools/clippy/tests/ui/deprecated.stderr @@ -54,11 +54,17 @@ error: lint `clippy::unused_label` has been removed: `this lint has been uplifte LL | #[warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ +error: lint `clippy::regex_macro` has been removed: `the regex! macro has been removed from the regex crate in 2018` + --> $DIR/deprecated.rs:10:8 + | +LL | #[warn(clippy::regex_macro)] + | ^^^^^^^^^^^^^^^^^^^ + error: lint `clippy::str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon` --> $DIR/deprecated.rs:1:8 | LL | #[warn(clippy::str_to_string)] | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/find_map.rs b/src/tools/clippy/tests/ui/find_map.rs index c28cca144ca3f..88d3b0e749001 100644 --- a/src/tools/clippy/tests/ui/find_map.rs +++ b/src/tools/clippy/tests/ui/find_map.rs @@ -19,6 +19,7 @@ fn main() { let _: Option = a.iter().find(|s| s.parse::().is_ok()).map(|s| s.parse().unwrap()); + #[allow(clippy::match_like_matches_macro)] let _: Option = desserts_of_the_week .iter() .find(|dessert| match *dessert { diff --git a/src/tools/clippy/tests/ui/find_map.stderr b/src/tools/clippy/tests/ui/find_map.stderr index 92f40fe6f1fb2..f279850fef8af 100644 --- a/src/tools/clippy/tests/ui/find_map.stderr +++ b/src/tools/clippy/tests/ui/find_map.stderr @@ -8,7 +8,7 @@ LL | let _: Option = a.iter().find(|s| s.parse::().is_ok()).map(|s = help: this is more succinctly expressed by calling `.find_map(..)` instead error: called `find(p).map(q)` on an `Iterator` - --> $DIR/find_map.rs:22:29 + --> $DIR/find_map.rs:23:29 | LL | let _: Option = desserts_of_the_week | _____________________________^ diff --git a/src/tools/clippy/tests/ui/floating_point_hypot.fixed b/src/tools/clippy/tests/ui/floating_point_hypot.fixed new file mode 100644 index 0000000000000..bbe411b3f4884 --- /dev/null +++ b/src/tools/clippy/tests/ui/floating_point_hypot.fixed @@ -0,0 +1,14 @@ +// run-rustfix +#![warn(clippy::imprecise_flops)] + +fn main() { + let x = 3f32; + let y = 4f32; + let _ = x.hypot(y); + let _ = (x + 1f32).hypot(y); + let _ = x.hypot(y); + // Cases where the lint shouldn't be applied + // TODO: linting this adds some complexity, but could be done + let _ = x.mul_add(x, y * y).sqrt(); + let _ = (x * 4f32 + y * y).sqrt(); +} diff --git a/src/tools/clippy/tests/ui/floating_point_hypot.rs b/src/tools/clippy/tests/ui/floating_point_hypot.rs new file mode 100644 index 0000000000000..586fd170ea145 --- /dev/null +++ b/src/tools/clippy/tests/ui/floating_point_hypot.rs @@ -0,0 +1,14 @@ +// run-rustfix +#![warn(clippy::imprecise_flops)] + +fn main() { + let x = 3f32; + let y = 4f32; + let _ = (x * x + y * y).sqrt(); + let _ = ((x + 1f32) * (x + 1f32) + y * y).sqrt(); + let _ = (x.powi(2) + y.powi(2)).sqrt(); + // Cases where the lint shouldn't be applied + // TODO: linting this adds some complexity, but could be done + let _ = x.mul_add(x, y * y).sqrt(); + let _ = (x * 4f32 + y * y).sqrt(); +} diff --git a/src/tools/clippy/tests/ui/floating_point_hypot.stderr b/src/tools/clippy/tests/ui/floating_point_hypot.stderr new file mode 100644 index 0000000000000..42069d9ee9efb --- /dev/null +++ b/src/tools/clippy/tests/ui/floating_point_hypot.stderr @@ -0,0 +1,22 @@ +error: hypotenuse can be computed more accurately + --> $DIR/floating_point_hypot.rs:7:13 + | +LL | let _ = (x * x + y * y).sqrt(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.hypot(y)` + | + = note: `-D clippy::imprecise-flops` implied by `-D warnings` + +error: hypotenuse can be computed more accurately + --> $DIR/floating_point_hypot.rs:8:13 + | +LL | let _ = ((x + 1f32) * (x + 1f32) + y * y).sqrt(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 1f32).hypot(y)` + +error: hypotenuse can be computed more accurately + --> $DIR/floating_point_hypot.rs:9:13 + | +LL | let _ = (x.powi(2) + y.powi(2)).sqrt(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.hypot(y)` + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/floating_point_log.fixed b/src/tools/clippy/tests/ui/floating_point_log.fixed index 42c5e5d2bae24..7dc7ee94affc0 100644 --- a/src/tools/clippy/tests/ui/floating_point_log.fixed +++ b/src/tools/clippy/tests/ui/floating_point_log.fixed @@ -25,11 +25,11 @@ fn check_ln1p() { let _ = 2.0f32.ln_1p(); let _ = x.ln_1p(); let _ = (x / 2.0).ln_1p(); - let _ = x.powi(2).ln_1p(); - let _ = (x.powi(2) / 2.0).ln_1p(); + let _ = x.powi(3).ln_1p(); + let _ = (x.powi(3) / 2.0).ln_1p(); let _ = ((std::f32::consts::E - 1.0)).ln_1p(); let _ = x.ln_1p(); - let _ = x.powi(2).ln_1p(); + let _ = x.powi(3).ln_1p(); let _ = (x + 2.0).ln_1p(); let _ = (x / 2.0).ln_1p(); // Cases where the lint shouldn't be applied @@ -43,9 +43,9 @@ fn check_ln1p() { let _ = 2.0f64.ln_1p(); let _ = x.ln_1p(); let _ = (x / 2.0).ln_1p(); - let _ = x.powi(2).ln_1p(); + let _ = x.powi(3).ln_1p(); let _ = x.ln_1p(); - let _ = x.powi(2).ln_1p(); + let _ = x.powi(3).ln_1p(); let _ = (x + 2.0).ln_1p(); let _ = (x / 2.0).ln_1p(); // Cases where the lint shouldn't be applied diff --git a/src/tools/clippy/tests/ui/floating_point_log.rs b/src/tools/clippy/tests/ui/floating_point_log.rs index 8be0d9ad56fc3..01181484e7dee 100644 --- a/src/tools/clippy/tests/ui/floating_point_log.rs +++ b/src/tools/clippy/tests/ui/floating_point_log.rs @@ -25,11 +25,11 @@ fn check_ln1p() { let _ = (1f32 + 2.0).ln(); let _ = (1.0 + x).ln(); let _ = (1.0 + x / 2.0).ln(); - let _ = (1.0 + x.powi(2)).ln(); - let _ = (1.0 + x.powi(2) / 2.0).ln(); + let _ = (1.0 + x.powi(3)).ln(); + let _ = (1.0 + x.powi(3) / 2.0).ln(); let _ = (1.0 + (std::f32::consts::E - 1.0)).ln(); let _ = (x + 1.0).ln(); - let _ = (x.powi(2) + 1.0).ln(); + let _ = (x.powi(3) + 1.0).ln(); let _ = (x + 2.0 + 1.0).ln(); let _ = (x / 2.0 + 1.0).ln(); // Cases where the lint shouldn't be applied @@ -43,9 +43,9 @@ fn check_ln1p() { let _ = (1f64 + 2.0).ln(); let _ = (1.0 + x).ln(); let _ = (1.0 + x / 2.0).ln(); - let _ = (1.0 + x.powi(2)).ln(); + let _ = (1.0 + x.powi(3)).ln(); let _ = (x + 1.0).ln(); - let _ = (x.powi(2) + 1.0).ln(); + let _ = (x.powi(3) + 1.0).ln(); let _ = (x + 2.0 + 1.0).ln(); let _ = (x / 2.0 + 1.0).ln(); // Cases where the lint shouldn't be applied diff --git a/src/tools/clippy/tests/ui/floating_point_log.stderr b/src/tools/clippy/tests/ui/floating_point_log.stderr index 943fbdb0b8323..900dc2b79336a 100644 --- a/src/tools/clippy/tests/ui/floating_point_log.stderr +++ b/src/tools/clippy/tests/ui/floating_point_log.stderr @@ -77,14 +77,14 @@ LL | let _ = (1.0 + x / 2.0).ln(); error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:28:13 | -LL | let _ = (1.0 + x.powi(2)).ln(); - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` +LL | let _ = (1.0 + x.powi(3)).ln(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()` error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:29:13 | -LL | let _ = (1.0 + x.powi(2) / 2.0).ln(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(2) / 2.0).ln_1p()` +LL | let _ = (1.0 + x.powi(3) / 2.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(3) / 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:30:13 @@ -101,8 +101,8 @@ LL | let _ = (x + 1.0).ln(); error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:32:13 | -LL | let _ = (x.powi(2) + 1.0).ln(); - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` +LL | let _ = (x.powi(3) + 1.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()` error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:33:13 @@ -143,8 +143,8 @@ LL | let _ = (1.0 + x / 2.0).ln(); error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:46:13 | -LL | let _ = (1.0 + x.powi(2)).ln(); - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` +LL | let _ = (1.0 + x.powi(3)).ln(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()` error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:47:13 @@ -155,8 +155,8 @@ LL | let _ = (x + 1.0).ln(); error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:48:13 | -LL | let _ = (x.powi(2) + 1.0).ln(); - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` +LL | let _ = (x.powi(3) + 1.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()` error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:49:13 diff --git a/src/tools/clippy/tests/ui/floating_point_logbase.fixed b/src/tools/clippy/tests/ui/floating_point_logbase.fixed new file mode 100644 index 0000000000000..13962a272d455 --- /dev/null +++ b/src/tools/clippy/tests/ui/floating_point_logbase.fixed @@ -0,0 +1,16 @@ +// run-rustfix +#![warn(clippy::suboptimal_flops)] + +fn main() { + let x = 3f32; + let y = 5f32; + let _ = x.log(y); + let _ = x.log(y); + let _ = x.log(y); + let _ = x.log(y); + // Cases where the lint shouldn't be applied + let _ = x.ln() / y.powf(3.2); + let _ = x.powf(3.2) / y.powf(3.2); + let _ = x.powf(3.2) / y.ln(); + let _ = x.log(5f32) / y.log(7f32); +} diff --git a/src/tools/clippy/tests/ui/floating_point_logbase.rs b/src/tools/clippy/tests/ui/floating_point_logbase.rs new file mode 100644 index 0000000000000..26bc20d5370b1 --- /dev/null +++ b/src/tools/clippy/tests/ui/floating_point_logbase.rs @@ -0,0 +1,16 @@ +// run-rustfix +#![warn(clippy::suboptimal_flops)] + +fn main() { + let x = 3f32; + let y = 5f32; + let _ = x.ln() / y.ln(); + let _ = x.log2() / y.log2(); + let _ = x.log10() / y.log10(); + let _ = x.log(5f32) / y.log(5f32); + // Cases where the lint shouldn't be applied + let _ = x.ln() / y.powf(3.2); + let _ = x.powf(3.2) / y.powf(3.2); + let _ = x.powf(3.2) / y.ln(); + let _ = x.log(5f32) / y.log(7f32); +} diff --git a/src/tools/clippy/tests/ui/floating_point_logbase.stderr b/src/tools/clippy/tests/ui/floating_point_logbase.stderr new file mode 100644 index 0000000000000..78354c2f62d43 --- /dev/null +++ b/src/tools/clippy/tests/ui/floating_point_logbase.stderr @@ -0,0 +1,28 @@ +error: log base can be expressed more clearly + --> $DIR/floating_point_logbase.rs:7:13 + | +LL | let _ = x.ln() / y.ln(); + | ^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` + | + = note: `-D clippy::suboptimal-flops` implied by `-D warnings` + +error: log base can be expressed more clearly + --> $DIR/floating_point_logbase.rs:8:13 + | +LL | let _ = x.log2() / y.log2(); + | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` + +error: log base can be expressed more clearly + --> $DIR/floating_point_logbase.rs:9:13 + | +LL | let _ = x.log10() / y.log10(); + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` + +error: log base can be expressed more clearly + --> $DIR/floating_point_logbase.rs:10:13 + | +LL | let _ = x.log(5f32) / y.log(5f32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` + +error: aborting due to 4 previous errors + diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.fixed b/src/tools/clippy/tests/ui/floating_point_mul_add.fixed index e343c37740da5..911700bab0040 100644 --- a/src/tools/clippy/tests/ui/floating_point_mul_add.fixed +++ b/src/tools/clippy/tests/ui/floating_point_mul_add.fixed @@ -18,4 +18,9 @@ fn main() { let _ = a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c)) + c; let _ = 1234.567_f64.mul_add(45.67834_f64, 0.0004_f64); + + let _ = a.mul_add(a, b).sqrt(); + + // Cases where the lint shouldn't be applied + let _ = (a * a + b * b).sqrt(); } diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.rs b/src/tools/clippy/tests/ui/floating_point_mul_add.rs index 810f929c8568b..d202385fc8ae7 100644 --- a/src/tools/clippy/tests/ui/floating_point_mul_add.rs +++ b/src/tools/clippy/tests/ui/floating_point_mul_add.rs @@ -18,4 +18,9 @@ fn main() { let _ = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c; let _ = 1234.567_f64 * 45.67834_f64 + 0.0004_f64; + + let _ = (a * a + b).sqrt(); + + // Cases where the lint shouldn't be applied + let _ = (a * a + b * b).sqrt(); } diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.stderr b/src/tools/clippy/tests/ui/floating_point_mul_add.stderr index 2dfbf562d15fc..ac8d0c0cae068 100644 --- a/src/tools/clippy/tests/ui/floating_point_mul_add.stderr +++ b/src/tools/clippy/tests/ui/floating_point_mul_add.stderr @@ -54,5 +54,11 @@ error: multiply and add expressions can be calculated more efficiently and accur LL | let _ = 1234.567_f64 * 45.67834_f64 + 0.0004_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1234.567_f64.mul_add(45.67834_f64, 0.0004_f64)` -error: aborting due to 9 previous errors +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_mul_add.rs:22:13 + | +LL | let _ = (a * a + b).sqrt(); + | ^^^^^^^^^^^ help: consider using: `a.mul_add(a, b)` + +error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/floating_point_powf.fixed b/src/tools/clippy/tests/ui/floating_point_powf.fixed index 78a9d44829bb1..b0641a100cdc8 100644 --- a/src/tools/clippy/tests/ui/floating_point_powf.fixed +++ b/src/tools/clippy/tests/ui/floating_point_powf.fixed @@ -11,7 +11,7 @@ fn main() { let _ = (-3.1f32).exp(); let _ = x.sqrt(); let _ = x.cbrt(); - let _ = x.powi(2); + let _ = x.powi(3); let _ = x.powi(-2); let _ = x.powi(16_777_215); let _ = x.powi(-16_777_215); @@ -30,7 +30,7 @@ fn main() { let _ = (-3.1f64).exp(); let _ = x.sqrt(); let _ = x.cbrt(); - let _ = x.powi(2); + let _ = x.powi(3); let _ = x.powi(-2); let _ = x.powi(-2_147_483_648); let _ = x.powi(2_147_483_647); diff --git a/src/tools/clippy/tests/ui/floating_point_powf.rs b/src/tools/clippy/tests/ui/floating_point_powf.rs index dbc1cac5cb431..a0a2c973900f4 100644 --- a/src/tools/clippy/tests/ui/floating_point_powf.rs +++ b/src/tools/clippy/tests/ui/floating_point_powf.rs @@ -11,7 +11,7 @@ fn main() { let _ = std::f32::consts::E.powf(-3.1); let _ = x.powf(1.0 / 2.0); let _ = x.powf(1.0 / 3.0); - let _ = x.powf(2.0); + let _ = x.powf(3.0); let _ = x.powf(-2.0); let _ = x.powf(16_777_215.0); let _ = x.powf(-16_777_215.0); @@ -30,7 +30,7 @@ fn main() { let _ = std::f64::consts::E.powf(-3.1); let _ = x.powf(1.0 / 2.0); let _ = x.powf(1.0 / 3.0); - let _ = x.powf(2.0); + let _ = x.powf(3.0); let _ = x.powf(-2.0); let _ = x.powf(-2_147_483_648.0); let _ = x.powf(2_147_483_647.0); diff --git a/src/tools/clippy/tests/ui/floating_point_powf.stderr b/src/tools/clippy/tests/ui/floating_point_powf.stderr index ad5163f0079be..2422eb911e90a 100644 --- a/src/tools/clippy/tests/ui/floating_point_powf.stderr +++ b/src/tools/clippy/tests/ui/floating_point_powf.stderr @@ -53,8 +53,8 @@ LL | let _ = x.powf(1.0 / 3.0); error: exponentiation with integer powers can be computed more efficiently --> $DIR/floating_point_powf.rs:14:13 | -LL | let _ = x.powf(2.0); - | ^^^^^^^^^^^ help: consider using: `x.powi(2)` +LL | let _ = x.powf(3.0); + | ^^^^^^^^^^^ help: consider using: `x.powi(3)` error: exponentiation with integer powers can be computed more efficiently --> $DIR/floating_point_powf.rs:15:13 @@ -125,8 +125,8 @@ LL | let _ = x.powf(1.0 / 3.0); error: exponentiation with integer powers can be computed more efficiently --> $DIR/floating_point_powf.rs:33:13 | -LL | let _ = x.powf(2.0); - | ^^^^^^^^^^^ help: consider using: `x.powi(2)` +LL | let _ = x.powf(3.0); + | ^^^^^^^^^^^ help: consider using: `x.powi(3)` error: exponentiation with integer powers can be computed more efficiently --> $DIR/floating_point_powf.rs:34:13 diff --git a/src/tools/clippy/tests/ui/floating_point_powi.fixed b/src/tools/clippy/tests/ui/floating_point_powi.fixed new file mode 100644 index 0000000000000..56762400593b5 --- /dev/null +++ b/src/tools/clippy/tests/ui/floating_point_powi.fixed @@ -0,0 +1,19 @@ +// run-rustfix +#![warn(clippy::suboptimal_flops)] + +fn main() { + let one = 1; + let x = 3f32; + let _ = x * x; + let _ = x * x; + + let y = 4f32; + let _ = x.mul_add(x, y); + let _ = y.mul_add(y, x); + let _ = x.mul_add(x, y).sqrt(); + let _ = y.mul_add(y, x).sqrt(); + // Cases where the lint shouldn't be applied + let _ = x.powi(3); + let _ = x.powi(one + 1); + let _ = (x.powi(2) + y.powi(2)).sqrt(); +} diff --git a/src/tools/clippy/tests/ui/floating_point_powi.rs b/src/tools/clippy/tests/ui/floating_point_powi.rs new file mode 100644 index 0000000000000..1f800e4628dca --- /dev/null +++ b/src/tools/clippy/tests/ui/floating_point_powi.rs @@ -0,0 +1,19 @@ +// run-rustfix +#![warn(clippy::suboptimal_flops)] + +fn main() { + let one = 1; + let x = 3f32; + let _ = x.powi(2); + let _ = x.powi(1 + 1); + + let y = 4f32; + let _ = x.powi(2) + y; + let _ = x + y.powi(2); + let _ = (x.powi(2) + y).sqrt(); + let _ = (x + y.powi(2)).sqrt(); + // Cases where the lint shouldn't be applied + let _ = x.powi(3); + let _ = x.powi(one + 1); + let _ = (x.powi(2) + y.powi(2)).sqrt(); +} diff --git a/src/tools/clippy/tests/ui/floating_point_powi.stderr b/src/tools/clippy/tests/ui/floating_point_powi.stderr new file mode 100644 index 0000000000000..d5a5f1bcca101 --- /dev/null +++ b/src/tools/clippy/tests/ui/floating_point_powi.stderr @@ -0,0 +1,40 @@ +error: square can be computed more efficiently + --> $DIR/floating_point_powi.rs:7:13 + | +LL | let _ = x.powi(2); + | ^^^^^^^^^ help: consider using: `x * x` + | + = note: `-D clippy::suboptimal-flops` implied by `-D warnings` + +error: square can be computed more efficiently + --> $DIR/floating_point_powi.rs:8:13 + | +LL | let _ = x.powi(1 + 1); + | ^^^^^^^^^^^^^ help: consider using: `x * x` + +error: square can be computed more efficiently + --> $DIR/floating_point_powi.rs:11:13 + | +LL | let _ = x.powi(2) + y; + | ^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)` + +error: square can be computed more efficiently + --> $DIR/floating_point_powi.rs:12:13 + | +LL | let _ = x + y.powi(2); + | ^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)` + +error: square can be computed more efficiently + --> $DIR/floating_point_powi.rs:13:13 + | +LL | let _ = (x.powi(2) + y).sqrt(); + | ^^^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)` + +error: square can be computed more efficiently + --> $DIR/floating_point_powi.rs:14:13 + | +LL | let _ = (x + y.powi(2)).sqrt(); + | ^^^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)` + +error: aborting due to 6 previous errors + diff --git a/src/tools/clippy/tests/ui/floating_point_rad.fixed b/src/tools/clippy/tests/ui/floating_point_rad.fixed new file mode 100644 index 0000000000000..92480c5db8be4 --- /dev/null +++ b/src/tools/clippy/tests/ui/floating_point_rad.fixed @@ -0,0 +1,13 @@ +// run-rustfix +#![warn(clippy::suboptimal_flops)] + +fn main() { + let x = 3f32; + let _ = x.to_degrees(); + let _ = x.to_radians(); + // Cases where the lint shouldn't be applied + let _ = x * 90f32 / std::f32::consts::PI; + let _ = x * std::f32::consts::PI / 90f32; + let _ = x * 180f32 / std::f32::consts::E; + let _ = x * std::f32::consts::E / 180f32; +} diff --git a/src/tools/clippy/tests/ui/floating_point_rad.rs b/src/tools/clippy/tests/ui/floating_point_rad.rs new file mode 100644 index 0000000000000..062e7c3fdc17a --- /dev/null +++ b/src/tools/clippy/tests/ui/floating_point_rad.rs @@ -0,0 +1,13 @@ +// run-rustfix +#![warn(clippy::suboptimal_flops)] + +fn main() { + let x = 3f32; + let _ = x * 180f32 / std::f32::consts::PI; + let _ = x * std::f32::consts::PI / 180f32; + // Cases where the lint shouldn't be applied + let _ = x * 90f32 / std::f32::consts::PI; + let _ = x * std::f32::consts::PI / 90f32; + let _ = x * 180f32 / std::f32::consts::E; + let _ = x * std::f32::consts::E / 180f32; +} diff --git a/src/tools/clippy/tests/ui/floating_point_rad.stderr b/src/tools/clippy/tests/ui/floating_point_rad.stderr new file mode 100644 index 0000000000000..a6ffdca64eefe --- /dev/null +++ b/src/tools/clippy/tests/ui/floating_point_rad.stderr @@ -0,0 +1,16 @@ +error: conversion to degrees can be done more accurately + --> $DIR/floating_point_rad.rs:6:13 + | +LL | let _ = x * 180f32 / std::f32::consts::PI; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_degrees()` + | + = note: `-D clippy::suboptimal-flops` implied by `-D warnings` + +error: conversion to radians can be done more accurately + --> $DIR/floating_point_rad.rs:7:13 + | +LL | let _ = x * std::f32::consts::PI / 180f32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_radians()` + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/map_flatten.fixed b/src/tools/clippy/tests/ui/map_flatten.fixed index 7ac368878ab7e..4171d80f48a3f 100644 --- a/src/tools/clippy/tests/ui/map_flatten.fixed +++ b/src/tools/clippy/tests/ui/map_flatten.fixed @@ -2,6 +2,7 @@ #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::missing_docs_in_private_items)] +#![allow(clippy::map_identity)] fn main() { let _: Vec<_> = vec![5_i8; 6].into_iter().flat_map(|x| 0..x).collect(); diff --git a/src/tools/clippy/tests/ui/map_flatten.rs b/src/tools/clippy/tests/ui/map_flatten.rs index a608601039ce7..16a0fd090ad04 100644 --- a/src/tools/clippy/tests/ui/map_flatten.rs +++ b/src/tools/clippy/tests/ui/map_flatten.rs @@ -2,6 +2,7 @@ #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::missing_docs_in_private_items)] +#![allow(clippy::map_identity)] fn main() { let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); diff --git a/src/tools/clippy/tests/ui/map_flatten.stderr b/src/tools/clippy/tests/ui/map_flatten.stderr index 3cf2abd5b6d85..00bc41c15e9b8 100644 --- a/src/tools/clippy/tests/ui/map_flatten.stderr +++ b/src/tools/clippy/tests/ui/map_flatten.stderr @@ -1,5 +1,5 @@ error: called `map(..).flatten()` on an `Iterator`. This is more succinctly expressed by calling `.flat_map(..)` - --> $DIR/map_flatten.rs:7:21 + --> $DIR/map_flatten.rs:8:21 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `flat_map` instead: `vec![5_i8; 6].into_iter().flat_map(|x| 0..x)` @@ -7,7 +7,7 @@ LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().colle = note: `-D clippy::map-flatten` implied by `-D warnings` error: called `map(..).flatten()` on an `Option`. This is more succinctly expressed by calling `.and_then(..)` - --> $DIR/map_flatten.rs:8:24 + --> $DIR/map_flatten.rs:9:24 | LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `(Some(Some(1))).and_then(|x| x)` diff --git a/src/tools/clippy/tests/ui/map_identity.fixed b/src/tools/clippy/tests/ui/map_identity.fixed new file mode 100644 index 0000000000000..4a1452b25f343 --- /dev/null +++ b/src/tools/clippy/tests/ui/map_identity.fixed @@ -0,0 +1,23 @@ +// run-rustfix +#![warn(clippy::map_identity)] +#![allow(clippy::needless_return)] + +fn main() { + let x: [u16; 3] = [1, 2, 3]; + // should lint + let _: Vec<_> = x.iter().map(not_identity).collect(); + let _: Vec<_> = x.iter().collect(); + let _: Option = Some(3); + let _: Result = Ok(-3); + // should not lint + let _: Vec<_> = x.iter().map(|x| 2 * x).collect(); + let _: Vec<_> = x.iter().map(not_identity).map(|x| return x - 4).collect(); + let _: Option = None.map(|x: u8| x - 1); + let _: Result = Err(2.3).map(|x: i8| { + return x + 3; + }); +} + +fn not_identity(x: &u16) -> u16 { + *x +} diff --git a/src/tools/clippy/tests/ui/map_identity.rs b/src/tools/clippy/tests/ui/map_identity.rs new file mode 100644 index 0000000000000..65c7e6e1ea554 --- /dev/null +++ b/src/tools/clippy/tests/ui/map_identity.rs @@ -0,0 +1,25 @@ +// run-rustfix +#![warn(clippy::map_identity)] +#![allow(clippy::needless_return)] + +fn main() { + let x: [u16; 3] = [1, 2, 3]; + // should lint + let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect(); + let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect(); + let _: Option = Some(3).map(|x| x); + let _: Result = Ok(-3).map(|x| { + return x; + }); + // should not lint + let _: Vec<_> = x.iter().map(|x| 2 * x).collect(); + let _: Vec<_> = x.iter().map(not_identity).map(|x| return x - 4).collect(); + let _: Option = None.map(|x: u8| x - 1); + let _: Result = Err(2.3).map(|x: i8| { + return x + 3; + }); +} + +fn not_identity(x: &u16) -> u16 { + *x +} diff --git a/src/tools/clippy/tests/ui/map_identity.stderr b/src/tools/clippy/tests/ui/map_identity.stderr new file mode 100644 index 0000000000000..e4a0320cbda55 --- /dev/null +++ b/src/tools/clippy/tests/ui/map_identity.stderr @@ -0,0 +1,37 @@ +error: unnecessary map of the identity function + --> $DIR/map_identity.rs:8:47 + | +LL | let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect(); + | ^^^^^^^^^^^^^^^^^^ help: remove the call to `map` + | + = note: `-D clippy::map-identity` implied by `-D warnings` + +error: unnecessary map of the identity function + --> $DIR/map_identity.rs:9:57 + | +LL | let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect(); + | ^^^^^^^^^^^ help: remove the call to `map` + +error: unnecessary map of the identity function + --> $DIR/map_identity.rs:9:29 + | +LL | let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` + +error: unnecessary map of the identity function + --> $DIR/map_identity.rs:10:32 + | +LL | let _: Option = Some(3).map(|x| x); + | ^^^^^^^^^^^ help: remove the call to `map` + +error: unnecessary map of the identity function + --> $DIR/map_identity.rs:11:36 + | +LL | let _: Result = Ok(-3).map(|x| { + | ____________________________________^ +LL | | return x; +LL | | }); + | |______^ help: remove the call to `map` + +error: aborting due to 5 previous errors + diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed new file mode 100644 index 0000000000000..f3e19092480ad --- /dev/null +++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed @@ -0,0 +1,36 @@ +// run-rustfix + +#![warn(clippy::match_like_matches_macro)] +#![allow(unreachable_patterns)] + +fn main() { + let x = Some(5); + + // Lint + let _y = matches!(x, Some(0)); + + // Lint + let _w = matches!(x, Some(_)); + + // Turn into is_none + let _z = x.is_none(); + + // Lint + let _zz = !matches!(x, Some(r) if r == 0); + + // Lint + let _zzz = matches!(x, Some(5)); + + // No lint + let _a = match x { + Some(_) => false, + _ => false, + }; + + // No lint + let _ab = match x { + Some(0) => false, + _ => true, + None => false, + }; +} diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs new file mode 100644 index 0000000000000..fbae7c18b9239 --- /dev/null +++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs @@ -0,0 +1,48 @@ +// run-rustfix + +#![warn(clippy::match_like_matches_macro)] +#![allow(unreachable_patterns)] + +fn main() { + let x = Some(5); + + // Lint + let _y = match x { + Some(0) => true, + _ => false, + }; + + // Lint + let _w = match x { + Some(_) => true, + _ => false, + }; + + // Turn into is_none + let _z = match x { + Some(_) => false, + None => true, + }; + + // Lint + let _zz = match x { + Some(r) if r == 0 => false, + _ => true, + }; + + // Lint + let _zzz = if let Some(5) = x { true } else { false }; + + // No lint + let _a = match x { + Some(_) => false, + _ => false, + }; + + // No lint + let _ab = match x { + Some(0) => false, + _ => true, + None => false, + }; +} diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr new file mode 100644 index 0000000000000..4668f8565a656 --- /dev/null +++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr @@ -0,0 +1,52 @@ +error: match expression looks like `matches!` macro + --> $DIR/match_expr_like_matches_macro.rs:10:14 + | +LL | let _y = match x { + | ______________^ +LL | | Some(0) => true, +LL | | _ => false, +LL | | }; + | |_____^ help: try this: `matches!(x, Some(0))` + | + = note: `-D clippy::match-like-matches-macro` implied by `-D warnings` + +error: match expression looks like `matches!` macro + --> $DIR/match_expr_like_matches_macro.rs:16:14 + | +LL | let _w = match x { + | ______________^ +LL | | Some(_) => true, +LL | | _ => false, +LL | | }; + | |_____^ help: try this: `matches!(x, Some(_))` + +error: redundant pattern matching, consider using `is_none()` + --> $DIR/match_expr_like_matches_macro.rs:22:14 + | +LL | let _z = match x { + | ______________^ +LL | | Some(_) => false, +LL | | None => true, +LL | | }; + | |_____^ help: try this: `x.is_none()` + | + = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` + +error: match expression looks like `matches!` macro + --> $DIR/match_expr_like_matches_macro.rs:28:15 + | +LL | let _zz = match x { + | _______________^ +LL | | Some(r) if r == 0 => false, +LL | | _ => true, +LL | | }; + | |_____^ help: try this: `!matches!(x, Some(r) if r == 0)` + +error: if let .. else expression looks like `matches!` macro + --> $DIR/match_expr_like_matches_macro.rs:34:16 + | +LL | let _zzz = if let Some(5) = x { true } else { false }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `matches!(x, Some(5))` + +error: aborting due to 5 previous errors + diff --git a/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.rs b/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.rs index 0b47119527247..2d392c593b3e7 100644 --- a/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.rs +++ b/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.rs @@ -4,7 +4,7 @@ use std::cmp::Ordering; -#[allow(clippy::unnested_or_patterns)] +#[allow(clippy::unnested_or_patterns, clippy::match_like_matches_macro)] #[warn(clippy::neg_cmp_op_on_partial_ord)] fn main() { let a_value = 1.0; diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed new file mode 100644 index 0000000000000..695a460cc4edf --- /dev/null +++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed @@ -0,0 +1,74 @@ +// run-rustfix +#![warn(clippy::option_if_let_else)] + +fn bad1(string: Option<&str>) -> (bool, &str) { + string.map_or((false, "hello"), |x| (true, x)) +} + +fn else_if_option(string: Option<&str>) -> Option<(bool, &str)> { + if string.is_none() { + None + } else { string.map_or(Some((false, "")), |x| Some((true, x))) } +} + +fn unop_bad(string: &Option<&str>, mut num: Option) { + let _ = string.map_or(0, |s| s.len()); + let _ = num.as_ref().map_or(&0, |s| s); + let _ = num.as_mut().map_or(&mut 0, |s| { + *s += 1; + s + }); + let _ = num.as_ref().map_or(&0, |s| s); + let _ = num.map_or(0, |mut s| { + s += 1; + s + }); + let _ = num.as_mut().map_or(&mut 0, |s| { + *s += 1; + s + }); +} + +fn longer_body(arg: Option) -> u32 { + arg.map_or(13, |x| { + let y = x * x; + y * y + }) +} + +fn test_map_or_else(arg: Option) { + let _ = arg.map_or_else(|| { + let mut y = 1; + y = (y + 2 / y) / 2; + y = (y + 2 / y) / 2; + y + }, |x| x * x * x * x); +} + +fn negative_tests(arg: Option) -> u32 { + let _ = if let Some(13) = arg { "unlucky" } else { "lucky" }; + for _ in 0..10 { + let _ = if let Some(x) = arg { + x + } else { + continue; + }; + } + let _ = if let Some(x) = arg { + return x; + } else { + 5 + }; + 7 +} + +fn main() { + let optional = Some(5); + let _ = optional.map_or(5, |x| x + 2); + let _ = bad1(None); + let _ = else_if_option(None); + unop_bad(&None, None); + let _ = longer_body(None); + test_map_or_else(None); + let _ = negative_tests(None); +} diff --git a/src/tools/clippy/tests/ui/option_if_let_else.rs b/src/tools/clippy/tests/ui/option_if_let_else.rs new file mode 100644 index 0000000000000..dee80d26bd976 --- /dev/null +++ b/src/tools/clippy/tests/ui/option_if_let_else.rs @@ -0,0 +1,92 @@ +// run-rustfix +#![warn(clippy::option_if_let_else)] + +fn bad1(string: Option<&str>) -> (bool, &str) { + if let Some(x) = string { + (true, x) + } else { + (false, "hello") + } +} + +fn else_if_option(string: Option<&str>) -> Option<(bool, &str)> { + if string.is_none() { + None + } else if let Some(x) = string { + Some((true, x)) + } else { + Some((false, "")) + } +} + +fn unop_bad(string: &Option<&str>, mut num: Option) { + let _ = if let Some(s) = *string { s.len() } else { 0 }; + let _ = if let Some(s) = &num { s } else { &0 }; + let _ = if let Some(s) = &mut num { + *s += 1; + s + } else { + &mut 0 + }; + let _ = if let Some(ref s) = num { s } else { &0 }; + let _ = if let Some(mut s) = num { + s += 1; + s + } else { + 0 + }; + let _ = if let Some(ref mut s) = num { + *s += 1; + s + } else { + &mut 0 + }; +} + +fn longer_body(arg: Option) -> u32 { + if let Some(x) = arg { + let y = x * x; + y * y + } else { + 13 + } +} + +fn test_map_or_else(arg: Option) { + let _ = if let Some(x) = arg { + x * x * x * x + } else { + let mut y = 1; + y = (y + 2 / y) / 2; + y = (y + 2 / y) / 2; + y + }; +} + +fn negative_tests(arg: Option) -> u32 { + let _ = if let Some(13) = arg { "unlucky" } else { "lucky" }; + for _ in 0..10 { + let _ = if let Some(x) = arg { + x + } else { + continue; + }; + } + let _ = if let Some(x) = arg { + return x; + } else { + 5 + }; + 7 +} + +fn main() { + let optional = Some(5); + let _ = if let Some(x) = optional { x + 2 } else { 5 }; + let _ = bad1(None); + let _ = else_if_option(None); + unop_bad(&None, None); + let _ = longer_body(None); + test_map_or_else(None); + let _ = negative_tests(None); +} diff --git a/src/tools/clippy/tests/ui/option_if_let_else.stderr b/src/tools/clippy/tests/ui/option_if_let_else.stderr new file mode 100644 index 0000000000000..7005850efaf83 --- /dev/null +++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr @@ -0,0 +1,151 @@ +error: use Option::map_or instead of an if let/else + --> $DIR/option_if_let_else.rs:5:5 + | +LL | / if let Some(x) = string { +LL | | (true, x) +LL | | } else { +LL | | (false, "hello") +LL | | } + | |_____^ help: try: `string.map_or((false, "hello"), |x| (true, x))` + | + = note: `-D clippy::option-if-let-else` implied by `-D warnings` + +error: use Option::map_or instead of an if let/else + --> $DIR/option_if_let_else.rs:15:12 + | +LL | } else if let Some(x) = string { + | ____________^ +LL | | Some((true, x)) +LL | | } else { +LL | | Some((false, "")) +LL | | } + | |_____^ help: try: `{ string.map_or(Some((false, "")), |x| Some((true, x))) }` + +error: use Option::map_or instead of an if let/else + --> $DIR/option_if_let_else.rs:23:13 + | +LL | let _ = if let Some(s) = *string { s.len() } else { 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())` + +error: use Option::map_or instead of an if let/else + --> $DIR/option_if_let_else.rs:24:13 + | +LL | let _ = if let Some(s) = &num { s } else { &0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` + +error: use Option::map_or instead of an if let/else + --> $DIR/option_if_let_else.rs:25:13 + | +LL | let _ = if let Some(s) = &mut num { + | _____________^ +LL | | *s += 1; +LL | | s +LL | | } else { +LL | | &mut 0 +LL | | }; + | |_____^ + | +help: try + | +LL | let _ = num.as_mut().map_or(&mut 0, |s| { +LL | *s += 1; +LL | s +LL | }); + | + +error: use Option::map_or instead of an if let/else + --> $DIR/option_if_let_else.rs:31:13 + | +LL | let _ = if let Some(ref s) = num { s } else { &0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` + +error: use Option::map_or instead of an if let/else + --> $DIR/option_if_let_else.rs:32:13 + | +LL | let _ = if let Some(mut s) = num { + | _____________^ +LL | | s += 1; +LL | | s +LL | | } else { +LL | | 0 +LL | | }; + | |_____^ + | +help: try + | +LL | let _ = num.map_or(0, |mut s| { +LL | s += 1; +LL | s +LL | }); + | + +error: use Option::map_or instead of an if let/else + --> $DIR/option_if_let_else.rs:38:13 + | +LL | let _ = if let Some(ref mut s) = num { + | _____________^ +LL | | *s += 1; +LL | | s +LL | | } else { +LL | | &mut 0 +LL | | }; + | |_____^ + | +help: try + | +LL | let _ = num.as_mut().map_or(&mut 0, |s| { +LL | *s += 1; +LL | s +LL | }); + | + +error: use Option::map_or instead of an if let/else + --> $DIR/option_if_let_else.rs:47:5 + | +LL | / if let Some(x) = arg { +LL | | let y = x * x; +LL | | y * y +LL | | } else { +LL | | 13 +LL | | } + | |_____^ + | +help: try + | +LL | arg.map_or(13, |x| { +LL | let y = x * x; +LL | y * y +LL | }) + | + +error: use Option::map_or_else instead of an if let/else + --> $DIR/option_if_let_else.rs:56:13 + | +LL | let _ = if let Some(x) = arg { + | _____________^ +LL | | x * x * x * x +LL | | } else { +LL | | let mut y = 1; +... | +LL | | y +LL | | }; + | |_____^ + | +help: try + | +LL | let _ = arg.map_or_else(|| { +LL | let mut y = 1; +LL | y = (y + 2 / y) / 2; +LL | y = (y + 2 / y) / 2; +LL | y +LL | }, |x| x * x * x * x); + | + +error: use Option::map_or instead of an if let/else + --> $DIR/option_if_let_else.rs:85:13 + | +LL | let _ = if let Some(x) = optional { x + 2 } else { 5 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)` + +error: aborting due to 11 previous errors + diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.rs new file mode 100644 index 0000000000000..9b4f2f1f57934 --- /dev/null +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.rs @@ -0,0 +1,40 @@ +#![allow(clippy::all)] +#![warn(clippy::pattern_type_mismatch)] + +fn main() {} + +fn should_lint() { + let value = &Some(23); + match value { + Some(_) => (), + _ => (), + } + + let value = &mut Some(23); + match value { + Some(_) => (), + _ => (), + } +} + +fn should_not_lint() { + let value = &Some(23); + match value { + &Some(_) => (), + _ => (), + } + match *value { + Some(_) => (), + _ => (), + } + + let value = &mut Some(23); + match value { + &mut Some(_) => (), + _ => (), + } + match *value { + Some(_) => (), + _ => (), + } +} diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.stderr new file mode 100644 index 0000000000000..3421d568365cc --- /dev/null +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.stderr @@ -0,0 +1,19 @@ +error: type of pattern does not match the expression type + --> $DIR/mutability.rs:9:9 + | +LL | Some(_) => (), + | ^^^^^^^ + | + = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/mutability.rs:15:9 + | +LL | Some(_) => (), + | ^^^^^^^ + | + = help: use `*` to dereference the match expression or explicitly match against a `&mut _` pattern and adjust the enclosed variable bindings + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.rs new file mode 100644 index 0000000000000..065ea9fb9b5a4 --- /dev/null +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.rs @@ -0,0 +1,24 @@ +#![allow(clippy::all)] +#![warn(clippy::pattern_type_mismatch)] + +fn main() {} + +fn alternatives() { + enum Value<'a> { + Unused, + A(&'a Option), + B, + } + let ref_value = &Value::A(&Some(23)); + + // not ok + if let Value::B | Value::A(_) = ref_value {} + if let &Value::B | &Value::A(Some(_)) = ref_value {} + if let Value::B | Value::A(Some(_)) = *ref_value {} + + // ok + if let &Value::B | &Value::A(_) = ref_value {} + if let Value::B | Value::A(_) = *ref_value {} + if let &Value::B | &Value::A(&Some(_)) = ref_value {} + if let Value::B | Value::A(&Some(_)) = *ref_value {} +} diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr new file mode 100644 index 0000000000000..d285c93782c67 --- /dev/null +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr @@ -0,0 +1,27 @@ +error: type of pattern does not match the expression type + --> $DIR/pattern_alternatives.rs:15:12 + | +LL | if let Value::B | Value::A(_) = ref_value {} + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_alternatives.rs:16:34 + | +LL | if let &Value::B | &Value::A(Some(_)) = ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_alternatives.rs:17:32 + | +LL | if let Value::B | Value::A(Some(_)) = *ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.rs new file mode 100644 index 0000000000000..417b1c107c55b --- /dev/null +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.rs @@ -0,0 +1,45 @@ +#![allow(clippy::all)] +#![warn(clippy::pattern_type_mismatch)] + +fn main() {} + +fn struct_types() { + struct Struct<'a> { + ref_inner: &'a Option, + } + let ref_value = &Struct { ref_inner: &Some(42) }; + + // not ok + let Struct { .. } = ref_value; + if let &Struct { ref_inner: Some(_) } = ref_value {} + if let Struct { ref_inner: Some(_) } = *ref_value {} + + // ok + let &Struct { .. } = ref_value; + let Struct { .. } = *ref_value; + if let &Struct { ref_inner: &Some(_) } = ref_value {} + if let Struct { ref_inner: &Some(_) } = *ref_value {} +} + +fn struct_enum_variants() { + enum StructEnum<'a> { + Empty, + Var { inner_ref: &'a Option }, + } + let ref_value = &StructEnum::Var { inner_ref: &Some(42) }; + + // not ok + if let StructEnum::Var { .. } = ref_value {} + if let StructEnum::Var { inner_ref: Some(_) } = ref_value {} + if let &StructEnum::Var { inner_ref: Some(_) } = ref_value {} + if let StructEnum::Var { inner_ref: Some(_) } = *ref_value {} + if let StructEnum::Empty = ref_value {} + + // ok + if let &StructEnum::Var { .. } = ref_value {} + if let StructEnum::Var { .. } = *ref_value {} + if let &StructEnum::Var { inner_ref: &Some(_) } = ref_value {} + if let StructEnum::Var { inner_ref: &Some(_) } = *ref_value {} + if let &StructEnum::Empty = ref_value {} + if let StructEnum::Empty = *ref_value {} +} diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.stderr new file mode 100644 index 0000000000000..d428e85b0c914 --- /dev/null +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.stderr @@ -0,0 +1,67 @@ +error: type of pattern does not match the expression type + --> $DIR/pattern_structs.rs:13:9 + | +LL | let Struct { .. } = ref_value; + | ^^^^^^^^^^^^^ + | + = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_structs.rs:14:33 + | +LL | if let &Struct { ref_inner: Some(_) } = ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_structs.rs:15:32 + | +LL | if let Struct { ref_inner: Some(_) } = *ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_structs.rs:32:12 + | +LL | if let StructEnum::Var { .. } = ref_value {} + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_structs.rs:33:12 + | +LL | if let StructEnum::Var { inner_ref: Some(_) } = ref_value {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_structs.rs:34:42 + | +LL | if let &StructEnum::Var { inner_ref: Some(_) } = ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_structs.rs:35:41 + | +LL | if let StructEnum::Var { inner_ref: Some(_) } = *ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_structs.rs:36:12 + | +LL | if let StructEnum::Empty = ref_value {} + | ^^^^^^^^^^^^^^^^^ + | + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: aborting due to 8 previous errors + diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.rs new file mode 100644 index 0000000000000..19504a051d8b1 --- /dev/null +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.rs @@ -0,0 +1,57 @@ +#![allow(clippy::all)] +#![warn(clippy::pattern_type_mismatch)] + +fn main() {} + +fn tuple_types() { + struct TupleStruct<'a>(&'a Option); + let ref_value = &TupleStruct(&Some(42)); + + // not ok + let TupleStruct(_) = ref_value; + if let &TupleStruct(Some(_)) = ref_value {} + if let TupleStruct(Some(_)) = *ref_value {} + + // ok + let &TupleStruct(_) = ref_value; + let TupleStruct(_) = *ref_value; + if let &TupleStruct(&Some(_)) = ref_value {} + if let TupleStruct(&Some(_)) = *ref_value {} +} + +fn tuple_enum_variants() { + enum TupleEnum<'a> { + Empty, + Var(&'a Option), + } + let ref_value = &TupleEnum::Var(&Some(42)); + + // not ok + if let TupleEnum::Var(_) = ref_value {} + if let &TupleEnum::Var(Some(_)) = ref_value {} + if let TupleEnum::Var(Some(_)) = *ref_value {} + if let TupleEnum::Empty = ref_value {} + + // ok + if let &TupleEnum::Var(_) = ref_value {} + if let TupleEnum::Var(_) = *ref_value {} + if let &TupleEnum::Var(&Some(_)) = ref_value {} + if let TupleEnum::Var(&Some(_)) = *ref_value {} + if let &TupleEnum::Empty = ref_value {} + if let TupleEnum::Empty = *ref_value {} +} + +fn plain_tuples() { + let ref_value = &(&Some(23), &Some(42)); + + // not ok + let (_a, _b) = ref_value; + if let &(_a, Some(_)) = ref_value {} + if let (_a, Some(_)) = *ref_value {} + + // ok + let &(_a, _b) = ref_value; + let (_a, _b) = *ref_value; + if let &(_a, &Some(_)) = ref_value {} + if let (_a, &Some(_)) = *ref_value {} +} diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.stderr new file mode 100644 index 0000000000000..edd0074d00d3b --- /dev/null +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.stderr @@ -0,0 +1,83 @@ +error: type of pattern does not match the expression type + --> $DIR/pattern_tuples.rs:11:9 + | +LL | let TupleStruct(_) = ref_value; + | ^^^^^^^^^^^^^^ + | + = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_tuples.rs:12:25 + | +LL | if let &TupleStruct(Some(_)) = ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_tuples.rs:13:24 + | +LL | if let TupleStruct(Some(_)) = *ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_tuples.rs:30:12 + | +LL | if let TupleEnum::Var(_) = ref_value {} + | ^^^^^^^^^^^^^^^^^ + | + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_tuples.rs:31:28 + | +LL | if let &TupleEnum::Var(Some(_)) = ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_tuples.rs:32:27 + | +LL | if let TupleEnum::Var(Some(_)) = *ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_tuples.rs:33:12 + | +LL | if let TupleEnum::Empty = ref_value {} + | ^^^^^^^^^^^^^^^^ + | + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_tuples.rs:48:9 + | +LL | let (_a, _b) = ref_value; + | ^^^^^^^^ + | + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_tuples.rs:49:18 + | +LL | if let &(_a, Some(_)) = ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_tuples.rs:50:17 + | +LL | if let (_a, Some(_)) = *ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: aborting due to 10 previous errors + diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.rs new file mode 100644 index 0000000000000..e89917c41e8c1 --- /dev/null +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.rs @@ -0,0 +1,146 @@ +#![allow(clippy::all)] +#![warn(clippy::pattern_type_mismatch)] + +fn main() {} + +fn syntax_match() { + let ref_value = &Some(&Some(42)); + + // not ok + match ref_value { + Some(_) => (), + None => (), + } + + // ok + match ref_value { + &Some(_) => (), + &None => (), + } + match *ref_value { + Some(_) => (), + None => (), + } +} + +fn syntax_if_let() { + let ref_value = &Some(42); + + // not ok + if let Some(_) = ref_value {} + + // ok + if let &Some(_) = ref_value {} + if let Some(_) = *ref_value {} +} + +fn syntax_while_let() { + let ref_value = &Some(42); + + // not ok + while let Some(_) = ref_value { + break; + } + + // ok + while let &Some(_) = ref_value { + break; + } + while let Some(_) = *ref_value { + break; + } +} + +fn syntax_for() { + let ref_value = &Some(23); + let slice = &[(2, 3), (4, 2)]; + + // not ok + for (_a, _b) in slice.iter() {} + + // ok + for &(_a, _b) in slice.iter() {} +} + +fn syntax_let() { + let ref_value = &(2, 3); + + // not ok + let (_n, _m) = ref_value; + + // ok + let &(_n, _m) = ref_value; + let (_n, _m) = *ref_value; +} + +fn syntax_fn() { + // not ok + fn foo((_a, _b): &(i32, i32)) {} + + // ok + fn foo_ok_1(&(_a, _b): &(i32, i32)) {} +} + +fn syntax_closure() { + fn foo(f: F) + where + F: FnOnce(&(i32, i32)), + { + } + + // not ok + foo(|(_a, _b)| ()); + + // ok + foo(|&(_a, _b)| ()); +} + +fn macro_with_expression() { + macro_rules! matching_macro { + ($e:expr) => { + $e + }; + } + let value = &Some(23); + + // not ok + matching_macro!(match value { + Some(_) => (), + _ => (), + }); + + // ok + matching_macro!(match value { + &Some(_) => (), + _ => (), + }); + matching_macro!(match *value { + Some(_) => (), + _ => (), + }); +} + +fn macro_expansion() { + macro_rules! matching_macro { + ($e:expr) => { + // not ok + match $e { + Some(_) => (), + _ => (), + } + + // ok + match $e { + &Some(_) => (), + _ => (), + } + match *$e { + Some(_) => (), + _ => (), + } + }; + } + + let value = &Some(23); + matching_macro!(value); +} diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr new file mode 100644 index 0000000000000..5a5186bd4fcb3 --- /dev/null +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr @@ -0,0 +1,79 @@ +error: type of pattern does not match the expression type + --> $DIR/syntax.rs:11:9 + | +LL | Some(_) => (), + | ^^^^^^^ + | + = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/syntax.rs:30:12 + | +LL | if let Some(_) = ref_value {} + | ^^^^^^^ + | + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/syntax.rs:41:15 + | +LL | while let Some(_) = ref_value { + | ^^^^^^^ + | + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/syntax.rs:59:9 + | +LL | for (_a, _b) in slice.iter() {} + | ^^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/syntax.rs:69:9 + | +LL | let (_n, _m) = ref_value; + | ^^^^^^^^ + | + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/syntax.rs:78:12 + | +LL | fn foo((_a, _b): &(i32, i32)) {} + | ^^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/syntax.rs:92:10 + | +LL | foo(|(_a, _b)| ()); + | ^^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/syntax.rs:108:9 + | +LL | Some(_) => (), + | ^^^^^^^ + | + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/syntax.rs:128:17 + | +LL | Some(_) => (), + | ^^^^^^^ +... +LL | matching_macro!(value); + | ----------------------- in this macro invocation + | + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 9 previous errors + diff --git a/src/tools/clippy/tests/ui/range_plus_minus_one.fixed b/src/tools/clippy/tests/ui/range_plus_minus_one.fixed index 6b40211409974..19b253b0fe2c6 100644 --- a/src/tools/clippy/tests/ui/range_plus_minus_one.fixed +++ b/src/tools/clippy/tests/ui/range_plus_minus_one.fixed @@ -7,6 +7,7 @@ fn f() -> usize { } #[warn(clippy::range_plus_one)] +#[warn(clippy::range_minus_one)] fn main() { for _ in 0..2 {} for _ in 0..=2 {} diff --git a/src/tools/clippy/tests/ui/range_plus_minus_one.rs b/src/tools/clippy/tests/ui/range_plus_minus_one.rs index 3cfed4125b35c..7d034117547ca 100644 --- a/src/tools/clippy/tests/ui/range_plus_minus_one.rs +++ b/src/tools/clippy/tests/ui/range_plus_minus_one.rs @@ -7,6 +7,7 @@ fn f() -> usize { } #[warn(clippy::range_plus_one)] +#[warn(clippy::range_minus_one)] fn main() { for _ in 0..2 {} for _ in 0..=2 {} diff --git a/src/tools/clippy/tests/ui/range_plus_minus_one.stderr b/src/tools/clippy/tests/ui/range_plus_minus_one.stderr index f72943a04f252..fb4f1658597a5 100644 --- a/src/tools/clippy/tests/ui/range_plus_minus_one.stderr +++ b/src/tools/clippy/tests/ui/range_plus_minus_one.stderr @@ -1,5 +1,5 @@ error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:14:14 + --> $DIR/range_plus_minus_one.rs:15:14 | LL | for _ in 0..3 + 1 {} | ^^^^^^^^ help: use: `0..=3` @@ -7,25 +7,25 @@ LL | for _ in 0..3 + 1 {} = note: `-D clippy::range-plus-one` implied by `-D warnings` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:17:14 + --> $DIR/range_plus_minus_one.rs:18:14 | LL | for _ in 0..1 + 5 {} | ^^^^^^^^ help: use: `0..=5` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:20:14 + --> $DIR/range_plus_minus_one.rs:21:14 | LL | for _ in 1..1 + 1 {} | ^^^^^^^^ help: use: `1..=1` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:26:14 + --> $DIR/range_plus_minus_one.rs:27:14 | LL | for _ in 0..(1 + f()) {} | ^^^^^^^^^^^^ help: use: `0..=f()` error: an exclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:30:13 + --> $DIR/range_plus_minus_one.rs:31:13 | LL | let _ = ..=11 - 1; | ^^^^^^^^^ help: use: `..11` @@ -33,25 +33,25 @@ LL | let _ = ..=11 - 1; = note: `-D clippy::range-minus-one` implied by `-D warnings` error: an exclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:31:13 + --> $DIR/range_plus_minus_one.rs:32:13 | LL | let _ = ..=(11 - 1); | ^^^^^^^^^^^ help: use: `..11` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:32:13 + --> $DIR/range_plus_minus_one.rs:33:13 | LL | let _ = (1..11 + 1); | ^^^^^^^^^^^ help: use: `(1..=11)` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:33:13 + --> $DIR/range_plus_minus_one.rs:34:13 | LL | let _ = (f() + 1)..(f() + 1); | ^^^^^^^^^^^^^^^^^^^^ help: use: `((f() + 1)..=f())` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:37:14 + --> $DIR/range_plus_minus_one.rs:38:14 | LL | for _ in 1..ONE + ONE {} | ^^^^^^^^^^^^ help: use: `1..=ONE` diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching.fixed index 8b4e2d21331cd..ce8582d2b221c 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching.fixed @@ -2,7 +2,13 @@ #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] -#![allow(clippy::unit_arg, unused_must_use, clippy::needless_bool, deprecated)] +#![allow( + clippy::unit_arg, + unused_must_use, + clippy::needless_bool, + clippy::match_like_matches_macro, + deprecated +)] fn main() { if Ok::(42).is_ok() {} diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching.rs index b0904e41b6f43..a3a9aa40e3b9c 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching.rs +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching.rs @@ -2,7 +2,13 @@ #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] -#![allow(clippy::unit_arg, unused_must_use, clippy::needless_bool, deprecated)] +#![allow( + clippy::unit_arg, + unused_must_use, + clippy::needless_bool, + clippy::match_like_matches_macro, + deprecated +)] fn main() { if let Ok(_) = Ok::(42) {} diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching.stderr index 51a6f4350d32c..25d1476062e7f 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:8:12 + --> $DIR/redundant_pattern_matching.rs:14:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` @@ -7,67 +7,67 @@ LL | if let Ok(_) = Ok::(42) {} = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:10:12 + --> $DIR/redundant_pattern_matching.rs:16:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:12:12 + --> $DIR/redundant_pattern_matching.rs:18:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try this: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:14:12 + --> $DIR/redundant_pattern_matching.rs:20:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:16:12 + --> $DIR/redundant_pattern_matching.rs:22:12 | LL | if let Some(_) = Some(42) { | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:22:15 + --> $DIR/redundant_pattern_matching.rs:28:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:24:15 + --> $DIR/redundant_pattern_matching.rs:30:15 | LL | while let None = Some(42) {} | ----------^^^^----------- help: try this: `while Some(42).is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:26:15 + --> $DIR/redundant_pattern_matching.rs:32:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try this: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:28:15 + --> $DIR/redundant_pattern_matching.rs:34:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:30:15 + --> $DIR/redundant_pattern_matching.rs:36:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:33:15 + --> $DIR/redundant_pattern_matching.rs:39:15 | LL | while let Some(_) = v.pop() { | ----------^^^^^^^---------- help: try this: `while v.pop().is_some()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:49:5 + --> $DIR/redundant_pattern_matching.rs:55:5 | LL | / match Ok::(42) { LL | | Ok(_) => true, @@ -76,7 +76,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:54:5 + --> $DIR/redundant_pattern_matching.rs:60:5 | LL | / match Ok::(42) { LL | | Ok(_) => false, @@ -85,7 +85,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_err()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:59:5 + --> $DIR/redundant_pattern_matching.rs:65:5 | LL | / match Err::(42) { LL | | Ok(_) => false, @@ -94,7 +94,7 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:64:5 + --> $DIR/redundant_pattern_matching.rs:70:5 | LL | / match Err::(42) { LL | | Ok(_) => true, @@ -103,7 +103,7 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_ok()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:69:5 + --> $DIR/redundant_pattern_matching.rs:75:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -112,7 +112,7 @@ LL | | }; | |_____^ help: try this: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:74:5 + --> $DIR/redundant_pattern_matching.rs:80:5 | LL | / match None::<()> { LL | | Some(_) => false, @@ -121,7 +121,7 @@ LL | | }; | |_____^ help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:79:13 + --> $DIR/redundant_pattern_matching.rs:85:13 | LL | let _ = match None::<()> { | _____________^ @@ -131,61 +131,61 @@ LL | | }; | |_____^ help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:84:20 + --> $DIR/redundant_pattern_matching.rs:90:20 | LL | let _ = if let Ok(_) = Ok::(4) { true } else { false }; | -------^^^^^--------------------- help: try this: `if Ok::(4).is_ok()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:87:20 + --> $DIR/redundant_pattern_matching.rs:93:20 | LL | let x = if let Some(_) = opt { true } else { false }; | -------^^^^^^^------ help: try this: `if opt.is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:93:20 + --> $DIR/redundant_pattern_matching.rs:99:20 | LL | let _ = if let Some(_) = gen_opt() { | -------^^^^^^^------------ help: try this: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:95:19 + --> $DIR/redundant_pattern_matching.rs:101:19 | LL | } else if let None = gen_opt() { | -------^^^^------------ help: try this: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:97:19 + --> $DIR/redundant_pattern_matching.rs:103:19 | LL | } else if let Ok(_) = gen_res() { | -------^^^^^------------ help: try this: `if gen_res().is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:99:19 + --> $DIR/redundant_pattern_matching.rs:105:19 | LL | } else if let Err(_) = gen_res() { | -------^^^^^^------------ help: try this: `if gen_res().is_err()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:132:19 + --> $DIR/redundant_pattern_matching.rs:138:19 | LL | while let Some(_) = r#try!(result_opt()) {} | ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:133:16 + --> $DIR/redundant_pattern_matching.rs:139:16 | LL | if let Some(_) = r#try!(result_opt()) {} | -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:139:12 + --> $DIR/redundant_pattern_matching.rs:145:12 | LL | if let Some(_) = m!() {} | -------^^^^^^^------- help: try this: `if m!().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:140:15 + --> $DIR/redundant_pattern_matching.rs:146:15 | LL | while let Some(_) = m!() {} | ----------^^^^^^^------- help: try this: `while m!().is_some()` diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.fixed index 8a81e92f04a73..de3fe00d5fa68 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.fixed @@ -2,7 +2,7 @@ #![feature(const_result)] #![warn(clippy::redundant_pattern_matching)] -#![allow(unused)] +#![allow(clippy::match_like_matches_macro, unused)] // Test that results are linted with the feature enabled. diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.rs index 1cd515441d13a..b77969d53d92d 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.rs +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.rs @@ -2,7 +2,7 @@ #![feature(const_result)] #![warn(clippy::redundant_pattern_matching)] -#![allow(unused)] +#![allow(clippy::match_like_matches_macro, unused)] // Test that results are linted with the feature enabled. diff --git a/src/tools/clippy/tests/ui/regex.rs b/src/tools/clippy/tests/ui/regex.rs index b523fa5b711ae..9767e5bf76a85 100644 --- a/src/tools/clippy/tests/ui/regex.rs +++ b/src/tools/clippy/tests/ui/regex.rs @@ -1,5 +1,5 @@ #![allow(unused)] -#![warn(clippy::invalid_regex, clippy::trivial_regex, clippy::regex_macro)] +#![warn(clippy::invalid_regex, clippy::trivial_regex)] extern crate regex; diff --git a/src/tools/clippy/tests/ui/repeat_once.fixed b/src/tools/clippy/tests/ui/repeat_once.fixed new file mode 100644 index 0000000000000..a637c22fbcd26 --- /dev/null +++ b/src/tools/clippy/tests/ui/repeat_once.fixed @@ -0,0 +1,16 @@ +// run-rustfix +#![warn(clippy::repeat_once)] +#[allow(unused, clippy::many_single_char_names, clippy::redundant_clone)] +fn main() { + const N: usize = 1; + let s = "str"; + let string = "String".to_string(); + let slice = [1; 5]; + + let a = [1; 5].to_vec(); + let b = slice.to_vec(); + let c = "hello".to_string(); + let d = "hi".to_string(); + let e = s.to_string(); + let f = string.clone(); +} diff --git a/src/tools/clippy/tests/ui/repeat_once.rs b/src/tools/clippy/tests/ui/repeat_once.rs new file mode 100644 index 0000000000000..d99ca1b5b55d4 --- /dev/null +++ b/src/tools/clippy/tests/ui/repeat_once.rs @@ -0,0 +1,16 @@ +// run-rustfix +#![warn(clippy::repeat_once)] +#[allow(unused, clippy::many_single_char_names, clippy::redundant_clone)] +fn main() { + const N: usize = 1; + let s = "str"; + let string = "String".to_string(); + let slice = [1; 5]; + + let a = [1; 5].repeat(1); + let b = slice.repeat(1); + let c = "hello".repeat(N); + let d = "hi".repeat(1); + let e = s.repeat(1); + let f = string.repeat(1); +} diff --git a/src/tools/clippy/tests/ui/repeat_once.stderr b/src/tools/clippy/tests/ui/repeat_once.stderr new file mode 100644 index 0000000000000..915eea3bfc6b8 --- /dev/null +++ b/src/tools/clippy/tests/ui/repeat_once.stderr @@ -0,0 +1,40 @@ +error: calling `repeat(1)` on slice + --> $DIR/repeat_once.rs:10:13 + | +LL | let a = [1; 5].repeat(1); + | ^^^^^^^^^^^^^^^^ help: consider using `.to_vec()` instead: `[1; 5].to_vec()` + | + = note: `-D clippy::repeat-once` implied by `-D warnings` + +error: calling `repeat(1)` on slice + --> $DIR/repeat_once.rs:11:13 + | +LL | let b = slice.repeat(1); + | ^^^^^^^^^^^^^^^ help: consider using `.to_vec()` instead: `slice.to_vec()` + +error: calling `repeat(1)` on str + --> $DIR/repeat_once.rs:12:13 + | +LL | let c = "hello".repeat(N); + | ^^^^^^^^^^^^^^^^^ help: consider using `.to_string()` instead: `"hello".to_string()` + +error: calling `repeat(1)` on str + --> $DIR/repeat_once.rs:13:13 + | +LL | let d = "hi".repeat(1); + | ^^^^^^^^^^^^^^ help: consider using `.to_string()` instead: `"hi".to_string()` + +error: calling `repeat(1)` on str + --> $DIR/repeat_once.rs:14:13 + | +LL | let e = s.repeat(1); + | ^^^^^^^^^^^ help: consider using `.to_string()` instead: `s.to_string()` + +error: calling `repeat(1)` on a string literal + --> $DIR/repeat_once.rs:15:13 + | +LL | let f = string.repeat(1); + | ^^^^^^^^^^^^^^^^ help: consider using `.clone()` instead: `string.clone()` + +error: aborting due to 6 previous errors + diff --git a/src/tools/clippy/tests/ui/single_match_else.rs b/src/tools/clippy/tests/ui/single_match_else.rs index 34193be0b75e4..b624a41a29b2d 100644 --- a/src/tools/clippy/tests/ui/single_match_else.rs +++ b/src/tools/clippy/tests/ui/single_match_else.rs @@ -1,4 +1,6 @@ #![warn(clippy::single_match_else)] +#![allow(clippy::needless_return)] +#![allow(clippy::no_effect)] enum ExprNode { ExprAddrOf, @@ -30,6 +32,55 @@ macro_rules! unwrap_addr { }; } +#[rustfmt::skip] fn main() { unwrap_addr!(ExprNode::Unicorns); + + // + // don't lint single exprs/statements + // + + // don't lint here + match Some(1) { + Some(a) => println!("${:?}", a), + None => return, + } + + // don't lint here + match Some(1) { + Some(a) => println!("${:?}", a), + None => { + return + }, + } + + // don't lint here + match Some(1) { + Some(a) => println!("${:?}", a), + None => { + return; + }, + } + + // + // lint multiple exprs/statements "else" blocks + // + + // lint here + match Some(1) { + Some(a) => println!("${:?}", a), + None => { + println!("else block"); + return + }, + } + + // lint here + match Some(1) { + Some(a) => println!("${:?}", a), + None => { + println!("else block"); + return; + }, + } } diff --git a/src/tools/clippy/tests/ui/single_match_else.stderr b/src/tools/clippy/tests/ui/single_match_else.stderr index 59861d46eb34c..3a07c2ec54262 100644 --- a/src/tools/clippy/tests/ui/single_match_else.stderr +++ b/src/tools/clippy/tests/ui/single_match_else.stderr @@ -1,5 +1,5 @@ error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match_else.rs:12:5 + --> $DIR/single_match_else.rs:14:5 | LL | / match ExprNode::Butterflies { LL | | ExprNode::ExprAddrOf => Some(&NODE), @@ -19,5 +19,45 @@ LL | None LL | } | -error: aborting due to previous error +error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` + --> $DIR/single_match_else.rs:70:5 + | +LL | / match Some(1) { +LL | | Some(a) => println!("${:?}", a), +LL | | None => { +LL | | println!("else block"); +LL | | return +LL | | }, +LL | | } + | |_____^ + | +help: try this + | +LL | if let Some(a) = Some(1) { println!("${:?}", a) } else { +LL | println!("else block"); +LL | return +LL | } + | + +error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` + --> $DIR/single_match_else.rs:79:5 + | +LL | / match Some(1) { +LL | | Some(a) => println!("${:?}", a), +LL | | None => { +LL | | println!("else block"); +LL | | return; +LL | | }, +LL | | } + | |_____^ + | +help: try this + | +LL | if let Some(a) = Some(1) { println!("${:?}", a) } else { +LL | println!("else block"); +LL | return; +LL | } + | + +error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/type_repetition_in_bounds.rs b/src/tools/clippy/tests/ui/type_repetition_in_bounds.rs index 8b538be762b0c..766190f209977 100644 --- a/src/tools/clippy/tests/ui/type_repetition_in_bounds.rs +++ b/src/tools/clippy/tests/ui/type_repetition_in_bounds.rs @@ -1,4 +1,6 @@ -#[deny(clippy::type_repetition_in_bounds)] +#![deny(clippy::type_repetition_in_bounds)] + +use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; pub fn foo(_t: T) where @@ -16,4 +18,55 @@ where unimplemented!(); } +// Threshold test (see #4380) +trait LintBounds +where + Self: Clone, + Self: Copy + Default + Ord, + Self: Add + AddAssign + Sub + SubAssign, + Self: Mul + MulAssign + Div + DivAssign, +{ +} + +trait LotsOfBounds +where + Self: Clone + Copy + Default + Ord, + Self: Add + AddAssign + Sub + SubAssign, + Self: Mul + MulAssign + Div + DivAssign, +{ +} + +// Generic distinction (see #4323) +mod issue4323 { + pub struct Foo(A); + pub struct Bar { + a: Foo, + b: Foo, + } + + impl Unpin for Bar + where + Foo: Unpin, + Foo: Unpin, + { + } +} + +// Extern macros shouldn't lint (see #4326) +extern crate serde; +mod issue4326 { + use serde::{Deserialize, Serialize}; + + trait Foo {} + impl Foo for String {} + + #[derive(Debug, Serialize, Deserialize)] + struct Bar + where + S: Foo, + { + foo: S, + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr b/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr index 4264e2e10bf17..148c19c7d0701 100644 --- a/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr +++ b/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr @@ -1,15 +1,23 @@ error: this type has already been used as a bound predicate - --> $DIR/type_repetition_in_bounds.rs:6:5 + --> $DIR/type_repetition_in_bounds.rs:8:5 | LL | T: Clone, | ^^^^^^^^ | note: the lint level is defined here - --> $DIR/type_repetition_in_bounds.rs:1:8 + --> $DIR/type_repetition_in_bounds.rs:1:9 | -LL | #[deny(clippy::type_repetition_in_bounds)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(clippy::type_repetition_in_bounds)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: consider combining the bounds: `T: Copy + Clone` -error: aborting due to previous error +error: this type has already been used as a bound predicate + --> $DIR/type_repetition_in_bounds.rs:25:5 + | +LL | Self: Copy + Default + Ord, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider combining the bounds: `Self: Clone + Copy + Default + Ord` + +error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_clone.rs b/src/tools/clippy/tests/ui/unnecessary_clone.rs index f1cc5b564c1dc..2c9d4d39e6c7d 100644 --- a/src/tools/clippy/tests/ui/unnecessary_clone.rs +++ b/src/tools/clippy/tests/ui/unnecessary_clone.rs @@ -13,31 +13,6 @@ impl SomeTrait for SomeImpl {} fn main() {} -fn is_ascii(ch: char) -> bool { - ch.is_ascii() -} - -fn clone_on_copy() { - 42.clone(); - - vec![1].clone(); // ok, not a Copy type - Some(vec![1]).clone(); // ok, not a Copy type - (&42).clone(); - - let rc = RefCell::new(0); - rc.borrow().clone(); - - // Issue #4348 - let mut x = 43; - let _ = &x.clone(); // ok, getting a ref - 'a'.clone().make_ascii_uppercase(); // ok, clone and then mutate - is_ascii('z'.clone()); - - // Issue #5436 - let mut vec = Vec::new(); - vec.push(42.clone()); -} - fn clone_on_ref_ptr() { let rc = Rc::new(true); let arc = Arc::new(true); diff --git a/src/tools/clippy/tests/ui/unnecessary_clone.stderr b/src/tools/clippy/tests/ui/unnecessary_clone.stderr index 6176a2bc46479..113fab6900954 100644 --- a/src/tools/clippy/tests/ui/unnecessary_clone.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_clone.stderr @@ -1,37 +1,5 @@ -error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:21:5 - | -LL | 42.clone(); - | ^^^^^^^^^^ help: try removing the `clone` call: `42` - | - = note: `-D clippy::clone-on-copy` implied by `-D warnings` - -error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:25:5 - | -LL | (&42).clone(); - | ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)` - -error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:28:5 - | -LL | rc.borrow().clone(); - | ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()` - -error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:34:14 - | -LL | is_ascii('z'.clone()); - | ^^^^^^^^^^^ help: try removing the `clone` call: `'z'` - -error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:38:14 - | -LL | vec.push(42.clone()); - | ^^^^^^^^^^ help: try removing the `clone` call: `42` - error: using `.clone()` on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:48:5 + --> $DIR/unnecessary_clone.rs:23:5 | LL | rc.clone(); | ^^^^^^^^^^ help: try this: `Rc::::clone(&rc)` @@ -39,43 +7,45 @@ LL | rc.clone(); = note: `-D clippy::clone-on-ref-ptr` implied by `-D warnings` error: using `.clone()` on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:51:5 + --> $DIR/unnecessary_clone.rs:26:5 | LL | arc.clone(); | ^^^^^^^^^^^ help: try this: `Arc::::clone(&arc)` error: using `.clone()` on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:54:5 + --> $DIR/unnecessary_clone.rs:29:5 | LL | rcweak.clone(); | ^^^^^^^^^^^^^^ help: try this: `Weak::::clone(&rcweak)` error: using `.clone()` on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:57:5 + --> $DIR/unnecessary_clone.rs:32:5 | LL | arc_weak.clone(); | ^^^^^^^^^^^^^^^^ help: try this: `Weak::::clone(&arc_weak)` error: using `.clone()` on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:61:33 + --> $DIR/unnecessary_clone.rs:36:33 | LL | let _: Arc = x.clone(); | ^^^^^^^^^ help: try this: `Arc::::clone(&x)` error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:65:5 + --> $DIR/unnecessary_clone.rs:40:5 | LL | t.clone(); | ^^^^^^^^^ help: try removing the `clone` call: `t` + | + = note: `-D clippy::clone-on-copy` implied by `-D warnings` error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:67:5 + --> $DIR/unnecessary_clone.rs:42:5 | LL | Some(t).clone(); | ^^^^^^^^^^^^^^^ help: try removing the `clone` call: `Some(t)` error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type - --> $DIR/unnecessary_clone.rs:73:22 + --> $DIR/unnecessary_clone.rs:48:22 | LL | let z: &Vec<_> = y.clone(); | ^^^^^^^^^ @@ -91,13 +61,13 @@ LL | let z: &Vec<_> = <&std::vec::Vec>::clone(y); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:109:20 + --> $DIR/unnecessary_clone.rs:84:20 | LL | let _: E = a.clone(); | ^^^^^^^^^ help: try dereferencing it: `*****a` error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type - --> $DIR/unnecessary_clone.rs:114:22 + --> $DIR/unnecessary_clone.rs:89:22 | LL | let _ = &mut encoded.clone(); | ^^^^^^^^^^^^^^^ @@ -112,7 +82,7 @@ LL | let _ = &mut <&[u8]>::clone(encoded); | ^^^^^^^^^^^^^^^^^^^^^^^ error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type - --> $DIR/unnecessary_clone.rs:115:18 + --> $DIR/unnecessary_clone.rs:90:18 | LL | let _ = &encoded.clone(); | ^^^^^^^^^^^^^^^ @@ -126,5 +96,5 @@ help: or try being explicit if you are sure, that you want to clone a reference LL | let _ = &<&[u8]>::clone(encoded); | ^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 16 previous errors +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed b/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed index 779fd57707ad4..c017d1cf9a468 100644 --- a/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed @@ -2,11 +2,11 @@ use std::cmp::Reverse; -fn id(x: isize) -> isize { - x -} +fn unnecessary_sort_by() { + fn id(x: isize) -> isize { + x + } -fn main() { let mut vec: Vec = vec![3, 6, 1, 2, 5]; // Forward examples vec.sort(); @@ -24,3 +24,41 @@ fn main() { vec.sort_by(|_, b| b.cmp(c)); vec.sort_unstable_by(|a, _| a.cmp(c)); } + +// Should not be linted to avoid hitting https://github.com/rust-lang/rust/issues/34162 +mod issue_5754 { + struct Test(String); + + #[derive(PartialOrd, Ord, PartialEq, Eq)] + struct Wrapper<'a>(&'a str); + + impl Test { + fn name(&self) -> &str { + &self.0 + } + + fn wrapped(&self) -> Wrapper<'_> { + Wrapper(&self.0) + } + } + + pub fn test() { + let mut args: Vec = vec![]; + + // Forward + args.sort_by(|a, b| a.name().cmp(b.name())); + args.sort_by(|a, b| a.wrapped().cmp(&b.wrapped())); + args.sort_unstable_by(|a, b| a.name().cmp(b.name())); + args.sort_unstable_by(|a, b| a.wrapped().cmp(&b.wrapped())); + // Reverse + args.sort_by(|a, b| b.name().cmp(a.name())); + args.sort_by(|a, b| b.wrapped().cmp(&a.wrapped())); + args.sort_unstable_by(|a, b| b.name().cmp(a.name())); + args.sort_unstable_by(|a, b| b.wrapped().cmp(&a.wrapped())); + } +} + +fn main() { + unnecessary_sort_by(); + issue_5754::test(); +} diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.rs b/src/tools/clippy/tests/ui/unnecessary_sort_by.rs index 0485a5630afef..1929c72b2f2cd 100644 --- a/src/tools/clippy/tests/ui/unnecessary_sort_by.rs +++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.rs @@ -2,11 +2,11 @@ use std::cmp::Reverse; -fn id(x: isize) -> isize { - x -} +fn unnecessary_sort_by() { + fn id(x: isize) -> isize { + x + } -fn main() { let mut vec: Vec = vec![3, 6, 1, 2, 5]; // Forward examples vec.sort_by(|a, b| a.cmp(b)); @@ -24,3 +24,41 @@ fn main() { vec.sort_by(|_, b| b.cmp(c)); vec.sort_unstable_by(|a, _| a.cmp(c)); } + +// Should not be linted to avoid hitting https://github.com/rust-lang/rust/issues/34162 +mod issue_5754 { + struct Test(String); + + #[derive(PartialOrd, Ord, PartialEq, Eq)] + struct Wrapper<'a>(&'a str); + + impl Test { + fn name(&self) -> &str { + &self.0 + } + + fn wrapped(&self) -> Wrapper<'_> { + Wrapper(&self.0) + } + } + + pub fn test() { + let mut args: Vec = vec![]; + + // Forward + args.sort_by(|a, b| a.name().cmp(b.name())); + args.sort_by(|a, b| a.wrapped().cmp(&b.wrapped())); + args.sort_unstable_by(|a, b| a.name().cmp(b.name())); + args.sort_unstable_by(|a, b| a.wrapped().cmp(&b.wrapped())); + // Reverse + args.sort_by(|a, b| b.name().cmp(a.name())); + args.sort_by(|a, b| b.wrapped().cmp(&a.wrapped())); + args.sort_unstable_by(|a, b| b.name().cmp(a.name())); + args.sort_unstable_by(|a, b| b.wrapped().cmp(&a.wrapped())); + } +} + +fn main() { + unnecessary_sort_by(); + issue_5754::test(); +} diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns3.rs b/src/tools/clippy/tests/ui/unnested_or_patterns3.rs new file mode 100644 index 0000000000000..6bd35057bfad1 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnested_or_patterns3.rs @@ -0,0 +1,6 @@ +#![warn(clippy::unnested_or_patterns)] + +// Test that `unnested_or_patterns` does not trigger without enabling `or_patterns` +fn main() { + if let (0, 1) | (0, 2) | (0, 3) = (0, 0) {} +}