about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md177
-rw-r--r--Cargo.toml6
-rw-r--r--book/src/README.md2
-rw-r--r--build.rs14
-rw-r--r--clippy_lints/Cargo.toml2
-rw-r--r--clippy_lints/src/box_default.rs2
-rw-r--r--clippy_lints/src/casts/mod.rs2
-rw-r--r--clippy_lints/src/declared_lints.rs3
-rw-r--r--clippy_lints/src/dereference.rs17
-rw-r--r--clippy_lints/src/derive.rs7
-rw-r--r--clippy_lints/src/disallowed_macros.rs2
-rw-r--r--clippy_lints/src/disallowed_types.rs4
-rw-r--r--clippy_lints/src/fn_null_check.rs106
-rw-r--r--clippy_lints/src/format_args.rs10
-rw-r--r--clippy_lints/src/from_over_into.rs4
-rw-r--r--clippy_lints/src/future_not_send.rs8
-rw-r--r--clippy_lints/src/implicit_saturating_add.rs2
-rw-r--r--clippy_lints/src/invalid_utf8_in_unchecked.rs2
-rw-r--r--clippy_lints/src/large_const_arrays.rs6
-rw-r--r--clippy_lints/src/large_include_file.rs2
-rw-r--r--clippy_lints/src/large_stack_arrays.rs6
-rw-r--r--clippy_lints/src/len_zero.rs2
-rw-r--r--clippy_lints/src/lib.rs4
-rw-r--r--clippy_lints/src/loops/utils.rs10
-rw-r--r--clippy_lints/src/macro_use.rs5
-rw-r--r--clippy_lints/src/manual_clamp.rs5
-rw-r--r--clippy_lints/src/manual_is_ascii_check.rs91
-rw-r--r--clippy_lints/src/manual_retain.rs3
-rw-r--r--clippy_lints/src/matches/manual_filter.rs17
-rw-r--r--clippy_lints/src/matches/match_same_arms.rs2
-rw-r--r--clippy_lints/src/methods/mod.rs2
-rw-r--r--clippy_lints/src/methods/needless_collect.rs2
-rw-r--r--clippy_lints/src/methods/option_map_unwrap_or.rs4
-rw-r--r--clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs6
-rw-r--r--clippy_lints/src/missing_enforced_import_rename.rs59
-rw-r--r--clippy_lints/src/permissions_set_readonly_false.rs52
-rw-r--r--clippy_lints/src/redundant_pub_crate.rs6
-rw-r--r--clippy_lints/src/returns.rs8
-rw-r--r--clippy_lints/src/single_component_path_imports.rs4
-rw-r--r--clippy_lints/src/transmute/mod.rs31
-rw-r--r--clippy_lints/src/transmute/transmute_null_to_fn.rs64
-rw-r--r--clippy_lints/src/transmute/transmuting_null.rs3
-rw-r--r--clippy_lints/src/unnecessary_self_imports.rs2
-rw-r--r--clippy_lints/src/unsafe_removed_from_name.rs4
-rw-r--r--clippy_lints/src/useless_conversion.rs28
-rw-r--r--clippy_lints/src/utils/author.rs2
-rw-r--r--clippy_lints/src/utils/conf.rs2
-rw-r--r--clippy_lints/src/utils/internal_lints/invalid_paths.rs10
-rw-r--r--clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs2
-rw-r--r--clippy_lints/src/utils/internal_lints/metadata_collector.rs2
-rw-r--r--clippy_lints/src/wildcard_imports.rs3
-rw-r--r--clippy_utils/Cargo.toml2
-rw-r--r--clippy_utils/src/ast_utils.rs2
-rw-r--r--clippy_utils/src/check_proc_macro.rs4
-rw-r--r--clippy_utils/src/consts.rs9
-rw-r--r--clippy_utils/src/lib.rs2
-rw-r--r--clippy_utils/src/macros.rs6
-rw-r--r--clippy_utils/src/paths.rs1
-rw-r--r--clippy_utils/src/qualify_min_const_fn.rs8
-rw-r--r--clippy_utils/src/ty.rs124
-rw-r--r--clippy_utils/src/usage.rs2
-rw-r--r--declare_clippy_lint/Cargo.toml2
-rw-r--r--rust-toolchain2
-rw-r--r--rustc_tools_util/CHANGELOG.md6
-rw-r--r--rustc_tools_util/Cargo.toml2
-rw-r--r--rustc_tools_util/README.md38
-rw-r--r--rustc_tools_util/src/lib.rs48
-rw-r--r--src/driver.rs1
-rw-r--r--src/main.rs1
-rw-r--r--tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr16
-rw-r--r--tests/ui/crashes/ice-10044.rs3
-rw-r--r--tests/ui/crashes/ice-10044.stderr10
-rw-r--r--tests/ui/explicit_counter_loop.rs30
-rw-r--r--tests/ui/fn_null_check.rs21
-rw-r--r--tests/ui/fn_null_check.stderr43
-rw-r--r--tests/ui/macro_use_imports.stderr8
-rw-r--r--tests/ui/manual_filter.fixed41
-rw-r--r--tests/ui/manual_filter.rs41
-rw-r--r--tests/ui/manual_is_ascii_check.fixed13
-rw-r--r--tests/ui/manual_is_ascii_check.rs13
-rw-r--r--tests/ui/manual_is_ascii_check.stderr64
-rw-r--r--tests/ui/needless_return.fixed5
-rw-r--r--tests/ui/needless_return.rs5
-rw-r--r--tests/ui/needless_return.stderr92
-rw-r--r--tests/ui/new_ret_no_self.rs23
-rw-r--r--tests/ui/new_ret_no_self.stderr42
-rw-r--r--tests/ui/permissions_set_readonly_false.rs29
-rw-r--r--tests/ui/permissions_set_readonly_false.stderr13
-rw-r--r--tests/ui/seek_to_start_instead_of_rewind.fixed6
-rw-r--r--tests/ui/seek_to_start_instead_of_rewind.rs6
-rw-r--r--tests/ui/seek_to_start_instead_of_rewind.stderr2
-rw-r--r--tests/ui/transmute_null_to_fn.rs28
-rw-r--r--tests/ui/transmute_null_to_fn.stderr27
-rw-r--r--tests/ui/uninlined_format_args_panic.edition2018.fixed3
-rw-r--r--tests/ui/uninlined_format_args_panic.edition2021.fixed3
-rw-r--r--tests/ui/uninlined_format_args_panic.edition2021.stderr26
-rw-r--r--tests/ui/uninlined_format_args_panic.rs3
-rw-r--r--tests/ui/useless_conversion.fixed73
-rw-r--r--tests/ui/useless_conversion.rs73
-rw-r--r--tests/ui/useless_conversion.stderr54
-rw-r--r--tests/ui/wildcard_imports.fixed1
-rw-r--r--tests/ui/wildcard_imports.rs1
-rw-r--r--tests/ui/wildcard_imports.stderr42
-rw-r--r--tests/ui/wildcard_imports_2021.edition2018.fixed240
-rw-r--r--tests/ui/wildcard_imports_2021.edition2018.stderr132
-rw-r--r--tests/ui/wildcard_imports_2021.edition2021.fixed240
-rw-r--r--tests/ui/wildcard_imports_2021.edition2021.stderr132
-rw-r--r--tests/ui/wildcard_imports_2021.rs241
-rw-r--r--tests/ui/wildcard_imports_2021.stderr132
-rw-r--r--tests/versioncheck.rs1
110 files changed, 2653 insertions, 404 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 70a09db074e..52efa8db485 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,11 +6,181 @@ document.
 
 ## Unreleased / Beta / In Rust Nightly
 
