From 7ff71e5fb4c025b261f6c7e7eb996b36382c178e Mon Sep 17 00:00:00 2001 From: yukang Date: Sat, 13 Jul 2024 12:43:35 +0800 Subject: [PATCH 001/260] Remove invalid help diagnostics for const pointer --- .../src/diagnostics/mutability_errors.rs | 33 ++++++++++++------- ...suggest_raw_pointer_syntax-issue-127562.rs | 7 ++++ ...est_raw_pointer_syntax-issue-127562.stderr | 9 +++++ 3 files changed, 37 insertions(+), 12 deletions(-) create mode 100644 tests/ui/suggestions/dont_suggest_raw_pointer_syntax-issue-127562.rs create mode 100644 tests/ui/suggestions/dont_suggest_raw_pointer_syntax-issue-127562.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 26b0d23b16642..0b6c527b8c082 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1146,6 +1146,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { } // don't create labels for compiler-generated spans Some(_) => None, + // don't create labels for the span not from user's code + None if opt_assignment_rhs_span + .is_some_and(|span| self.infcx.tcx.sess.source_map().is_imported(span)) => + { + None + } None => { let (has_sugg, decl_span, sugg) = if name != kw::SelfLower { suggest_ampmut( @@ -1198,18 +1204,21 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { sugg.push(s); } - err.multipart_suggestion_verbose( - format!( - "consider changing this to be a mutable {pointer_desc}{}", - if is_trait_sig { - " in the `impl` method and the `trait` definition" - } else { - "" - } - ), - sugg, - Applicability::MachineApplicable, - ); + if sugg.iter().all(|(span, _)| !self.infcx.tcx.sess.source_map().is_imported(*span)) + { + err.multipart_suggestion_verbose( + format!( + "consider changing this to be a mutable {pointer_desc}{}", + if is_trait_sig { + " in the `impl` method and the `trait` definition" + } else { + "" + } + ), + sugg, + Applicability::MachineApplicable, + ); + } } Some((false, err_label_span, message, _)) => { let def_id = self.body.source.def_id(); diff --git a/tests/ui/suggestions/dont_suggest_raw_pointer_syntax-issue-127562.rs b/tests/ui/suggestions/dont_suggest_raw_pointer_syntax-issue-127562.rs new file mode 100644 index 0000000000000..03b736e60b63a --- /dev/null +++ b/tests/ui/suggestions/dont_suggest_raw_pointer_syntax-issue-127562.rs @@ -0,0 +1,7 @@ +fn main() { + let val = 2; + let ptr = std::ptr::addr_of!(val); + unsafe { + *ptr = 3; //~ ERROR cannot assign to `*ptr`, which is behind a `*const` pointer + } +} diff --git a/tests/ui/suggestions/dont_suggest_raw_pointer_syntax-issue-127562.stderr b/tests/ui/suggestions/dont_suggest_raw_pointer_syntax-issue-127562.stderr new file mode 100644 index 0000000000000..5396db7940f72 --- /dev/null +++ b/tests/ui/suggestions/dont_suggest_raw_pointer_syntax-issue-127562.stderr @@ -0,0 +1,9 @@ +error[E0594]: cannot assign to `*ptr`, which is behind a `*const` pointer + --> $DIR/dont_suggest_raw_pointer_syntax-issue-127562.rs:5:9 + | +LL | *ptr = 3; + | ^^^^^^^^ `ptr` is a `*const` pointer, so the data it refers to cannot be written + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0594`. From 9ce811cd004e4f1bb7042d0f3fa4b54ffbe9421f Mon Sep 17 00:00:00 2001 From: Jonathan Birk <1965620+cafce25@users.noreply.github.com> Date: Tue, 30 Jul 2024 14:55:27 +0200 Subject: [PATCH 002/260] Change orphan hint from "only" to "any uncovered type inside..." --- compiler/rustc_hir_analysis/messages.ftl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 367f6e17e7fe6..33bda77e3353b 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -351,7 +351,7 @@ hir_analysis_only_current_traits_arbitrary = only traits defined in the current hir_analysis_only_current_traits_foreign = this is not defined in the current crate because this is a foreign trait -hir_analysis_only_current_traits_label = impl doesn't use only types from inside the current crate +hir_analysis_only_current_traits_label = impl doesn't use any uncovered types from inside the current crate hir_analysis_only_current_traits_name = this is not defined in the current crate because {$name} are always foreign From 86a9959466dd996bd9bc926bd79289fdf7f1790d Mon Sep 17 00:00:00 2001 From: Jonathan Birk Date: Tue, 30 Jul 2024 15:39:04 +0000 Subject: [PATCH 003/260] Adjust orphan note in tests --- tests/ui/coherence/coherence-cow.re_a.stderr | 2 +- tests/ui/coherence/coherence-cow.re_b.stderr | 2 +- tests/ui/coherence/coherence-cow.re_c.stderr | 2 +- .../coherence-fundamental-trait-objects.stderr | 2 +- ...impl-trait-for-marker-trait-negative.stderr | 2 +- ...impl-trait-for-marker-trait-positive.stderr | 2 +- tests/ui/coherence/coherence-impls-copy.stderr | 8 ++++---- tests/ui/coherence/coherence-impls-send.stderr | 6 +++--- .../ui/coherence/coherence-impls-sized.stderr | 6 +++--- .../coherence-negative-impls-copy-bad.stderr | 6 +++--- tests/ui/coherence/coherence-orphan.stderr | 4 ++-- .../coherence-overlapping-pairs.stderr | 2 +- .../coherence-pair-covered-uncovered-1.stderr | 2 +- .../coherence-pair-covered-uncovered.stderr | 2 +- .../ui/coherence/coherence-vec-local-2.stderr | 2 +- tests/ui/coherence/coherence-vec-local.stderr | 2 +- .../coherence_local_err_struct.stderr | 2 +- .../coherence/coherence_local_err_tuple.stderr | 2 +- .../coherence/impl-foreign-for-foreign.stderr | 2 +- .../impl-foreign-for-foreign[foreign].stderr | 6 +++--- ...mpl-foreign-for-fundamental[foreign].stderr | 4 ++-- .../impl-foreign[foreign]-for-foreign.stderr | 2 +- ...gn[fundemental[foreign]]-for-foreign.stderr | 6 +++--- .../impl[t]-foreign-for-foreign[t].stderr | 4 ++-- tests/ui/dropck/drop-on-non-struct.stderr | 2 +- tests/ui/error-codes/E0117.stderr | 2 +- tests/ui/error-codes/e0119/complex-impl.stderr | 2 +- .../issue-99572-impl-trait-on-pointer.rs | 18 +++++++++--------- .../issue-99572-impl-trait-on-pointer.stderr | 4 ++-- tests/ui/issues/issue-67535.stderr | 6 +++--- .../const-and-non-const-impl.stderr | 2 +- .../coherence.classic.stderr | 2 +- .../coherence.next.stderr | 2 +- .../range_patterns_trait_impls2.stderr | 2 +- ...ult-trait-impl-cross-crate-coherence.stderr | 6 +++--- 35 files changed, 64 insertions(+), 64 deletions(-) diff --git a/tests/ui/coherence/coherence-cow.re_a.stderr b/tests/ui/coherence/coherence-cow.re_a.stderr index 0bc017817b67d..3e929d4fb3379 100644 --- a/tests/ui/coherence/coherence-cow.re_a.stderr +++ b/tests/ui/coherence/coherence-cow.re_a.stderr @@ -5,7 +5,7 @@ LL | impl Remote for Pair> { } | ^^^^^^^^^^^^^^^^^^^---------------- | | | | | `Pair` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-cow.re_b.stderr b/tests/ui/coherence/coherence-cow.re_b.stderr index 9bdb49dcc04ff..d267f859aea28 100644 --- a/tests/ui/coherence/coherence-cow.re_b.stderr +++ b/tests/ui/coherence/coherence-cow.re_b.stderr @@ -5,7 +5,7 @@ LL | impl Remote for Pair,T> { } | ^^^^^^^^^^^^^^^^^^^---------------- | | | | | `Pair` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-cow.re_c.stderr b/tests/ui/coherence/coherence-cow.re_c.stderr index dfff2667ebbcc..e2671cc3dd155 100644 --- a/tests/ui/coherence/coherence-cow.re_c.stderr +++ b/tests/ui/coherence/coherence-cow.re_c.stderr @@ -5,7 +5,7 @@ LL | impl Remote for Pair,U> { } | ^^^^^^^^^^^^^^^^^^^^^---------------- | | | | | `Pair` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-fundamental-trait-objects.stderr b/tests/ui/coherence/coherence-fundamental-trait-objects.stderr index db6a94748042d..a0bf8f23f2c61 100644 --- a/tests/ui/coherence/coherence-fundamental-trait-objects.stderr +++ b/tests/ui/coherence/coherence-fundamental-trait-objects.stderr @@ -5,7 +5,7 @@ LL | impl Misc for dyn Fundamental {} | ^^^^^^^^^^^^^^---------------------- | | | | | `dyn Fundamental` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr index ea38afc40ce80..abe752cb65e99 100644 --- a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr +++ b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr @@ -41,7 +41,7 @@ LL | impl !Send for dyn Marker2 {} | ^^^^^^^^^^^^^^^----------- | | | | | `dyn Marker2` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr index 2a8713bc32794..99a32f1bf9347 100644 --- a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr +++ b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr @@ -41,7 +41,7 @@ LL | unsafe impl Send for dyn Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^----------- | | | | | `dyn Marker2` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-impls-copy.stderr b/tests/ui/coherence/coherence-impls-copy.stderr index f529a056b0fd5..e8db69fa983d9 100644 --- a/tests/ui/coherence/coherence-impls-copy.stderr +++ b/tests/ui/coherence/coherence-impls-copy.stderr @@ -15,7 +15,7 @@ LL | impl Copy for &'static [NotSync] {} | ^^^^^^^^^^^^^^------------------ | | | | | this is not defined in the current crate because slices are always foreign - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead @@ -26,7 +26,7 @@ LL | impl Copy for i32 {} | ^^^^^^^^^^^^^^--- | | | | | `i32` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead @@ -43,7 +43,7 @@ LL | impl Copy for (MyType, MyType) {} | ^^^^^^^^^^^^^^---------------- | | | | | this is not defined in the current crate because tuples are always foreign - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead @@ -60,7 +60,7 @@ LL | impl Copy for [MyType] {} | ^^^^^^^^^^^^^^-------- | | | | | this is not defined in the current crate because slices are always foreign - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-impls-send.stderr b/tests/ui/coherence/coherence-impls-send.stderr index e1071846e146e..2432e6f22d13a 100644 --- a/tests/ui/coherence/coherence-impls-send.stderr +++ b/tests/ui/coherence/coherence-impls-send.stderr @@ -5,7 +5,7 @@ LL | unsafe impl Send for &'static [NotSync] {} | ^^^^^^^^^^^^^^^^^^^^^------------------ | | | | | this is not defined in the current crate because slices are always foreign - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead @@ -16,7 +16,7 @@ LL | unsafe impl Send for (MyType, MyType) {} | ^^^^^^^^^^^^^^^^^^^^^---------------- | | | | | this is not defined in the current crate because tuples are always foreign - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead @@ -33,7 +33,7 @@ LL | unsafe impl Send for [MyType] {} | ^^^^^^^^^^^^^^^^^^^^^-------- | | | | | this is not defined in the current crate because slices are always foreign - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-impls-sized.stderr b/tests/ui/coherence/coherence-impls-sized.stderr index 17a7544521de5..5069f752f7434 100644 --- a/tests/ui/coherence/coherence-impls-sized.stderr +++ b/tests/ui/coherence/coherence-impls-sized.stderr @@ -23,7 +23,7 @@ LL | impl Sized for (MyType, MyType) {} | ^^^^^^^^^^^^^^^---------------- | | | | | this is not defined in the current crate because tuples are always foreign - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead @@ -46,7 +46,7 @@ LL | impl Sized for [MyType] {} | ^^^^^^^^^^^^^^^-------- | | | | | this is not defined in the current crate because slices are always foreign - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead @@ -63,7 +63,7 @@ LL | impl Sized for &'static [NotSync] {} | ^^^^^^^^^^^^^^^------------------ | | | | | this is not defined in the current crate because slices are always foreign - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-negative-impls-copy-bad.stderr b/tests/ui/coherence/coherence-negative-impls-copy-bad.stderr index 2295d6315d1c2..2994d1ce0e54a 100644 --- a/tests/ui/coherence/coherence-negative-impls-copy-bad.stderr +++ b/tests/ui/coherence/coherence-negative-impls-copy-bad.stderr @@ -5,7 +5,7 @@ LL | impl !Copy for str {} | ^^^^^^^^^^^^^^^--- | | | | | `str` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead @@ -16,7 +16,7 @@ LL | impl !Copy for fn() {} | ^^^^^^^^^^^^^^^---- | | | | | `fn()` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead @@ -27,7 +27,7 @@ LL | impl !Copy for () {} | ^^^^^^^^^^^^^^^-- | | | | | this is not defined in the current crate because tuples are always foreign - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-orphan.stderr b/tests/ui/coherence/coherence-orphan.stderr index f6ffae342908a..11b90d8bf2a3f 100644 --- a/tests/ui/coherence/coherence-orphan.stderr +++ b/tests/ui/coherence/coherence-orphan.stderr @@ -6,7 +6,7 @@ LL | impl TheTrait for isize {} | | | | | | | `isize` is not defined in the current crate | | `usize` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead @@ -17,7 +17,7 @@ LL | impl !Send for Vec {} | ^^^^^^^^^^^^^^^---------- | | | | | `Vec` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-overlapping-pairs.stderr b/tests/ui/coherence/coherence-overlapping-pairs.stderr index 4d0a9c6ee1400..17bb8dc314d20 100644 --- a/tests/ui/coherence/coherence-overlapping-pairs.stderr +++ b/tests/ui/coherence/coherence-overlapping-pairs.stderr @@ -5,7 +5,7 @@ LL | impl Remote for lib::Pair { } | ^^^^^^^^^^^^^^^^^^^---------------- | | | | | `Pair` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-pair-covered-uncovered-1.stderr b/tests/ui/coherence/coherence-pair-covered-uncovered-1.stderr index 15cd66e9d09d0..f2a3ec4daae6f 100644 --- a/tests/ui/coherence/coherence-pair-covered-uncovered-1.stderr +++ b/tests/ui/coherence/coherence-pair-covered-uncovered-1.stderr @@ -6,7 +6,7 @@ LL | impl Remote1>> for i32 { } | | | | | | | `i32` is not defined in the current crate | | `Pair` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-pair-covered-uncovered.stderr b/tests/ui/coherence/coherence-pair-covered-uncovered.stderr index 359dbe8509d80..e3f85c3215374 100644 --- a/tests/ui/coherence/coherence-pair-covered-uncovered.stderr +++ b/tests/ui/coherence/coherence-pair-covered-uncovered.stderr @@ -5,7 +5,7 @@ LL | impl Remote for Pair> { } | ^^^^^^^^^^^^^^^^^^^^^---------------- | | | | | `Pair` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-vec-local-2.stderr b/tests/ui/coherence/coherence-vec-local-2.stderr index e4249710d0028..1998dedbbc895 100644 --- a/tests/ui/coherence/coherence-vec-local-2.stderr +++ b/tests/ui/coherence/coherence-vec-local-2.stderr @@ -5,7 +5,7 @@ LL | impl Remote for Vec> { } | ^^^^^^^^^^^^^^^^^^^------------- | | | | | `Vec` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-vec-local.stderr b/tests/ui/coherence/coherence-vec-local.stderr index c465fb1966eb8..6e95eb7251f6d 100644 --- a/tests/ui/coherence/coherence-vec-local.stderr +++ b/tests/ui/coherence/coherence-vec-local.stderr @@ -5,7 +5,7 @@ LL | impl Remote for Vec { } | ^^^^^^^^^^^^^^^^---------- | | | | | `Vec` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence_local_err_struct.stderr b/tests/ui/coherence/coherence_local_err_struct.stderr index 96572b5a71648..bbf968d5d131c 100644 --- a/tests/ui/coherence/coherence_local_err_struct.stderr +++ b/tests/ui/coherence/coherence_local_err_struct.stderr @@ -5,7 +5,7 @@ LL | impl lib::MyCopy for lib::MyStruct { } | ^^^^^^^^^^^^^^^^^^^^^--------------------- | | | | | `MyStruct` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence_local_err_tuple.stderr b/tests/ui/coherence/coherence_local_err_tuple.stderr index 85a063bb34ae2..c988e738af4d8 100644 --- a/tests/ui/coherence/coherence_local_err_tuple.stderr +++ b/tests/ui/coherence/coherence_local_err_tuple.stderr @@ -5,7 +5,7 @@ LL | impl lib::MyCopy for (MyType,) { } | ^^^^^^^^^^^^^^^^^^^^^--------- | | | | | this is not defined in the current crate because tuples are always foreign - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/impl-foreign-for-foreign.stderr b/tests/ui/coherence/impl-foreign-for-foreign.stderr index 6c74b47a1c48e..81ae36c6a53db 100644 --- a/tests/ui/coherence/impl-foreign-for-foreign.stderr +++ b/tests/ui/coherence/impl-foreign-for-foreign.stderr @@ -5,7 +5,7 @@ LL | impl Remote for i32 { | ^^^^^^^^^^^^^^^^--- | | | | | `i32` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/impl-foreign-for-foreign[foreign].stderr b/tests/ui/coherence/impl-foreign-for-foreign[foreign].stderr index e24537bce229a..9ac7aeff46122 100644 --- a/tests/ui/coherence/impl-foreign-for-foreign[foreign].stderr +++ b/tests/ui/coherence/impl-foreign-for-foreign[foreign].stderr @@ -6,7 +6,7 @@ LL | impl Remote1> for i32 { | | | | | | | `i32` is not defined in the current crate | | `Rc` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead @@ -18,7 +18,7 @@ LL | impl Remote1> for f64 { | | | | | | | `f64` is not defined in the current crate | | `Rc` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead @@ -30,7 +30,7 @@ LL | impl Remote1> for f32 { | | | | | | | `f32` is not defined in the current crate | | `Rc` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/impl-foreign-for-fundamental[foreign].stderr b/tests/ui/coherence/impl-foreign-for-fundamental[foreign].stderr index 55ea4409e6f36..fff6a6b511e17 100644 --- a/tests/ui/coherence/impl-foreign-for-fundamental[foreign].stderr +++ b/tests/ui/coherence/impl-foreign-for-fundamental[foreign].stderr @@ -6,7 +6,7 @@ LL | impl Remote for Box { | | | | | | | `i32` is not defined in the current crate | | `std::alloc::Global` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead @@ -18,7 +18,7 @@ LL | impl Remote for Box> { | | | | | | | `Rc` is not defined in the current crate | | `std::alloc::Global` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/impl-foreign[foreign]-for-foreign.stderr b/tests/ui/coherence/impl-foreign[foreign]-for-foreign.stderr index fe8a34b78cfd0..ca85063986215 100644 --- a/tests/ui/coherence/impl-foreign[foreign]-for-foreign.stderr +++ b/tests/ui/coherence/impl-foreign[foreign]-for-foreign.stderr @@ -6,7 +6,7 @@ LL | impl Remote1 for f64 { | | | | | | | `f64` is not defined in the current crate | | `u32` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr b/tests/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr index 8e77c13e1116a..cc0882095e22f 100644 --- a/tests/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr +++ b/tests/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr @@ -7,7 +7,7 @@ LL | impl Remote1> for i32 { | | | `i32` is not defined in the current crate | | `String` is not defined in the current crate | | `std::alloc::Global` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead @@ -20,7 +20,7 @@ LL | impl Remote1>> for f64 { | | | `f64` is not defined in the current crate | | `Rc` is not defined in the current crate | | `std::alloc::Global` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead @@ -33,7 +33,7 @@ LL | impl Remote1>> for f32 { | | | `f32` is not defined in the current crate | | `Rc` is not defined in the current crate | | `std::alloc::Global` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/impl[t]-foreign-for-foreign[t].stderr b/tests/ui/coherence/impl[t]-foreign-for-foreign[t].stderr index 92346c29198ce..11260b7d64a33 100644 --- a/tests/ui/coherence/impl[t]-foreign-for-foreign[t].stderr +++ b/tests/ui/coherence/impl[t]-foreign-for-foreign[t].stderr @@ -5,7 +5,7 @@ LL | impl Remote for Rc { | ^^^^^^^^^^^^^^^^--------- | | | | | `Rc` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead @@ -16,7 +16,7 @@ LL | impl Remote for Arc { | ^^^^^^^^^^^^^^^^^^^------ | | | | | `Arc` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/dropck/drop-on-non-struct.stderr b/tests/ui/dropck/drop-on-non-struct.stderr index e8fbe5e972642..ec0b2e0d0b645 100644 --- a/tests/ui/dropck/drop-on-non-struct.stderr +++ b/tests/ui/dropck/drop-on-non-struct.stderr @@ -11,7 +11,7 @@ LL | impl<'a> Drop for &'a mut isize { | ^^^^^^^^^^^^^^^^^^------------- | | | | | `isize` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/error-codes/E0117.stderr b/tests/ui/error-codes/E0117.stderr index f144aa9f72c13..86328e8131ac0 100644 --- a/tests/ui/error-codes/E0117.stderr +++ b/tests/ui/error-codes/E0117.stderr @@ -5,7 +5,7 @@ LL | impl Drop for u32 {} | ^^^^^^^^^^^^^^--- | | | | | `u32` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/error-codes/e0119/complex-impl.stderr b/tests/ui/error-codes/e0119/complex-impl.stderr index c0519c60e4227..6562593adfafc 100644 --- a/tests/ui/error-codes/e0119/complex-impl.stderr +++ b/tests/ui/error-codes/e0119/complex-impl.stderr @@ -5,7 +5,7 @@ LL | impl External for (Q, R) {} | ^^^^^^^^^^^^^^^^^^^^^------ | | | | | this is not defined in the current crate because tuples are always foreign - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/errors/issue-99572-impl-trait-on-pointer.rs b/tests/ui/errors/issue-99572-impl-trait-on-pointer.rs index 272c6bd3fb782..ae2329ec9c8ca 100644 --- a/tests/ui/errors/issue-99572-impl-trait-on-pointer.rs +++ b/tests/ui/errors/issue-99572-impl-trait-on-pointer.rs @@ -5,21 +5,21 @@ use std::{fmt, marker}; struct LocalType; impl fmt::Display for *mut LocalType { -//~^ ERROR only traits defined in the current crate can be implemented for arbitrary types -//~| NOTE impl doesn't use only types from inside the current crate -//~| NOTE `*mut LocalType` is not defined in the current crate because raw pointers are always foreign -//~| NOTE define and implement a trait or new type instead -//~| HELP consider introducing a new wrapper type + //~^ ERROR only traits defined in the current crate can be implemented for arbitrary types + //~| NOTE impl doesn't use any uncovered types from inside the current crate + //~| NOTE `*mut LocalType` is not defined in the current crate because raw pointers are always foreign + //~| NOTE define and implement a trait or new type instead + //~| HELP consider introducing a new wrapper type fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "This not compile") } } impl marker::Copy for *mut T { -//~^ ERROR only traits defined in the current crate can be implemented for arbitrary types -//~| NOTE impl doesn't use only types from inside the current crate -//~| NOTE `*mut T` is not defined in the current crate because raw pointers are always foreign -//~| NOTE define and implement a trait or new type instead + //~^ ERROR only traits defined in the current crate can be implemented for arbitrary types + //~| NOTE impl doesn't use any uncovered types from inside the current crate + //~| NOTE `*mut T` is not defined in the current crate because raw pointers are always foreign + //~| NOTE define and implement a trait or new type instead } fn main() {} diff --git a/tests/ui/errors/issue-99572-impl-trait-on-pointer.stderr b/tests/ui/errors/issue-99572-impl-trait-on-pointer.stderr index 78d7a47deaac3..5809387e91716 100644 --- a/tests/ui/errors/issue-99572-impl-trait-on-pointer.stderr +++ b/tests/ui/errors/issue-99572-impl-trait-on-pointer.stderr @@ -5,7 +5,7 @@ LL | impl fmt::Display for *mut LocalType { | ^^^^^^^^^^^^^^^^^^^^^^-------------- | | | | | `*mut LocalType` is not defined in the current crate because raw pointers are always foreign - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead help: consider introducing a new wrapper type @@ -22,7 +22,7 @@ LL | impl marker::Copy for *mut T { | ^^^^^^^^^^^^^^^^^^^^^^^^^------ | | | | | `*mut T` is not defined in the current crate because raw pointers are always foreign - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/issues/issue-67535.stderr b/tests/ui/issues/issue-67535.stderr index 4d7a02a50969f..4bfbf1bffdbe7 100644 --- a/tests/ui/issues/issue-67535.stderr +++ b/tests/ui/issues/issue-67535.stderr @@ -6,7 +6,7 @@ LL | impl std::ops::AddAssign for () { | | | | | | | this is not defined in the current crate because tuples are always foreign | | this is not defined in the current crate because this is a foreign trait - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead @@ -18,7 +18,7 @@ LL | impl std::ops::AddAssign for [(); 1] { | | | | | | | this is not defined in the current crate because arrays are always foreign | | this is not defined in the current crate because this is a foreign trait - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead @@ -30,7 +30,7 @@ LL | impl std::ops::AddAssign for &[u8] { | | | | | | | this is not defined in the current crate because slices are always foreign | | this is not defined in the current crate because this is a foreign trait - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr index 9c1c8df8da459..056cd76075e1b 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr @@ -33,7 +33,7 @@ LL | impl const std::ops::Add for i32 { | | | | | | | `i32` is not defined in the current crate | | `i32` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/type-alias-impl-trait/coherence.classic.stderr b/tests/ui/type-alias-impl-trait/coherence.classic.stderr index ff059bc5806de..3930a7513d879 100644 --- a/tests/ui/type-alias-impl-trait/coherence.classic.stderr +++ b/tests/ui/type-alias-impl-trait/coherence.classic.stderr @@ -5,7 +5,7 @@ LL | impl foreign_crate::ForeignTrait for AliasOfForeignType<()> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------- | | | | | type alias impl trait is treated as if it were foreign, because its hidden type could be from a foreign crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/type-alias-impl-trait/coherence.next.stderr b/tests/ui/type-alias-impl-trait/coherence.next.stderr index dab2786c1f0fb..bbda986818848 100644 --- a/tests/ui/type-alias-impl-trait/coherence.next.stderr +++ b/tests/ui/type-alias-impl-trait/coherence.next.stderr @@ -5,7 +5,7 @@ LL | impl foreign_crate::ForeignTrait for AliasOfForeignType<()> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------- | | | | | `AliasOfForeignType<()>` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr b/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr index 41f42455bde0a..5403b4fd2dc87 100644 --- a/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr +++ b/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr @@ -5,7 +5,7 @@ LL | impl Eq for Y {} | ^^^^^^^^^^^^- | | | | | `(u32) is 1..=` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr b/tests/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr index 32e6e88fc4834..65202c1369160 100644 --- a/tests/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr +++ b/tests/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr @@ -5,7 +5,7 @@ LL | impl DefaultedTrait for (A,) {} | ^^^^^^^^^^^^^^^^^^^^^^^^---- | | | | | this is not defined in the current crate because tuples are always foreign - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead @@ -16,7 +16,7 @@ LL | impl !DefaultedTrait for (B,) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^---- | | | | | this is not defined in the current crate because tuples are always foreign - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead @@ -33,7 +33,7 @@ LL | impl DefaultedTrait for lib::Something {} | ^^^^^^^^^^^^^^^^^^^^^^^^----------------- | | | | | `Something` is not defined in the current crate - | impl doesn't use only types from inside the current crate + | impl doesn't use any uncovered types from inside the current crate | = note: define and implement a trait or new type instead From ca94dd5beac8252f03047a1eeb6a7c456b467c03 Mon Sep 17 00:00:00 2001 From: Jonathan Birk Date: Sun, 11 Aug 2024 10:13:50 +0000 Subject: [PATCH 004/260] Add more information link to orphan impls --- compiler/rustc_hir_analysis/messages.ftl | 4 +++- compiler/rustc_hir_analysis/src/errors.rs | 3 +++ tests/ui/coherence/coherence-cow.re_a.stderr | 3 ++- tests/ui/coherence/coherence-cow.re_b.stderr | 3 ++- tests/ui/coherence/coherence-cow.re_c.stderr | 3 ++- .../coherence-fundamental-trait-objects.stderr | 3 ++- ...rence-impl-trait-for-marker-trait-negative.stderr | 3 ++- ...rence-impl-trait-for-marker-trait-positive.stderr | 3 ++- tests/ui/coherence/coherence-impls-copy.stderr | 12 ++++++++---- tests/ui/coherence/coherence-impls-send.stderr | 9 ++++++--- tests/ui/coherence/coherence-impls-sized.stderr | 9 ++++++--- .../coherence-negative-impls-copy-bad.stderr | 9 ++++++--- tests/ui/coherence/coherence-orphan.stderr | 6 ++++-- .../ui/coherence/coherence-overlapping-pairs.stderr | 3 ++- .../coherence-pair-covered-uncovered-1.stderr | 3 ++- .../coherence-pair-covered-uncovered.stderr | 3 ++- tests/ui/coherence/coherence-vec-local-2.stderr | 3 ++- tests/ui/coherence/coherence-vec-local.stderr | 3 ++- tests/ui/coherence/coherence_local_err_struct.stderr | 3 ++- tests/ui/coherence/coherence_local_err_tuple.stderr | 3 ++- tests/ui/coherence/impl-foreign-for-foreign.stderr | 3 ++- .../impl-foreign-for-foreign[foreign].stderr | 9 ++++++--- .../impl-foreign-for-fundamental[foreign].stderr | 6 ++++-- .../impl-foreign[foreign]-for-foreign.stderr | 3 ++- ...-foreign[fundemental[foreign]]-for-foreign.stderr | 9 ++++++--- .../coherence/impl[t]-foreign-for-foreign[t].stderr | 6 ++++-- tests/ui/dropck/drop-on-non-struct.stderr | 3 ++- tests/ui/error-codes/E0117.stderr | 3 ++- tests/ui/error-codes/e0119/complex-impl.stderr | 3 ++- tests/ui/errors/issue-99572-impl-trait-on-pointer.rs | 6 ++++-- .../errors/issue-99572-impl-trait-on-pointer.stderr | 8 +++++--- tests/ui/issues/issue-67535.stderr | 9 ++++++--- .../const-and-non-const-impl.stderr | 3 ++- .../type-alias-impl-trait/coherence.classic.stderr | 3 ++- tests/ui/type-alias-impl-trait/coherence.next.stderr | 3 ++- .../pattern_types/range_patterns_trait_impls2.stderr | 3 ++- ...k-default-trait-impl-cross-crate-coherence.stderr | 9 ++++++--- 37 files changed, 121 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 33bda77e3353b..c81f1c62be9cc 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -351,7 +351,9 @@ hir_analysis_only_current_traits_arbitrary = only traits defined in the current hir_analysis_only_current_traits_foreign = this is not defined in the current crate because this is a foreign trait -hir_analysis_only_current_traits_label = impl doesn't use any uncovered types from inside the current crate +hir_analysis_only_current_traits_label = impl doesn't have any local type before any uncovered type parameters + +hir_analysis_only_current_traits_label_more_info = for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules hir_analysis_only_current_traits_name = this is not defined in the current crate because {$name} are always foreign diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index b1ac973ef2e00..9488f2f86cb3e 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1441,6 +1441,7 @@ pub enum OnlyCurrentTraits { Outside { #[primary_span] #[label(hir_analysis_only_current_traits_label)] + #[label(hir_analysis_only_current_traits_label_more_info)] span: Span, #[note(hir_analysis_only_current_traits_note)] note: (), @@ -1449,6 +1450,7 @@ pub enum OnlyCurrentTraits { Primitive { #[primary_span] #[label(hir_analysis_only_current_traits_label)] + #[label(hir_analysis_only_current_traits_label_more_info)] span: Span, #[note(hir_analysis_only_current_traits_note)] note: (), @@ -1457,6 +1459,7 @@ pub enum OnlyCurrentTraits { Arbitrary { #[primary_span] #[label(hir_analysis_only_current_traits_label)] + #[label(hir_analysis_only_current_traits_label_more_info)] span: Span, #[note(hir_analysis_only_current_traits_note)] note: (), diff --git a/tests/ui/coherence/coherence-cow.re_a.stderr b/tests/ui/coherence/coherence-cow.re_a.stderr index 3e929d4fb3379..b4331fc475b1e 100644 --- a/tests/ui/coherence/coherence-cow.re_a.stderr +++ b/tests/ui/coherence/coherence-cow.re_a.stderr @@ -5,7 +5,8 @@ LL | impl Remote for Pair> { } | ^^^^^^^^^^^^^^^^^^^---------------- | | | | | `Pair` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-cow.re_b.stderr b/tests/ui/coherence/coherence-cow.re_b.stderr index d267f859aea28..b401d96459885 100644 --- a/tests/ui/coherence/coherence-cow.re_b.stderr +++ b/tests/ui/coherence/coherence-cow.re_b.stderr @@ -5,7 +5,8 @@ LL | impl Remote for Pair,T> { } | ^^^^^^^^^^^^^^^^^^^---------------- | | | | | `Pair` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-cow.re_c.stderr b/tests/ui/coherence/coherence-cow.re_c.stderr index e2671cc3dd155..d95beee8139e2 100644 --- a/tests/ui/coherence/coherence-cow.re_c.stderr +++ b/tests/ui/coherence/coherence-cow.re_c.stderr @@ -5,7 +5,8 @@ LL | impl Remote for Pair,U> { } | ^^^^^^^^^^^^^^^^^^^^^---------------- | | | | | `Pair` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-fundamental-trait-objects.stderr b/tests/ui/coherence/coherence-fundamental-trait-objects.stderr index a0bf8f23f2c61..4933fb155f732 100644 --- a/tests/ui/coherence/coherence-fundamental-trait-objects.stderr +++ b/tests/ui/coherence/coherence-fundamental-trait-objects.stderr @@ -5,7 +5,8 @@ LL | impl Misc for dyn Fundamental {} | ^^^^^^^^^^^^^^---------------------- | | | | | `dyn Fundamental` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr index abe752cb65e99..c8b215037b9ef 100644 --- a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr +++ b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr @@ -41,7 +41,8 @@ LL | impl !Send for dyn Marker2 {} | ^^^^^^^^^^^^^^^----------- | | | | | `dyn Marker2` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr index 99a32f1bf9347..02107453a9ff3 100644 --- a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr +++ b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr @@ -41,7 +41,8 @@ LL | unsafe impl Send for dyn Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^----------- | | | | | `dyn Marker2` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-impls-copy.stderr b/tests/ui/coherence/coherence-impls-copy.stderr index e8db69fa983d9..2de854ed58430 100644 --- a/tests/ui/coherence/coherence-impls-copy.stderr +++ b/tests/ui/coherence/coherence-impls-copy.stderr @@ -15,7 +15,8 @@ LL | impl Copy for &'static [NotSync] {} | ^^^^^^^^^^^^^^------------------ | | | | | this is not defined in the current crate because slices are always foreign - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead @@ -26,7 +27,8 @@ LL | impl Copy for i32 {} | ^^^^^^^^^^^^^^--- | | | | | `i32` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead @@ -43,7 +45,8 @@ LL | impl Copy for (MyType, MyType) {} | ^^^^^^^^^^^^^^---------------- | | | | | this is not defined in the current crate because tuples are always foreign - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead @@ -60,7 +63,8 @@ LL | impl Copy for [MyType] {} | ^^^^^^^^^^^^^^-------- | | | | | this is not defined in the current crate because slices are always foreign - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-impls-send.stderr b/tests/ui/coherence/coherence-impls-send.stderr index 2432e6f22d13a..a41e9d620e01c 100644 --- a/tests/ui/coherence/coherence-impls-send.stderr +++ b/tests/ui/coherence/coherence-impls-send.stderr @@ -5,7 +5,8 @@ LL | unsafe impl Send for &'static [NotSync] {} | ^^^^^^^^^^^^^^^^^^^^^------------------ | | | | | this is not defined in the current crate because slices are always foreign - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead @@ -16,7 +17,8 @@ LL | unsafe impl Send for (MyType, MyType) {} | ^^^^^^^^^^^^^^^^^^^^^---------------- | | | | | this is not defined in the current crate because tuples are always foreign - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead @@ -33,7 +35,8 @@ LL | unsafe impl Send for [MyType] {} | ^^^^^^^^^^^^^^^^^^^^^-------- | | | | | this is not defined in the current crate because slices are always foreign - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-impls-sized.stderr b/tests/ui/coherence/coherence-impls-sized.stderr index 5069f752f7434..080d19e075b5f 100644 --- a/tests/ui/coherence/coherence-impls-sized.stderr +++ b/tests/ui/coherence/coherence-impls-sized.stderr @@ -23,7 +23,8 @@ LL | impl Sized for (MyType, MyType) {} | ^^^^^^^^^^^^^^^---------------- | | | | | this is not defined in the current crate because tuples are always foreign - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead @@ -46,7 +47,8 @@ LL | impl Sized for [MyType] {} | ^^^^^^^^^^^^^^^-------- | | | | | this is not defined in the current crate because slices are always foreign - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead @@ -63,7 +65,8 @@ LL | impl Sized for &'static [NotSync] {} | ^^^^^^^^^^^^^^^------------------ | | | | | this is not defined in the current crate because slices are always foreign - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-negative-impls-copy-bad.stderr b/tests/ui/coherence/coherence-negative-impls-copy-bad.stderr index 2994d1ce0e54a..85937c5f02a81 100644 --- a/tests/ui/coherence/coherence-negative-impls-copy-bad.stderr +++ b/tests/ui/coherence/coherence-negative-impls-copy-bad.stderr @@ -5,7 +5,8 @@ LL | impl !Copy for str {} | ^^^^^^^^^^^^^^^--- | | | | | `str` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead @@ -16,7 +17,8 @@ LL | impl !Copy for fn() {} | ^^^^^^^^^^^^^^^---- | | | | | `fn()` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead @@ -27,7 +29,8 @@ LL | impl !Copy for () {} | ^^^^^^^^^^^^^^^-- | | | | | this is not defined in the current crate because tuples are always foreign - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-orphan.stderr b/tests/ui/coherence/coherence-orphan.stderr index 11b90d8bf2a3f..c10ed013ef251 100644 --- a/tests/ui/coherence/coherence-orphan.stderr +++ b/tests/ui/coherence/coherence-orphan.stderr @@ -6,7 +6,8 @@ LL | impl TheTrait for isize {} | | | | | | | `isize` is not defined in the current crate | | `usize` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead @@ -17,7 +18,8 @@ LL | impl !Send for Vec {} | ^^^^^^^^^^^^^^^---------- | | | | | `Vec` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-overlapping-pairs.stderr b/tests/ui/coherence/coherence-overlapping-pairs.stderr index 17bb8dc314d20..448e7b9d5ef15 100644 --- a/tests/ui/coherence/coherence-overlapping-pairs.stderr +++ b/tests/ui/coherence/coherence-overlapping-pairs.stderr @@ -5,7 +5,8 @@ LL | impl Remote for lib::Pair { } | ^^^^^^^^^^^^^^^^^^^---------------- | | | | | `Pair` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-pair-covered-uncovered-1.stderr b/tests/ui/coherence/coherence-pair-covered-uncovered-1.stderr index f2a3ec4daae6f..2e616fefe0ee3 100644 --- a/tests/ui/coherence/coherence-pair-covered-uncovered-1.stderr +++ b/tests/ui/coherence/coherence-pair-covered-uncovered-1.stderr @@ -6,7 +6,8 @@ LL | impl Remote1>> for i32 { } | | | | | | | `i32` is not defined in the current crate | | `Pair` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-pair-covered-uncovered.stderr b/tests/ui/coherence/coherence-pair-covered-uncovered.stderr index e3f85c3215374..71a1e4c7ac3fb 100644 --- a/tests/ui/coherence/coherence-pair-covered-uncovered.stderr +++ b/tests/ui/coherence/coherence-pair-covered-uncovered.stderr @@ -5,7 +5,8 @@ LL | impl Remote for Pair> { } | ^^^^^^^^^^^^^^^^^^^^^---------------- | | | | | `Pair` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-vec-local-2.stderr b/tests/ui/coherence/coherence-vec-local-2.stderr index 1998dedbbc895..50788e4a990eb 100644 --- a/tests/ui/coherence/coherence-vec-local-2.stderr +++ b/tests/ui/coherence/coherence-vec-local-2.stderr @@ -5,7 +5,8 @@ LL | impl Remote for Vec> { } | ^^^^^^^^^^^^^^^^^^^------------- | | | | | `Vec` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence-vec-local.stderr b/tests/ui/coherence/coherence-vec-local.stderr index 6e95eb7251f6d..cd102fa1c6d1b 100644 --- a/tests/ui/coherence/coherence-vec-local.stderr +++ b/tests/ui/coherence/coherence-vec-local.stderr @@ -5,7 +5,8 @@ LL | impl Remote for Vec { } | ^^^^^^^^^^^^^^^^---------- | | | | | `Vec` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence_local_err_struct.stderr b/tests/ui/coherence/coherence_local_err_struct.stderr index bbf968d5d131c..97a26b54a1be0 100644 --- a/tests/ui/coherence/coherence_local_err_struct.stderr +++ b/tests/ui/coherence/coherence_local_err_struct.stderr @@ -5,7 +5,8 @@ LL | impl lib::MyCopy for lib::MyStruct { } | ^^^^^^^^^^^^^^^^^^^^^--------------------- | | | | | `MyStruct` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/coherence_local_err_tuple.stderr b/tests/ui/coherence/coherence_local_err_tuple.stderr index c988e738af4d8..cdd73be86bfa0 100644 --- a/tests/ui/coherence/coherence_local_err_tuple.stderr +++ b/tests/ui/coherence/coherence_local_err_tuple.stderr @@ -5,7 +5,8 @@ LL | impl lib::MyCopy for (MyType,) { } | ^^^^^^^^^^^^^^^^^^^^^--------- | | | | | this is not defined in the current crate because tuples are always foreign - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/impl-foreign-for-foreign.stderr b/tests/ui/coherence/impl-foreign-for-foreign.stderr index 81ae36c6a53db..0f8af5ef0280b 100644 --- a/tests/ui/coherence/impl-foreign-for-foreign.stderr +++ b/tests/ui/coherence/impl-foreign-for-foreign.stderr @@ -5,7 +5,8 @@ LL | impl Remote for i32 { | ^^^^^^^^^^^^^^^^--- | | | | | `i32` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/impl-foreign-for-foreign[foreign].stderr b/tests/ui/coherence/impl-foreign-for-foreign[foreign].stderr index 9ac7aeff46122..ae1807f6dd055 100644 --- a/tests/ui/coherence/impl-foreign-for-foreign[foreign].stderr +++ b/tests/ui/coherence/impl-foreign-for-foreign[foreign].stderr @@ -6,7 +6,8 @@ LL | impl Remote1> for i32 { | | | | | | | `i32` is not defined in the current crate | | `Rc` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead @@ -18,7 +19,8 @@ LL | impl Remote1> for f64 { | | | | | | | `f64` is not defined in the current crate | | `Rc` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead @@ -30,7 +32,8 @@ LL | impl Remote1> for f32 { | | | | | | | `f32` is not defined in the current crate | | `Rc` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/impl-foreign-for-fundamental[foreign].stderr b/tests/ui/coherence/impl-foreign-for-fundamental[foreign].stderr index fff6a6b511e17..a3522a75c86cf 100644 --- a/tests/ui/coherence/impl-foreign-for-fundamental[foreign].stderr +++ b/tests/ui/coherence/impl-foreign-for-fundamental[foreign].stderr @@ -6,7 +6,8 @@ LL | impl Remote for Box { | | | | | | | `i32` is not defined in the current crate | | `std::alloc::Global` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead @@ -18,7 +19,8 @@ LL | impl Remote for Box> { | | | | | | | `Rc` is not defined in the current crate | | `std::alloc::Global` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/impl-foreign[foreign]-for-foreign.stderr b/tests/ui/coherence/impl-foreign[foreign]-for-foreign.stderr index ca85063986215..bf22e73dd09d8 100644 --- a/tests/ui/coherence/impl-foreign[foreign]-for-foreign.stderr +++ b/tests/ui/coherence/impl-foreign[foreign]-for-foreign.stderr @@ -6,7 +6,8 @@ LL | impl Remote1 for f64 { | | | | | | | `f64` is not defined in the current crate | | `u32` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr b/tests/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr index cc0882095e22f..2ab5cca7983cb 100644 --- a/tests/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr +++ b/tests/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr @@ -7,7 +7,8 @@ LL | impl Remote1> for i32 { | | | `i32` is not defined in the current crate | | `String` is not defined in the current crate | | `std::alloc::Global` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead @@ -20,7 +21,8 @@ LL | impl Remote1>> for f64 { | | | `f64` is not defined in the current crate | | `Rc` is not defined in the current crate | | `std::alloc::Global` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead @@ -33,7 +35,8 @@ LL | impl Remote1>> for f32 { | | | `f32` is not defined in the current crate | | `Rc` is not defined in the current crate | | `std::alloc::Global` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/coherence/impl[t]-foreign-for-foreign[t].stderr b/tests/ui/coherence/impl[t]-foreign-for-foreign[t].stderr index 11260b7d64a33..ca9a7d5cd930a 100644 --- a/tests/ui/coherence/impl[t]-foreign-for-foreign[t].stderr +++ b/tests/ui/coherence/impl[t]-foreign-for-foreign[t].stderr @@ -5,7 +5,8 @@ LL | impl Remote for Rc { | ^^^^^^^^^^^^^^^^--------- | | | | | `Rc` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead @@ -16,7 +17,8 @@ LL | impl Remote for Arc { | ^^^^^^^^^^^^^^^^^^^------ | | | | | `Arc` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/dropck/drop-on-non-struct.stderr b/tests/ui/dropck/drop-on-non-struct.stderr index ec0b2e0d0b645..78b7212b6d9fd 100644 --- a/tests/ui/dropck/drop-on-non-struct.stderr +++ b/tests/ui/dropck/drop-on-non-struct.stderr @@ -11,7 +11,8 @@ LL | impl<'a> Drop for &'a mut isize { | ^^^^^^^^^^^^^^^^^^------------- | | | | | `isize` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/error-codes/E0117.stderr b/tests/ui/error-codes/E0117.stderr index 86328e8131ac0..2bfa78d1954d7 100644 --- a/tests/ui/error-codes/E0117.stderr +++ b/tests/ui/error-codes/E0117.stderr @@ -5,7 +5,8 @@ LL | impl Drop for u32 {} | ^^^^^^^^^^^^^^--- | | | | | `u32` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/error-codes/e0119/complex-impl.stderr b/tests/ui/error-codes/e0119/complex-impl.stderr index 6562593adfafc..36618cee0e837 100644 --- a/tests/ui/error-codes/e0119/complex-impl.stderr +++ b/tests/ui/error-codes/e0119/complex-impl.stderr @@ -5,7 +5,8 @@ LL | impl External for (Q, R) {} | ^^^^^^^^^^^^^^^^^^^^^------ | | | | | this is not defined in the current crate because tuples are always foreign - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/errors/issue-99572-impl-trait-on-pointer.rs b/tests/ui/errors/issue-99572-impl-trait-on-pointer.rs index ae2329ec9c8ca..61f11a88c6144 100644 --- a/tests/ui/errors/issue-99572-impl-trait-on-pointer.rs +++ b/tests/ui/errors/issue-99572-impl-trait-on-pointer.rs @@ -6,7 +6,8 @@ struct LocalType; impl fmt::Display for *mut LocalType { //~^ ERROR only traits defined in the current crate can be implemented for arbitrary types - //~| NOTE impl doesn't use any uncovered types from inside the current crate + //~| NOTE impl doesn't have any local type before any uncovered type parameters + //~| NOTE for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules //~| NOTE `*mut LocalType` is not defined in the current crate because raw pointers are always foreign //~| NOTE define and implement a trait or new type instead //~| HELP consider introducing a new wrapper type @@ -17,7 +18,8 @@ impl fmt::Display for *mut LocalType { impl marker::Copy for *mut T { //~^ ERROR only traits defined in the current crate can be implemented for arbitrary types - //~| NOTE impl doesn't use any uncovered types from inside the current crate + //~| NOTE impl doesn't have any local type before any uncovered type parameters + //~| NOTE for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules //~| NOTE `*mut T` is not defined in the current crate because raw pointers are always foreign //~| NOTE define and implement a trait or new type instead } diff --git a/tests/ui/errors/issue-99572-impl-trait-on-pointer.stderr b/tests/ui/errors/issue-99572-impl-trait-on-pointer.stderr index 5809387e91716..214618d6636fb 100644 --- a/tests/ui/errors/issue-99572-impl-trait-on-pointer.stderr +++ b/tests/ui/errors/issue-99572-impl-trait-on-pointer.stderr @@ -5,7 +5,8 @@ LL | impl fmt::Display for *mut LocalType { | ^^^^^^^^^^^^^^^^^^^^^^-------------- | | | | | `*mut LocalType` is not defined in the current crate because raw pointers are always foreign - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead help: consider introducing a new wrapper type @@ -16,13 +17,14 @@ LL ~ impl fmt::Display for WrapperType { | error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/issue-99572-impl-trait-on-pointer.rs:18:1 + --> $DIR/issue-99572-impl-trait-on-pointer.rs:19:1 | LL | impl marker::Copy for *mut T { | ^^^^^^^^^^^^^^^^^^^^^^^^^------ | | | | | `*mut T` is not defined in the current crate because raw pointers are always foreign - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/issues/issue-67535.stderr b/tests/ui/issues/issue-67535.stderr index 4bfbf1bffdbe7..a953a9152144f 100644 --- a/tests/ui/issues/issue-67535.stderr +++ b/tests/ui/issues/issue-67535.stderr @@ -6,7 +6,8 @@ LL | impl std::ops::AddAssign for () { | | | | | | | this is not defined in the current crate because tuples are always foreign | | this is not defined in the current crate because this is a foreign trait - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead @@ -18,7 +19,8 @@ LL | impl std::ops::AddAssign for [(); 1] { | | | | | | | this is not defined in the current crate because arrays are always foreign | | this is not defined in the current crate because this is a foreign trait - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead @@ -30,7 +32,8 @@ LL | impl std::ops::AddAssign for &[u8] { | | | | | | | this is not defined in the current crate because slices are always foreign | | this is not defined in the current crate because this is a foreign trait - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr index 056cd76075e1b..4dff35c46e840 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr @@ -33,7 +33,8 @@ LL | impl const std::ops::Add for i32 { | | | | | | | `i32` is not defined in the current crate | | `i32` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/type-alias-impl-trait/coherence.classic.stderr b/tests/ui/type-alias-impl-trait/coherence.classic.stderr index 3930a7513d879..4cd87253b3079 100644 --- a/tests/ui/type-alias-impl-trait/coherence.classic.stderr +++ b/tests/ui/type-alias-impl-trait/coherence.classic.stderr @@ -5,7 +5,8 @@ LL | impl foreign_crate::ForeignTrait for AliasOfForeignType<()> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------- | | | | | type alias impl trait is treated as if it were foreign, because its hidden type could be from a foreign crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/type-alias-impl-trait/coherence.next.stderr b/tests/ui/type-alias-impl-trait/coherence.next.stderr index bbda986818848..886b667b8c8bb 100644 --- a/tests/ui/type-alias-impl-trait/coherence.next.stderr +++ b/tests/ui/type-alias-impl-trait/coherence.next.stderr @@ -5,7 +5,8 @@ LL | impl foreign_crate::ForeignTrait for AliasOfForeignType<()> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------- | | | | | `AliasOfForeignType<()>` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr b/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr index 5403b4fd2dc87..2d3f8403315dc 100644 --- a/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr +++ b/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr @@ -5,7 +5,8 @@ LL | impl Eq for Y {} | ^^^^^^^^^^^^- | | | | | `(u32) is 1..=` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead diff --git a/tests/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr b/tests/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr index 65202c1369160..8ee6846eac28a 100644 --- a/tests/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr +++ b/tests/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr @@ -5,7 +5,8 @@ LL | impl DefaultedTrait for (A,) {} | ^^^^^^^^^^^^^^^^^^^^^^^^---- | | | | | this is not defined in the current crate because tuples are always foreign - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead @@ -16,7 +17,8 @@ LL | impl !DefaultedTrait for (B,) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^---- | | | | | this is not defined in the current crate because tuples are always foreign - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead @@ -33,7 +35,8 @@ LL | impl DefaultedTrait for lib::Something {} | ^^^^^^^^^^^^^^^^^^^^^^^^----------------- | | | | | `Something` is not defined in the current crate - | impl doesn't use any uncovered types from inside the current crate + | impl doesn't have any local type before any uncovered type parameters + | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules | = note: define and implement a trait or new type instead From e9cf280ef2ea4550d2305484873a63dfd133abb7 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Mon, 16 Oct 2023 23:56:22 -0700 Subject: [PATCH 005/260] warn less about non-exhaustive in ffi Bindgen allows generating `#[non_exhaustive] #[repr(u32)]` enums. This results in nonintuitive nonlocal `improper_ctypes` warnings, even when the types are otherwise perfectly valid in C. Adjust for actual tooling expectations by avoiding warning on simple enums with only unit variants. --- compiler/rustc_lint/src/types.rs | 27 ++++++++++++------- .../improper_ctypes/auxiliary/types.rs | 11 ++++++++ .../improper_ctypes/extern_crate_improper.rs | 10 ++++++- .../extern_crate_improper.stderr | 10 +++---- 4 files changed, 43 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 900c496e0330d..eef1f0d133ae4 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -3,6 +3,7 @@ use std::ops::ControlFlow; use rustc_data_structures::fx::FxHashSet; use rustc_errors::DiagMessage; +use rustc_hir::def::CtorKind; use rustc_hir::{is_range_literal, Expr, ExprKind, Node}; use rustc_middle::bug; use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton}; @@ -1386,15 +1387,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // Empty enums are okay... although sort of useless. return FfiSafe; } - - if def.is_variant_list_non_exhaustive() && !def.did().is_local() { - return FfiUnsafe { - ty, - reason: fluent::lint_improper_ctypes_non_exhaustive, - help: None, - }; - } - // Check for a repr() attribute to specify the size of the // discriminant. if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none() @@ -1413,8 +1405,25 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { }; } + // non_exhaustive suggests it is possible that someone might break ABI + // see: https://github.com/rust-lang/rust/issues/44109#issuecomment-537583344 + // so warn on complex enums being used outside their crate + let nonexhaustive_nonlocal_ffi = + def.is_variant_list_non_exhaustive() && !def.did().is_local(); + // Check the contained variants. for variant in def.variants() { + // but only warn about really_tagged_union reprs, + // exempt enums with unit ctors like C's (like rust-bindgen) + if nonexhaustive_nonlocal_ffi + && !matches!(variant.ctor_kind(), Some(CtorKind::Const)) + { + return FfiUnsafe { + ty, + reason: fluent::lint_improper_ctypes_non_exhaustive, + help: None, + }; + }; let is_non_exhaustive = variant.is_field_list_non_exhaustive(); if is_non_exhaustive && !variant.def_id.is_local() { return FfiUnsafe { diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/auxiliary/types.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/auxiliary/types.rs index d6251fcb768f4..4dc5932feab40 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/auxiliary/types.rs +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/auxiliary/types.rs @@ -27,3 +27,14 @@ pub enum NonExhaustiveVariants { #[non_exhaustive] Tuple(u32), #[non_exhaustive] Struct { field: u32 } } + +// Note the absence of repr(C): it's not necessary, and recent C code can now use repr hints too. +#[repr(u32)] +#[non_exhaustive] +pub enum NonExhaustiveCLikeEnum { + One = 1, + Two = 2, + Three = 3, + Four = 4, + Five = 5, +} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs index 7a9b465bb56f6..c7f470fb787a7 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs @@ -6,7 +6,10 @@ extern crate types; // This test checks that non-exhaustive types with `#[repr(C)]` from an extern crate are considered // improper. -use types::{NonExhaustiveEnum, NonExhaustiveVariants, NormalStruct, TupleStruct, UnitStruct}; +use types::{ + NonExhaustiveCLikeEnum, NonExhaustiveEnum, NonExhaustiveVariants, + NormalStruct, TupleStruct, UnitStruct, +}; extern "C" { pub fn non_exhaustive_enum(_: NonExhaustiveEnum); @@ -21,4 +24,9 @@ extern "C" { //~^ ERROR `extern` block uses type `NonExhaustiveVariants`, which is not FFI-safe } +// These should pass without remark, as they're C-compatible, despite being "non-exhaustive". +extern "C" { + pub fn non_exhaustive_c_compat_enum(_: NonExhaustiveCLikeEnum); +} + fn main() {} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.stderr index 43c8e1015e674..afc3d3838ad38 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.stderr @@ -1,5 +1,5 @@ error: `extern` block uses type `NonExhaustiveEnum`, which is not FFI-safe - --> $DIR/extern_crate_improper.rs:12:35 + --> $DIR/extern_crate_improper.rs:15:35 | LL | pub fn non_exhaustive_enum(_: NonExhaustiveEnum); | ^^^^^^^^^^^^^^^^^ not FFI-safe @@ -12,7 +12,7 @@ LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ error: `extern` block uses type `NormalStruct`, which is not FFI-safe - --> $DIR/extern_crate_improper.rs:14:44 + --> $DIR/extern_crate_improper.rs:17:44 | LL | pub fn non_exhaustive_normal_struct(_: NormalStruct); | ^^^^^^^^^^^^ not FFI-safe @@ -20,7 +20,7 @@ LL | pub fn non_exhaustive_normal_struct(_: NormalStruct); = note: this struct is non-exhaustive error: `extern` block uses type `UnitStruct`, which is not FFI-safe - --> $DIR/extern_crate_improper.rs:16:42 + --> $DIR/extern_crate_improper.rs:19:42 | LL | pub fn non_exhaustive_unit_struct(_: UnitStruct); | ^^^^^^^^^^ not FFI-safe @@ -28,7 +28,7 @@ LL | pub fn non_exhaustive_unit_struct(_: UnitStruct); = note: this struct is non-exhaustive error: `extern` block uses type `TupleStruct`, which is not FFI-safe - --> $DIR/extern_crate_improper.rs:18:43 + --> $DIR/extern_crate_improper.rs:21:43 | LL | pub fn non_exhaustive_tuple_struct(_: TupleStruct); | ^^^^^^^^^^^ not FFI-safe @@ -36,7 +36,7 @@ LL | pub fn non_exhaustive_tuple_struct(_: TupleStruct); = note: this struct is non-exhaustive error: `extern` block uses type `NonExhaustiveVariants`, which is not FFI-safe - --> $DIR/extern_crate_improper.rs:20:38 + --> $DIR/extern_crate_improper.rs:23:38 | LL | pub fn non_exhaustive_variant(_: NonExhaustiveVariants); | ^^^^^^^^^^^^^^^^^^^^^ not FFI-safe From a31ef1059f5f9e1a08d52ced7f7e171f8ec474a3 Mon Sep 17 00:00:00 2001 From: Maybe Lapkin Date: Fri, 20 Sep 2024 11:28:43 +0200 Subject: [PATCH 006/260] Add flake.nix and .envrc --- .envrc | 3 ++ .gitignore | 2 ++ src/tools/nix-dev-shell/flake.nix | 33 ++++++++++++++++++ src/tools/nix-dev-shell/x/default.nix | 22 ++++++++++++ src/tools/nix-dev-shell/x/x.rs | 50 +++++++++++++++++++++++++++ 5 files changed, 110 insertions(+) create mode 100644 .envrc create mode 100644 src/tools/nix-dev-shell/flake.nix create mode 100644 src/tools/nix-dev-shell/x/default.nix create mode 100644 src/tools/nix-dev-shell/x/x.rs diff --git a/.envrc b/.envrc new file mode 100644 index 0000000000000..ed519d8d9625d --- /dev/null +++ b/.envrc @@ -0,0 +1,3 @@ +if nix flake show path:./src/tools/nix-dev-shell &> /dev/null; then + use flake path:./src/tools/nix-dev-shell +fi diff --git a/.gitignore b/.gitignore index 2e6499081a634..89c62e126b085 100644 --- a/.gitignore +++ b/.gitignore @@ -56,6 +56,8 @@ build/ /src/tools/x/target # Created by default with `src/ci/docker/run.sh` /obj/ +# Created by nix dev shell / .envrc +src/tools/nix-dev-shell/flake.lock ## ICE reports rustc-ice-*.txt diff --git a/src/tools/nix-dev-shell/flake.nix b/src/tools/nix-dev-shell/flake.nix new file mode 100644 index 0000000000000..8ab5e097427d6 --- /dev/null +++ b/src/tools/nix-dev-shell/flake.nix @@ -0,0 +1,33 @@ +{ + description = "rustc dev shell"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, flake-utils, ... }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { inherit system; }; + x = import ./x { inherit pkgs; }; + in + { + devShells.default = with pkgs; mkShell { + name = "rustc-dev-shell"; + nativeBuildInputs = with pkgs; [ + binutils cmake ninja pkg-config python3 git curl cacert patchelf nix + ]; + buildInputs = with pkgs; [ + openssl glibc.out glibc.static x + ]; + # Avoid creating text files for ICEs. + RUSTC_ICE = "0"; + # Provide `libstdc++.so.6` for the self-contained lld. + LD_LIBRARY_PATH = "${with pkgs; lib.makeLibraryPath [ + stdenv.cc.cc.lib + ]}"; + }; + } + ); +} diff --git a/src/tools/nix-dev-shell/x/default.nix b/src/tools/nix-dev-shell/x/default.nix new file mode 100644 index 0000000000000..e6dfbad6f19c8 --- /dev/null +++ b/src/tools/nix-dev-shell/x/default.nix @@ -0,0 +1,22 @@ +{ + pkgs ? import { }, +}: +pkgs.stdenv.mkDerivation { + name = "x"; + + src = ./x.rs; + dontUnpack = true; + + nativeBuildInputs = with pkgs; [ rustc ]; + + buildPhase = '' + PYTHON=${pkgs.lib.getExe pkgs.python3} rustc -Copt-level=3 --crate-name x $src --out-dir $out/bin + ''; + + meta = with pkgs.lib; { + description = "Helper for rust-lang/rust x.py"; + homepage = "https://github.com/rust-lang/rust/blob/master/src/tools/x"; + license = licenses.mit; + mainProgram = "x"; + }; +} diff --git a/src/tools/nix-dev-shell/x/x.rs b/src/tools/nix-dev-shell/x/x.rs new file mode 100644 index 0000000000000..9f83b8fd62e14 --- /dev/null +++ b/src/tools/nix-dev-shell/x/x.rs @@ -0,0 +1,50 @@ +// git clone https://github.com/rust-lang/rust/blob/0ea7ddcc35a2fcaa5da8a7dcfc118c9fb4a63b95/src/tools/x/src/main.rs +// patched to stop doing python probing, stop the probe, please dont, i have a python +//! Run bootstrap from any subdirectory of a rust compiler checkout. +//! +//! We prefer `exec`, to avoid adding an extra process in the process tree. +//! However, since `exec` isn't available on Windows, we indirect through +//! `exec_or_status`, which will call `exec` on unix and `status` on Windows. +//! +//! We use `powershell.exe x.ps1` on Windows, and `sh -c x` on Unix, those are +//! the ones that call `x.py`. We use `sh -c` on Unix, because it is a standard. +//! We also don't use `pwsh` on Windows, because it is not installed by default; + +use std::env; +use std::os::unix::process::CommandExt; +use std::process::{self, Command}; + +fn main() { + match env::args().skip(1).next().as_deref() { + Some("--wrapper-version") => { + println!("0.1.0"); + return; + } + _ => {} + } + let current = match env::current_dir() { + Ok(dir) => dir, + Err(err) => { + eprintln!("Failed to get current directory: {err}"); + process::exit(1); + } + }; + + for dir in current.ancestors() { + let candidate = dir.join("x.py"); + if candidate.exists() { + let mut cmd = Command::new(env!("PYTHON")); + cmd.arg(dir.join("x.py")); + cmd.args(env::args().skip(1)).current_dir(dir); + + let error = cmd.exec(); + eprintln!("Failed to invoke `{:?}`: {}", cmd, error); + } + } + + eprintln!( + "x.py not found. Please run inside of a checkout of `https://github.com/rust-lang/rust`." + ); + + process::exit(1); +} From 002a6b134f910be617722f9d25e0ea8016c2a54e Mon Sep 17 00:00:00 2001 From: Maybe Lapkin Date: Sat, 21 Sep 2024 11:44:38 +0200 Subject: [PATCH 007/260] Add an option of using nix-shell instead of nix flake --- .envrc | 3 --- src/tools/nix-dev-shell/envrc-flake | 8 ++++++++ src/tools/nix-dev-shell/envrc-shell | 7 +++++++ src/tools/nix-dev-shell/shell.nix | 19 +++++++++++++++++++ 4 files changed, 34 insertions(+), 3 deletions(-) delete mode 100644 .envrc create mode 100644 src/tools/nix-dev-shell/envrc-flake create mode 100644 src/tools/nix-dev-shell/envrc-shell create mode 100644 src/tools/nix-dev-shell/shell.nix diff --git a/.envrc b/.envrc deleted file mode 100644 index ed519d8d9625d..0000000000000 --- a/.envrc +++ /dev/null @@ -1,3 +0,0 @@ -if nix flake show path:./src/tools/nix-dev-shell &> /dev/null; then - use flake path:./src/tools/nix-dev-shell -fi diff --git a/src/tools/nix-dev-shell/envrc-flake b/src/tools/nix-dev-shell/envrc-flake new file mode 100644 index 0000000000000..218d88d8721fa --- /dev/null +++ b/src/tools/nix-dev-shell/envrc-flake @@ -0,0 +1,8 @@ +# If you want to use this as an .envrc file to create a shell with necessery components +# to develop rustc, use the following command in the root of the rusr checkout: +# +# ln -s ./src/tools/nix-dev-shell/envrc-flake ./.envrc && echo .envrc >> .git/info/exclude + +if nix flake show path:./src/tools/nix-dev-shell &> /dev/null; then + use flake path:./src/tools/nix-dev-shell +fi diff --git a/src/tools/nix-dev-shell/envrc-shell b/src/tools/nix-dev-shell/envrc-shell new file mode 100644 index 0000000000000..fb7231a6c30ce --- /dev/null +++ b/src/tools/nix-dev-shell/envrc-shell @@ -0,0 +1,7 @@ +# If you want to use this as an .envrc file to create a shell with necessery components +# to develop rustc, use the following command in the root of the rusr checkout: +# +# ln -s ./src/tools/nix-dev-shell/envrc-shell ./.envrc && echo .envrc >> .git/info/exclude + +use nix ./src/tools/nix-dev-shell/shell.nix + diff --git a/src/tools/nix-dev-shell/shell.nix b/src/tools/nix-dev-shell/shell.nix new file mode 100644 index 0000000000000..8a5cbb7c89e47 --- /dev/null +++ b/src/tools/nix-dev-shell/shell.nix @@ -0,0 +1,19 @@ +{ pkgs ? import {} }: +let + x = import ./x { inherit pkgs; }; +in +pkgs.mkShell { + name = "rustc"; + nativeBuildInputs = with pkgs; [ + binutils cmake ninja pkg-config python3 git curl cacert patchelf nix + ]; + buildInputs = with pkgs; [ + openssl glibc.out glibc.static x + ]; + # Avoid creating text files for ICEs. + RUSTC_ICE = "0"; + # Provide `libstdc++.so.6` for the self-contained lld. + LD_LIBRARY_PATH = "${with pkgs; lib.makeLibraryPath [ + stdenv.cc.cc.lib + ]}"; +} From 9f5bfe24eb254fbe3f745062a4c9ce1c76ff800f Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Sat, 21 Sep 2024 12:46:08 +0100 Subject: [PATCH 008/260] Implement lint for regex::Regex compilation inside a loop --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/regex.rs | 62 +++++++++++++++++++++++++++++- tests/ui/regex.rs | 28 +++++++++++++- tests/ui/regex.stderr | 52 ++++++++++++++++++++++++- 5 files changed, 141 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e5d1688e4a72..c385405e08a84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5873,6 +5873,7 @@ Released 2018-09-13 [`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref [`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref [`ref_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_patterns +[`regex_creation_in_loops`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_creation_in_loops [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro [`renamed_function_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#renamed_function_params [`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 16c64830e70dd..25a224a47ff76 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -637,6 +637,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::ref_patterns::REF_PATTERNS_INFO, crate::reference::DEREF_ADDROF_INFO, crate::regex::INVALID_REGEX_INFO, + crate::regex::REGEX_CREATION_IN_LOOPS_INFO, crate::regex::TRIVIAL_REGEX_INFO, crate::repeat_vec_with_capacity::REPEAT_VEC_WITH_CAPACITY_INFO, crate::reserve_after_initialization::RESERVE_AFTER_INITIALIZATION_INFO, diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index f6ef02b7c2330..1671737db0181 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -55,6 +55,44 @@ declare_clippy_lint! { "trivial regular expressions" } +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for [regex](https://crates.io/crates/regex) compilation inside a loop with a literal. + /// + /// ### Why is this bad? + /// + /// Compiling a regex is a much more expensive operation than using one, and a compiled regex can be used multiple times. + /// This is documented as an antipattern [on the regex documentation](https://docs.rs/regex/latest/regex/#avoid-re-compiling-regexes-especially-in-a-loop) + /// + /// ### Example + /// ```no_run + /// # let haystacks = [""]; + /// # const MY_REGEX: &str = "a.b"; + /// for haystack in haystacks { + /// let regex = regex::Regex::new(MY_REGEX).unwrap(); + /// if regex.is_match(haystack) { + /// // Perform operation + /// } + /// } + /// ``` + /// can be replaced with + /// ```no_run + /// # let haystacks = [""]; + /// # const MY_REGEX: &str = "a.b"; + /// let regex = regex::Regex::new(MY_REGEX).unwrap(); + /// for haystack in haystacks { + /// if regex.is_match(haystack) { + /// // Perform operation + /// } + /// } + /// ``` + #[clippy::version = "1.83.0"] + pub REGEX_CREATION_IN_LOOPS, + perf, + "regular expression compilation performed in a loop" +} + #[derive(Copy, Clone)] enum RegexKind { Unicode, @@ -66,9 +104,10 @@ enum RegexKind { #[derive(Default)] pub struct Regex { definitions: DefIdMap, + loop_stack: Vec, } -impl_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]); +impl_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX, REGEX_CREATION_IN_LOOPS]); impl<'tcx> LateLintPass<'tcx> for Regex { fn check_crate(&mut self, cx: &LateContext<'tcx>) { @@ -96,12 +135,33 @@ impl<'tcx> LateLintPass<'tcx> for Regex { && let Some(def_id) = path_def_id(cx, fun) && let Some(regex_kind) = self.definitions.get(&def_id) { + if let Some(&loop_span) = self.loop_stack.last() + && (matches!(arg.kind, ExprKind::Lit(_)) || const_str(cx, arg).is_some()) + { + span_lint_and_help( + cx, + REGEX_CREATION_IN_LOOPS, + fun.span, + "compiling a regex in a loop", + Some(loop_span), + "move the regex construction outside this loop", + ); + } + match regex_kind { RegexKind::Unicode => check_regex(cx, arg, true), RegexKind::UnicodeSet => check_set(cx, arg, true), RegexKind::Bytes => check_regex(cx, arg, false), RegexKind::BytesSet => check_set(cx, arg, false), } + } else if let ExprKind::Loop(_, _, _, span) = expr.kind { + self.loop_stack.push(span); + } + } + + fn check_expr_post(&mut self, _: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if matches!(expr.kind, ExprKind::Loop(..)) { + self.loop_stack.pop(); } } } diff --git a/tests/ui/regex.rs b/tests/ui/regex.rs index 4fb6c08bb4495..3352239892c53 100644 --- a/tests/ui/regex.rs +++ b/tests/ui/regex.rs @@ -5,7 +5,7 @@ clippy::needless_borrow, clippy::needless_borrows_for_generic_args )] -#![warn(clippy::invalid_regex, clippy::trivial_regex)] +#![warn(clippy::invalid_regex, clippy::trivial_regex, clippy::regex_creation_in_loops)] extern crate regex; @@ -118,7 +118,33 @@ fn trivial_regex() { let _ = BRegex::new(r"\b{start}word\b{end}"); } +fn regex_creation_in_loops() { + loop { + let regex = Regex::new("a.b"); + //~^ ERROR: compiling a regex in a loop + let regex = BRegex::new("a.b"); + //~^ ERROR: compiling a regex in a loop + #[allow(clippy::regex_creation_in_loops)] + let allowed_regex = Regex::new("a.b"); + + if true { + let regex = Regex::new("a.b"); + //~^ ERROR: compiling a regex in a loop + } + + for _ in 0..10 { + let nested_regex = Regex::new("a.b"); + //~^ ERROR: compiling a regex in a loop + } + } + + for i in 0..10 { + let dependant_regex = Regex::new(&format!("{i}")); + } +} + fn main() { syntax_error(); trivial_regex(); + regex_creation_in_loops(); } diff --git a/tests/ui/regex.stderr b/tests/ui/regex.stderr index e936208d8d7b6..38e14b1631678 100644 --- a/tests/ui/regex.stderr +++ b/tests/ui/regex.stderr @@ -195,5 +195,55 @@ LL | let binary_trivial_empty = BRegex::new("^$"); | = help: consider using `str::is_empty` -error: aborting due to 24 previous errors +error: compiling a regex in a loop + --> tests/ui/regex.rs:123:21 + | +LL | let regex = Regex::new("a.b"); + | ^^^^^^^^^^ + | +help: move the regex construction outside this loop + --> tests/ui/regex.rs:122:5 + | +LL | loop { + | ^^^^ + = note: `-D clippy::regex-creation-in-loops` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::regex_creation_in_loops)]` + +error: compiling a regex in a loop + --> tests/ui/regex.rs:125:21 + | +LL | let regex = BRegex::new("a.b"); + | ^^^^^^^^^^^ + | +help: move the regex construction outside this loop + --> tests/ui/regex.rs:122:5 + | +LL | loop { + | ^^^^ + +error: compiling a regex in a loop + --> tests/ui/regex.rs:131:25 + | +LL | let regex = Regex::new("a.b"); + | ^^^^^^^^^^ + | +help: move the regex construction outside this loop + --> tests/ui/regex.rs:122:5 + | +LL | loop { + | ^^^^ + +error: compiling a regex in a loop + --> tests/ui/regex.rs:136:32 + | +LL | let nested_regex = Regex::new("a.b"); + | ^^^^^^^^^^ + | +help: move the regex construction outside this loop + --> tests/ui/regex.rs:135:9 + | +LL | for _ in 0..10 { + | ^^^^^^^^^^^^^^ + +error: aborting due to 28 previous errors From b522e7a944341d463bf9091bd72faffcc807d875 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 12 Aug 2024 20:39:25 +0200 Subject: [PATCH 009/260] Generate lint list in HTML directly instead of JS --- .github/deploy.sh | 1 - .gitignore | 1 + Cargo.toml | 2 + clippy_dev/src/serve.rs | 2 +- rinja.toml | 8 ++ tests/compile-test.rs | 33 +++++- .../{index.html => index_template.html} | 103 ++++++++--------- util/gh-pages/script.js | 108 ++++++++++-------- 8 files changed, 152 insertions(+), 106 deletions(-) create mode 100644 rinja.toml rename util/gh-pages/{index.html => index_template.html} (79%) diff --git a/.github/deploy.sh b/.github/deploy.sh index 5b4b4be4e36b5..6cebbb7801b0c 100644 --- a/.github/deploy.sh +++ b/.github/deploy.sh @@ -9,7 +9,6 @@ echo "Making the docs for master" mkdir out/master/ cp util/gh-pages/index.html out/master cp util/gh-pages/script.js out/master -cp util/gh-pages/lints.json out/master cp util/gh-pages/style.css out/master if [[ -n $TAG_NAME ]]; then diff --git a/.gitignore b/.gitignore index 181b71a658b9a..a7c25b29021fb 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ out # gh pages docs util/gh-pages/lints.json +util/gh-pages/index.html # rustfmt backups *.rs.bk diff --git a/Cargo.toml b/Cargo.toml index cf810798d8cc1..c7383520741be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,8 @@ toml = "0.7.3" walkdir = "2.3" filetime = "0.2.9" itertools = "0.12" +pulldown-cmark = "0.11" +rinja = { version = "0.3", default-features = false, features = ["config"] } # UI test dependencies clippy_utils = { path = "clippy_utils" } diff --git a/clippy_dev/src/serve.rs b/clippy_dev/src/serve.rs index cc14cd8dae69e..0216d884e2d59 100644 --- a/clippy_dev/src/serve.rs +++ b/clippy_dev/src/serve.rs @@ -19,7 +19,7 @@ pub fn run(port: u16, lint: Option) -> ! { }); loop { - if mtime("util/gh-pages/lints.json") < mtime("clippy_lints/src") { + if mtime("util/gh-pages/index.html") < mtime("clippy_lints/src") { Command::new(env::var("CARGO").unwrap_or("cargo".into())) .arg("collect-metadata") .spawn() diff --git a/rinja.toml b/rinja.toml new file mode 100644 index 0000000000000..5fa682788bd0e --- /dev/null +++ b/rinja.toml @@ -0,0 +1,8 @@ +[general] +dirs = ["util/gh-pages/"] +default_syntax = "mixed" + +[[syntax]] +name = "mixed" +expr_start = "{(" +expr_end = ")}" diff --git a/tests/compile-test.rs b/tests/compile-test.rs index af2aa51925777..0bd6ac677702d 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -8,6 +8,8 @@ use clippy_config::ClippyConfiguration; use clippy_lints::LintInfo; use clippy_lints::declared_lints::LINTS; use clippy_lints::deprecated_lints::{DEPRECATED, DEPRECATED_VERSION, RENAMED}; +use pulldown_cmark::{Options, Parser, html}; +use rinja::{Template, filters::Safe}; use serde::{Deserialize, Serialize}; use test_utils::IS_RUSTC_TEST_SUITE; use ui_test::custom_flags::Flag; @@ -385,6 +387,22 @@ fn ui_cargo_toml_metadata() { } } +#[derive(Template)] +#[template(path = "index_template.html")] +struct Renderer<'a> { + lints: &'a Vec, +} + +impl<'a> Renderer<'a> { + fn markdown(&self, input: &str) -> Safe { + let parser = Parser::new_ext(input, Options::all()); + let mut html_output = String::new(); + html::push_html(&mut html_output, parser); + // Oh deer, what a hack :O + Safe(html_output.replace(", @@ -559,4 +576,14 @@ impl LintMetadata { applicability: Applicability::Unspecified, } } + + fn applicability_str(&self) -> &str { + match self.applicability { + Applicability::MachineApplicable => "MachineApplicable", + Applicability::HasPlaceholders => "HasPlaceholders", + Applicability::MaybeIncorrect => "MaybeIncorrect", + Applicability::Unspecified => "Unspecified", + _ => panic!("needs to update this code"), + } + } } diff --git a/util/gh-pages/index.html b/util/gh-pages/index_template.html similarity index 79% rename from util/gh-pages/index.html rename to util/gh-pages/index_template.html index f3d7e504fdf80..ee134eaaa98e3 100644 --- a/util/gh-pages/index.html +++ b/util/gh-pages/index_template.html @@ -55,16 +55,8 @@

Clippy Lints

-
- - - - -
+
+
@@ -188,9 +180,7 @@

Clippy Lints

- +
- -
-
-

-
- {{lint.id}} - - - 📋 - -
+ {% for lint in lints %} +
+
+

+
+ {(lint.id)} + + + 📋 + +
-
- {{lint.group}} +
+ {(lint.group)} - {{lint.level}} + {(lint.level)} - - + -
-

-
+ + + +

+ + -
-
-
- -
- Applicability: - {{lint.applicability}} - (?) -
- -
- {{lint.group == "deprecated" ? "Deprecated" : "Added"}} in: - {{lint.version}} -
- - - -
- View Source +
+
{(markdown(lint.docs))}
+
+ {# Applicability #} +
+ Applicability: + {( lint.applicability_str() )} + (?) +
+ +
+ {% if lint.group == "deprecated" %}Deprecated{% else %} Added{% endif %} in: + {(lint.version)} +
+ + + +
-
- + + {% endfor %}
diff --git a/util/gh-pages/script.js b/util/gh-pages/script.js index 1a5330bc0e571..8942628d5da04 100644 --- a/util/gh-pages/script.js +++ b/util/gh-pages/script.js @@ -1,21 +1,4 @@ (function () { - const md = window.markdownit({ - html: true, - linkify: true, - typographer: true, - highlight: function (str, lang) { - if (lang && hljs.getLanguage(lang)) { - try { - return '
' +
-                        hljs.highlight(str, { language: lang, ignoreIllegals: true }).value +
-                        '
'; - } catch (__) {} - } - - return '
' + md.utils.escapeHtml(str) + '
'; - } - }); - function scrollToLint(lintId) { const target = document.getElementById(lintId); if (!target) { @@ -41,15 +24,6 @@ } angular.module("clippy", []) - .filter('markdown', function ($sce) { - return function (text) { - return $sce.trustAsHtml( - md.render(text || '') - // Oh deer, what a hack :O - .replace(' { + if (searchState.timeout !== null) { + clearTimeout(searchState.timeout); + searchState.timeout = null + } + }, + resetInputTimeout: () => { + searchState.clearInputTimeout(); + setTimeout(searchState.filterLints, 50); + }, + filterLints: () => { + let searchStr = searchState.value.trim().toLowerCase(); + if (searchStr.startsWith("clippy::")) { + searchStr = searchStr.slice(8); + } + const terms = searchStr.split(" "); + + onEachLazy(document.querySelectorAll("article"), lint => { + // Search by id + if (lint.id.indexOf(searchStr.replaceAll("-", "_")) !== -1) { + el.style.display = ""; + return; + } + // Search the description + // The use of `for`-loops instead of `foreach` enables us to return early + const docsLowerCase = lint.docs.toLowerCase(); + for (index = 0; index < terms.length; index++) { + // This is more likely and will therefore be checked first + if (docsLowerCase.indexOf(terms[index]) !== -1) { + continue; + } + + if (lint.id.indexOf(terms[index]) !== -1) { + continue; + } + + return false; + } + }); + }, +}; + +function handleInputChanged(event) { + if (event.target !== document.activeElement) { + return; + } + searchState.resetInputTimeout(); +} + function storeValue(settingName, value) { try { localStorage.setItem(`clippy-lint-list-${settingName}`, value); @@ -627,3 +643,5 @@ if (prefersDark.matches && !theme) { } let disableShortcuts = loadValue('disable-shortcuts') === "true"; document.getElementById("disable-shortcuts").checked = disableShortcuts; + +hljs.highlightAll(); From 9661ba07408c901d9521e27ee8453f769ab12744 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 13 Aug 2024 20:47:42 +0200 Subject: [PATCH 010/260] Update `cargo dev serve` command to look over the correct files --- clippy_dev/src/serve.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clippy_dev/src/serve.rs b/clippy_dev/src/serve.rs index 0216d884e2d59..d367fefec619c 100644 --- a/clippy_dev/src/serve.rs +++ b/clippy_dev/src/serve.rs @@ -19,7 +19,9 @@ pub fn run(port: u16, lint: Option) -> ! { }); loop { - if mtime("util/gh-pages/index.html") < mtime("clippy_lints/src") { + let index_time = mtime("util/gh-pages/index.html"); + + if index_time < mtime("clippy_lints/src") || index_time < mtime("util/gh-pages/index_template.html") { Command::new(env::var("CARGO").unwrap_or("cargo".into())) .arg("collect-metadata") .spawn() From 0055cebaa3c0ab3cb0921efa20b18b0f291ae3ea Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 13 Aug 2024 20:47:54 +0200 Subject: [PATCH 011/260] Replace search with vanilla JS --- tests/compile-test.rs | 2 +- util/gh-pages/index_template.html | 29 +++++++------ util/gh-pages/script.js | 68 ++++++++++++------------------- 3 files changed, 43 insertions(+), 56 deletions(-) diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 0bd6ac677702d..00627dc0bb1f9 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -10,7 +10,7 @@ use clippy_lints::declared_lints::LINTS; use clippy_lints::deprecated_lints::{DEPRECATED, DEPRECATED_VERSION, RENAMED}; use pulldown_cmark::{Options, Parser, html}; use rinja::{Template, filters::Safe}; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use test_utils::IS_RUSTC_TEST_SUITE; use ui_test::custom_flags::Flag; use ui_test::custom_flags::rustfix::RustfixMode; diff --git a/util/gh-pages/index_template.html b/util/gh-pages/index_template.html index ee134eaaa98e3..5baa03da2ea40 100644 --- a/util/gh-pages/index_template.html +++ b/util/gh-pages/index_template.html @@ -180,9 +180,9 @@

Clippy Lints

- + - @@ -199,22 +199,22 @@

Clippy Lints

{% for lint in lints %} -
+

{(lint.id)} - - + 📋
- {(lint.group)} + {(lint.group)} - {(lint.level)} + {(lint.level)} @@ -223,7 +223,7 @@

-
+
{(markdown(lint.docs))}
{# Applicability #} @@ -232,18 +232,21 @@

{( lint.applicability_str() )} (?)

- + {# Clippy version #}
{% if lint.group == "deprecated" %}Deprecated{% else %} Added{% endif %} in: {(lint.version)}
- + {# Open related issues #} - -
- View Source + + {# Jump to source #} + {% if let Some(id_location) = lint.id_location %} +
+ View Source + {% endif %}
diff --git a/util/gh-pages/script.js b/util/gh-pages/script.js index 8942628d5da04..eb563a0f242c4 100644 --- a/util/gh-pages/script.js +++ b/util/gh-pages/script.js @@ -361,42 +361,6 @@ return $scope.groups[lint.group]; }; - $scope.bySearch = function (lint, index, array) { - let searchStr = $scope.search; - // It can be `null` I haven't missed this value - if (searchStr == null) { - return true; - } - searchStr = searchStr.toLowerCase(); - if (searchStr.startsWith("clippy::")) { - searchStr = searchStr.slice(8); - } - - // Search by id - if (lint.id.indexOf(searchStr.replaceAll("-", "_")) !== -1) { - return true; - } - - // Search the description - // The use of `for`-loops instead of `foreach` enables us to return early - const terms = searchStr.split(" "); - const docsLowerCase = lint.docs.toLowerCase(); - for (index = 0; index < terms.length; index++) { - // This is more likely and will therefore be checked first - if (docsLowerCase.indexOf(terms[index]) !== -1) { - continue; - } - - if (lint.id.indexOf(terms[index]) !== -1) { - continue; - } - - return false; - } - - return true; - } - $scope.byApplicabilities = function (lint) { return $scope.applicabilities[lint.applicability]; }; @@ -472,6 +436,11 @@ function getQueryVariable(variable) { window.searchState = { timeout: null, inputElem: document.getElementById("search-input"), + lastSearch: '', + clearInput: () => { + searchState.inputElem.value = ""; + searchState.filterLints(); + }, clearInputTimeout: () => { if (searchState.timeout !== null) { clearTimeout(searchState.timeout); @@ -483,32 +452,38 @@ window.searchState = { setTimeout(searchState.filterLints, 50); }, filterLints: () => { - let searchStr = searchState.value.trim().toLowerCase(); + searchState.clearInputTimeout(); + + let searchStr = searchState.inputElem.value.trim().toLowerCase(); if (searchStr.startsWith("clippy::")) { searchStr = searchStr.slice(8); } + if (searchState.lastSearch === searchStr) { + return; + } + searchState.lastSearch = searchStr; const terms = searchStr.split(" "); onEachLazy(document.querySelectorAll("article"), lint => { // Search by id if (lint.id.indexOf(searchStr.replaceAll("-", "_")) !== -1) { - el.style.display = ""; + lint.style.display = ""; return; } // Search the description // The use of `for`-loops instead of `foreach` enables us to return early - const docsLowerCase = lint.docs.toLowerCase(); + const docsLowerCase = lint.textContent.toLowerCase(); for (index = 0; index < terms.length; index++) { // This is more likely and will therefore be checked first if (docsLowerCase.indexOf(terms[index]) !== -1) { - continue; + return; } if (lint.id.indexOf(terms[index]) !== -1) { - continue; + return; } - return false; + lint.style.display = "none"; } }); }, @@ -631,7 +606,16 @@ function generateSettings() { ); } +function generateSearch() { + searchState.inputElem.addEventListener("change", handleInputChanged); + searchState.inputElem.addEventListener("input", handleInputChanged); + searchState.inputElem.addEventListener("keydown", handleInputChanged); + searchState.inputElem.addEventListener("keyup", handleInputChanged); + searchState.inputElem.addEventListener("paste", handleInputChanged); +} + generateSettings(); +generateSearch(); // loading the theme after the initial load const prefersDark = window.matchMedia("(prefers-color-scheme: dark)"); From 574e3dd9226774d5a11cec900ec5322fbf7d6f28 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 13 Aug 2024 22:34:14 +0200 Subject: [PATCH 012/260] Finish porting lint functionalities to vanilla JS --- util/gh-pages/index_template.html | 19 ++- util/gh-pages/script.js | 230 +++++++++++++++++------------- util/gh-pages/style.css | 4 + 3 files changed, 140 insertions(+), 113 deletions(-) diff --git a/util/gh-pages/index_template.html b/util/gh-pages/index_template.html index 5baa03da2ea40..6571283cbf4db 100644 --- a/util/gh-pages/index_template.html +++ b/util/gh-pages/index_template.html @@ -199,14 +199,13 @@

Clippy Lints

{% for lint in lints %} -
-
+
{# Open related issues #} {# Jump to source #} {% if let Some(id_location) = lint.id_location %}
- View Source + View Source {% endif %}
@@ -315,7 +313,6 @@

- diff --git a/util/gh-pages/script.js b/util/gh-pages/script.js index eb563a0f242c4..902827b97e492 100644 --- a/util/gh-pages/script.js +++ b/util/gh-pages/script.js @@ -1,19 +1,4 @@ (function () { - function scrollToLint(lintId) { - const target = document.getElementById(lintId); - if (!target) { - return; - } - target.scrollIntoView(); - } - - function scrollToLintByURL($scope, $location) { - const removeListener = $scope.$on('ngRepeatFinished', function (ngRepeatFinishedEvent) { - scrollToLint($location.path().substring(1)); - removeListener(); - }); - } - function selectGroup($scope, selectedGroup) { const groups = $scope.groups; for (const group in groups) { @@ -365,39 +350,12 @@ return $scope.applicabilities[lint.applicability]; }; - // Show details for one lint - $scope.openLint = function (lint) { - $scope.open[lint.id] = true; - $location.path(lint.id); - }; - $scope.toggleExpansion = function(lints, isExpanded) { lints.forEach(lint => { $scope.open[lint.id] = isExpanded; }); } - $scope.copyToClipboard = function (lint) { - const clipboard = document.getElementById("clipboard-" + lint.id); - if (clipboard) { - let resetClipboardTimeout = null; - const resetClipboardIcon = clipboard.innerHTML; - - function resetClipboard() { - resetClipboardTimeout = null; - clipboard.innerHTML = resetClipboardIcon; - } - - navigator.clipboard.writeText("clippy::" + lint.id); - - clipboard.innerHTML = "✓"; - if (resetClipboardTimeout !== null) { - clearTimeout(resetClipboardTimeout); - } - resetClipboardTimeout = setTimeout(resetClipboard, 1000); - } - } - // Get data $scope.open = {}; $scope.loading = true; @@ -413,8 +371,6 @@ selectGroup($scope, selectedGroup.toLowerCase()); } - scrollToLintByURL($scope, $location); - setTimeout(function () { const el = document.getElementById('filter-input'); if (el) { el.focus() } @@ -433,6 +389,65 @@ function getQueryVariable(variable) { } } +function storeValue(settingName, value) { + try { + localStorage.setItem(`clippy-lint-list-${settingName}`, value); + } catch (e) { } +} + +function loadValue(settingName) { + return localStorage.getItem(`clippy-lint-list-${settingName}`); +} + +function setTheme(theme, store) { + let enableHighlight = false; + let enableNight = false; + let enableAyu = false; + + switch(theme) { + case "ayu": + enableAyu = true; + break; + case "coal": + case "navy": + enableNight = true; + break; + case "rust": + enableHighlight = true; + break; + default: + enableHighlight = true; + theme = "light"; + break; + } + + document.getElementsByTagName("body")[0].className = theme; + + document.getElementById("githubLightHighlight").disabled = enableNight || !enableHighlight; + document.getElementById("githubDarkHighlight").disabled = !enableNight && !enableAyu; + + document.getElementById("styleHighlight").disabled = !enableHighlight; + document.getElementById("styleNight").disabled = !enableNight; + document.getElementById("styleAyu").disabled = !enableAyu; + + if (store) { + storeValue("theme", theme); + } else { + document.getElementById(`theme-choice`).value = theme; + } +} + +// loading the theme after the initial load +const prefersDark = window.matchMedia("(prefers-color-scheme: dark)"); +const theme = loadValue('theme'); +if (prefersDark.matches && !theme) { + setTheme("coal", false); +} else { + setTheme(theme, false); +} +let disableShortcuts = loadValue('disable-shortcuts') === "true"; +document.getElementById("disable-shortcuts").checked = disableShortcuts; + window.searchState = { timeout: null, inputElem: document.getElementById("search-input"), @@ -486,6 +501,11 @@ window.searchState = { lint.style.display = "none"; } }); + if (searchStr.length > 0) { + window.location.hash = `/${searchStr}`; + } else { + window.location.hash = ''; + } }, }; @@ -496,54 +516,6 @@ function handleInputChanged(event) { searchState.resetInputTimeout(); } -function storeValue(settingName, value) { - try { - localStorage.setItem(`clippy-lint-list-${settingName}`, value); - } catch (e) { } -} - -function loadValue(settingName) { - return localStorage.getItem(`clippy-lint-list-${settingName}`); -} - -function setTheme(theme, store) { - let enableHighlight = false; - let enableNight = false; - let enableAyu = false; - - switch(theme) { - case "ayu": - enableAyu = true; - break; - case "coal": - case "navy": - enableNight = true; - break; - case "rust": - enableHighlight = true; - break; - default: - enableHighlight = true; - theme = "light"; - break; - } - - document.getElementsByTagName("body")[0].className = theme; - - document.getElementById("githubLightHighlight").disabled = enableNight || !enableHighlight; - document.getElementById("githubDarkHighlight").disabled = !enableNight && !enableAyu; - - document.getElementById("styleHighlight").disabled = !enableHighlight; - document.getElementById("styleNight").disabled = !enableNight; - document.getElementById("styleAyu").disabled = !enableAyu; - - if (store) { - storeValue("theme", theme); - } else { - document.getElementById(`theme-choice`).value = theme; - } -} - function handleShortcut(ev) { if (ev.ctrlKey || ev.altKey || ev.metaKey || disableShortcuts) { return; @@ -584,6 +556,52 @@ function onEachLazy(lazyArray, func) { } } +function expandLintId(lintId) { + searchState.inputElem.value = lintId; + searchState.filterLints(); + + // Expand the lint. + const lintElem = document.getElementById(lintId); + const isCollapsed = lintElem.classList.remove("collapsed"); + lintElem.querySelector(".label-doc-folding").innerText = "-"; +} + +// Show details for one lint +function openLint(event) { + event.preventDefault(); + event.stopPropagation(); + expandLintId(event.target.getAttribute("href").slice(1)); +} + +function expandLint(lintId) { + const lintElem = document.getElementById(lintId); + const isCollapsed = lintElem.classList.toggle("collapsed"); + lintElem.querySelector(".label-doc-folding").innerText = isCollapsed ? "+" : "-"; +} + +function copyToClipboard(event) { + event.preventDefault(); + event.stopPropagation(); + + const clipboard = event.target; + + let resetClipboardTimeout = null; + const resetClipboardIcon = clipboard.innerHTML; + + function resetClipboard() { + resetClipboardTimeout = null; + clipboard.innerHTML = resetClipboardIcon; + } + + navigator.clipboard.writeText("clippy::" + clipboard.parentElement.id.slice(5)); + + clipboard.innerHTML = "✓"; + if (resetClipboardTimeout !== null) { + clearTimeout(resetClipboardTimeout); + } + resetClipboardTimeout = setTimeout(resetClipboard, 1000); +} + function handleBlur(event) { const parent = document.getElementById("settings-dropdown"); if (!parent.contains(document.activeElement) && @@ -617,15 +635,23 @@ function generateSearch() { generateSettings(); generateSearch(); -// loading the theme after the initial load -const prefersDark = window.matchMedia("(prefers-color-scheme: dark)"); -const theme = loadValue('theme'); -if (prefersDark.matches && !theme) { - setTheme("coal", false); -} else { - setTheme(theme, false); +function scrollToLint(lintId) { + const target = document.getElementById(lintId); + if (!target) { + return; + } + target.scrollIntoView(); + expandLintId(lintId); } -let disableShortcuts = loadValue('disable-shortcuts') === "true"; -document.getElementById("disable-shortcuts").checked = disableShortcuts; -hljs.highlightAll(); +// If the page we arrive on has link to a given lint, we scroll to it. +function scrollToLintByURL() { + const lintId = window.location.hash.substring(2); + if (lintId.length > 0) { + scrollToLint(lintId); + } +} + +scrollToLintByURL(); + +onEachLazy(document.querySelectorAll("pre > code.language-rust"), el => hljs.highlightElement(el)); diff --git a/util/gh-pages/style.css b/util/gh-pages/style.css index a9485d511047a..9af566b5aa9e7 100644 --- a/util/gh-pages/style.css +++ b/util/gh-pages/style.css @@ -396,3 +396,7 @@ body { background: var(--bg); color: var(--fg); } + +article.collapsed .lint-docs { + display: none; +} \ No newline at end of file From f2193c680cc5e2d9cf711af0a9bb92b15887c892 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 13 Aug 2024 23:43:35 +0200 Subject: [PATCH 013/260] Completely remove angular and generate parts of settings in JS --- util/gh-pages/index_template.html | 80 ++--- util/gh-pages/script.js | 469 +++++------------------------- 2 files changed, 102 insertions(+), 447 deletions(-) diff --git a/util/gh-pages/index_template.html b/util/gh-pages/index_template.html index 6571283cbf4db..5a7af7d562ed8 100644 --- a/util/gh-pages/index_template.html +++ b/util/gh-pages/index_template.html @@ -25,7 +25,7 @@ - +
@@ -59,121 +59,90 @@

Clippy Lints

-
+
-
-
+
-
-
+
-
+
-
@@ -189,10 +158,10 @@

Clippy Lints

- -
@@ -315,7 +284,6 @@

- diff --git a/util/gh-pages/script.js b/util/gh-pages/script.js index 902827b97e492..6f506956e7c92 100644 --- a/util/gh-pages/script.js +++ b/util/gh-pages/script.js @@ -1,394 +1,3 @@ -(function () { - function selectGroup($scope, selectedGroup) { - const groups = $scope.groups; - for (const group in groups) { - if (groups.hasOwnProperty(group)) { - groups[group] = group === selectedGroup; - } - } - } - - angular.module("clippy", []) - .directive('filterDropdown', function ($document) { - return { - restrict: 'A', - link: function ($scope, $element, $attr) { - $element.bind('click', function (event) { - if (event.target.closest('button')) { - $element.toggleClass('open'); - } else { - $element.addClass('open'); - } - $element.addClass('open-recent'); - }); - - $document.bind('click', function () { - if (!$element.hasClass('open-recent')) { - $element.removeClass('open'); - } - $element.removeClass('open-recent'); - }) - } - } - }) - .directive('onFinishRender', function ($timeout) { - return { - restrict: 'A', - link: function (scope, element, attr) { - if (scope.$last === true) { - $timeout(function () { - scope.$emit(attr.onFinishRender); - }); - } - } - }; - }) - .controller("lintList", function ($scope, $http, $location, $timeout) { - // Level filter - const LEVEL_FILTERS_DEFAULT = {allow: true, warn: true, deny: true, none: true}; - $scope.levels = { ...LEVEL_FILTERS_DEFAULT }; - $scope.byLevels = function (lint) { - return $scope.levels[lint.level]; - }; - - const GROUPS_FILTER_DEFAULT = { - cargo: true, - complexity: true, - correctness: true, - nursery: true, - pedantic: true, - perf: true, - restriction: true, - style: true, - suspicious: true, - deprecated: false, - } - - $scope.groups = { - ...GROUPS_FILTER_DEFAULT - }; - - $scope.versionFilters = { - "≥": {enabled: false, minorVersion: null }, - "≤": {enabled: false, minorVersion: null }, - "=": {enabled: false, minorVersion: null }, - }; - - // Map the versionFilters to the query parameters in a way that is easier to work with in a URL - const versionFilterKeyMap = { - "≥": "gte", - "≤": "lte", - "=": "eq" - }; - const reverseVersionFilterKeyMap = Object.fromEntries( - Object.entries(versionFilterKeyMap).map(([key, value]) => [value, key]) - ); - - const APPLICABILITIES_FILTER_DEFAULT = { - MachineApplicable: true, - MaybeIncorrect: true, - HasPlaceholders: true, - Unspecified: true, - }; - - $scope.applicabilities = { - ...APPLICABILITIES_FILTER_DEFAULT - } - - // loadFromURLParameters retrieves filter settings from the URL parameters and assigns them - // to corresponding $scope variables. - function loadFromURLParameters() { - // Extract parameters from URL - const urlParameters = $location.search(); - - // Define a helper function that assigns URL parameters to a provided scope variable - const handleParameter = (parameter, scopeVariable, defaultValues) => { - if (urlParameters[parameter]) { - const items = urlParameters[parameter].split(','); - for (const key in scopeVariable) { - if (scopeVariable.hasOwnProperty(key)) { - scopeVariable[key] = items.includes(key); - } - } - } else if (defaultValues) { - for (const key in defaultValues) { - if (scopeVariable.hasOwnProperty(key)) { - scopeVariable[key] = defaultValues[key]; - } - } - } - }; - - handleParameter('levels', $scope.levels, LEVEL_FILTERS_DEFAULT); - handleParameter('groups', $scope.groups, GROUPS_FILTER_DEFAULT); - handleParameter('applicabilities', $scope.applicabilities, APPLICABILITIES_FILTER_DEFAULT); - - // Handle 'versions' parameter separately because it needs additional processing - if (urlParameters.versions) { - const versionFilters = urlParameters.versions.split(','); - for (const versionFilter of versionFilters) { - const [key, minorVersion] = versionFilter.split(':'); - const parsedMinorVersion = parseInt(minorVersion); - - // Map the key from the URL parameter to its original form - const originalKey = reverseVersionFilterKeyMap[key]; - - if (originalKey in $scope.versionFilters && !isNaN(parsedMinorVersion)) { - $scope.versionFilters[originalKey].enabled = true; - $scope.versionFilters[originalKey].minorVersion = parsedMinorVersion; - } - } - } - - // Load the search parameter from the URL path - const searchParameter = $location.path().substring(1); // Remove the leading slash - if (searchParameter) { - $scope.search = searchParameter; - $scope.open[searchParameter] = true; - scrollToLintByURL($scope, $location); - } - } - - // updateURLParameter updates the URL parameter with the given key to the given value - function updateURLParameter(filterObj, urlKey, defaultValue = {}, processFilter = filter => filter) { - const parameter = Object.keys(filterObj) - .filter(filter => filterObj[filter]) - .sort() - .map(processFilter) - .filter(Boolean) // Filters out any falsy values, including null - .join(','); - - const defaultParameter = Object.keys(defaultValue) - .filter(filter => defaultValue[filter]) - .sort() - .map(processFilter) - .filter(Boolean) // Filters out any falsy values, including null - .join(','); - - // if we ended up back at the defaults, just remove it from the URL - if (parameter === defaultParameter) { - $location.search(urlKey, null); - } else { - $location.search(urlKey, parameter || null); - } - } - - // updateVersionURLParameter updates the version URL parameter with the given version filters - function updateVersionURLParameter(versionFilters) { - updateURLParameter( - versionFilters, - 'versions', {}, - versionFilter => versionFilters[versionFilter].enabled && versionFilters[versionFilter].minorVersion != null - ? `${versionFilterKeyMap[versionFilter]}:${versionFilters[versionFilter].minorVersion}` - : null - ); - } - - // updateAllURLParameters updates all the URL parameters with the current filter settings - function updateAllURLParameters() { - updateURLParameter($scope.levels, 'levels', LEVEL_FILTERS_DEFAULT); - updateURLParameter($scope.groups, 'groups', GROUPS_FILTER_DEFAULT); - updateVersionURLParameter($scope.versionFilters); - updateURLParameter($scope.applicabilities, 'applicabilities', APPLICABILITIES_FILTER_DEFAULT); - } - - // Add $watches to automatically update URL parameters when the data changes - $scope.$watch('levels', function (newVal, oldVal) { - if (newVal !== oldVal) { - updateURLParameter(newVal, 'levels', LEVEL_FILTERS_DEFAULT); - } - }, true); - - $scope.$watch('groups', function (newVal, oldVal) { - if (newVal !== oldVal) { - updateURLParameter(newVal, 'groups', GROUPS_FILTER_DEFAULT); - } - }, true); - - $scope.$watch('versionFilters', function (newVal, oldVal) { - if (newVal !== oldVal) { - updateVersionURLParameter(newVal); - } - }, true); - - $scope.$watch('applicabilities', function (newVal, oldVal) { - if (newVal !== oldVal) { - updateURLParameter(newVal, 'applicabilities', APPLICABILITIES_FILTER_DEFAULT) - } - }, true); - - // Watch for changes in the URL path and update the search and lint display - $scope.$watch(function () { return $location.path(); }, function (newPath) { - const searchParameter = newPath.substring(1); - if ($scope.search !== searchParameter) { - $scope.search = searchParameter; - $scope.open[searchParameter] = true; - scrollToLintByURL($scope, $location); - } - }); - - let debounceTimeout; - $scope.$watch('search', function (newVal, oldVal) { - if (newVal !== oldVal) { - if (debounceTimeout) { - $timeout.cancel(debounceTimeout); - } - - debounceTimeout = $timeout(function () { - $location.path(newVal); - }, 1000); - } - }); - - $scope.$watch(function () { return $location.search(); }, function (newParameters) { - loadFromURLParameters(); - }, true); - - $scope.updatePath = function () { - if (debounceTimeout) { - $timeout.cancel(debounceTimeout); - } - - $location.path($scope.search); - } - - $scope.toggleLevels = function (value) { - const levels = $scope.levels; - for (const key in levels) { - if (levels.hasOwnProperty(key)) { - levels[key] = value; - } - } - }; - - $scope.toggleGroups = function (value) { - const groups = $scope.groups; - for (const key in groups) { - if (groups.hasOwnProperty(key)) { - groups[key] = value; - } - } - }; - - $scope.toggleApplicabilities = function (value) { - const applicabilities = $scope.applicabilities; - for (const key in applicabilities) { - if (applicabilities.hasOwnProperty(key)) { - applicabilities[key] = value; - } - } - } - - $scope.resetGroupsToDefault = function () { - $scope.groups = { - ...GROUPS_FILTER_DEFAULT - }; - }; - - $scope.selectedValuesCount = function (obj) { - return Object.values(obj).filter(x => x).length; - } - - $scope.clearVersionFilters = function () { - for (const filter in $scope.versionFilters) { - $scope.versionFilters[filter] = { enabled: false, minorVersion: null }; - } - } - - $scope.versionFilterCount = function(obj) { - return Object.values(obj).filter(x => x.enabled).length; - } - - $scope.updateVersionFilters = function() { - for (const filter in $scope.versionFilters) { - const minorVersion = $scope.versionFilters[filter].minorVersion; - - // 1.29.0 and greater - if (minorVersion && minorVersion > 28) { - $scope.versionFilters[filter].enabled = true; - continue; - } - - $scope.versionFilters[filter].enabled = false; - } - } - - $scope.byVersion = function(lint) { - const filters = $scope.versionFilters; - for (const filter in filters) { - if (filters[filter].enabled) { - const minorVersion = filters[filter].minorVersion; - - // Strip the "pre " prefix for pre 1.29.0 lints - const lintVersion = lint.version.startsWith("pre ") ? lint.version.substring(4, lint.version.length) : lint.version; - const lintMinorVersion = lintVersion.substring(2, 4); - - switch (filter) { - // "=" gets the highest priority, since all filters are inclusive - case "=": - return (lintMinorVersion == minorVersion); - case "≥": - if (lintMinorVersion < minorVersion) { return false; } - break; - case "≤": - if (lintMinorVersion > minorVersion) { return false; } - break; - default: - return true - } - } - } - - return true; - } - - $scope.byGroups = function (lint) { - return $scope.groups[lint.group]; - }; - - $scope.byApplicabilities = function (lint) { - return $scope.applicabilities[lint.applicability]; - }; - - $scope.toggleExpansion = function(lints, isExpanded) { - lints.forEach(lint => { - $scope.open[lint.id] = isExpanded; - }); - } - - // Get data - $scope.open = {}; - $scope.loading = true; - - // This will be used to jump into the source code of the version that this documentation is for. - $scope.docVersion = window.location.pathname.split('/')[2] || "master"; - - // Set up the filters from the URL parameters before we start loading the data - loadFromURLParameters(); - - const selectedGroup = getQueryVariable("sel"); - if (selectedGroup) { - selectGroup($scope, selectedGroup.toLowerCase()); - } - - setTimeout(function () { - const el = document.getElementById('filter-input'); - if (el) { el.focus() } - }, 0); - }); -})(); - -function getQueryVariable(variable) { - const query = window.location.search.substring(1); - const vars = query.split('&'); - for (const entry of vars) { - const pair = entry.split('='); - if (decodeURIComponent(pair[0]) == variable) { - return decodeURIComponent(pair[1]); - } - } -} - function storeValue(settingName, value) { try { localStorage.setItem(`clippy-lint-list-${settingName}`, value); @@ -611,6 +220,34 @@ function handleBlur(event) { } } +function toggleExpansion(expand) { + onEachLazy( + document.querySelectorAll("article"), + expand ? el => el.classList.remove("collapsed") : el => el.classList.add("collapsed"), + ); +} + +function generateListOfOptions(list, elementId) { + let html = ''; + let nbEnabled = 0; + for (const [key, value] of Object.entries(list)) { + const attr = value ? " checked" : ""; + html += `\ +
  • \ + \ +
  • `; + if (value) { + nbEnabled += 1; + } + } + + const elem = document.getElementById(elementId); + elem.previousElementSibling.querySelector(".badge").innerText = `${nbEnabled}`; + elem.innerHTML += html; +} + function generateSettings() { const settings = document.getElementById("settings-dropdown"); const settingsButton = settings.querySelector(".settings-icon") @@ -622,6 +259,56 @@ function generateSettings() { settingsMenu.querySelectorAll("input"), el => el.onblur = handleBlur, ); + + const LEVEL_FILTERS_DEFAULT = {allow: true, warn: true, deny: true, none: true}; + generateListOfOptions(LEVEL_FILTERS_DEFAULT, "lint-levels"); + + // Generate lint groups. + const GROUPS_FILTER_DEFAULT = { + cargo: true, + complexity: true, + correctness: true, + deprecated: false, + nursery: true, + pedantic: true, + perf: true, + restriction: true, + style: true, + suspicious: true, + }; + generateListOfOptions(GROUPS_FILTER_DEFAULT, "lint-groups"); + + const APPLICABILITIES_FILTER_DEFAULT = { + Unspecified: true, + Unresolved: true, + MachineApplicable: true, + MaybeIncorrect: true, + HasPlaceholders: true + }; + generateListOfOptions(APPLICABILITIES_FILTER_DEFAULT, "lint-applicabilities"); + + const VERSIONS_FILTERS = { + "≥": {enabled: false, minorVersion: null }, + "≤": {enabled: false, minorVersion: null }, + "=": {enabled: false, minorVersion: null }, + }; + + let html = ''; + for (const kind of ["≥", "≤", "="]) { + html += `\ +
  • \ + \ + 1. \ + \ + .0\ +
  • `; + } + document.getElementById("version-filter-selector").innerHTML += html; } function generateSearch() { From 4484085b18df4b10243b503a21602bb71836e8b3 Mon Sep 17 00:00:00 2001 From: Laiho Date: Mon, 9 Sep 2024 00:58:52 +0300 Subject: [PATCH 014/260] Add fast path for ascii to ascii in str::replace --- library/alloc/src/str.rs | 25 ++++++++++++++++++++++++- library/alloc/src/string.rs | 7 ++++++- library/core/src/str/pattern.rs | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 32212b61c6e87..709d11c52a06b 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -19,7 +19,7 @@ pub use core::str::SplitInclusive; pub use core::str::SplitWhitespace; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::pattern; -use core::str::pattern::{DoubleEndedSearcher, Pattern, ReverseSearcher, Searcher}; +use core::str::pattern::{DoubleEndedSearcher, Pattern, ReverseSearcher, Searcher, Utf8Pattern}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{Bytes, CharIndices, Chars, from_utf8, from_utf8_mut}; #[stable(feature = "str_escape", since = "1.34.0")] @@ -268,6 +268,18 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn replace(&self, from: P, to: &str) -> String { + // Fast path for ASCII to ASCII case. + + if let Some(from_byte) = match from.as_utf8_pattern() { + Some(Utf8Pattern::StringPattern([from_byte])) => Some(*from_byte), + Some(Utf8Pattern::CharPattern(c)) => c.as_ascii().map(|ascii_char| ascii_char.to_u8()), + _ => None, + } { + if let [to_byte] = to.as_bytes() { + return unsafe { replace_ascii(self.as_bytes(), from_byte, *to_byte) }; + } + } + let mut result = String::new(); let mut last_end = 0; for (start, part) in self.match_indices(from) { @@ -661,3 +673,14 @@ fn convert_while_ascii(b: &[u8], convert: fn(&u8) -> u8) -> Vec { out } +#[inline] +#[cfg(not(test))] +#[cfg(not(no_global_oom_handling))] +#[allow(dead_code)] +/// Faster implementation of string replacement for ASCII to ASCII cases. +/// Should produce fast vectorized code. +unsafe fn replace_ascii(utf8_bytes: &[u8], from: u8, to: u8) -> String { + let result: Vec = utf8_bytes.iter().map(|b| if *b == from { to } else { *b }).collect(); + // SAFETY: We replaced ascii with ascii on valid utf8 strings. + unsafe { String::from_utf8_unchecked(result) } +} diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index ee878e879e98a..0d1600a28aa74 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -53,7 +53,7 @@ use core::ops::AddAssign; #[cfg(not(no_global_oom_handling))] use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{self, Range, RangeBounds}; -use core::str::pattern::Pattern; +use core::str::pattern::{Pattern, Utf8Pattern}; use core::{fmt, hash, ptr, slice}; #[cfg(not(no_global_oom_handling))] @@ -2424,6 +2424,11 @@ impl<'b> Pattern for &'b String { { self[..].strip_suffix_of(haystack) } + + #[inline] + fn as_utf8_pattern(&self) -> Option> { + Some(Utf8Pattern::StringPattern(self.as_bytes())) + } } macro_rules! impl_eq { diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index 9f1294d760647..eb60effe8138f 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -160,6 +160,19 @@ pub trait Pattern: Sized { None } } + + /// Returns the pattern as utf-8 bytes if possible. + fn as_utf8_pattern(&self) -> Option>; +} +/// Result of calling [`Pattern::as_utf8_pattern()`]. +/// Can be used for inspecting the contents of a [`Pattern`] in cases +/// where the underlying representation can be represented as UTF-8. +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub enum Utf8Pattern<'a> { + /// Type returned by String and str types. + StringPattern(&'a [u8]), + /// Type returned by char types. + CharPattern(char), } // Searcher @@ -599,6 +612,11 @@ impl Pattern for char { { self.encode_utf8(&mut [0u8; 4]).strip_suffix_of(haystack) } + + #[inline] + fn as_utf8_pattern(&self) -> Option> { + Some(Utf8Pattern::CharPattern(*self)) + } } ///////////////////////////////////////////////////////////////////////////// @@ -657,6 +675,11 @@ impl Pattern for MultiCharEqPattern { fn into_searcher(self, haystack: &str) -> MultiCharEqSearcher<'_, C> { MultiCharEqSearcher { haystack, char_eq: self.0, char_indices: haystack.char_indices() } } + + #[inline] + fn as_utf8_pattern(&self) -> Option> { + None + } } unsafe impl<'a, C: MultiCharEq> Searcher<'a> for MultiCharEqSearcher<'a, C> { @@ -747,6 +770,11 @@ macro_rules! pattern_methods { { ($pmap)(self).strip_suffix_of(haystack) } + + #[inline] + fn as_utf8_pattern(&self) -> Option> { + None + } }; } @@ -1022,6 +1050,11 @@ impl<'b> Pattern for &'b str { None } } + + #[inline] + fn as_utf8_pattern(&self) -> Option> { + Some(Utf8Pattern::StringPattern(self.as_bytes())) + } } ///////////////////////////////////////////////////////////////////////////// From a235cbd8ac347f323084c99d198f96d27269ec85 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Mon, 23 Sep 2024 11:58:28 -0700 Subject: [PATCH 015/260] `module_name_repetitions`: don't warn if the item is in a private module. Fixes . There is still a warning (as there should be) if the item is reexported by name, but not by glob; that would require further work to examine the names in the glob, and I haven't looked into that. Credit to @Centri3 for suggesting approximately this simple fix in . However, per later comment , I am not making it configuration-dependent, but *always* checking public items in public modules only. --- clippy_lints/src/item_name_repetitions.rs | 33 +++++++++++++++---- clippy_lints/src/literal_representation.rs | 1 - clippy_lints/src/macro_use.rs | 1 - clippy_lints/src/vec.rs | 1 - .../allowed_prefixes/item_name_repetitions.rs | 2 +- .../item_name_repetitions.rs | 2 +- tests/ui/module_name_repetitions.rs | 18 +++++++++- tests/ui/module_name_repetitions.stderr | 8 ++++- 8 files changed, 53 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/item_name_repetitions.rs b/clippy_lints/src/item_name_repetitions.rs index 66a8a3167a4f2..511317c8b43f6 100644 --- a/clippy_lints/src/item_name_repetitions.rs +++ b/clippy_lints/src/item_name_repetitions.rs @@ -50,11 +50,28 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Detects type names that are prefixed or suffixed by the - /// containing module's name. + /// Detects public item names that are prefixed or suffixed by the + /// containing public module's name. /// /// ### Why is this bad? - /// It requires the user to type the module name twice. + /// It requires the user to type the module name twice in each usage, + /// especially if they choose to import the module rather than its contents. + /// + /// Lack of such repetition is also the style used in the Rust standard library; + /// e.g. `io::Error` and `fmt::Error` rather than `io::IoError` and `fmt::FmtError`; + /// and `array::from_ref` rather than `array::array_from_ref`. + /// + /// ### Known issues + /// Glob re-exports are ignored; e.g. this will not warn even though it should: + /// + /// ```no_run + /// pub mod foo { + /// mod iteration { + /// pub struct FooIter {} + /// } + /// pub use iteration::*; // creates the path `foo::FooIter` + /// } + /// ``` /// /// ### Example /// ```no_run @@ -389,12 +406,12 @@ impl LateLintPass<'_> for ItemNameRepetitions { let item_name = item.ident.name.as_str(); let item_camel = to_camel_case(item_name); if !item.span.from_expansion() && is_present_in_source(cx, item.span) { - if let [.., (mod_name, mod_camel, owner_id)] = &*self.modules { + if let [.., (mod_name, mod_camel, mod_owner_id)] = &*self.modules { // constants don't have surrounding modules if !mod_camel.is_empty() { if mod_name == &item.ident.name && let ItemKind::Mod(..) = item.kind - && (!self.allow_private_module_inception || cx.tcx.visibility(owner_id.def_id).is_public()) + && (!self.allow_private_module_inception || cx.tcx.visibility(mod_owner_id.def_id).is_public()) { span_lint( cx, @@ -403,9 +420,13 @@ impl LateLintPass<'_> for ItemNameRepetitions { "module has the same name as its containing module", ); } + // The `module_name_repetitions` lint should only trigger if the item has the module in its // name. Having the same name is accepted. - if cx.tcx.visibility(item.owner_id).is_public() && item_camel.len() > mod_camel.len() { + if cx.tcx.visibility(item.owner_id).is_public() + && cx.tcx.visibility(mod_owner_id.def_id).is_public() + && item_camel.len() > mod_camel.len() + { let matching = count_match_start(mod_camel, &item_camel); let rmatching = count_match_end(mod_camel, &item_camel); let nchars = mod_camel.chars().count(); diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 81f2a03fb55fb..e2dcb20f906d3 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -412,7 +412,6 @@ impl LiteralDigitGrouping { } } -#[expect(clippy::module_name_repetitions)] pub struct DecimalLiteralRepresentation { threshold: u64, } diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index bd6b3f1a47b16..d5d6226f0aaaf 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -43,7 +43,6 @@ impl MacroRefData { } #[derive(Default)] -#[expect(clippy::module_name_repetitions)] pub struct MacroUseImports { /// the actual import path used and the span of the attribute above it. The value is /// the location, where the lint should be emitted. diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index ce4f41e854d5e..0fdef51d6fc50 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -17,7 +17,6 @@ use rustc_middle::ty::layout::LayoutOf; use rustc_session::impl_lint_pass; use rustc_span::{DesugaringKind, Span, sym}; -#[expect(clippy::module_name_repetitions)] pub struct UselessVec { too_large_for_stack: u64, msrv: Msrv, diff --git a/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs b/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs index 4142ced5f6b54..2ae673a6def08 100644 --- a/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs +++ b/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs @@ -1,7 +1,7 @@ #![warn(clippy::module_name_repetitions)] #![allow(dead_code)] -mod foo { +pub mod foo { // #12544 - shouldn't warn if item name consists only of an allowed prefix and a module name. // In this test, allowed prefixes are configured to be ["bar"]. diff --git a/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs b/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs index b132305d01cf3..dbd61992c0d6b 100644 --- a/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs +++ b/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs @@ -1,7 +1,7 @@ #![warn(clippy::module_name_repetitions)] #![allow(dead_code)] -mod foo { +pub mod foo { // #12544 - shouldn't warn if item name consists only of an allowed prefix and a module name. // In this test, allowed prefixes are configured to be all of the default prefixes and ["bar"]. diff --git a/tests/ui/module_name_repetitions.rs b/tests/ui/module_name_repetitions.rs index b75ef87ab3640..71d8ac7a1f0e0 100644 --- a/tests/ui/module_name_repetitions.rs +++ b/tests/ui/module_name_repetitions.rs @@ -3,7 +3,7 @@ #![warn(clippy::module_name_repetitions)] #![allow(dead_code)] -mod foo { +pub mod foo { pub fn foo() {} pub fn foo_bar() {} //~^ ERROR: item name starts with its containing module's name @@ -20,6 +20,22 @@ mod foo { // Should not warn pub struct Foobar; + // #8524 - shouldn't warn when item is declared in a private module... + mod error { + pub struct Error; + pub struct FooError; + } + pub use error::Error; + // ... but should still warn when the item is reexported to create a *public* path with repetition. + pub use error::FooError; + //~^ ERROR: item name starts with its containing module's name + + // FIXME: This should also warn because it creates the public path `foo::FooIter`. + mod iter { + pub struct FooIter; + } + pub use iter::*; + // #12544 - shouldn't warn if item name consists only of an allowed prefix and a module name. pub fn to_foo() {} pub fn into_foo() {} diff --git a/tests/ui/module_name_repetitions.stderr b/tests/ui/module_name_repetitions.stderr index bffb08f6f879f..8fd8b39487537 100644 --- a/tests/ui/module_name_repetitions.stderr +++ b/tests/ui/module_name_repetitions.stderr @@ -31,5 +31,11 @@ error: item name starts with its containing module's name LL | pub struct Foo7Bar; | ^^^^^^^ -error: aborting due to 5 previous errors +error: item name starts with its containing module's name + --> tests/ui/module_name_repetitions.rs:30:20 + | +LL | pub use error::FooError; + | ^^^^^^^^ + +error: aborting due to 6 previous errors From 4997ee7afcda865406352f755e9e3b44958560bd Mon Sep 17 00:00:00 2001 From: blyxyas Date: Fri, 6 Sep 2024 00:26:02 +0200 Subject: [PATCH 016/260] Turn declare_clippy_lint into a declarative macro --- clippy_lints/Cargo.toml | 1 - clippy_lints/src/declare_clippy_lint.rs | 162 +++++++++++++++++++++ clippy_lints/src/lib.rs | 6 +- clippy_utils/src/lib.rs | 2 +- declare_clippy_lint/Cargo.toml | 13 -- declare_clippy_lint/src/lib.rs | 182 ------------------------ tests/versioncheck.rs | 1 - 7 files changed, 167 insertions(+), 200 deletions(-) create mode 100644 clippy_lints/src/declare_clippy_lint.rs delete mode 100644 declare_clippy_lint/Cargo.toml delete mode 100644 declare_clippy_lint/src/lib.rs diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index d1188940b46a8..55f1d31b4addc 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -13,7 +13,6 @@ arrayvec = { version = "0.7", default-features = false } cargo_metadata = "0.18" clippy_config = { path = "../clippy_config" } clippy_utils = { path = "../clippy_utils" } -declare_clippy_lint = { path = "../declare_clippy_lint" } itertools = "0.12" quine-mc_cluskey = "0.2" regex-syntax = "0.8" diff --git a/clippy_lints/src/declare_clippy_lint.rs b/clippy_lints/src/declare_clippy_lint.rs new file mode 100644 index 0000000000000..b1e39c70baa2b --- /dev/null +++ b/clippy_lints/src/declare_clippy_lint.rs @@ -0,0 +1,162 @@ +#[macro_export] +#[allow(clippy::crate_in_macro_def)] +macro_rules! declare_clippy_lint { + (@ + $(#[doc = $lit:literal])* + pub $lint_name:ident, + $category:ident, + $lintcategory:expr, + $desc:literal, + $version_expr:expr, + $version_lit:literal + ) => { + rustc_session::declare_tool_lint! { + $(#[doc = $lit])* + #[clippy::version = $version_lit] + pub clippy::$lint_name, + $category, + $desc, + report_in_external_macro:true + } + + pub(crate) static ${concat($lint_name, _INFO)}: &'static crate::LintInfo = &crate::LintInfo { + lint: &$lint_name, + category: $lintcategory, + explanation: concat!($($lit,"\n",)*), + location: concat!(file!(), "#L", line!()), + version: $version_expr + }; + }; + ( + $(#[doc = $lit:literal])* + #[clippy::version = $version:literal] + pub $lint_name:ident, + restriction, + $desc:literal + ) => { + declare_clippy_lint! {@ + $(#[doc = $lit])* + pub $lint_name, Allow, crate::LintCategory::Restriction, $desc, + Some($version), $version + } + }; + ( + $(#[doc = $lit:literal])* + #[clippy::version = $version:literal] + pub $lint_name:ident, + style, + $desc:literal + ) => { + declare_clippy_lint! {@ + $(#[doc = $lit])* + pub $lint_name, Warn, crate::LintCategory::Style, $desc, + Some($version), $version + + } + }; + ( + $(#[doc = $lit:literal])* + #[clippy::version = $version:literal] + pub $lint_name:ident, + correctness, + $desc:literal + ) => { + declare_clippy_lint! {@ + $(#[doc = $lit])* + pub $lint_name, Deny, crate::LintCategory::Correctness, $desc, + Some($version), $version + + } + }; + ( + $(#[doc = $lit:literal])* + #[clippy::version = $version:literal] + pub $lint_name:ident, + perf, + $desc:literal + ) => { + declare_clippy_lint! {@ + $(#[doc = $lit])* + pub $lint_name, Warn, crate::LintCategory::Perf, $desc, + Some($version), $version + } + }; + ( + $(#[doc = $lit:literal])* + #[clippy::version = $version:literal] + pub $lint_name:ident, + complexity, + $desc:literal + ) => { + declare_clippy_lint! {@ + $(#[doc = $lit])* + pub $lint_name, Warn, crate::LintCategory::Complexity, $desc, + Some($version), $version + } + }; + ( + $(#[doc = $lit:literal])* + #[clippy::version = $version:literal] + pub $lint_name:ident, + suspicious, + $desc:literal + ) => { + declare_clippy_lint! {@ + $(#[doc = $lit])* + pub $lint_name, Warn, crate::LintCategory::Suspicious, $desc, + Some($version), $version + } + }; + ( + $(#[doc = $lit:literal])* + #[clippy::version = $version:literal] + pub $lint_name:ident, + nursery, + $desc:literal + ) => { + declare_clippy_lint! {@ + $(#[doc = $lit])* + pub $lint_name, Allow, crate::LintCategory::Nursery, $desc, + Some($version), $version + } + }; + ( + $(#[doc = $lit:literal])* + #[clippy::version = $version:literal] + pub $lint_name:ident, + pedantic, + $desc:literal + ) => { + declare_clippy_lint! {@ + $(#[doc = $lit])* + pub $lint_name, Allow, crate::LintCategory::Pedantic, $desc, + Some($version), $version + } + }; + ( + $(#[doc = $lit:literal])* + #[clippy::version = $version:literal] + pub $lint_name:ident, + cargo, + $desc:literal + ) => { + declare_clippy_lint! {@ + $(#[doc = $lit])* + pub $lint_name, Allow, crate::LintCategory::Cargo, $desc, + Some($version), $version + } + }; + + ( + $(#[doc = $lit:literal])* + pub $lint_name:ident, + internal, + $desc:literal + ) => { + declare_clippy_lint! {@ + $(#[doc = $lit])* + pub $lint_name, Allow, crate::LintCategory::Internal, $desc, + None, "0.0.0" + } + }; +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1d41f568f3785..efc9fe6f3157d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1,6 +1,7 @@ #![feature(array_windows)] #![feature(binary_heap_into_iter_sorted)] #![feature(box_patterns)] +#![feature(macro_metavar_expr_concat)] #![feature(control_flow_enum)] #![feature(f128)] #![feature(f16)] @@ -59,9 +60,10 @@ extern crate rustc_trait_selection; extern crate thin_vec; #[macro_use] -extern crate clippy_utils; +mod declare_clippy_lint; + #[macro_use] -extern crate declare_clippy_lint; +extern crate clippy_utils; #[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))] mod utils; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index a925549b0bff0..bf7484f7902bb 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -4,6 +4,7 @@ #![feature(f128)] #![feature(f16)] #![feature(if_let_guard)] +#![feature(macro_metavar_expr_concat)] #![feature(let_chains)] #![feature(never_type)] #![feature(rustc_private)] @@ -129,7 +130,6 @@ use crate::consts::{ConstEvalCtxt, Constant, mir_to_const}; use crate::higher::Range; use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type}; use crate::visitors::for_each_expr_without_closures; - use rustc_middle::hir::nested_filter; #[macro_export] diff --git a/declare_clippy_lint/Cargo.toml b/declare_clippy_lint/Cargo.toml deleted file mode 100644 index 67a1f7cc72c54..0000000000000 --- a/declare_clippy_lint/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "declare_clippy_lint" -version = "0.1.83" -edition = "2021" -publish = false - -[lib] -proc-macro = true - -[dependencies] -itertools = "0.12" -quote = "1.0.21" -syn = "2.0" diff --git a/declare_clippy_lint/src/lib.rs b/declare_clippy_lint/src/lib.rs deleted file mode 100644 index fefc1a0a6c402..0000000000000 --- a/declare_clippy_lint/src/lib.rs +++ /dev/null @@ -1,182 +0,0 @@ -#![feature(let_chains, proc_macro_span)] -// warn on lints, that are included in `rust-lang/rust`s bootstrap -#![warn(rust_2018_idioms, unused_lifetimes)] - -use proc_macro::TokenStream; -use quote::{format_ident, quote}; -use syn::parse::{Parse, ParseStream}; -use syn::{Attribute, Error, Expr, ExprLit, Ident, Lit, LitStr, Meta, Result, Token, parse_macro_input}; - -fn parse_attr(path: [&'static str; LEN], attr: &Attribute) -> Option { - if let Meta::NameValue(name_value) = &attr.meta { - let path_idents = name_value.path.segments.iter().map(|segment| &segment.ident); - - if itertools::equal(path_idents, path) - && let Expr::Lit(ExprLit { lit: Lit::Str(s), .. }) = &name_value.value - { - return Some(s.clone()); - } - } - - None -} - -struct ClippyLint { - attrs: Vec, - version: Option, - explanation: String, - name: Ident, - category: Ident, - description: LitStr, -} - -impl Parse for ClippyLint { - fn parse(input: ParseStream<'_>) -> Result { - let attrs = input.call(Attribute::parse_outer)?; - - let mut in_code = false; - let mut explanation = String::new(); - let mut version = None; - for attr in &attrs { - if let Some(lit) = parse_attr(["doc"], attr) { - let value = lit.value(); - let line = value.strip_prefix(' ').unwrap_or(&value); - - if let Some(lang) = line.strip_prefix("```") { - let tag = lang.split_once(',').map_or(lang, |(left, _)| left); - if !in_code && matches!(tag, "" | "rust" | "ignore" | "should_panic" | "no_run" | "compile_fail") { - explanation += "```rust\n"; - } else { - explanation += line; - explanation.push('\n'); - } - in_code = !in_code; - } else if !(in_code && line.starts_with("# ")) { - explanation += line; - explanation.push('\n'); - } - } else if let Some(lit) = parse_attr(["clippy", "version"], attr) { - if let Some(duplicate) = version.replace(lit) { - return Err(Error::new_spanned(duplicate, "duplicate clippy::version")); - } - } else { - return Err(Error::new_spanned(attr, "unexpected attribute")); - } - } - - input.parse::()?; - let name = input.parse()?; - input.parse::()?; - - let category = input.parse()?; - input.parse::()?; - - let description = input.parse()?; - - Ok(Self { - attrs, - version, - explanation, - name, - category, - description, - }) - } -} - -/// Macro used to declare a Clippy lint. -/// -/// Every lint declaration consists of 4 parts: -/// -/// 1. The documentation, which is used for the website and `cargo clippy --explain` -/// 2. The `LINT_NAME`. See [lint naming][lint_naming] on lint naming conventions. -/// 3. The `lint_level`, which is a mapping from *one* of our lint groups to `Allow`, `Warn` or -/// `Deny`. The lint level here has nothing to do with what lint groups the lint is a part of. -/// 4. The `description` that contains a short explanation on what's wrong with code where the lint -/// is triggered. -/// -/// Currently the categories `style`, `correctness`, `suspicious`, `complexity` and `perf` are -/// enabled by default. As said in the README.md of this repository, if the lint level mapping -/// changes, please update README.md. -/// -/// # Example -/// -/// ```ignore -/// use rustc_session::declare_tool_lint; -/// -/// declare_clippy_lint! { -/// /// ### What it does -/// /// Checks for ... (describe what the lint matches). -/// /// -/// /// ### Why is this bad? -/// /// Supply the reason for linting the code. -/// /// -/// /// ### Example -/// /// ```rust -/// /// Insert a short example of code that triggers the lint -/// /// ``` -/// /// -/// /// Use instead: -/// /// ```rust -/// /// Insert a short example of improved code that doesn't trigger the lint -/// /// ``` -/// #[clippy::version = "1.65.0"] -/// pub LINT_NAME, -/// pedantic, -/// "description" -/// } -/// ``` -/// [lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints -#[proc_macro] -pub fn declare_clippy_lint(input: TokenStream) -> TokenStream { - let ClippyLint { - attrs, - version, - explanation, - name, - category, - description, - } = parse_macro_input!(input as ClippyLint); - - let mut category = category.to_string(); - - let level = format_ident!("{}", match category.as_str() { - "correctness" => "Deny", - "style" | "suspicious" | "complexity" | "perf" => "Warn", - "pedantic" | "restriction" | "cargo" | "nursery" | "internal" => "Allow", - _ => panic!("unknown category {category}"), - },); - - let info_name = format_ident!("{name}_INFO"); - - (&mut category[0..1]).make_ascii_uppercase(); - let category_variant = format_ident!("{category}"); - - let name_span = name.span().unwrap(); - let location = format!("{}#L{}", name_span.source_file().path().display(), name_span.line()); - - let version = match version { - Some(version) => quote!(Some(#version)), - None => quote!(None), - }; - - let output = quote! { - rustc_session::declare_tool_lint! { - #(#attrs)* - pub clippy::#name, - #level, - #description, - report_in_external_macro: true - } - - pub(crate) static #info_name: &'static crate::LintInfo = &crate::LintInfo { - lint: &#name, - category: crate::LintCategory::#category_variant, - explanation: #explanation, - location: #location, - version: #version, - }; - }; - - TokenStream::from(output) -} diff --git a/tests/versioncheck.rs b/tests/versioncheck.rs index 6832833393766..e29898f068d37 100644 --- a/tests/versioncheck.rs +++ b/tests/versioncheck.rs @@ -24,7 +24,6 @@ fn consistent_clippy_crate_versions() { let clippy_version = read_version("Cargo.toml"); let paths = [ - "declare_clippy_lint/Cargo.toml", "clippy_config/Cargo.toml", "clippy_lints/Cargo.toml", "clippy_utils/Cargo.toml", From 0735031be94cd4f6a102e83e72630fae04a18090 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Wed, 25 Sep 2024 13:42:21 +0200 Subject: [PATCH 017/260] Move tag removing to --explain --- clippy_lints/src/lib.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index efc9fe6f3157d..e927d9a2d5bff 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -524,8 +524,28 @@ impl LintInfo { pub fn explain(name: &str) -> i32 { let target = format!("clippy::{}", name.to_ascii_uppercase()); + if let Some(info) = declared_lints::LINTS.iter().find(|info| info.lint.name == target) { - println!("{}", info.explanation); + // Remove tags and hidden code: + let mut explanation = String::with_capacity(128); + let mut in_code = false; + for line in info.explanation.lines().map(|line| line.trim()) { + if let Some(lang) = line.strip_prefix("```") { + let tag = lang.split_once(',').map_or(lang, |(left, _)| left); + if !in_code && matches!(tag, "" | "rust" | "ignore" | "should_panic" | "no_run" | "compile_fail") { + explanation += "```rust\n"; + } else { + explanation += line; + explanation.push('\n'); + } + in_code = !in_code; + } else if !(in_code && line.starts_with("# ")) { + explanation += line; + explanation.push('\n'); + } + } + + println!("{}", explanation); // Check if the lint has configuration let mut mdconf = get_configuration_metadata(); let name = name.to_ascii_lowercase(); From daf730caedb638696ee704e22942617cf5848e5f Mon Sep 17 00:00:00 2001 From: blyxyas Date: Thu, 26 Sep 2024 00:23:38 +0200 Subject: [PATCH 018/260] Add `sanitize_explanation` --- clippy_lints/src/lib.rs | 43 +++++++++++++++++++++++------------------ tests/compile-test.rs | 7 ++++++- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e927d9a2d5bff..0bfbb92dfda55 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -522,30 +522,35 @@ impl LintInfo { } } -pub fn explain(name: &str) -> i32 { - let target = format!("clippy::{}", name.to_ascii_uppercase()); - - if let Some(info) = declared_lints::LINTS.iter().find(|info| info.lint.name == target) { - // Remove tags and hidden code: - let mut explanation = String::with_capacity(128); - let mut in_code = false; - for line in info.explanation.lines().map(|line| line.trim()) { - if let Some(lang) = line.strip_prefix("```") { - let tag = lang.split_once(',').map_or(lang, |(left, _)| left); - if !in_code && matches!(tag, "" | "rust" | "ignore" | "should_panic" | "no_run" | "compile_fail") { - explanation += "```rust\n"; - } else { - explanation += line; - explanation.push('\n'); - } - in_code = !in_code; - } else if !(in_code && line.starts_with("# ")) { +// Remove code tags and code behind '# 's, as they are not needed for the lint docs and --explain +pub fn sanitize_explanation(raw_docs: &str) -> String { + // Remove tags and hidden code: + let mut explanation = String::with_capacity(128); + let mut in_code = false; + for line in raw_docs.lines().map(|line| line.trim()) { + if let Some(lang) = line.strip_prefix("```") { + let tag = lang.split_once(',').map_or(lang, |(left, _)| left); + if !in_code && matches!(tag, "" | "rust" | "ignore" | "should_panic" | "no_run" | "compile_fail") { + explanation += "```rust\n"; + } else { explanation += line; explanation.push('\n'); } + in_code = !in_code; + } else if !(in_code && line.starts_with("# ")) { + explanation += line; + explanation.push('\n'); } + } - println!("{}", explanation); + explanation +} + +pub fn explain(name: &str) -> i32 { + let target = format!("clippy::{}", name.to_ascii_uppercase()); + + if let Some(info) = declared_lints::LINTS.iter().find(|info| info.lint.name == target) { + println!("{}", sanitize_explanation(info.explanation)); // Check if the lint has configuration let mut mdconf = get_configuration_metadata(); let name = name.to_ascii_lowercase(); diff --git a/tests/compile-test.rs b/tests/compile-test.rs index af2aa51925777..23dd41235bdbd 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -5,9 +5,9 @@ use cargo_metadata::Message; use cargo_metadata::diagnostic::{Applicability, Diagnostic}; use clippy_config::ClippyConfiguration; -use clippy_lints::LintInfo; use clippy_lints::declared_lints::LINTS; use clippy_lints::deprecated_lints::{DEPRECATED, DEPRECATED_VERSION, RENAMED}; +use clippy_lints::{LintInfo, sanitize_explanation}; use serde::{Deserialize, Serialize}; use test_utils::IS_RUSTC_TEST_SUITE; use ui_test::custom_flags::Flag; @@ -444,7 +444,12 @@ impl DiagnosticCollector { iter::zip(DEPRECATED, DEPRECATED_VERSION) .map(|((lint, reason), version)| LintMetadata::new_deprecated(lint, reason, version)), ) + .map(|mut metadata| { + metadata.docs = sanitize_explanation(&metadata.docs); + metadata + }) .collect(); + metadata.sort_unstable_by(|a, b| a.id.cmp(&b.id)); let json = serde_json::to_string_pretty(&metadata).unwrap(); From d232d094b8e2776a6a1e88f478442fd98e2e70b4 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Wed, 18 Sep 2024 10:34:27 -0700 Subject: [PATCH 019/260] Remove the `control_flow_enum` feature from clippy --- clippy_lints/src/lib.rs | 1 - clippy_utils/src/lib.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1d41f568f3785..54c3758459c72 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1,7 +1,6 @@ #![feature(array_windows)] #![feature(binary_heap_into_iter_sorted)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(f128)] #![feature(f16)] #![feature(if_let_guard)] diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 6dbc3334157e3..6c0413c180868 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1,6 +1,5 @@ #![feature(array_chunks)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(f128)] #![feature(f16)] #![feature(if_let_guard)] From c8725f70e77a08974a1d51bd360345a2ab7fabc6 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Thu, 26 Sep 2024 17:44:59 +0200 Subject: [PATCH 020/260] add proc macro check to needless_return --- clippy_lints/src/returns.rs | 2 +- tests/ui/needless_return.fixed | 8 +++ tests/ui/needless_return.rs | 8 +++ tests/ui/needless_return.stderr | 108 ++++++++++++++++---------------- 4 files changed, 71 insertions(+), 55 deletions(-) diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 3754fdddedfd1..6754912f76564 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -407,7 +407,7 @@ fn check_final_expr<'tcx>( } } - if ret_span.from_expansion() { + if ret_span.from_expansion() || is_from_proc_macro(cx, expr) { return; } diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index c5c570690b450..1507bc50a75e3 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -1,3 +1,4 @@ +//@aux-build:proc_macros.rs #![feature(yeet_expr)] #![allow(unused)] #![allow( @@ -9,6 +10,9 @@ )] #![warn(clippy::needless_return)] +extern crate proc_macros; +use proc_macros::with_span; + use std::cell::RefCell; macro_rules! the_answer { @@ -359,4 +363,8 @@ fn issue12907() -> String { "".split("").next().unwrap().to_string() } +fn issue13458() { + with_span!(span return); +} + fn main() {} diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index 738611391dfdf..c59bfced6d6f6 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -1,3 +1,4 @@ +//@aux-build:proc_macros.rs #![feature(yeet_expr)] #![allow(unused)] #![allow( @@ -9,6 +10,9 @@ )] #![warn(clippy::needless_return)] +extern crate proc_macros; +use proc_macros::with_span; + use std::cell::RefCell; macro_rules! the_answer { @@ -369,4 +373,8 @@ fn issue12907() -> String { return "".split("").next().unwrap().to_string(); } +fn issue13458() { + with_span!(span return); +} + fn main() {} diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index da0fa220d8c4a..d3c2a6badc0f4 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -1,5 +1,5 @@ error: unneeded `return` statement - --> tests/ui/needless_return.rs:25:5 + --> tests/ui/needless_return.rs:29:5 | LL | return true; | ^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:29:5 + --> tests/ui/needless_return.rs:33:5 | LL | return true; | ^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:34:5 + --> tests/ui/needless_return.rs:38:5 | LL | return true;;; | ^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:39:5 + --> tests/ui/needless_return.rs:43:5 | LL | return true;; ; ; | ^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:44:9 + --> tests/ui/needless_return.rs:48:9 | LL | return true; | ^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:46:9 + --> tests/ui/needless_return.rs:50:9 | LL | return false; | ^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + false | error: unneeded `return` statement - --> tests/ui/needless_return.rs:52:17 + --> tests/ui/needless_return.rs:56:17 | LL | true => return false, | ^^^^^^^^^^^^ @@ -84,7 +84,7 @@ LL | true => false, | ~~~~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:54:13 + --> tests/ui/needless_return.rs:58:13 | LL | return true; | ^^^^^^^^^^^ @@ -96,7 +96,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:61:9 + --> tests/ui/needless_return.rs:65:9 | LL | return true; | ^^^^^^^^^^^ @@ -108,7 +108,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:63:16 + --> tests/ui/needless_return.rs:67:16 | LL | let _ = || return true; | ^^^^^^^^^^^ @@ -119,7 +119,7 @@ LL | let _ = || true; | ~~~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:67:5 + --> tests/ui/needless_return.rs:71:5 | LL | return the_answer!(); | ^^^^^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL + the_answer!() | error: unneeded `return` statement - --> tests/ui/needless_return.rs:70:21 + --> tests/ui/needless_return.rs:74:21 | LL | fn test_void_fun() { | _____________________^ @@ -146,7 +146,7 @@ LL + fn test_void_fun() { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:75:11 + --> tests/ui/needless_return.rs:79:11 | LL | if b { | ___________^ @@ -161,7 +161,7 @@ LL + if b { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:77:13 + --> tests/ui/needless_return.rs:81:13 | LL | } else { | _____________^ @@ -176,7 +176,7 @@ LL + } else { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:85:14 + --> tests/ui/needless_return.rs:89:14 | LL | _ => return, | ^^^^^^ @@ -187,7 +187,7 @@ LL | _ => (), | ~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:93:24 + --> tests/ui/needless_return.rs:97:24 | LL | let _ = 42; | ________________________^ @@ -202,7 +202,7 @@ LL + let _ = 42; | error: unneeded `return` statement - --> tests/ui/needless_return.rs:96:14 + --> tests/ui/needless_return.rs:100:14 | LL | _ => return, | ^^^^^^ @@ -213,7 +213,7 @@ LL | _ => (), | ~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:109:9 + --> tests/ui/needless_return.rs:113:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -225,7 +225,7 @@ LL + String::from("test") | error: unneeded `return` statement - --> tests/ui/needless_return.rs:111:9 + --> tests/ui/needless_return.rs:115:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^ @@ -237,7 +237,7 @@ LL + String::new() | error: unneeded `return` statement - --> tests/ui/needless_return.rs:133:32 + --> tests/ui/needless_return.rs:137:32 | LL | bar.unwrap_or_else(|_| return) | ^^^^^^ @@ -248,7 +248,7 @@ LL | bar.unwrap_or_else(|_| {}) | ~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:137:21 + --> tests/ui/needless_return.rs:141:21 | LL | let _ = || { | _____________________^ @@ -263,7 +263,7 @@ LL + let _ = || { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:140:20 + --> tests/ui/needless_return.rs:144:20 | LL | let _ = || return; | ^^^^^^ @@ -274,7 +274,7 @@ LL | let _ = || {}; | ~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:146:32 + --> tests/ui/needless_return.rs:150:32 | LL | res.unwrap_or_else(|_| return Foo) | ^^^^^^^^^^ @@ -285,7 +285,7 @@ LL | res.unwrap_or_else(|_| Foo) | ~~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:155:5 + --> tests/ui/needless_return.rs:159:5 | LL | return true; | ^^^^^^^^^^^ @@ -297,7 +297,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:159:5 + --> tests/ui/needless_return.rs:163:5 | LL | return true; | ^^^^^^^^^^^ @@ -309,7 +309,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:164:9 + --> tests/ui/needless_return.rs:168:9 | LL | return true; | ^^^^^^^^^^^ @@ -321,7 +321,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:166:9 + --> tests/ui/needless_return.rs:170:9 | LL | return false; | ^^^^^^^^^^^^ @@ -333,7 +333,7 @@ LL + false | error: unneeded `return` statement - --> tests/ui/needless_return.rs:172:17 + --> tests/ui/needless_return.rs:176:17 | LL | true => return false, | ^^^^^^^^^^^^ @@ -344,7 +344,7 @@ LL | true => false, | ~~~~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:174:13 + --> tests/ui/needless_return.rs:178:13 | LL | return true; | ^^^^^^^^^^^ @@ -356,7 +356,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:181:9 + --> tests/ui/needless_return.rs:185:9 | LL | return true; | ^^^^^^^^^^^ @@ -368,7 +368,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:183:16 + --> tests/ui/needless_return.rs:187:16 | LL | let _ = || return true; | ^^^^^^^^^^^ @@ -379,7 +379,7 @@ LL | let _ = || true; | ~~~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:187:5 + --> tests/ui/needless_return.rs:191:5 | LL | return the_answer!(); | ^^^^^^^^^^^^^^^^^^^^ @@ -391,7 +391,7 @@ LL + the_answer!() | error: unneeded `return` statement - --> tests/ui/needless_return.rs:190:33 + --> tests/ui/needless_return.rs:194:33 | LL | async fn async_test_void_fun() { | _________________________________^ @@ -406,7 +406,7 @@ LL + async fn async_test_void_fun() { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:195:11 + --> tests/ui/needless_return.rs:199:11 | LL | if b { | ___________^ @@ -421,7 +421,7 @@ LL + if b { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:197:13 + --> tests/ui/needless_return.rs:201:13 | LL | } else { | _____________^ @@ -436,7 +436,7 @@ LL + } else { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:205:14 + --> tests/ui/needless_return.rs:209:14 | LL | _ => return, | ^^^^^^ @@ -447,7 +447,7 @@ LL | _ => (), | ~~ error: unneeded `return` statement - --> tests/ui/needless_return.rs:218:9 + --> tests/ui/needless_return.rs:222:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -459,7 +459,7 @@ LL + String::from("test") | error: unneeded `return` statement - --> tests/ui/needless_return.rs:220:9 + --> tests/ui/needless_return.rs:224:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^ @@ -471,7 +471,7 @@ LL + String::new() | error: unneeded `return` statement - --> tests/ui/needless_return.rs:236:5 + --> tests/ui/needless_return.rs:240:5 | LL | return format!("Hello {}", "world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -483,7 +483,7 @@ LL + format!("Hello {}", "world!") | error: unneeded `return` statement - --> tests/ui/needless_return.rs:277:9 + --> tests/ui/needless_return.rs:281:9 | LL | return true; | ^^^^^^^^^^^ @@ -497,7 +497,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:279:9 + --> tests/ui/needless_return.rs:283:9 | LL | return false; | ^^^^^^^^^^^^ @@ -509,7 +509,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:286:13 + --> tests/ui/needless_return.rs:290:13 | LL | return 10; | ^^^^^^^^^ @@ -524,7 +524,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:289:13 + --> tests/ui/needless_return.rs:293:13 | LL | return 100; | ^^^^^^^^^^ @@ -537,7 +537,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:297:9 + --> tests/ui/needless_return.rs:301:9 | LL | return 0; | ^^^^^^^^ @@ -549,7 +549,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:304:13 + --> tests/ui/needless_return.rs:308:13 | LL | return *(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -564,7 +564,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:306:13 + --> tests/ui/needless_return.rs:310:13 | LL | return !*(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -577,7 +577,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:313:20 + --> tests/ui/needless_return.rs:317:20 | LL | let _ = 42; | ____________________^ @@ -594,7 +594,7 @@ LL + let _ = 42; | error: unneeded `return` statement - --> tests/ui/needless_return.rs:320:20 + --> tests/ui/needless_return.rs:324:20 | LL | let _ = 42; return; | ^^^^^^^ @@ -606,7 +606,7 @@ LL + let _ = 42; | error: unneeded `return` statement - --> tests/ui/needless_return.rs:332:9 + --> tests/ui/needless_return.rs:336:9 | LL | return Ok(format!("ok!")); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -618,7 +618,7 @@ LL + Ok(format!("ok!")) | error: unneeded `return` statement - --> tests/ui/needless_return.rs:334:9 + --> tests/ui/needless_return.rs:338:9 | LL | return Err(format!("err!")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -630,7 +630,7 @@ LL + Err(format!("err!")) | error: unneeded `return` statement - --> tests/ui/needless_return.rs:340:9 + --> tests/ui/needless_return.rs:344:9 | LL | return if true { 1 } else { 2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -642,7 +642,7 @@ LL + if true { 1 } else { 2 } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:344:9 + --> tests/ui/needless_return.rs:348:9 | LL | return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -654,7 +654,7 @@ LL + (if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else | error: unneeded `return` statement - --> tests/ui/needless_return.rs:365:5 + --> tests/ui/needless_return.rs:369:5 | LL | return { "a".to_string() } + "b" + { "c" }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -666,7 +666,7 @@ LL + ({ "a".to_string() } + "b" + { "c" }) | error: unneeded `return` statement - --> tests/ui/needless_return.rs:369:5 + --> tests/ui/needless_return.rs:373:5 | LL | return "".split("").next().unwrap().to_string(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From b89c6204da4331d5d7c181e5c999cd34bfc54e10 Mon Sep 17 00:00:00 2001 From: Jonathan Birk Date: Thu, 26 Sep 2024 17:10:03 +0000 Subject: [PATCH 021/260] Make new information notes instead of labels --- compiler/rustc_hir_analysis/messages.ftl | 8 ++--- compiler/rustc_hir_analysis/src/errors.rs | 12 +++---- tests/ui/coherence/coherence-cow.re_a.stderr | 8 ++--- tests/ui/coherence/coherence-cow.re_b.stderr | 8 ++--- tests/ui/coherence/coherence-cow.re_c.stderr | 8 ++--- ...coherence-fundamental-trait-objects.stderr | 8 ++--- ...mpl-trait-for-marker-trait-negative.stderr | 8 ++--- ...mpl-trait-for-marker-trait-positive.stderr | 8 ++--- .../ui/coherence/coherence-impls-copy.stderr | 32 ++++++++--------- .../ui/coherence/coherence-impls-send.stderr | 24 ++++++------- .../ui/coherence/coherence-impls-sized.stderr | 24 ++++++------- .../coherence-negative-impls-copy-bad.stderr | 24 ++++++------- tests/ui/coherence/coherence-orphan.stderr | 18 +++++----- .../coherence-overlapping-pairs.stderr | 8 ++--- .../coherence-pair-covered-uncovered-1.stderr | 10 +++--- .../coherence-pair-covered-uncovered.stderr | 8 ++--- .../ui/coherence/coherence-vec-local-2.stderr | 8 ++--- tests/ui/coherence/coherence-vec-local.stderr | 8 ++--- .../coherence_local_err_struct.stderr | 8 ++--- .../coherence_local_err_tuple.stderr | 8 ++--- .../coherence/impl-foreign-for-foreign.stderr | 8 ++--- .../impl-foreign-for-foreign[foreign].stderr | 30 ++++++++-------- ...pl-foreign-for-fundamental[foreign].stderr | 20 +++++------ .../impl-foreign[foreign]-for-foreign.stderr | 10 +++--- ...n[fundemental[foreign]]-for-foreign.stderr | 36 +++++++++---------- .../impl[t]-foreign-for-foreign[t].stderr | 16 ++++----- tests/ui/dropck/drop-on-non-struct.stderr | 8 ++--- tests/ui/error-codes/E0117.stderr | 8 ++--- .../ui/error-codes/e0119/complex-impl.stderr | 8 ++--- .../issue-99572-impl-trait-on-pointer.stderr | 16 ++++----- tests/ui/issues/issue-67535.stderr | 30 ++++++++-------- .../const-and-non-const-impl.stderr | 10 +++--- .../coherence.classic.stderr | 8 ++--- .../coherence.next.stderr | 8 ++--- .../range_patterns_trait_impls2.stderr | 8 ++--- ...lt-trait-impl-cross-crate-coherence.stderr | 24 ++++++------- 36 files changed, 248 insertions(+), 248 deletions(-) diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index c81f1c62be9cc..444c4548ccbdd 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -351,14 +351,14 @@ hir_analysis_only_current_traits_arbitrary = only traits defined in the current hir_analysis_only_current_traits_foreign = this is not defined in the current crate because this is a foreign trait -hir_analysis_only_current_traits_label = impl doesn't have any local type before any uncovered type parameters - -hir_analysis_only_current_traits_label_more_info = for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules - hir_analysis_only_current_traits_name = this is not defined in the current crate because {$name} are always foreign hir_analysis_only_current_traits_note = define and implement a trait or new type instead +hir_analysis_only_current_traits_note_more_info = for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + +hir_analysis_only_current_traits_note_uncovered = impl doesn't have any local type before any uncovered type parameters + hir_analysis_only_current_traits_opaque = type alias impl trait is treated as if it were foreign, because its hidden type could be from a foreign crate hir_analysis_only_current_traits_outside = only traits defined in the current crate can be implemented for types defined outside of the crate diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 9488f2f86cb3e..25b79518dbb63 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1440,27 +1440,27 @@ pub enum OnlyCurrentTraits { #[diag(hir_analysis_only_current_traits_outside, code = E0117)] Outside { #[primary_span] - #[label(hir_analysis_only_current_traits_label)] - #[label(hir_analysis_only_current_traits_label_more_info)] span: Span, + #[note(hir_analysis_only_current_traits_note_uncovered)] + #[note(hir_analysis_only_current_traits_note_more_info)] #[note(hir_analysis_only_current_traits_note)] note: (), }, #[diag(hir_analysis_only_current_traits_primitive, code = E0117)] Primitive { #[primary_span] - #[label(hir_analysis_only_current_traits_label)] - #[label(hir_analysis_only_current_traits_label_more_info)] span: Span, + #[note(hir_analysis_only_current_traits_note_uncovered)] + #[note(hir_analysis_only_current_traits_note_more_info)] #[note(hir_analysis_only_current_traits_note)] note: (), }, #[diag(hir_analysis_only_current_traits_arbitrary, code = E0117)] Arbitrary { #[primary_span] - #[label(hir_analysis_only_current_traits_label)] - #[label(hir_analysis_only_current_traits_label_more_info)] span: Span, + #[note(hir_analysis_only_current_traits_note_uncovered)] + #[note(hir_analysis_only_current_traits_note_more_info)] #[note(hir_analysis_only_current_traits_note)] note: (), }, diff --git a/tests/ui/coherence/coherence-cow.re_a.stderr b/tests/ui/coherence/coherence-cow.re_a.stderr index b4331fc475b1e..67de3629491dd 100644 --- a/tests/ui/coherence/coherence-cow.re_a.stderr +++ b/tests/ui/coherence/coherence-cow.re_a.stderr @@ -3,11 +3,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ty | LL | impl Remote for Pair> { } | ^^^^^^^^^^^^^^^^^^^---------------- - | | | - | | `Pair` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `Pair` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 1 previous error diff --git a/tests/ui/coherence/coherence-cow.re_b.stderr b/tests/ui/coherence/coherence-cow.re_b.stderr index b401d96459885..360900cc7fff6 100644 --- a/tests/ui/coherence/coherence-cow.re_b.stderr +++ b/tests/ui/coherence/coherence-cow.re_b.stderr @@ -3,11 +3,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ty | LL | impl Remote for Pair,T> { } | ^^^^^^^^^^^^^^^^^^^---------------- - | | | - | | `Pair` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `Pair` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 1 previous error diff --git a/tests/ui/coherence/coherence-cow.re_c.stderr b/tests/ui/coherence/coherence-cow.re_c.stderr index d95beee8139e2..73f2aa196fd4b 100644 --- a/tests/ui/coherence/coherence-cow.re_c.stderr +++ b/tests/ui/coherence/coherence-cow.re_c.stderr @@ -3,11 +3,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ty | LL | impl Remote for Pair,U> { } | ^^^^^^^^^^^^^^^^^^^^^---------------- - | | | - | | `Pair` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `Pair` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 1 previous error diff --git a/tests/ui/coherence/coherence-fundamental-trait-objects.stderr b/tests/ui/coherence/coherence-fundamental-trait-objects.stderr index 4933fb155f732..ca43d70e0b1b8 100644 --- a/tests/ui/coherence/coherence-fundamental-trait-objects.stderr +++ b/tests/ui/coherence/coherence-fundamental-trait-objects.stderr @@ -3,11 +3,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl Misc for dyn Fundamental {} | ^^^^^^^^^^^^^^---------------------- - | | | - | | `dyn Fundamental` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `dyn Fundamental` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 1 previous error diff --git a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr index c8b215037b9ef..77d1bdee5acf1 100644 --- a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr +++ b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr @@ -39,11 +39,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl !Send for dyn Marker2 {} | ^^^^^^^^^^^^^^^----------- - | | | - | | `dyn Marker2` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `dyn Marker2` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `(dyn Object + 'static)` diff --git a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr index 02107453a9ff3..f38aeaed0aaca 100644 --- a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr +++ b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr @@ -39,11 +39,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | unsafe impl Send for dyn Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^----------- - | | | - | | `dyn Marker2` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `dyn Marker2` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `(dyn Object + 'static)` diff --git a/tests/ui/coherence/coherence-impls-copy.stderr b/tests/ui/coherence/coherence-impls-copy.stderr index 2de854ed58430..79fe044c4cf4a 100644 --- a/tests/ui/coherence/coherence-impls-copy.stderr +++ b/tests/ui/coherence/coherence-impls-copy.stderr @@ -13,11 +13,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl Copy for &'static [NotSync] {} | ^^^^^^^^^^^^^^------------------ - | | | - | | this is not defined in the current crate because slices are always foreign - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | this is not defined in the current crate because slices are always foreign | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0117]: only traits defined in the current crate can be implemented for primitive types @@ -25,11 +25,11 @@ error[E0117]: only traits defined in the current crate can be implemented for pr | LL | impl Copy for i32 {} | ^^^^^^^^^^^^^^--- - | | | - | | `i32` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `i32` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0206]: the trait `Copy` cannot be implemented for this type @@ -43,11 +43,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl Copy for (MyType, MyType) {} | ^^^^^^^^^^^^^^---------------- - | | | - | | this is not defined in the current crate because tuples are always foreign - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | this is not defined in the current crate because tuples are always foreign | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0206]: the trait `Copy` cannot be implemented for this type @@ -61,11 +61,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl Copy for [MyType] {} | ^^^^^^^^^^^^^^-------- - | | | - | | this is not defined in the current crate because slices are always foreign - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | this is not defined in the current crate because slices are always foreign | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0206]: the trait `Copy` cannot be implemented for this type diff --git a/tests/ui/coherence/coherence-impls-send.stderr b/tests/ui/coherence/coherence-impls-send.stderr index a41e9d620e01c..78e89eb55409f 100644 --- a/tests/ui/coherence/coherence-impls-send.stderr +++ b/tests/ui/coherence/coherence-impls-send.stderr @@ -3,11 +3,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | unsafe impl Send for &'static [NotSync] {} | ^^^^^^^^^^^^^^^^^^^^^------------------ - | | | - | | this is not defined in the current crate because slices are always foreign - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | this is not defined in the current crate because slices are always foreign | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0117]: only traits defined in the current crate can be implemented for arbitrary types @@ -15,11 +15,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | unsafe impl Send for (MyType, MyType) {} | ^^^^^^^^^^^^^^^^^^^^^---------------- - | | | - | | this is not defined in the current crate because tuples are always foreign - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | this is not defined in the current crate because tuples are always foreign | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `&'static NotSync` @@ -33,11 +33,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | unsafe impl Send for [MyType] {} | ^^^^^^^^^^^^^^^^^^^^^-------- - | | | - | | this is not defined in the current crate because slices are always foreign - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | this is not defined in the current crate because slices are always foreign | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 4 previous errors diff --git a/tests/ui/coherence/coherence-impls-sized.stderr b/tests/ui/coherence/coherence-impls-sized.stderr index 080d19e075b5f..3201f1b25def8 100644 --- a/tests/ui/coherence/coherence-impls-sized.stderr +++ b/tests/ui/coherence/coherence-impls-sized.stderr @@ -21,11 +21,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl Sized for (MyType, MyType) {} | ^^^^^^^^^^^^^^^---------------- - | | | - | | this is not defined in the current crate because tuples are always foreign - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | this is not defined in the current crate because tuples are always foreign | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0322]: explicit impls for the `Sized` trait are not permitted @@ -45,11 +45,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl Sized for [MyType] {} | ^^^^^^^^^^^^^^^-------- - | | | - | | this is not defined in the current crate because slices are always foreign - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | this is not defined in the current crate because slices are always foreign | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0322]: explicit impls for the `Sized` trait are not permitted @@ -63,11 +63,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl Sized for &'static [NotSync] {} | ^^^^^^^^^^^^^^^------------------ - | | | - | | this is not defined in the current crate because slices are always foreign - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | this is not defined in the current crate because slices are always foreign | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 9 previous errors diff --git a/tests/ui/coherence/coherence-negative-impls-copy-bad.stderr b/tests/ui/coherence/coherence-negative-impls-copy-bad.stderr index 85937c5f02a81..074cd87ba9246 100644 --- a/tests/ui/coherence/coherence-negative-impls-copy-bad.stderr +++ b/tests/ui/coherence/coherence-negative-impls-copy-bad.stderr @@ -3,11 +3,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl !Copy for str {} | ^^^^^^^^^^^^^^^--- - | | | - | | `str` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `str` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0117]: only traits defined in the current crate can be implemented for arbitrary types @@ -15,11 +15,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl !Copy for fn() {} | ^^^^^^^^^^^^^^^---- - | | | - | | `fn()` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `fn()` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0117]: only traits defined in the current crate can be implemented for arbitrary types @@ -27,11 +27,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl !Copy for () {} | ^^^^^^^^^^^^^^^-- - | | | - | | this is not defined in the current crate because tuples are always foreign - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | this is not defined in the current crate because tuples are always foreign | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 3 previous errors diff --git a/tests/ui/coherence/coherence-orphan.stderr b/tests/ui/coherence/coherence-orphan.stderr index c10ed013ef251..dcf423e24eedb 100644 --- a/tests/ui/coherence/coherence-orphan.stderr +++ b/tests/ui/coherence/coherence-orphan.stderr @@ -3,12 +3,12 @@ error[E0117]: only traits defined in the current crate can be implemented for pr | LL | impl TheTrait for isize {} | ^^^^^---------------^^^^^----- - | | | | - | | | `isize` is not defined in the current crate - | | `usize` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | | + | | `isize` is not defined in the current crate + | `usize` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate @@ -16,11 +16,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ty | LL | impl !Send for Vec {} | ^^^^^^^^^^^^^^^---------- - | | | - | | `Vec` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `Vec` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 2 previous errors diff --git a/tests/ui/coherence/coherence-overlapping-pairs.stderr b/tests/ui/coherence/coherence-overlapping-pairs.stderr index 448e7b9d5ef15..6e7a90ac369c4 100644 --- a/tests/ui/coherence/coherence-overlapping-pairs.stderr +++ b/tests/ui/coherence/coherence-overlapping-pairs.stderr @@ -3,11 +3,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ty | LL | impl Remote for lib::Pair { } | ^^^^^^^^^^^^^^^^^^^---------------- - | | | - | | `Pair` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `Pair` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 1 previous error diff --git a/tests/ui/coherence/coherence-pair-covered-uncovered-1.stderr b/tests/ui/coherence/coherence-pair-covered-uncovered-1.stderr index 2e616fefe0ee3..d7890d156cae9 100644 --- a/tests/ui/coherence/coherence-pair-covered-uncovered-1.stderr +++ b/tests/ui/coherence/coherence-pair-covered-uncovered-1.stderr @@ -3,12 +3,12 @@ error[E0117]: only traits defined in the current crate can be implemented for pr | LL | impl Remote1>> for i32 { } | ^^^^^^^^^^^--------------------------^^^^^--- - | | | | - | | | `i32` is not defined in the current crate - | | `Pair` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | | + | | `i32` is not defined in the current crate + | `Pair` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 1 previous error diff --git a/tests/ui/coherence/coherence-pair-covered-uncovered.stderr b/tests/ui/coherence/coherence-pair-covered-uncovered.stderr index 71a1e4c7ac3fb..fa3d170f81d4f 100644 --- a/tests/ui/coherence/coherence-pair-covered-uncovered.stderr +++ b/tests/ui/coherence/coherence-pair-covered-uncovered.stderr @@ -3,11 +3,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ty | LL | impl Remote for Pair> { } | ^^^^^^^^^^^^^^^^^^^^^---------------- - | | | - | | `Pair` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `Pair` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 1 previous error diff --git a/tests/ui/coherence/coherence-vec-local-2.stderr b/tests/ui/coherence/coherence-vec-local-2.stderr index 50788e4a990eb..cb12275cf01cb 100644 --- a/tests/ui/coherence/coherence-vec-local-2.stderr +++ b/tests/ui/coherence/coherence-vec-local-2.stderr @@ -3,11 +3,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ty | LL | impl Remote for Vec> { } | ^^^^^^^^^^^^^^^^^^^------------- - | | | - | | `Vec` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `Vec` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 1 previous error diff --git a/tests/ui/coherence/coherence-vec-local.stderr b/tests/ui/coherence/coherence-vec-local.stderr index cd102fa1c6d1b..9278b9458d56e 100644 --- a/tests/ui/coherence/coherence-vec-local.stderr +++ b/tests/ui/coherence/coherence-vec-local.stderr @@ -3,11 +3,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ty | LL | impl Remote for Vec { } | ^^^^^^^^^^^^^^^^---------- - | | | - | | `Vec` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `Vec` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 1 previous error diff --git a/tests/ui/coherence/coherence_local_err_struct.stderr b/tests/ui/coherence/coherence_local_err_struct.stderr index 97a26b54a1be0..280dd57bd42d4 100644 --- a/tests/ui/coherence/coherence_local_err_struct.stderr +++ b/tests/ui/coherence/coherence_local_err_struct.stderr @@ -3,11 +3,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ty | LL | impl lib::MyCopy for lib::MyStruct { } | ^^^^^^^^^^^^^^^^^^^^^--------------------- - | | | - | | `MyStruct` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `MyStruct` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 1 previous error diff --git a/tests/ui/coherence/coherence_local_err_tuple.stderr b/tests/ui/coherence/coherence_local_err_tuple.stderr index cdd73be86bfa0..d07adab0014e2 100644 --- a/tests/ui/coherence/coherence_local_err_tuple.stderr +++ b/tests/ui/coherence/coherence_local_err_tuple.stderr @@ -3,11 +3,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl lib::MyCopy for (MyType,) { } | ^^^^^^^^^^^^^^^^^^^^^--------- - | | | - | | this is not defined in the current crate because tuples are always foreign - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | this is not defined in the current crate because tuples are always foreign | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 1 previous error diff --git a/tests/ui/coherence/impl-foreign-for-foreign.stderr b/tests/ui/coherence/impl-foreign-for-foreign.stderr index 0f8af5ef0280b..4ff965290c883 100644 --- a/tests/ui/coherence/impl-foreign-for-foreign.stderr +++ b/tests/ui/coherence/impl-foreign-for-foreign.stderr @@ -3,11 +3,11 @@ error[E0117]: only traits defined in the current crate can be implemented for pr | LL | impl Remote for i32 { | ^^^^^^^^^^^^^^^^--- - | | | - | | `i32` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `i32` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 1 previous error diff --git a/tests/ui/coherence/impl-foreign-for-foreign[foreign].stderr b/tests/ui/coherence/impl-foreign-for-foreign[foreign].stderr index ae1807f6dd055..ce5376f98cb72 100644 --- a/tests/ui/coherence/impl-foreign-for-foreign[foreign].stderr +++ b/tests/ui/coherence/impl-foreign-for-foreign[foreign].stderr @@ -3,12 +3,12 @@ error[E0117]: only traits defined in the current crate can be implemented for pr | LL | impl Remote1> for i32 { | ^^^^^----------------^^^^^--- - | | | | - | | | `i32` is not defined in the current crate - | | `Rc` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | | + | | `i32` is not defined in the current crate + | `Rc` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0117]: only traits defined in the current crate can be implemented for primitive types @@ -16,12 +16,12 @@ error[E0117]: only traits defined in the current crate can be implemented for pr | LL | impl Remote1> for f64 { | ^^^^^------------------^^^^^--- - | | | | - | | | `f64` is not defined in the current crate - | | `Rc` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | | + | | `f64` is not defined in the current crate + | `Rc` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0117]: only traits defined in the current crate can be implemented for primitive types @@ -29,12 +29,12 @@ error[E0117]: only traits defined in the current crate can be implemented for pr | LL | impl Remote1> for f32 { | ^^^^^^^^--------------^^^^^--- - | | | | - | | | `f32` is not defined in the current crate - | | `Rc` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | | + | | `f32` is not defined in the current crate + | `Rc` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 3 previous errors diff --git a/tests/ui/coherence/impl-foreign-for-fundamental[foreign].stderr b/tests/ui/coherence/impl-foreign-for-fundamental[foreign].stderr index a3522a75c86cf..596f8436567ae 100644 --- a/tests/ui/coherence/impl-foreign-for-fundamental[foreign].stderr +++ b/tests/ui/coherence/impl-foreign-for-fundamental[foreign].stderr @@ -3,12 +3,12 @@ error[E0117]: only traits defined in the current crate can be implemented for ty | LL | impl Remote for Box { | ^^^^^------^^^^^-------- - | | | | - | | | `i32` is not defined in the current crate - | | `std::alloc::Global` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | | + | | `i32` is not defined in the current crate + | `std::alloc::Global` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate @@ -16,12 +16,12 @@ error[E0117]: only traits defined in the current crate can be implemented for ty | LL | impl Remote for Box> { | ^^^^^^^^------^^^^^---------- - | | | | - | | | `Rc` is not defined in the current crate - | | `std::alloc::Global` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | | + | | `Rc` is not defined in the current crate + | `std::alloc::Global` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 2 previous errors diff --git a/tests/ui/coherence/impl-foreign[foreign]-for-foreign.stderr b/tests/ui/coherence/impl-foreign[foreign]-for-foreign.stderr index bf22e73dd09d8..d9dd2b8a8c625 100644 --- a/tests/ui/coherence/impl-foreign[foreign]-for-foreign.stderr +++ b/tests/ui/coherence/impl-foreign[foreign]-for-foreign.stderr @@ -3,12 +3,12 @@ error[E0117]: only traits defined in the current crate can be implemented for pr | LL | impl Remote1 for f64 { | ^^^^^------------^^^^^--- - | | | | - | | | `f64` is not defined in the current crate - | | `u32` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | | + | | `f64` is not defined in the current crate + | `u32` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 1 previous error diff --git a/tests/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr b/tests/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr index 2ab5cca7983cb..91f1886142cf6 100644 --- a/tests/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr +++ b/tests/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr @@ -3,13 +3,13 @@ error[E0117]: only traits defined in the current crate can be implemented for pr | LL | impl Remote1> for i32 { | ^^^^^--------------------^^^^^--- - | | | | - | | | `i32` is not defined in the current crate - | | `String` is not defined in the current crate - | | `std::alloc::Global` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | | + | | `i32` is not defined in the current crate + | `String` is not defined in the current crate + | `std::alloc::Global` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0117]: only traits defined in the current crate can be implemented for primitive types @@ -17,13 +17,13 @@ error[E0117]: only traits defined in the current crate can be implemented for pr | LL | impl Remote1>> for f64 { | ^^^^^---------------------^^^^^--- - | | | | - | | | `f64` is not defined in the current crate - | | `Rc` is not defined in the current crate - | | `std::alloc::Global` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | | + | | `f64` is not defined in the current crate + | `Rc` is not defined in the current crate + | `std::alloc::Global` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0117]: only traits defined in the current crate can be implemented for primitive types @@ -31,13 +31,13 @@ error[E0117]: only traits defined in the current crate can be implemented for pr | LL | impl Remote1>> for f32 { | ^^^^^^^^-------------------^^^^^--- - | | | | - | | | `f32` is not defined in the current crate - | | `Rc` is not defined in the current crate - | | `std::alloc::Global` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | | + | | `f32` is not defined in the current crate + | `Rc` is not defined in the current crate + | `std::alloc::Global` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 3 previous errors diff --git a/tests/ui/coherence/impl[t]-foreign-for-foreign[t].stderr b/tests/ui/coherence/impl[t]-foreign-for-foreign[t].stderr index ca9a7d5cd930a..306a5d1610d70 100644 --- a/tests/ui/coherence/impl[t]-foreign-for-foreign[t].stderr +++ b/tests/ui/coherence/impl[t]-foreign-for-foreign[t].stderr @@ -3,11 +3,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ty | LL | impl Remote for Rc { | ^^^^^^^^^^^^^^^^--------- - | | | - | | `Rc` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `Rc` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate @@ -15,11 +15,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ty | LL | impl Remote for Arc { | ^^^^^^^^^^^^^^^^^^^------ - | | | - | | `Arc` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `Arc` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 2 previous errors diff --git a/tests/ui/dropck/drop-on-non-struct.stderr b/tests/ui/dropck/drop-on-non-struct.stderr index 78b7212b6d9fd..9495642e45e4d 100644 --- a/tests/ui/dropck/drop-on-non-struct.stderr +++ b/tests/ui/dropck/drop-on-non-struct.stderr @@ -9,11 +9,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl<'a> Drop for &'a mut isize { | ^^^^^^^^^^^^^^^^^^------------- - | | | - | | `isize` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `isize` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0120]: the `Drop` trait may only be implemented for local structs, enums, and unions diff --git a/tests/ui/error-codes/E0117.stderr b/tests/ui/error-codes/E0117.stderr index 2bfa78d1954d7..f6e80e5930447 100644 --- a/tests/ui/error-codes/E0117.stderr +++ b/tests/ui/error-codes/E0117.stderr @@ -3,11 +3,11 @@ error[E0117]: only traits defined in the current crate can be implemented for pr | LL | impl Drop for u32 {} | ^^^^^^^^^^^^^^--- - | | | - | | `u32` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `u32` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0120]: the `Drop` trait may only be implemented for local structs, enums, and unions diff --git a/tests/ui/error-codes/e0119/complex-impl.stderr b/tests/ui/error-codes/e0119/complex-impl.stderr index 36618cee0e837..b7e434c4afe3c 100644 --- a/tests/ui/error-codes/e0119/complex-impl.stderr +++ b/tests/ui/error-codes/e0119/complex-impl.stderr @@ -3,11 +3,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl External for (Q, R) {} | ^^^^^^^^^^^^^^^^^^^^^------ - | | | - | | this is not defined in the current crate because tuples are always foreign - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | this is not defined in the current crate because tuples are always foreign | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 1 previous error diff --git a/tests/ui/errors/issue-99572-impl-trait-on-pointer.stderr b/tests/ui/errors/issue-99572-impl-trait-on-pointer.stderr index 214618d6636fb..bd40b059e5809 100644 --- a/tests/ui/errors/issue-99572-impl-trait-on-pointer.stderr +++ b/tests/ui/errors/issue-99572-impl-trait-on-pointer.stderr @@ -3,11 +3,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl fmt::Display for *mut LocalType { | ^^^^^^^^^^^^^^^^^^^^^^-------------- - | | | - | | `*mut LocalType` is not defined in the current crate because raw pointers are always foreign - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `*mut LocalType` is not defined in the current crate because raw pointers are always foreign | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead help: consider introducing a new wrapper type | @@ -21,11 +21,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl marker::Copy for *mut T { | ^^^^^^^^^^^^^^^^^^^^^^^^^------ - | | | - | | `*mut T` is not defined in the current crate because raw pointers are always foreign - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `*mut T` is not defined in the current crate because raw pointers are always foreign | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-67535.stderr b/tests/ui/issues/issue-67535.stderr index a953a9152144f..2afa2199a6afe 100644 --- a/tests/ui/issues/issue-67535.stderr +++ b/tests/ui/issues/issue-67535.stderr @@ -3,12 +3,12 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl std::ops::AddAssign for () { | ^^^^^-------------------^^^^^-- - | | | | - | | | this is not defined in the current crate because tuples are always foreign - | | this is not defined in the current crate because this is a foreign trait - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | | + | | this is not defined in the current crate because tuples are always foreign + | this is not defined in the current crate because this is a foreign trait | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0117]: only traits defined in the current crate can be implemented for arbitrary types @@ -16,12 +16,12 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl std::ops::AddAssign for [(); 1] { | ^^^^^-------------------^^^^^------- - | | | | - | | | this is not defined in the current crate because arrays are always foreign - | | this is not defined in the current crate because this is a foreign trait - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | | + | | this is not defined in the current crate because arrays are always foreign + | this is not defined in the current crate because this is a foreign trait | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0117]: only traits defined in the current crate can be implemented for arbitrary types @@ -29,12 +29,12 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl std::ops::AddAssign for &[u8] { | ^^^^^-------------------^^^^^----- - | | | | - | | | this is not defined in the current crate because slices are always foreign - | | this is not defined in the current crate because this is a foreign trait - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | | + | | this is not defined in the current crate because slices are always foreign + | this is not defined in the current crate because this is a foreign trait | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 3 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr index 4dff35c46e840..cf7af41cd4e47 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr @@ -30,12 +30,12 @@ error[E0117]: only traits defined in the current crate can be implemented for pr | LL | impl const std::ops::Add for i32 { | ^^^^^^^^^^^-------------^^^^^--- - | | | | - | | | `i32` is not defined in the current crate - | | `i32` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | | + | | `i32` is not defined in the current crate + | `i32` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 4 previous errors diff --git a/tests/ui/type-alias-impl-trait/coherence.classic.stderr b/tests/ui/type-alias-impl-trait/coherence.classic.stderr index 4cd87253b3079..98badeef382de 100644 --- a/tests/ui/type-alias-impl-trait/coherence.classic.stderr +++ b/tests/ui/type-alias-impl-trait/coherence.classic.stderr @@ -3,11 +3,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl foreign_crate::ForeignTrait for AliasOfForeignType<()> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------- - | | | - | | type alias impl trait is treated as if it were foreign, because its hidden type could be from a foreign crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | type alias impl trait is treated as if it were foreign, because its hidden type could be from a foreign crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/coherence.next.stderr b/tests/ui/type-alias-impl-trait/coherence.next.stderr index 886b667b8c8bb..8d7183831109a 100644 --- a/tests/ui/type-alias-impl-trait/coherence.next.stderr +++ b/tests/ui/type-alias-impl-trait/coherence.next.stderr @@ -3,11 +3,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl foreign_crate::ForeignTrait for AliasOfForeignType<()> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------- - | | | - | | `AliasOfForeignType<()>` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `AliasOfForeignType<()>` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 1 previous error diff --git a/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr b/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr index 2d3f8403315dc..df56db031ed18 100644 --- a/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr +++ b/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr @@ -3,11 +3,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl Eq for Y {} | ^^^^^^^^^^^^- - | | | - | | `(u32) is 1..=` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `(u32) is 1..=` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 1 previous error diff --git a/tests/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr b/tests/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr index 8ee6846eac28a..c7d714dcb1adb 100644 --- a/tests/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr +++ b/tests/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr @@ -3,11 +3,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl DefaultedTrait for (A,) {} | ^^^^^^^^^^^^^^^^^^^^^^^^---- - | | | - | | this is not defined in the current crate because tuples are always foreign - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | this is not defined in the current crate because tuples are always foreign | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0117]: only traits defined in the current crate can be implemented for arbitrary types @@ -15,11 +15,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ar | LL | impl !DefaultedTrait for (B,) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^---- - | | | - | | this is not defined in the current crate because tuples are always foreign - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | this is not defined in the current crate because tuples are always foreign | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error[E0321]: cross-crate traits with a default impl, like `DefaultedTrait`, can only be implemented for a struct/enum type defined in the current crate @@ -33,11 +33,11 @@ error[E0117]: only traits defined in the current crate can be implemented for ty | LL | impl DefaultedTrait for lib::Something {} | ^^^^^^^^^^^^^^^^^^^^^^^^----------------- - | | | - | | `Something` is not defined in the current crate - | impl doesn't have any local type before any uncovered type parameters - | for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + | | + | `Something` is not defined in the current crate | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules = note: define and implement a trait or new type instead error: aborting due to 4 previous errors From 1598aa4f83d249bbef1c8593274eb09b1d58f6ba Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 25 Aug 2024 16:54:46 +0100 Subject: [PATCH 022/260] Make destructors on `extern "C"` frames to be executed --- .../src/abort_unwinding_calls.rs | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs index d889bc90c9d74..84c8a91b08252 100644 --- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs +++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs @@ -51,11 +51,20 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls { // This will filter to functions with `extern "C-unwind"` ABIs, for // example. for block in body.basic_blocks.as_mut() { + let Some(terminator) = &mut block.terminator else { continue }; + let span = terminator.source_info.span; + + // If we see an `UnwindResume` terminator inside a function that cannot unwind, we need + // to replace it with `UnwindTerminate`. + if let TerminatorKind::UnwindResume = &terminator.kind + && !body_can_unwind + { + terminator.kind = TerminatorKind::UnwindTerminate(UnwindTerminateReason::Abi); + } + if block.is_cleanup { continue; } - let Some(terminator) = &block.terminator else { continue }; - let span = terminator.source_info.span; let call_can_unwind = match &terminator.kind { TerminatorKind::Call { func, .. } => { @@ -87,14 +96,18 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls { if !call_can_unwind { // If this function call can't unwind, then there's no need for it // to have a landing pad. This means that we can remove any cleanup - // registered for it. + // registered for it (and turn it into `UnwindAction::Unreachable`). let cleanup = block.terminator_mut().unwind_mut().unwrap(); *cleanup = UnwindAction::Unreachable; - } else if !body_can_unwind { + } else if !body_can_unwind + && matches!(terminator.unwind(), Some(UnwindAction::Continue)) + { // Otherwise if this function can unwind, then if the outer function // can also unwind there's nothing to do. If the outer function - // can't unwind, however, we need to change the landing pad for this - // function call to one that aborts. + // can't unwind, however, we need to ensure that any `UnwindAction::Continue` + // is replaced with terminate. For those with `UnwindAction::Cleanup`, + // cleanup will still happen, and terminate will happen afterwards handled by + // the `UnwindResume` -> `UnwindTerminate` terminator replacement. let cleanup = block.terminator_mut().unwind_mut().unwrap(); *cleanup = UnwindAction::Terminate(UnwindTerminateReason::Abi); } From 8f63b6a7454c05f512515946a0e9ca7e3b904144 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 28 Aug 2024 18:00:21 +0100 Subject: [PATCH 023/260] Add and adapt tests --- ...c_abort.main.AbortUnwindingCalls.after.mir | 6 +++- tests/mir-opt/asm_unwind_panic_abort.rs | 4 ++- tests/mir-opt/c_unwind_terminate.rs | 25 +++++++++++++ ...rminate.test.AbortUnwindingCalls.after.mir | 36 +++++++++++++++++++ tests/ui/panics/panic-in-ffi.rs | 9 +++++ tests/ui/panics/panic-in-ffi.run.stderr | 3 +- 6 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 tests/mir-opt/c_unwind_terminate.rs create mode 100644 tests/mir-opt/c_unwind_terminate.test.AbortUnwindingCalls.after.mir diff --git a/tests/mir-opt/asm_unwind_panic_abort.main.AbortUnwindingCalls.after.mir b/tests/mir-opt/asm_unwind_panic_abort.main.AbortUnwindingCalls.after.mir index 005b3ee3b249b..0ea9937e2a243 100644 --- a/tests/mir-opt/asm_unwind_panic_abort.main.AbortUnwindingCalls.after.mir +++ b/tests/mir-opt/asm_unwind_panic_abort.main.AbortUnwindingCalls.after.mir @@ -7,7 +7,7 @@ fn main() -> () { bb0: { StorageLive(_1); _1 = const (); - asm!("", options(MAY_UNWIND)) -> [return: bb1, unwind terminate(abi)]; + asm!("", options(MAY_UNWIND)) -> [return: bb1, unwind: bb2]; } bb1: { @@ -15,4 +15,8 @@ fn main() -> () { _0 = const (); return; } + + bb2 (cleanup): { + terminate(abi); + } } diff --git a/tests/mir-opt/asm_unwind_panic_abort.rs b/tests/mir-opt/asm_unwind_panic_abort.rs index fff6094212449..4ae76cbd16fe7 100644 --- a/tests/mir-opt/asm_unwind_panic_abort.rs +++ b/tests/mir-opt/asm_unwind_panic_abort.rs @@ -10,7 +10,9 @@ fn main() { // CHECK-LABEL: fn main( // CHECK: asm!( - // CHECK-SAME: unwind terminate(abi) + // CHECK-SAME: unwind: [[unwind:bb.*]]] + // CHECK: [[unwind]] (cleanup) + // CHECK-NEXT: terminate(abi) unsafe { std::arch::asm!("", options(may_unwind)); } diff --git a/tests/mir-opt/c_unwind_terminate.rs b/tests/mir-opt/c_unwind_terminate.rs new file mode 100644 index 0000000000000..64524e74d28e5 --- /dev/null +++ b/tests/mir-opt/c_unwind_terminate.rs @@ -0,0 +1,25 @@ +//@ needs-unwind + +struct Noise; +impl Drop for Noise { + fn drop(&mut self) { + eprintln!("Noisy Drop"); + } +} + +fn panic() { + panic!(); +} + +// EMIT_MIR c_unwind_terminate.test.AbortUnwindingCalls.after.mir +extern "C" fn test() { + // CHECK-LABEL: fn test( + // CHECK: drop + // CHECK-SAME: unwind: [[unwind:bb.*]]] + // CHECK: [[unwind]] (cleanup) + // CHECK-NEXT: terminate(abi) + let _val = Noise; + panic(); +} + +fn main() {} diff --git a/tests/mir-opt/c_unwind_terminate.test.AbortUnwindingCalls.after.mir b/tests/mir-opt/c_unwind_terminate.test.AbortUnwindingCalls.after.mir new file mode 100644 index 0000000000000..dd792d743cc5a --- /dev/null +++ b/tests/mir-opt/c_unwind_terminate.test.AbortUnwindingCalls.after.mir @@ -0,0 +1,36 @@ +// MIR for `test` after AbortUnwindingCalls + +fn test() -> () { + let mut _0: (); + let _1: Noise; + let _2: (); + scope 1 { + debug _val => _1; + } + + bb0: { + StorageLive(_1); + _1 = Noise; + StorageLive(_2); + _2 = panic() -> [return: bb1, unwind: bb3]; + } + + bb1: { + StorageDead(_2); + _0 = const (); + drop(_1) -> [return: bb2, unwind: bb4]; + } + + bb2: { + StorageDead(_1); + return; + } + + bb3 (cleanup): { + drop(_1) -> [return: bb4, unwind terminate(cleanup)]; + } + + bb4 (cleanup): { + terminate(abi); + } +} diff --git a/tests/ui/panics/panic-in-ffi.rs b/tests/ui/panics/panic-in-ffi.rs index 88f45f9a871d7..c0ae1899f4c28 100644 --- a/tests/ui/panics/panic-in-ffi.rs +++ b/tests/ui/panics/panic-in-ffi.rs @@ -2,13 +2,22 @@ //@ exec-env:RUST_BACKTRACE=0 //@ check-run-results //@ error-pattern: panic in a function that cannot unwind +//@ error-pattern: Noisy Drop //@ normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@ normalize-stderr-test: "\n +at [^\n]+" -> "" //@ normalize-stderr-test: "(core/src/panicking\.rs):[0-9]+:[0-9]+" -> "$1:$$LINE:$$COL" //@ needs-unwind //@ ignore-emscripten "RuntimeError" junk in output +struct Noise; +impl Drop for Noise { + fn drop(&mut self) { + eprintln!("Noisy Drop"); + } +} + extern "C" fn panic_in_ffi() { + let _val = Noise; panic!("Test"); } diff --git a/tests/ui/panics/panic-in-ffi.run.stderr b/tests/ui/panics/panic-in-ffi.run.stderr index fc70847ad9a3a..58f5187f0daf5 100644 --- a/tests/ui/panics/panic-in-ffi.run.stderr +++ b/tests/ui/panics/panic-in-ffi.run.stderr @@ -1,6 +1,7 @@ -thread 'main' panicked at $DIR/panic-in-ffi.rs:12:5: +thread 'main' panicked at $DIR/panic-in-ffi.rs:21:5: Test note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +Noisy Drop thread 'main' panicked at core/src/panicking.rs:$LINE:$COL: panic in a function that cannot unwind stack backtrace: From 1239c81c145d2bfb96f32856f377cd741d5c7256 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 10 Feb 2024 05:26:32 +0000 Subject: [PATCH 024/260] ci update freebsd version proposal, freebsd 12 being eol. raising to the lowest still active supported freebsd version. From 13.1 (already eol too), freebsd introduces a cpu affinity layer with linux. It also introduces a api compatible copy_file_range which can be used like its linux's counterpart. The former is essential to build #120589, therefore breaks the backward compatibility with the previous FreeBSD releases. --- .../host-x86_64/dist-various-2/Dockerfile | 6 +++--- .../host-x86_64/dist-x86_64-freebsd/Dockerfile | 6 +++--- src/ci/docker/scripts/freebsd-toolchain.sh | 8 ++++---- src/doc/rustc/src/platform-support.md | 18 +++++++++--------- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile index 1b98d54169338..410f0f92e60b6 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -56,9 +56,9 @@ ENV \ CFLAGS_x86_64_fortanix_unknown_sgx="-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \ CXX_x86_64_fortanix_unknown_sgx=clang++-11 \ CXXFLAGS_x86_64_fortanix_unknown_sgx="-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \ - AR_i686_unknown_freebsd=i686-unknown-freebsd12-ar \ - CC_i686_unknown_freebsd=i686-unknown-freebsd12-clang \ - CXX_i686_unknown_freebsd=i686-unknown-freebsd12-clang++ \ + AR_i686_unknown_freebsd=i686-unknown-freebsd13-ar \ + CC_i686_unknown_freebsd=i686-unknown-freebsd13-clang \ + CXX_i686_unknown_freebsd=i686-unknown-freebsd13-clang++ \ CC_aarch64_unknown_uefi=clang-11 \ CXX_aarch64_unknown_uefi=clang++-11 \ CC_i686_unknown_uefi=clang-11 \ diff --git a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile index b3c5f41bdd7d0..0be98a3a9293a 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile @@ -29,9 +29,9 @@ COPY scripts/cmake.sh /scripts/ RUN /scripts/cmake.sh ENV \ - AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-ar \ - CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-clang \ - CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-clang++ + AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-ar \ + CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-clang \ + CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-clang++ ENV HOSTS=x86_64-unknown-freebsd diff --git a/src/ci/docker/scripts/freebsd-toolchain.sh b/src/ci/docker/scripts/freebsd-toolchain.sh index 0d02636db9196..4826b81d56ce3 100755 --- a/src/ci/docker/scripts/freebsd-toolchain.sh +++ b/src/ci/docker/scripts/freebsd-toolchain.sh @@ -5,8 +5,8 @@ set -eux arch=$1 binutils_version=2.40 -freebsd_version=12.3 -triple=$arch-unknown-freebsd12 +freebsd_version=13.2 +triple=$arch-unknown-freebsd13 sysroot=/usr/local/$triple hide_output() { @@ -59,7 +59,7 @@ done # Originally downloaded from: # URL=https://download.freebsd.org/ftp/releases/${freebsd_arch}/${freebsd_version}-RELEASE/base.txz -URL=https://ci-mirrors.rust-lang.org/rustc/2022-05-06-freebsd-${freebsd_version}-${freebsd_arch}-base.txz +URL=https://ci-mirrors.rust-lang.org/rustc/2024-02-18-freebsd-${freebsd_version}-${freebsd_arch}-base.txz curl "$URL" | tar xJf - -C "$sysroot" --wildcards "${files_to_extract[@]}" # Clang can do cross-builds out of the box, if we give it the right @@ -68,7 +68,7 @@ curl "$URL" | tar xJf - -C "$sysroot" --wildcards "${files_to_extract[@]}" # there might be other problems.) # # The --target option is last because the cross-build of LLVM uses -# --target without an OS version ("-freebsd" vs. "-freebsd12"). This +# --target without an OS version ("-freebsd" vs. "-freebsd13"). This # makes Clang default to libstdc++ (which no longer exists), and also # controls other features, like GNU-style symbol table hashing and # anything predicated on the version number in the __FreeBSD__ diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 207eb5d6d4f76..1754de2adc58a 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -100,7 +100,7 @@ target | notes [`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20, glibc 2.29) [`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20, musl 1.2.3) `s390x-unknown-linux-gnu` | S390x Linux (kernel 3.2, glibc 2.17) -`x86_64-unknown-freebsd` | 64-bit FreeBSD +`x86_64-unknown-freebsd` | 64-bit FreeBSD (version 13.2) `x86_64-unknown-illumos` | illumos `x86_64-unknown-linux-musl` | 64-bit Linux with musl 1.2.3 [`x86_64-unknown-netbsd`](platform-support/netbsd.md) | NetBSD/amd64 @@ -166,7 +166,7 @@ target | std | notes `i586-unknown-linux-musl` | ✓ | 32-bit Linux w/o SSE, musl 1.2.3 [^x86_32-floats-x87] [`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android [^x86_32-floats-return-ABI] [`i686-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | 32-bit x86 MinGW (Windows 10+), LLVM ABI [^x86_32-floats-return-ABI] -`i686-unknown-freebsd` | ✓ | 32-bit FreeBSD [^x86_32-floats-return-ABI] +`i686-unknown-freebsd` | ✓ | 32-bit FreeBSD (version 13.2) [^x86_32-floats-return-ABI] `i686-unknown-linux-musl` | ✓ | 32-bit Linux with musl 1.2.3 [^x86_32-floats-return-ABI] [`i686-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 32-bit UEFI [`loongarch64-unknown-none`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64D ABI) @@ -257,7 +257,7 @@ target | std | host | notes [`aarch64-unknown-teeos`](platform-support/aarch64-unknown-teeos.md) | ? | | ARM64 TEEOS | [`aarch64-unknown-nto-qnx700`](platform-support/nto-qnx.md) | ? | | ARM64 QNX Neutrino 7.0 RTOS | [`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 7.1 RTOS | -`aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD +`aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD (version 13.2) [`aarch64-unknown-hermit`](platform-support/hermit.md) | ✓ | | ARM64 Hermit `aarch64-unknown-illumos` | ✓ | ✓ | ARM64 illumos `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI) @@ -276,14 +276,14 @@ target | std | host | notes `armv4t-unknown-linux-gnueabi` | ? | | Armv4T Linux [`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Bare Armv5TE `armv5te-unknown-linux-uclibceabi` | ? | | Armv5TE Linux with uClibc -`armv6-unknown-freebsd` | ✓ | ✓ | Armv6 FreeBSD +`armv6-unknown-freebsd` | ✓ | ✓ | Armv6 FreeBSD (version 13.2) [`armv6-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | Armv6 NetBSD w/hard-float [`armv6k-nintendo-3ds`](platform-support/armv6k-nintendo-3ds.md) | ? | | Armv6k Nintendo 3DS, Horizon (Requires devkitARM toolchain) [`armv7-rtems-eabihf`](platform-support/armv7-rtems-eabihf.md) | ? | | RTEMS OS for ARM BSPs [`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ✓ | | Armv7-A Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain) [`armv7-unknown-linux-uclibceabi`](platform-support/armv7-unknown-linux-uclibceabi.md) | ✓ | ✓ | Armv7-A Linux with uClibc, softfloat [`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | Armv7-A Linux with uClibc, hardfloat -`armv7-unknown-freebsd` | ✓ | ✓ | Armv7-A FreeBSD +`armv7-unknown-freebsd` | ✓ | ✓ | Armv7-A FreeBSD (version 13.2) [`armv7-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | Armv7-A NetBSD w/hard-float [`armv7-unknown-trusty`](platform-support/trusty.md) | ? | | [`armv7-wrs-vxworks-eabihf`](platform-support/vxworks.md) | ✓ | | Armv7-A for VxWorks @@ -342,9 +342,9 @@ target | std | host | notes [`powerpc-unknown-openbsd`](platform-support/powerpc-unknown-openbsd.md) | * | | [`powerpc-wrs-vxworks-spe`](platform-support/vxworks.md) | ✓ | | [`powerpc-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | -`powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2) -`powerpc64le-unknown-freebsd` | | | PPC64LE FreeBSD -`powerpc-unknown-freebsd` | | | PowerPC FreeBSD +`powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2, version 13.2) +`powerpc64le-unknown-freebsd` | | | PPC64LE FreeBSD (version 13.2) +`powerpc-unknown-freebsd` | | | PowerPC FreeBSD (version 13.2) `powerpc64-unknown-linux-musl` | ? | | 64-bit PowerPC Linux with musl 1.2.3 [`powerpc64-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | `powerpc64le-unknown-linux-musl` | ? | | 64-bit PowerPC Linux with musl 1.2.3, Little Endian @@ -360,7 +360,7 @@ target | std | host | notes [`riscv32imafc-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF [`riscv32-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | [`riscv64gc-unknown-hermit`](platform-support/hermit.md) | ✓ | | RISC-V Hermit -`riscv64gc-unknown-freebsd` | | | RISC-V FreeBSD +`riscv64gc-unknown-freebsd` | | | RISC-V FreeBSD (version 13.2) `riscv64gc-unknown-fuchsia` | | | RISC-V Fuchsia [`riscv64gc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | RISC-V NetBSD [`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64 From 65f05af5a79f8b9b82721fba5b138b88b71bb32f Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 27 Jul 2024 08:44:35 +0100 Subject: [PATCH 025/260] update Docker ? --- src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile index 0be98a3a9293a..fd0f5da8c495a 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:18.04 +FROM ubuntu:22.04 RUN apt-get update && apt-get install -y --no-install-recommends \ clang \ From 3b1a95642ba44e1630ba7d001d29630c3116bd77 Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Sat, 28 Sep 2024 16:38:46 +0100 Subject: [PATCH 026/260] Fix typos in arm-none-eabi.md These arrived in #125690, I think by mistake. --- src/doc/rustc/src/platform-support/arm-none-eabi.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/doc/rustc/src/platform-support/arm-none-eabi.md b/src/doc/rustc/src/platform-support/arm-none-eabi.md index de0ef322fa673..f135ff155a2ee 100644 --- a/src/doc/rustc/src/platform-support/arm-none-eabi.md +++ b/src/doc/rustc/src/platform-support/arm-none-eabi.md @@ -42,16 +42,15 @@ their own document. There are two 32-bit instruction set architectures (ISAs) defined by Arm: - The [*A32 ISA*][a32-isa], with fixed-width 32-bit instructions. Previously - known as the *Arm* ISA, this originated with the original Arm1 of 1985 and has + known as the *Arm* ISA, this originated with the original ARM1 of 1985 and has been updated by various revisions to the architecture specifications ever since. - The [*T32 ISA*][t32-isa], with a mix of 16-bit and 32-bit width instructions. Note that this term includes both the original 16-bit width *Thumb* ISA introduced with the Armv4T architecture in 1994, and the later 16/32-bit sized - *Thumb-2* ISA introduced with the Armv6T2 architecture in 2003. - -Again, these ISAs have been revised by subsequent revisions to the relevant Arm -architecture specifications. + *Thumb-2* ISA introduced with the Armv6T2 architecture in 2003. Again, these + ISAs have been revised by subsequent revisions to the relevant Arm + architecture specifications. There is also a 64-bit ISA with fixed-width 32-bit instructions called the *A64 ISA*, but targets which implement that instruction set generally start with From 487e8d8350409f4970b74bf06611bd7885a3212a Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Sat, 28 Sep 2024 18:19:16 +0100 Subject: [PATCH 027/260] Suggested -fpregs instead of +soft-float. Has the same effect, but turning off a feature matches the other flags better than turning on a feature (which actually turns off a feature). --- .../platform-support/thumbv7em-none-eabi.md | 15 ++++++--- .../thumbv8m.main-none-eabi.md | 31 ++++++++++++------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md index f25ef0383b185..7436a4a53b172 100644 --- a/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md @@ -35,9 +35,9 @@ to use these flags. | CPU | FPU | DSP | Target CPU | Target Features | | ---------- | --- | --- | ----------- | --------------- | | Any | No | Yes | None | None | -| Cortex-M4 | No | Yes | `cortex-m4` | `+soft-float` | +| Cortex-M4 | No | Yes | `cortex-m4` | `-fpregs` | | Cortex-M4F | SP | Yes | `cortex-m4` | None | -| Cortex-M7 | No | Yes | `cortex-m7` | `+soft-float` | +| Cortex-M7 | No | Yes | `cortex-m7` | `-fpregs` | | Cortex-M7F | SP | Yes | `cortex-m7` | `-fp64` | | Cortex-M7F | DP | Yes | `cortex-m7` | None | @@ -50,6 +50,13 @@ to use these flags. | Cortex-M7F | SP | Yes | `cortex-m7` | `-fp64` | | Cortex-M7F | DP | Yes | `cortex-m7` | None | +
    + +Never use the `-fpregs` *target-feature* with these `eabihf` targets +as it will cause compilation units to have different ABIs, which is unsound. + +
    + ### Arm Cortex-M4 and Arm Cortex-M4F The target CPU is `cortex-m4`. @@ -59,7 +66,7 @@ The target CPU is `cortex-m4`. * enabled by default with this *target* * Cortex-M4F has a single precision FPU * support is enabled by default with this *target-cpu* - * disable support using the `+soft-float` feature (`eabi` only) + * disable support using the `-fpregs` *target-feature* (`eabi` only) ### Arm Cortex-M7 and Arm Cortex-M7F @@ -71,4 +78,4 @@ The target CPU is `cortex-m7`. * Cortex-M7F have either a single-precision or double-precision FPU * double-precision support is enabled by default with this *target-cpu* * opt-out by using the `-f64` *target-feature* - * disable support entirely using the `+soft-float` feature (`eabi` only) + * disable support entirely using the `-fpregs` *target-feature* (`eabi` only) diff --git a/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md index 4e696f9c30461..7d4abfc8485c0 100644 --- a/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md @@ -39,22 +39,22 @@ to use these flags. | CPU | FPU | DSP | MVE | Target CPU | Target Features | | ----------- | --- | --- | --------- | ------------- | --------------------- | | Unspecified | No | No | No | None | None | -| Cortex-M33 | No | No | No | `cortex-m33` | `+soft-float,-dsp` | -| Cortex-M33 | No | Yes | No | `cortex-m33` | `+soft-float` | +| Cortex-M33 | No | No | No | `cortex-m33` | `-fpregs,-dsp` | +| Cortex-M33 | No | Yes | No | `cortex-m33` | `-fpregs` | | Cortex-M33 | SP | No | No | `cortex-m33` | `-dsp` | | Cortex-M33 | SP | Yes | No | `cortex-m33` | None | -| Cortex-M35P | No | No | No | `cortex-m35p` | `+soft-float,-dsp` | -| Cortex-M35P | No | Yes | No | `cortex-m35p` | `+soft-float` | +| Cortex-M35P | No | No | No | `cortex-m35p` | `-fpregs,-dsp` | +| Cortex-M35P | No | Yes | No | `cortex-m35p` | `-fpregs` | | Cortex-M35P | SP | No | No | `cortex-m35p` | `-dsp` | | Cortex-M35P | SP | Yes | No | `cortex-m35p` | None | -| Cortex-M55 | No | Yes | No | `cortex-m55` | `+soft-float,-mve` | +| Cortex-M55 | No | Yes | No | `cortex-m55` | `-fpregs,-mve` | | Cortex-M55 | DP | Yes | No | `cortex-m55` | `-mve` | -| Cortex-M55 | No | Yes | Int | `cortex-m55` | `+soft-float,-mve.fp` | +| Cortex-M55 | No | Yes | Int | `cortex-m55` | `-fpregs,-mve.fp,+mve`| | Cortex-M55 | DP | Yes | Int | `cortex-m55` | `-mve.fp` | | Cortex-M55 | DP | Yes | Int+Float | `cortex-m55` | None | -| Cortex-M85 | No | Yes | No | `cortex-m85` | `+soft-float,-mve` | +| Cortex-M85 | No | Yes | No | `cortex-m85` | `-fpregs,-mve` | | Cortex-M85 | DP | Yes | No | `cortex-m85` | `-mve` | -| Cortex-M85 | No | Yes | Int | `cortex-m85` | `+soft-float,-mve.fp` | +| Cortex-M85 | No | Yes | Int | `cortex-m85` | `-fpregs,-mve.fp,+mve`| | Cortex-M85 | DP | Yes | Int | `cortex-m85` | `-mve.fp` | | Cortex-M85 | DP | Yes | Int+Float | `cortex-m85` | None | @@ -74,6 +74,13 @@ to use these flags. | Cortex-M85 | DP | Yes | Int | `cortex-m85` | `-mve.fp` | | Cortex-M85 | DP | Yes | Int+Float | `cortex-m85` | None | +
    + +Never use the `-fpregs` *target-feature* with these `eabihf` targets +as it will cause compilation units to have different ABIs, which is unsound. + +
    + ### Arm Cortex-M33 The target CPU is `cortex-m33`. @@ -83,7 +90,7 @@ The target CPU is `cortex-m33`. * enabled by default with this *target-cpu* * Has an optional single precision FPU * support is enabled by default with this *target-cpu* - * disable support using the `+soft-float` feature (`eabi` only) + * disable support using the `-fpregs` *target-feature* (`eabi` only) ### Arm Cortex-M35P @@ -94,7 +101,7 @@ The target CPU is `cortex-m35p`. * enabled by default with this *target-cpu* * Has an optional single precision FPU * support is enabled by default with this *target-cpu* - * disable support using the `+soft-float` feature (`eabi` only) + * disable support using the `-fpregs` *target-feature* (`eabi` only) ### Arm Cortex-M55 @@ -106,7 +113,7 @@ The target CPU is `cortex-m55`. * Has an optional double-precision FPU that also supports half-precision FP16 values * support is enabled by default with this *target-cpu* - * disable support using the `+soft-float` feature (`eabi` only) + * disable support using the `-fpregs` *target-feature* (`eabi` only) * Has optional support for M-Profile Vector Extensions * Also known as *Helium Technology* * Available with only integer support, or both integer/float support @@ -125,7 +132,7 @@ The target CPU is `cortex-m85`. * Has an optional double-precision FPU that also supports half-precision FP16 values * support is enabled by default with this *target-cpu* - * disable support using the `+soft-float` feature (`eabi` only) + * disable support using the `-fpregs` *target-feature* (`eabi` only) * Has optional support for M-Profile Vector Extensions * Also known as *Helium Technology* * Available with only integer support, or both integer/float support From 1bec0226d9ec3cf12d1709daa6b23e9f16f08d10 Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Sat, 28 Sep 2024 18:20:12 +0100 Subject: [PATCH 028/260] Add warning to arm-none-eabi.md instead of a Note: --- src/doc/rustc/src/platform-support/arm-none-eabi.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/arm-none-eabi.md b/src/doc/rustc/src/platform-support/arm-none-eabi.md index f135ff155a2ee..9732df4be7f72 100644 --- a/src/doc/rustc/src/platform-support/arm-none-eabi.md +++ b/src/doc/rustc/src/platform-support/arm-none-eabi.md @@ -105,10 +105,14 @@ features you do not have available, leaving you with the optimized instruction scheduling and support for the features you do have. More details are available in the detailed target-specific documentation. -**Note:** Many target-features are currently unstable and subject to change, and +
    + +Many target-features are currently unstable and subject to change, and if you use them you should disassemble the compiler output and manually inspect it to ensure only appropriate instructions for your CPU have been generated. +
    + If you wish to use the *target-cpu* and *target-feature* options, you can add them to your `.cargo/config.toml` file alongside any other flags your project uses (likely linker related ones): From 55834a362c1e849bbab9cb0adc641a22be598d7e Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Thu, 26 Sep 2024 17:49:14 +0200 Subject: [PATCH 029/260] deal with differing syntax contexts for subexpressions in check_proc_macro --- clippy_utils/src/check_proc_macro.rs | 135 ++++++++++++++++----------- tests/ui/dbg_macro/dbg_macro.fixed | 2 +- tests/ui/dbg_macro/dbg_macro.rs | 2 +- 3 files changed, 83 insertions(+), 56 deletions(-) diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 9143d292f670f..9a18bff3c7afc 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -141,62 +141,89 @@ fn path_search_pat(path: &Path<'_>) -> (Pat, Pat) { /// Get the search patterns to use for the given expression fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) { - match e.kind { - ExprKind::ConstBlock(_) => (Pat::Str("const"), Pat::Str("}")), - // Parenthesis are trimmed from the text before the search patterns are matched. - // See: `span_matches_pat` - ExprKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")), - ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat(tcx, e).1), - ExprKind::Unary(UnOp::Not, e) => (Pat::Str("!"), expr_search_pat(tcx, e).1), - ExprKind::Unary(UnOp::Neg, e) => (Pat::Str("-"), expr_search_pat(tcx, e).1), - ExprKind::Lit(lit) => lit_search_pat(&lit.node), - ExprKind::Array(_) | ExprKind::Repeat(..) => (Pat::Str("["), Pat::Str("]")), - ExprKind::Call(e, []) | ExprKind::MethodCall(_, e, [], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")), - ExprKind::Call(first, [.., last]) - | ExprKind::MethodCall(_, first, [.., last], _) - | ExprKind::Binary(_, first, last) - | ExprKind::Tup([first, .., last]) - | ExprKind::Assign(first, last, _) - | ExprKind::AssignOp(_, first, last) => (expr_search_pat(tcx, first).0, expr_search_pat(tcx, last).1), - ExprKind::Tup([e]) | ExprKind::DropTemps(e) => expr_search_pat(tcx, e), - ExprKind::Cast(e, _) | ExprKind::Type(e, _) => (expr_search_pat(tcx, e).0, Pat::Str("")), - ExprKind::Let(let_expr) => (Pat::Str("let"), expr_search_pat(tcx, let_expr.init).1), - ExprKind::If(..) => (Pat::Str("if"), Pat::Str("}")), - ExprKind::Loop(_, Some(_), _, _) | ExprKind::Block(_, Some(_)) => (Pat::Str("'"), Pat::Str("}")), - ExprKind::Loop(_, None, LoopSource::Loop, _) => (Pat::Str("loop"), Pat::Str("}")), - ExprKind::Loop(_, None, LoopSource::While, _) => (Pat::Str("while"), Pat::Str("}")), - ExprKind::Loop(_, None, LoopSource::ForLoop, _) | ExprKind::Match(_, _, MatchSource::ForLoopDesugar) => { - (Pat::Str("for"), Pat::Str("}")) - }, - ExprKind::Match(_, _, MatchSource::Normal) => (Pat::Str("match"), Pat::Str("}")), - ExprKind::Match(e, _, MatchSource::TryDesugar(_)) => (expr_search_pat(tcx, e).0, Pat::Str("?")), - ExprKind::Match(e, _, MatchSource::AwaitDesugar) | ExprKind::Yield(e, YieldSource::Await { .. }) => { - (expr_search_pat(tcx, e).0, Pat::Str("await")) - }, - ExprKind::Closure(&Closure { body, .. }) => (Pat::Str(""), expr_search_pat(tcx, tcx.hir().body(body).value).1), - ExprKind::Block( - Block { - rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided), - .. + fn expr_search_pat_inner(tcx: TyCtxt<'_>, e: &Expr<'_>, outer_span: Span) -> (Pat, Pat) { + // The expression can have subexpressions in different contexts, in which case + // building up a search pattern from the macro expansion would lead to false positives; + // e.g. `return format!(..)` would be considered to be from a proc macro + // if we build up a pattern for the macro expansion and compare it to the invocation `format!()`. + // So instead we return an empty pattern such that `span_matches_pat` always returns true. + if !e.span.eq_ctxt(outer_span) { + return (Pat::Str(""), Pat::Str("")); + } + + match e.kind { + ExprKind::ConstBlock(_) => (Pat::Str("const"), Pat::Str("}")), + // Parenthesis are trimmed from the text before the search patterns are matched. + // See: `span_matches_pat` + ExprKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")), + ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat_inner(tcx, e, outer_span).1), + ExprKind::Unary(UnOp::Not, e) => (Pat::Str("!"), expr_search_pat_inner(tcx, e, outer_span).1), + ExprKind::Unary(UnOp::Neg, e) => (Pat::Str("-"), expr_search_pat_inner(tcx, e, outer_span).1), + ExprKind::Lit(lit) => lit_search_pat(&lit.node), + ExprKind::Array(_) | ExprKind::Repeat(..) => (Pat::Str("["), Pat::Str("]")), + ExprKind::Call(e, []) | ExprKind::MethodCall(_, e, [], _) => { + (expr_search_pat_inner(tcx, e, outer_span).0, Pat::Str("(")) }, - None, - ) => (Pat::Str("unsafe"), Pat::Str("}")), - ExprKind::Block(_, None) => (Pat::Str("{"), Pat::Str("}")), - ExprKind::Field(e, name) => (expr_search_pat(tcx, e).0, Pat::Sym(name.name)), - ExprKind::Index(e, _, _) => (expr_search_pat(tcx, e).0, Pat::Str("]")), - ExprKind::Path(ref path) => qpath_search_pat(path), - ExprKind::AddrOf(_, _, e) => (Pat::Str("&"), expr_search_pat(tcx, e).1), - ExprKind::Break(Destination { label: None, .. }, None) => (Pat::Str("break"), Pat::Str("break")), - ExprKind::Break(Destination { label: Some(name), .. }, None) => (Pat::Str("break"), Pat::Sym(name.ident.name)), - ExprKind::Break(_, Some(e)) => (Pat::Str("break"), expr_search_pat(tcx, e).1), - ExprKind::Continue(Destination { label: None, .. }) => (Pat::Str("continue"), Pat::Str("continue")), - ExprKind::Continue(Destination { label: Some(name), .. }) => (Pat::Str("continue"), Pat::Sym(name.ident.name)), - ExprKind::Ret(None) => (Pat::Str("return"), Pat::Str("return")), - ExprKind::Ret(Some(e)) => (Pat::Str("return"), expr_search_pat(tcx, e).1), - ExprKind::Struct(path, _, _) => (qpath_search_pat(path).0, Pat::Str("}")), - ExprKind::Yield(e, YieldSource::Yield) => (Pat::Str("yield"), expr_search_pat(tcx, e).1), - _ => (Pat::Str(""), Pat::Str("")), + ExprKind::Call(first, [.., last]) + | ExprKind::MethodCall(_, first, [.., last], _) + | ExprKind::Binary(_, first, last) + | ExprKind::Tup([first, .., last]) + | ExprKind::Assign(first, last, _) + | ExprKind::AssignOp(_, first, last) => ( + expr_search_pat_inner(tcx, first, outer_span).0, + expr_search_pat_inner(tcx, last, outer_span).1, + ), + ExprKind::Tup([e]) | ExprKind::DropTemps(e) => expr_search_pat_inner(tcx, e, outer_span), + ExprKind::Cast(e, _) | ExprKind::Type(e, _) => (expr_search_pat_inner(tcx, e, outer_span).0, Pat::Str("")), + ExprKind::Let(let_expr) => (Pat::Str("let"), expr_search_pat_inner(tcx, let_expr.init, outer_span).1), + ExprKind::If(..) => (Pat::Str("if"), Pat::Str("}")), + ExprKind::Loop(_, Some(_), _, _) | ExprKind::Block(_, Some(_)) => (Pat::Str("'"), Pat::Str("}")), + ExprKind::Loop(_, None, LoopSource::Loop, _) => (Pat::Str("loop"), Pat::Str("}")), + ExprKind::Loop(_, None, LoopSource::While, _) => (Pat::Str("while"), Pat::Str("}")), + ExprKind::Loop(_, None, LoopSource::ForLoop, _) | ExprKind::Match(_, _, MatchSource::ForLoopDesugar) => { + (Pat::Str("for"), Pat::Str("}")) + }, + ExprKind::Match(_, _, MatchSource::Normal) => (Pat::Str("match"), Pat::Str("}")), + ExprKind::Match(e, _, MatchSource::TryDesugar(_)) => { + (expr_search_pat_inner(tcx, e, outer_span).0, Pat::Str("?")) + }, + ExprKind::Match(e, _, MatchSource::AwaitDesugar) | ExprKind::Yield(e, YieldSource::Await { .. }) => { + (expr_search_pat_inner(tcx, e, outer_span).0, Pat::Str("await")) + }, + ExprKind::Closure(&Closure { body, .. }) => ( + Pat::Str(""), + expr_search_pat_inner(tcx, tcx.hir().body(body).value, outer_span).1, + ), + ExprKind::Block( + Block { + rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided), + .. + }, + None, + ) => (Pat::Str("unsafe"), Pat::Str("}")), + ExprKind::Block(_, None) => (Pat::Str("{"), Pat::Str("}")), + ExprKind::Field(e, name) => (expr_search_pat_inner(tcx, e, outer_span).0, Pat::Sym(name.name)), + ExprKind::Index(e, _, _) => (expr_search_pat_inner(tcx, e, outer_span).0, Pat::Str("]")), + ExprKind::Path(ref path) => qpath_search_pat(path), + ExprKind::AddrOf(_, _, e) => (Pat::Str("&"), expr_search_pat_inner(tcx, e, outer_span).1), + ExprKind::Break(Destination { label: None, .. }, None) => (Pat::Str("break"), Pat::Str("break")), + ExprKind::Break(Destination { label: Some(name), .. }, None) => { + (Pat::Str("break"), Pat::Sym(name.ident.name)) + }, + ExprKind::Break(_, Some(e)) => (Pat::Str("break"), expr_search_pat_inner(tcx, e, outer_span).1), + ExprKind::Continue(Destination { label: None, .. }) => (Pat::Str("continue"), Pat::Str("continue")), + ExprKind::Continue(Destination { label: Some(name), .. }) => { + (Pat::Str("continue"), Pat::Sym(name.ident.name)) + }, + ExprKind::Ret(None) => (Pat::Str("return"), Pat::Str("return")), + ExprKind::Ret(Some(e)) => (Pat::Str("return"), expr_search_pat_inner(tcx, e, outer_span).1), + ExprKind::Struct(path, _, _) => (qpath_search_pat(path).0, Pat::Str("}")), + ExprKind::Yield(e, YieldSource::Yield) => (Pat::Str("yield"), expr_search_pat_inner(tcx, e, outer_span).1), + _ => (Pat::Str(""), Pat::Str("")), + } } + + expr_search_pat_inner(tcx, e, e.span) } fn fn_header_search_pat(header: FnHeader) -> Pat { diff --git a/tests/ui/dbg_macro/dbg_macro.fixed b/tests/ui/dbg_macro/dbg_macro.fixed index e352519142332..bda9221a5e1e9 100644 --- a/tests/ui/dbg_macro/dbg_macro.fixed +++ b/tests/ui/dbg_macro/dbg_macro.fixed @@ -1,5 +1,5 @@ #![warn(clippy::dbg_macro)] -#![allow(clippy::unnecessary_operation, clippy::no_effect)] +#![allow(clippy::unnecessary_operation, clippy::no_effect, clippy::unit_arg)] fn foo(n: u32) -> u32 { if let Some(n) = n.checked_sub(4) { n } else { n } diff --git a/tests/ui/dbg_macro/dbg_macro.rs b/tests/ui/dbg_macro/dbg_macro.rs index 80606c2db054a..8244254026be7 100644 --- a/tests/ui/dbg_macro/dbg_macro.rs +++ b/tests/ui/dbg_macro/dbg_macro.rs @@ -1,5 +1,5 @@ #![warn(clippy::dbg_macro)] -#![allow(clippy::unnecessary_operation, clippy::no_effect)] +#![allow(clippy::unnecessary_operation, clippy::no_effect, clippy::unit_arg)] fn foo(n: u32) -> u32 { if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n } From d1dec199eea9678b0b3d728100ff356b0cd6f216 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Mon, 2 Sep 2024 02:20:35 -0400 Subject: [PATCH 030/260] Add manual_ignore_cast_cmp lint --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/manual_ignore_case_cmp.rs | 127 +++++ tests/ui/manual_ignore_case_cmp.fixed | 107 ++++ tests/ui/manual_ignore_case_cmp.rs | 107 ++++ tests/ui/manual_ignore_case_cmp.stderr | 546 +++++++++++++++++++++ 7 files changed, 891 insertions(+) create mode 100644 clippy_lints/src/manual_ignore_case_cmp.rs create mode 100644 tests/ui/manual_ignore_case_cmp.fixed create mode 100644 tests/ui/manual_ignore_case_cmp.rs create mode 100644 tests/ui/manual_ignore_case_cmp.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d253d52531e6..98be47ec5a199 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5621,6 +5621,7 @@ Released 2018-09-13 [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map [`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten [`manual_hash_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one +[`manual_ignore_case_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ignore_case_cmp [`manual_inspect`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_inspect [`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed [`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 9cec672beb004..0b37dffd7323e 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -306,6 +306,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::manual_float_methods::MANUAL_IS_FINITE_INFO, crate::manual_float_methods::MANUAL_IS_INFINITE_INFO, crate::manual_hash_one::MANUAL_HASH_ONE_INFO, + crate::manual_ignore_case_cmp::MANUAL_IGNORE_CASE_CMP_INFO, crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO, crate::manual_is_power_of_two::MANUAL_IS_POWER_OF_TWO_INFO, crate::manual_let_else::MANUAL_LET_ELSE_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1d41f568f3785..56722e7f537b1 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -206,6 +206,7 @@ mod manual_clamp; mod manual_div_ceil; mod manual_float_methods; mod manual_hash_one; +mod manual_ignore_case_cmp; mod manual_is_ascii_check; mod manual_is_power_of_two; mod manual_let_else; @@ -944,5 +945,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(manual_is_power_of_two::ManualIsPowerOfTwo)); store.register_late_pass(|_| Box::new(non_zero_suggestions::NonZeroSuggestions)); store.register_late_pass(move |_| Box::new(unused_trait_names::UnusedTraitNames::new(conf))); + store.register_late_pass(|_| Box::new(manual_ignore_case_cmp::ManualIgnoreCaseCmp)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/manual_ignore_case_cmp.rs b/clippy_lints/src/manual_ignore_case_cmp.rs new file mode 100644 index 0000000000000..dabfac3f6137b --- /dev/null +++ b/clippy_lints/src/manual_ignore_case_cmp.rs @@ -0,0 +1,127 @@ +use crate::manual_ignore_case_cmp::MatchType::{Literal, ToAscii}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::{get_type_diagnostic_name, is_type_diagnostic_item, is_type_lang_item}; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::ExprKind::{Binary, Lit, MethodCall}; +use rustc_hir::{BinOpKind, Expr, LangItem}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_middle::ty::{Ty, UintTy}; +use rustc_session::declare_lint_pass; +use rustc_span::{Span, sym}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for manual case-insensitive ASCII comparison. + /// + /// ### Why is this bad? + /// The `eq_ignore_ascii_case` method is faster because it does not allocate + /// memory for the new strings, and it is more readable. + /// + /// ### Example + /// ```no_run + /// fn compare(a: &str, b: &str) -> bool { + /// a.to_ascii_lowercase() == b.to_ascii_lowercase() || a.to_ascii_lowercase() == "abc" + /// } + /// ``` + /// Use instead: + /// ```no_run + /// fn compare(a: &str, b: &str) -> bool { + /// a.eq_ignore_ascii_case(b) || a.eq_ignore_ascii_case("abc") + /// } + /// ``` + #[clippy::version = "1.82.0"] + pub MANUAL_IGNORE_CASE_CMP, + perf, + "manual case-insensitive ASCII comparison" +} + +declare_lint_pass!(ManualIgnoreCaseCmp => [MANUAL_IGNORE_CASE_CMP]); + +enum MatchType<'a, 'b> { + ToAscii(bool, Ty<'a>), + Literal(&'b LitKind), +} + +fn get_ascii_type<'a, 'b>(cx: &LateContext<'a>, kind: rustc_hir::ExprKind<'b>) -> Option<(Span, MatchType<'a, 'b>)> { + if let MethodCall(path, expr, _, _) = kind { + let is_lower = match path.ident.name.as_str() { + "to_ascii_lowercase" => true, + "to_ascii_uppercase" => false, + _ => return None, + }; + let ty_raw = cx.typeck_results().expr_ty(expr); + let ty = ty_raw.peel_refs(); + if needs_ref_to_cmp(cx, ty) + || ty.is_str() + || ty.is_slice() + || matches!(get_type_diagnostic_name(cx, ty), Some(sym::OsStr | sym::OsString)) + { + return Some((expr.span, ToAscii(is_lower, ty_raw))); + } + } else if let Lit(expr) = kind { + return Some((expr.span, Literal(&expr.node))); + } + None +} + +/// Returns true if the type needs to be dereferenced to be compared +fn needs_ref_to_cmp(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { + ty.is_char() + || *ty.kind() == ty::Uint(UintTy::U8) + || is_type_diagnostic_item(cx, ty, sym::Vec) + || is_type_lang_item(cx, ty, LangItem::String) +} + +impl LateLintPass<'_> for ManualIgnoreCaseCmp { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { + // check if expression represents a comparison of two strings + // using .to_ascii_lowercase() or .to_ascii_uppercase() methods, + // or one of the sides is a literal + // Offer to replace it with .eq_ignore_ascii_case() method + if let Binary(op, left, right) = &expr.kind + && (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne) + && let Some((left_span, left_val)) = get_ascii_type(cx, left.kind) + && let Some((right_span, right_val)) = get_ascii_type(cx, right.kind) + && match (&left_val, &right_val) { + (ToAscii(l_lower, ..), ToAscii(r_lower, ..)) if l_lower == r_lower => true, + (ToAscii(..), Literal(..)) | (Literal(..), ToAscii(..)) => true, + _ => false, + } + { + let deref = match right_val { + ToAscii(_, ty) if needs_ref_to_cmp(cx, ty) => "&", + ToAscii(..) => "", + Literal(ty) => { + if let LitKind::Char(_) | LitKind::Byte(_) = ty { + "&" + } else { + "" + } + }, + }; + let neg = if op.node == BinOpKind::Ne { "!" } else { "" }; + span_lint_and_then( + cx, + MANUAL_IGNORE_CASE_CMP, + expr.span, + "manual case-insensitive ASCII comparison", + |diag| { + let mut app = Applicability::MachineApplicable; + diag.span_suggestion_verbose( + expr.span, + "consider using `.eq_ignore_ascii_case()` instead", + format!( + "{neg}{}.eq_ignore_ascii_case({deref}{})", + snippet_with_applicability(cx, left_span, "_", &mut app), + snippet_with_applicability(cx, right_span, "_", &mut app) + ), + app, + ); + }, + ); + } + } +} diff --git a/tests/ui/manual_ignore_case_cmp.fixed b/tests/ui/manual_ignore_case_cmp.fixed new file mode 100644 index 0000000000000..53a124f59c8dc --- /dev/null +++ b/tests/ui/manual_ignore_case_cmp.fixed @@ -0,0 +1,107 @@ +#![allow(clippy::all)] +#![deny(clippy::manual_ignore_case_cmp)] + +use std::ffi::{OsStr, OsString}; + +fn main() {} + +fn variants(a: &str, b: &str) { + if a.eq_ignore_ascii_case(b) { + return; + } + if a.eq_ignore_ascii_case(b) { + return; + } + let r = a.eq_ignore_ascii_case(b); + let r = r || a.eq_ignore_ascii_case(b); + r && a.eq_ignore_ascii_case(&b.to_uppercase()); + // != + if !a.eq_ignore_ascii_case(b) { + return; + } + if !a.eq_ignore_ascii_case(b) { + return; + } + let r = !a.eq_ignore_ascii_case(b); + let r = r || !a.eq_ignore_ascii_case(b); + r && !a.eq_ignore_ascii_case(&b.to_uppercase()); +} + +fn unsupported(a: char, b: char) { + // TODO:: these are rare, and might not be worth supporting + a.to_ascii_lowercase() == char::to_ascii_lowercase(&b); + char::to_ascii_lowercase(&a) == b.to_ascii_lowercase(); + char::to_ascii_lowercase(&a) == char::to_ascii_lowercase(&b); +} + +fn char(a: char, b: char) { + a.eq_ignore_ascii_case(&b); + a.to_ascii_lowercase() == *&b.to_ascii_lowercase(); + *&a.to_ascii_lowercase() == b.to_ascii_lowercase(); + a.eq_ignore_ascii_case(&'a'); + 'a'.eq_ignore_ascii_case(&b); +} +fn u8(a: u8, b: u8) { + a.eq_ignore_ascii_case(&b); + a.eq_ignore_ascii_case(&b'a'); + b'a'.eq_ignore_ascii_case(&b); +} +fn ref_str(a: &str, b: &str) { + a.eq_ignore_ascii_case(b); + a.to_uppercase().eq_ignore_ascii_case(b); + a.eq_ignore_ascii_case("a"); + "a".eq_ignore_ascii_case(b); +} +fn ref_ref_str(a: &&str, b: &&str) { + a.eq_ignore_ascii_case(b); + a.to_uppercase().eq_ignore_ascii_case(b); + a.eq_ignore_ascii_case("a"); + "a".eq_ignore_ascii_case(b); +} +fn string(a: String, b: String) { + a.eq_ignore_ascii_case(&b); + a.eq_ignore_ascii_case("a"); + "a".eq_ignore_ascii_case(&b); + &a.to_ascii_lowercase() == &b.to_ascii_lowercase(); + &&a.to_ascii_lowercase() == &&b.to_ascii_lowercase(); + a.eq_ignore_ascii_case("a"); + "a".eq_ignore_ascii_case(&b); +} +fn ref_string(a: String, b: &String) { + a.eq_ignore_ascii_case(b); + a.eq_ignore_ascii_case("a"); + "a".eq_ignore_ascii_case(b); + + b.eq_ignore_ascii_case(&a); + b.eq_ignore_ascii_case("a"); + "a".eq_ignore_ascii_case(&a); +} +fn string_ref_str(a: String, b: &str) { + a.eq_ignore_ascii_case(b); + a.eq_ignore_ascii_case("a"); + "a".eq_ignore_ascii_case(b); + + b.eq_ignore_ascii_case(&a); + b.eq_ignore_ascii_case("a"); + "a".eq_ignore_ascii_case(&a); +} +fn ref_u8slice(a: &[u8], b: &[u8]) { + a.eq_ignore_ascii_case(b); +} +fn u8vec(a: Vec, b: Vec) { + a.eq_ignore_ascii_case(&b); +} +fn ref_u8vec(a: Vec, b: &Vec) { + a.eq_ignore_ascii_case(b); + b.eq_ignore_ascii_case(&a); +} +fn ref_osstr(a: &OsStr, b: &OsStr) { + a.eq_ignore_ascii_case(b); +} +fn osstring(a: OsString, b: OsString) { + a.eq_ignore_ascii_case(b); +} +fn ref_osstring(a: OsString, b: &OsString) { + a.eq_ignore_ascii_case(b); + b.eq_ignore_ascii_case(a); +} diff --git a/tests/ui/manual_ignore_case_cmp.rs b/tests/ui/manual_ignore_case_cmp.rs new file mode 100644 index 0000000000000..2a4d84b30acec --- /dev/null +++ b/tests/ui/manual_ignore_case_cmp.rs @@ -0,0 +1,107 @@ +#![allow(clippy::all)] +#![deny(clippy::manual_ignore_case_cmp)] + +use std::ffi::{OsStr, OsString}; + +fn main() {} + +fn variants(a: &str, b: &str) { + if a.to_ascii_lowercase() == b.to_ascii_lowercase() { + return; + } + if a.to_ascii_uppercase() == b.to_ascii_uppercase() { + return; + } + let r = a.to_ascii_lowercase() == b.to_ascii_lowercase(); + let r = r || a.to_ascii_uppercase() == b.to_ascii_uppercase(); + r && a.to_ascii_lowercase() == b.to_uppercase().to_ascii_lowercase(); + // != + if a.to_ascii_lowercase() != b.to_ascii_lowercase() { + return; + } + if a.to_ascii_uppercase() != b.to_ascii_uppercase() { + return; + } + let r = a.to_ascii_lowercase() != b.to_ascii_lowercase(); + let r = r || a.to_ascii_uppercase() != b.to_ascii_uppercase(); + r && a.to_ascii_lowercase() != b.to_uppercase().to_ascii_lowercase(); +} + +fn unsupported(a: char, b: char) { + // TODO:: these are rare, and might not be worth supporting + a.to_ascii_lowercase() == char::to_ascii_lowercase(&b); + char::to_ascii_lowercase(&a) == b.to_ascii_lowercase(); + char::to_ascii_lowercase(&a) == char::to_ascii_lowercase(&b); +} + +fn char(a: char, b: char) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); + a.to_ascii_lowercase() == *&b.to_ascii_lowercase(); + *&a.to_ascii_lowercase() == b.to_ascii_lowercase(); + a.to_ascii_lowercase() == 'a'; + 'a' == b.to_ascii_lowercase(); +} +fn u8(a: u8, b: u8) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); + a.to_ascii_lowercase() == b'a'; + b'a' == b.to_ascii_lowercase(); +} +fn ref_str(a: &str, b: &str) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); + a.to_uppercase().to_ascii_lowercase() == b.to_ascii_lowercase(); + a.to_ascii_lowercase() == "a"; + "a" == b.to_ascii_lowercase(); +} +fn ref_ref_str(a: &&str, b: &&str) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); + a.to_uppercase().to_ascii_lowercase() == b.to_ascii_lowercase(); + a.to_ascii_lowercase() == "a"; + "a" == b.to_ascii_lowercase(); +} +fn string(a: String, b: String) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); + a.to_ascii_lowercase() == "a"; + "a" == b.to_ascii_lowercase(); + &a.to_ascii_lowercase() == &b.to_ascii_lowercase(); + &&a.to_ascii_lowercase() == &&b.to_ascii_lowercase(); + a.to_ascii_lowercase() == "a"; + "a" == b.to_ascii_lowercase(); +} +fn ref_string(a: String, b: &String) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); + a.to_ascii_lowercase() == "a"; + "a" == b.to_ascii_lowercase(); + + b.to_ascii_lowercase() == a.to_ascii_lowercase(); + b.to_ascii_lowercase() == "a"; + "a" == a.to_ascii_lowercase(); +} +fn string_ref_str(a: String, b: &str) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); + a.to_ascii_lowercase() == "a"; + "a" == b.to_ascii_lowercase(); + + b.to_ascii_lowercase() == a.to_ascii_lowercase(); + b.to_ascii_lowercase() == "a"; + "a" == a.to_ascii_lowercase(); +} +fn ref_u8slice(a: &[u8], b: &[u8]) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); +} +fn u8vec(a: Vec, b: Vec) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); +} +fn ref_u8vec(a: Vec, b: &Vec) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); + b.to_ascii_lowercase() == a.to_ascii_lowercase(); +} +fn ref_osstr(a: &OsStr, b: &OsStr) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); +} +fn osstring(a: OsString, b: OsString) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); +} +fn ref_osstring(a: OsString, b: &OsString) { + a.to_ascii_lowercase() == b.to_ascii_lowercase(); + b.to_ascii_lowercase() == a.to_ascii_lowercase(); +} diff --git a/tests/ui/manual_ignore_case_cmp.stderr b/tests/ui/manual_ignore_case_cmp.stderr new file mode 100644 index 0000000000000..11e8b8aebb541 --- /dev/null +++ b/tests/ui/manual_ignore_case_cmp.stderr @@ -0,0 +1,546 @@ +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:9:8 + | +LL | if a.to_ascii_lowercase() == b.to_ascii_lowercase() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> tests/ui/manual_ignore_case_cmp.rs:2:9 + | +LL | #![deny(clippy::manual_ignore_case_cmp)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | if a.eq_ignore_ascii_case(b) { + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:12:8 + | +LL | if a.to_ascii_uppercase() == b.to_ascii_uppercase() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | if a.eq_ignore_ascii_case(b) { + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:15:13 + | +LL | let r = a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | let r = a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:16:18 + | +LL | let r = r || a.to_ascii_uppercase() == b.to_ascii_uppercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | let r = r || a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:17:10 + | +LL | r && a.to_ascii_lowercase() == b.to_uppercase().to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | r && a.eq_ignore_ascii_case(&b.to_uppercase()); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:19:8 + | +LL | if a.to_ascii_lowercase() != b.to_ascii_lowercase() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | if !a.eq_ignore_ascii_case(b) { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:22:8 + | +LL | if a.to_ascii_uppercase() != b.to_ascii_uppercase() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | if !a.eq_ignore_ascii_case(b) { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:25:13 + | +LL | let r = a.to_ascii_lowercase() != b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | let r = !a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:26:18 + | +LL | let r = r || a.to_ascii_uppercase() != b.to_ascii_uppercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | let r = r || !a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:27:10 + | +LL | r && a.to_ascii_lowercase() != b.to_uppercase().to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | r && !a.eq_ignore_ascii_case(&b.to_uppercase()); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:38:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(&b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:41:5 + | +LL | a.to_ascii_lowercase() == 'a'; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(&'a'); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:42:5 + | +LL | 'a' == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | 'a'.eq_ignore_ascii_case(&b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:45:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(&b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:46:5 + | +LL | a.to_ascii_lowercase() == b'a'; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(&b'a'); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:47:5 + | +LL | b'a' == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | b'a'.eq_ignore_ascii_case(&b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:50:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:51:5 + | +LL | a.to_uppercase().to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.to_uppercase().eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:52:5 + | +LL | a.to_ascii_lowercase() == "a"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case("a"); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:53:5 + | +LL | "a" == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | "a".eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:56:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:57:5 + | +LL | a.to_uppercase().to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.to_uppercase().eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:58:5 + | +LL | a.to_ascii_lowercase() == "a"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case("a"); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:59:5 + | +LL | "a" == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | "a".eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:62:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(&b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:63:5 + | +LL | a.to_ascii_lowercase() == "a"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case("a"); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:64:5 + | +LL | "a" == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | "a".eq_ignore_ascii_case(&b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:67:5 + | +LL | a.to_ascii_lowercase() == "a"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case("a"); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:68:5 + | +LL | "a" == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | "a".eq_ignore_ascii_case(&b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:71:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:72:5 + | +LL | a.to_ascii_lowercase() == "a"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case("a"); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:73:5 + | +LL | "a" == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | "a".eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:75:5 + | +LL | b.to_ascii_lowercase() == a.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | b.eq_ignore_ascii_case(&a); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:76:5 + | +LL | b.to_ascii_lowercase() == "a"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | b.eq_ignore_ascii_case("a"); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:77:5 + | +LL | "a" == a.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | "a".eq_ignore_ascii_case(&a); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:80:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:81:5 + | +LL | a.to_ascii_lowercase() == "a"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case("a"); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:82:5 + | +LL | "a" == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | "a".eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:84:5 + | +LL | b.to_ascii_lowercase() == a.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | b.eq_ignore_ascii_case(&a); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:85:5 + | +LL | b.to_ascii_lowercase() == "a"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | b.eq_ignore_ascii_case("a"); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:86:5 + | +LL | "a" == a.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | "a".eq_ignore_ascii_case(&a); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:89:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:92:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(&b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:95:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:96:5 + | +LL | b.to_ascii_lowercase() == a.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | b.eq_ignore_ascii_case(&a); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:99:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:102:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:105:5 + | +LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | a.eq_ignore_ascii_case(b); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:106:5 + | +LL | b.to_ascii_lowercase() == a.to_ascii_lowercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL | b.eq_ignore_ascii_case(a); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 49 previous errors + From 13e2633f193838eadcddd5bf5842b9ce0a1f17dd Mon Sep 17 00:00:00 2001 From: blyxyas Date: Tue, 1 Oct 2024 19:39:18 +0200 Subject: [PATCH 031/260] Also sanitize configuration --- clippy_config/src/conf.rs | 24 ++++++++++++++++++++++++ clippy_config/src/lib.rs | 2 +- clippy_lints/src/lib.rs | 26 +------------------------- tests/compile-test.rs | 6 +----- 4 files changed, 27 insertions(+), 31 deletions(-) diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 757620341ccc1..df13be8009880 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -97,6 +97,30 @@ impl ConfError { } } +// Remove code tags and code behind '# 's, as they are not needed for the lint docs and --explain +pub fn sanitize_explanation(raw_docs: &str) -> String { + // Remove tags and hidden code: + let mut explanation = String::with_capacity(128); + let mut in_code = false; + for line in raw_docs.lines().map(str::trim) { + if let Some(lang) = line.strip_prefix("```") { + let tag = lang.split_once(',').map_or(lang, |(left, _)| left); + if !in_code && matches!(tag, "" | "rust" | "ignore" | "should_panic" | "no_run" | "compile_fail") { + explanation += "```rust\n"; + } else { + explanation += line; + explanation.push('\n'); + } + in_code = !in_code; + } else if !(in_code && line.starts_with("# ")) { + explanation += line; + explanation.push('\n'); + } + } + + explanation +} + macro_rules! wrap_option { () => { None diff --git a/clippy_config/src/lib.rs b/clippy_config/src/lib.rs index c63d98a0a13f9..42651521f8d7a 100644 --- a/clippy_config/src/lib.rs +++ b/clippy_config/src/lib.rs @@ -26,5 +26,5 @@ mod metadata; pub mod msrvs; pub mod types; -pub use conf::{Conf, get_configuration_metadata, lookup_conf_file}; +pub use conf::{Conf, get_configuration_metadata, lookup_conf_file, sanitize_explanation}; pub use metadata::ClippyConfiguration; diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 0bfbb92dfda55..71e7b56408e2f 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -396,7 +396,7 @@ mod zero_sized_map_values; mod zombie_processes; // end lints modules, do not remove this comment, it’s used in `update_lints` -use clippy_config::{Conf, get_configuration_metadata}; +use clippy_config::{Conf, get_configuration_metadata, sanitize_explanation}; use clippy_utils::macros::FormatArgsStorage; use rustc_data_structures::fx::FxHashSet; use rustc_lint::{Lint, LintId}; @@ -522,30 +522,6 @@ impl LintInfo { } } -// Remove code tags and code behind '# 's, as they are not needed for the lint docs and --explain -pub fn sanitize_explanation(raw_docs: &str) -> String { - // Remove tags and hidden code: - let mut explanation = String::with_capacity(128); - let mut in_code = false; - for line in raw_docs.lines().map(|line| line.trim()) { - if let Some(lang) = line.strip_prefix("```") { - let tag = lang.split_once(',').map_or(lang, |(left, _)| left); - if !in_code && matches!(tag, "" | "rust" | "ignore" | "should_panic" | "no_run" | "compile_fail") { - explanation += "```rust\n"; - } else { - explanation += line; - explanation.push('\n'); - } - in_code = !in_code; - } else if !(in_code && line.starts_with("# ")) { - explanation += line; - explanation.push('\n'); - } - } - - explanation -} - pub fn explain(name: &str) -> i32 { let target = format!("clippy::{}", name.to_ascii_uppercase()); diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 23dd41235bdbd..8734bd4136492 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -5,9 +5,9 @@ use cargo_metadata::Message; use cargo_metadata::diagnostic::{Applicability, Diagnostic}; use clippy_config::ClippyConfiguration; +use clippy_lints::LintInfo; use clippy_lints::declared_lints::LINTS; use clippy_lints::deprecated_lints::{DEPRECATED, DEPRECATED_VERSION, RENAMED}; -use clippy_lints::{LintInfo, sanitize_explanation}; use serde::{Deserialize, Serialize}; use test_utils::IS_RUSTC_TEST_SUITE; use ui_test::custom_flags::Flag; @@ -444,10 +444,6 @@ impl DiagnosticCollector { iter::zip(DEPRECATED, DEPRECATED_VERSION) .map(|((lint, reason), version)| LintMetadata::new_deprecated(lint, reason, version)), ) - .map(|mut metadata| { - metadata.docs = sanitize_explanation(&metadata.docs); - metadata - }) .collect(); metadata.sort_unstable_by(|a, b| a.id.cmp(&b.id)); From 3ac3c3495173d2b93c585e0df37667f7633b9ab5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 29 Sep 2024 22:23:44 -0400 Subject: [PATCH 032/260] Remove crashes and fix tests --- tests/ui/crashes/ice-12284.rs | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 tests/ui/crashes/ice-12284.rs diff --git a/tests/ui/crashes/ice-12284.rs b/tests/ui/crashes/ice-12284.rs deleted file mode 100644 index 8d1dbface8eba..0000000000000 --- a/tests/ui/crashes/ice-12284.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![allow(incomplete_features)] -#![feature(unnamed_fields)] - -#[repr(C)] -struct Foo { - _: struct { - }, -} - -fn main() {} From ce22fd34d9c35ad08da74d82bea4227f8dba77f7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 2 Oct 2024 21:52:44 -0400 Subject: [PATCH 033/260] Remove redundant in_trait from hir::TyKind::OpaqueDef --- clippy_lints/src/extra_unused_type_parameters.rs | 2 +- clippy_lints/src/lifetimes.rs | 2 +- clippy_lints/src/manual_async_fn.rs | 2 +- clippy_utils/src/hir_utils.rs | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs index bf9388b4a70fd..a7fb9535e7904 100644 --- a/clippy_lints/src/extra_unused_type_parameters.rs +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -199,7 +199,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> { fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) { if let Some((def_id, _)) = t.peel_refs().as_generic_param() { self.ty_params.remove(&def_id); - } else if let TyKind::OpaqueDef(id, _, _) = t.kind { + } else if let TyKind::OpaqueDef(id, _) = t.kind { // Explicitly walk OpaqueDef. Normally `walk_ty` would do the job, but it calls // `visit_nested_item`, which checks that `Self::NestedFilter::INTER` is set. We're // using `OnlyBodies`, so the check ends up failing and the type isn't fully walked. diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 755afe959b37a..d3cc5ea628c72 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -523,7 +523,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { fn visit_ty(&mut self, ty: &'tcx Ty<'_>) { match ty.kind { - TyKind::OpaqueDef(item, bounds, _) => { + TyKind::OpaqueDef(item, bounds) => { let map = self.cx.tcx.hir(); let item = map.item(item); let len = self.lts.len(); diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index fc3bba9e51232..7097c85156c34 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -105,7 +105,7 @@ fn future_trait_ref<'tcx>( cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>, ) -> Option<(&'tcx TraitRef<'tcx>, Vec)> { - if let TyKind::OpaqueDef(item_id, bounds, false) = ty.kind + if let TyKind::OpaqueDef(item_id, bounds) = ty.kind && let item = cx.tcx.hir().item(item_id) && let ItemKind::OpaqueTy(opaque) = &item.kind && let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| { diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 76900379ac787..b2d75125ccdb1 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1115,9 +1115,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } }, TyKind::Path(ref qpath) => self.hash_qpath(qpath), - TyKind::OpaqueDef(_, arg_list, in_trait) => { + TyKind::OpaqueDef(_, arg_list) => { self.hash_generic_args(arg_list); - in_trait.hash(&mut self.s); }, TyKind::TraitObject(_, lifetime, _) => { self.hash_lifetime(lifetime); From cbd64a4868a84e980101be7779b7b17156dff383 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 2 Oct 2024 22:04:18 -0400 Subject: [PATCH 034/260] Use named fields for OpaqueTyOrigin --- clippy_lints/src/len_zero.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 8bc2a56af9938..0cbcdbeb90ae1 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -313,7 +313,7 @@ fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<& kind: ItemKind::OpaqueTy(opaque), .. } = item - && let OpaqueTyOrigin::AsyncFn(_) = opaque.origin + && let OpaqueTyOrigin::AsyncFn { .. } = opaque.origin && let [GenericBound::Trait(trait_ref, _)] = &opaque.bounds && let Some(segment) = trait_ref.trait_ref.path.segments.last() && let Some(generic_args) = segment.args From 2080634d336ac73a00aa256993ee035da7226aca Mon Sep 17 00:00:00 2001 From: coekjan Date: Wed, 2 Oct 2024 23:51:52 +0800 Subject: [PATCH 035/260] Fix lint `manual_slice_size_calculation` when the slice is ref more than once --- .../src/manual_slice_size_calculation.rs | 14 +++++----- tests/ui/manual_slice_size_calculation.fixed | 4 +++ tests/ui/manual_slice_size_calculation.rs | 4 +++ tests/ui/manual_slice_size_calculation.stderr | 26 ++++++++++++++----- 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/manual_slice_size_calculation.rs b/clippy_lints/src/manual_slice_size_calculation.rs index b24a0f4695a6c..a984a7f952052 100644 --- a/clippy_lints/src/manual_slice_size_calculation.rs +++ b/clippy_lints/src/manual_slice_size_calculation.rs @@ -45,10 +45,11 @@ impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation { && !expr.span.from_expansion() // Does not apply inside const because size_of_val is not cost in stable. && !is_in_const_context(cx) - && let Some(receiver) = simplify(cx, left, right) + && let Some((receiver, refs_count)) = simplify(cx, left, right) { let ctxt = expr.span.ctxt(); let mut app = Applicability::MachineApplicable; + let deref = "*".repeat(refs_count - 1); let val_name = snippet_with_context(cx, receiver.span, ctxt, "slice", &mut app).0; let Some(sugg) = std_or_core(cx) else { return }; @@ -58,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation { expr.span, "manual slice size calculation", "try", - format!("{sugg}::mem::size_of_val({val_name})"), + format!("{sugg}::mem::size_of_val({deref}{val_name})"), app, ); } @@ -69,7 +70,7 @@ fn simplify<'tcx>( cx: &LateContext<'tcx>, expr1: &'tcx Expr<'tcx>, expr2: &'tcx Expr<'tcx>, -) -> Option<&'tcx Expr<'tcx>> { +) -> Option<(&'tcx Expr<'tcx>, usize)> { let expr1 = expr_or_init(cx, expr1); let expr2 = expr_or_init(cx, expr2); @@ -80,13 +81,14 @@ fn simplify_half<'tcx>( cx: &LateContext<'tcx>, expr1: &'tcx Expr<'tcx>, expr2: &'tcx Expr<'tcx>, -) -> Option<&'tcx Expr<'tcx>> { +) -> Option<(&'tcx Expr<'tcx>, usize)> { if !expr1.span.from_expansion() // expr1 is `[T1].len()`? && let ExprKind::MethodCall(method_path, receiver, _, _) = expr1.kind && method_path.ident.name == sym::len && let receiver_ty = cx.typeck_results().expr_ty(receiver) - && let ty::Slice(ty1) = receiver_ty.peel_refs().kind() + && let (receiver_ty, refs_count) = clippy_utils::ty::walk_ptrs_ty_depth(receiver_ty) + && let ty::Slice(ty1) = receiver_ty.kind() // expr2 is `size_of::()`? && let ExprKind::Call(func, _) = expr2.kind && let ExprKind::Path(ref func_qpath) = func.kind @@ -96,7 +98,7 @@ fn simplify_half<'tcx>( // T1 == T2? && *ty1 == ty2 { - Some(receiver) + Some((receiver, refs_count)) } else { None } diff --git a/tests/ui/manual_slice_size_calculation.fixed b/tests/ui/manual_slice_size_calculation.fixed index 62b372f4b8d9c..0603b30e34653 100644 --- a/tests/ui/manual_slice_size_calculation.fixed +++ b/tests/ui/manual_slice_size_calculation.fixed @@ -10,11 +10,15 @@ use proc_macros::external; fn main() { let v_i32 = Vec::::new(); let s_i32 = v_i32.as_slice(); + let s_i32_ref = &s_i32; + let s_i32_ref_ref = &s_i32_ref; // True positives: let _ = std::mem::size_of_val(s_i32); // WARNING let _ = std::mem::size_of_val(s_i32); // WARNING let _ = std::mem::size_of_val(s_i32) * 5; // WARNING + let _ = std::mem::size_of_val(*s_i32_ref); // WARNING + let _ = std::mem::size_of_val(**s_i32_ref_ref); // WARNING let len = s_i32.len(); let size = size_of::(); diff --git a/tests/ui/manual_slice_size_calculation.rs b/tests/ui/manual_slice_size_calculation.rs index d59f5fd8b9427..14093e653c09d 100644 --- a/tests/ui/manual_slice_size_calculation.rs +++ b/tests/ui/manual_slice_size_calculation.rs @@ -10,11 +10,15 @@ use proc_macros::external; fn main() { let v_i32 = Vec::::new(); let s_i32 = v_i32.as_slice(); + let s_i32_ref = &s_i32; + let s_i32_ref_ref = &s_i32_ref; // True positives: let _ = s_i32.len() * size_of::(); // WARNING let _ = size_of::() * s_i32.len(); // WARNING let _ = size_of::() * s_i32.len() * 5; // WARNING + let _ = size_of::() * s_i32_ref.len(); // WARNING + let _ = size_of::() * s_i32_ref_ref.len(); // WARNING let len = s_i32.len(); let size = size_of::(); diff --git a/tests/ui/manual_slice_size_calculation.stderr b/tests/ui/manual_slice_size_calculation.stderr index 4bd8a4fdf17b7..0397f3a4969a8 100644 --- a/tests/ui/manual_slice_size_calculation.stderr +++ b/tests/ui/manual_slice_size_calculation.stderr @@ -1,5 +1,5 @@ error: manual slice size calculation - --> tests/ui/manual_slice_size_calculation.rs:15:13 + --> tests/ui/manual_slice_size_calculation.rs:17:13 | LL | let _ = s_i32.len() * size_of::(); // WARNING | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` @@ -8,40 +8,52 @@ LL | let _ = s_i32.len() * size_of::(); // WARNING = help: to override `-D warnings` add `#[allow(clippy::manual_slice_size_calculation)]` error: manual slice size calculation - --> tests/ui/manual_slice_size_calculation.rs:16:13 + --> tests/ui/manual_slice_size_calculation.rs:18:13 | LL | let _ = size_of::() * s_i32.len(); // WARNING | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` error: manual slice size calculation - --> tests/ui/manual_slice_size_calculation.rs:17:13 + --> tests/ui/manual_slice_size_calculation.rs:19:13 | LL | let _ = size_of::() * s_i32.len() * 5; // WARNING | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` +error: manual slice size calculation + --> tests/ui/manual_slice_size_calculation.rs:20:13 + | +LL | let _ = size_of::() * s_i32_ref.len(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(*s_i32_ref)` + error: manual slice size calculation --> tests/ui/manual_slice_size_calculation.rs:21:13 | +LL | let _ = size_of::() * s_i32_ref_ref.len(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(**s_i32_ref_ref)` + +error: manual slice size calculation + --> tests/ui/manual_slice_size_calculation.rs:25:13 + | LL | let _ = len * size_of::(); // WARNING | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` error: manual slice size calculation - --> tests/ui/manual_slice_size_calculation.rs:22:13 + --> tests/ui/manual_slice_size_calculation.rs:26:13 | LL | let _ = s_i32.len() * size; // WARNING | ^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` error: manual slice size calculation - --> tests/ui/manual_slice_size_calculation.rs:23:13 + --> tests/ui/manual_slice_size_calculation.rs:27:13 | LL | let _ = len * size; // WARNING | ^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` error: manual slice size calculation - --> tests/ui/manual_slice_size_calculation.rs:25:13 + --> tests/ui/manual_slice_size_calculation.rs:29:13 | LL | let _ = external!(&[1u64][..]).len() * size_of::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(external!(&[1u64][..]))` -error: aborting due to 7 previous errors +error: aborting due to 9 previous errors From aeb548a4f76c742608c2b7154461814440048506 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 14 Aug 2024 16:40:00 +0200 Subject: [PATCH 036/260] Put back interactions with settings menus --- util/gh-pages/index_template.html | 78 ++++++++++------------------ util/gh-pages/script.js | 85 +++++++++++++++++++------------ util/gh-pages/style.css | 14 ++++- 3 files changed, 91 insertions(+), 86 deletions(-) diff --git a/util/gh-pages/index_template.html b/util/gh-pages/index_template.html index 5a7af7d562ed8..a18948a206042 100644 --- a/util/gh-pages/index_template.html +++ b/util/gh-pages/index_template.html @@ -27,7 +27,7 @@
    -
    +
    Theme
    - All - +
  • - +
  • -
    +
    -
    -
    -
    - - -
    +
    + +
    -
    +
    -

    diff --git a/util/gh-pages/script.js b/util/gh-pages/script.js index 7dce72c18590c..4c61c5129df2f 100644 --- a/util/gh-pages/script.js +++ b/util/gh-pages/script.js @@ -76,6 +76,29 @@ window.searchState = { setTimeout(searchState.filterLints, 50); }, filterLints: () => { + function matchesSearch(lint, terms, searchStr) { + // Search by id + if (lint.elem.id.indexOf(searchStr) !== -1) { + return true; + } + // Search the description + // The use of `for`-loops instead of `foreach` enables us to return early + const docsLowerCase = lint.elem.textContent.toLowerCase(); + for (const term of terms) { + // This is more likely and will therefore be checked first + if (docsLowerCase.indexOf(term) !== -1) { + return true; + } + + if (lint.elem.id.indexOf(term) !== -1) { + return true; + } + + return false; + } + return true; + } + searchState.clearInputTimeout(); let searchStr = searchState.inputElem.value.trim().toLowerCase(); @@ -87,29 +110,19 @@ window.searchState = { } searchState.lastSearch = searchStr; const terms = searchStr.split(" "); + const cleanedSearchStr = searchStr.replaceAll("-", "_"); - onEachLazy(document.querySelectorAll("article"), lint => { - // Search by id - if (lint.id.indexOf(searchStr.replaceAll("-", "_")) !== -1) { - lint.style.display = ""; - return; + for (const lint of filters.getAllLints()) { + lint.searchFilteredOut = !matchesSearch(lint, terms, cleanedSearchStr); + if (lint.filteredOut) { + continue; } - // Search the description - // The use of `for`-loops instead of `foreach` enables us to return early - const docsLowerCase = lint.textContent.toLowerCase(); - for (index = 0; index < terms.length; index++) { - // This is more likely and will therefore be checked first - if (docsLowerCase.indexOf(terms[index]) !== -1) { - return; - } - - if (lint.id.indexOf(terms[index]) !== -1) { - return; - } - - lint.style.display = "none"; + if (lint.searchFilteredOut) { + lint.elem.style.display = "none"; + } else { + lint.elem.style.display = ""; } - }); + } if (searchStr.length > 0) { window.location.hash = `/${searchStr}`; } else { @@ -151,12 +164,26 @@ function handleShortcut(ev) { document.addEventListener("keypress", handleShortcut); document.addEventListener("keydown", handleShortcut); -function toggleElements(element, value) { - // `element` is always a button in a `li` in a `ul`. We want the `input` in the `ul`. +function toggleElements(filter, value) { + let needsUpdate = false; + let count = 0; + + const element = document.getElementById(filters[filter].id); onEachLazy( - element.parentElement.parentElement.getElementsByTagName("input"), - el => el.checked = value, + element.querySelectorAll("ul input"), + el => { + if (el.checked !== value) { + el.checked = value; + filters[filter][el.getAttribute("data-value")] = value; + needsUpdate = true; + } + count += 1; + } ); + element.querySelector(".badge").innerText = value ? count : 0; + if (needsUpdate) { + filters.filterLints(); + } } function changeSetting(elem) { @@ -251,15 +278,90 @@ const GROUPS_FILTER_DEFAULT = { style: true, suspicious: true, }; +const LEVEL_FILTERS_DEFAULT = { + allow: true, + warn: true, + deny: true, + none: true, +}; +const APPLICABILITIES_FILTER_DEFAULT = { + Unspecified: true, + Unresolved: true, + MachineApplicable: true, + MaybeIncorrect: true, + HasPlaceholders: true, +}; + +window.filters = { + groups_filter: { id: "lint-groups", ...GROUPS_FILTER_DEFAULT }, + levels_filter: { id: "lint-levels", ...LEVEL_FILTERS_DEFAULT }, + applicabilities_filter: { id: "lint-applicabilities", ...APPLICABILITIES_FILTER_DEFAULT }, + version_filter: { + "≥": null, + "≤": null, + "=": null, + }, + allLints: null, + getAllLints: () => { + if (filters.allLints === null) { + filters.allLints = Array.prototype.slice.call( + document.getElementsByTagName("article"), + ).map(elem => { + return { + elem: elem, + group: elem.querySelector(".label-lint-group").innerText, + level: elem.querySelector(".label-lint-level").innerText, + version: elem.querySelector(".label-version").innerText, + applicability: elem.querySelector(".label-applicability").innerText, + filteredOut: false, + searchFilteredOut: false, + }; + }); + } + return filters.allLints; + }, + filterLints: () => { + for (const lint of filters.getAllLints()) { + lint.filteredOut = (!filters.groups_filter[lint.group] + || !filters.levels_filter[lint.level] + || !filters.applicabilities_filter[lint.applicability]); + if (lint.filteredOut || lint.searchFilteredOut) { + lint.elem.style.display = "none"; + } else { + lint.elem.style.display = ""; + } + } + }, +}; + +function updateFilter(elem, filter) { + const value = elem.getAttribute("data-value"); + if (filters[filter][value] !== elem.checked) { + filters[filter][value] = elem.checked; + const counter = document.querySelector(`#${filters[filter].id} .badge`); + counter.innerText = parseInt(counter.innerText) + (elem.checked ? 1 : -1); + filters.filterLints(); + } +} function resetGroupsToDefault() { + let needsUpdate = false; + onEachLazy(document.querySelectorAll("#lint-groups-selector input"), el => { const key = el.getAttribute("data-value"); - el.checked = GROUPS_FILTER_DEFAULT[key]; + const value = GROUPS_FILTER_DEFAULT[key]; + if (filters.groups_filter[key] !== value) { + filters.groups_filter[key] = value; + el.checked = value; + needsUpdate = true; + } }); + if (needsUpdate) { + filters.filterLints(); + } } -function generateListOfOptions(list, elementId) { +function generateListOfOptions(list, elementId, filter) { let html = ''; let nbEnabled = 0; for (const [key, value] of Object.entries(list)) { @@ -267,7 +369,8 @@ function generateListOfOptions(list, elementId) { html += `\
  • \ \
  • `; if (value) { @@ -298,20 +401,10 @@ function setupDropdown(elementId) { function generateSettings() { setupDropdown("settings-dropdown"); - const LEVEL_FILTERS_DEFAULT = {allow: true, warn: true, deny: true, none: true}; - generateListOfOptions(LEVEL_FILTERS_DEFAULT, "lint-levels"); - - // Generate lint groups. - generateListOfOptions(GROUPS_FILTER_DEFAULT, "lint-groups"); - - const APPLICABILITIES_FILTER_DEFAULT = { - Unspecified: true, - Unresolved: true, - MachineApplicable: true, - MaybeIncorrect: true, - HasPlaceholders: true - }; - generateListOfOptions(APPLICABILITIES_FILTER_DEFAULT, "lint-applicabilities"); + generateListOfOptions(LEVEL_FILTERS_DEFAULT, "lint-levels", "levels_filter"); + generateListOfOptions(GROUPS_FILTER_DEFAULT, "lint-groups", "groups_filter"); + generateListOfOptions( + APPLICABILITIES_FILTER_DEFAULT, "lint-applicabilities", "applicabilities_filter"); let html = ''; for (const kind of ["≥", "≤", "="]) { @@ -361,5 +454,5 @@ function scrollToLintByURL() { } scrollToLintByURL(); - +filters.filterLints(); onEachLazy(document.querySelectorAll("pre > code.language-rust"), el => hljs.highlightElement(el)); From 00c11df107e27b8f37c63efbdf359b0d62e9f54c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 15 Aug 2024 00:47:20 +0200 Subject: [PATCH 038/260] Add support for version filtering --- util/gh-pages/script.js | 58 +++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 8 deletions(-) diff --git a/util/gh-pages/script.js b/util/gh-pages/script.js index 4c61c5129df2f..6b25bfa48bbec 100644 --- a/util/gh-pages/script.js +++ b/util/gh-pages/script.js @@ -262,10 +262,6 @@ function toggleExpansion(expand) { ); } -function clearVersionFilters() { - onEachLazy(document.querySelectorAll("#version-filter-count input"), el => el.value = ""); -} - const GROUPS_FILTER_DEFAULT = { cargo: true, complexity: true, @@ -307,11 +303,16 @@ window.filters = { filters.allLints = Array.prototype.slice.call( document.getElementsByTagName("article"), ).map(elem => { + let version = elem.querySelector(".label-version").innerText; + // Strip the "pre " prefix for pre 1.29.0 lints + if (version.startsWith("pre ")) { + version = version.slice(4); + } return { elem: elem, group: elem.querySelector(".label-lint-group").innerText, level: elem.querySelector(".label-lint-level").innerText, - version: elem.querySelector(".label-version").innerText, + version: parseInt(version.split(".")[1]), applicability: elem.querySelector(".label-applicability").innerText, filteredOut: false, searchFilteredOut: false, @@ -324,7 +325,11 @@ window.filters = { for (const lint of filters.getAllLints()) { lint.filteredOut = (!filters.groups_filter[lint.group] || !filters.levels_filter[lint.level] - || !filters.applicabilities_filter[lint.applicability]); + || !filters.applicabilities_filter[lint.applicability] + || !(filters.version_filter["="] === null || lint.version === filters.version_filter["="]) + || !(filters.version_filter["≥"] === null || lint.version > filters.version_filter["≥"]) + || !(filters.version_filter["≤"] === null || lint.version < filters.version_filter["≤"]) + ); if (lint.filteredOut || lint.searchFilteredOut) { lint.elem.style.display = "none"; } else { @@ -344,6 +349,38 @@ function updateFilter(elem, filter) { } } +function updateVersionFilters(elem, comparisonKind) { + let value = elem.value.trim(); + if (value.length === 0) { + value = null; + } else if (/^\d+$/.test(value)) { + value = parseInt(value); + } else { + console.error(`Failed to get version number from "${value}"`); + return; + } + if (filters.version_filter[comparisonKind] !== value) { + filters.version_filter[comparisonKind] = value; + filters.filterLints(); + } +} + +function clearVersionFilters() { + let needsUpdate = false; + + onEachLazy(document.querySelectorAll("#version-filter input"), el => { + el.value = ""; + const comparisonKind = el.getAttribute("data-value"); + if (filters.version_filter[comparisonKind] !== null) { + needsUpdate = true; + filters.version_filter[comparisonKind] = null; + } + }); + if (needsUpdate) { + filters.filterLints(); + } +} + function resetGroupsToDefault() { let needsUpdate = false; @@ -414,10 +451,15 @@ function generateSettings() { 1. \ \ + data-value="${kind}" \ + onchange="updateVersionFilters(this, '${kind}')" \ + oninput="updateVersionFilters(this, '${kind}')" \ + onkeydown="updateVersionFilters(this, '${kind}')" \ + onkeyup="updateVersionFilters(this, '${kind}')" \ + onpaste="updateVersionFilters(this, '${kind}')" \ + /> .0\ `; } From 4bb4cc6fcbc0fe1bacd44ab9004405c19ae52781 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 15 Aug 2024 01:56:53 +0200 Subject: [PATCH 039/260] Add support for URL arguments --- util/gh-pages/script.js | 124 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 115 insertions(+), 9 deletions(-) diff --git a/util/gh-pages/script.js b/util/gh-pages/script.js index 6b25bfa48bbec..cbe2a79934f72 100644 --- a/util/gh-pages/script.js +++ b/util/gh-pages/script.js @@ -262,6 +262,11 @@ function toggleExpansion(expand) { ); } +// Returns the current URL without any query parameter or hash. +function getNakedUrl() { + return window.location.href.split("?")[0].split("#")[0]; +} + const GROUPS_FILTER_DEFAULT = { cargo: true, complexity: true, @@ -287,6 +292,17 @@ const APPLICABILITIES_FILTER_DEFAULT = { MaybeIncorrect: true, HasPlaceholders: true, }; +const URL_PARAMS_CORRESPONDANCE = { + "groups_filter": "groups", + "levels_filter": "levels", + "applicabilities_filter": "applicabilities", + "version_filter": "versions", +}; +const VERSIONS_CORRESPONDANCE = { + "lte": "≤", + "gte": "≥", + "eq": "=", +}; window.filters = { groups_filter: { id: "lint-groups", ...GROUPS_FILTER_DEFAULT }, @@ -321,7 +337,65 @@ window.filters = { } return filters.allLints; }, + regenerateURLparams: () => { + const urlParams = new URLSearchParams(window.location.search); + + function compareObjects(obj1, obj2) { + return (JSON.stringify(obj1) === JSON.stringify({ id: obj1.id, ...obj2 })); + } + function updateIfNeeded(filterName, obj2) { + const obj1 = filters[filterName]; + const name = URL_PARAMS_CORRESPONDANCE[filterName]; + if (!compareObjects(obj1, obj2)) { + urlParams.set( + name, + Object.entries(obj1).filter( + ([key, value]) => value && key !== "id" + ).map( + ([key, _]) => key + ).join(","), + ); + } else { + urlParams.delete(name); + } + } + + updateIfNeeded("groups_filter", GROUPS_FILTER_DEFAULT); + updateIfNeeded("levels_filter", LEVEL_FILTERS_DEFAULT); + updateIfNeeded( + "applicabilities_filter", APPLICABILITIES_FILTER_DEFAULT); + + const versions = []; + if (filters.version_filter["="] !== null) { + versions.push(`eq:${filters.version_filter["="]}`); + } + if (filters.version_filter["≥"] !== null) { + versions.push(`gte:${filters.version_filter["≥"]}`); + } + if (filters.version_filter["≤"] !== null) { + versions.push(`lte:${filters.version_filter["≤"]}`); + } + if (versions.length !== 0) { + urlParams.set(URL_PARAMS_CORRESPONDANCE["version_filter"], versions.join(",")); + } else { + urlParams.delete(URL_PARAMS_CORRESPONDANCE["version_filter"]); + } + + let params = urlParams.toString(); + if (params.length !== 0) { + params = `?${params}`; + } + + const url = getNakedUrl() + params + window.location.hash + if (!history.state) { + history.pushState(null, "", url); + } else { + history.replaceState(null, "", url); + } + }, filterLints: () => { + // First we regenerate the URL parameters. + filters.regenerateURLparams(); for (const lint of filters.getAllLints()) { lint.filteredOut = (!filters.groups_filter[lint.group] || !filters.levels_filter[lint.level] @@ -339,17 +413,19 @@ window.filters = { }, }; -function updateFilter(elem, filter) { +function updateFilter(elem, filter, skipLintsFiltering) { const value = elem.getAttribute("data-value"); if (filters[filter][value] !== elem.checked) { filters[filter][value] = elem.checked; const counter = document.querySelector(`#${filters[filter].id} .badge`); counter.innerText = parseInt(counter.innerText) + (elem.checked ? 1 : -1); - filters.filterLints(); + if (!skipLintsFiltering) { + filters.filterLints(); + } } } -function updateVersionFilters(elem, comparisonKind) { +function updateVersionFilters(elem, skipLintsFiltering) { let value = elem.value.trim(); if (value.length === 0) { value = null; @@ -359,9 +435,12 @@ function updateVersionFilters(elem, comparisonKind) { console.error(`Failed to get version number from "${value}"`); return; } + const comparisonKind = elem.getAttribute("data-value"); if (filters.version_filter[comparisonKind] !== value) { filters.version_filter[comparisonKind] = value; - filters.filterLints(); + if (!skipLintsFiltering) { + filters.filterLints(); + } } } @@ -454,11 +533,11 @@ function generateSettings() { class="version-filter-input form-control filter-input" \ maxlength="2" \ data-value="${kind}" \ - onchange="updateVersionFilters(this, '${kind}')" \ - oninput="updateVersionFilters(this, '${kind}')" \ - onkeydown="updateVersionFilters(this, '${kind}')" \ - onkeyup="updateVersionFilters(this, '${kind}')" \ - onpaste="updateVersionFilters(this, '${kind}')" \ + onchange="updateVersionFilters(this)" \ + oninput="updateVersionFilters(this)" \ + onkeydown="updateVersionFilters(this)" \ + onkeyup="updateVersionFilters(this)" \ + onpaste="updateVersionFilters(this)" \ /> .0\ `; @@ -495,6 +574,33 @@ function scrollToLintByURL() { } } +function parseURLFilters() { + const urlParams = new URLSearchParams(window.location.search); + + for (const [key, value] of urlParams.entries()) { + for (const [corres_key, corres_value] of Object.entries(URL_PARAMS_CORRESPONDANCE)) { + if (corres_value === key) { + if (key !== "versions") { + const settings = new Set(value.split(",")); + onEachLazy(document.querySelectorAll(`#lint-${key} ul input`), elem => { + elem.checked = settings.has(elem.getAttribute("data-value")); + updateFilter(elem, corres_key, true); + }); + } else { + const settings = value.split(",").map(elem => elem.split(":")); + + for (const [kind, value] of settings) { + const elem = document.querySelector( + `#version-filter input[data-value="${VERSIONS_CORRESPONDANCE[kind]}"]`); + updateVersionFilters(elem, true); + } + } + } + } + } +} + +parseURLFilters(); scrollToLintByURL(); filters.filterLints(); onEachLazy(document.querySelectorAll("pre > code.language-rust"), el => hljs.highlightElement(el)); From e0b0851ba8a83d4f258a9d86ba5579c4f2c61b46 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 15 Aug 2024 16:08:48 +0200 Subject: [PATCH 040/260] Support version filter URL parameters --- util/gh-pages/script.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/util/gh-pages/script.js b/util/gh-pages/script.js index cbe2a79934f72..d3bc6f6fc9977 100644 --- a/util/gh-pages/script.js +++ b/util/gh-pages/script.js @@ -435,6 +435,16 @@ function updateVersionFilters(elem, skipLintsFiltering) { console.error(`Failed to get version number from "${value}"`); return; } + + const counter = document.querySelector("#version-filter .badge"); + let count = 0; + onEachLazy(document.querySelectorAll("#version-filter input"), el => { + if (el.value.trim().length !== 0) { + count += 1; + } + }); + counter.innerText = count; + const comparisonKind = elem.getAttribute("data-value"); if (filters.version_filter[comparisonKind] !== value) { filters.version_filter[comparisonKind] = value; @@ -455,6 +465,7 @@ function clearVersionFilters() { filters.version_filter[comparisonKind] = null; } }); + document.querySelector("#version-filter .badge").innerText = 0; if (needsUpdate) { filters.filterLints(); } @@ -462,6 +473,7 @@ function clearVersionFilters() { function resetGroupsToDefault() { let needsUpdate = false; + let count = 0; onEachLazy(document.querySelectorAll("#lint-groups-selector input"), el => { const key = el.getAttribute("data-value"); @@ -471,7 +483,11 @@ function resetGroupsToDefault() { el.checked = value; needsUpdate = true; } + if (value) { + count += 1; + } }); + document.querySelector("#lint-groups .badge").innerText = count; if (needsUpdate) { filters.filterLints(); } @@ -592,6 +608,7 @@ function parseURLFilters() { for (const [kind, value] of settings) { const elem = document.querySelector( `#version-filter input[data-value="${VERSIONS_CORRESPONDANCE[kind]}"]`); + elem.value = value; updateVersionFilters(elem, true); } } From 47f40d468acae7e37d101cee9a6d79bff3461c64 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 15 Aug 2024 16:13:53 +0200 Subject: [PATCH 041/260] Improve rendering speed by moving settings generation after theme rendering --- tests/compile-test.rs | 11 +++++-- util/gh-pages/index_template.html | 4 +-- util/gh-pages/script.js | 49 ++++++++++++++++--------------- 3 files changed, 36 insertions(+), 28 deletions(-) diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 00627dc0bb1f9..162aed393c461 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -9,7 +9,8 @@ use clippy_lints::LintInfo; use clippy_lints::declared_lints::LINTS; use clippy_lints::deprecated_lints::{DEPRECATED, DEPRECATED_VERSION, RENAMED}; use pulldown_cmark::{Options, Parser, html}; -use rinja::{Template, filters::Safe}; +use rinja::Template; +use rinja::filters::Safe; use serde::Deserialize; use test_utils::IS_RUSTC_TEST_SUITE; use ui_test::custom_flags::Flag; @@ -394,7 +395,7 @@ struct Renderer<'a> { } impl<'a> Renderer<'a> { - fn markdown(&self, input: &str) -> Safe { + fn markdown(input: &str) -> Safe { let parser = Parser::new_ext(input, Options::all()); let mut html_output = String::new(); html::push_html(&mut html_output, parser); @@ -465,7 +466,11 @@ impl DiagnosticCollector { .collect(); metadata.sort_unstable_by(|a, b| a.id.cmp(&b.id)); - fs::write("util/gh-pages/index.html", Renderer { lints: &metadata }.render().unwrap()).unwrap(); + fs::write( + "util/gh-pages/index.html", + Renderer { lints: &metadata }.render().unwrap(), + ) + .unwrap(); }); (Self { sender }, handle) diff --git a/util/gh-pages/index_template.html b/util/gh-pages/index_template.html index 774c7b487c166..d942cbe39e72d 100644 --- a/util/gh-pages/index_template.html +++ b/util/gh-pages/index_template.html @@ -1,7 +1,7 @@ - - - - - + {# #} + {# #} + {# #} + {# #} + {# #} - Clippy Lints + Clippy Lints {# #} - - - + {# #} + {# #} + {# #} - - - - - - - - -
    - -
    -
    Theme
    - - -
    -
    + {# #} + {# #} + {# #} + {# #} + {# #} + {# #} + {# #} + {# #} +
    {# #} + {# #} +
    {# #} +
    Theme
    {# #} + {# #} + {# #} +
    {# #} +
    {# #} -
    - +
    {# #} + {# #} - + {# #} -
    -
    -
    -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    -
    -
    - - - - - -
    -
    -
    - - -
    -
    +
    {# #} +
    {# #} +
    {# #} +
    {# #} +
    {# #} + {# #} + {# #} +
    {# #} +
    {# #} + {# #} + {# #} +
    {# #} +
    {# #} + {# #} + {# #} +
    {# #} +
    {# #} + {# #} + {# #} +
    {# #} +
    {# #} +
    {# #} +
    {# #} + {# #} + {# #} + {# #} + {# #} + {# #} +
    {# #} +
    {# #} +
    {# #} + {# #} + {# #} +
    {# #} +
    {# #}
    {% for lint in lints %} -
    {# #} +

    {# #} + {# #} -
    -
    {{Self::markdown(lint.docs)}}
    +
    {# #} +
    {{Self::markdown(lint.docs)}}
    {# #}
    {# Applicability #} -
    - Applicability: - {{ lint.applicability_str() }} - (?) +
    {# #} + Applicability: {# #} + {{ lint.applicability_str() }} {# #} + (?) {# #}
    {# Clippy version #} -
    - {% if lint.group == "deprecated" %}Deprecated{% else %} Added{% endif %} in: - {{lint.version}} +
    {# #} + {% if lint.group == "deprecated" %}Deprecated{% else %} Added{% endif +%} in: {# #} + {{lint.version}} {# #}
    {# Open related issues #} -
    - Related Issues +
    {# #} + Related Issues {# #}
    {# Jump to source #} {% if let Some(id_location) = lint.id_location %} -
    - View Source +
    {# #} + View Source {# #} +
    {% endif %} -
    -
    -
    +
    {# #} +
    {# #} {% endfor %} -
    -
    +
    {# #} +
    {# #} - - - + {# #} + {# #} + {# #} - - - - - + {# #} + {# #} + {# #} + {# #} + {# #} diff --git a/util/gh-pages/script.js b/util/gh-pages/script.js index 7f36021e1aa3a..cc22a39b3d190 100644 --- a/util/gh-pages/script.js +++ b/util/gh-pages/script.js @@ -140,19 +140,15 @@ function onEachLazy(lazyArray, func) { function highlightIfNeeded(elem) { onEachLazy(elem.querySelectorAll("pre > code.language-rust:not(.highlighted)"), el => { - hljs.highlightElement(el) + hljs.highlightElement(el.parentElement) el.classList.add("highlighted"); }); } -function expandLintId(lintId) { - searchState.inputElem.value = lintId; - searchState.filterLints(); - - // Expand the lint. +function expandLint(lintId) { const lintElem = document.getElementById(lintId); - const isCollapsed = lintElem.classList.remove("collapsed"); - lintElem.querySelector(".label-doc-folding").innerText = "-"; + const isCollapsed = lintElem.classList.toggle("collapsed"); + lintElem.querySelector(".label-doc-folding").innerText = isCollapsed ? "+" : "−"; highlightIfNeeded(lintElem); } @@ -160,14 +156,7 @@ function expandLintId(lintId) { function openLint(event) { event.preventDefault(); event.stopPropagation(); - expandLintId(event.target.getAttribute("href").slice(1)); -} - -function expandLint(lintId) { - const lintElem = document.getElementById(lintId); - const isCollapsed = lintElem.classList.toggle("collapsed"); - lintElem.querySelector(".label-doc-folding").innerText = isCollapsed ? "+" : "-"; - highlightIfNeeded(lintElem); + expandLint(event.target.getAttribute("href").slice(1)); } function copyToClipboard(event) { @@ -526,7 +515,7 @@ function scrollToLint(lintId) { return; } target.scrollIntoView(); - expandLintId(lintId); + expandLint(lintId); } // If the page we arrive on has link to a given lint, we scroll to it. diff --git a/util/gh-pages/style.css b/util/gh-pages/style.css index 43c6264220765..a68a10b14011a 100644 --- a/util/gh-pages/style.css +++ b/util/gh-pages/style.css @@ -272,6 +272,9 @@ L4.75,12h2.5l0.5393066-2.1572876 c0.2276001-0.1062012,0.4459839-0.2269287,0.649 height: 18px; display: block; filter: invert(0.7); + position: absolute; + top: 4px; + left: 5px; } .settings-menu * { From 277c4e4baff50ff0df4b63e86404b8eea70e61ec Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 3 Oct 2024 16:32:51 +0200 Subject: [PATCH 047/260] Merge commit 'aa0d551351a9c15d8a95fdb3e2946b505893dda8' into clippy-subtree-update --- .github/workflows/remark.yml | 2 +- CHANGELOG.md | 1 + book/src/lint_configuration.md | 1 + clippy_config/src/conf.rs | 1 + clippy_config/src/msrvs.rs | 1 + clippy_lints/src/booleans.rs | 86 +++- clippy_lints/src/box_default.rs | 2 +- clippy_lints/src/cargo/common_metadata.rs | 16 +- clippy_lints/src/casts/borrow_as_ptr.rs | 6 +- clippy_lints/src/casts/ref_as_ptr.rs | 6 +- clippy_lints/src/checked_conversions.rs | 2 +- clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/default_numeric_fallback.rs | 2 +- clippy_lints/src/derive.rs | 2 +- clippy_lints/src/doc/mod.rs | 2 +- clippy_lints/src/empty_enum.rs | 2 +- clippy_lints/src/escape.rs | 4 +- clippy_lints/src/excessive_nesting.rs | 2 +- .../src/extra_unused_type_parameters.rs | 2 +- clippy_lints/src/fallible_impl_from.rs | 2 +- clippy_lints/src/format_args.rs | 2 +- clippy_lints/src/format_impl.rs | 2 +- clippy_lints/src/from_over_into.rs | 2 +- clippy_lints/src/functions/mod.rs | 60 +++ clippy_lints/src/functions/ref_option.rs | 122 +++++ clippy_lints/src/implicit_hasher.rs | 4 +- clippy_lints/src/index_refutable_slice.rs | 2 +- clippy_lints/src/len_zero.rs | 4 +- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/lifetimes.rs | 439 ++++++++++-------- clippy_lints/src/loops/manual_memcpy.rs | 2 +- clippy_lints/src/loops/missing_spin_loop.rs | 10 +- clippy_lints/src/loops/needless_range_loop.rs | 4 +- clippy_lints/src/loops/same_item_push.rs | 2 +- clippy_lints/src/loops/utils.rs | 4 +- .../src/loops/while_immutable_condition.rs | 4 +- .../src/loops/while_let_on_iterator.rs | 2 +- clippy_lints/src/macro_metavars_in_unsafe.rs | 2 +- clippy_lints/src/macro_use.rs | 2 +- clippy_lints/src/manual_clamp.rs | 2 +- clippy_lints/src/manual_strip.rs | 2 +- clippy_lints/src/map_unit_fn.rs | 2 +- .../src/matches/match_str_case_mismatch.rs | 4 +- clippy_lints/src/matches/mod.rs | 2 +- clippy_lints/src/matches/overlapping_arms.rs | 4 +- .../matches/significant_drop_in_scrutinee.rs | 4 +- clippy_lints/src/matches/wild_in_or_pats.rs | 14 +- clippy_lints/src/methods/mut_mutex_lock.rs | 6 +- clippy_lints/src/methods/needless_collect.rs | 2 +- .../src/methods/option_map_unwrap_or.rs | 4 +- clippy_lints/src/methods/or_fun_call.rs | 2 +- clippy_lints/src/methods/utils.rs | 4 +- .../src/mixed_read_write_in_expression.rs | 6 +- clippy_lints/src/mut_mut.rs | 2 +- clippy_lints/src/mutable_debug_assertion.rs | 2 +- clippy_lints/src/needless_for_each.rs | 2 +- clippy_lints/src/needless_pass_by_ref_mut.rs | 2 +- clippy_lints/src/non_expressive_names.rs | 10 +- .../src/non_send_fields_in_send_ty.rs | 2 +- clippy_lints/src/pass_by_ref_or_value.rs | 4 +- clippy_lints/src/pathbuf_init_then_push.rs | 2 +- clippy_lints/src/ptr.rs | 8 +- clippy_lints/src/redundant_closure_call.rs | 2 +- clippy_lints/src/returns.rs | 6 +- .../src/significant_drop_tightening.rs | 2 +- .../src/single_component_path_imports.rs | 2 +- .../src/slow_vector_initialization.rs | 4 +- clippy_lints/src/swap.rs | 2 +- clippy_lints/src/unnested_or_patterns.rs | 11 +- clippy_lints/src/unused_async.rs | 25 +- clippy_lints/src/unwrap.rs | 4 +- clippy_lints/src/use_self.rs | 2 +- .../interning_defined_symbol.rs | 2 +- .../src/utils/internal_lints/invalid_paths.rs | 3 +- .../internal_lints/lint_without_lint_pass.rs | 2 +- clippy_lints/src/zombie_processes.rs | 11 +- clippy_utils/src/ast_utils.rs | 109 +++-- clippy_utils/src/consts.rs | 6 +- clippy_utils/src/eager_or_lazy.rs | 2 +- clippy_utils/src/hir_utils.rs | 49 +- clippy_utils/src/lib.rs | 8 +- clippy_utils/src/mir/mod.rs | 2 +- clippy_utils/src/mir/possible_borrower.rs | 6 +- clippy_utils/src/mir/possible_origin.rs | 2 +- clippy_utils/src/qualify_min_const_fn.rs | 3 +- clippy_utils/src/ty.rs | 2 +- clippy_utils/src/ty/type_certainty/mod.rs | 2 +- clippy_utils/src/usage.rs | 6 +- clippy_utils/src/visitors.rs | 4 +- lintcheck/src/main.rs | 4 +- rust-toolchain | 2 +- src/driver.rs | 61 ++- tests/ui-toml/suppress_lint_in_const/test.rs | 3 +- .../suppress_lint_in_const/test.stderr | 12 +- tests/ui/as_ptr_cast_mut.rs | 2 +- tests/ui/borrow_box.fixed | 133 ++++++ tests/ui/borrow_box.rs | 20 +- tests/ui/borrow_box.stderr | 14 +- tests/ui/boxed_local.rs | 3 +- tests/ui/boxed_local.stderr | 8 +- tests/ui/bytecount.rs | 2 +- .../needless_lifetimes_impl_trait.fixed | 2 +- .../needless_lifetimes_impl_trait.stderr | 20 +- tests/ui/deref_addrof_double_trigger.rs | 4 +- tests/ui/derive.rs | 7 +- tests/ui/derive.stderr | 20 +- tests/ui/eta.fixed | 3 +- tests/ui/eta.rs | 3 +- tests/ui/eta.stderr | 68 +-- tests/ui/explicit_auto_deref.fixed | 3 +- tests/ui/explicit_auto_deref.rs | 3 +- tests/ui/explicit_auto_deref.stderr | 92 ++-- tests/ui/extra_unused_lifetimes.rs | 8 + tests/ui/extra_unused_lifetimes.stderr | 8 +- tests/ui/float_cmp.rs | 2 +- tests/ui/float_cmp_const.rs | 3 +- tests/ui/float_cmp_const.stderr | 16 +- tests/ui/float_equality_without_abs.rs | 2 +- .../if_let_slice_binding.rs | 2 +- tests/ui/invalid_null_ptr_usage.fixed | 7 +- tests/ui/invalid_null_ptr_usage.rs | 5 +- tests/ui/invalid_null_ptr_usage.stderr | 36 +- tests/ui/iter_without_into_iter.rs | 1 + tests/ui/iter_without_into_iter.stderr | 16 +- tests/ui/mem_replace.fixed | 3 +- tests/ui/mem_replace.rs | 3 +- tests/ui/mem_replace.stderr | 48 +- tests/ui/mem_replace_no_std.fixed | 3 +- tests/ui/mem_replace_no_std.rs | 3 +- tests/ui/mem_replace_no_std.stderr | 14 +- tests/ui/mismatching_type_param_order.rs | 2 +- tests/ui/mut_mutex_lock.fixed | 12 + tests/ui/mut_mutex_lock.rs | 12 + tests/ui/mut_mutex_lock.stderr | 8 +- tests/ui/needless_borrow.fixed | 3 +- tests/ui/needless_borrow.rs | 3 +- tests/ui/needless_borrow.stderr | 56 +-- tests/ui/needless_lifetimes.fixed | 23 +- tests/ui/needless_lifetimes.rs | 21 +- tests/ui/needless_lifetimes.stderr | 24 +- tests/ui/needless_pass_by_value.rs | 3 +- tests/ui/needless_pass_by_value.stderr | 52 +-- tests/ui/needless_return.fixed | 20 + tests/ui/needless_return.rs | 20 + tests/ui/new_without_default.fixed | 3 +- tests/ui/new_without_default.rs | 3 +- tests/ui/new_without_default.stderr | 18 +- tests/ui/nonminimal_bool_methods.fixed | 62 +++ tests/ui/nonminimal_bool_methods.rs | 62 +++ tests/ui/nonminimal_bool_methods.stderr | 110 ++++- tests/ui/nonminimal_bool_methods_unfixable.rs | 9 + .../nonminimal_bool_methods_unfixable.stderr | 17 + tests/ui/ref_as_ptr.fixed | 2 +- tests/ui/ref_as_ptr.rs | 2 +- tests/ui/ref_option/all/clippy.toml | 1 + tests/ui/ref_option/private/clippy.toml | 1 + tests/ui/ref_option/ref_option.all.fixed | 62 +++ tests/ui/ref_option/ref_option.all.stderr | 162 +++++++ tests/ui/ref_option/ref_option.private.fixed | 62 +++ tests/ui/ref_option/ref_option.private.stderr | 108 +++++ tests/ui/ref_option/ref_option.rs | 62 +++ .../ref_option/ref_option_traits.all.stderr | 37 ++ .../ref_option_traits.private.stderr | 21 + tests/ui/ref_option/ref_option_traits.rs | 37 ++ tests/ui/serde.rs | 2 +- tests/ui/significant_drop_in_scrutinee.rs | 7 +- tests/ui/significant_drop_in_scrutinee.stderr | 58 +-- tests/ui/str_split.fixed | 1 + tests/ui/str_split.rs | 1 + tests/ui/str_split.stderr | 20 +- tests/ui/temporary_assignment.rs | 2 +- tests/ui/unconditional_recursion.rs | 3 +- tests/ui/unconditional_recursion.stderr | 90 ++-- tests/ui/unused_async.rs | 16 + tests/ui/unused_async.stderr | 4 +- tests/ui/unused_format_specs.1.fixed | 35 ++ tests/ui/unused_format_specs.2.fixed | 35 ++ ...cs_unfixable.rs => unused_format_specs.rs} | 2 +- ...able.stderr => unused_format_specs.stderr} | 8 +- tests/ui/useful_asref.rs | 1 + tests/ui/wild_in_or_pats.rs | 68 +++ tests/ui/wild_in_or_pats.stderr | 18 +- tests/ui/zombie_processes.rs | 7 + 183 files changed, 2484 insertions(+), 848 deletions(-) create mode 100644 clippy_lints/src/functions/ref_option.rs create mode 100644 tests/ui/borrow_box.fixed create mode 100644 tests/ui/nonminimal_bool_methods_unfixable.rs create mode 100644 tests/ui/nonminimal_bool_methods_unfixable.stderr create mode 100644 tests/ui/ref_option/all/clippy.toml create mode 100644 tests/ui/ref_option/private/clippy.toml create mode 100644 tests/ui/ref_option/ref_option.all.fixed create mode 100644 tests/ui/ref_option/ref_option.all.stderr create mode 100644 tests/ui/ref_option/ref_option.private.fixed create mode 100644 tests/ui/ref_option/ref_option.private.stderr create mode 100644 tests/ui/ref_option/ref_option.rs create mode 100644 tests/ui/ref_option/ref_option_traits.all.stderr create mode 100644 tests/ui/ref_option/ref_option_traits.private.stderr create mode 100644 tests/ui/ref_option/ref_option_traits.rs create mode 100644 tests/ui/unused_format_specs.1.fixed create mode 100644 tests/ui/unused_format_specs.2.fixed rename tests/ui/{unused_format_specs_unfixable.rs => unused_format_specs.rs} (98%) rename tests/ui/{unused_format_specs_unfixable.stderr => unused_format_specs.stderr} (89%) diff --git a/.github/workflows/remark.yml b/.github/workflows/remark.yml index 348d52020fd23..a1b011dc32d84 100644 --- a/.github/workflows/remark.yml +++ b/.github/workflows/remark.yml @@ -19,7 +19,7 @@ jobs: uses: actions/checkout@v4 - name: Setup Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: '18.x' diff --git a/CHANGELOG.md b/CHANGELOG.md index 41a86e8ce5102..5d253d52531e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5871,6 +5871,7 @@ Released 2018-09-13 [`ref_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_as_ptr [`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference [`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref +[`ref_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option [`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref [`ref_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_patterns [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 91159bc79c511..07a56fb33df11 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -353,6 +353,7 @@ Suppress lints whenever the suggested change would cause breakage for other crat * [`rc_buffer`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer) * [`rc_mutex`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex) * [`redundant_allocation`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation) +* [`ref_option`](https://rust-lang.github.io/rust-clippy/master/index.html#ref_option) * [`single_call_fn`](https://rust-lang.github.io/rust-clippy/master/index.html#single_call_fn) * [`trivially_copy_pass_by_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref) * [`unnecessary_box_returns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns) diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 757620341ccc1..e4e2c97fdc1d9 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -378,6 +378,7 @@ define_Conf! { rc_buffer, rc_mutex, redundant_allocation, + ref_option, single_call_fn, trivially_copy_pass_by_ref, unnecessary_box_returns, diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index e30df3d32341a..68a3b11d3848f 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -19,6 +19,7 @@ macro_rules! msrv_aliases { msrv_aliases! { 1,83,0 { CONST_EXTERN_FN } 1,83,0 { CONST_FLOAT_BITS_CONV } + 1,82,0 { IS_NONE_OR } 1,81,0 { LINT_REASONS_STABILIZATION } 1,80,0 { BOX_INTO_ITER} 1,77,0 { C_STR_LITERALS } diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 3c2af72624f60..26888f7e3a0ed 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -1,3 +1,5 @@ +use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::eq_expr_value; use clippy_utils::source::SpanRangeExt; @@ -7,7 +9,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp}; use rustc_lint::{LateContext, LateLintPass, Level}; -use rustc_session::declare_lint_pass; +use rustc_session::{RustcVersion, impl_lint_pass}; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, sym}; @@ -69,9 +71,25 @@ declare_clippy_lint! { } // For each pairs, both orders are considered. -const METHODS_WITH_NEGATION: [(&str, &str); 2] = [("is_some", "is_none"), ("is_err", "is_ok")]; +const METHODS_WITH_NEGATION: [(Option, &str, &str); 3] = [ + (None, "is_some", "is_none"), + (None, "is_err", "is_ok"), + (Some(msrvs::IS_NONE_OR), "is_some_and", "is_none_or"), +]; + +pub struct NonminimalBool { + msrv: Msrv, +} + +impl NonminimalBool { + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } + } +} -declare_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, OVERLY_COMPLEX_BOOL_EXPR]); +impl_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, OVERLY_COMPLEX_BOOL_EXPR]); impl<'tcx> LateLintPass<'tcx> for NonminimalBool { fn check_fn( @@ -83,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for NonminimalBool { _: Span, _: LocalDefId, ) { - NonminimalBoolVisitor { cx }.visit_body(body); + NonminimalBoolVisitor { cx, msrv: &self.msrv }.visit_body(body); } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { @@ -100,6 +118,8 @@ impl<'tcx> LateLintPass<'tcx> for NonminimalBool { _ => {}, } } + + extract_msrv_attr!(LateContext); } fn inverted_bin_op_eq_str(op: BinOpKind) -> Option<&'static str> { @@ -176,11 +196,11 @@ fn check_inverted_bool_in_condition( ); } -fn check_simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) { +fn check_simplify_not(cx: &LateContext<'_>, msrv: &Msrv, expr: &Expr<'_>) { if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind && !expr.span.from_expansion() && !inner.span.from_expansion() - && let Some(suggestion) = simplify_not(cx, inner) + && let Some(suggestion) = simplify_not(cx, msrv, inner) && cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, expr.hir_id).0 != Level::Allow { span_lint_and_sugg( @@ -197,6 +217,7 @@ fn check_simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) { struct NonminimalBoolVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, + msrv: &'a Msrv, } use quine_mc_cluskey::Bool; @@ -205,7 +226,7 @@ struct Hir2Qmm<'a, 'tcx, 'v> { cx: &'a LateContext<'tcx>, } -impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { +impl<'v> Hir2Qmm<'_, '_, 'v> { fn extract(&mut self, op: BinOpKind, a: &[&'v Expr<'_>], mut v: Vec) -> Result, String> { for a in a { if let ExprKind::Binary(binop, lhs, rhs) = &a.kind { @@ -289,10 +310,11 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { struct SuggestContext<'a, 'tcx, 'v> { terminals: &'v [&'v Expr<'v>], cx: &'a LateContext<'tcx>, + msrv: &'a Msrv, output: String, } -impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> { +impl SuggestContext<'_, '_, '_> { fn recurse(&mut self, suggestion: &Bool) -> Option<()> { use quine_mc_cluskey::Bool::{And, False, Not, Or, Term, True}; match suggestion { @@ -311,7 +333,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> { }, Term(n) => { let terminal = self.terminals[n as usize]; - if let Some(str) = simplify_not(self.cx, terminal) { + if let Some(str) = simplify_not(self.cx, self.msrv, terminal) { self.output.push_str(&str); } else { self.output.push('!'); @@ -358,7 +380,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> { } } -fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { +fn simplify_not(cx: &LateContext<'_>, curr_msrv: &Msrv, expr: &Expr<'_>) -> Option { match &expr.kind { ExprKind::Binary(binop, lhs, rhs) => { if !implements_ord(cx, lhs) { @@ -389,7 +411,7 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { Some(format!("{lhs_snippet}{op}{rhs_snippet}")) }) }, - ExprKind::MethodCall(path, receiver, [], _) => { + ExprKind::MethodCall(path, receiver, args, _) => { let type_of_receiver = cx.typeck_results().expr_ty(receiver); if !is_type_diagnostic_item(cx, type_of_receiver, sym::Option) && !is_type_diagnostic_item(cx, type_of_receiver, sym::Result) @@ -399,21 +421,41 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { METHODS_WITH_NEGATION .iter() .copied() - .flat_map(|(a, b)| vec![(a, b), (b, a)]) - .find(|&(a, _)| { - let path: &str = path.ident.name.as_str(); - a == path + .flat_map(|(msrv, a, b)| vec![(msrv, a, b), (msrv, b, a)]) + .find(|&(msrv, a, _)| msrv.is_none_or(|msrv| curr_msrv.meets(msrv)) && a == path.ident.name.as_str()) + .and_then(|(_, _, neg_method)| { + let negated_args = args + .iter() + .map(|arg| simplify_not(cx, curr_msrv, arg)) + .collect::>>()? + .join(", "); + Some(format!( + "{}.{neg_method}({negated_args})", + receiver.span.get_source_text(cx)? + )) }) - .and_then(|(_, neg_method)| Some(format!("{}.{neg_method}()", receiver.span.get_source_text(cx)?))) }, + ExprKind::Closure(closure) => { + let body = cx.tcx.hir().body(closure.body); + let params = body + .params + .iter() + .map(|param| param.span.get_source_text(cx).map(|t| t.to_string())) + .collect::>>()? + .join(", "); + let negated = simplify_not(cx, curr_msrv, body.value)?; + Some(format!("|{params}| {negated}")) + }, + ExprKind::Unary(UnOp::Not, expr) => expr.span.get_source_text(cx).map(|t| t.to_string()), _ => None, } } -fn suggest(cx: &LateContext<'_>, suggestion: &Bool, terminals: &[&Expr<'_>]) -> String { +fn suggest(cx: &LateContext<'_>, msrv: &Msrv, suggestion: &Bool, terminals: &[&Expr<'_>]) -> String { let mut suggest_context = SuggestContext { terminals, cx, + msrv, output: String::new(), }; suggest_context.recurse(suggestion); @@ -475,7 +517,7 @@ fn terminal_stats(b: &Bool) -> Stats { stats } -impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { +impl<'tcx> NonminimalBoolVisitor<'_, 'tcx> { fn bool_expr(&self, e: &'tcx Expr<'_>) { let mut h2q = Hir2Qmm { terminals: Vec::new(), @@ -526,7 +568,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { diag.span_suggestion( e.span, "it would look like the following", - suggest(self.cx, suggestion, &h2q.terminals), + suggest(self.cx, self.msrv, suggestion, &h2q.terminals), // nonminimal_bool can produce minimal but // not human readable expressions (#3141) Applicability::Unspecified, @@ -569,12 +611,12 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { } }; if improvements.is_empty() { - check_simplify_not(self.cx, e); + check_simplify_not(self.cx, self.msrv, e); } else { nonminimal_bool_lint( improvements .into_iter() - .map(|suggestion| suggest(self.cx, suggestion, &h2q.terminals)) + .map(|suggestion| suggest(self.cx, self.msrv, suggestion, &h2q.terminals)) .collect(), ); } @@ -582,7 +624,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'_, 'tcx> { fn visit_expr(&mut self, e: &'tcx Expr<'_>) { if !e.span.from_expansion() { match &e.kind { diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index 8261c65354fd5..40d154c0bdfe3 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -91,7 +91,7 @@ fn is_local_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>, ref_expr: &Expr<'_>) #[derive(Default)] struct InferVisitor(bool); -impl<'tcx> Visitor<'tcx> for InferVisitor { +impl Visitor<'_> for InferVisitor { fn visit_ty(&mut self, t: &Ty<'_>) { self.0 |= matches!(t.kind, TyKind::Infer | TyKind::OpaqueDef(..) | TyKind::TraitObject(..)); if !self.0 { diff --git a/clippy_lints/src/cargo/common_metadata.rs b/clippy_lints/src/cargo/common_metadata.rs index fed0aa8b2758b..6714c053913c9 100644 --- a/clippy_lints/src/cargo/common_metadata.rs +++ b/clippy_lints/src/cargo/common_metadata.rs @@ -10,27 +10,27 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata, ignore_publish: b // only run the lint if publish is `None` (`publish = true` or skipped entirely) // or if the vector isn't empty (`publish = ["something"]`) if package.publish.as_ref().filter(|publish| publish.is_empty()).is_none() || ignore_publish { - if is_empty_str(&package.description) { + if is_empty_str(package.description.as_ref()) { missing_warning(cx, package, "package.description"); } - if is_empty_str(&package.license) && is_empty_str(&package.license_file) { + if is_empty_str(package.license.as_ref()) && is_empty_str(package.license_file.as_ref()) { missing_warning(cx, package, "either package.license or package.license_file"); } - if is_empty_str(&package.repository) { + if is_empty_str(package.repository.as_ref()) { missing_warning(cx, package, "package.repository"); } - if is_empty_str(&package.readme) { + if is_empty_str(package.readme.as_ref()) { missing_warning(cx, package, "package.readme"); } - if is_empty_vec(&package.keywords) { + if is_empty_vec(package.keywords.as_ref()) { missing_warning(cx, package, "package.keywords"); } - if is_empty_vec(&package.categories) { + if is_empty_vec(package.categories.as_ref()) { missing_warning(cx, package, "package.categories"); } } @@ -42,8 +42,8 @@ fn missing_warning(cx: &LateContext<'_>, package: &cargo_metadata::Package, fiel span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, message); } -fn is_empty_str>(value: &Option) -> bool { - value.as_ref().map_or(true, |s| s.as_ref().is_empty()) +fn is_empty_str>(value: Option<&T>) -> bool { + value.map_or(true, |s| s.as_ref().is_empty()) } fn is_empty_vec(value: &[String]) -> bool { diff --git a/clippy_lints/src/casts/borrow_as_ptr.rs b/clippy_lints/src/casts/borrow_as_ptr.rs index b7256dd2eae9d..4dd51dcbc9a20 100644 --- a/clippy_lints/src/casts/borrow_as_ptr.rs +++ b/clippy_lints/src/casts/borrow_as_ptr.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_no_std_crate; use clippy_utils::source::snippet_with_context; +use clippy_utils::std_or_core; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Ty, TyKind}; use rustc_lint::LateContext; @@ -16,8 +16,8 @@ pub(super) fn check<'tcx>( ) { if matches!(cast_to.kind, TyKind::Ptr(_)) && let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = cast_expr.kind + && let Some(std_or_core) = std_or_core(cx) { - let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" }; let macro_name = match mutability { Mutability::Not => "addr_of", Mutability::Mut => "addr_of_mut", @@ -40,7 +40,7 @@ pub(super) fn check<'tcx>( expr.span, "borrow as raw pointer", "try", - format!("{core_or_std}::ptr::{macro_name}!({snip})"), + format!("{std_or_core}::ptr::{macro_name}!({snip})"), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/casts/ref_as_ptr.rs b/clippy_lints/src/casts/ref_as_ptr.rs index dfa240ccec623..f699bba20ed01 100644 --- a/clippy_lints/src/casts/ref_as_ptr.rs +++ b/clippy_lints/src/casts/ref_as_ptr.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; -use clippy_utils::{ExprUseNode, expr_use_ctxt, is_no_std_crate}; +use clippy_utils::{ExprUseNode, expr_use_ctxt, std_or_core}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability, Ty, TyKind}; use rustc_lint::LateContext; @@ -25,8 +25,8 @@ pub(super) fn check<'tcx>( && let use_cx = expr_use_ctxt(cx, expr) // TODO: only block the lint if `cast_expr` is a temporary && !matches!(use_cx.use_node(cx), ExprUseNode::LetStmt(_) | ExprUseNode::ConstStatic(_)) + && let Some(std_or_core) = std_or_core(cx) { - let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" }; let fn_name = match to_mutbl { Mutability::Not => "from_ref", Mutability::Mut => "from_mut", @@ -56,7 +56,7 @@ pub(super) fn check<'tcx>( expr.span, "reference as raw pointer", "try", - format!("{core_or_std}::ptr::{fn_name}{turbofish}({cast_expr_sugg})"), + format!("{std_or_core}::ptr::{fn_name}{turbofish}({cast_expr_sugg})"), app, ); } diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index d3aa2fd1ea12c..2e7f91a842e1e 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -48,7 +48,7 @@ impl CheckedConversions { impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]); -impl<'tcx> LateLintPass<'tcx> for CheckedConversions { +impl LateLintPass<'_> for CheckedConversions { fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) { if let ExprKind::Binary(op, lhs, rhs) = item.kind && let (lt1, gt1, op2) = match op.node { diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 2b229d2fe6ac5..9cec672beb004 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -202,6 +202,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::functions::MUST_USE_CANDIDATE_INFO, crate::functions::MUST_USE_UNIT_INFO, crate::functions::NOT_UNSAFE_PTR_ARG_DEREF_INFO, + crate::functions::REF_OPTION_INFO, crate::functions::RENAMED_FUNCTION_PARAMS_INFO, crate::functions::RESULT_LARGE_ERR_INFO, crate::functions::RESULT_UNIT_ERR_INFO, diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index a065dc2cf7e52..4808c372754c4 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -119,7 +119,7 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for NumericFallbackVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { match &expr.kind { ExprKind::Block( diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 35a97adfb452a..82a66cc92029b 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -385,7 +385,7 @@ fn check_unsafe_derive_deserialize<'tcx>( && cx .tcx .inherent_impls(def.did()) - .into_iter() + .iter() .map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local())) .any(|imp| has_unsafe(cx, imp)) { diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 0ae1fad569213..e090644ae4410 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -970,7 +970,7 @@ impl<'a, 'tcx> FindPanicUnwrap<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for FindPanicUnwrap<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index f4c55738cb83a..70eb81fa09c1a 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -60,7 +60,7 @@ declare_clippy_lint! { declare_lint_pass!(EmptyEnum => [EMPTY_ENUM]); -impl<'tcx> LateLintPass<'tcx> for EmptyEnum { +impl LateLintPass<'_> for EmptyEnum { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { if let ItemKind::Enum(..) = item.kind // Only suggest the `never_type` if the feature is enabled diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 5588124e791ea..a89f0d9c43274 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -141,7 +141,7 @@ fn is_argument(tcx: TyCtxt<'_>, id: HirId) -> bool { matches!(tcx.parent_hir_node(id), Node::Param(_)) } -impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { +impl<'tcx> Delegate<'tcx> for EscapeDelegate<'_, 'tcx> { fn consume(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) { if cmt.place.projections.is_empty() { if let PlaceBase::Local(lid) = cmt.place.base { @@ -188,7 +188,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} } -impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> { +impl<'tcx> EscapeDelegate<'_, 'tcx> { fn is_large_box(&self, ty: Ty<'tcx>) -> bool { // Large types need to be boxed to avoid stack overflows. if let Some(boxed_ty) = ty.boxed_ty() { diff --git a/clippy_lints/src/excessive_nesting.rs b/clippy_lints/src/excessive_nesting.rs index ce0e0faa01489..ffc76366983aa 100644 --- a/clippy_lints/src/excessive_nesting.rs +++ b/clippy_lints/src/excessive_nesting.rs @@ -135,7 +135,7 @@ impl NestingVisitor<'_, '_> { } } -impl<'conf, 'cx> Visitor<'_> for NestingVisitor<'conf, 'cx> { +impl Visitor<'_> for NestingVisitor<'_, '_> { fn visit_block(&mut self, block: &Block) { if block.span.from_expansion() { return; diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs index bf9388b4a70fd..3b93d3ff93ed4 100644 --- a/clippy_lints/src/extra_unused_type_parameters.rs +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -193,7 +193,7 @@ fn bound_to_trait_def_id(bound: &GenericBound<'_>) -> Option { bound.trait_ref()?.trait_def_id()?.as_local() } -impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> { +impl<'tcx> Visitor<'tcx> for TypeWalker<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) { diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 747ea9a434464..f822432cce63a 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -73,7 +73,7 @@ fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::Impl result: Vec, } - impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> { + impl<'tcx> Visitor<'tcx> for FindPanicUnwrap<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { if let Some(macro_call) = root_macro_call_first_node(self.lcx, expr) { if is_panic(self.lcx, macro_call.def_id) { diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 83ab9f6557bdd..4c043f8dc14b7 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -219,7 +219,7 @@ struct FormatArgsExpr<'a, 'tcx> { ignore_mixed: bool, } -impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> { +impl FormatArgsExpr<'_, '_> { fn check_templates(&self) { for piece in &self.format_args.template { if let FormatArgsPiece::Placeholder(placeholder) = piece diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index c196f404ce677..7c0515b8c5608 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -148,7 +148,7 @@ struct FormatImplExpr<'a, 'tcx> { format_trait_impl: FormatTraitNames, } -impl<'a, 'tcx> FormatImplExpr<'a, 'tcx> { +impl FormatImplExpr<'_, '_> { fn check_to_string_in_display(&self) { if self.format_trait_impl.name == sym::Display && let ExprKind::MethodCall(path, self_arg, ..) = self.expr.kind diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 8832cd42dd98f..d5a2e06863dc5 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -126,7 +126,7 @@ struct SelfFinder<'a, 'tcx> { invalid: bool, } -impl<'a, 'tcx> Visitor<'tcx> for SelfFinder<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for SelfFinder<'_, 'tcx> { type NestedFilter = OnlyBodies; fn nested_visit_map(&mut self) -> Self::Map { diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index ba8a459c917e6..91d73c2a9c962 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -2,6 +2,7 @@ mod impl_trait_in_params; mod misnamed_getters; mod must_use; mod not_unsafe_ptr_arg_deref; +mod ref_option; mod renamed_function_params; mod result; mod too_many_arguments; @@ -399,6 +400,53 @@ declare_clippy_lint! { "renamed function parameters in trait implementation" } +declare_clippy_lint! { + /// ### What it does + /// Warns when a function signature uses `&Option` instead of `Option<&T>`. + /// + /// ### Why is this bad? + /// More flexibility, better memory optimization, and more idiomatic Rust code. + /// + /// `&Option` in a function signature breaks encapsulation because the caller must own T + /// and move it into an Option to call with it. When returned, the owner must internally store + /// it as `Option` in order to return it. + /// At a lower level, `&Option` points to memory with the `presence` bit flag plus the `T` value, + /// whereas `Option<&T>` is usually [optimized](https://doc.rust-lang.org/1.81.0/std/option/index.html#representation) + /// to a single pointer, so it may be more optimal. + /// + /// See this [YouTube video](https://www.youtube.com/watch?v=6c7pZYP_iIE) by + /// Logan Smith for an in-depth explanation of why this is important. + /// + /// ### Known problems + /// This lint recommends changing the function signatures, but it cannot + /// automatically change the function calls or the function implementations. + /// + /// ### Example + /// ```no_run + /// // caller uses foo(&opt) + /// fn foo(a: &Option) {} + /// # struct Unit {} + /// # impl Unit { + /// fn bar(&self) -> &Option { &None } + /// # } + /// ``` + /// Use instead: + /// ```no_run + /// // caller should use `foo1(opt.as_ref())` + /// fn foo1(a: Option<&String>) {} + /// // better yet, use string slice `foo2(opt.as_deref())` + /// fn foo2(a: Option<&str>) {} + /// # struct Unit {} + /// # impl Unit { + /// fn bar(&self) -> Option<&String> { None } + /// # } + /// ``` + #[clippy::version = "1.82.0"] + pub REF_OPTION, + pedantic, + "function signature uses `&Option` instead of `Option<&T>`" +} + pub struct Functions { too_many_arguments_threshold: u64, too_many_lines_threshold: u64, @@ -437,6 +485,7 @@ impl_lint_pass!(Functions => [ MISNAMED_GETTERS, IMPL_TRAIT_IN_PARAMS, RENAMED_FUNCTION_PARAMS, + REF_OPTION, ]); impl<'tcx> LateLintPass<'tcx> for Functions { @@ -455,6 +504,16 @@ impl<'tcx> LateLintPass<'tcx> for Functions { not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, def_id); misnamed_getters::check_fn(cx, kind, decl, body, span); impl_trait_in_params::check_fn(cx, &kind, body, hir_id); + ref_option::check_fn( + cx, + kind, + decl, + span, + hir_id, + def_id, + body, + self.avoid_breaking_exported_api, + ); } fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { @@ -475,5 +534,6 @@ impl<'tcx> LateLintPass<'tcx> for Functions { must_use::check_trait_item(cx, item); result::check_trait_item(cx, item, self.large_error_threshold); impl_trait_in_params::check_trait_item(cx, item, self.avoid_breaking_exported_api); + ref_option::check_trait_item(cx, item, self.avoid_breaking_exported_api); } } diff --git a/clippy_lints/src/functions/ref_option.rs b/clippy_lints/src/functions/ref_option.rs new file mode 100644 index 0000000000000..373ecd74cb379 --- /dev/null +++ b/clippy_lints/src/functions/ref_option.rs @@ -0,0 +1,122 @@ +use crate::functions::REF_OPTION; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_trait_impl_item; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_hir::intravisit::FnKind; +use rustc_hir::{FnDecl, HirId}; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, GenericArgKind, Mutability, Ty}; +use rustc_span::def_id::LocalDefId; +use rustc_span::{Span, sym}; + +fn check_ty<'a>(cx: &LateContext<'a>, param: &rustc_hir::Ty<'a>, param_ty: Ty<'a>, fixes: &mut Vec<(Span, String)>) { + if let ty::Ref(_, opt_ty, Mutability::Not) = param_ty.kind() + && is_type_diagnostic_item(cx, *opt_ty, sym::Option) + && let ty::Adt(_, opt_gen) = opt_ty.kind() + && let [gen] = opt_gen.as_slice() + && let GenericArgKind::Type(gen_ty) = gen.unpack() + && !gen_ty.is_ref() + // Need to gen the original spans, so first parsing mid, and hir parsing afterward + && let hir::TyKind::Ref(lifetime, hir::MutTy { ty, .. }) = param.kind + && let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind + && let (Some(first), Some(last)) = (path.segments.first(), path.segments.last()) + && let Some(hir::GenericArgs { + args: [hir::GenericArg::Type(opt_ty)], + .. + }) = last.args + { + let lifetime = snippet(cx, lifetime.ident.span, ".."); + fixes.push(( + param.span, + format!( + "{}<&{lifetime}{}{}>", + snippet(cx, first.ident.span.to(last.ident.span), ".."), + if lifetime.is_empty() { "" } else { " " }, + snippet(cx, opt_ty.span, "..") + ), + )); + } +} + +fn check_fn_sig<'a>(cx: &LateContext<'a>, decl: &FnDecl<'a>, span: Span, sig: ty::FnSig<'a>) { + let mut fixes = Vec::new(); + // Check function arguments' types + for (param, param_ty) in decl.inputs.iter().zip(sig.inputs()) { + check_ty(cx, param, *param_ty, &mut fixes); + } + // Check return type + if let hir::FnRetTy::Return(ty) = &decl.output { + check_ty(cx, ty, sig.output(), &mut fixes); + } + if !fixes.is_empty() { + span_lint_and_then( + cx, + REF_OPTION, + span, + "it is more idiomatic to use `Option<&T>` instead of `&Option`", + |diag| { + diag.multipart_suggestion("change this to", fixes, Applicability::Unspecified); + }, + ); + } +} + +#[allow(clippy::too_many_arguments)] +pub(crate) fn check_fn<'a>( + cx: &LateContext<'a>, + kind: FnKind<'_>, + decl: &FnDecl<'a>, + span: Span, + hir_id: HirId, + def_id: LocalDefId, + body: &hir::Body<'_>, + avoid_breaking_exported_api: bool, +) { + if avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) { + return; + } + + if let FnKind::Closure = kind { + // Compute the span of the closure parameters + return type if set + let span = if let hir::FnRetTy::Return(out_ty) = &decl.output { + if decl.inputs.is_empty() { + out_ty.span + } else { + span.with_hi(out_ty.span.hi()) + } + } else if let (Some(first), Some(last)) = (decl.inputs.first(), decl.inputs.last()) { + first.span.to(last.span) + } else { + // No parameters - no point in checking + return; + }; + + // Figure out the signature of the closure + let ty::Closure(_, args) = cx.typeck_results().expr_ty(body.value).kind() else { + return; + }; + let sig = args.as_closure().sig().skip_binder(); + + check_fn_sig(cx, decl, span, sig); + } else if !is_trait_impl_item(cx, hir_id) { + let sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder(); + check_fn_sig(cx, decl, span, sig); + } +} + +pub(super) fn check_trait_item<'a>( + cx: &LateContext<'a>, + trait_item: &hir::TraitItem<'a>, + avoid_breaking_exported_api: bool, +) { + if let hir::TraitItemKind::Fn(ref sig, _) = trait_item.kind + && !(avoid_breaking_exported_api && cx.effective_visibilities.is_exported(trait_item.owner_id.def_id)) + { + let def_id = trait_item.owner_id.def_id; + let ty_sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder(); + check_fn_sig(cx, sig.decl, sig.span, ty_sig); + } +} diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index f683925145a28..4c5375730b8e3 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -281,7 +281,7 @@ impl<'a, 'tcx> ImplicitHasherTypeVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'_, 'tcx> { fn visit_ty(&mut self, t: &'tcx hir::Ty<'_>) { if let Some(target) = ImplicitHasherType::new(self.cx, t) { self.found.push(target); @@ -318,7 +318,7 @@ impl<'a, 'b, 'tcx> ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> { } } -impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> { +impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_body(&mut self, body: &Body<'tcx>) { diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 39afb6810b8e2..73ebe6aec15a0 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -226,7 +226,7 @@ struct SliceIndexLintingVisitor<'a, 'tcx> { max_suggested_slice: u64, } -impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn nested_visit_map(&mut self) -> Self::Map { diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 8bc2a56af9938..c88eb70384333 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -460,7 +460,7 @@ fn check_for_is_empty( let is_empty = cx .tcx .inherent_impls(impl_ty) - .into_iter() + .iter() .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(is_empty)) .find(|item| item.kind == AssocKind::Fn); @@ -628,7 +628,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// Checks the inherent impl's items for an `is_empty(self)` method. fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool { let is_empty = sym!(is_empty); - cx.tcx.inherent_impls(id).into_iter().any(|imp| { + cx.tcx.inherent_impls(id).iter().any(|imp| { cx.tcx .associated_items(*imp) .filter_by_name_unhygienic(is_empty) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1d41f568f3785..2eb6d99b761f7 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -609,7 +609,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |tcx| Box::new(await_holding_invalid::AwaitHolding::new(tcx, conf))); store.register_late_pass(|_| Box::new(serde_api::SerdeApi)); store.register_late_pass(move |_| Box::new(types::Types::new(conf))); - store.register_late_pass(|_| Box::new(booleans::NonminimalBool)); + store.register_late_pass(move |_| Box::new(booleans::NonminimalBool::new(conf))); store.register_late_pass(|_| Box::new(enum_clike::UnportableVariant)); store.register_late_pass(|_| Box::new(float_literal::FloatLiteral)); store.register_late_pass(|_| Box::new(ptr::Ptr)); diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 755afe959b37a..034cab7202523 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -6,12 +6,12 @@ use rustc_errors::Applicability; use rustc_hir::FnRetTy::Return; use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter}; use rustc_hir::intravisit::{ - Visitor, walk_fn_decl, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound, - walk_poly_trait_ref, walk_trait_ref, walk_ty, + Visitor, walk_fn_decl, walk_generic_args, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound, + walk_poly_trait_ref, walk_trait_ref, walk_ty, walk_where_predicate, }; use rustc_hir::{ - BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, - ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef, + BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind, Generics, + Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef, PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, lang_items, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -21,7 +21,7 @@ use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; use rustc_span::Span; use rustc_span::def_id::LocalDefId; -use rustc_span::symbol::{Ident, Symbol, kw}; +use rustc_span::symbol::{Ident, kw}; use std::ops::ControlFlow; declare_clippy_lint! { @@ -191,45 +191,10 @@ fn check_fn_inner<'tcx>( if usages.iter().any(|usage| !usage.ident.span.eq_ctxt(span)) { return; } - - let lts = elidable_lts - .iter() - // In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a - // `Node::GenericParam`. - .filter_map(|&def_id| cx.tcx.hir_node_by_def_id(def_id).ident()) - .map(|ident| ident.to_string()) - .collect::>() - .join(", "); - - span_lint_and_then( - cx, - NEEDLESS_LIFETIMES, - elidable_lts - .iter() - .map(|<| cx.tcx.def_span(lt)) - .chain(usages.iter().filter_map(|usage| { - if let LifetimeName::Param(def_id) = usage.res - && elidable_lts.contains(&def_id) - { - return Some(usage.ident.span); - } - - None - })) - .collect_vec(), - format!("the following explicit lifetimes could be elided: {lts}"), - |diag| { - if sig.header.is_async() { - // async functions have usages whose spans point at the lifetime declaration which messes up - // suggestions - return; - }; - - if let Some(suggestions) = elision_suggestions(cx, generics, &elidable_lts, &usages) { - diag.multipart_suggestion("elide the lifetimes", suggestions, Applicability::MachineApplicable); - } - }, - ); + // async functions have usages whose spans point at the lifetime declaration which messes up + // suggestions + let include_suggestions = !sig.header.is_async(); + report_elidable_lifetimes(cx, generics, &elidable_lts, &usages, include_suggestions); } if report_extra_lifetimes { @@ -237,97 +202,6 @@ fn check_fn_inner<'tcx>( } } -fn elision_suggestions( - cx: &LateContext<'_>, - generics: &Generics<'_>, - elidable_lts: &[LocalDefId], - usages: &[Lifetime], -) -> Option> { - let explicit_params = generics - .params - .iter() - .filter(|param| !param.is_elided_lifetime() && !param.is_impl_trait()) - .collect::>(); - - let mut suggestions = if elidable_lts.len() == explicit_params.len() { - // if all the params are elided remove the whole generic block - // - // fn x<'a>() {} - // ^^^^ - vec![(generics.span, String::new())] - } else { - elidable_lts - .iter() - .map(|&id| { - let pos = explicit_params.iter().position(|param| param.def_id == id)?; - let param = explicit_params.get(pos)?; - - let span = if let Some(next) = explicit_params.get(pos + 1) { - // fn x<'prev, 'a, 'next>() {} - // ^^^^ - param.span.until(next.span) - } else { - // `pos` should be at least 1 here, because the param in position 0 would either have a `next` - // param or would have taken the `elidable_lts.len() == explicit_params.len()` branch. - let prev = explicit_params.get(pos - 1)?; - - // fn x<'prev, 'a>() {} - // ^^^^ - param.span.with_lo(prev.span.hi()) - }; - - Some((span, String::new())) - }) - .collect::>>()? - }; - - suggestions.extend( - usages - .iter() - .filter(|usage| named_lifetime(usage).map_or(false, |id| elidable_lts.contains(&id))) - .map(|usage| { - match cx.tcx.parent_hir_node(usage.hir_id) { - Node::Ty(Ty { - kind: TyKind::Ref(..), .. - }) => { - // expand `&'a T` to `&'a T` - // ^^ ^^^ - let span = cx.sess().source_map().span_extend_while_whitespace(usage.ident.span); - - (span, String::new()) - }, - // `T<'a>` and `impl Foo + 'a` should be replaced by `'_` - _ => (usage.ident.span, String::from("'_")), - } - }), - ); - - Some(suggestions) -} - -// elision doesn't work for explicit self types, see rust-lang/rust#69064 -fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option) -> bool { - if let Some(ident) = ident - && ident.name == kw::SelfLower - && !func.implicit_self.has_implicit_self() - && let Some(self_ty) = func.inputs.first() - { - let mut visitor = RefVisitor::new(cx); - visitor.visit_ty(self_ty); - - !visitor.all_lts().is_empty() - } else { - false - } -} - -fn named_lifetime(lt: &Lifetime) -> Option { - match lt.res { - LifetimeName::Param(id) if !lt.is_anonymous() => Some(id), - _ => None, - } -} - fn could_use_elision<'tcx>( cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>, @@ -450,6 +324,22 @@ fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option) -> bool { + if let Some(ident) = ident + && ident.name == kw::SelfLower + && !func.implicit_self.has_implicit_self() + && let Some(self_ty) = func.inputs.first() + { + let mut visitor = RefVisitor::new(cx); + visitor.visit_ty(self_ty); + + !visitor.all_lts().is_empty() + } else { + false + } +} + /// Number of times each named lifetime occurs in the given slice. Returns a vector to preserve /// relative order. #[must_use] @@ -470,6 +360,13 @@ fn named_lifetime_occurrences(lts: &[Lifetime]) -> Vec<(LocalDefId, usize)> { occurrences } +fn named_lifetime(lt: &Lifetime) -> Option { + match lt.res { + LifetimeName::Param(id) if !lt.is_anonymous() => Some(id), + _ => None, + } +} + struct RefVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, lts: Vec, @@ -500,7 +397,7 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for RefVisitor<'_, 'tcx> { // for lifetimes as parameters of generics fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) { self.lts.push(*lifetime); @@ -594,23 +491,43 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_ false } +struct Usage { + lifetime: Lifetime, + in_where_predicate: bool, + in_generics_arg: bool, +} + struct LifetimeChecker<'cx, 'tcx, F> { cx: &'cx LateContext<'tcx>, - map: FxHashMap, + map: FxHashMap>, + where_predicate_depth: usize, + generic_args_depth: usize, phantom: std::marker::PhantomData, } impl<'cx, 'tcx, F> LifetimeChecker<'cx, 'tcx, F> { - fn new(cx: &'cx LateContext<'tcx>, map: FxHashMap) -> LifetimeChecker<'cx, 'tcx, F> { + fn new(cx: &'cx LateContext<'tcx>, generics: &'tcx Generics<'_>) -> LifetimeChecker<'cx, 'tcx, F> { + let map = generics + .params + .iter() + .filter_map(|par| match par.kind { + GenericParamKind::Lifetime { + kind: LifetimeParamKind::Explicit, + } => Some((par.def_id, Vec::new())), + _ => None, + }) + .collect(); Self { cx, map, + where_predicate_depth: 0, + generic_args_depth: 0, phantom: std::marker::PhantomData, } } } -impl<'cx, 'tcx, F> Visitor<'tcx> for LifetimeChecker<'cx, 'tcx, F> +impl<'tcx, F> Visitor<'tcx> for LifetimeChecker<'_, 'tcx, F> where F: NestedFilter<'tcx>, { @@ -619,18 +536,27 @@ where // for lifetimes as parameters of generics fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) { - self.map.remove(&lifetime.ident.name); + if let LifetimeName::Param(def_id) = lifetime.res + && let Some(usages) = self.map.get_mut(&def_id) + { + usages.push(Usage { + lifetime: *lifetime, + in_where_predicate: self.where_predicate_depth != 0, + in_generics_arg: self.generic_args_depth != 0, + }); + } } - fn visit_generic_param(&mut self, param: &'tcx GenericParam<'_>) { - // don't actually visit `<'a>` or `<'a: 'b>` - // we've already visited the `'a` declarations and - // don't want to spuriously remove them - // `'b` in `'a: 'b` is useless unless used elsewhere in - // a non-lifetime bound - if let GenericParamKind::Type { .. } = param.kind { - walk_generic_param(self, param); - } + fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) { + self.where_predicate_depth += 1; + walk_where_predicate(self, predicate); + self.where_predicate_depth -= 1; + } + + fn visit_generic_args(&mut self, generic_args: &'tcx GenericArgs<'tcx>) -> Self::Result { + self.generic_args_depth += 1; + walk_generic_args(self, generic_args); + self.generic_args_depth -= 1; } fn nested_visit_map(&mut self) -> Self::Map { @@ -639,44 +565,28 @@ where } fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>, generics: &'tcx Generics<'_>) { - let hs = generics - .params - .iter() - .filter_map(|par| match par.kind { - GenericParamKind::Lifetime { - kind: LifetimeParamKind::Explicit, - } => Some((par.name.ident().name, par.span)), - _ => None, - }) - .collect(); - let mut checker = LifetimeChecker::::new(cx, hs); + let mut checker = LifetimeChecker::::new(cx, generics); walk_generics(&mut checker, generics); walk_fn_decl(&mut checker, func); - for &v in checker.map.values() { - span_lint( - cx, - EXTRA_UNUSED_LIFETIMES, - v, - "this lifetime isn't used in the function definition", - ); + for (def_id, usages) in checker.map { + if usages + .iter() + .all(|usage| usage.in_where_predicate && !usage.in_generics_arg) + { + span_lint( + cx, + EXTRA_UNUSED_LIFETIMES, + cx.tcx.def_span(def_id), + "this lifetime isn't used in the function definition", + ); + } } } fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'_>) { - let hs = impl_ - .generics - .params - .iter() - .filter_map(|par| match par.kind { - GenericParamKind::Lifetime { - kind: LifetimeParamKind::Explicit, - } => Some((par.name.ident().name, par.span)), - _ => None, - }) - .collect(); - let mut checker = LifetimeChecker::::new(cx, hs); + let mut checker = LifetimeChecker::::new(cx, impl_.generics); walk_generics(&mut checker, impl_.generics); if let Some(ref trait_ref) = impl_.of_trait { @@ -687,9 +597,176 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<' walk_impl_item_ref(&mut checker, item); } - for &v in checker.map.values() { - span_lint(cx, EXTRA_UNUSED_LIFETIMES, v, "this lifetime isn't used in the impl"); + for (&def_id, usages) in &checker.map { + if usages + .iter() + .all(|usage| usage.in_where_predicate && !usage.in_generics_arg) + { + span_lint( + cx, + EXTRA_UNUSED_LIFETIMES, + cx.tcx.def_span(def_id), + "this lifetime isn't used in the impl", + ); + } + } + + report_elidable_impl_lifetimes(cx, impl_, &checker.map); +} + +// An `impl` lifetime is elidable if it satisfies the following conditions: +// - It is used exactly once. +// - That single use is not in `GenericArgs` in a `WherePredicate`. (Note that `GenericArgs` are +// different from `GenericParam`s.) +fn report_elidable_impl_lifetimes<'tcx>( + cx: &LateContext<'tcx>, + impl_: &'tcx Impl<'_>, + map: &FxHashMap>, +) { + let single_usages = map + .iter() + .filter_map(|(def_id, usages)| { + if let [ + Usage { + lifetime, + in_where_predicate: false, + .. + } + | Usage { + lifetime, + in_generics_arg: false, + .. + }, + ] = usages.as_slice() + { + Some((def_id, lifetime)) + } else { + None + } + }) + .collect::>(); + + if single_usages.is_empty() { + return; } + + let (elidable_lts, usages): (Vec<_>, Vec<_>) = single_usages.into_iter().unzip(); + + report_elidable_lifetimes(cx, impl_.generics, &elidable_lts, &usages, true); +} + +/// Generate diagnostic messages for elidable lifetimes. +fn report_elidable_lifetimes( + cx: &LateContext<'_>, + generics: &Generics<'_>, + elidable_lts: &[LocalDefId], + usages: &[Lifetime], + include_suggestions: bool, +) { + let lts = elidable_lts + .iter() + // In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a + // `Node::GenericParam`. + .filter_map(|&def_id| cx.tcx.hir_node_by_def_id(def_id).ident()) + .map(|ident| ident.to_string()) + .collect::>() + .join(", "); + + span_lint_and_then( + cx, + NEEDLESS_LIFETIMES, + elidable_lts + .iter() + .map(|<| cx.tcx.def_span(lt)) + .chain(usages.iter().filter_map(|usage| { + if let LifetimeName::Param(def_id) = usage.res + && elidable_lts.contains(&def_id) + { + return Some(usage.ident.span); + } + + None + })) + .collect_vec(), + format!("the following explicit lifetimes could be elided: {lts}"), + |diag| { + if !include_suggestions { + return; + }; + + if let Some(suggestions) = elision_suggestions(cx, generics, elidable_lts, usages) { + diag.multipart_suggestion("elide the lifetimes", suggestions, Applicability::MachineApplicable); + } + }, + ); +} + +fn elision_suggestions( + cx: &LateContext<'_>, + generics: &Generics<'_>, + elidable_lts: &[LocalDefId], + usages: &[Lifetime], +) -> Option> { + let explicit_params = generics + .params + .iter() + .filter(|param| !param.is_elided_lifetime() && !param.is_impl_trait()) + .collect::>(); + + let mut suggestions = if elidable_lts.len() == explicit_params.len() { + // if all the params are elided remove the whole generic block + // + // fn x<'a>() {} + // ^^^^ + vec![(generics.span, String::new())] + } else { + elidable_lts + .iter() + .map(|&id| { + let pos = explicit_params.iter().position(|param| param.def_id == id)?; + let param = explicit_params.get(pos)?; + + let span = if let Some(next) = explicit_params.get(pos + 1) { + // fn x<'prev, 'a, 'next>() {} + // ^^^^ + param.span.until(next.span) + } else { + // `pos` should be at least 1 here, because the param in position 0 would either have a `next` + // param or would have taken the `elidable_lts.len() == explicit_params.len()` branch. + let prev = explicit_params.get(pos - 1)?; + + // fn x<'prev, 'a>() {} + // ^^^^ + param.span.with_lo(prev.span.hi()) + }; + + Some((span, String::new())) + }) + .collect::>>()? + }; + + suggestions.extend( + usages + .iter() + .filter(|usage| named_lifetime(usage).map_or(false, |id| elidable_lts.contains(&id))) + .map(|usage| { + match cx.tcx.parent_hir_node(usage.hir_id) { + Node::Ty(Ty { + kind: TyKind::Ref(..), .. + }) => { + // expand `&'a T` to `&'a T` + // ^^ ^^^ + let span = cx.sess().source_map().span_extend_while_whitespace(usage.ident.span); + + (span, String::new()) + }, + // `T<'a>` and `impl Foo + 'a` should be replaced by `'_` + _ => (usage.ident.span, String::from("'_")), + } + }), + ); + + Some(suggestions) } struct BodyLifetimeChecker; diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs index a7c1d1bd6cd36..68d063ad5e54e 100644 --- a/clippy_lints/src/loops/manual_memcpy.rs +++ b/clippy_lints/src/loops/manual_memcpy.rs @@ -209,7 +209,7 @@ fn build_manual_memcpy_suggestion<'tcx>( #[derive(Clone)] struct MinifyingSugg<'a>(Sugg<'a>); -impl<'a> Display for MinifyingSugg<'a> { +impl Display for MinifyingSugg<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.0.fmt(f) } diff --git a/clippy_lints/src/loops/missing_spin_loop.rs b/clippy_lints/src/loops/missing_spin_loop.rs index e405829b2f4ba..a9944d64ce2dd 100644 --- a/clippy_lints/src/loops/missing_spin_loop.rs +++ b/clippy_lints/src/loops/missing_spin_loop.rs @@ -1,6 +1,6 @@ use super::MISSING_SPIN_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_no_std_crate; +use clippy_utils::std_or_core; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind}; use rustc_lint::LateContext; @@ -41,6 +41,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &' && [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name) && let ty::Adt(def, _args) = cx.typeck_results().expr_ty(callee).kind() && cx.tcx.is_diagnostic_item(sym::AtomicBool, def.did()) + && let Some(std_or_core) = std_or_core(cx) { span_lint_and_sugg( cx, @@ -48,12 +49,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &' body.span, "busy-waiting loop should at least have a spin loop hint", "try", - (if is_no_std_crate(cx) { - "{ core::hint::spin_loop() }" - } else { - "{ std::hint::spin_loop() }" - }) - .into(), + format!("{{ {std_or_core}::hint::spin_loop() }}"), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index 20dd5a311dca0..745f070a577d5 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -241,7 +241,7 @@ struct VarVisitor<'a, 'tcx> { prefer_mutable: bool, } -impl<'a, 'tcx> VarVisitor<'a, 'tcx> { +impl<'tcx> VarVisitor<'_, 'tcx> { fn check(&mut self, idx: &'tcx Expr<'_>, seqexpr: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) -> bool { if let ExprKind::Path(ref seqpath) = seqexpr.kind // the indexed container is referenced by a name @@ -292,7 +292,7 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for VarVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { if let ExprKind::MethodCall(meth, args_0, [args_1, ..], _) = &expr.kind // a range index op diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index 5662d3013e15b..f8659897ffe97 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -123,7 +123,7 @@ impl<'a, 'tcx> SameItemPushVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for SameItemPushVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { match &expr.kind { // Non-determinism may occur ... don't give a lint diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs index 9a89a41d2b395..c4c504e1ae4ff 100644 --- a/clippy_lints/src/loops/utils.rs +++ b/clippy_lints/src/loops/utils.rs @@ -44,7 +44,7 @@ impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for IncrementVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { // If node is a variable if let Some(def_id) = path_to_local(expr) { @@ -138,7 +138,7 @@ impl<'a, 'tcx> InitializeVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for InitializeVisitor<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_local(&mut self, l: &'tcx LetStmt<'_>) { diff --git a/clippy_lints/src/loops/while_immutable_condition.rs b/clippy_lints/src/loops/while_immutable_condition.rs index eab096e9a227d..1a1cde3c5bd63 100644 --- a/clippy_lints/src/loops/while_immutable_condition.rs +++ b/clippy_lints/src/loops/while_immutable_condition.rs @@ -84,7 +84,7 @@ struct VarCollectorVisitor<'a, 'tcx> { skip: bool, } -impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> { +impl<'tcx> VarCollectorVisitor<'_, 'tcx> { fn insert_def_id(&mut self, ex: &'tcx Expr<'_>) { if let ExprKind::Path(ref qpath) = ex.kind && let QPath::Resolved(None, _) = *qpath @@ -103,7 +103,7 @@ impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for VarCollectorVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for VarCollectorVisitor<'_, 'tcx> { fn visit_expr(&mut self, ex: &'tcx Expr<'_>) { match ex.kind { ExprKind::Path(_) => self.insert_def_id(ex), diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index 7d9fbaf3ceabf..74467522619e9 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -283,7 +283,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: & found_local: bool, used_after: bool, } - impl<'a, 'b, 'tcx> Visitor<'tcx> for NestedLoopVisitor<'a, 'b, 'tcx> { + impl<'tcx> Visitor<'tcx> for NestedLoopVisitor<'_, '_, 'tcx> { type NestedFilter = OnlyBodies; fn nested_visit_map(&mut self) -> Self::Map { self.cx.tcx.hir() diff --git a/clippy_lints/src/macro_metavars_in_unsafe.rs b/clippy_lints/src/macro_metavars_in_unsafe.rs index ccc554042d685..312bcb55a9533 100644 --- a/clippy_lints/src/macro_metavars_in_unsafe.rs +++ b/clippy_lints/src/macro_metavars_in_unsafe.rs @@ -149,7 +149,7 @@ fn is_public_macro(cx: &LateContext<'_>, def_id: LocalDefId) -> bool { && !cx.tcx.is_doc_hidden(def_id) } -impl<'a, 'tcx> Visitor<'tcx> for BodyVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for BodyVisitor<'_, 'tcx> { fn visit_stmt(&mut self, s: &'tcx Stmt<'tcx>) { let from_expn = s.span.from_expansion(); if from_expn { diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index bd6b3f1a47b16..50680331fbc4e 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -81,7 +81,7 @@ impl MacroUseImports { } } -impl<'tcx> LateLintPass<'tcx> for MacroUseImports { +impl LateLintPass<'_> for MacroUseImports { fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { if cx.sess().opts.edition >= Edition::Edition2018 && let hir::ItemKind::Use(path, _kind) = &item.kind diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index 788649fd4f90e..fd66cacdfe933 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -741,7 +741,7 @@ enum MaybeBorrowedStmtKind<'a> { Owned(StmtKind<'a>), } -impl<'a> Clone for MaybeBorrowedStmtKind<'a> { +impl Clone for MaybeBorrowedStmtKind<'_> { fn clone(&self) -> Self { match self { Self::Borrowed(t) => Self::Borrowed(t), diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 9aceca66bf774..828c5a3f6ffd2 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -203,7 +203,7 @@ fn find_stripping<'tcx>( results: Vec, } - impl<'a, 'tcx> Visitor<'tcx> for StrippingFinder<'a, 'tcx> { + impl<'tcx> Visitor<'tcx> for StrippingFinder<'_, 'tcx> { fn visit_expr(&mut self, ex: &'tcx Expr<'_>) { if is_ref_str(self.cx, ex) && let unref = peel_ref(ex) diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index a97dbbbc33fd0..3221a04d2d03f 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -251,7 +251,7 @@ fn lint_map_unit_fn( } } -impl<'tcx> LateLintPass<'tcx> for MapUnit { +impl LateLintPass<'_> for MapUnit { fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) { if let hir::StmtKind::Semi(expr) = stmt.kind && !stmt.span.from_expansion() diff --git a/clippy_lints/src/matches/match_str_case_mismatch.rs b/clippy_lints/src/matches/match_str_case_mismatch.rs index 40518ce2ca775..463aa602bc8b9 100644 --- a/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/clippy_lints/src/matches/match_str_case_mismatch.rs @@ -40,7 +40,7 @@ struct MatchExprVisitor<'a, 'tcx> { case_method: Option, } -impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for MatchExprVisitor<'_, 'tcx> { fn visit_expr(&mut self, ex: &'tcx Expr<'_>) { match ex.kind { ExprKind::MethodCall(segment, receiver, [], _) if self.case_altered(segment.ident.as_str(), receiver) => {}, @@ -49,7 +49,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> MatchExprVisitor<'a, 'tcx> { +impl MatchExprVisitor<'_, '_> { fn case_altered(&mut self, segment_ident: &str, receiver: &Expr<'_>) -> bool { if let Some(case_method) = get_case_method(segment_ident) { let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs(); diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 686fc4a0fa0a5..28adcc2f22746 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -1045,7 +1045,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { if !from_expansion { // These don't depend on a relationship between multiple arms match_wild_err_arm::check(cx, ex, arms); - wild_in_or_pats::check(cx, arms); + wild_in_or_pats::check(cx, ex, arms); } if let MatchSource::TryDesugar(_) = source { diff --git a/clippy_lints/src/matches/overlapping_arms.rs b/clippy_lints/src/matches/overlapping_arms.rs index 6a4c553cee0ee..856311899f268 100644 --- a/clippy_lints/src/matches/overlapping_arms.rs +++ b/clippy_lints/src/matches/overlapping_arms.rs @@ -96,13 +96,13 @@ where #[derive(Copy, Clone, Debug, Eq, PartialEq)] struct RangeBound<'a, T>(T, BoundKind, &'a SpannedRange); - impl<'a, T: Copy + Ord> PartialOrd for RangeBound<'a, T> { + impl PartialOrd for RangeBound<'_, T> { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } - impl<'a, T: Copy + Ord> Ord for RangeBound<'a, T> { + impl Ord for RangeBound<'_, T> { fn cmp(&self, RangeBound(other_value, other_kind, _): &Self) -> Ordering { let RangeBound(self_value, self_kind, _) = *self; (self_value, self_kind).cmp(&(*other_value, *other_kind)) diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index 537f7272f7f34..7372f52e1e5bd 100644 --- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -424,7 +424,7 @@ fn ty_has_erased_regions(ty: Ty<'_>) -> bool { ty.visit_with(&mut V).is_break() } -impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for SigDropHelper<'_, 'tcx> { fn visit_expr(&mut self, ex: &'tcx Expr<'_>) { // We've emitted a lint on some neighborhood expression. That lint will suggest to move out the // _parent_ expression (not the expression itself). Since we decide to move out the parent @@ -495,7 +495,7 @@ fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &[&'tcx Expr helper.found_sig_drop_spans } -impl<'a, 'tcx> Visitor<'tcx> for ArmSigDropHelper<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for ArmSigDropHelper<'_, 'tcx> { fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { if self.sig_drop_checker.is_sig_drop_expr(ex) { self.found_sig_drop_spans.insert(ex.span); diff --git a/clippy_lints/src/matches/wild_in_or_pats.rs b/clippy_lints/src/matches/wild_in_or_pats.rs index 459513e65bfad..390ba889fd2e6 100644 --- a/clippy_lints/src/matches/wild_in_or_pats.rs +++ b/clippy_lints/src/matches/wild_in_or_pats.rs @@ -1,11 +1,19 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::is_wild; -use rustc_hir::{Arm, PatKind}; +use clippy_utils::{has_non_exhaustive_attr, is_wild}; +use rustc_hir::{Arm, Expr, PatKind}; use rustc_lint::LateContext; +use rustc_middle::ty; use super::WILDCARD_IN_OR_PATTERNS; -pub(crate) fn check(cx: &LateContext<'_>, arms: &[Arm<'_>]) { +pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arms: &[Arm<'_>]) { + // first check if we are matching on an enum that has the non_exhaustive attribute + let ty = cx.typeck_results().expr_ty(expr).peel_refs(); + if let ty::Adt(adt_def, _) = ty.kind() + && has_non_exhaustive_attr(cx.tcx, *adt_def) + { + return; + }; for arm in arms { if let PatKind::Or(fields) = arm.pat.kind { // look for multiple fields in this arm that contains at least one Wild pattern diff --git a/clippy_lints/src/methods/mut_mutex_lock.rs b/clippy_lints/src/methods/mut_mutex_lock.rs index 83e8370f939bc..320523aceb675 100644 --- a/clippy_lints/src/methods/mut_mutex_lock.rs +++ b/clippy_lints/src/methods/mut_mutex_lock.rs @@ -1,17 +1,17 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::expr_custom_deref_adjustment; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; -use rustc_middle::ty; use rustc_span::{Span, sym}; use super::MUT_MUTEX_LOCK; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'tcx Expr<'tcx>, name_span: Span) { if matches!(expr_custom_deref_adjustment(cx, recv), None | Some(Mutability::Mut)) - && let ty::Ref(_, _, Mutability::Mut) = cx.typeck_results().expr_ty(recv).kind() + && let (_, ref_depth, Mutability::Mut) = peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(recv)) + && ref_depth >= 1 && let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id) && let Some(impl_id) = cx.tcx.impl_of_method(method_id) && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Mutex) diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 421c7a5e070d9..c58e27e37ad31 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -441,7 +441,7 @@ struct UsedCountVisitor<'a, 'tcx> { count: usize, } -impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for UsedCountVisitor<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index b160ab6de8e95..528e2204cf8f7 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -130,7 +130,7 @@ struct UnwrapVisitor<'a, 'tcx> { identifiers: FxHashSet, } -impl<'a, 'tcx> Visitor<'tcx> for UnwrapVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for UnwrapVisitor<'_, 'tcx> { type NestedFilter = nested_filter::All; fn visit_path(&mut self, path: &Path<'tcx>, _: HirId) { @@ -154,7 +154,7 @@ struct ReferenceVisitor<'a, 'tcx> { unwrap_or_span: Span, } -impl<'a, 'tcx> Visitor<'tcx> for ReferenceVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for ReferenceVisitor<'_, 'tcx> { type NestedFilter = nested_filter::All; type Result = ControlFlow<()>; fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'_>) -> ControlFlow<()> { diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index c60a839432c97..b971f60d41699 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -77,7 +77,7 @@ pub(super) fn check<'tcx>( let Some(suggested_method_def_id) = receiver_ty.ty_adt_def().and_then(|adt_def| { cx.tcx .inherent_impls(adt_def.did()) - .into_iter() + .iter() .flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg)) .find_map(|assoc| { if assoc.fn_has_self_parameter diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index 4e33dc1df54d8..cf0ee569f1310 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -86,7 +86,7 @@ struct CloneOrCopyVisitor<'cx, 'tcx> { references_to_binding: Vec<(Span, String)>, } -impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> { +impl<'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn nested_visit_map(&mut self) -> Self::Map { @@ -123,7 +123,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> { } } -impl<'cx, 'tcx> CloneOrCopyVisitor<'cx, 'tcx> { +impl<'tcx> CloneOrCopyVisitor<'_, 'tcx> { fn is_binding(&self, expr: &Expr<'tcx>) -> bool { self.binding_hir_ids .iter() diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index d333b71edb1ae..a7452c8a3c84e 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -116,7 +116,7 @@ struct DivergenceVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, } -impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> { +impl<'tcx> DivergenceVisitor<'_, 'tcx> { fn maybe_walk_expr(&mut self, e: &'tcx Expr<'_>) { match e.kind { ExprKind::Closure(..) | ExprKind::If(..) | ExprKind::Loop(..) => {}, @@ -148,7 +148,7 @@ fn stmt_might_diverge(stmt: &Stmt<'_>) -> bool { !matches!(stmt.kind, StmtKind::Item(..)) } -impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for DivergenceVisitor<'_, 'tcx> { fn visit_expr(&mut self, e: &'tcx Expr<'_>) { match e.kind { // fix #10776 @@ -321,7 +321,7 @@ struct ReadVisitor<'a, 'tcx> { last_expr: &'tcx Expr<'tcx>, } -impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for ReadVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { if expr.hir_id == self.last_expr.hir_id { return; diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index 60372121a7a4c..6cddd7ea813b2 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -55,7 +55,7 @@ pub struct MutVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, } -impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> { +impl<'tcx> intravisit::Visitor<'tcx> for MutVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { if in_external_macro(self.cx.sess(), expr.span) { return; diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index 785bf70a3ec9f..152635a5c35c7 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -87,7 +87,7 @@ impl<'a, 'tcx> MutArgVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for MutArgVisitor<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index b54eb164e81d5..93e20f37ef8ac 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -133,7 +133,7 @@ struct RetCollector { loop_depth: u16, } -impl<'tcx> Visitor<'tcx> for RetCollector { +impl Visitor<'_> for RetCollector { fn visit_expr(&mut self, expr: &Expr<'_>) { match expr.kind { ExprKind::Ret(..) => { diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index 19cbf59590840..c2facb2fcf68c 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -311,7 +311,7 @@ struct MutablyUsedVariablesCtxt<'tcx> { tcx: TyCtxt<'tcx>, } -impl<'tcx> MutablyUsedVariablesCtxt<'tcx> { +impl MutablyUsedVariablesCtxt<'_> { fn add_mutably_used_var(&mut self, used_id: HirId) { self.mutably_used_vars.insert(used_id); } diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index d85032e9eee84..2fee1c72a91b5 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -104,7 +104,7 @@ struct SimilarNamesLocalVisitor<'a, 'tcx> { single_char_names: Vec>, } -impl<'a, 'tcx> SimilarNamesLocalVisitor<'a, 'tcx> { +impl SimilarNamesLocalVisitor<'_, '_> { fn check_single_char_names(&self) { if self.single_char_names.last().map(Vec::len) == Some(0) { return; @@ -152,7 +152,7 @@ fn chars_are_similar(a: char, b: char) -> bool { struct SimilarNamesNameVisitor<'a, 'tcx, 'b>(&'b mut SimilarNamesLocalVisitor<'a, 'tcx>); -impl<'a, 'tcx, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> { +impl<'tcx> Visitor<'tcx> for SimilarNamesNameVisitor<'_, 'tcx, '_> { fn visit_pat(&mut self, pat: &'tcx Pat) { match pat.kind { PatKind::Ident(_, ident, _) => { @@ -189,7 +189,7 @@ fn allowed_to_be_similar(interned_name: &str, list: &[&str]) -> bool { .any(|&name| interned_name.starts_with(name) || interned_name.ends_with(name)) } -impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { +impl SimilarNamesNameVisitor<'_, '_, '_> { fn check_short_ident(&mut self, ident: Ident) { // Ignore shadowing if self @@ -329,7 +329,7 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { } } -impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> { +impl SimilarNamesLocalVisitor<'_, '_> { /// ensure scoping rules work fn apply Fn(&'c mut Self)>(&mut self, f: F) { let n = self.names.len(); @@ -340,7 +340,7 @@ impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> { } } -impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'_, 'tcx> { fn visit_local(&mut self, local: &'tcx Local) { if let Some((init, els)) = &local.kind.init_else_opt() { self.apply(|this| walk_expr(this, init)); diff --git a/clippy_lints/src/non_send_fields_in_send_ty.rs b/clippy_lints/src/non_send_fields_in_send_ty.rs index a60988ac5dbc2..793eb5d945603 100644 --- a/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -159,7 +159,7 @@ struct NonSendField<'tcx> { generic_params: Vec>, } -impl<'tcx> NonSendField<'tcx> { +impl NonSendField<'_> { fn generic_params_string(&self) -> String { self.generic_params .iter() diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 75d8c09f2b08d..1bddfab39c694 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -110,7 +110,7 @@ pub struct PassByRefOrValue { avoid_breaking_exported_api: bool, } -impl<'tcx> PassByRefOrValue { +impl PassByRefOrValue { pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { let ref_min_size = conf.trivial_copy_size_limit.unwrap_or_else(|| { let bit_width = u64::from(tcx.sess.target.pointer_width); @@ -130,7 +130,7 @@ impl<'tcx> PassByRefOrValue { } } - fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, def_id: LocalDefId, decl: &FnDecl<'_>, span: Option) { + fn check_poly_fn(&mut self, cx: &LateContext<'_>, def_id: LocalDefId, decl: &FnDecl<'_>, span: Option) { if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) { return; } diff --git a/clippy_lints/src/pathbuf_init_then_push.rs b/clippy_lints/src/pathbuf_init_then_push.rs index 1b9a5a4438297..9f84686a0b12e 100644 --- a/clippy_lints/src/pathbuf_init_then_push.rs +++ b/clippy_lints/src/pathbuf_init_then_push.rs @@ -60,7 +60,7 @@ struct PathbufPushSearcher<'tcx> { err_span: Span, } -impl<'tcx> PathbufPushSearcher<'tcx> { +impl PathbufPushSearcher<'_> { /// Try to generate a suggestion with `PathBuf::from`. /// Returns `None` if the suggestion would be invalid. fn gen_pathbuf_from(&self, cx: &LateContext<'_>) -> Option { diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 807636bb642b2..bb8a9b6fca85b 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -271,14 +271,18 @@ fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id() && let Some(name) = cx.tcx.get_diagnostic_name(fun_def_id) { + // TODO: `ptr_slice_from_raw_parts` and its mutable variant should probably still be linted + // conditionally based on how the return value is used, but not universally like the other + // functions since there are valid uses for null slice pointers. + // + // See: https://github.com/rust-lang/rust-clippy/pull/13452/files#r1773772034 + // `arg` positions where null would cause U.B. let arg_indices: &[_] = match name { sym::ptr_read | sym::ptr_read_unaligned | sym::ptr_read_volatile | sym::ptr_replace - | sym::ptr_slice_from_raw_parts - | sym::ptr_slice_from_raw_parts_mut | sym::ptr_write | sym::ptr_write_bytes | sym::ptr_write_unaligned diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index 6930a01d48be4..41a44de536b15 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -228,7 +228,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { path: &'tcx hir::Path<'tcx>, count: usize, } - impl<'a, 'tcx> Visitor<'tcx> for ClosureUsageCount<'a, 'tcx> { + impl<'tcx> Visitor<'tcx> for ClosureUsageCount<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 3754fdddedfd1..1f223048ce5ce 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -140,7 +140,7 @@ enum RetReplacement<'tcx> { Expr(Cow<'tcx, str>, Applicability), } -impl<'tcx> RetReplacement<'tcx> { +impl RetReplacement<'_> { fn sugg_help(&self) -> &'static str { match self { Self::Empty | Self::Expr(..) => "remove `return`", @@ -158,7 +158,7 @@ impl<'tcx> RetReplacement<'tcx> { } } -impl<'tcx> Display for RetReplacement<'tcx> { +impl Display for RetReplacement<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Empty => write!(f, ""), @@ -421,7 +421,7 @@ fn check_final_expr<'tcx>( if matches!(Level::from_attr(attr), Some(Level::Expect(_))) && let metas = attr.meta_item_list() && let Some(lst) = metas - && let [NestedMetaItem::MetaItem(meta_item)] = lst.as_slice() + && let [NestedMetaItem::MetaItem(meta_item), ..] = lst.as_slice() && let [tool, lint_name] = meta_item.path.segments.as_slice() && tool.ident.name == sym::clippy && matches!( diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index d1114cb29f7a3..0eece9221438a 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -249,7 +249,7 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx } } -impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx> { +impl<'tcx> Visitor<'tcx> for StmtsChecker<'_, '_, '_, '_, 'tcx> { fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) { self.ap.curr_block_hir_id = block.hir_id; self.ap.curr_block_span = block.span; diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index c986c3e8aa6e8..9fdee8543a854 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -102,7 +102,7 @@ struct ImportUsageVisitor { imports_referenced_with_self: Vec, } -impl<'tcx> Visitor<'tcx> for ImportUsageVisitor { +impl Visitor<'_> for ImportUsageVisitor { fn visit_expr(&mut self, expr: &Expr) { if let ExprKind::Path(_, path) = &expr.kind && path.segments.len() > 1 diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 5129bbf26655e..fc799cad67e8b 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -229,7 +229,7 @@ struct VectorInitializationVisitor<'a, 'tcx> { initialization_found: bool, } -impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { +impl<'tcx> VectorInitializationVisitor<'_, 'tcx> { /// Checks if the given expression is extending a vector with `repeat(0).take(..)` fn search_slow_extend_filling(&mut self, expr: &'tcx Expr<'_>) { if self.initialization_found @@ -299,7 +299,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for VectorInitializationVisitor<'_, 'tcx> { fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) { if self.initialization_found { match stmt.kind { diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index e05fa4095b8e3..a3145c4647cab 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -332,7 +332,7 @@ struct IndexBinding<'a, 'tcx> { applicability: &'a mut Applicability, } -impl<'a, 'tcx> IndexBinding<'a, 'tcx> { +impl<'tcx> IndexBinding<'_, 'tcx> { fn snippet_index_bindings(&mut self, exprs: &[&'tcx Expr<'tcx>]) -> String { let mut bindings = FxHashSet::default(); for expr in exprs { diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index 104be63bb1579..c7c837de505e4 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -275,12 +275,15 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec>, focus_idx: us |k, ps1, idx| matches!( k, TupleStruct(qself2, path2, ps2) - if eq_maybe_qself(qself1, qself2) && eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx) + if eq_maybe_qself(qself1.as_ref(), qself2.as_ref()) + && eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx) ), |k| always_pat!(k, TupleStruct(_, _, ps) => ps), ), // Transform a record pattern `S { fp_0, ..., fp_n }`. - Struct(qself1, path1, fps1, rest1) => extend_with_struct_pat(qself1, path1, fps1, *rest1, start, alternatives), + Struct(qself1, path1, fps1, rest1) => { + extend_with_struct_pat(qself1.as_ref(), path1, fps1, *rest1, start, alternatives) + }, }; alternatives[focus_idx].kind = focus_kind; @@ -292,7 +295,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec>, focus_idx: us /// So when we fixate on some `ident_k: pat_k`, we try to find `ident_k` in the other pattern /// and check that all `fp_i` where `i ∈ ((0...n) \ k)` between two patterns are equal. fn extend_with_struct_pat( - qself1: &Option>, + qself1: Option<&P>, path1: &ast::Path, fps1: &mut [ast::PatField], rest1: ast::PatFieldsRest, @@ -307,7 +310,7 @@ fn extend_with_struct_pat( |k| { matches!(k, Struct(qself2, path2, fps2, rest2) if rest1 == *rest2 // If one struct pattern has `..` so must the other. - && eq_maybe_qself(qself1, qself2) + && eq_maybe_qself(qself1, qself2.as_ref()) && eq_path(path1, path2) && fps1.len() == fps2.len() && fps1.iter().enumerate().all(|(idx_1, fp1)| { diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs index a1f08cf6623bc..c899b1868a6cf 100644 --- a/clippy_lints/src/unused_async.rs +++ b/clippy_lints/src/unused_async.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::is_def_id_trait_method; use rustc_hir::def::DefKind; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn}; -use rustc_hir::{Body, Expr, ExprKind, FnDecl, Node, YieldSource}; +use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, Node, YieldSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_session::impl_lint_pass; @@ -67,7 +67,7 @@ struct AsyncFnVisitor<'a, 'tcx> { async_depth: usize, } -impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for AsyncFnVisitor<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { @@ -137,17 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync { } } - fn check_path(&mut self, cx: &LateContext<'tcx>, path: &rustc_hir::Path<'tcx>, hir_id: rustc_hir::HirId) { - fn is_node_func_call(node: Node<'_>, expected_receiver: Span) -> bool { - matches!( - node, - Node::Expr(Expr { - kind: ExprKind::Call(Expr { span, .. }, _) | ExprKind::MethodCall(_, Expr { span, .. }, ..), - .. - }) if *span == expected_receiver - ) - } - + fn check_path(&mut self, cx: &LateContext<'tcx>, path: &rustc_hir::Path<'tcx>, hir_id: HirId) { // Find paths to local async functions that aren't immediately called. // E.g. `async fn f() {}; let x = f;` // Depending on how `x` is used, f's asyncness might be required despite not having any `await` @@ -156,7 +146,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync { && let Some(local_def_id) = def_id.as_local() && cx.tcx.def_kind(def_id) == DefKind::Fn && cx.tcx.asyncness(def_id).is_async() - && !is_node_func_call(cx.tcx.parent_hir_node(hir_id), path.span) + && let parent = cx.tcx.parent_hir_node(hir_id) + && !matches!( + parent, + Node::Expr(Expr { + kind: ExprKind::Call(Expr { span, .. }, _), + .. + }) if *span == path.span + ) { self.async_fns_as_value.insert(local_def_id); } diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 596f0fd9c8b02..6fe660b6a479f 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -235,7 +235,7 @@ impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx> { fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} } -impl<'a, 'tcx> UnwrappableVariablesVisitor<'a, 'tcx> { +impl<'tcx> UnwrappableVariablesVisitor<'_, 'tcx> { fn visit_branch( &mut self, if_expr: &'tcx Expr<'_>, @@ -288,7 +288,7 @@ fn consume_option_as_ref<'tcx>(expr: &'tcx Expr<'tcx>) -> (&'tcx Expr<'tcx>, Opt } } -impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index e340b419bd07b..08449de79b364 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -280,7 +280,7 @@ struct SkipTyCollector { types_to_skip: Vec, } -impl<'tcx> Visitor<'tcx> for SkipTyCollector { +impl Visitor<'_> for SkipTyCollector { fn visit_infer(&mut self, inf: &hir::InferArg) { self.types_to_skip.push(inf.hir_id); diff --git a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs index 7c2e23995c1d3..9e400d2391f02 100644 --- a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs +++ b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs @@ -80,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { && let ty = cx.tcx.type_of(item_def_id).instantiate_identity() && match_type(cx, ty, &paths::SYMBOL) && let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id) - && let Ok(value) = value.to_u32() + && let Some(value) = value.to_u32().discard_err() { self.symbol_map.insert(value, item_def_id); } diff --git a/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/clippy_lints/src/utils/internal_lints/invalid_paths.rs index d444ad45087cf..96397375d5edb 100644 --- a/clippy_lints/src/utils/internal_lints/invalid_paths.rs +++ b/clippy_lints/src/utils/internal_lints/invalid_paths.rs @@ -72,8 +72,7 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool { SimplifiedType::Bool, ] .iter() - .flat_map(|&ty| cx.tcx.incoherent_impls(ty).into_iter()) - .flatten() + .flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter()) .copied(); for item_def_id in lang_items.iter().map(|(_, def_id)| def_id).chain(incoherent_impls) { let lang_item_path = cx.get_def_path(item_def_id); diff --git a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs index 7c45a5b2f0971..dd45602221267 100644 --- a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs @@ -270,7 +270,7 @@ struct LintCollector<'a, 'tcx> { cx: &'a LateContext<'tcx>, } -impl<'a, 'tcx> Visitor<'tcx> for LintCollector<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for LintCollector<'_, 'tcx> { type NestedFilter = nested_filter::All; fn visit_path(&mut self, path: &Path<'_>, _: HirId) { diff --git a/clippy_lints/src/zombie_processes.rs b/clippy_lints/src/zombie_processes.rs index ba2a80ee66b05..8d9241cc7d9a2 100644 --- a/clippy_lints/src/zombie_processes.rs +++ b/clippy_lints/src/zombie_processes.rs @@ -6,6 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_local}; use rustc_hir::{Expr, ExprKind, HirId, LetStmt, Node, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::nested_filter; use rustc_session::declare_lint_pass; use rustc_span::sym; use std::ops::ControlFlow; @@ -118,7 +119,8 @@ enum WaitFinder<'a, 'tcx> { Found(&'a LateContext<'tcx>, HirId), } -impl<'a, 'tcx> Visitor<'tcx> for WaitFinder<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> { + type NestedFilter = nested_filter::OnlyBodies; type Result = ControlFlow; fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) -> Self::Result { @@ -204,6 +206,11 @@ impl<'a, 'tcx> Visitor<'tcx> for WaitFinder<'a, 'tcx> { walk_expr(self, ex) } + + fn nested_visit_map(&mut self) -> Self::Map { + let (Self::Found(cx, _) | Self::WalkUpTo(cx, _)) = self; + cx.tcx.hir() + } } /// This function has shared logic between the different kinds of nodes that can trigger the lint. @@ -300,7 +307,7 @@ struct ExitPointFinder<'a, 'tcx> { struct ExitCallFound; -impl<'a, 'tcx> Visitor<'tcx> for ExitPointFinder<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for ExitPointFinder<'_, 'tcx> { type Result = ControlFlow; fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> Self::Result { diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 49323492e124d..68f74e52ed7b7 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -37,20 +37,27 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool { (_, Paren(r)) => eq_pat(l, r), (Wild, Wild) | (Rest, Rest) => true, (Lit(l), Lit(r)) => eq_expr(l, r), - (Ident(b1, i1, s1), Ident(b2, i2, s2)) => b1 == b2 && eq_id(*i1, *i2) && both(s1, s2, |l, r| eq_pat(l, r)), + (Ident(b1, i1, s1), Ident(b2, i2, s2)) => { + b1 == b2 && eq_id(*i1, *i2) && both(s1.as_deref(), s2.as_deref(), eq_pat) + }, (Range(lf, lt, le), Range(rf, rt, re)) => { - eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt) && eq_range_end(&le.node, &re.node) + eq_expr_opt(lf.as_ref(), rf.as_ref()) + && eq_expr_opt(lt.as_ref(), rt.as_ref()) + && eq_range_end(&le.node, &re.node) }, (Box(l), Box(r)) | (Ref(l, Mutability::Not), Ref(r, Mutability::Not)) | (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r), (Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, |l, r| eq_pat(l, r)), - (Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp), + (Path(lq, lp), Path(rq, rp)) => both(lq.as_ref(), rq.as_ref(), eq_qself) && eq_path(lp, rp), (TupleStruct(lqself, lp, lfs), TupleStruct(rqself, rp, rfs)) => { - eq_maybe_qself(lqself, rqself) && eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)) + eq_maybe_qself(lqself.as_ref(), rqself.as_ref()) && eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)) }, (Struct(lqself, lp, lfs, lr), Struct(rqself, rp, rfs, rr)) => { - lr == rr && eq_maybe_qself(lqself, rqself) && eq_path(lp, rp) && unordered_over(lfs, rfs, eq_field_pat) + lr == rr + && eq_maybe_qself(lqself.as_ref(), rqself.as_ref()) + && eq_path(lp, rp) + && unordered_over(lfs, rfs, eq_field_pat) }, (Or(ls), Or(rs)) => unordered_over(ls, rs, |l, r| eq_pat(l, r)), (MacCall(l), MacCall(r)) => eq_mac_call(l, r), @@ -79,7 +86,7 @@ pub fn eq_qself(l: &P, r: &P) -> bool { l.position == r.position && eq_ty(&l.ty, &r.ty) } -pub fn eq_maybe_qself(l: &Option>, r: &Option>) -> bool { +pub fn eq_maybe_qself(l: Option<&P>, r: Option<&P>) -> bool { match (l, r) { (Some(l), Some(r)) => eq_qself(l, r), (None, None) => true, @@ -92,7 +99,7 @@ pub fn eq_path(l: &Path, r: &Path) -> bool { } pub fn eq_path_seg(l: &PathSegment, r: &PathSegment) -> bool { - eq_id(l.ident, r.ident) && both(&l.args, &r.args, |l, r| eq_generic_args(l, r)) + eq_id(l.ident, r.ident) && both(l.args.as_ref(), r.args.as_ref(), |l, r| eq_generic_args(l, r)) } pub fn eq_generic_args(l: &GenericArgs, r: &GenericArgs) -> bool { @@ -122,7 +129,7 @@ pub fn eq_generic_arg(l: &GenericArg, r: &GenericArg) -> bool { } } -pub fn eq_expr_opt(l: &Option>, r: &Option>) -> bool { +pub fn eq_expr_opt(l: Option<&P>, r: Option<&P>) -> bool { both(l, r, |l, r| eq_expr(l, r)) } @@ -169,8 +176,12 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (Lit(l), Lit(r)) => l == r, (Cast(l, lt), Cast(r, rt)) | (Type(l, lt), Type(r, rt)) => eq_expr(l, r) && eq_ty(lt, rt), (Let(lp, le, _, _), Let(rp, re, _, _)) => eq_pat(lp, rp) && eq_expr(le, re), - (If(lc, lt, le), If(rc, rt, re)) => eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le, re), - (While(lc, lt, ll), While(rc, rt, rl)) => eq_label(ll, rl) && eq_expr(lc, rc) && eq_block(lt, rt), + (If(lc, lt, le), If(rc, rt, re)) => { + eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()) + }, + (While(lc, lt, ll), While(rc, rt, rl)) => { + eq_label(ll.as_ref(), rl.as_ref()) && eq_expr(lc, rc) && eq_block(lt, rt) + }, ( ForLoop { pat: lp, @@ -186,13 +197,13 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { label: rl, kind: rk, }, - ) => eq_label(ll, rl) && eq_pat(lp, rp) && eq_expr(li, ri) && eq_block(lt, rt) && lk == rk, - (Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll, rl) && eq_block(lt, rt), - (Block(lb, ll), Block(rb, rl)) => eq_label(ll, rl) && eq_block(lb, rb), + ) => eq_label(ll.as_ref(), rl.as_ref()) && eq_pat(lp, rp) && eq_expr(li, ri) && eq_block(lt, rt) && lk == rk, + (Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lt, rt), + (Block(lb, ll), Block(rb, rl)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lb, rb), (TryBlock(l), TryBlock(r)) => eq_block(l, r), - (Yield(l), Yield(r)) | (Ret(l), Ret(r)) => eq_expr_opt(l, r), - (Break(ll, le), Break(rl, re)) => eq_label(ll, rl) && eq_expr_opt(le, re), - (Continue(ll), Continue(rl)) => eq_label(ll, rl), + (Yield(l), Yield(r)) | (Ret(l), Ret(r)) => eq_expr_opt(l.as_ref(), r.as_ref()), + (Break(ll, le), Break(rl, re)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_expr_opt(le.as_ref(), re.as_ref()), + (Continue(ll), Continue(rl)) => eq_label(ll.as_ref(), rl.as_ref()), (Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2, _), Index(r1, r2, _)) => { eq_expr(l1, r1) && eq_expr(l2, r2) }, @@ -227,12 +238,14 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { && eq_expr(le, re) }, (Gen(lc, lb, lk, _), Gen(rc, rb, rk, _)) => lc == rc && eq_block(lb, rb) && lk == rk, - (Range(lf, lt, ll), Range(rf, rt, rl)) => ll == rl && eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt), + (Range(lf, lt, ll), Range(rf, rt, rl)) => { + ll == rl && eq_expr_opt(lf.as_ref(), rf.as_ref()) && eq_expr_opt(lt.as_ref(), rt.as_ref()) + }, (AddrOf(lbk, lm, le), AddrOf(rbk, rm, re)) => lbk == rbk && lm == rm && eq_expr(le, re), - (Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp), + (Path(lq, lp), Path(rq, rp)) => both(lq.as_ref(), rq.as_ref(), eq_qself) && eq_path(lp, rp), (MacCall(l), MacCall(r)) => eq_mac_call(l, r), (Struct(lse), Struct(rse)) => { - eq_maybe_qself(&lse.qself, &rse.qself) + eq_maybe_qself(lse.qself.as_ref(), rse.qself.as_ref()) && eq_path(&lse.path, &rse.path) && eq_struct_rest(&lse.rest, &rse.rest) && unordered_over(&lse.fields, &rse.fields, eq_field) @@ -264,12 +277,12 @@ pub fn eq_field(l: &ExprField, r: &ExprField) -> bool { pub fn eq_arm(l: &Arm, r: &Arm) -> bool { l.is_placeholder == r.is_placeholder && eq_pat(&l.pat, &r.pat) - && eq_expr_opt(&l.body, &r.body) - && eq_expr_opt(&l.guard, &r.guard) + && eq_expr_opt(l.body.as_ref(), r.body.as_ref()) + && eq_expr_opt(l.guard.as_ref(), r.guard.as_ref()) && over(&l.attrs, &r.attrs, eq_attr) } -pub fn eq_label(l: &Option