-[b52fb523...master](https://github.com/rust-lang/rust-clippy/compare/b52fb523...master)
+[4f142aa1...master](https://github.com/rust-lang/rust-clippy/compare/4f142aa1...master)
+
+## Rust 1.66
+
+Current stable, released 2022-12-15
+
+[b52fb523...4f142aa1](https://github.com/rust-lang/rust-clippy/compare/b52fb523...4f142aa1)
+
+### New Lints
+
+* [`manual_clamp`]
+  [#9484](https://github.com/rust-lang/rust-clippy/pull/9484)
+* [`missing_trait_methods`]
+  [#9670](https://github.com/rust-lang/rust-clippy/pull/9670)
+* [`unused_format_specs`]
+  [#9637](https://github.com/rust-lang/rust-clippy/pull/9637)
+* [`iter_kv_map`]
+  [#9409](https://github.com/rust-lang/rust-clippy/pull/9409)
+* [`manual_filter`]
+  [#9451](https://github.com/rust-lang/rust-clippy/pull/9451)
+* [`box_default`]
+  [#9511](https://github.com/rust-lang/rust-clippy/pull/9511)
+* [`implicit_saturating_add`]
+  [#9549](https://github.com/rust-lang/rust-clippy/pull/9549)
+* [`as_ptr_cast_mut`]
+  [#9572](https://github.com/rust-lang/rust-clippy/pull/9572)
+* [`disallowed_macros`]
+  [#9495](https://github.com/rust-lang/rust-clippy/pull/9495)
+* [`partial_pub_fields`]
+  [#9658](https://github.com/rust-lang/rust-clippy/pull/9658)
+* [`uninlined_format_args`]
+  [#9233](https://github.com/rust-lang/rust-clippy/pull/9233)
+* [`cast_nan_to_int`]
+  [#9617](https://github.com/rust-lang/rust-clippy/pull/9617)
+
+### Moves and Deprecations
+
+* `positional_named_format_parameters` was uplifted to rustc under the new name
+  `named_arguments_used_positionally`
+  [#8518](https://github.com/rust-lang/rust-clippy/pull/8518)
+* Moved [`implicit_saturating_sub`] to `style` (Now warn-by-default)
+  [#9584](https://github.com/rust-lang/rust-clippy/pull/9584)
+* Moved `derive_partial_eq_without_eq` to `nursery` (now allow-by-default)
+  [#9536](https://github.com/rust-lang/rust-clippy/pull/9536)
+
+### Enhancements
+
+* [`nonstandard_macro_braces`]: Now includes `matches!()` in the default lint config
+  [#9471](https://github.com/rust-lang/rust-clippy/pull/9471)
+* [`suboptimal_flops`]: Now supports multiplication and subtraction operations
+  [#9581](https://github.com/rust-lang/rust-clippy/pull/9581)
+* [`arithmetic_side_effects`]: Now detects cases with literals behind references
+  [#9587](https://github.com/rust-lang/rust-clippy/pull/9587)
+* [`upper_case_acronyms`]: Now also checks enum names
+  [#9580](https://github.com/rust-lang/rust-clippy/pull/9580)
+* [`needless_borrowed_reference`]: Now lints nested patterns
+  [#9573](https://github.com/rust-lang/rust-clippy/pull/9573)
+* [`unnecessary_cast`]: Now works for non-trivial non-literal expressions
+  [#9576](https://github.com/rust-lang/rust-clippy/pull/9576)
+* [`arithmetic_side_effects`]: Now detects operations with custom types
+  [#9559](https://github.com/rust-lang/rust-clippy/pull/9559)
+* [`disallowed_methods`], [`disallowed_types`]: Not correctly lints types, functions and macros
+  with the same path
+  [#9495](https://github.com/rust-lang/rust-clippy/pull/9495)
+* [`self_named_module_files`], [`mod_module_files`]: Now take remapped path prefixes into account
+  [#9475](https://github.com/rust-lang/rust-clippy/pull/9475)
+* [`bool_to_int_with_if`]: Now detects the inverse if case
+  [#9476](https://github.com/rust-lang/rust-clippy/pull/9476)
+
+### False Positive Fixes
+
+* [`arithmetic_side_effects`]: Now allows operations that can't overflow
+  [#9474](https://github.com/rust-lang/rust-clippy/pull/9474)
+* [`unnecessary_lazy_evaluations`]: No longer lints in external macros
+  [#9486](https://github.com/rust-lang/rust-clippy/pull/9486)
+* [`needless_borrow`], [`explicit_auto_deref`]: No longer lint on unions that require the reference
+  [#9490](https://github.com/rust-lang/rust-clippy/pull/9490)
+* [`almost_complete_letter_range`]: No longer lints in external macros
+  [#9467](https://github.com/rust-lang/rust-clippy/pull/9467)
+* [`drop_copy`]: No longer lints on idiomatic cases in match arms 
+  [#9491](https://github.com/rust-lang/rust-clippy/pull/9491)
+* [`question_mark`]: No longer lints in const context
+  [#9487](https://github.com/rust-lang/rust-clippy/pull/9487)
+* [`collapsible_if`]: Suggestion now work in macros
+  [#9410](https://github.com/rust-lang/rust-clippy/pull/9410)
+* [`std_instead_of_core`]: No longer triggers on unstable modules
+  [#9545](https://github.com/rust-lang/rust-clippy/pull/9545)
+* [`unused_peekable`]: No longer lints, if the peak is done in a closure or function
+  [#9465](https://github.com/rust-lang/rust-clippy/pull/9465)
+* [`useless_attribute`]: No longer lints on `#[allow]` attributes for [`unsafe_removed_from_name`]
+  [#9593](https://github.com/rust-lang/rust-clippy/pull/9593)
+* [`unnecessary_lazy_evaluations`]: No longer suggest switching to early evaluation when type has
+  custom `Drop` implementation
+  [#9551](https://github.com/rust-lang/rust-clippy/pull/9551)
+* [`unnecessary_cast`]: No longer lints on negative hexadecimal literals when cast as floats
+  [#9609](https://github.com/rust-lang/rust-clippy/pull/9609)
+* [`use_self`]: No longer lints in proc macros
+  [#9454](https://github.com/rust-lang/rust-clippy/pull/9454)
+* [`never_loop`]: Now takes `let ... else` statements into consideration.
+  [#9496](https://github.com/rust-lang/rust-clippy/pull/9496)
+* [`default_numeric_fallback`]: Now ignores constants
+  [#9636](https://github.com/rust-lang/rust-clippy/pull/9636)
+* [`uninit_vec`]: No longer lints `Vec::set_len(0)`
+  [#9519](https://github.com/rust-lang/rust-clippy/pull/9519)
+* [`arithmetic_side_effects`]: Now ignores references to integer types
+  [#9507](https://github.com/rust-lang/rust-clippy/pull/9507)
+* [`large_stack_arrays`]: No longer lints inside static items
+  [#9466](https://github.com/rust-lang/rust-clippy/pull/9466)
+* [`ref_option_ref`]: No longer lints if the inner reference is mutable
+  [#9684](https://github.com/rust-lang/rust-clippy/pull/9684)
+* [`ptr_arg`]: No longer lints if the argument is used as an incomplete trait object
+  [#9645](https://github.com/rust-lang/rust-clippy/pull/9645)
+* [`should_implement_trait`]: Now also works for `default` methods
+  [#9546](https://github.com/rust-lang/rust-clippy/pull/9546)
+
+### Suggestion Fixes/Improvements
+
+* [`derivable_impls`]: The suggestion is now machine applicable
+  [#9429](https://github.com/rust-lang/rust-clippy/pull/9429)
+* [`match_single_binding`]: The suggestion now handles scrutinies with side effects better
+  [#9601](https://github.com/rust-lang/rust-clippy/pull/9601)
+* [`zero_prefixed_literal`]: Only suggests using octal numbers, if this is possible
+  [#9652](https://github.com/rust-lang/rust-clippy/pull/9652)
+* [`rc_buffer`]: The suggestion is no longer machine applicable to avoid semantic changes
+  [#9633](https://github.com/rust-lang/rust-clippy/pull/9633)
+* [`print_literal`], [`write_literal`], [`uninlined_format_args`]: The suggestion now ignores
+  comments after the macro call.
+  [#9586](https://github.com/rust-lang/rust-clippy/pull/9586)
+* [`expect_fun_call`]:Improved the suggestion for `format!` calls with captured variables
+  [#9586](https://github.com/rust-lang/rust-clippy/pull/9586)
+* [`nonstandard_macro_braces`]: The suggestion is now machine applicable and will no longer
+  replace brackets inside the macro argument.
+  [#9499](https://github.com/rust-lang/rust-clippy/pull/9499)
+* [`from_over_into`]: The suggestion is now a machine applicable and contains explanations
+  [#9649](https://github.com/rust-lang/rust-clippy/pull/9649)
+* [`needless_return`]: The automatic suggestion now removes all required semicolons
+  [#9497](https://github.com/rust-lang/rust-clippy/pull/9497)
+* [`to_string_in_format_args`]: The suggestion now keeps parenthesis around values
+  [#9590](https://github.com/rust-lang/rust-clippy/pull/9590)
+* [`manual_assert`]: The suggestion now preserves comments
+  [#9479](https://github.com/rust-lang/rust-clippy/pull/9479)
+* [`redundant_allocation`]: The suggestion applicability is now marked `MaybeIncorrect` to
+  avoid semantic changes
+  [#9634](https://github.com/rust-lang/rust-clippy/pull/9634)
+* [`assertions_on_result_states`]: The suggestion has been corrected, for cases where the
+  `assert!` is not in a statement.
+  [#9453](https://github.com/rust-lang/rust-clippy/pull/9453)
+* [`nonminimal_bool`]: The suggestion no longer expands macros
+  [#9457](https://github.com/rust-lang/rust-clippy/pull/9457)
+* [`collapsible_match`]: Now specifies field names, when a struct is destructed
+  [#9685](https://github.com/rust-lang/rust-clippy/pull/9685)
+* [`unnecessary_cast`]: The suggestion now adds parenthesis for negative numbers
+  [#9577](https://github.com/rust-lang/rust-clippy/pull/9577)
+* [`redundant_closure`]: The suggestion now works for `impl FnMut` arguments
+  [#9556](https://github.com/rust-lang/rust-clippy/pull/9556)
+
+### ICE Fixes
+
+* [`unnecessary_to_owned`]: Avoid ICEs in favor of false negatives if information is missing
+  [#9505](https://github.com/rust-lang/rust-clippy/pull/9505)
+* [`manual_range_contains`]: No longer ICEs on values behind references
+  [#9627](https://github.com/rust-lang/rust-clippy/pull/9627)
+* [`needless_pass_by_value`]: No longer ICEs on unsized `dyn Fn` arguments
+  [#9531](https://github.com/rust-lang/rust-clippy/pull/9531)
+* `*_interior_mutable_const` lints: no longer ICE on const unions containing `!Freeze` types
+  [#9539](https://github.com/rust-lang/rust-clippy/pull/9539)
+
+### Others
+
+* Released `rustc_tools_util` for version information on `Crates.io`. (Further adjustments will
+  not be published as part of this changelog)
 
 ## Rust 1.65
 
-Current stable, released 2022-11-03
+Released 2022-11-03
 
 [3c7e7dbc...b52fb523](https://github.com/rust-lang/rust-clippy/compare/3c7e7dbc...b52fb523)
 
@@ -4033,6 +4203,7 @@ Released 2018-09-13
 [`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const
 [`float_equality_without_abs`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_equality_without_abs
 [`fn_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_address_comparisons
+[`fn_null_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_null_check
 [`fn_params_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools
 [`fn_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast
 [`fn_to_numeric_cast_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_any
@@ -4290,6 +4461,7 @@ Released 2018-09-13
 [`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none
 [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite
 [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch
+[`permissions_set_readonly_false`]: https://rust-lang.github.io/rust-clippy/master/index.html#permissions_set_readonly_false
 [`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters
 [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
 [`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence
@@ -4420,6 +4592,7 @@ Released 2018-09-13
 [`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool
 [`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char
 [`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float
+[`transmute_null_to_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_null_to_fn
 [`transmute_num_to_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_num_to_bytes
 [`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr
 [`transmute_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref
diff --git a/Cargo.toml b/Cargo.toml
index 6bdac84ada0..e1b15cc49da 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy"
-version = "0.1.67"
+version = "0.1.68"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
@@ -23,7 +23,7 @@ path = "src/driver.rs"
 [dependencies]
 clippy_lints = { path = "clippy_lints" }
 semver = "1.0"
-rustc_tools_util = "0.2.1"
+rustc_tools_util = "0.3.0"
 tempfile = { version = "3.2", optional = true }
 termize = "0.1"
 
@@ -56,7 +56,7 @@ tokio = { version = "1", features = ["io-util"] }
 rustc-semver = "1.1"
 
 [build-dependencies]
-rustc_tools_util = "0.2.1"
+rustc_tools_util = "0.3.0"
 
 [features]
 deny-warnings = ["clippy_lints/deny-warnings"]
diff --git a/book/src/README.md b/book/src/README.md
index 6248d588a89..23867df8efe 100644
--- a/book/src/README.md
+++ b/book/src/README.md
@@ -1,6 +1,6 @@
 # Clippy
 
-[![Clippy Test](https://github.com/rust-lang/rust-clippy/workflows/Clippy%20Test/badge.svg?branch=auto&event=push)](https://github.com/rust-lang/rust-clippy/actions?query=workflow%3A%22Clippy+Test%22+event%3Apush+branch%3Aauto)
+[![Clippy Test](https://github.com/rust-lang/rust-clippy/workflows/Clippy%20Test%20(bors)/badge.svg?branch=auto&event=push)](https://github.com/rust-lang/rust-clippy/actions?query=workflow%3A%22Clippy+Test+(bors)%22+event%3Apush+branch%3Aauto)
 [![License: MIT OR Apache-2.0](https://img.shields.io/crates/l/clippy.svg)](https://github.com/rust-lang/rust-clippy#license)
 
 A collection of lints to catch common mistakes and improve your
diff --git a/build.rs b/build.rs
index b5484bec3c8..b79d09b0dd2 100644
--- a/build.rs
+++ b/build.rs
@@ -3,17 +3,5 @@ fn main() {
     println!("cargo:rustc-env=PROFILE={}", std::env::var("PROFILE").unwrap());
     // Don't rebuild even if nothing changed
     println!("cargo:rerun-if-changed=build.rs");
-    // forward git repo hashes we build at
-    println!(
-        "cargo:rustc-env=GIT_HASH={}",
-        rustc_tools_util::get_commit_hash().unwrap_or_default()
-    );
-    println!(
-        "cargo:rustc-env=COMMIT_DATE={}",
-        rustc_tools_util::get_commit_date().unwrap_or_default()
-    );
-    println!(
-        "cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}",
-        rustc_tools_util::get_channel()
-    );
+    rustc_tools_util::setup_version_info!();
 }
diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml
index dcadd012a44..38a87017635 100644
--- a/clippy_lints/Cargo.toml
+++ b/clippy_lints/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_lints"
-version = "0.1.67"
+version = "0.1.68"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs
index 36daceabe0b..91900542af8 100644
--- a/clippy_lints/src/box_default.rs
+++ b/clippy_lints/src/box_default.rs
@@ -30,7 +30,7 @@ declare_clippy_lint! {
     /// ```rust
     /// let x: Box<String> = Box::default();
     /// ```
-    #[clippy::version = "1.65.0"]
+    #[clippy::version = "1.66.0"]
     pub BOX_DEFAULT,
     perf,
     "Using Box::new(T::default()) instead of Box::default()"
diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs
index c6d505c4a18..161e3a698e9 100644
--- a/clippy_lints/src/casts/mod.rs
+++ b/clippy_lints/src/casts/mod.rs
@@ -641,7 +641,7 @@ declare_clippy_lint! {
     /// ```rust,ignore
     /// let _: = 0_u64;
     /// ```
-    #[clippy::version = "1.64.0"]
+    #[clippy::version = "1.66.0"]
     pub CAST_NAN_TO_INT,
     suspicious,
     "casting a known floating-point NaN into an integer"
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 3cd7d1d7e72..980e128cba4 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -161,6 +161,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::float_literal::LOSSY_FLOAT_LITERAL_INFO,
     crate::floating_point_arithmetic::IMPRECISE_FLOPS_INFO,
     crate::floating_point_arithmetic::SUBOPTIMAL_FLOPS_INFO,
+    crate::fn_null_check::FN_NULL_CHECK_INFO,
     crate::format::USELESS_FORMAT_INFO,
     crate::format_args::FORMAT_IN_FORMAT_ARGS_INFO,
     crate::format_args::TO_STRING_IN_FORMAT_ARGS_INFO,
@@ -494,6 +495,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE_INFO,
     crate::pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF_INFO,
     crate::pattern_type_mismatch::PATTERN_TYPE_MISMATCH_INFO,
+    crate::permissions_set_readonly_false::PERMISSIONS_SET_READONLY_FALSE_INFO,
     crate::precedence::PRECEDENCE_INFO,
     crate::ptr::CMP_NULL_INFO,
     crate::ptr::INVALID_NULL_PTR_USAGE_INFO,
@@ -568,6 +570,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::transmute::TRANSMUTE_INT_TO_BOOL_INFO,
     crate::transmute::TRANSMUTE_INT_TO_CHAR_INFO,
     crate::transmute::TRANSMUTE_INT_TO_FLOAT_INFO,
+    crate::transmute::TRANSMUTE_NULL_TO_FN_INFO,
     crate::transmute::TRANSMUTE_NUM_TO_BYTES_INFO,
     crate::transmute::TRANSMUTE_PTR_TO_PTR_INFO,
     crate::transmute::TRANSMUTE_PTR_TO_REF_INFO,
diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs
index 38329659e02..7b43d8ccc67 100644
--- a/clippy_lints/src/dereference.rs
+++ b/clippy_lints/src/dereference.rs
@@ -1244,7 +1244,7 @@ fn is_mixed_projection_predicate<'tcx>(
         let mut projection_ty = projection_predicate.projection_ty;
         loop {
             match projection_ty.self_ty().kind() {
-                ty::Projection(inner_projection_ty) => {
+                ty::Alias(ty::Projection, inner_projection_ty) => {
                     projection_ty = *inner_projection_ty;
                 }
                 ty::Param(param_ty) => {
@@ -1330,7 +1330,7 @@ fn replace_types<'tcx>(
                     && let Some(term_ty) = projection_predicate.term.ty()
                     && let ty::Param(term_param_ty) = term_ty.kind()
                 {
-                    let item_def_id = projection_predicate.projection_ty.item_def_id;
+                    let item_def_id = projection_predicate.projection_ty.def_id;
                     let assoc_item = cx.tcx.associated_item(item_def_id);
                     let projection = cx.tcx
                         .mk_projection(assoc_item.def_id, cx.tcx.mk_substs_trait(new_ty, []));
@@ -1390,10 +1390,15 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc
                 continue;
             },
             ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
-            ty::Projection(_) if ty.has_non_region_param() => TyPosition::new_deref_stable_for_result(precedence, ty),
-            ty::Infer(_) | ty::Error(_) | ty::Bound(..) | ty::Opaque(..) | ty::Placeholder(_) | ty::Dynamic(..) => {
-                Position::ReborrowStable(precedence).into()
+            ty::Alias(ty::Projection, _) if ty.has_non_region_param() => {
+                TyPosition::new_deref_stable_for_result(precedence, ty)
             },
+            ty::Infer(_)
+            | ty::Error(_)
+            | ty::Bound(..)
+            | ty::Alias(ty::Opaque, ..)
+            | ty::Placeholder(_)
+            | ty::Dynamic(..) => Position::ReborrowStable(precedence).into(),
             ty::Adt(..) if ty.has_placeholders() || ty.has_opaque_types() => {
                 Position::ReborrowStable(precedence).into()
             },
@@ -1417,7 +1422,7 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc
             | ty::Closure(..)
             | ty::Never
             | ty::Tuple(_)
-            | ty::Projection(_) => {
+            | ty::Alias(ty::Projection, _) => {
                 Position::DerefStable(precedence, ty.is_sized(cx.tcx, cx.param_env.without_caller_bounds())).into()
             },
         };
diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs
index 9e596ca8157..cf3483d4c00 100644
--- a/clippy_lints/src/derive.rs
+++ b/clippy_lints/src/derive.rs
@@ -15,7 +15,7 @@ use rustc_middle::hir::nested_filter;
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::{
     self, Binder, BoundConstness, Clause, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate,
-    TraitRef, Ty, TyCtxt,
+    Ty, TyCtxt,
 };
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
@@ -513,10 +513,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
         tcx.mk_predicates(ty_predicates.iter().map(|&(p, _)| p).chain(
             params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
                 tcx.mk_predicate(Binder::dummy(PredicateKind::Clause(Clause::Trait(TraitPredicate {
-                    trait_ref: TraitRef::new(
-                        eq_trait_id,
-                        tcx.mk_substs(std::iter::once(tcx.mk_param_from_def(param))),
-                    ),
+                    trait_ref: tcx.mk_trait_ref(eq_trait_id, [tcx.mk_param_from_def(param)]),
                     constness: BoundConstness::NotConst,
                     polarity: ImplPolarity::Positive,
                 }))))
diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs
index 68122b4cef5..1971cab64ef 100644
--- a/clippy_lints/src/disallowed_macros.rs
+++ b/clippy_lints/src/disallowed_macros.rs
@@ -47,7 +47,7 @@ declare_clippy_lint! {
     ///     value: usize,
     /// }
     /// ```
-    #[clippy::version = "1.65.0"]
+    #[clippy::version = "1.66.0"]
     pub DISALLOWED_MACROS,
     style,
     "use of a disallowed macro"
diff --git a/clippy_lints/src/disallowed_types.rs b/clippy_lints/src/disallowed_types.rs
index aee3d8c4f08..1f56d0118a4 100644
--- a/clippy_lints/src/disallowed_types.rs
+++ b/clippy_lints/src/disallowed_types.rs
@@ -106,7 +106,9 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
 
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
         if let ItemKind::Use(path, UseKind::Single) = &item.kind {
-            self.check_res_emit(cx, &path.res, item.span);
+            for res in &path.res {
+                self.check_res_emit(cx, res, item.span);
+            }
         }
     }
 
diff --git a/clippy_lints/src/fn_null_check.rs b/clippy_lints/src/fn_null_check.rs
new file mode 100644
index 00000000000..91c8c340ce2
--- /dev/null
+++ b/clippy_lints/src/fn_null_check.rs
@@ -0,0 +1,106 @@
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::{is_integer_literal, is_path_diagnostic_item};
+use rustc_hir::{BinOpKind, Expr, ExprKind, TyKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for comparing a function pointer to null.
+    ///
+    /// ### Why is this bad?
+    /// Function pointers are assumed to not be null.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// let fn_ptr: fn() = /* somehow obtained nullable function pointer */
+    ///
+    /// if (fn_ptr as *const ()).is_null() { ... }
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// let fn_ptr: Option<fn()> = /* somehow obtained nullable function pointer */
+    ///
+    /// if fn_ptr.is_none() { ... }
+    /// ```
+    #[clippy::version = "1.67.0"]
+    pub FN_NULL_CHECK,
+    correctness,
+    "`fn()` type assumed to be nullable"
+}
+declare_lint_pass!(FnNullCheck => [FN_NULL_CHECK]);
+
+fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
+    span_lint_and_help(
+        cx,
+        FN_NULL_CHECK,
+        expr.span,
+        "function pointer assumed to be nullable, even though it isn't",
+        None,
+        "try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value",
+    );
+}
+
+fn is_fn_ptr_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    if let ExprKind::Cast(cast_expr, cast_ty) = expr.kind
+        && let TyKind::Ptr(_) = cast_ty.kind
+    {
+        cx.typeck_results().expr_ty_adjusted(cast_expr).is_fn()
+    } else {
+        false
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for FnNullCheck {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        match expr.kind {
+            // Catching:
+            // (fn_ptr as *<const/mut> <ty>).is_null()
+            ExprKind::MethodCall(method_name, receiver, _, _)
+                if method_name.ident.as_str() == "is_null" && is_fn_ptr_cast(cx, receiver) =>
+            {
+                lint_expr(cx, expr);
+            },
+
+            ExprKind::Binary(op, left, right) if matches!(op.node, BinOpKind::Eq) => {
+                let to_check: &Expr<'_>;
+                if is_fn_ptr_cast(cx, left) {
+                    to_check = right;
+                } else if is_fn_ptr_cast(cx, right) {
+                    to_check = left;
+                } else {
+                    return;
+                }
+
+                match to_check.kind {
+                    // Catching:
+                    // (fn_ptr as *<const/mut> <ty>) == (0 as <ty>)
+                    ExprKind::Cast(cast_expr, _) if is_integer_literal(cast_expr, 0) => {
+                        lint_expr(cx, expr);
+                    },
+
+                    // Catching:
+                    // (fn_ptr as *<const/mut> <ty>) == std::ptr::null()
+                    ExprKind::Call(func, []) if is_path_diagnostic_item(cx, func, sym::ptr_null) => {
+                        lint_expr(cx, expr);
+                    },
+
+                    // Catching:
+                    // (fn_ptr as *<const/mut> <ty>) == <const that evaluates to null_ptr>
+                    _ if matches!(
+                        constant(cx, cx.typeck_results(), to_check),
+                        Some((Constant::RawPtr(0), _))
+                    ) =>
+                    {
+                        lint_expr(cx, expr);
+                    },
+
+                    _ => {},
+                }
+            },
+            _ => {},
+        }
+    }
+}
diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs
index f0995a81329..62284235dbf 100644
--- a/clippy_lints/src/format_args.rs
+++ b/clippy_lints/src/format_args.rs
@@ -2,7 +2,8 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::is_diag_trait_item;
 use clippy_utils::macros::FormatParamKind::{Implicit, Named, NamedInline, Numbered, Starred};
 use clippy_utils::macros::{
-    is_format_macro, is_panic, root_macro_call, Count, FormatArg, FormatArgsExpn, FormatParam, FormatParamUsage,
+    is_assert_macro, is_format_macro, is_panic, root_macro_call, Count, FormatArg, FormatArgsExpn, FormatParam,
+    FormatParamUsage,
 };
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_opt;
@@ -122,7 +123,7 @@ declare_clippy_lint! {
     ///
     /// If a format string contains a numbered argument that cannot be inlined
     /// nothing will be suggested, e.g. `println!("{0}={1}", var, 1+2)`.
-    #[clippy::version = "1.65.0"]
+    #[clippy::version = "1.66.0"]
     pub UNINLINED_FORMAT_ARGS,
     style,
     "using non-inlined variables in `format!` calls"
@@ -290,8 +291,9 @@ fn check_uninlined_args(
     if args.format_string.span.from_expansion() {
         return;
     }
-    if call_site.edition() < Edition2021 && is_panic(cx, def_id) {
-        // panic! before 2021 edition considers a single string argument as non-format
+    if call_site.edition() < Edition2021 && (is_panic(cx, def_id) || is_assert_macro(cx, def_id)) {
+        // panic!, assert!, and debug_assert! before 2021 edition considers a single string argument as
+        // non-format
         return;
     }
 
diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs
index cc3c35f4863..a92f7548ff2 100644
--- a/clippy_lints/src/from_over_into.rs
+++ b/clippy_lints/src/from_over_into.rs
@@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
             && let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args
             && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
             && cx.tcx.is_diagnostic_item(sym::Into, middle_trait_ref.def_id)
-            && !matches!(middle_trait_ref.substs.type_at(1).kind(), ty::Opaque(..))
+            && !matches!(middle_trait_ref.substs.type_at(1).kind(), ty::Alias(ty::Opaque, _))
         {
             span_lint_and_then(
                 cx,
@@ -127,7 +127,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SelfFinder<'a, 'tcx> {
         self.cx.tcx.hir()
     }
 
-    fn visit_path(&mut self, path: &'tcx Path<'tcx>, _id: HirId) {
+    fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) {
         for segment in path.segments {
             match segment.ident.name {
                 kw::SelfLower => self.lower.push(segment.ident.span),
diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs
index 61934a91426..989f83cf80d 100644
--- a/clippy_lints/src/future_not_send.rs
+++ b/clippy_lints/src/future_not_send.rs
@@ -4,7 +4,7 @@ use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, FnDecl, HirId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{Clause, EarlyBinder, Opaque, PredicateKind};
+use rustc_middle::ty::{self, AliasTy, Clause, EarlyBinder, PredicateKind};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{sym, Span};
 use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
@@ -62,11 +62,11 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
             return;
         }
         let ret_ty = return_ty(cx, hir_id);
-        if let Opaque(id, subst) = *ret_ty.kind() {
-            let preds = cx.tcx.explicit_item_bounds(id);
+        if let ty::Alias(ty::Opaque, AliasTy { def_id, substs, .. }) = *ret_ty.kind() {
+            let preds = cx.tcx.explicit_item_bounds(def_id);
             let mut is_future = false;
             for &(p, _span) in preds {
-                let p = EarlyBinder(p).subst(cx.tcx, subst);
+                let p = EarlyBinder(p).subst(cx.tcx, substs);
                 if let Some(trait_pred) = p.to_opt_poly_trait_pred() {
                     if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() {
                         is_future = true;
diff --git a/clippy_lints/src/implicit_saturating_add.rs b/clippy_lints/src/implicit_saturating_add.rs
index bf1351829c6..6e19343931e 100644
--- a/clippy_lints/src/implicit_saturating_add.rs
+++ b/clippy_lints/src/implicit_saturating_add.rs
@@ -31,7 +31,7 @@ declare_clippy_lint! {
     ///
     /// u = u.saturating_add(1);
     /// ```
-    #[clippy::version = "1.65.0"]
+    #[clippy::version = "1.66.0"]
     pub IMPLICIT_SATURATING_ADD,
     style,
     "Perform saturating addition instead of implicitly checking max bound of data type"
diff --git a/clippy_lints/src/invalid_utf8_in_unchecked.rs b/clippy_lints/src/invalid_utf8_in_unchecked.rs
index e0a607f9a95..6a4861747d2 100644
--- a/clippy_lints/src/invalid_utf8_in_unchecked.rs
+++ b/clippy_lints/src/invalid_utf8_in_unchecked.rs
@@ -33,7 +33,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidUtf8InUnchecked {
         if let Some([arg]) = match_function_call(cx, expr, &paths::STR_FROM_UTF8_UNCHECKED) {
             match &arg.kind {
                 ExprKind::Lit(Spanned { node: lit, .. }) => {
-                    if let LitKind::ByteStr(bytes) = &lit
+                    if let LitKind::ByteStr(bytes, _) = &lit
                         && std::str::from_utf8(bytes).is_err()
                     {
                         lint(cx, expr.span);
diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs
index 76c83ab47d0..db637dfc068 100644
--- a/clippy_lints/src/large_const_arrays.rs
+++ b/clippy_lints/src/large_const_arrays.rs
@@ -34,12 +34,12 @@ declare_clippy_lint! {
 }
 
 pub struct LargeConstArrays {
-    maximum_allowed_size: u64,
+    maximum_allowed_size: u128,
 }
 
 impl LargeConstArrays {
     #[must_use]
-    pub fn new(maximum_allowed_size: u64) -> Self {
+    pub fn new(maximum_allowed_size: u128) -> Self {
         Self { maximum_allowed_size }
     }
 }
@@ -56,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
             if let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind();
             if let Ok(element_count) = element_count.try_to_machine_usize(cx.tcx);
             if let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes());
-            if self.maximum_allowed_size < element_count * element_size;
+            if self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size);
 
             then {
                 let hi_pos = item.ident.span.lo() - BytePos::from_usize(1);
diff --git a/clippy_lints/src/large_include_file.rs b/clippy_lints/src/large_include_file.rs
index 84dd61a1e4b..424c0d9e798 100644
--- a/clippy_lints/src/large_include_file.rs
+++ b/clippy_lints/src/large_include_file.rs
@@ -60,7 +60,7 @@ impl LateLintPass<'_> for LargeIncludeFile {
             then {
                 let len = match &lit.node {
                     // include_bytes
-                    LitKind::ByteStr(bstr) => bstr.len(),
+                    LitKind::ByteStr(bstr, _) => bstr.len(),
                     // include_str
                     LitKind::Str(sym, _) => sym.as_str().len(),
                     _ => return,
diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs
index 5857d81ab1f..89ae83d48f5 100644
--- a/clippy_lints/src/large_stack_arrays.rs
+++ b/clippy_lints/src/large_stack_arrays.rs
@@ -24,12 +24,12 @@ declare_clippy_lint! {
 }
 
 pub struct LargeStackArrays {
-    maximum_allowed_size: u64,
+    maximum_allowed_size: u128,
 }
 
 impl LargeStackArrays {
     #[must_use]
-    pub fn new(maximum_allowed_size: u64) -> Self {
+    pub fn new(maximum_allowed_size: u128) -> Self {
         Self { maximum_allowed_size }
     }
 }
@@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays {
           && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
           && !cx.tcx.hir().parent_iter(expr.hir_id)
               .any(|(_, node)| matches!(node, Node::Item(Item { kind: ItemKind::Static(..), .. })))
-          && self.maximum_allowed_size < element_count * element_size {
+          && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size) {
               span_lint_and_help(
                   cx,
                   LARGE_STACK_ARRAYS,
diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs
index 3babc2a5895..e88d1764a24 100644
--- a/clippy_lints/src/len_zero.rs
+++ b/clippy_lints/src/len_zero.rs
@@ -501,7 +501,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
                 .filter_by_name_unhygienic(is_empty)
                 .any(|item| is_is_empty(cx, item))
         }),
-        ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id),
+        ty::Alias(ty::Projection, ref proj) => has_is_empty_impl(cx, proj.def_id),
         ty::Adt(id, _) => has_is_empty_impl(cx, id.did()),
         ty::Array(..) | ty::Slice(..) | ty::Str => true,
         _ => false,
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 39850d59803..676ef3946bf 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -125,6 +125,7 @@ mod explicit_write;
 mod fallible_impl_from;
 mod float_literal;
 mod floating_point_arithmetic;
+mod fn_null_check;
 mod format;
 mod format_args;
 mod format_impl;
@@ -234,6 +235,7 @@ mod partialeq_ne_impl;
 mod partialeq_to_none;
 mod pass_by_ref_or_value;
 mod pattern_type_mismatch;
+mod permissions_set_readonly_false;
 mod precedence;
 mod ptr;
 mod ptr_offset_with_cast;
@@ -902,6 +904,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
     store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv())));
     store.register_late_pass(|_| Box::new(semicolon_block::SemicolonBlock));
+    store.register_late_pass(|_| Box::new(fn_null_check::FnNullCheck));
+    store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs
index b6f4cf7bbb3..28ee24309cc 100644
--- a/clippy_lints/src/loops/utils.rs
+++ b/clippy_lints/src/loops/utils.rs
@@ -25,7 +25,6 @@ pub(super) struct IncrementVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,                  // context reference
     states: HirIdMap<IncrementVisitorVarState>, // incremented variables
     depth: u32,                                 // depth of conditional expressions
-    done: bool,
 }
 
 impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> {
@@ -34,7 +33,6 @@ impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> {
             cx,
             states: HirIdMap::default(),
             depth: 0,
-            done: false,
         }
     }
 
@@ -51,10 +49,6 @@ impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> {
 
 impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
-        if self.done {
-            return;
-        }
-
         // If node is a variable
         if let Some(def_id) = path_to_local(expr) {
             if let Some(parent) = get_parent_expr(self.cx, expr) {
@@ -95,7 +89,9 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
             walk_expr(self, expr);
             self.depth -= 1;
         } else if let ExprKind::Continue(_) = expr.kind {
-            self.done = true;
+            // If we see a `continue` block, then we increment depth so that the IncrementVisitor
+            // state will be set to DontWarn if we see the variable being modified anywhere afterwards.
+            self.depth += 1;
         } else {
             walk_expr(self, expr);
         }
diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs
index f5617a905ff..26ae4b409c7 100644
--- a/clippy_lints/src/macro_use.rs
+++ b/clippy_lints/src/macro_use.rs
@@ -95,7 +95,10 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
             let hir_id = item.hir_id();
             let attrs = cx.tcx.hir().attrs(hir_id);
             if let Some(mac_attr) = attrs.iter().find(|attr| attr.has_name(sym::macro_use));
-            if let Res::Def(DefKind::Mod, id) = path.res;
+            if let Some(id) = path.res.iter().find_map(|res| match res {
+                Res::Def(DefKind::Mod, id) => Some(id),
+                _ => None,
+            });
             if !id.is_local();
             then {
                 for kid in cx.tcx.module_children(id).iter() {
diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs
index bb6d628af3b..f239736d38a 100644
--- a/clippy_lints/src/manual_clamp.rs
+++ b/clippy_lints/src/manual_clamp.rs
@@ -35,6 +35,9 @@ declare_clippy_lint! {
     /// Some may consider panicking in these situations to be desirable, but it also may
     /// introduce panicking where there wasn't any before.
     ///
+    /// See also [the discussion in the
+    /// PR](https://github.com/rust-lang/rust-clippy/pull/9484#issuecomment-1278922613).
+    ///
     /// ### Examples
     /// ```rust
     /// # let (input, min, max) = (0, -2, 1);
@@ -78,7 +81,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.66.0"]
     pub MANUAL_CLAMP,
-    complexity,
+    nursery,
     "using a clamp pattern instead of the clamp function"
 }
 impl_lint_pass!(ManualClamp => [MANUAL_CLAMP]);
diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs
index 5ab049d8d13..d9ef7dffa02 100644
--- a/clippy_lints/src/manual_is_ascii_check.rs
+++ b/clippy_lints/src/manual_is_ascii_check.rs
@@ -1,11 +1,12 @@
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::{diagnostics::span_lint_and_sugg, in_constant, macros::root_macro_call, source::snippet};
+use clippy_utils::{diagnostics::span_lint_and_sugg, higher, in_constant, macros::root_macro_call, source::snippet};
+use rustc_ast::ast::RangeLimits;
 use rustc_ast::LitKind::{Byte, Char};
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd};
+use rustc_hir::{BorrowKind, Expr, ExprKind, PatKind, RangeEnd};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{def_id::DefId, sym};
+use rustc_span::{def_id::DefId, sym, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -23,6 +24,10 @@ declare_clippy_lint! {
     ///     assert!(matches!(b'X', b'A'..=b'Z'));
     ///     assert!(matches!('2', '0'..='9'));
     ///     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
+    ///
+    ///     ('0'..='9').contains(&'0');
+    ///     ('a'..='z').contains(&'a');
+    ///     ('A'..='Z').contains(&'A');
     /// }
     /// ```
     /// Use instead:
@@ -32,6 +37,10 @@ declare_clippy_lint! {
     ///     assert!(b'X'.is_ascii_uppercase());
     ///     assert!('2'.is_ascii_digit());
     ///     assert!('x'.is_ascii_alphabetic());
+    ///
+    ///     '0'.is_ascii_digit();
+    ///     'a'.is_ascii_lowercase();
+    ///     'A'.is_ascii_uppercase();
     /// }
     /// ```
     #[clippy::version = "1.66.0"]
@@ -75,40 +84,21 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
             return;
         }
 
-        let Some(macro_call) = root_macro_call(expr.span) else { return };
-
-        if is_matches_macro(cx, macro_call.def_id) {
+        if let Some(macro_call) = root_macro_call(expr.span)
+            && is_matches_macro(cx, macro_call.def_id) {
             if let ExprKind::Match(recv, [arm, ..], _) = expr.kind {
                 let range = check_pat(&arm.pat.kind);
-
-                if let Some(sugg) = match range {
-                    CharRange::UpperChar => Some("is_ascii_uppercase"),
-                    CharRange::LowerChar => Some("is_ascii_lowercase"),
-                    CharRange::FullChar => Some("is_ascii_alphabetic"),
-                    CharRange::Digit => Some("is_ascii_digit"),
-                    CharRange::Otherwise => None,
-                } {
-                    let default_snip = "..";
-                    // `snippet_with_applicability` may set applicability to `MaybeIncorrect` for
-                    // macro span, so we check applicability manually by comparing `recv` is not default.
-                    let recv = snippet(cx, recv.span, default_snip);
-
-                    let applicability = if recv == default_snip {
-                        Applicability::HasPlaceholders
-                    } else {
-                        Applicability::MachineApplicable
-                    };
-
-                    span_lint_and_sugg(
-                        cx,
-                        MANUAL_IS_ASCII_CHECK,
-                        macro_call.span,
-                        "manual check for common ascii range",
-                        "try",
-                        format!("{recv}.{sugg}()"),
-                        applicability,
-                    );
-                }
+                check_is_ascii(cx, macro_call.span, recv, &range);
+            }
+        } else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind
+            && path.ident.name == sym!(contains)
+            && let Some(higher::Range { start: Some(start), end: Some(end), limits: RangeLimits::Closed })
+            = higher::Range::hir(receiver) {
+            let range = check_range(start, end);
+            if let ExprKind::AddrOf(BorrowKind::Ref, _, e) = arg.kind {
+                check_is_ascii(cx, expr.span, e, &range);
+            } else {
+                check_is_ascii(cx, expr.span, arg, &range);
             }
         }
     }
@@ -116,6 +106,37 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
     extract_msrv_attr!(LateContext);
 }
 
+fn check_is_ascii(cx: &LateContext<'_>, span: Span, recv: &Expr<'_>, range: &CharRange) {
+    if let Some(sugg) = match range {
+        CharRange::UpperChar => Some("is_ascii_uppercase"),
+        CharRange::LowerChar => Some("is_ascii_lowercase"),
+        CharRange::FullChar => Some("is_ascii_alphabetic"),
+        CharRange::Digit => Some("is_ascii_digit"),
+        CharRange::Otherwise => None,
+    } {
+        let default_snip = "..";
+        // `snippet_with_applicability` may set applicability to `MaybeIncorrect` for
+        // macro span, so we check applicability manually by comparing `recv` is not default.
+        let recv = snippet(cx, recv.span, default_snip);
+
+        let applicability = if recv == default_snip {
+            Applicability::HasPlaceholders
+        } else {
+            Applicability::MachineApplicable
+        };
+
+        span_lint_and_sugg(
+            cx,
+            MANUAL_IS_ASCII_CHECK,
+            span,
+            "manual check for common ascii range",
+            "try",
+            format!("{recv}.{sugg}()"),
+            applicability,
+        );
+    }
+}
+
 fn check_pat(pat_kind: &PatKind<'_>) -> CharRange {
     match pat_kind {
         PatKind::Or(pats) => {
diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs
index c1e6c82487d..72cdb9c1736 100644
--- a/clippy_lints/src/manual_retain.rs
+++ b/clippy_lints/src/manual_retain.rs
@@ -70,7 +70,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualRetain {
             && seg.args.is_none()
             && let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind
             && let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id)
-            && match_def_path(cx, collect_def_id, &paths::CORE_ITER_COLLECT) {
+            && cx.tcx.is_diagnostic_item(sym::iterator_collect_fn, collect_def_id)
+        {
             check_into_iter(cx, parent_expr, left_expr, target_expr, &self.msrv);
             check_iter(cx, parent_expr, left_expr, target_expr, &self.msrv);
             check_to_owned(cx, parent_expr, left_expr, target_expr, &self.msrv);
diff --git a/clippy_lints/src/matches/manual_filter.rs b/clippy_lints/src/matches/manual_filter.rs
index d521a529e0d..f6bf0e7aa1a 100644
--- a/clippy_lints/src/matches/manual_filter.rs
+++ b/clippy_lints/src/matches/manual_filter.rs
@@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::contains_unsafe_block;
 use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id};
 
-use rustc_hir::LangItem::OptionSome;
+use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatKind};
 use rustc_lint::LateContext;
 use rustc_span::{sym, SyntaxContext};
@@ -25,15 +25,13 @@ fn get_cond_expr<'tcx>(
         if let Some(block_expr) = peels_blocks_incl_unsafe_opt(expr);
         if let ExprKind::If(cond, then_expr, Some(else_expr)) = block_expr.kind;
         if let PatKind::Binding(_,target, ..) = pat.kind;
-        if let (then_visitor, else_visitor)
-            = (is_some_expr(cx, target, ctxt, then_expr),
-                is_some_expr(cx, target, ctxt, else_expr));
-        if then_visitor != else_visitor; // check that one expr resolves to `Some(x)`, the other to `None`
+        if is_some_expr(cx, target, ctxt, then_expr) && is_none_expr(cx, else_expr)
+            || is_none_expr(cx, then_expr) && is_some_expr(cx, target, ctxt, else_expr); // check that one expr resolves to `Some(x)`, the other to `None`
         then {
             return Some(SomeExpr {
                     expr: peels_blocks_incl_unsafe(cond.peel_drop_temps()),
                     needs_unsafe_block: contains_unsafe_block(cx, expr),
-                    needs_negated: !then_visitor // if the `then_expr` resolves to `None`, need to negate the cond
+                    needs_negated: is_none_expr(cx, then_expr) // if the `then_expr` resolves to `None`, need to negate the cond
                 })
             }
     };
@@ -74,6 +72,13 @@ fn is_some_expr(cx: &LateContext<'_>, target: HirId, ctxt: SyntaxContext, expr:
     false
 }
 
+fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    if let Some(inner_expr) = peels_blocks_incl_unsafe_opt(expr) {
+        return is_res_lang_ctor(cx, path_res(cx, inner_expr), OptionNone);
+    };
+    false
+}
+
 // given the closure: `|<pattern>| <expr>`
 // returns `|&<pattern>| <expr>`
 fn add_ampersand_if_copy(body_str: String, has_copy_trait: bool) -> String {
diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs
index 168c1e4d2e6..158e6caa4de 100644
--- a/clippy_lints/src/matches/match_same_arms.rs
+++ b/clippy_lints/src/matches/match_same_arms.rs
@@ -282,7 +282,7 @@ impl<'a> NormalizedPat<'a> {
                 // TODO: Handle negative integers. They're currently treated as a wild match.
                 ExprKind::Lit(lit) => match lit.node {
                     LitKind::Str(sym, _) => Self::LitStr(sym),
-                    LitKind::ByteStr(ref bytes) => Self::LitBytes(bytes),
+                    LitKind::ByteStr(ref bytes, _) => Self::LitBytes(bytes),
                     LitKind::Byte(val) => Self::LitInt(val.into()),
                     LitKind::Char(val) => Self::LitInt(val.into()),
                     LitKind::Int(val, _) => Self::LitInt(val),
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index cb7229ba8a4..561e4336593 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -3059,7 +3059,7 @@ declare_clippy_lint! {
     /// let map: HashMap<u32, u32> = HashMap::new();
     /// let values = map.values().collect::<Vec<_>>();
     /// ```
-    #[clippy::version = "1.65.0"]
+    #[clippy::version = "1.66.0"]
     pub ITER_KV_MAP,
     complexity,
     "iterating on map using `iter` when `keys` or `values` would do"
diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs
index b088e642e0e..f4d3ef3b742 100644
--- a/clippy_lints/src/methods/needless_collect.rs
+++ b/clippy_lints/src/methods/needless_collect.rs
@@ -151,7 +151,7 @@ fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty:
         && let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, item, [collect_ty])
         && let Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions(
             cx.param_env,
-            cx.tcx.mk_projection(into_iter_item_proj.item_def_id, into_iter_item_proj.substs)
+            cx.tcx.mk_projection(into_iter_item_proj.def_id, into_iter_item_proj.substs)
         )
     {
         iter_item_ty == into_iter_item_ty
diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs
index 30421a6dd5a..910ee14855e 100644
--- a/clippy_lints/src/methods/option_map_unwrap_or.rs
+++ b/clippy_lints/src/methods/option_map_unwrap_or.rs
@@ -97,7 +97,7 @@ struct UnwrapVisitor<'a, 'tcx> {
 impl<'a, 'tcx> Visitor<'tcx> for UnwrapVisitor<'a, 'tcx> {
     type NestedFilter = nested_filter::All;
 
-    fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) {
+    fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) {
         self.identifiers.insert(ident(path));
         walk_path(self, path);
     }
@@ -116,7 +116,7 @@ struct MapExprVisitor<'a, 'tcx> {
 impl<'a, 'tcx> Visitor<'tcx> for MapExprVisitor<'a, 'tcx> {
     type NestedFilter = nested_filter::All;
 
-    fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) {
+    fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) {
         if self.identifiers.contains(&ident(path)) {
             self.found_identifier = true;
             return;
diff --git a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
index 7e3bed1e41a..660b7049cce 100644
--- a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
+++ b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{get_trait_def_id, match_def_path, paths};
+use clippy_utils::{get_trait_def_id, is_expr_used_or_unified, match_def_path, paths};
 use rustc_ast::ast::{LitIntType, LitKind};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
@@ -19,6 +19,10 @@ pub(super) fn check<'tcx>(
     // Get receiver type
     let ty = cx.typeck_results().expr_ty(recv).peel_refs();
 
+    if is_expr_used_or_unified(cx.tcx, expr) {
+        return;
+    }
+
     if let Some(seek_trait_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) &&
         implements_trait(cx, ty, seek_trait_id, &[]) &&
         let ExprKind::Call(func, args1) = arg.kind &&
diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs
index 4712846939e..773174679db 100644
--- a/clippy_lints/src/missing_enforced_import_rename.rs
+++ b/clippy_lints/src/missing_enforced_import_rename.rs
@@ -66,35 +66,38 @@ impl LateLintPass<'_> for ImportRename {
     }
 
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
-        if_chain! {
-            if let ItemKind::Use(path, UseKind::Single) = &item.kind;
-            if let Res::Def(_, id) = path.res;
-            if let Some(name) = self.renames.get(&id);
-            // Remove semicolon since it is not present for nested imports
-            let span_without_semi = cx.sess().source_map().span_until_char(item.span, ';');
-            if let Some(snip) = snippet_opt(cx, span_without_semi);
-            if let Some(import) = match snip.split_once(" as ") {
-                None => Some(snip.as_str()),
-                Some((import, rename)) => {
-                    if rename.trim() == name.as_str() {
-                        None
-                    } else {
-                        Some(import.trim())
+        if let ItemKind::Use(path, UseKind::Single) = &item.kind {
+            for &res in &path.res {
+                if_chain! {
+                    if let Res::Def(_, id) = res;
+                    if let Some(name) = self.renames.get(&id);
+                    // Remove semicolon since it is not present for nested imports
+                    let span_without_semi = cx.sess().source_map().span_until_char(item.span, ';');
+                    if let Some(snip) = snippet_opt(cx, span_without_semi);
+                    if let Some(import) = match snip.split_once(" as ") {
+                        None => Some(snip.as_str()),
+                        Some((import, rename)) => {
+                            if rename.trim() == name.as_str() {
+                                None
+                            } else {
+                                Some(import.trim())
+                            }
+                        },
+                    };
+                    then {
+                        span_lint_and_sugg(
+                            cx,
+                            MISSING_ENFORCED_IMPORT_RENAMES,
+                            span_without_semi,
+                            "this import should be renamed",
+                            "try",
+                            format!(
+                                "{import} as {name}",
+                            ),
+                            Applicability::MachineApplicable,
+                        );
                     }
-                },
-            };
-            then {
-                span_lint_and_sugg(
-                    cx,
-                    MISSING_ENFORCED_IMPORT_RENAMES,
-                    span_without_semi,
-                    "this import should be renamed",
-                    "try",
-                    format!(
-                        "{import} as {name}",
-                    ),
-                    Applicability::MachineApplicable,
-                );
+                }
             }
         }
     }
diff --git a/clippy_lints/src/permissions_set_readonly_false.rs b/clippy_lints/src/permissions_set_readonly_false.rs
new file mode 100644
index 00000000000..e7095ec191f
--- /dev/null
+++ b/clippy_lints/src/permissions_set_readonly_false.rs
@@ -0,0 +1,52 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::paths;
+use clippy_utils::ty::match_type;
+use rustc_ast::ast::LitKind;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for calls to `std::fs::Permissions.set_readonly` with argument `false`.
+    ///
+    /// ### Why is this bad?
+    /// On Unix platforms this results in the file being world writable,
+    /// equivalent to `chmod a+w <file>`.
+    /// ### Example
+    /// ```rust
+    /// use std::fs::File;
+    /// let f = File::create("foo.txt").unwrap();
+    /// let metadata = f.metadata().unwrap();
+    /// let mut permissions = metadata.permissions();
+    /// permissions.set_readonly(false);
+    /// ```
+    #[clippy::version = "1.66.0"]
+    pub PERMISSIONS_SET_READONLY_FALSE,
+    suspicious,
+    "Checks for calls to `std::fs::Permissions.set_readonly` with argument `false`"
+}
+declare_lint_pass!(PermissionsSetReadonlyFalse => [PERMISSIONS_SET_READONLY_FALSE]);
+
+impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+        if let ExprKind::MethodCall(path, receiver, [arg], _) = &expr.kind
+            && match_type(cx, cx.typeck_results().expr_ty(receiver), &paths::PERMISSIONS)
+            && path.ident.name == sym!(set_readonly)
+            && let ExprKind::Lit(lit) = &arg.kind
+            && LitKind::Bool(false) == lit.node
+        {
+            span_lint_and_then(
+                cx,
+                PERMISSIONS_SET_READONLY_FALSE,
+                expr.span,
+                "call to `set_readonly` with argument `false`",
+                |diag| {
+                    diag.note("on Unix platforms this results in the file being world writable");
+                    diag.help("you can set the desired permissions using `PermissionsExt`. For more information, see\n\
+                        https://doc.rust-lang.org/std/os/unix/fs/trait.PermissionsExt.html");
+                }
+            );
+        }
+    }
+}
diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs
index 833dc4913b4..c2a8db7df03 100644
--- a/clippy_lints/src/redundant_pub_crate.rs
+++ b/clippy_lints/src/redundant_pub_crate.rs
@@ -84,7 +84,11 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
 
 fn is_not_macro_export<'tcx>(item: &'tcx Item<'tcx>) -> bool {
     if let ItemKind::Use(path, _) = item.kind {
-        if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = path.res {
+        if path
+            .res
+            .iter()
+            .all(|res| matches!(res, Res::Def(DefKind::Macro(MacroKind::Bang), _)))
+        {
             return false;
         }
     } else if let ItemKind::Macro(..) = item.kind {
diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs
index 81143d7799e..d4d50660520 100644
--- a/clippy_lints/src/returns.rs
+++ b/clippy_lints/src/returns.rs
@@ -6,7 +6,7 @@ use core::ops::ControlFlow;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, MatchSource, PatKind, StmtKind};
+use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, LangItem, MatchSource, PatKind, QPath, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::subst::GenericArgKind;
@@ -207,6 +207,12 @@ fn check_final_expr<'tcx>(
     match &peeled_drop_expr.kind {
         // simple return is always "bad"
         ExprKind::Ret(ref inner) => {
+            // if desugar of `do yeet`, don't lint
+            if let Some(inner_expr) = inner
+                && let ExprKind::Call(path_expr, _) = inner_expr.kind
+                && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind {
+                    return;
+            }
             if cx.tcx.hir().attrs(expr.hir_id).is_empty() {
                 let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner));
                 if !borrows {
diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs
index 2036e85db7e..d46f6a6352c 100644
--- a/clippy_lints/src/single_component_path_imports.rs
+++ b/clippy_lints/src/single_component_path_imports.rs
@@ -149,7 +149,7 @@ impl SingleComponentPathImports {
 
                 // keep track of `use some_module;` usages
                 if segments.len() == 1 {
-                    if let UseTreeKind::Simple(None, _, _) = use_tree.kind {
+                    if let UseTreeKind::Simple(None) = use_tree.kind {
                         let name = segments[0].ident.name;
                         if !macros.contains(&name) {
                             single_use_usages.push(SingleUse {
@@ -169,7 +169,7 @@ impl SingleComponentPathImports {
                         for tree in trees {
                             let segments = &tree.0.prefix.segments;
                             if segments.len() == 1 {
-                                if let UseTreeKind::Simple(None, _, _) = tree.0.kind {
+                                if let UseTreeKind::Simple(None) = tree.0.kind {
                                     let name = segments[0].ident.name;
                                     if !macros.contains(&name) {
                                         single_use_usages.push(SingleUse {
diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs
index 83e651aba8e..691d759d773 100644
--- a/clippy_lints/src/transmute/mod.rs
+++ b/clippy_lints/src/transmute/mod.rs
@@ -3,6 +3,7 @@ mod transmute_float_to_int;
 mod transmute_int_to_bool;
 mod transmute_int_to_char;
 mod transmute_int_to_float;
+mod transmute_null_to_fn;
 mod transmute_num_to_bytes;
 mod transmute_ptr_to_ptr;
 mod transmute_ptr_to_ref;
@@ -409,6 +410,34 @@ declare_clippy_lint! {
     "transmutes from a null pointer to a reference, which is undefined behavior"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for null function pointer creation through transmute.
+    ///
+    /// ### Why is this bad?
+    /// Creating a null function pointer is undefined behavior.
+    ///
+    /// More info: https://doc.rust-lang.org/nomicon/ffi.html#the-nullable-pointer-optimization
+    ///
+    /// ### Known problems
+    /// Not all cases can be detected at the moment of this writing.
+    /// For example, variables which hold a null pointer and are then fed to a `transmute`
+    /// call, aren't detectable yet.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let null_fn: fn() = unsafe { std::mem::transmute( std::ptr::null::<()>() ) };
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let null_fn: Option<fn()> = None;
+    /// ```
+    #[clippy::version = "1.67.0"]
+    pub TRANSMUTE_NULL_TO_FN,
+    correctness,
+    "transmute results in a null function pointer, which is undefined behavior"
+}
+
 pub struct Transmute {
     msrv: Msrv,
 }
@@ -428,6 +457,7 @@ impl_lint_pass!(Transmute => [
     TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
     TRANSMUTE_UNDEFINED_REPR,
     TRANSMUTING_NULL,
+    TRANSMUTE_NULL_TO_FN,
 ]);
 impl Transmute {
     #[must_use]
@@ -461,6 +491,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
                 let linted = wrong_transmute::check(cx, e, from_ty, to_ty)
                     | crosspointer_transmute::check(cx, e, from_ty, to_ty)
                     | transmuting_null::check(cx, e, arg, to_ty)
+                    | transmute_null_to_fn::check(cx, e, arg, to_ty)
                     | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, &self.msrv)
                     | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context)
                     | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
diff --git a/clippy_lints/src/transmute/transmute_null_to_fn.rs b/clippy_lints/src/transmute/transmute_null_to_fn.rs
new file mode 100644
index 00000000000..e75d7f6bf1d
--- /dev/null
+++ b/clippy_lints/src/transmute/transmute_null_to_fn.rs
@@ -0,0 +1,64 @@
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::{is_integer_literal, is_path_diagnostic_item};
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::Ty;
+use rustc_span::symbol::sym;
+
+use super::TRANSMUTE_NULL_TO_FN;
+
+fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
+    span_lint_and_then(
+        cx,
+        TRANSMUTE_NULL_TO_FN,
+        expr.span,
+        "transmuting a known null pointer into a function pointer",
+        |diag| {
+            diag.span_label(expr.span, "this transmute results in undefined behavior");
+            diag.help(
+               "try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value"
+            );
+        },
+    );
+}
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'tcx Expr<'_>, to_ty: Ty<'tcx>) -> bool {
+    if !to_ty.is_fn() {
+        return false;
+    }
+
+    match arg.kind {
+        // Catching:
+        // transmute over constants that resolve to `null`.
+        ExprKind::Path(ref _qpath)
+            if matches!(constant(cx, cx.typeck_results(), arg), Some((Constant::RawPtr(0), _))) =>
+        {
+            lint_expr(cx, expr);
+            true
+        },
+
+        // Catching:
+        // `std::mem::transmute(0 as *const i32)`
+        ExprKind::Cast(inner_expr, _cast_ty) if is_integer_literal(inner_expr, 0) => {
+            lint_expr(cx, expr);
+            true
+        },
+
+        // Catching:
+        // `std::mem::transmute(std::ptr::null::<i32>())`
+        ExprKind::Call(func1, []) if is_path_diagnostic_item(cx, func1, sym::ptr_null) => {
+            lint_expr(cx, expr);
+            true
+        },
+
+        _ => {
+            // FIXME:
+            // Also catch transmutations of variables which are known nulls.
+            // To do this, MIR const propagation seems to be the better tool.
+            // Whenever MIR const prop routines are more developed, this will
+            // become available. As of this writing (25/03/19) it is not yet.
+            false
+        },
+    }
+}
diff --git a/clippy_lints/src/transmute/transmuting_null.rs b/clippy_lints/src/transmute/transmuting_null.rs
index 19ce5ae72c2..1e407fc4138 100644
--- a/clippy_lints/src/transmute/transmuting_null.rs
+++ b/clippy_lints/src/transmute/transmuting_null.rs
@@ -18,8 +18,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
     // Catching transmute over constants that resolve to `null`.
     let mut const_eval_context = constant_context(cx, cx.typeck_results());
     if let ExprKind::Path(ref _qpath) = arg.kind &&
-        let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg) &&
-        x == 0
+        let Some(Constant::RawPtr(0)) = const_eval_context.expr(arg)
     {
         span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
         return true;
diff --git a/clippy_lints/src/unnecessary_self_imports.rs b/clippy_lints/src/unnecessary_self_imports.rs
index bc0dd263d88..397633f533b 100644
--- a/clippy_lints/src/unnecessary_self_imports.rs
+++ b/clippy_lints/src/unnecessary_self_imports.rs
@@ -57,7 +57,7 @@ impl EarlyLintPass for UnnecessarySelfImports {
                             format!(
                                 "{}{};",
                                 last_segment.ident,
-                                if let UseTreeKind::Simple(Some(alias), ..) = self_tree.kind { format!(" as {alias}") } else { String::new() },
+                                if let UseTreeKind::Simple(Some(alias)) = self_tree.kind { format!(" as {alias}") } else { String::new() },
                             ),
                             Applicability::MaybeIncorrect,
                         );
diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs
index 95258652768..7ee785804f0 100644
--- a/clippy_lints/src/unsafe_removed_from_name.rs
+++ b/clippy_lints/src/unsafe_removed_from_name.rs
@@ -39,7 +39,7 @@ impl EarlyLintPass for UnsafeNameRemoval {
 
 fn check_use_tree(use_tree: &UseTree, cx: &EarlyContext<'_>, span: Span) {
     match use_tree.kind {
-        UseTreeKind::Simple(Some(new_name), ..) => {
+        UseTreeKind::Simple(Some(new_name)) => {
             let old_name = use_tree
                 .prefix
                 .segments
@@ -48,7 +48,7 @@ fn check_use_tree(use_tree: &UseTree, cx: &EarlyContext<'_>, span: Span) {
                 .ident;
             unsafe_to_safe_check(old_name, new_name, cx, span);
         },
-        UseTreeKind::Simple(None, ..) | UseTreeKind::Glob => {},
+        UseTreeKind::Simple(None) | UseTreeKind::Glob => {},
         UseTreeKind::Nested(ref nested_use_tree) => {
             for (use_tree, _) in nested_use_tree {
                 check_use_tree(use_tree, cx, span);
diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs
index 3743d5d97a7..a95e7b61374 100644
--- a/clippy_lints/src/useless_conversion.rs
+++ b/clippy_lints/src/useless_conversion.rs
@@ -1,11 +1,11 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
 use clippy_utils::source::{snippet, snippet_with_macro_callsite};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{is_type_diagnostic_item, same_type_and_consts};
-use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, paths};
+use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts};
+use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, path_to_local, paths};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, HirId, MatchSource};
+use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, MatchSource, Node, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -81,16 +81,24 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                     }
                 }
                 if is_trait_method(cx, e, sym::IntoIterator) && name.ident.name == sym::into_iter {
-                    if let Some(parent_expr) = get_parent_expr(cx, e) {
-                        if let ExprKind::MethodCall(parent_name, ..) = parent_expr.kind {
-                            if parent_name.ident.name != sym::into_iter {
-                                return;
-                            }
-                        }
+                    if get_parent_expr(cx, e).is_some() &&
+                       let Some(id) = path_to_local(recv) &&
+                       let Node::Pat(pat) = cx.tcx.hir().get(id) &&
+                       let PatKind::Binding(ann, ..) = pat.kind &&
+                       ann != BindingAnnotation::MUT
+                    {
+                        // Do not remove .into_iter() applied to a non-mutable local variable used in
+                        // a larger expression context as it would differ in mutability.
+                        return;
                     }
+
                     let a = cx.typeck_results().expr_ty(e);
                     let b = cx.typeck_results().expr_ty(recv);
-                    if same_type_and_consts(a, b) {
+
+                    // If the types are identical then .into_iter() can be removed, unless the type
+                    // implements Copy, in which case .into_iter() returns a copy of the receiver and
+                    // cannot be safely omitted.
+                    if same_type_and_consts(a, b) && !is_copy(cx, b) {
                         let sugg = snippet(cx, recv.span, "<expr>").into_owned();
                         span_lint_and_sugg(
                             cx,
diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs
index 0c052d86eda..bd7daf0773c 100644
--- a/clippy_lints/src/utils/author.rs
+++ b/clippy_lints/src/utils/author.rs
@@ -299,7 +299,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 };
                 kind!("Float(_, {float_ty})");
             },
-            LitKind::ByteStr(ref vec) => {
+            LitKind::ByteStr(ref vec, _) => {
                 bind!(self, vec);
                 kind!("ByteStr(ref {vec})");
                 chain!(self, "let [{:?}] = **{vec}", vec.value);
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 3e7d0028c0f..c1589c771c4 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -333,7 +333,7 @@ define_Conf! {
     /// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS.
     ///
     /// The maximum allowed size for arrays on the stack
-    (array_size_threshold: u64 = 512_000),
+    (array_size_threshold: u128 = 512_000),
     /// Lint: VEC_BOX.
     ///
     /// The size of the boxed type in bytes, where boxing in a `Vec` is allowed
diff --git a/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/clippy_lints/src/utils/internal_lints/invalid_paths.rs
index 680935f2329..9afe02c1e47 100644
--- a/clippy_lints/src/utils/internal_lints/invalid_paths.rs
+++ b/clippy_lints/src/utils/internal_lints/invalid_paths.rs
@@ -7,7 +7,7 @@ use rustc_hir::def::DefKind;
 use rustc_hir::Item;
 use rustc_hir_analysis::hir_ty_to_ty;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, fast_reject::SimplifiedTypeGen, FloatTy};
+use rustc_middle::ty::{self, fast_reject::SimplifiedType, FloatTy};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::Symbol;
 
@@ -73,10 +73,10 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
     let lang_items = cx.tcx.lang_items();
     // This list isn't complete, but good enough for our current list of paths.
     let incoherent_impls = [
-        SimplifiedTypeGen::FloatSimplifiedType(FloatTy::F32),
-        SimplifiedTypeGen::FloatSimplifiedType(FloatTy::F64),
-        SimplifiedTypeGen::SliceSimplifiedType,
-        SimplifiedTypeGen::StrSimplifiedType,
+        SimplifiedType::FloatSimplifiedType(FloatTy::F32),
+        SimplifiedType::FloatSimplifiedType(FloatTy::F64),
+        SimplifiedType::SliceSimplifiedType,
+        SimplifiedType::StrSimplifiedType,
     ]
     .iter()
     .flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter().copied());
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 1aebb8b3104..786d9608c85 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
@@ -330,7 +330,7 @@ struct LintCollector<'a, 'tcx> {
 impl<'a, 'tcx> Visitor<'tcx> for LintCollector<'a, 'tcx> {
     type NestedFilter = nested_filter::All;
 
-    fn visit_path(&mut self, path: &'tcx Path<'_>, _: HirId) {
+    fn visit_path(&mut self, path: &Path<'_>, _: HirId) {
         if path.segments.len() == 1 {
             self.output.insert(path.segments[0].ident.name);
         }
diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index d06a616e4b3..857abe77e21 100644
--- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -1019,7 +1019,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for ApplicabilityResolver<'a, 'hir> {
         self.cx.tcx.hir()
     }
 
-    fn visit_path(&mut self, path: &'hir hir::Path<'hir>, _id: hir::HirId) {
+    fn visit_path(&mut self, path: &hir::Path<'hir>, _id: hir::HirId) {
         for (index, enum_value) in paths::APPLICABILITY_VALUES.iter().enumerate() {
             if match_path(path, enum_value) {
                 self.add_new_index(index);
diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs
index be98344470b..e4d1ee195c4 100644
--- a/clippy_lints/src/wildcard_imports.rs
+++ b/clippy_lints/src/wildcard_imports.rs
@@ -176,7 +176,8 @@ impl LateLintPass<'_> for WildcardImports {
                     format!("{import_source_snippet}::{imports_string}")
                 };
 
-                let (lint, message) = if let Res::Def(DefKind::Enum, _) = use_path.res {
+                // Glob imports always have a single resolution.
+                let (lint, message) = if let Res::Def(DefKind::Enum, _) = use_path.res[0] {
                     (ENUM_GLOB_USE, "usage of wildcard import for enum variants")
                 } else {
                     (WILDCARD_IMPORTS, "usage of wildcard import")
diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml
index fb9f4740ecc..ac6a566b9cd 100644
--- a/clippy_utils/Cargo.toml
+++ b/clippy_utils/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_utils"
-version = "0.1.67"
+version = "0.1.68"
 edition = "2021"
 publish = false
 
diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs
index 6bcf0bbd7eb..49e5f283db0 100644
--- a/clippy_utils/src/ast_utils.rs
+++ b/clippy_utils/src/ast_utils.rs
@@ -566,7 +566,7 @@ pub fn eq_use_tree_kind(l: &UseTreeKind, r: &UseTreeKind) -> bool {
     use UseTreeKind::*;
     match (l, r) {
         (Glob, Glob) => true,
-        (Simple(l, _, _), Simple(r, _, _)) => both(l, r, |l, r| eq_id(*l, *r)),
+        (Simple(l), Simple(r)) => both(l, r, |l, r| eq_id(*l, *r)),
         (Nested(l), Nested(r)) => over(l, r, |(l, _), (r, _)| eq_use_tree(l, r)),
         _ => false,
     }
diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs
index c6bf98b7b8b..43f0df145f0 100644
--- a/clippy_utils/src/check_proc_macro.rs
+++ b/clippy_utils/src/check_proc_macro.rs
@@ -69,7 +69,9 @@ fn lit_search_pat(lit: &LitKind) -> (Pat, Pat) {
         LitKind::Str(_, StrStyle::Cooked) => (Pat::Str("\""), Pat::Str("\"")),
         LitKind::Str(_, StrStyle::Raw(0)) => (Pat::Str("r"), Pat::Str("\"")),
         LitKind::Str(_, StrStyle::Raw(_)) => (Pat::Str("r#"), Pat::Str("#")),
-        LitKind::ByteStr(_) => (Pat::Str("b\""), Pat::Str("\"")),
+        LitKind::ByteStr(_, StrStyle::Cooked) => (Pat::Str("b\""), Pat::Str("\"")),
+        LitKind::ByteStr(_, StrStyle::Raw(0)) => (Pat::Str("br\""), Pat::Str("\"")),
+        LitKind::ByteStr(_, StrStyle::Raw(_)) => (Pat::Str("br#\""), Pat::Str("#")),
         LitKind::Byte(_) => (Pat::Str("b'"), Pat::Str("'")),
         LitKind::Char(_) => (Pat::Str("'"), Pat::Str("'")),
         LitKind::Int(_, LitIntType::Signed(IntTy::Isize)) => (Pat::Num, Pat::Str("isize")),
diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs
index 315aea9aa09..a67bd8d4600 100644
--- a/clippy_utils/src/consts.rs
+++ b/clippy_utils/src/consts.rs
@@ -210,7 +210,7 @@ pub fn lit_to_mir_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
     match *lit {
         LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
         LitKind::Byte(b) => Constant::Int(u128::from(b)),
-        LitKind::ByteStr(ref s) => Constant::Binary(Lrc::clone(s)),
+        LitKind::ByteStr(ref s, _) => Constant::Binary(Lrc::clone(s)),
         LitKind::Char(c) => Constant::Char(c),
         LitKind::Int(n, _) => Constant::Int(n),
         LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty {
@@ -620,12 +620,7 @@ pub fn miri_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::ConstantKind<'tcx>) -
                 ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(
                     int.try_into().expect("invalid f64 bit representation"),
                 ))),
-                ty::RawPtr(type_and_mut) => {
-                    if let ty::Uint(_) = type_and_mut.ty.kind() {
-                        return Some(Constant::RawPtr(int.assert_bits(int.size())));
-                    }
-                    None
-                },
+                ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))),
                 // FIXME: implement other conversions.
                 _ => None,
             }
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index 09ed7255a2b..43e2d1ec826 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -97,7 +97,7 @@ use rustc_middle::hir::place::PlaceBase;
 use rustc_middle::ty as rustc_ty;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::binding::BindingMode;
-use rustc_middle::ty::fast_reject::SimplifiedTypeGen::{
+use rustc_middle::ty::fast_reject::SimplifiedType::{
     ArraySimplifiedType, BoolSimplifiedType, CharSimplifiedType, FloatSimplifiedType, IntSimplifiedType,
     PtrSimplifiedType, SliceSimplifiedType, StrSimplifiedType, UintSimplifiedType,
 };
diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs
index d13b34a66cc..77c5f115542 100644
--- a/clippy_utils/src/macros.rs
+++ b/clippy_utils/src/macros.rs
@@ -208,6 +208,12 @@ pub fn is_panic(cx: &LateContext<'_>, def_id: DefId) -> bool {
     )
 }
 
+/// Is `def_id` of `assert!` or `debug_assert!`
+pub fn is_assert_macro(cx: &LateContext<'_>, def_id: DefId) -> bool {
+    let Some(name) = cx.tcx.get_diagnostic_name(def_id) else { return false };
+    matches!(name, sym::assert_macro | sym::debug_assert_macro)
+}
+
 pub enum PanicExpn<'a> {
     /// No arguments - `panic!()`
     Empty,
diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs
index 6417f0f3c71..9ca50105ae5 100644
--- a/clippy_utils/src/paths.rs
+++ b/clippy_utils/src/paths.rs
@@ -20,7 +20,6 @@ pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "
 pub const BTREEMAP_INSERT: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "insert"];
 pub const BTREESET_ITER: [&str; 6] = ["alloc", "collections", "btree", "set", "BTreeSet", "iter"];
 pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"];
-pub const CORE_ITER_COLLECT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "collect"];
 pub const CORE_ITER_CLONED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "cloned"];
 pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "copied"];
 pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"];
diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs
index 480e8e55cf3..e5d7da68281 100644
--- a/clippy_utils/src/qualify_min_const_fn.rs
+++ b/clippy_utils/src/qualify_min_const_fn.rs
@@ -82,7 +82,7 @@ fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult {
             ty::Ref(_, _, hir::Mutability::Mut) => {
                 return Err((span, "mutable references in const fn are unstable".into()));
             },
-            ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
+            ty::Alias(ty::Opaque, ..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
             ty::FnPtr(..) => {
                 return Err((span, "function pointers in const fn are unstable".into()));
             },
@@ -301,11 +301,7 @@ fn check_terminator<'tcx>(
             check_operand(tcx, value, span, body)
         },
 
-        TerminatorKind::SwitchInt {
-            discr,
-            switch_ty: _,
-            targets: _,
-        } => check_operand(tcx, discr, span, body),
+        TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body),
 
         TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())),
         TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs
index 81b08ae5600..2773da70d78 100644
--- a/clippy_utils/src/ty.rs
+++ b/clippy_utils/src/ty.rs
@@ -16,8 +16,8 @@ use rustc_infer::infer::{
 use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::{ConstValue, Scalar};
 use rustc_middle::ty::{
-    self, AdtDef, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, IntTy, List, ParamEnv, Predicate, PredicateKind,
-    ProjectionTy, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy,
+    self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, IntTy, List, ParamEnv, Predicate,
+    PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy,
     VariantDef, VariantDiscr,
 };
 use rustc_middle::ty::{GenericArg, GenericArgKind};
@@ -69,50 +69,66 @@ pub fn contains_adt_constructor<'tcx>(ty: Ty<'tcx>, adt: AdtDef<'tcx>) -> bool {
 /// This method also recurses into opaque type predicates, so call it with `impl Trait<U>` and `U`
 /// will also return `true`.
 pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, needle: Ty<'tcx>) -> bool {
-    ty.walk().any(|inner| match inner.unpack() {
-        GenericArgKind::Type(inner_ty) => {
-            if inner_ty == needle {
-                return true;
-            }
+    fn contains_ty_adt_constructor_opaque_inner<'tcx>(
+        cx: &LateContext<'tcx>,
+        ty: Ty<'tcx>,
+        needle: Ty<'tcx>,
+        seen: &mut FxHashSet<DefId>,
+    ) -> bool {
+        ty.walk().any(|inner| match inner.unpack() {
+            GenericArgKind::Type(inner_ty) => {
+                if inner_ty == needle {
+                    return true;
+                }
 
-            if inner_ty.ty_adt_def() == needle.ty_adt_def() {
-                return true;
-            }
+                if inner_ty.ty_adt_def() == needle.ty_adt_def() {
+                    return true;
+                }
 
-            if let ty::Opaque(def_id, _) = *inner_ty.kind() {
-                for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
-                    match predicate.kind().skip_binder() {
-                        // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
-                        // and check substituions to find `U`.
-                        ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
-                            if trait_predicate
-                                .trait_ref
-                                .substs
-                                .types()
-                                .skip(1) // Skip the implicit `Self` generic parameter
-                                .any(|ty| contains_ty_adt_constructor_opaque(cx, ty, needle))
-                            {
-                                return true;
-                            }
-                        },
-                        // For `impl Trait<Assoc=U>`, it will register a predicate of `<T as Trait>::Assoc = U`,
-                        // so we check the term for `U`.
-                        ty::PredicateKind::Clause(ty::Clause::Projection(projection_predicate)) => {
-                            if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack() {
-                                if contains_ty_adt_constructor_opaque(cx, ty, needle) {
+                if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *inner_ty.kind() {
+                    if !seen.insert(def_id) {
+                        return false;
+                    }
+
+                    for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
+                        match predicate.kind().skip_binder() {
+                            // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
+                            // and check substituions to find `U`.
+                            ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
+                                if trait_predicate
+                                    .trait_ref
+                                    .substs
+                                    .types()
+                                    .skip(1) // Skip the implicit `Self` generic parameter
+                                    .any(|ty| contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen))
+                                {
                                     return true;
                                 }
-                            };
-                        },
-                        _ => (),
+                            },
+                            // For `impl Trait<Assoc=U>`, it will register a predicate of `<T as Trait>::Assoc = U`,
+                            // so we check the term for `U`.
+                            ty::PredicateKind::Clause(ty::Clause::Projection(projection_predicate)) => {
+                                if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack() {
+                                    if contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen) {
+                                        return true;
+                                    }
+                                };
+                            },
+                            _ => (),
+                        }
                     }
                 }
-            }
 
-            false
-        },
-        GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
-    })
+                false
+            },
+            GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
+        })
+    }
+
+    // A hash set to ensure that the same opaque type (`impl Trait` in RPIT or TAIT) is not
+    // visited twice.
+    let mut seen = FxHashSet::default();
+    contains_ty_adt_constructor_opaque_inner(cx, ty, needle, &mut seen)
 }
 
 /// Resolves `<T as Iterator>::Item` for `T`
@@ -250,7 +266,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
             is_must_use_ty(cx, *ty)
         },
         ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)),
-        ty::Opaque(def_id, _) => {
+        ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
             for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
                 if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() {
                     if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) {
@@ -631,7 +647,9 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
             Some(ExprFnSig::Closure(decl, subs.as_closure().sig()))
         },
         ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))),
-        ty::Opaque(id, _) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(id), cx.tcx.opt_parent(id)),
+        ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
+            sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id), cx.tcx.opt_parent(def_id))
+        },
         ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
         ty::Dynamic(bounds, _, _) => {
             let lang_items = cx.tcx.lang_items();
@@ -650,7 +668,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
                 _ => None,
             }
         },
-        ty::Projection(proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) {
+        ty::Alias(ty::Projection, proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) {
             Ok(normalized_ty) if normalized_ty != ty => ty_sig(cx, normalized_ty),
             _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)),
         },
@@ -685,8 +703,7 @@ fn sig_from_bounds<'tcx>(
                 inputs = Some(i);
             },
             PredicateKind::Clause(ty::Clause::Projection(p))
-                if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output()
-                    && p.projection_ty.self_ty() == ty =>
+                if Some(p.projection_ty.def_id) == lang_items.fn_once_output() && p.projection_ty.self_ty() == ty =>
             {
                 if output.is_some() {
                     // Multiple different fn trait impls. Is this even allowed?
@@ -701,14 +718,14 @@ fn sig_from_bounds<'tcx>(
     inputs.map(|ty| ExprFnSig::Trait(ty, output, predicates_id))
 }
 
-fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> Option<ExprFnSig<'tcx>> {
+fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option<ExprFnSig<'tcx>> {
     let mut inputs = None;
     let mut output = None;
     let lang_items = cx.tcx.lang_items();
 
     for (pred, _) in cx
         .tcx
-        .bound_explicit_item_bounds(ty.item_def_id)
+        .bound_explicit_item_bounds(ty.def_id)
         .subst_iter_copied(cx.tcx, ty.substs)
     {
         match pred.kind().skip_binder() {
@@ -726,7 +743,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O
                 inputs = Some(i);
             },
             PredicateKind::Clause(ty::Clause::Projection(p))
-                if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() =>
+                if Some(p.projection_ty.def_id) == lang_items.fn_once_output() =>
             {
                 if output.is_some() {
                     // Multiple different fn trait impls. Is this even allowed?
@@ -980,13 +997,13 @@ pub fn make_projection<'tcx>(
     container_id: DefId,
     assoc_ty: Symbol,
     substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
-) -> Option<ProjectionTy<'tcx>> {
+) -> Option<AliasTy<'tcx>> {
     fn helper<'tcx>(
         tcx: TyCtxt<'tcx>,
         container_id: DefId,
         assoc_ty: Symbol,
         substs: SubstsRef<'tcx>,
-    ) -> Option<ProjectionTy<'tcx>> {
+    ) -> Option<AliasTy<'tcx>> {
         let Some(assoc_item) = tcx
             .associated_items(container_id)
             .find_by_name_and_kind(tcx, Ident::with_dummy_span(assoc_ty), AssocKind::Type, container_id)
@@ -1039,10 +1056,7 @@ pub fn make_projection<'tcx>(
             }
         }
 
-        Some(ProjectionTy {
-            substs,
-            item_def_id: assoc_item.def_id,
-        })
+        Some(tcx.mk_alias_ty(assoc_item.def_id, substs))
     }
     helper(
         tcx,
@@ -1065,7 +1079,7 @@ pub fn make_normalized_projection<'tcx>(
     assoc_ty: Symbol,
     substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
 ) -> Option<Ty<'tcx>> {
-    fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: ProjectionTy<'tcx>) -> Option<Ty<'tcx>> {
+    fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> {
         #[cfg(debug_assertions)]
         if let Some((i, subst)) = ty
             .substs
@@ -1081,7 +1095,7 @@ pub fn make_normalized_projection<'tcx>(
             );
             return None;
         }
-        match tcx.try_normalize_erasing_regions(param_env, tcx.mk_projection(ty.item_def_id, ty.substs)) {
+        match tcx.try_normalize_erasing_regions(param_env, tcx.mk_projection(ty.def_id, ty.substs)) {
             Ok(ty) => Some(ty),
             Err(e) => {
                 debug_assert!(false, "failed to normalize type `{ty}`: {e:#?}");
diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs
index 797722cfc1f..ab3976a13bd 100644
--- a/clippy_utils/src/usage.rs
+++ b/clippy_utils/src/usage.rs
@@ -128,7 +128,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> {
         }
     }
 
-    fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) {
+    fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
         if let hir::def::Res::Local(id) = path.res {
             if self.binding_ids.contains(&id) {
                 self.usage_found = true;
diff --git a/declare_clippy_lint/Cargo.toml b/declare_clippy_lint/Cargo.toml
index 082570f1fe5..c01e1062cb5 100644
--- a/declare_clippy_lint/Cargo.toml
+++ b/declare_clippy_lint/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "declare_clippy_lint"
-version = "0.1.67"
+version = "0.1.68"
 edition = "2021"
 publish = false
 
diff --git a/rust-toolchain b/rust-toolchain
index 19fee38db46..8e21cef32ab 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-12-01"
+channel = "nightly-2022-12-17"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/rustc_tools_util/CHANGELOG.md b/rustc_tools_util/CHANGELOG.md
new file mode 100644
index 00000000000..1b351da2e7b
--- /dev/null
+++ b/rustc_tools_util/CHANGELOG.md
@@ -0,0 +1,6 @@
+# Changelog
+
+## Version 0.3.0
+
+* Added `setup_version_info!();` macro for automated scripts.
+* `get_version_info!()` no longer requires the user to import `rustc_tools_util::VersionInfo` and `std::env`
diff --git a/rustc_tools_util/Cargo.toml b/rustc_tools_util/Cargo.toml
index 89c3d6aaa89..877049ae7d0 100644
--- a/rustc_tools_util/Cargo.toml
+++ b/rustc_tools_util/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "rustc_tools_util"
-version = "0.2.1"
+version = "0.3.0"
 description = "small helper to generate version information for git packages"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/rustc_tools_util/README.md b/rustc_tools_util/README.md
index e947f9c7e66..eefc661f963 100644
--- a/rustc_tools_util/README.md
+++ b/rustc_tools_util/README.md
@@ -13,43 +13,39 @@ build = "build.rs"
 List rustc_tools_util as regular AND build dependency.
 ````toml
 [dependencies]
-rustc_tools_util = "0.2.1"
+rustc_tools_util = "0.3.0"
 
 [build-dependencies]
-rustc_tools_util = "0.2.1"
+rustc_tools_util = "0.3.0"
 ````
 
 In `build.rs`, generate the data in your `main()`
-````rust
+
+```rust
 fn main() {
-    println!(
-        "cargo:rustc-env=GIT_HASH={}",
-        rustc_tools_util::get_commit_hash().unwrap_or_default()
-    );
-    println!(
-        "cargo:rustc-env=COMMIT_DATE={}",
-        rustc_tools_util::get_commit_date().unwrap_or_default()
-    );
-    println!(
-        "cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}",
-        rustc_tools_util::get_channel().unwrap_or_default()
-    );
+    rustc_tools_util::setup_version_info!();
 }
-
-````
+```
 
 Use the version information in your main.rs
-````rust
-use rustc_tools_util::*;
 
+```rust
 fn show_version() {
     let version_info = rustc_tools_util::get_version_info!();
     println!("{}", version_info);
 }
-````
+```
+
 This gives the following output in clippy:
-`clippy 0.0.212 (a416c5e 2018-12-14)`
+`clippy 0.1.66 (a28f3c8 2022-11-20)`
+
+## Repository
+
+This project is part of the rust-lang/rust-clippy repository. The source code
+can be found under `./rustc_tools_util/`.
 
+The changelog for `rustc_tools_util` is available under:
+[`rustc_tools_util/CHANGELOG.md`](https://github.com/rust-lang/rust-clippy/blob/master/rustc_tools_util/CHANGELOG.md)
 
 ## License
 
diff --git a/rustc_tools_util/src/lib.rs b/rustc_tools_util/src/lib.rs
index 01d25c53126..4c1d8c3733d 100644
--- a/rustc_tools_util/src/lib.rs
+++ b/rustc_tools_util/src/lib.rs
@@ -1,20 +1,20 @@
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
 
-use std::env;
-
+/// This macro creates the version string during compilation from the
+/// current environment
 #[macro_export]
 macro_rules! get_version_info {
     () => {{
-        let major = env!("CARGO_PKG_VERSION_MAJOR").parse::<u8>().unwrap();
-        let minor = env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap();
-        let patch = env!("CARGO_PKG_VERSION_PATCH").parse::<u16>().unwrap();
-        let crate_name = String::from(env!("CARGO_PKG_NAME"));
+        let major = std::env!("CARGO_PKG_VERSION_MAJOR").parse::<u8>().unwrap();
+        let minor = std::env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap();
+        let patch = std::env!("CARGO_PKG_VERSION_PATCH").parse::<u16>().unwrap();
+        let crate_name = String::from(std::env!("CARGO_PKG_NAME"));
 
-        let host_compiler = option_env!("RUSTC_RELEASE_CHANNEL").map(str::to_string);
-        let commit_hash = option_env!("GIT_HASH").map(str::to_string);
-        let commit_date = option_env!("COMMIT_DATE").map(str::to_string);
+        let host_compiler = std::option_env!("RUSTC_RELEASE_CHANNEL").map(str::to_string);
+        let commit_hash = std::option_env!("GIT_HASH").map(str::to_string);
+        let commit_date = std::option_env!("COMMIT_DATE").map(str::to_string);
 
-        VersionInfo {
+        $crate::VersionInfo {
             major,
             minor,
             patch,
@@ -26,6 +26,24 @@ macro_rules! get_version_info {
     }};
 }
 
+/// This macro can be used in `build.rs` to automatically set the needed
+/// environment values, namely `GIT_HASH`, `COMMIT_DATE` and
+/// `RUSTC_RELEASE_CHANNEL`
+#[macro_export]
+macro_rules! setup_version_info {
+    () => {{
+        println!(
+            "cargo:rustc-env=GIT_HASH={}",
+            $crate::get_commit_hash().unwrap_or_default()
+        );
+        println!(
+            "cargo:rustc-env=COMMIT_DATE={}",
+            $crate::get_commit_date().unwrap_or_default()
+        );
+        println!("cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}", $crate::get_channel());
+    }};
+}
+
 // some code taken and adapted from RLS and cargo
 pub struct VersionInfo {
     pub major: u8,
@@ -101,7 +119,7 @@ pub fn get_commit_date() -> Option<String> {
 
 #[must_use]
 pub fn get_channel() -> String {
-    match env::var("CFG_RELEASE_CHANNEL") {
+    match std::env::var("CFG_RELEASE_CHANNEL") {
         Ok(channel) => channel,
         Err(_) => {
             // if that failed, try to ask rustc -V, do some parsing and find out
@@ -136,8 +154,8 @@ mod test {
     fn test_struct_local() {
         let vi = get_version_info!();
         assert_eq!(vi.major, 0);
-        assert_eq!(vi.minor, 2);
-        assert_eq!(vi.patch, 1);
+        assert_eq!(vi.minor, 3);
+        assert_eq!(vi.patch, 0);
         assert_eq!(vi.crate_name, "rustc_tools_util");
         // hard to make positive tests for these since they will always change
         assert!(vi.commit_hash.is_none());
@@ -147,7 +165,7 @@ mod test {
     #[test]
     fn test_display_local() {
         let vi = get_version_info!();
-        assert_eq!(vi.to_string(), "rustc_tools_util 0.2.1");
+        assert_eq!(vi.to_string(), "rustc_tools_util 0.3.0");
     }
 
     #[test]
@@ -156,7 +174,7 @@ mod test {
         let s = format!("{vi:?}");
         assert_eq!(
             s,
-            "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 2, patch: 1 }"
+            "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 3, patch: 0 }"
         );
     }
 }
diff --git a/src/driver.rs b/src/driver.rs
index 9ec4df8e651..bcc096c570e 100644
--- a/src/driver.rs
+++ b/src/driver.rs
@@ -19,7 +19,6 @@ extern crate rustc_span;
 use rustc_interface::interface;
 use rustc_session::parse::ParseSess;
 use rustc_span::symbol::Symbol;
-use rustc_tools_util::VersionInfo;
 
 use std::borrow::Cow;
 use std::env;
diff --git a/src/main.rs b/src/main.rs
index d418d2daa31..7a78b32620d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,7 +2,6 @@
 // warn on lints, that are included in `rust-lang/rust`s bootstrap
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
-use rustc_tools_util::VersionInfo;
 use std::env;
 use std::path::PathBuf;
 use std::process::{self, Command};
diff --git a/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr b/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
index 2a240cc249b..3ca45404e44 100644
--- a/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
+++ b/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
@@ -7,14 +7,6 @@ LL |     const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"];
    = help: convert all references to use `sym::Deref`
    = note: `-D clippy::unnecessary-def-path` implied by `-D warnings`
 
-error: hardcoded path to a diagnostic item
-  --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
-   |
-LL |     const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
-   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: convert all references to use `sym::deref_method`
-
 error: hardcoded path to a language item
   --> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40
    |
@@ -23,5 +15,13 @@ LL |     const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"]
    |
    = help: convert all references to use `LangItem::DerefMut`
 
+error: hardcoded path to a diagnostic item
+  --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
+   |
+LL |     const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: convert all references to use `sym::deref_method`
+
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/crashes/ice-10044.rs b/tests/ui/crashes/ice-10044.rs
new file mode 100644
index 00000000000..65f38fe7118
--- /dev/null
+++ b/tests/ui/crashes/ice-10044.rs
@@ -0,0 +1,3 @@
+fn main() {
+    [0; usize::MAX];
+}
diff --git a/tests/ui/crashes/ice-10044.stderr b/tests/ui/crashes/ice-10044.stderr
new file mode 100644
index 00000000000..731f8265ad6
--- /dev/null
+++ b/tests/ui/crashes/ice-10044.stderr
@@ -0,0 +1,10 @@
+error: statement with no effect
+  --> $DIR/ice-10044.rs:2:5
+   |
+LL |     [0; usize::MAX];
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::no-effect` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/explicit_counter_loop.rs b/tests/ui/explicit_counter_loop.rs
index 6eddc01e2c4..46565a97f00 100644
--- a/tests/ui/explicit_counter_loop.rs
+++ b/tests/ui/explicit_counter_loop.rs
@@ -189,3 +189,33 @@ mod issue_7920 {
         }
     }
 }
+
+mod issue_10058 {
+    pub fn test() {
+        // should not lint since we are increasing counter potentially more than once in the loop
+        let values = [0, 1, 0, 1, 1, 1, 0, 1, 0, 1];
+        let mut counter = 0;
+        for value in values {
+            counter += 1;
+
+            if value == 0 {
+                continue;
+            }
+
+            counter += 1;
+        }
+    }
+
+    pub fn test2() {
+        // should not lint since we are increasing counter potentially more than once in the loop
+        let values = [0, 1, 0, 1, 1, 1, 0, 1, 0, 1];
+        let mut counter = 0;
+        for value in values {
+            counter += 1;
+
+            if value != 0 {
+                counter += 1;
+            }
+        }
+    }
+}
diff --git a/tests/ui/fn_null_check.rs b/tests/ui/fn_null_check.rs
new file mode 100644
index 00000000000..df5bc8420d5
--- /dev/null
+++ b/tests/ui/fn_null_check.rs
@@ -0,0 +1,21 @@
+#![allow(unused)]
+#![warn(clippy::fn_null_check)]
+#![allow(clippy::cmp_null)]
+#![allow(clippy::ptr_eq)]
+#![allow(clippy::zero_ptr)]
+
+pub const ZPTR: *const () = 0 as *const _;
+pub const NOT_ZPTR: *const () = 1 as *const _;
+
+fn main() {
+    let fn_ptr = main;
+
+    if (fn_ptr as *mut ()).is_null() {}
+    if (fn_ptr as *const u8).is_null() {}
+    if (fn_ptr as *const ()) == std::ptr::null() {}
+    if (fn_ptr as *const ()) == (0 as *const ()) {}
+    if (fn_ptr as *const ()) == ZPTR {}
+
+    // no lint
+    if (fn_ptr as *const ()) == NOT_ZPTR {}
+}
diff --git a/tests/ui/fn_null_check.stderr b/tests/ui/fn_null_check.stderr
new file mode 100644
index 00000000000..660dd323979
--- /dev/null
+++ b/tests/ui/fn_null_check.stderr
@@ -0,0 +1,43 @@
+error: function pointer assumed to be nullable, even though it isn't
+  --> $DIR/fn_null_check.rs:13:8
+   |
+LL |     if (fn_ptr as *mut ()).is_null() {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
+   = note: `-D clippy::fn-null-check` implied by `-D warnings`
+
+error: function pointer assumed to be nullable, even though it isn't
+  --> $DIR/fn_null_check.rs:14:8
+   |
+LL |     if (fn_ptr as *const u8).is_null() {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
+
+error: function pointer assumed to be nullable, even though it isn't
+  --> $DIR/fn_null_check.rs:15:8
+   |
+LL |     if (fn_ptr as *const ()) == std::ptr::null() {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
+
+error: function pointer assumed to be nullable, even though it isn't
+  --> $DIR/fn_null_check.rs:16:8
+   |
+LL |     if (fn_ptr as *const ()) == (0 as *const ()) {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
+
+error: function pointer assumed to be nullable, even though it isn't
+  --> $DIR/fn_null_check.rs:17:8
+   |
+LL |     if (fn_ptr as *const ()) == ZPTR {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/macro_use_imports.stderr b/tests/ui/macro_use_imports.stderr
index bf7b6edd0e3..61843124ccd 100644
--- a/tests/ui/macro_use_imports.stderr
+++ b/tests/ui/macro_use_imports.stderr
@@ -1,8 +1,8 @@
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> $DIR/macro_use_imports.rs:23:5
+  --> $DIR/macro_use_imports.rs:25:5
    |
 LL |     #[macro_use]
-   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
    |
    = note: `-D clippy::macro-use-imports` implied by `-D warnings`
 
@@ -13,10 +13,10 @@ LL |     #[macro_use]
    |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;`
 
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> $DIR/macro_use_imports.rs:25:5
+  --> $DIR/macro_use_imports.rs:23:5
    |
 LL |     #[macro_use]
-   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
 
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
   --> $DIR/macro_use_imports.rs:19:5
diff --git a/tests/ui/manual_filter.fixed b/tests/ui/manual_filter.fixed
index 3553291b87d..ef6780dc96d 100644
--- a/tests/ui/manual_filter.fixed
+++ b/tests/ui/manual_filter.fixed
@@ -116,4 +116,45 @@ fn main() {
         },
         None => None,
     };
+
+    match Some(20) {
+        // Don't Lint, because `Some(3*x)` is not `None`
+        None => None,
+        Some(x) => {
+            if x > 0 {
+                Some(3 * x)
+            } else {
+                Some(x)
+            }
+        },
+    };
+
+    // Don't lint: https://github.com/rust-lang/rust-clippy/issues/10088
+    let result = if let Some(a) = maybe_some() {
+        if let Some(b) = maybe_some() {
+            Some(a + b)
+        } else {
+            Some(a)
+        }
+    } else {
+        None
+    };
+
+    let allowed_integers = vec![3, 4, 5, 6];
+    // Don't lint, since there's a side effect in the else branch
+    match Some(21) {
+        Some(x) => {
+            if allowed_integers.contains(&x) {
+                Some(x)
+            } else {
+                println!("Invalid integer: {x:?}");
+                None
+            }
+        },
+        None => None,
+    };
+}
+
+fn maybe_some() -> Option<u32> {
+    Some(0)
 }
diff --git a/tests/ui/manual_filter.rs b/tests/ui/manual_filter.rs
index aa9f90f752b..ea0ce83172b 100644
--- a/tests/ui/manual_filter.rs
+++ b/tests/ui/manual_filter.rs
@@ -240,4 +240,45 @@ fn main() {
         },
         None => None,
     };
+
+    match Some(20) {
+        // Don't Lint, because `Some(3*x)` is not `None`
+        None => None,
+        Some(x) => {
+            if x > 0 {
+                Some(3 * x)
+            } else {
+                Some(x)
+            }
+        },
+    };
+
+    // Don't lint: https://github.com/rust-lang/rust-clippy/issues/10088
+    let result = if let Some(a) = maybe_some() {
+        if let Some(b) = maybe_some() {
+            Some(a + b)
+        } else {
+            Some(a)
+        }
+    } else {
+        None
+    };
+
+    let allowed_integers = vec![3, 4, 5, 6];
+    // Don't lint, since there's a side effect in the else branch
+    match Some(21) {
+        Some(x) => {
+            if allowed_integers.contains(&x) {
+                Some(x)
+            } else {
+                println!("Invalid integer: {x:?}");
+                None
+            }
+        },
+        None => None,
+    };
+}
+
+fn maybe_some() -> Option<u32> {
+    Some(0)
 }
diff --git a/tests/ui/manual_is_ascii_check.fixed b/tests/ui/manual_is_ascii_check.fixed
index 231ba83b142..5b2b44c2fdb 100644
--- a/tests/ui/manual_is_ascii_check.fixed
+++ b/tests/ui/manual_is_ascii_check.fixed
@@ -15,6 +15,19 @@ fn main() {
     assert!('x'.is_ascii_alphabetic());
 
     assert!(matches!('x', 'A'..='Z' | 'a'..='z' | '_'));
+
+    b'0'.is_ascii_digit();
+    b'a'.is_ascii_lowercase();
+    b'A'.is_ascii_uppercase();
+
+    '0'.is_ascii_digit();
+    'a'.is_ascii_lowercase();
+    'A'.is_ascii_uppercase();
+
+    let cool_letter = &'g';
+    cool_letter.is_ascii_digit();
+    cool_letter.is_ascii_lowercase();
+    cool_letter.is_ascii_uppercase();
 }
 
 #[clippy::msrv = "1.23"]
diff --git a/tests/ui/manual_is_ascii_check.rs b/tests/ui/manual_is_ascii_check.rs
index 39ee6151c56..c9433f33a1b 100644
--- a/tests/ui/manual_is_ascii_check.rs
+++ b/tests/ui/manual_is_ascii_check.rs
@@ -15,6 +15,19 @@ fn main() {
     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
 
     assert!(matches!('x', 'A'..='Z' | 'a'..='z' | '_'));
+
+    (b'0'..=b'9').contains(&b'0');
+    (b'a'..=b'z').contains(&b'a');
+    (b'A'..=b'Z').contains(&b'A');
+
+    ('0'..='9').contains(&'0');
+    ('a'..='z').contains(&'a');
+    ('A'..='Z').contains(&'A');
+
+    let cool_letter = &'g';
+    ('0'..='9').contains(cool_letter);
+    ('a'..='z').contains(cool_letter);
+    ('A'..='Z').contains(cool_letter);
 }
 
 #[clippy::msrv = "1.23"]
diff --git a/tests/ui/manual_is_ascii_check.stderr b/tests/ui/manual_is_ascii_check.stderr
index 397cbe05c82..ee60188506d 100644
--- a/tests/ui/manual_is_ascii_check.stderr
+++ b/tests/ui/manual_is_ascii_check.stderr
@@ -43,28 +43,82 @@ LL |     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_alphabetic()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:29:13
+  --> $DIR/manual_is_ascii_check.rs:19:5
+   |
+LL |     (b'0'..=b'9').contains(&b'0');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'0'.is_ascii_digit()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:20:5
+   |
+LL |     (b'a'..=b'z').contains(&b'a');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'a'.is_ascii_lowercase()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:21:5
+   |
+LL |     (b'A'..=b'Z').contains(&b'A');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'A'.is_ascii_uppercase()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:23:5
+   |
+LL |     ('0'..='9').contains(&'0');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'0'.is_ascii_digit()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:24:5
+   |
+LL |     ('a'..='z').contains(&'a');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'a'.is_ascii_lowercase()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:25:5
+   |
+LL |     ('A'..='Z').contains(&'A');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'A'.is_ascii_uppercase()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:28:5
+   |
+LL |     ('0'..='9').contains(cool_letter);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_digit()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:29:5
+   |
+LL |     ('a'..='z').contains(cool_letter);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_lowercase()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:30:5
+   |
+LL |     ('A'..='Z').contains(cool_letter);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_uppercase()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:42:13
    |
 LL |     assert!(matches!(b'1', b'0'..=b'9'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'1'.is_ascii_digit()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:30:13
+  --> $DIR/manual_is_ascii_check.rs:43:13
    |
 LL |     assert!(matches!('X', 'A'..='Z'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'X'.is_ascii_uppercase()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:31:13
+  --> $DIR/manual_is_ascii_check.rs:44:13
    |
 LL |     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_alphabetic()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:41:23
+  --> $DIR/manual_is_ascii_check.rs:54:23
    |
 LL |     const FOO: bool = matches!('x', '0'..='9');
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_digit()`
 
-error: aborting due to 11 previous errors
+error: aborting due to 20 previous errors
 
diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed
index 4386aaec49e..d451be1f389 100644
--- a/tests/ui/needless_return.fixed
+++ b/tests/ui/needless_return.fixed
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![feature(lint_reasons)]
+#![feature(yeet_expr)]
 #![allow(unused)]
 #![allow(
     clippy::if_same_then_else,
@@ -272,4 +273,8 @@ mod issue9416 {
     }
 }
 
+fn issue9947() -> Result<(), String> {
+    do yeet "hello";
+}
+
 fn main() {}
diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs
index 666dc54b76b..e1a1bea2c0b 100644
--- a/tests/ui/needless_return.rs
+++ b/tests/ui/needless_return.rs
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![feature(lint_reasons)]
+#![feature(yeet_expr)]
 #![allow(unused)]
 #![allow(
     clippy::if_same_then_else,
@@ -282,4 +283,8 @@ mod issue9416 {
     }
 }
 
+fn issue9947() -> Result<(), String> {
+    do yeet "hello";
+}
+
 fn main() {}
diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr
index a8b5d86cd55..ca2253e6586 100644
--- a/tests/ui/needless_return.stderr
+++ b/tests/ui/needless_return.stderr
@@ -1,5 +1,5 @@
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:26:5
+  --> $DIR/needless_return.rs:27:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL |     return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:30:5
+  --> $DIR/needless_return.rs:31:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL |     return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:35:9
+  --> $DIR/needless_return.rs:36:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -24,7 +24,7 @@ LL |         return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:37:9
+  --> $DIR/needless_return.rs:38:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^
@@ -32,7 +32,7 @@ LL |         return false;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:43:17
+  --> $DIR/needless_return.rs:44:17
    |
 LL |         true => return false,
    |                 ^^^^^^^^^^^^
@@ -40,7 +40,7 @@ LL |         true => return false,
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:45:13
+  --> $DIR/needless_return.rs:46:13
    |
 LL |             return true;
    |             ^^^^^^^^^^^
@@ -48,7 +48,7 @@ LL |             return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:52:9
+  --> $DIR/needless_return.rs:53:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -56,7 +56,7 @@ LL |         return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:54:16
+  --> $DIR/needless_return.rs:55:16
    |
 LL |     let _ = || return true;
    |                ^^^^^^^^^^^
@@ -64,7 +64,7 @@ LL |     let _ = || return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:58:5
+  --> $DIR/needless_return.rs:59:5
    |
 LL |     return the_answer!();
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -72,7 +72,7 @@ LL |     return the_answer!();
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:61:21
+  --> $DIR/needless_return.rs:62:21
    |
 LL |   fn test_void_fun() {
    |  _____________________^
@@ -82,7 +82,7 @@ LL | |     return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:66:11
+  --> $DIR/needless_return.rs:67:11
    |
 LL |       if b {
    |  ___________^
@@ -92,7 +92,7 @@ LL | |         return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:68:13
+  --> $DIR/needless_return.rs:69:13
    |
 LL |       } else {
    |  _____________^
@@ -102,7 +102,7 @@ LL | |         return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:76:14
+  --> $DIR/needless_return.rs:77:14
    |
 LL |         _ => return,
    |              ^^^^^^
@@ -110,7 +110,7 @@ LL |         _ => return,
    = help: replace `return` with a unit value
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:84:24
+  --> $DIR/needless_return.rs:85:24
    |
 LL |               let _ = 42;
    |  ________________________^
@@ -120,7 +120,7 @@ LL | |             return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:87:14
+  --> $DIR/needless_return.rs:88:14
    |
 LL |         _ => return,
    |              ^^^^^^
@@ -128,7 +128,7 @@ LL |         _ => return,
    = help: replace `return` with a unit value
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:100:9
+  --> $DIR/needless_return.rs:101:9
    |
 LL |         return String::from("test");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -136,7 +136,7 @@ LL |         return String::from("test");
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:102:9
+  --> $DIR/needless_return.rs:103:9
    |
 LL |         return String::new();
    |         ^^^^^^^^^^^^^^^^^^^^
@@ -144,7 +144,7 @@ LL |         return String::new();
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:124:32
+  --> $DIR/needless_return.rs:125:32
    |
 LL |         bar.unwrap_or_else(|_| return)
    |                                ^^^^^^
@@ -152,7 +152,7 @@ LL |         bar.unwrap_or_else(|_| return)
    = help: replace `return` with an empty block
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:128:21
+  --> $DIR/needless_return.rs:129:21
    |
 LL |           let _ = || {
    |  _____________________^
@@ -162,7 +162,7 @@ LL | |             return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:131:20
+  --> $DIR/needless_return.rs:132:20
    |
 LL |         let _ = || return;
    |                    ^^^^^^
@@ -170,7 +170,7 @@ LL |         let _ = || return;
    = help: replace `return` with an empty block
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:137:32
+  --> $DIR/needless_return.rs:138:32
    |
 LL |         res.unwrap_or_else(|_| return Foo)
    |                                ^^^^^^^^^^
@@ -178,7 +178,7 @@ LL |         res.unwrap_or_else(|_| return Foo)
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:146:5
+  --> $DIR/needless_return.rs:147:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^
@@ -186,7 +186,7 @@ LL |     return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:150:5
+  --> $DIR/needless_return.rs:151:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^
@@ -194,7 +194,7 @@ LL |     return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:155:9
+  --> $DIR/needless_return.rs:156:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -202,7 +202,7 @@ LL |         return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:157:9
+  --> $DIR/needless_return.rs:158:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^
@@ -210,7 +210,7 @@ LL |         return false;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:163:17
+  --> $DIR/needless_return.rs:164:17
    |
 LL |         true => return false,
    |                 ^^^^^^^^^^^^
@@ -218,7 +218,7 @@ LL |         true => return false,
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:165:13
+  --> $DIR/needless_return.rs:166:13
    |
 LL |             return true;
    |             ^^^^^^^^^^^
@@ -226,7 +226,7 @@ LL |             return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:172:9
+  --> $DIR/needless_return.rs:173:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -234,7 +234,7 @@ LL |         return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:174:16
+  --> $DIR/needless_return.rs:175:16
    |
 LL |     let _ = || return true;
    |                ^^^^^^^^^^^
@@ -242,7 +242,7 @@ LL |     let _ = || return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:178:5
+  --> $DIR/needless_return.rs:179:5
    |
 LL |     return the_answer!();
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -250,7 +250,7 @@ LL |     return the_answer!();
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:181:33
+  --> $DIR/needless_return.rs:182:33
    |
 LL |   async fn async_test_void_fun() {
    |  _________________________________^
@@ -260,7 +260,7 @@ LL | |     return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:186:11
+  --> $DIR/needless_return.rs:187:11
    |
 LL |       if b {
    |  ___________^
@@ -270,7 +270,7 @@ LL | |         return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:188:13
+  --> $DIR/needless_return.rs:189:13
    |
 LL |       } else {
    |  _____________^
@@ -280,7 +280,7 @@ LL | |         return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:196:14
+  --> $DIR/needless_return.rs:197:14
    |
 LL |         _ => return,
    |              ^^^^^^
@@ -288,7 +288,7 @@ LL |         _ => return,
    = help: replace `return` with a unit value
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:209:9
+  --> $DIR/needless_return.rs:210:9
    |
 LL |         return String::from("test");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -296,7 +296,7 @@ LL |         return String::from("test");
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:211:9
+  --> $DIR/needless_return.rs:212:9
    |
 LL |         return String::new();
    |         ^^^^^^^^^^^^^^^^^^^^
@@ -304,7 +304,7 @@ LL |         return String::new();
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:227:5
+  --> $DIR/needless_return.rs:228:5
    |
 LL |     return format!("Hello {}", "world!");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -312,7 +312,7 @@ LL |     return format!("Hello {}", "world!");
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:238:9
+  --> $DIR/needless_return.rs:239:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -320,7 +320,7 @@ LL |         return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:240:9
+  --> $DIR/needless_return.rs:241:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^
@@ -328,7 +328,7 @@ LL |         return false;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:247:13
+  --> $DIR/needless_return.rs:248:13
    |
 LL |             return 10;
    |             ^^^^^^^^^
@@ -336,7 +336,7 @@ LL |             return 10;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:250:13
+  --> $DIR/needless_return.rs:251:13
    |
 LL |             return 100;
    |             ^^^^^^^^^^
@@ -344,7 +344,7 @@ LL |             return 100;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:258:9
+  --> $DIR/needless_return.rs:259:9
    |
 LL |         return 0;
    |         ^^^^^^^^
@@ -352,7 +352,7 @@ LL |         return 0;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:265:13
+  --> $DIR/needless_return.rs:266:13
    |
 LL |             return *(x as *const isize);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -360,7 +360,7 @@ LL |             return *(x as *const isize);
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:267:13
+  --> $DIR/needless_return.rs:268:13
    |
 LL |             return !*(x as *const isize);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -368,7 +368,7 @@ LL |             return !*(x as *const isize);
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:274:20
+  --> $DIR/needless_return.rs:275:20
    |
 LL |           let _ = 42;
    |  ____________________^
@@ -379,7 +379,7 @@ LL | |         return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:281:20
+  --> $DIR/needless_return.rs:282:20
    |
 LL |         let _ = 42; return;
    |                    ^^^^^^^
diff --git a/tests/ui/new_ret_no_self.rs b/tests/ui/new_ret_no_self.rs
index f69982d63a8..beec42f08bb 100644
--- a/tests/ui/new_ret_no_self.rs
+++ b/tests/ui/new_ret_no_self.rs
@@ -1,3 +1,4 @@
+#![feature(type_alias_impl_trait)]
 #![warn(clippy::new_ret_no_self)]
 #![allow(dead_code)]
 
@@ -400,3 +401,25 @@ mod issue7344 {
         }
     }
 }
+
+mod issue10041 {
+    struct Bomb;
+
+    impl Bomb {
+        // Hidden <Rhs = Self> default generic paramter.
+        pub fn new() -> impl PartialOrd {
+            0i32
+        }
+    }
+
+    // TAIT with self-referencing bounds
+    type X = impl std::ops::Add<Output = X>;
+
+    struct Bomb2;
+
+    impl Bomb2 {
+        pub fn new() -> X {
+            0i32
+        }
+    }
+}
diff --git a/tests/ui/new_ret_no_self.stderr b/tests/ui/new_ret_no_self.stderr
index bc13be47927..2eaebfb5cac 100644
--- a/tests/ui/new_ret_no_self.stderr
+++ b/tests/ui/new_ret_no_self.stderr
@@ -1,5 +1,5 @@
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:49:5
+  --> $DIR/new_ret_no_self.rs:50:5
    |
 LL | /     pub fn new(_: String) -> impl R<Item = u32> {
 LL | |         S3
@@ -9,7 +9,7 @@ LL | |     }
    = note: `-D clippy::new-ret-no-self` implied by `-D warnings`
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:81:5
+  --> $DIR/new_ret_no_self.rs:82:5
    |
 LL | /     pub fn new() -> u32 {
 LL | |         unimplemented!();
@@ -17,7 +17,7 @@ LL | |     }
    | |_____^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:90:5
+  --> $DIR/new_ret_no_self.rs:91:5
    |
 LL | /     pub fn new(_: String) -> u32 {
 LL | |         unimplemented!();
@@ -25,7 +25,7 @@ LL | |     }
    | |_____^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:126:5
+  --> $DIR/new_ret_no_self.rs:127:5
    |
 LL | /     pub fn new() -> (u32, u32) {
 LL | |         unimplemented!();
@@ -33,7 +33,7 @@ LL | |     }
    | |_____^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:153:5
+  --> $DIR/new_ret_no_self.rs:154:5
    |
 LL | /     pub fn new() -> *mut V {
 LL | |         unimplemented!();
@@ -41,7 +41,7 @@ LL | |     }
    | |_____^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:171:5
+  --> $DIR/new_ret_no_self.rs:172:5
    |
 LL | /     pub fn new() -> Option<u32> {
 LL | |         unimplemented!();
@@ -49,19 +49,19 @@ LL | |     }
    | |_____^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:224:9
+  --> $DIR/new_ret_no_self.rs:225:9
    |
 LL |         fn new() -> String;
    |         ^^^^^^^^^^^^^^^^^^^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:236:9
+  --> $DIR/new_ret_no_self.rs:237:9
    |
 LL |         fn new(_: String) -> String;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:271:9
+  --> $DIR/new_ret_no_self.rs:272:9
    |
 LL | /         fn new() -> (u32, u32) {
 LL | |             unimplemented!();
@@ -69,7 +69,7 @@ LL | |         }
    | |_________^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:298:9
+  --> $DIR/new_ret_no_self.rs:299:9
    |
 LL | /         fn new() -> *mut V {
 LL | |             unimplemented!();
@@ -77,7 +77,7 @@ LL | |         }
    | |_________^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:368:9
+  --> $DIR/new_ret_no_self.rs:369:9
    |
 LL | /         fn new(t: T) -> impl Into<i32> {
 LL | |             1
@@ -85,12 +85,28 @@ LL | |         }
    | |_________^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:389:9
+  --> $DIR/new_ret_no_self.rs:390:9
    |
 LL | /         fn new(t: T) -> impl Trait2<(), i32> {
 LL | |             unimplemented!()
 LL | |         }
    | |_________^
 
-error: aborting due to 12 previous errors
+error: methods called `new` usually return `Self`
+  --> $DIR/new_ret_no_self.rs:410:9
+   |
+LL | /         pub fn new() -> impl PartialOrd {
+LL | |             0i32
+LL | |         }
+   | |_________^
+
+error: methods called `new` usually return `Self`
+  --> $DIR/new_ret_no_self.rs:421:9
+   |
+LL | /         pub fn new() -> X {
+LL | |             0i32
+LL | |         }
+   | |_________^
+
+error: aborting due to 14 previous errors
 
diff --git a/tests/ui/permissions_set_readonly_false.rs b/tests/ui/permissions_set_readonly_false.rs
new file mode 100644
index 00000000000..28c00d10094
--- /dev/null
+++ b/tests/ui/permissions_set_readonly_false.rs
@@ -0,0 +1,29 @@
+#![allow(unused)]
+#![warn(clippy::permissions_set_readonly_false)]
+
+use std::fs::File;
+
+struct A;
+
+impl A {
+    pub fn set_readonly(&mut self, b: bool) {}
+}
+
+fn set_readonly(b: bool) {}
+
+fn main() {
+    let f = File::create("foo.txt").unwrap();
+    let metadata = f.metadata().unwrap();
+    let mut permissions = metadata.permissions();
+    // lint here
+    permissions.set_readonly(false);
+    // no lint
+    permissions.set_readonly(true);
+
+    let mut a = A;
+    // no lint here - a is not of type std::fs::Permissions
+    a.set_readonly(false);
+
+    // no lint here - plain function
+    set_readonly(false);
+}
diff --git a/tests/ui/permissions_set_readonly_false.stderr b/tests/ui/permissions_set_readonly_false.stderr
new file mode 100644
index 00000000000..e7a8ee6cb19
--- /dev/null
+++ b/tests/ui/permissions_set_readonly_false.stderr
@@ -0,0 +1,13 @@
+error: call to `set_readonly` with argument `false`
+  --> $DIR/permissions_set_readonly_false.rs:19:5
+   |
+LL |     permissions.set_readonly(false);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: on Unix platforms this results in the file being world writable
+   = help: you can set the desired permissions using `PermissionsExt`. For more information, see
+           https://doc.rust-lang.org/std/os/unix/fs/trait.PermissionsExt.html
+   = note: `-D clippy::permissions-set-readonly-false` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/seek_to_start_instead_of_rewind.fixed b/tests/ui/seek_to_start_instead_of_rewind.fixed
index 9d0d1124c46..713cff604a1 100644
--- a/tests/ui/seek_to_start_instead_of_rewind.fixed
+++ b/tests/ui/seek_to_start_instead_of_rewind.fixed
@@ -70,6 +70,12 @@ fn seek_to_end<T: Seek>(t: &mut T) {
     t.seek(SeekFrom::End(0));
 }
 
+// This should NOT trigger clippy warning because
+// expr is used here
+fn seek_to_start_in_let<T: Seek>(t: &mut T) {
+    let a = t.seek(SeekFrom::Start(0)).unwrap();
+}
+
 fn main() {
     let mut f = OpenOptions::new()
         .write(true)
diff --git a/tests/ui/seek_to_start_instead_of_rewind.rs b/tests/ui/seek_to_start_instead_of_rewind.rs
index c5bc57cc3a7..467003a1a66 100644
--- a/tests/ui/seek_to_start_instead_of_rewind.rs
+++ b/tests/ui/seek_to_start_instead_of_rewind.rs
@@ -70,6 +70,12 @@ fn seek_to_end<T: Seek>(t: &mut T) {
     t.seek(SeekFrom::End(0));
 }
 
+// This should NOT trigger clippy warning because
+// expr is used here
+fn seek_to_start_in_let<T: Seek>(t: &mut T) {
+    let a = t.seek(SeekFrom::Start(0)).unwrap();
+}
+
 fn main() {
     let mut f = OpenOptions::new()
         .write(true)
diff --git a/tests/ui/seek_to_start_instead_of_rewind.stderr b/tests/ui/seek_to_start_instead_of_rewind.stderr
index 6cce025359f..342ec00fe72 100644
--- a/tests/ui/seek_to_start_instead_of_rewind.stderr
+++ b/tests/ui/seek_to_start_instead_of_rewind.stderr
@@ -13,7 +13,7 @@ LL |     t.seek(SeekFrom::Start(0));
    |       ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()`
 
 error: used `seek` to go to the start of the stream
-  --> $DIR/seek_to_start_instead_of_rewind.rs:128:7
+  --> $DIR/seek_to_start_instead_of_rewind.rs:134:7
    |
 LL |     f.seek(SeekFrom::Start(0));
    |       ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()`
diff --git a/tests/ui/transmute_null_to_fn.rs b/tests/ui/transmute_null_to_fn.rs
new file mode 100644
index 00000000000..b3ea3d9039e
--- /dev/null
+++ b/tests/ui/transmute_null_to_fn.rs
@@ -0,0 +1,28 @@
+#![allow(dead_code)]
+#![warn(clippy::transmute_null_to_fn)]
+#![allow(clippy::zero_ptr)]
+
+// Easy to lint because these only span one line.
+fn one_liners() {
+    unsafe {
+        let _: fn() = std::mem::transmute(0 as *const ());
+        let _: fn() = std::mem::transmute(std::ptr::null::<()>());
+    }
+}
+
+pub const ZPTR: *const usize = 0 as *const _;
+pub const NOT_ZPTR: *const usize = 1 as *const _;
+
+fn transmute_const() {
+    unsafe {
+        // Should raise a lint.
+        let _: fn() = std::mem::transmute(ZPTR);
+        // Should NOT raise a lint.
+        let _: fn() = std::mem::transmute(NOT_ZPTR);
+    }
+}
+
+fn main() {
+    one_liners();
+    transmute_const();
+}
diff --git a/tests/ui/transmute_null_to_fn.stderr b/tests/ui/transmute_null_to_fn.stderr
new file mode 100644
index 00000000000..f0c65497d75
--- /dev/null
+++ b/tests/ui/transmute_null_to_fn.stderr
@@ -0,0 +1,27 @@
+error: transmuting a known null pointer into a function pointer
+  --> $DIR/transmute_null_to_fn.rs:8:23
+   |
+LL |         let _: fn() = std::mem::transmute(0 as *const ());
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value
+   = note: `-D clippy::transmute-null-to-fn` implied by `-D warnings`
+
+error: transmuting a known null pointer into a function pointer
+  --> $DIR/transmute_null_to_fn.rs:9:23
+   |
+LL |         let _: fn() = std::mem::transmute(std::ptr::null::<()>());
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value
+
+error: transmuting a known null pointer into a function pointer
+  --> $DIR/transmute_null_to_fn.rs:19:23
+   |
+LL |         let _: fn() = std::mem::transmute(ZPTR);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/uninlined_format_args_panic.edition2018.fixed b/tests/ui/uninlined_format_args_panic.edition2018.fixed
index 96cc0877960..52b5343c351 100644
--- a/tests/ui/uninlined_format_args_panic.edition2018.fixed
+++ b/tests/ui/uninlined_format_args_panic.edition2018.fixed
@@ -26,4 +26,7 @@ fn main() {
             panic!("p4 {var}");
         }
     }
+
+    assert!(var == 1, "p5 {}", var);
+    debug_assert!(var == 1, "p6 {}", var);
 }
diff --git a/tests/ui/uninlined_format_args_panic.edition2021.fixed b/tests/ui/uninlined_format_args_panic.edition2021.fixed
index faf8ca4d3a7..ee72065e28a 100644
--- a/tests/ui/uninlined_format_args_panic.edition2021.fixed
+++ b/tests/ui/uninlined_format_args_panic.edition2021.fixed
@@ -26,4 +26,7 @@ fn main() {
             panic!("p4 {var}");
         }
     }
+
+    assert!(var == 1, "p5 {var}");
+    debug_assert!(var == 1, "p6 {var}");
 }
diff --git a/tests/ui/uninlined_format_args_panic.edition2021.stderr b/tests/ui/uninlined_format_args_panic.edition2021.stderr
index 0f09c45f413..fc7b125080e 100644
--- a/tests/ui/uninlined_format_args_panic.edition2021.stderr
+++ b/tests/ui/uninlined_format_args_panic.edition2021.stderr
@@ -47,5 +47,29 @@ LL -         panic!("p3 {var}", var = var);
 LL +         panic!("p3 {var}");
    |
 
-error: aborting due to 4 previous errors
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args_panic.rs:30:5
+   |
+LL |     assert!(var == 1, "p5 {}", var);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: change this to
+   |
+LL -     assert!(var == 1, "p5 {}", var);
+LL +     assert!(var == 1, "p5 {var}");
+   |
+
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args_panic.rs:31:5
+   |
+LL |     debug_assert!(var == 1, "p6 {}", var);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: change this to
+   |
+LL -     debug_assert!(var == 1, "p6 {}", var);
+LL +     debug_assert!(var == 1, "p6 {var}");
+   |
+
+error: aborting due to 6 previous errors
 
diff --git a/tests/ui/uninlined_format_args_panic.rs b/tests/ui/uninlined_format_args_panic.rs
index 6421c5bbed2..b4a0a0f496e 100644
--- a/tests/ui/uninlined_format_args_panic.rs
+++ b/tests/ui/uninlined_format_args_panic.rs
@@ -26,4 +26,7 @@ fn main() {
             panic!("p4 {var}");
         }
     }
+
+    assert!(var == 1, "p5 {}", var);
+    debug_assert!(var == 1, "p6 {}", var);
 }
diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed
index 70ff08f3655..94b206d8e58 100644
--- a/tests/ui/useless_conversion.fixed
+++ b/tests/ui/useless_conversion.fixed
@@ -33,12 +33,71 @@ fn test_issue_3913() -> Result<(), std::io::Error> {
     Ok(())
 }
 
-fn test_issue_5833() -> Result<(), ()> {
+fn dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr() {
     let text = "foo\r\nbar\n\nbaz\n";
     let lines = text.lines();
     if Some("ok") == lines.into_iter().next() {}
+}
 
-    Ok(())
+fn lint_into_iter_on_mutable_local_implementing_iterator_in_expr() {
+    let text = "foo\r\nbar\n\nbaz\n";
+    let mut lines = text.lines();
+    if Some("ok") == lines.next() {}
+}
+
+fn lint_into_iter_on_expr_implementing_iterator() {
+    let text = "foo\r\nbar\n\nbaz\n";
+    let mut lines = text.lines();
+    if Some("ok") == lines.next() {}
+}
+
+fn lint_into_iter_on_expr_implementing_iterator_2() {
+    let text = "foo\r\nbar\n\nbaz\n";
+    if Some("ok") == text.lines().next() {}
+}
+
+#[allow(const_item_mutation)]
+fn lint_into_iter_on_const_implementing_iterator() {
+    const NUMBERS: std::ops::Range<i32> = 0..10;
+    let _ = NUMBERS.next();
+}
+
+fn lint_into_iter_on_const_implementing_iterator_2() {
+    const NUMBERS: std::ops::Range<i32> = 0..10;
+    let mut n = NUMBERS;
+    n.next();
+}
+
+#[derive(Clone, Copy)]
+struct CopiableCounter {
+    counter: u32,
+}
+
+impl Iterator for CopiableCounter {
+    type Item = u32;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.counter = self.counter.wrapping_add(1);
+        Some(self.counter)
+    }
+}
+
+fn dont_lint_into_iter_on_copy_iter() {
+    let mut c = CopiableCounter { counter: 0 };
+    assert_eq!(c.into_iter().next(), Some(1));
+    assert_eq!(c.into_iter().next(), Some(1));
+    assert_eq!(c.next(), Some(1));
+    assert_eq!(c.next(), Some(2));
+}
+
+fn dont_lint_into_iter_on_static_copy_iter() {
+    static mut C: CopiableCounter = CopiableCounter { counter: 0 };
+    unsafe {
+        assert_eq!(C.into_iter().next(), Some(1));
+        assert_eq!(C.into_iter().next(), Some(1));
+        assert_eq!(C.next(), Some(1));
+        assert_eq!(C.next(), Some(2));
+    }
 }
 
 fn main() {
@@ -46,7 +105,15 @@ fn main() {
     test_generic2::<i32, i32>(10i32);
     test_questionmark().unwrap();
     test_issue_3913().unwrap();
-    test_issue_5833().unwrap();
+
+    dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr();
+    lint_into_iter_on_mutable_local_implementing_iterator_in_expr();
+    lint_into_iter_on_expr_implementing_iterator();
+    lint_into_iter_on_expr_implementing_iterator_2();
+    lint_into_iter_on_const_implementing_iterator();
+    lint_into_iter_on_const_implementing_iterator_2();
+    dont_lint_into_iter_on_copy_iter();
+    dont_lint_into_iter_on_static_copy_iter();
 
     let _: String = "foo".into();
     let _: String = From::from("foo");
diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs
index f2444a8f436..c7ae927941b 100644
--- a/tests/ui/useless_conversion.rs
+++ b/tests/ui/useless_conversion.rs
@@ -33,12 +33,71 @@ fn test_issue_3913() -> Result<(), std::io::Error> {
     Ok(())
 }
 
-fn test_issue_5833() -> Result<(), ()> {
+fn dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr() {
     let text = "foo\r\nbar\n\nbaz\n";
     let lines = text.lines();
     if Some("ok") == lines.into_iter().next() {}
+}
 
-    Ok(())
+fn lint_into_iter_on_mutable_local_implementing_iterator_in_expr() {
+    let text = "foo\r\nbar\n\nbaz\n";
+    let mut lines = text.lines();
+    if Some("ok") == lines.into_iter().next() {}
+}
+
+fn lint_into_iter_on_expr_implementing_iterator() {
+    let text = "foo\r\nbar\n\nbaz\n";
+    let mut lines = text.lines().into_iter();
+    if Some("ok") == lines.next() {}
+}
+
+fn lint_into_iter_on_expr_implementing_iterator_2() {
+    let text = "foo\r\nbar\n\nbaz\n";
+    if Some("ok") == text.lines().into_iter().next() {}
+}
+
+#[allow(const_item_mutation)]
+fn lint_into_iter_on_const_implementing_iterator() {
+    const NUMBERS: std::ops::Range<i32> = 0..10;
+    let _ = NUMBERS.into_iter().next();
+}
+
+fn lint_into_iter_on_const_implementing_iterator_2() {
+    const NUMBERS: std::ops::Range<i32> = 0..10;
+    let mut n = NUMBERS.into_iter();
+    n.next();
+}
+
+#[derive(Clone, Copy)]
+struct CopiableCounter {
+    counter: u32,
+}
+
+impl Iterator for CopiableCounter {
+    type Item = u32;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.counter = self.counter.wrapping_add(1);
+        Some(self.counter)
+    }
+}
+
+fn dont_lint_into_iter_on_copy_iter() {
+    let mut c = CopiableCounter { counter: 0 };
+    assert_eq!(c.into_iter().next(), Some(1));
+    assert_eq!(c.into_iter().next(), Some(1));
+    assert_eq!(c.next(), Some(1));
+    assert_eq!(c.next(), Some(2));
+}
+
+fn dont_lint_into_iter_on_static_copy_iter() {
+    static mut C: CopiableCounter = CopiableCounter { counter: 0 };
+    unsafe {
+        assert_eq!(C.into_iter().next(), Some(1));
+        assert_eq!(C.into_iter().next(), Some(1));
+        assert_eq!(C.next(), Some(1));
+        assert_eq!(C.next(), Some(2));
+    }
 }
 
 fn main() {
@@ -46,7 +105,15 @@ fn main() {
     test_generic2::<i32, i32>(10i32);
     test_questionmark().unwrap();
     test_issue_3913().unwrap();
-    test_issue_5833().unwrap();
+
+    dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr();
+    lint_into_iter_on_mutable_local_implementing_iterator_in_expr();
+    lint_into_iter_on_expr_implementing_iterator();
+    lint_into_iter_on_expr_implementing_iterator_2();
+    lint_into_iter_on_const_implementing_iterator();
+    lint_into_iter_on_const_implementing_iterator_2();
+    dont_lint_into_iter_on_copy_iter();
+    dont_lint_into_iter_on_static_copy_iter();
 
     let _: String = "foo".into();
     let _: String = From::from("foo");
diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr
index 65ee3807fa9..be067c6843a 100644
--- a/tests/ui/useless_conversion.stderr
+++ b/tests/ui/useless_conversion.stderr
@@ -22,71 +22,101 @@ error: useless conversion to the same type: `i32`
 LL |         let _: i32 = 0i32.into();
    |                      ^^^^^^^^^^^ help: consider removing `.into()`: `0i32`
 
+error: useless conversion to the same type: `std::str::Lines<'_>`
+  --> $DIR/useless_conversion.rs:45:22
+   |
+LL |     if Some("ok") == lines.into_iter().next() {}
+   |                      ^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `lines`
+
+error: useless conversion to the same type: `std::str::Lines<'_>`
+  --> $DIR/useless_conversion.rs:50:21
+   |
+LL |     let mut lines = text.lines().into_iter();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()`
+
+error: useless conversion to the same type: `std::str::Lines<'_>`
+  --> $DIR/useless_conversion.rs:56:22
+   |
+LL |     if Some("ok") == text.lines().into_iter().next() {}
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()`
+
+error: useless conversion to the same type: `std::ops::Range<i32>`
+  --> $DIR/useless_conversion.rs:62:13
+   |
+LL |     let _ = NUMBERS.into_iter().next();
+   |             ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS`
+
+error: useless conversion to the same type: `std::ops::Range<i32>`
+  --> $DIR/useless_conversion.rs:67:17
+   |
+LL |     let mut n = NUMBERS.into_iter();
+   |                 ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS`
+
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion.rs:61:21
+  --> $DIR/useless_conversion.rs:128:21
    |
 LL |     let _: String = "foo".to_string().into();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion.rs:62:21
+  --> $DIR/useless_conversion.rs:129:21
    |
 LL |     let _: String = From::from("foo".to_string());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion.rs:63:13
+  --> $DIR/useless_conversion.rs:130:13
    |
 LL |     let _ = String::from("foo".to_string());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion.rs:64:13
+  --> $DIR/useless_conversion.rs:131:13
    |
 LL |     let _ = String::from(format!("A: {:04}", 123));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)`
 
 error: useless conversion to the same type: `std::str::Lines<'_>`
-  --> $DIR/useless_conversion.rs:65:13
+  --> $DIR/useless_conversion.rs:132:13
    |
 LL |     let _ = "".lines().into_iter();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()`
 
 error: useless conversion to the same type: `std::vec::IntoIter<i32>`
-  --> $DIR/useless_conversion.rs:66:13
+  --> $DIR/useless_conversion.rs:133:13
    |
 LL |     let _ = vec![1, 2, 3].into_iter().into_iter();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion.rs:67:21
+  --> $DIR/useless_conversion.rs:134:21
    |
 LL |     let _: String = format!("Hello {}", "world").into();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")`
 
 error: useless conversion to the same type: `i32`
-  --> $DIR/useless_conversion.rs:72:13
+  --> $DIR/useless_conversion.rs:139:13
    |
 LL |     let _ = i32::from(a + b) * 3;
    |             ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)`
 
 error: useless conversion to the same type: `Foo<'a'>`
-  --> $DIR/useless_conversion.rs:78:23
+  --> $DIR/useless_conversion.rs:145:23
    |
 LL |     let _: Foo<'a'> = s2.into();
    |                       ^^^^^^^^^ help: consider removing `.into()`: `s2`
 
 error: useless conversion to the same type: `Foo<'a'>`
-  --> $DIR/useless_conversion.rs:80:13
+  --> $DIR/useless_conversion.rs:147:13
    |
 LL |     let _ = Foo::<'a'>::from(s3);
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider removing `Foo::<'a'>::from()`: `s3`
 
 error: useless conversion to the same type: `std::vec::IntoIter<Foo<'a'>>`
-  --> $DIR/useless_conversion.rs:82:13
+  --> $DIR/useless_conversion.rs:149:13
    |
 LL |     let _ = vec![s4, s4, s4].into_iter().into_iter();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()`
 
-error: aborting due to 14 previous errors
+error: aborting due to 19 previous errors
 
diff --git a/tests/ui/wildcard_imports.fixed b/tests/ui/wildcard_imports.fixed
index ef55f1c31a8..0baec6f0b64 100644
--- a/tests/ui/wildcard_imports.fixed
+++ b/tests/ui/wildcard_imports.fixed
@@ -5,7 +5,6 @@
 // the 2015 edition here is needed because edition 2018 changed the module system
 // (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint
 // no longer detects some of the cases starting with Rust 2018.
-// FIXME: We should likely add another edition 2021 test case for this lint
 
 #![warn(clippy::wildcard_imports)]
 #![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
diff --git a/tests/ui/wildcard_imports.rs b/tests/ui/wildcard_imports.rs
index b8128514206..db591d56ab4 100644
--- a/tests/ui/wildcard_imports.rs
+++ b/tests/ui/wildcard_imports.rs
@@ -5,7 +5,6 @@
 // the 2015 edition here is needed because edition 2018 changed the module system
 // (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint
 // no longer detects some of the cases starting with Rust 2018.
-// FIXME: We should likely add another edition 2021 test case for this lint
 
 #![warn(clippy::wildcard_imports)]
 #![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
diff --git a/tests/ui/wildcard_imports.stderr b/tests/ui/wildcard_imports.stderr
index 626c1754fc8..6b469cdfc44 100644
--- a/tests/ui/wildcard_imports.stderr
+++ b/tests/ui/wildcard_imports.stderr
@@ -1,5 +1,5 @@
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:16:5
+  --> $DIR/wildcard_imports.rs:15:5
    |
 LL | use crate::fn_mod::*;
    |     ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
@@ -7,85 +7,85 @@ LL | use crate::fn_mod::*;
    = note: `-D clippy::wildcard-imports` implied by `-D warnings`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:17:5
+  --> $DIR/wildcard_imports.rs:16:5
    |
 LL | use crate::mod_mod::*;
    |     ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:18:5
+  --> $DIR/wildcard_imports.rs:17:5
    |
 LL | use crate::multi_fn_mod::*;
    |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:20:5
+  --> $DIR/wildcard_imports.rs:19:5
    |
 LL | use crate::struct_mod::*;
    |     ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:24:5
+  --> $DIR/wildcard_imports.rs:23:5
    |
 LL | use wildcard_imports_helper::inner::inner_for_self_import::*;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:25:5
+  --> $DIR/wildcard_imports.rs:24:5
    |
 LL | use wildcard_imports_helper::*;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:96:13
+  --> $DIR/wildcard_imports.rs:95:13
    |
 LL |         use crate::fn_mod::*;
    |             ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:102:75
+  --> $DIR/wildcard_imports.rs:101:75
    |
 LL |         use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
    |                                                                           ^ help: try: `inner_extern_foo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:103:13
+  --> $DIR/wildcard_imports.rs:102:13
    |
 LL |         use wildcard_imports_helper::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:114:20
+  --> $DIR/wildcard_imports.rs:113:20
    |
 LL |         use self::{inner::*, inner2::*};
    |                    ^^^^^^^^ help: try: `inner::inner_foo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:114:30
+  --> $DIR/wildcard_imports.rs:113:30
    |
 LL |         use self::{inner::*, inner2::*};
    |                              ^^^^^^^^^ help: try: `inner2::inner_bar`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:121:13
+  --> $DIR/wildcard_imports.rs:120:13
    |
 LL |         use wildcard_imports_helper::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:150:9
+  --> $DIR/wildcard_imports.rs:149:9
    |
 LL |     use crate::in_fn_test::*;
    |         ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:159:9
+  --> $DIR/wildcard_imports.rs:158:9
    |
 LL |     use crate:: in_fn_test::  * ;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:160:9
+  --> $DIR/wildcard_imports.rs:159:9
    |
 LL |       use crate:: fn_mod::
    |  _________^
@@ -93,37 +93,37 @@ LL | |         *;
    | |_________^ help: try: `crate:: fn_mod::foo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:171:13
+  --> $DIR/wildcard_imports.rs:170:13
    |
 LL |         use super::*;
    |             ^^^^^^^^ help: try: `super::foofoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:206:17
+  --> $DIR/wildcard_imports.rs:205:17
    |
 LL |             use super::*;
    |                 ^^^^^^^^ help: try: `super::insidefoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:214:13
+  --> $DIR/wildcard_imports.rs:213:13
    |
 LL |         use super_imports::*;
    |             ^^^^^^^^^^^^^^^^ help: try: `super_imports::foofoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:223:17
+  --> $DIR/wildcard_imports.rs:222:17
    |
 LL |             use super::super::*;
    |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:232:13
+  --> $DIR/wildcard_imports.rs:231:13
    |
 LL |         use super::super::super_imports::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:240:13
+  --> $DIR/wildcard_imports.rs:239:13
    |
 LL |         use super::*;
    |             ^^^^^^^^ help: try: `super::foofoo`
diff --git a/tests/ui/wildcard_imports_2021.edition2018.fixed b/tests/ui/wildcard_imports_2021.edition2018.fixed
new file mode 100644
index 00000000000..6d534a10edc
--- /dev/null
+++ b/tests/ui/wildcard_imports_2021.edition2018.fixed
@@ -0,0 +1,240 @@
+// revisions: edition2018 edition2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
+// run-rustfix
+// aux-build:wildcard_imports_helper.rs
+
+#![warn(clippy::wildcard_imports)]
+#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
+#![warn(unused_imports)]
+
+extern crate wildcard_imports_helper;
+
+use crate::fn_mod::foo;
+use crate::mod_mod::inner_mod;
+use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod};
+use crate::struct_mod::{A, inner_struct_mod};
+
+#[allow(unused_imports)]
+use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar;
+use wildcard_imports_helper::prelude::v1::*;
+use wildcard_imports_helper::{ExternA, extern_foo};
+
+use std::io::prelude::*;
+
+struct ReadFoo;
+
+impl Read for ReadFoo {
+    fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
+        Ok(0)
+    }
+}
+
+mod fn_mod {
+    pub fn foo() {}
+}
+
+mod mod_mod {
+    pub mod inner_mod {
+        pub fn foo() {}
+    }
+}
+
+mod multi_fn_mod {
+    pub fn multi_foo() {}
+    pub fn multi_bar() {}
+    pub fn multi_baz() {}
+    pub mod multi_inner_mod {
+        pub fn foo() {}
+    }
+}
+
+mod struct_mod {
+    pub struct A;
+    pub struct B;
+    pub mod inner_struct_mod {
+        pub struct C;
+    }
+
+    #[macro_export]
+    macro_rules! double_struct_import_test {
+        () => {
+            let _ = A;
+        };
+    }
+}
+
+fn main() {
+    foo();
+    multi_foo();
+    multi_bar();
+    multi_inner_mod::foo();
+    inner_mod::foo();
+    extern_foo();
+    inner_extern_bar();
+
+    let _ = A;
+    let _ = inner_struct_mod::C;
+    let _ = ExternA;
+    let _ = PreludeModAnywhere;
+
+    double_struct_import_test!();
+    double_struct_import_test!();
+}
+
+mod in_fn_test {
+    pub use self::inner_exported::*;
+    #[allow(unused_imports)]
+    pub(crate) use self::inner_exported2::*;
+
+    fn test_intern() {
+        use crate::fn_mod::foo;
+
+        foo();
+    }
+
+    fn test_extern() {
+        use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo};
+        use wildcard_imports_helper::{ExternA, extern_foo};
+
+        inner_for_self_import::inner_extern_foo();
+        inner_extern_foo();
+
+        extern_foo();
+
+        let _ = ExternA;
+    }
+
+    fn test_inner_nested() {
+        use self::{inner::inner_foo, inner2::inner_bar};
+
+        inner_foo();
+        inner_bar();
+    }
+
+    fn test_extern_reexported() {
+        use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported};
+
+        extern_exported();
+        let _ = ExternExportedStruct;
+        let _ = ExternExportedEnum::A;
+    }
+
+    mod inner_exported {
+        pub fn exported() {}
+        pub struct ExportedStruct;
+        pub enum ExportedEnum {
+            A,
+        }
+    }
+
+    mod inner_exported2 {
+        pub(crate) fn exported2() {}
+    }
+
+    mod inner {
+        pub fn inner_foo() {}
+    }
+
+    mod inner2 {
+        pub fn inner_bar() {}
+    }
+}
+
+fn test_reexported() {
+    use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported};
+
+    exported();
+    let _ = ExportedStruct;
+    let _ = ExportedEnum::A;
+}
+
+#[rustfmt::skip]
+fn test_weird_formatting() {
+    use crate:: in_fn_test::exported;
+    use crate:: fn_mod::foo;
+
+    exported();
+    foo();
+}
+
+mod super_imports {
+    fn foofoo() {}
+
+    mod should_be_replaced {
+        use super::foofoo;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass {
+        use super::*;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_inside_function {
+        fn with_super_inside_function() {
+            use super::*;
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_further_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::*;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod should_be_replaced_further_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::insidefoo;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod use_explicit_should_be_replaced {
+        use crate::super_imports::foofoo;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
+
+    mod use_double_super_should_be_replaced {
+        mod inner {
+            use super::super::foofoo;
+
+            fn with_double_super() {
+                let _ = foofoo();
+            }
+        }
+    }
+
+    mod use_super_explicit_should_be_replaced {
+        use super::super::super_imports::foofoo;
+
+        fn with_super_explicit() {
+            let _ = foofoo();
+        }
+    }
+
+    mod attestation_should_be_replaced {
+        use super::foofoo;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
+}
diff --git a/tests/ui/wildcard_imports_2021.edition2018.stderr b/tests/ui/wildcard_imports_2021.edition2018.stderr
new file mode 100644
index 00000000000..acca9f651b4
--- /dev/null
+++ b/tests/ui/wildcard_imports_2021.edition2018.stderr
@@ -0,0 +1,132 @@
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:13:5
+   |
+LL | use crate::fn_mod::*;
+   |     ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+   |
+   = note: `-D clippy::wildcard-imports` implied by `-D warnings`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:14:5
+   |
+LL | use crate::mod_mod::*;
+   |     ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:15:5
+   |
+LL | use crate::multi_fn_mod::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:16:5
+   |
+LL | use crate::struct_mod::*;
+   |     ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:19:5
+   |
+LL | use wildcard_imports_helper::inner::inner_for_self_import::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:21:5
+   |
+LL | use wildcard_imports_helper::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:91:13
+   |
+LL |         use crate::fn_mod::*;
+   |             ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:97:75
+   |
+LL |         use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
+   |                                                                           ^ help: try: `inner_extern_foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:98:13
+   |
+LL |         use wildcard_imports_helper::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:109:20
+   |
+LL |         use self::{inner::*, inner2::*};
+   |                    ^^^^^^^^ help: try: `inner::inner_foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:109:30
+   |
+LL |         use self::{inner::*, inner2::*};
+   |                              ^^^^^^^^^ help: try: `inner2::inner_bar`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:116:13
+   |
+LL |         use wildcard_imports_helper::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:145:9
+   |
+LL |     use crate::in_fn_test::*;
+   |         ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:154:9
+   |
+LL |     use crate:: in_fn_test::  * ;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:155:9
+   |
+LL |       use crate:: fn_mod::
+   |  _________^
+LL | |         *;
+   | |_________^ help: try: `crate:: fn_mod::foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:166:13
+   |
+LL |         use super::*;
+   |             ^^^^^^^^ help: try: `super::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:201:17
+   |
+LL |             use super::*;
+   |                 ^^^^^^^^ help: try: `super::insidefoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:209:13
+   |
+LL |         use crate::super_imports::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:218:17
+   |
+LL |             use super::super::*;
+   |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:227:13
+   |
+LL |         use super::super::super_imports::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:235:13
+   |
+LL |         use super::*;
+   |             ^^^^^^^^ help: try: `super::foofoo`
+
+error: aborting due to 21 previous errors
+
diff --git a/tests/ui/wildcard_imports_2021.edition2021.fixed b/tests/ui/wildcard_imports_2021.edition2021.fixed
new file mode 100644
index 00000000000..6d534a10edc
--- /dev/null
+++ b/tests/ui/wildcard_imports_2021.edition2021.fixed
@@ -0,0 +1,240 @@
+// revisions: edition2018 edition2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
+// run-rustfix
+// aux-build:wildcard_imports_helper.rs
+
+#![warn(clippy::wildcard_imports)]
+#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
+#![warn(unused_imports)]
+
+extern crate wildcard_imports_helper;
+
+use crate::fn_mod::foo;
+use crate::mod_mod::inner_mod;
+use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod};
+use crate::struct_mod::{A, inner_struct_mod};
+
+#[allow(unused_imports)]
+use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar;
+use wildcard_imports_helper::prelude::v1::*;
+use wildcard_imports_helper::{ExternA, extern_foo};
+
+use std::io::prelude::*;
+
+struct ReadFoo;
+
+impl Read for ReadFoo {
+    fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
+        Ok(0)
+    }
+}
+
+mod fn_mod {
+    pub fn foo() {}
+}
+
+mod mod_mod {
+    pub mod inner_mod {
+        pub fn foo() {}
+    }
+}
+
+mod multi_fn_mod {
+    pub fn multi_foo() {}
+    pub fn multi_bar() {}
+    pub fn multi_baz() {}
+    pub mod multi_inner_mod {
+        pub fn foo() {}
+    }
+}
+
+mod struct_mod {
+    pub struct A;
+    pub struct B;
+    pub mod inner_struct_mod {
+        pub struct C;
+    }
+
+    #[macro_export]
+    macro_rules! double_struct_import_test {
+        () => {
+            let _ = A;
+        };
+    }
+}
+
+fn main() {
+    foo();
+    multi_foo();
+    multi_bar();
+    multi_inner_mod::foo();
+    inner_mod::foo();
+    extern_foo();
+    inner_extern_bar();
+
+    let _ = A;
+    let _ = inner_struct_mod::C;
+    let _ = ExternA;
+    let _ = PreludeModAnywhere;
+
+    double_struct_import_test!();
+    double_struct_import_test!();
+}
+
+mod in_fn_test {
+    pub use self::inner_exported::*;
+    #[allow(unused_imports)]
+    pub(crate) use self::inner_exported2::*;
+
+    fn test_intern() {
+        use crate::fn_mod::foo;
+
+        foo();
+    }
+
+    fn test_extern() {
+        use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo};
+        use wildcard_imports_helper::{ExternA, extern_foo};
+
+        inner_for_self_import::inner_extern_foo();
+        inner_extern_foo();
+
+        extern_foo();
+
+        let _ = ExternA;
+    }
+
+    fn test_inner_nested() {
+        use self::{inner::inner_foo, inner2::inner_bar};
+
+        inner_foo();
+        inner_bar();
+    }
+
+    fn test_extern_reexported() {
+        use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported};
+
+        extern_exported();
+        let _ = ExternExportedStruct;
+        let _ = ExternExportedEnum::A;
+    }
+
+    mod inner_exported {
+        pub fn exported() {}
+        pub struct ExportedStruct;
+        pub enum ExportedEnum {
+            A,
+        }
+    }
+
+    mod inner_exported2 {
+        pub(crate) fn exported2() {}
+    }
+
+    mod inner {
+        pub fn inner_foo() {}
+    }
+
+    mod inner2 {
+        pub fn inner_bar() {}
+    }
+}
+
+fn test_reexported() {
+    use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported};
+
+    exported();
+    let _ = ExportedStruct;
+    let _ = ExportedEnum::A;
+}
+
+#[rustfmt::skip]
+fn test_weird_formatting() {
+    use crate:: in_fn_test::exported;
+    use crate:: fn_mod::foo;
+
+    exported();
+    foo();
+}
+
+mod super_imports {
+    fn foofoo() {}
+
+    mod should_be_replaced {
+        use super::foofoo;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass {
+        use super::*;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_inside_function {
+        fn with_super_inside_function() {
+            use super::*;
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_further_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::*;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod should_be_replaced_further_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::insidefoo;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod use_explicit_should_be_replaced {
+        use crate::super_imports::foofoo;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
+
+    mod use_double_super_should_be_replaced {
+        mod inner {
+            use super::super::foofoo;
+
+            fn with_double_super() {
+                let _ = foofoo();
+            }
+        }
+    }
+
+    mod use_super_explicit_should_be_replaced {
+        use super::super::super_imports::foofoo;
+
+        fn with_super_explicit() {
+            let _ = foofoo();
+        }
+    }
+
+    mod attestation_should_be_replaced {
+        use super::foofoo;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
+}
diff --git a/tests/ui/wildcard_imports_2021.edition2021.stderr b/tests/ui/wildcard_imports_2021.edition2021.stderr
new file mode 100644
index 00000000000..acca9f651b4
--- /dev/null
+++ b/tests/ui/wildcard_imports_2021.edition2021.stderr
@@ -0,0 +1,132 @@
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:13:5
+   |
+LL | use crate::fn_mod::*;
+   |     ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+   |
+   = note: `-D clippy::wildcard-imports` implied by `-D warnings`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:14:5
+   |
+LL | use crate::mod_mod::*;
+   |     ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:15:5
+   |
+LL | use crate::multi_fn_mod::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:16:5
+   |
+LL | use crate::struct_mod::*;
+   |     ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:19:5
+   |
+LL | use wildcard_imports_helper::inner::inner_for_self_import::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:21:5
+   |
+LL | use wildcard_imports_helper::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:91:13
+   |
+LL |         use crate::fn_mod::*;
+   |             ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:97:75
+   |
+LL |         use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
+   |                                                                           ^ help: try: `inner_extern_foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:98:13
+   |
+LL |         use wildcard_imports_helper::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:109:20
+   |
+LL |         use self::{inner::*, inner2::*};
+   |                    ^^^^^^^^ help: try: `inner::inner_foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:109:30
+   |
+LL |         use self::{inner::*, inner2::*};
+   |                              ^^^^^^^^^ help: try: `inner2::inner_bar`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:116:13
+   |
+LL |         use wildcard_imports_helper::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:145:9
+   |
+LL |     use crate::in_fn_test::*;
+   |         ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:154:9
+   |
+LL |     use crate:: in_fn_test::  * ;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:155:9
+   |
+LL |       use crate:: fn_mod::
+   |  _________^
+LL | |         *;
+   | |_________^ help: try: `crate:: fn_mod::foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:166:13
+   |
+LL |         use super::*;
+   |             ^^^^^^^^ help: try: `super::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:201:17
+   |
+LL |             use super::*;
+   |                 ^^^^^^^^ help: try: `super::insidefoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:209:13
+   |
+LL |         use crate::super_imports::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:218:17
+   |
+LL |             use super::super::*;
+   |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:227:13
+   |
+LL |         use super::super::super_imports::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:235:13
+   |
+LL |         use super::*;
+   |             ^^^^^^^^ help: try: `super::foofoo`
+
+error: aborting due to 21 previous errors
+
diff --git a/tests/ui/wildcard_imports_2021.rs b/tests/ui/wildcard_imports_2021.rs
new file mode 100644
index 00000000000..b5ed58e6813
--- /dev/null
+++ b/tests/ui/wildcard_imports_2021.rs
@@ -0,0 +1,241 @@
+// revisions: edition2018 edition2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
+// run-rustfix
+// aux-build:wildcard_imports_helper.rs
+
+#![warn(clippy::wildcard_imports)]
+#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
+#![warn(unused_imports)]
+
+extern crate wildcard_imports_helper;
+
+use crate::fn_mod::*;
+use crate::mod_mod::*;
+use crate::multi_fn_mod::*;
+use crate::struct_mod::*;
+
+#[allow(unused_imports)]
+use wildcard_imports_helper::inner::inner_for_self_import::*;
+use wildcard_imports_helper::prelude::v1::*;
+use wildcard_imports_helper::*;
+
+use std::io::prelude::*;
+
+struct ReadFoo;
+
+impl Read for ReadFoo {
+    fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
+        Ok(0)
+    }
+}
+
+mod fn_mod {
+    pub fn foo() {}
+}
+
+mod mod_mod {
+    pub mod inner_mod {
+        pub fn foo() {}
+    }
+}
+
+mod multi_fn_mod {
+    pub fn multi_foo() {}
+    pub fn multi_bar() {}
+    pub fn multi_baz() {}
+    pub mod multi_inner_mod {
+        pub fn foo() {}
+    }
+}
+
+mod struct_mod {
+    pub struct A;
+    pub struct B;
+    pub mod inner_struct_mod {
+        pub struct C;
+    }
+
+    #[macro_export]
+    macro_rules! double_struct_import_test {
+        () => {
+            let _ = A;
+        };
+    }
+}
+
+fn main() {
+    foo();
+    multi_foo();
+    multi_bar();
+    multi_inner_mod::foo();
+    inner_mod::foo();
+    extern_foo();
+    inner_extern_bar();
+
+    let _ = A;
+    let _ = inner_struct_mod::C;
+    let _ = ExternA;
+    let _ = PreludeModAnywhere;
+
+    double_struct_import_test!();
+    double_struct_import_test!();
+}
+
+mod in_fn_test {
+    pub use self::inner_exported::*;
+    #[allow(unused_imports)]
+    pub(crate) use self::inner_exported2::*;
+
+    fn test_intern() {
+        use crate::fn_mod::*;
+
+        foo();
+    }
+
+    fn test_extern() {
+        use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
+        use wildcard_imports_helper::*;
+
+        inner_for_self_import::inner_extern_foo();
+        inner_extern_foo();
+
+        extern_foo();
+
+        let _ = ExternA;
+    }
+
+    fn test_inner_nested() {
+        use self::{inner::*, inner2::*};
+
+        inner_foo();
+        inner_bar();
+    }
+
+    fn test_extern_reexported() {
+        use wildcard_imports_helper::*;
+
+        extern_exported();
+        let _ = ExternExportedStruct;
+        let _ = ExternExportedEnum::A;
+    }
+
+    mod inner_exported {
+        pub fn exported() {}
+        pub struct ExportedStruct;
+        pub enum ExportedEnum {
+            A,
+        }
+    }
+
+    mod inner_exported2 {
+        pub(crate) fn exported2() {}
+    }
+
+    mod inner {
+        pub fn inner_foo() {}
+    }
+
+    mod inner2 {
+        pub fn inner_bar() {}
+    }
+}
+
+fn test_reexported() {
+    use crate::in_fn_test::*;
+
+    exported();
+    let _ = ExportedStruct;
+    let _ = ExportedEnum::A;
+}
+
+#[rustfmt::skip]
+fn test_weird_formatting() {
+    use crate:: in_fn_test::  * ;
+    use crate:: fn_mod::
+        *;
+
+    exported();
+    foo();
+}
+
+mod super_imports {
+    fn foofoo() {}
+
+    mod should_be_replaced {
+        use super::*;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass {
+        use super::*;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_inside_function {
+        fn with_super_inside_function() {
+            use super::*;
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_further_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::*;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod should_be_replaced_further_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::*;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod use_explicit_should_be_replaced {
+        use crate::super_imports::*;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
+
+    mod use_double_super_should_be_replaced {
+        mod inner {
+            use super::super::*;
+
+            fn with_double_super() {
+                let _ = foofoo();
+            }
+        }
+    }
+
+    mod use_super_explicit_should_be_replaced {
+        use super::super::super_imports::*;
+
+        fn with_super_explicit() {
+            let _ = foofoo();
+        }
+    }
+
+    mod attestation_should_be_replaced {
+        use super::*;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
+}
diff --git a/tests/ui/wildcard_imports_2021.stderr b/tests/ui/wildcard_imports_2021.stderr
new file mode 100644
index 00000000000..92f6d31530f
--- /dev/null
+++ b/tests/ui/wildcard_imports_2021.stderr
@@ -0,0 +1,132 @@
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:9:5
+   |
+LL | use crate::fn_mod::*;
+   |     ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+   |
+   = note: `-D clippy::wildcard-imports` implied by `-D warnings`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:10:5
+   |
+LL | use crate::mod_mod::*;
+   |     ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:11:5
+   |
+LL | use crate::multi_fn_mod::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:12:5
+   |
+LL | use crate::struct_mod::*;
+   |     ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:15:5
+   |
+LL | use wildcard_imports_helper::inner::inner_for_self_import::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:17:5
+   |
+LL | use wildcard_imports_helper::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:87:13
+   |
+LL |         use crate::fn_mod::*;
+   |             ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:93:75
+   |
+LL |         use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
+   |                                                                           ^ help: try: `inner_extern_foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:94:13
+   |
+LL |         use wildcard_imports_helper::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:105:20
+   |
+LL |         use self::{inner::*, inner2::*};
+   |                    ^^^^^^^^ help: try: `inner::inner_foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:105:30
+   |
+LL |         use self::{inner::*, inner2::*};
+   |                              ^^^^^^^^^ help: try: `inner2::inner_bar`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:112:13
+   |
+LL |         use wildcard_imports_helper::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:141:9
+   |
+LL |     use crate::in_fn_test::*;
+   |         ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:150:9
+   |
+LL |     use crate:: in_fn_test::  * ;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:151:9
+   |
+LL |       use crate:: fn_mod::
+   |  _________^
+LL | |         *;
+   | |_________^ help: try: `crate:: fn_mod::foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:162:13
+   |
+LL |         use super::*;
+   |             ^^^^^^^^ help: try: `super::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:197:17
+   |
+LL |             use super::*;
+   |                 ^^^^^^^^ help: try: `super::insidefoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:205:13
+   |
+LL |         use crate::super_imports::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:214:17
+   |
+LL |             use super::super::*;
+   |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:223:13
+   |
+LL |         use super::super::super_imports::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:231:13
+   |
+LL |         use super::*;
+   |             ^^^^^^^^ help: try: `super::foofoo`
+
+error: aborting due to 21 previous errors
+
diff --git a/tests/versioncheck.rs b/tests/versioncheck.rs
index 7a85386a3df..c721e9969c9 100644
--- a/tests/versioncheck.rs
+++ b/tests/versioncheck.rs
@@ -2,7 +2,6 @@
 #![warn(rust_2018_idioms, unused_lifetimes)]
 #![allow(clippy::single_match_else)]
 
-use rustc_tools_util::VersionInfo;
 use std::fs;
 
 #[test]