about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--RELEASES.md6
-rw-r--r--compiler/rustc_ast/src/ast_like.rs102
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs14
-rw-r--r--compiler/rustc_ast/src/expand/mod.rs2
-rw-r--r--compiler/rustc_ast/src/lib.rs2
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs49
-rw-r--r--compiler/rustc_ast/src/tokenstream.rs160
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs54
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_eval.rs222
-rw-r--r--compiler/rustc_codegen_cranelift/src/vtable.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs44
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs75
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs54
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs12
-rw-r--r--compiler/rustc_data_structures/src/svh.rs2
-rw-r--r--compiler/rustc_expand/src/base.rs79
-rw-r--r--compiler/rustc_expand/src/config.rs121
-rw-r--r--compiler/rustc_expand/src/expand.rs50
-rw-r--r--compiler/rustc_expand/src/proc_macro.rs2
-rw-r--r--compiler/rustc_feature/src/active.rs3
-rw-r--r--compiler/rustc_feature/src/lib.rs2
-rw-r--r--compiler/rustc_hir/src/stable_hash_impls.rs2
-rw-r--r--compiler/rustc_hir/src/weak_lang_items.rs4
-rw-r--r--compiler/rustc_infer/src/lib.rs2
-rw-r--r--compiler/rustc_lexer/src/lib.rs6
-rw-r--r--compiler/rustc_lint/src/builtin.rs2
-rw-r--r--compiler/rustc_lint/src/levels.rs7
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp33
-rw-r--r--compiler/rustc_middle/src/ich/impls_syntax.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs2
-rw-r--r--compiler/rustc_middle/src/traits/query.rs2
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs2
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs2
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs109
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs4
-rw-r--r--compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs2
-rw-r--r--compiler/rustc_mir/src/transform/generator.rs7
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs1
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs2
-rw-r--r--compiler/rustc_parse/src/lib.rs75
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs22
-rw-r--r--compiler/rustc_parse/src/parser/attr_wrapper.rs517
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs12
-rw-r--r--compiler/rustc_parse/src/parser/item.rs54
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs151
-rw-r--r--compiler/rustc_parse/src/parser/nonterminal.rs4
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs65
-rw-r--r--compiler/rustc_query_system/src/dep_graph/dep_node.rs2
-rw-r--r--compiler/rustc_resolve/src/late.rs2
-rw-r--r--compiler/rustc_resolve/src/late/lifetimes.rs193
-rw-r--r--compiler/rustc_resolve/src/lib.rs67
-rw-r--r--compiler/rustc_session/src/config.rs19
-rw-r--r--compiler/rustc_session/src/session.rs25
-rw-r--r--compiler/rustc_session/src/utils.rs55
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_target/README.md2
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs18
-rw-r--r--compiler/rustc_target/src/abi/call/wasm.rs (renamed from compiler/rustc_target/src/abi/call/wasm32.rs)27
-rw-r--r--compiler/rustc_target/src/abi/call/wasm32_bindgen_compat.rs29
-rw-r--r--compiler/rustc_target/src/abi/call/wasm64.rs58
-rw-r--r--compiler/rustc_target/src/lib.rs2
-rw-r--r--compiler/rustc_target/src/spec/abi.rs15
-rw-r--r--compiler/rustc_target/src/spec/mod.rs22
-rw-r--r--compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/mod.rs2
-rw-r--r--compiler/rustc_typeck/src/check/coercion.rs5
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs2
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs8
-rw-r--r--library/alloc/src/boxed.rs2
-rw-r--r--library/core/src/cmp.rs3
-rw-r--r--library/core/src/iter/adapters/peekable.rs3
-rw-r--r--library/core/src/iter/traits/iterator.rs46
-rw-r--r--library/core/src/lib.rs3
-rw-r--r--library/core/src/mem/maybe_uninit.rs12
-rw-r--r--library/core/src/pin.rs217
-rw-r--r--library/core/src/ptr/const_ptr.rs2
-rw-r--r--library/core/src/ptr/mut_ptr.rs2
-rw-r--r--library/core/src/sync/atomic.rs21
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/panic_abort/Cargo.toml1
-rw-r--r--library/panic_abort/src/android.rs49
-rw-r--r--library/panic_abort/src/lib.rs7
-rw-r--r--src/bootstrap/bootstrap.py89
-rw-r--r--src/bootstrap/test.rs2
-rw-r--r--src/ci/docker/host-x86_64/test-various/Dockerfile4
-rw-r--r--src/doc/rustdoc/src/lints.md23
-rw-r--r--src/doc/unstable-book/src/library-features/asm.md72
-rw-r--r--src/librustdoc/html/highlight.rs125
-rw-r--r--src/librustdoc/html/highlight/fixtures/sample.html10
-rw-r--r--src/librustdoc/html/highlight/fixtures/sample.rs10
-rw-r--r--src/librustdoc/lint.rs15
-rw-r--r--src/librustdoc/passes/bare_urls.rs (renamed from src/librustdoc/passes/non_autolinks.rs)85
-rw-r--r--src/librustdoc/passes/calculate_doc_coverage.rs50
-rw-r--r--src/librustdoc/passes/mod.rs9
m---------src/llvm-project0
-rw-r--r--src/test/assembly/panic-no-unwind-no-uwtable.rs8
-rw-r--r--src/test/assembly/panic-unwind-no-uwtable.rs12
-rw-r--r--src/test/codegen/force-no-unwind-tables.rs6
-rw-r--r--src/test/codegen/panic-unwind-default-uwtable.rs6
-rw-r--r--src/test/debuginfo/var-captured-in-nested-closure.rs49
-rw-r--r--src/test/debuginfo/var-captured-in-stack-closure.rs42
-rw-r--r--src/test/run-make/wasm-abi/Makefile7
-rw-r--r--src/test/run-make/wasm-abi/foo.js22
-rw-r--r--src/test/run-make/wasm-abi/foo.rs87
-rw-r--r--src/test/rustdoc-ui/coverage/traits.rs14
-rw-r--r--src/test/rustdoc-ui/coverage/traits.stdout4
-rw-r--r--src/test/rustdoc-ui/renamed-lint-still-applies.rs5
-rw-r--r--src/test/rustdoc-ui/renamed-lint-still-applies.stderr22
-rw-r--r--src/test/rustdoc-ui/unknown-renamed-lints.rs6
-rw-r--r--src/test/rustdoc-ui/unknown-renamed-lints.stderr18
-rw-r--r--src/test/rustdoc-ui/url-improvements.rs16
-rw-r--r--src/test/rustdoc-ui/url-improvements.stderr56
-rw-r--r--src/test/ui/asm/sym.rs2
-rw-r--r--src/test/ui/codemap_tests/unicode.stderr2
-rw-r--r--src/test/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs4
-rw-r--r--src/test/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs4
-rw-r--r--src/test/ui/feature-gates/feature-gate-abi.rs25
-rw-r--r--src/test/ui/feature-gates/feature-gate-abi.stderr195
-rw-r--r--src/test/ui/feature-gates/feature-gate-wasm_abi.rs7
-rw-r--r--src/test/ui/feature-gates/feature-gate-wasm_abi.stderr12
-rw-r--r--src/test/ui/issues/issue-69225-SCEVAddExpr-wrap-flag.rs1
-rw-r--r--src/test/ui/lifetimes/issue-83737-binders-across-types.rs14
-rw-r--r--src/test/ui/linkage-attr/linkage-detect-extern-generated-name-collision.rs2
-rw-r--r--src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.rs3
-rw-r--r--src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.stderr2
-rw-r--r--src/test/ui/macros/builtin-std-paths-fail.stderr40
-rw-r--r--src/test/ui/panic-runtime/unwind-tables-panic-required.rs10
-rw-r--r--src/test/ui/parser/issue-63116.stderr6
-rw-r--r--src/test/ui/parser/issue-8537.stderr2
-rw-r--r--src/test/ui/parser/use-unclosed-brace.rs12
-rw-r--r--src/test/ui/parser/use-unclosed-brace.stderr27
-rw-r--r--src/test/ui/proc-macro/attr-complex-fn.stdout38
-rw-r--r--src/test/ui/proc-macro/attribute-after-derive.stdout50
-rw-r--r--src/test/ui/proc-macro/auxiliary/multiple-derives.rs22
-rw-r--r--src/test/ui/proc-macro/auxiliary/nonterminal-recollect-attr.rs4
-rw-r--r--src/test/ui/proc-macro/cfg-eval-inner.rs39
-rw-r--r--src/test/ui/proc-macro/cfg-eval-inner.stdout247
-rw-r--r--src/test/ui/proc-macro/cfg-eval.rs9
-rw-r--r--src/test/ui/proc-macro/cfg-eval.stdout69
-rw-r--r--src/test/ui/proc-macro/derive-expand-order.rs14
-rw-r--r--src/test/ui/proc-macro/derive-expand-order.stdout5
-rw-r--r--src/test/ui/proc-macro/expand-to-derive.stdout47
-rw-r--r--src/test/ui/proc-macro/inner-attrs.rs54
-rw-r--r--src/test/ui/proc-macro/inner-attrs.stderr36
-rw-r--r--src/test/ui/proc-macro/inner-attrs.stdout833
-rw-r--r--src/test/ui/proc-macro/issue-36935.stderr16
-rw-r--r--src/test/ui/proc-macro/issue-75930-derive-cfg.stdout275
-rw-r--r--src/test/ui/proc-macro/issue-78675-captured-inner-attrs.stdout20
-rw-r--r--src/test/ui/proc-macro/macro-rules-derive-cfg.stdout73
-rw-r--r--src/test/ui/proc-macro/nested-derive-cfg.stdout47
-rw-r--r--src/test/ui/proc-macro/nonterminal-recollect-attr.rs4
-rw-r--r--src/test/ui/proc-macro/nonterminal-recollect-attr.stdout72
-rw-r--r--src/test/ui/proc-macro/simple-tuple.rs19
-rw-r--r--src/test/ui/proc-macro/simple-tuple.stdout79
-rw-r--r--src/test/ui/proc-macro/weird-braces.stdout196
-rw-r--r--src/test/ui/resolve/issue-81508.rs22
-rw-r--r--src/test/ui/resolve/issue-81508.stderr21
-rw-r--r--src/test/ui/sanitize/hwaddress.rs3
-rw-r--r--src/test/ui/suggestions/issue-83892.fixed11
-rw-r--r--src/test/ui/suggestions/issue-83892.rs11
-rw-r--r--src/test/ui/suggestions/issue-83892.stderr14
-rw-r--r--src/test/ui/traits/associated_type_bound/issue-51446.rs34
-rw-r--r--src/test/ui/union/union-derive.stderr36
-rw-r--r--src/test/ui/unwind-no-uwtable.rs34
-rw-r--r--src/tools/clippy/CHANGELOG.md146
-rw-r--r--src/tools/clippy/README.md2
-rw-r--r--src/tools/clippy/clippy_dev/src/fmt.rs2
-rw-r--r--src/tools/clippy/clippy_dev/src/lib.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs173
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_constants.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/atomic_ordering.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs.rs118
-rw-r--r--src/tools/clippy/clippy_lints/src/await_holding_invalid.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/bytecount.rs90
-rw-r--r--src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/checked_conversions.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/cognitive_complexity.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/collapsible_match.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/comparison_chain.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/copies.rs488
-rw-r--r--src/tools/clippy/clippy_lints/src/create_dir.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/default.rs53
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs91
-rw-r--r--src/tools/clippy/clippy_lints/src/doc.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/double_comparison.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/double_parens.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/drop_forget_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/duration_subsec.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/entry.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/eq_op.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/erasing_op.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/eval_order_dependence.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/excessive_bools.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/exit.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/explicit_write.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/fallible_impl_from.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/float_equality_without_abs.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/float_literal.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs42
-rw-r--r--src/tools/clippy/clippy_lints/src/format.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/formatting.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/functions.rs738
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/mod.rs267
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs272
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs124
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/result_unit_err.rs66
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs73
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs68
-rw-r--r--src/tools/clippy/clippy_lints/src/get_last_with_len.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/identity_op.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/if_let_mutex.rs28
-rw-r--r--src/tools/clippy/clippy_lints/src/if_let_some_result.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_hasher.rs377
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_return.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/indexing_slicing.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/infinite_iter.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_impl.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs221
-rw-r--r--src/tools/clippy/clippy_lints/src/large_enum_variant.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs99
-rw-r--r--src/tools/clippy/clippy_lints/src/let_if_seq.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs2462
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/literal_representation.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_collect.rs126
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs92
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/never_loop.rs46
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/same_item_push.rs139
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/utils.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/macro_use.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_map.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_strip.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/map_clone.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/map_err_ignore.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/map_identity.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/map_unit_fn.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/match_on_vec_items.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches.rs126
-rw-r--r--src/tools/clippy/clippy_lints/src/mem_discriminant.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/mem_forget.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mem_replace.rs63
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs169
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs55
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs118
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/expect_used.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map.rs223
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_next.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_count.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_nth.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs61
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_flatten.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs345
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/ok_expect.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/search_is_some.rs90
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/skip_while_next.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/useless_asref.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/utils.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/zst_offset.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/minmax.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs126
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_inline.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_key.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_mut.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_reference.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_bool.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrow.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_for_each.rs167
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_update.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/neg_multiply.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/new_without_default.rs96
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs58
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs106
-rw-r--r--src/tools/clippy/clippy_lints/src/open_options.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/option_env_unwrap.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/option_if_let_else.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/panic_unimplemented.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs45
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr_eq.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/ranges.rs63
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_clone.rs258
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_closure_call.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_slicing.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/ref_option_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/regex.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/repeat_once.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/shadow.rs69
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs42
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/swap.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/to_string_in_display.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/trait_bounds.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/utils.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmuting_null.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/try_err.rs25
-rw-r--r--src/tools/clippy/clippy_lints/src/types/borrowed_box.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs1075
-rw-r--r--src/tools/clippy/clippy_lints/src/types/type_complexity.rs79
-rw-r--r--src/tools/clippy/clippy_lints/src/types/utils.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/types/vec_box.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/undropped_manually_drops.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/utils.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unnamed_address.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs44
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_io_amount.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_self.rs25
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_unit.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap_in_result.rs44
-rw-r--r--src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs25
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs53
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs96
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/inspector.rs92
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints.rs199
-rw-r--r--src/tools/clippy/clippy_lints/src/vec.rs54
-rw-r--r--src/tools/clippy/clippy_lints/src/vec_init_then_push.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_div_zero.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/attrs.rs12
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs10
-rw-r--r--src/tools/clippy/clippy_utils/src/diagnostics.rs11
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs30
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs104
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs14
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs42
-rw-r--r--src/tools/clippy/clippy_utils/src/usage.rs8
-rw-r--r--src/tools/clippy/doc/adding_lints.md60
-rw-r--r--src/tools/clippy/lintcheck-logs/lintcheck_crates_logs.txt180
-rw-r--r--src/tools/clippy/lintcheck/src/main.rs8
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/src/driver.rs12
-rw-r--r--src/tools/clippy/tests/compile-test.rs16
-rw-r--r--src/tools/clippy/tests/lint_message_convention.rs4
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr6
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.stderr6
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.stderr6
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml1
-rw-r--r--src/tools/clippy/tests/ui-internal/if_chain_style.rs92
-rw-r--r--src/tools/clippy/tests/ui-internal/if_chain_style.stderr85
-rw-r--r--src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs16
-rw-r--r--src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.stderr14
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs6
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr28
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs209
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr143
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs103
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr121
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs119
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr154
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs155
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.stderr101
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.rs2
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs2
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs2
-rw-r--r--src/tools/clippy/tests/ui/clone_on_copy.fixed34
-rw-r--r--src/tools/clippy/tests/ui/clone_on_copy.rs34
-rw-r--r--src/tools/clippy/tests/ui/clone_on_copy.stderr30
-rw-r--r--src/tools/clippy/tests/ui/clone_on_copy_mut.rs18
-rw-r--r--src/tools/clippy/tests/ui/collapsible_match2.rs7
-rw-r--r--src/tools/clippy/tests/ui/collapsible_match2.stderr20
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-7012.rs17
-rw-r--r--src/tools/clippy/tests/ui/default_numeric_fallback.rs1
-rw-r--r--src/tools/clippy/tests/ui/default_numeric_fallback.stderr48
-rw-r--r--src/tools/clippy/tests/ui/derive.rs21
-rw-r--r--src/tools/clippy/tests/ui/derive.stderr30
-rw-r--r--src/tools/clippy/tests/ui/doc.rs21
-rw-r--r--src/tools/clippy/tests/ui/escape_analysis.rs4
-rw-r--r--src/tools/clippy/tests/ui/floating_point_log.fixed2
-rw-r--r--src/tools/clippy/tests/ui/floating_point_log.stderr2
-rw-r--r--src/tools/clippy/tests/ui/from_str_radix_10.stderr2
-rw-r--r--src/tools/clippy/tests/ui/if_same_then_else.rs3
-rw-r--r--src/tools/clippy/tests/ui/if_same_then_else.stderr88
-rw-r--r--src/tools/clippy/tests/ui/if_same_then_else2.rs3
-rw-r--r--src/tools/clippy/tests/ui/if_same_then_else2.stderr106
-rw-r--r--src/tools/clippy/tests/ui/implicit_clone.rs2
-rw-r--r--src/tools/clippy/tests/ui/into_iter_on_ref.fixed2
-rw-r--r--src/tools/clippy/tests/ui/into_iter_on_ref.rs2
-rw-r--r--src/tools/clippy/tests/ui/len_without_is_empty.rs99
-rw-r--r--src/tools/clippy/tests/ui/len_without_is_empty.stderr79
-rw-r--r--src/tools/clippy/tests/ui/let_if_seq.rs3
-rw-r--r--src/tools/clippy/tests/ui/let_if_seq.stderr8
-rw-r--r--src/tools/clippy/tests/ui/linkedlist.rs (renamed from src/tools/clippy/tests/ui/dlist.rs)3
-rw-r--r--src/tools/clippy/tests/ui/linkedlist.stderr (renamed from src/tools/clippy/tests/ui/dlist.stderr)32
-rw-r--r--src/tools/clippy/tests/ui/manual_map_option.fixed15
-rw-r--r--src/tools/clippy/tests/ui/manual_map_option.rs17
-rw-r--r--src/tools/clippy/tests/ui/manual_map_option.stderr55
-rw-r--r--src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.stderr2
-rw-r--r--src/tools/clippy/tests/ui/match_ref_pats.stderr16
-rw-r--r--src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed16
-rw-r--r--src/tools/clippy/tests/ui/match_wildcard_for_single_variants.rs16
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_attr.rs6
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_attr.stderr8
-rw-r--r--src/tools/clippy/tests/ui/missing_panics_doc.rs (renamed from src/tools/clippy/tests/ui/doc_panics.rs)40
-rw-r--r--src/tools/clippy/tests/ui/missing_panics_doc.stderr (renamed from src/tools/clippy/tests/ui/doc_panics.stderr)54
-rw-r--r--src/tools/clippy/tests/ui/needless_bool/simple.rs3
-rw-r--r--src/tools/clippy/tests/ui/needless_bool/simple.stderr8
-rw-r--r--src/tools/clippy/tests/ui/needless_collect_indirect.stderr45
-rw-r--r--src/tools/clippy/tests/ui/needless_for_each_fixable.fixed113
-rw-r--r--src/tools/clippy/tests/ui/needless_for_each_fixable.rs113
-rw-r--r--src/tools/clippy/tests/ui/needless_for_each_fixable.stderr123
-rw-r--r--src/tools/clippy/tests/ui/needless_for_each_unfixable.rs14
-rw-r--r--src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr29
-rw-r--r--src/tools/clippy/tests/ui/needless_return.fixed9
-rw-r--r--src/tools/clippy/tests/ui/needless_return.rs9
-rw-r--r--src/tools/clippy/tests/ui/needless_return.stderr36
-rw-r--r--src/tools/clippy/tests/ui/non_octal_unix_permissions.fixed33
-rw-r--r--src/tools/clippy/tests/ui/non_octal_unix_permissions.rs33
-rw-r--r--src/tools/clippy/tests/ui/non_octal_unix_permissions.stderr28
-rw-r--r--src/tools/clippy/tests/ui/option_filter_map.fixed23
-rw-r--r--src/tools/clippy/tests/ui/option_filter_map.rs25
-rw-r--r--src/tools/clippy/tests/ui/option_filter_map.stderr56
-rw-r--r--src/tools/clippy/tests/ui/option_option.rs3
-rw-r--r--src/tools/clippy/tests/ui/option_option.stderr38
-rw-r--r--src/tools/clippy/tests/ui/redundant_clone.fixed24
-rw-r--r--src/tools/clippy/tests/ui/redundant_clone.rs24
-rw-r--r--src/tools/clippy/tests/ui/redundant_clone.stderr20
-rw-r--r--src/tools/clippy/tests/ui/redundant_slicing.rs29
-rw-r--r--src/tools/clippy/tests/ui/redundant_slicing.stderr32
-rw-r--r--src/tools/clippy/tests/ui/ref_option_ref.rs2
-rw-r--r--src/tools/clippy/tests/ui/ref_option_ref.stderr2
-rw-r--r--src/tools/clippy/tests/ui/result_unit_error.stderr20
-rw-r--r--src/tools/clippy/tests/ui/same_item_push.rs7
-rw-r--r--src/tools/clippy/tests/ui/stable_sort_primitive.fixed2
-rw-r--r--src/tools/clippy/tests/ui/stable_sort_primitive.rs2
-rw-r--r--src/tools/clippy/tests/ui/type_complexity.rs (renamed from src/tools/clippy/tests/ui/complex_types.rs)0
-rw-r--r--src/tools/clippy/tests/ui/type_complexity.stderr (renamed from src/tools/clippy/tests/ui/complex_types.stderr)30
-rw-r--r--src/tools/clippy/tests/ui/upper_case_acronyms.rs14
-rw-r--r--src/tools/clippy/tests/ui/upper_case_acronyms.stderr8
-rw-r--r--src/tools/clippy/tests/ui/vec.fixed16
-rw-r--r--src/tools/clippy/tests/ui/vec.rs16
-rw-r--r--src/tools/clippy/tests/ui/vec.stderr44
-rw-r--r--src/tools/clippy/tests/ui/vec_box_sized.fixed2
-rw-r--r--src/tools/clippy/tests/ui/vec_box_sized.rs2
-rw-r--r--src/tools/clippy/tests/ui/vec_box_sized.stderr26
-rw-r--r--src/tools/clippy/tests/ui/wrong_self_convention.rs9
-rw-r--r--src/tools/clippy/tests/ui/wrong_self_convention.stderr4
-rw-r--r--src/tools/clippy/tests/ui/wrong_self_convention2.rs32
-rw-r--r--src/tools/clippy/tests/ui/wrong_self_convention2.stderr11
-rw-r--r--src/tools/clippy/util/gh-pages/index.html191
-rw-r--r--src/tools/compiletest/src/runtest.rs1
m---------src/tools/miri18
518 files changed, 15243 insertions, 7781 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 2b7fbf1b647..e892d87245c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2492,6 +2492,7 @@ dependencies = [
 name = "panic_abort"
 version = "0.0.0"
 dependencies = [
+ "alloc",
  "cfg-if 0.1.10",
  "compiler_builtins",
  "core",
diff --git a/RELEASES.md b/RELEASES.md
index 2fcb94cf0a6..c6c0007d115 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1906,6 +1906,11 @@ Cargo
 - [You can now pass the `--features` option multiple times to enable
   multiple features.][cargo/7084]
 
+Rustdoc
+-------
+
+- [Documentation on `pub use` statements is prepended to the documentation of the re-exported item][63048]
+
 Misc
 ----
 - [`rustc` will now warn about some incorrect uses of
@@ -1940,6 +1945,7 @@ Compatibility Notes
 [63421]: https://github.com/rust-lang/rust/pull/63421/
 [cargo/7084]: https://github.com/rust-lang/cargo/pull/7084/
 [cargo/7143]: https://github.com/rust-lang/cargo/pull/7143/
+[63048]: https://github.com/rust-lang/rust/pull/63048
 [`<*const T>::cast`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.cast
 [`<*mut T>::cast`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.cast
 [`Duration::as_secs_f32`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.as_secs_f32
diff --git a/compiler/rustc_ast/src/ast_like.rs b/compiler/rustc_ast/src/ast_like.rs
index 63bc7c49a99..945a44ab663 100644
--- a/compiler/rustc_ast/src/ast_like.rs
+++ b/compiler/rustc_ast/src/ast_like.rs
@@ -1,20 +1,32 @@
 use super::ptr::P;
+use super::token::Nonterminal;
 use super::tokenstream::LazyTokenStream;
 use super::{Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant};
-use super::{AssocItem, Expr, ForeignItem, Item, Local};
+use super::{AssocItem, Expr, ForeignItem, Item, Local, MacCallStmt};
 use super::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility};
 use super::{AttrVec, Attribute, Stmt, StmtKind};
 
+use std::fmt::Debug;
+
 /// An `AstLike` represents an AST node (or some wrapper around
 /// and AST node) which stores some combination of attributes
 /// and tokens.
-pub trait AstLike: Sized {
+pub trait AstLike: Sized + Debug {
+    /// This is `true` if this `AstLike` might support 'custom' (proc-macro) inner
+    /// attributes. Attributes like `#![cfg]` and `#![cfg_attr]` are not
+    /// considered 'custom' attributes
+    ///
+    /// If this is `false`, then this `AstLike` definitely does
+    /// not support 'custom' inner attributes, which enables some optimizations
+    /// during token collection.
+    const SUPPORTS_CUSTOM_INNER_ATTRS: bool;
     fn attrs(&self) -> &[Attribute];
     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
     fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>>;
 }
 
 impl<T: AstLike + 'static> AstLike for P<T> {
+    const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS;
     fn attrs(&self) -> &[Attribute] {
         (**self).attrs()
     }
@@ -26,6 +38,55 @@ impl<T: AstLike + 'static> AstLike for P<T> {
     }
 }
 
+impl AstLike for crate::token::Nonterminal {
+    const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true;
+    fn attrs(&self) -> &[Attribute] {
+        match self {
+            Nonterminal::NtItem(item) => item.attrs(),
+            Nonterminal::NtStmt(stmt) => stmt.attrs(),
+            Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.attrs(),
+            Nonterminal::NtPat(_)
+            | Nonterminal::NtTy(_)
+            | Nonterminal::NtMeta(_)
+            | Nonterminal::NtPath(_)
+            | Nonterminal::NtVis(_)
+            | Nonterminal::NtTT(_)
+            | Nonterminal::NtBlock(_)
+            | Nonterminal::NtIdent(..)
+            | Nonterminal::NtLifetime(_) => &[],
+        }
+    }
+    fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
+        match self {
+            Nonterminal::NtItem(item) => item.visit_attrs(f),
+            Nonterminal::NtStmt(stmt) => stmt.visit_attrs(f),
+            Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.visit_attrs(f),
+            Nonterminal::NtPat(_)
+            | Nonterminal::NtTy(_)
+            | Nonterminal::NtMeta(_)
+            | Nonterminal::NtPath(_)
+            | Nonterminal::NtVis(_)
+            | Nonterminal::NtTT(_)
+            | Nonterminal::NtBlock(_)
+            | Nonterminal::NtIdent(..)
+            | Nonterminal::NtLifetime(_) => {}
+        }
+    }
+    fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
+        match self {
+            Nonterminal::NtItem(item) => item.tokens_mut(),
+            Nonterminal::NtStmt(stmt) => stmt.tokens_mut(),
+            Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(),
+            Nonterminal::NtPat(pat) => pat.tokens_mut(),
+            Nonterminal::NtTy(ty) => ty.tokens_mut(),
+            Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(),
+            Nonterminal::NtPath(path) => path.tokens_mut(),
+            Nonterminal::NtVis(vis) => vis.tokens_mut(),
+            _ => panic!("Called tokens_mut on {:?}", self),
+        }
+    }
+}
+
 fn visit_attrvec(attrs: &mut AttrVec, f: impl FnOnce(&mut Vec<Attribute>)) {
     crate::mut_visit::visit_clobber(attrs, |attrs| {
         let mut vec = attrs.into();
@@ -35,6 +96,10 @@ fn visit_attrvec(attrs: &mut AttrVec, f: impl FnOnce(&mut Vec<Attribute>)) {
 }
 
 impl AstLike for StmtKind {
+    // This might be an `StmtKind::Item`, which contains
+    // an item that supports inner attrs
+    const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true;
+
     fn attrs(&self) -> &[Attribute] {
         match self {
             StmtKind::Local(local) => local.attrs(),
@@ -66,6 +131,8 @@ impl AstLike for StmtKind {
 }
 
 impl AstLike for Stmt {
+    const SUPPORTS_CUSTOM_INNER_ATTRS: bool = StmtKind::SUPPORTS_CUSTOM_INNER_ATTRS;
+
     fn attrs(&self) -> &[Attribute] {
         self.kind.attrs()
     }
@@ -79,6 +146,8 @@ impl AstLike for Stmt {
 }
 
 impl AstLike for Attribute {
+    const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
+
     fn attrs(&self) -> &[Attribute] {
         &[]
     }
@@ -94,6 +163,8 @@ impl AstLike for Attribute {
 }
 
 impl<T: AstLike> AstLike for Option<T> {
+    const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS;
+
     fn attrs(&self) -> &[Attribute] {
         self.as_ref().map(|inner| inner.attrs()).unwrap_or(&[])
     }
@@ -127,8 +198,13 @@ impl VecOrAttrVec for AttrVec {
 }
 
 macro_rules! derive_has_tokens_and_attrs {
-    ($($ty:path),*) => { $(
+    (
+        const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner_attrs:literal;
+        $($ty:path),*
+    ) => { $(
         impl AstLike for $ty {
+            const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner_attrs;
+
             fn attrs(&self) -> &[Attribute] {
                 &self.attrs
             }
@@ -140,6 +216,7 @@ macro_rules! derive_has_tokens_and_attrs {
             fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
                 Some(&mut self.tokens)
             }
+
         }
     )* }
 }
@@ -147,6 +224,8 @@ macro_rules! derive_has_tokens_and_attrs {
 macro_rules! derive_has_attrs_no_tokens {
     ($($ty:path),*) => { $(
         impl AstLike for $ty {
+            const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
+
             fn attrs(&self) -> &[Attribute] {
                 &self.attrs
             }
@@ -165,12 +244,13 @@ macro_rules! derive_has_attrs_no_tokens {
 macro_rules! derive_has_tokens_no_attrs {
     ($($ty:path),*) => { $(
         impl AstLike for $ty {
+            const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
+
             fn attrs(&self) -> &[Attribute] {
                 &[]
             }
 
             fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec<Attribute>)) {}
-
             fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
                 Some(&mut self.tokens)
             }
@@ -178,10 +258,18 @@ macro_rules! derive_has_tokens_no_attrs {
     )* }
 }
 
-// These AST nodes support both inert and active
-// attributes, so they also have tokens.
+// These ast nodes support both active and inert attributes,
+// so they have tokens collected to pass to proc macros
+derive_has_tokens_and_attrs! {
+    // Both `Item` and `AssocItem` can have bodies, which
+    // can contain inner attributes
+    const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true;
+    Item, AssocItem, ForeignItem
+}
+
 derive_has_tokens_and_attrs! {
-    Item, Expr, Local, AssocItem, ForeignItem
+    const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
+    Local, MacCallStmt, Expr
 }
 
 // These ast nodes only support inert attributes, so they don't
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 0fbe4d0120c..41121d095f3 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -6,7 +6,9 @@ use crate::ast::{Lit, LitKind};
 use crate::ast::{MacArgs, MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem};
 use crate::ast::{Path, PathSegment};
 use crate::token::{self, CommentKind, Token};
-use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream, TokenTree, TreeAndSpacing};
+use crate::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree};
+use crate::tokenstream::{DelimSpan, Spacing, TokenTree, TreeAndSpacing};
+use crate::tokenstream::{LazyTokenStream, TokenStream};
 
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_span::source_map::BytePos;
@@ -268,14 +270,18 @@ impl Attribute {
         }
     }
 
-    pub fn tokens(&self) -> TokenStream {
+    pub fn tokens(&self) -> AttrAnnotatedTokenStream {
         match self.kind {
             AttrKind::Normal(_, ref tokens) => tokens
                 .as_ref()
                 .unwrap_or_else(|| panic!("attribute is missing tokens: {:?}", self))
                 .create_token_stream(),
-            AttrKind::DocComment(comment_kind, data) => TokenStream::from(TokenTree::Token(
-                Token::new(token::DocComment(comment_kind, self.style, data), self.span),
+            AttrKind::DocComment(comment_kind, data) => AttrAnnotatedTokenStream::from((
+                AttrAnnotatedTokenTree::Token(Token::new(
+                    token::DocComment(comment_kind, self.style, data),
+                    self.span,
+                )),
+                Spacing::Alone,
             )),
         }
     }
diff --git a/compiler/rustc_ast/src/expand/mod.rs b/compiler/rustc_ast/src/expand/mod.rs
index eebfc38bdf4..2ee1bfe0ae7 100644
--- a/compiler/rustc_ast/src/expand/mod.rs
+++ b/compiler/rustc_ast/src/expand/mod.rs
@@ -1,3 +1,3 @@
-//! Definitions shared by macros / syntax extensions and e.g. librustc_middle.
+//! Definitions shared by macros / syntax extensions and e.g. `rustc_middle`.
 
 pub mod allocator;
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index 032a4e6c782..1e6da044ec0 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -59,7 +59,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 
 /// Requirements for a `StableHashingContext` to be used in this crate.
 /// This is a hack to allow using the `HashStable_Generic` derive macro
-/// instead of implementing everything in librustc_middle.
+/// instead of implementing everything in `rustc_middle`.
 pub trait HashStableContext: rustc_span::HashStableContext {
     fn hash_attr(&mut self, _: &ast::Attribute, hasher: &mut StableHasher);
 }
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index b1840f475aa..05f57f978c7 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -631,6 +631,33 @@ pub fn noop_flat_map_param<T: MutVisitor>(mut param: Param, vis: &mut T) -> Smal
 }
 
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_attr_annotated_tt<T: MutVisitor>(tt: &mut AttrAnnotatedTokenTree, vis: &mut T) {
+    match tt {
+        AttrAnnotatedTokenTree::Token(token) => {
+            visit_token(token, vis);
+        }
+        AttrAnnotatedTokenTree::Delimited(DelimSpan { open, close }, _delim, tts) => {
+            vis.visit_span(open);
+            vis.visit_span(close);
+            visit_attr_annotated_tts(tts, vis);
+        }
+        AttrAnnotatedTokenTree::Attributes(data) => {
+            for attr in &mut *data.attrs {
+                match &mut attr.kind {
+                    AttrKind::Normal(_, attr_tokens) => {
+                        visit_lazy_tts(attr_tokens, vis);
+                    }
+                    AttrKind::DocComment(..) => {
+                        vis.visit_span(&mut attr.span);
+                    }
+                }
+            }
+            visit_lazy_tts_opt_mut(Some(&mut data.tokens), vis);
+        }
+    }
+}
+
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
 pub fn visit_tt<T: MutVisitor>(tt: &mut TokenTree, vis: &mut T) {
     match tt {
         TokenTree::Token(token) => {
@@ -652,16 +679,30 @@ pub fn visit_tts<T: MutVisitor>(TokenStream(tts): &mut TokenStream, vis: &mut T)
     }
 }
 
-pub fn visit_lazy_tts<T: MutVisitor>(lazy_tts: &mut Option<LazyTokenStream>, vis: &mut T) {
+pub fn visit_attr_annotated_tts<T: MutVisitor>(
+    AttrAnnotatedTokenStream(tts): &mut AttrAnnotatedTokenStream,
+    vis: &mut T,
+) {
+    if vis.token_visiting_enabled() && !tts.is_empty() {
+        let tts = Lrc::make_mut(tts);
+        visit_vec(tts, |(tree, _is_joint)| visit_attr_annotated_tt(tree, vis));
+    }
+}
+
+pub fn visit_lazy_tts_opt_mut<T: MutVisitor>(lazy_tts: Option<&mut LazyTokenStream>, vis: &mut T) {
     if vis.token_visiting_enabled() {
-        visit_opt(lazy_tts, |lazy_tts| {
+        if let Some(lazy_tts) = lazy_tts {
             let mut tts = lazy_tts.create_token_stream();
-            visit_tts(&mut tts, vis);
+            visit_attr_annotated_tts(&mut tts, vis);
             *lazy_tts = LazyTokenStream::new(tts);
-        })
+        }
     }
 }
 
+pub fn visit_lazy_tts<T: MutVisitor>(lazy_tts: &mut Option<LazyTokenStream>, vis: &mut T) {
+    visit_lazy_tts_opt_mut(lazy_tts.as_mut(), vis);
+}
+
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
 // Applies ident visitor if it's an ident; applies other visits to interpolated nodes.
 // In practice the ident part is not actually used by specific visitors right now,
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 1c26668779f..8318b242cae 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -14,6 +14,7 @@
 //! ownership of the original.
 
 use crate::token::{self, DelimToken, Token, TokenKind};
+use crate::AttrVec;
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::{self, Lrc};
@@ -123,11 +124,11 @@ where
 }
 
 pub trait CreateTokenStream: sync::Send + sync::Sync {
-    fn create_token_stream(&self) -> TokenStream;
+    fn create_token_stream(&self) -> AttrAnnotatedTokenStream;
 }
 
-impl CreateTokenStream for TokenStream {
-    fn create_token_stream(&self) -> TokenStream {
+impl CreateTokenStream for AttrAnnotatedTokenStream {
+    fn create_token_stream(&self) -> AttrAnnotatedTokenStream {
         self.clone()
     }
 }
@@ -143,14 +144,14 @@ impl LazyTokenStream {
         LazyTokenStream(Lrc::new(Box::new(inner)))
     }
 
-    pub fn create_token_stream(&self) -> TokenStream {
+    pub fn create_token_stream(&self) -> AttrAnnotatedTokenStream {
         self.0.create_token_stream()
     }
 }
 
 impl fmt::Debug for LazyTokenStream {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Debug::fmt("LazyTokenStream", f)
+        write!(f, "LazyTokenStream({:?})", self.create_token_stream())
     }
 }
 
@@ -173,6 +174,145 @@ impl<CTX> HashStable<CTX> for LazyTokenStream {
     }
 }
 
+/// A `AttrAnnotatedTokenStream` is similar to a `TokenStream`, but with extra
+/// information about the tokens for attribute targets. This is used
+/// during expansion to perform early cfg-expansion, and to process attributes
+/// during proc-macro invocations.
+#[derive(Clone, Debug, Default, Encodable, Decodable)]
+pub struct AttrAnnotatedTokenStream(pub Lrc<Vec<(AttrAnnotatedTokenTree, Spacing)>>);
+
+/// Like `TokenTree`, but for `AttrAnnotatedTokenStream`
+#[derive(Clone, Debug, Encodable, Decodable)]
+pub enum AttrAnnotatedTokenTree {
+    Token(Token),
+    Delimited(DelimSpan, DelimToken, AttrAnnotatedTokenStream),
+    /// Stores the attributes for an attribute target,
+    /// along with the tokens for that attribute target.
+    /// See `AttributesData` for more information
+    Attributes(AttributesData),
+}
+
+impl AttrAnnotatedTokenStream {
+    pub fn new(tokens: Vec<(AttrAnnotatedTokenTree, Spacing)>) -> AttrAnnotatedTokenStream {
+        AttrAnnotatedTokenStream(Lrc::new(tokens))
+    }
+
+    /// Converts this `AttrAnnotatedTokenStream` to a plain `TokenStream
+    /// During conversion, `AttrAnnotatedTokenTree::Attributes` get 'flattened'
+    /// back to a `TokenStream` of the form `outer_attr attr_target`.
+    /// If there are inner attributes, they are inserted into the proper
+    /// place in the attribute target tokens.
+    pub fn to_tokenstream(&self) -> TokenStream {
+        let trees: Vec<_> = self
+            .0
+            .iter()
+            .flat_map(|tree| match &tree.0 {
+                AttrAnnotatedTokenTree::Token(inner) => {
+                    smallvec![(TokenTree::Token(inner.clone()), tree.1)].into_iter()
+                }
+                AttrAnnotatedTokenTree::Delimited(span, delim, stream) => smallvec![(
+                    TokenTree::Delimited(*span, *delim, stream.to_tokenstream()),
+                    tree.1,
+                )]
+                .into_iter(),
+                AttrAnnotatedTokenTree::Attributes(data) => {
+                    let mut outer_attrs = Vec::new();
+                    let mut inner_attrs = Vec::new();
+                    let attrs: Vec<_> = data.attrs.clone().into();
+                    for attr in attrs {
+                        match attr.style {
+                            crate::AttrStyle::Outer => {
+                                assert!(
+                                    inner_attrs.len() == 0,
+                                    "Found outer attribute {:?} after inner attrs {:?}",
+                                    attr,
+                                    inner_attrs
+                                );
+                                outer_attrs.push(attr);
+                            }
+                            crate::AttrStyle::Inner => {
+                                inner_attrs.push(attr);
+                            }
+                        }
+                    }
+
+                    let mut target_tokens: Vec<_> = data
+                        .tokens
+                        .create_token_stream()
+                        .to_tokenstream()
+                        .0
+                        .iter()
+                        .cloned()
+                        .collect();
+                    if !inner_attrs.is_empty() {
+                        let mut found = false;
+                        // Check the last two trees (to account for a trailing semi)
+                        for (tree, _) in target_tokens.iter_mut().rev().take(2) {
+                            if let TokenTree::Delimited(span, delim, delim_tokens) = tree {
+                                // Inner attributes are only supported on extern blocks, functions, impls,
+                                // and modules. All of these have their inner attributes placed at
+                                // the beginning of the rightmost outermost braced group:
+                                // e.g. fn foo() { #![my_attr} }
+                                //
+                                // Therefore, we can insert them back into the right location
+                                // without needing to do any extra position tracking.
+                                //
+                                // Note: Outline modules are an exception - they can
+                                // have attributes like `#![my_attr]` at the start of a file.
+                                // Support for custom attributes in this position is not
+                                // properly implemented - we always synthesize fake tokens,
+                                // so we never reach this code.
+
+                                let mut builder = TokenStreamBuilder::new();
+                                for inner_attr in &inner_attrs {
+                                    builder.push(inner_attr.tokens().to_tokenstream());
+                                }
+                                builder.push(delim_tokens.clone());
+                                *tree = TokenTree::Delimited(*span, *delim, builder.build());
+                                found = true;
+                                break;
+                            }
+                        }
+
+                        assert!(
+                            found,
+                            "Failed to find trailing delimited group in: {:?}",
+                            target_tokens
+                        );
+                    }
+                    let mut flat: SmallVec<[_; 1]> = SmallVec::new();
+                    for attr in outer_attrs {
+                        // FIXME: Make this more efficient
+                        flat.extend(attr.tokens().to_tokenstream().0.clone().iter().cloned());
+                    }
+                    flat.extend(target_tokens);
+                    flat.into_iter()
+                }
+            })
+            .collect();
+        TokenStream::new(trees)
+    }
+}
+
+/// Stores the tokens for an attribute target, along
+/// with its attributes.
+///
+/// This is constructed during parsing when we need to capture
+/// tokens.
+///
+/// For example, `#[cfg(FALSE)] struct Foo {}` would
+/// have an `attrs` field contaiing the `#[cfg(FALSE)]` attr,
+/// and a `tokens` field storing the (unparesd) tokens `struct Foo {}`
+#[derive(Clone, Debug, Encodable, Decodable)]
+pub struct AttributesData {
+    /// Attributes, both outer and inner.
+    /// These are stored in the original order that they were parsed in.
+    pub attrs: AttrVec,
+    /// The underlying tokens for the attribute target that `attrs`
+    /// are applied to
+    pub tokens: LazyTokenStream,
+}
+
 /// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s.
 ///
 /// The goal is for procedural macros to work with `TokenStream`s and `TokenTree`s
@@ -235,6 +375,12 @@ impl TokenStream {
     }
 }
 
+impl From<(AttrAnnotatedTokenTree, Spacing)> for AttrAnnotatedTokenStream {
+    fn from((tree, spacing): (AttrAnnotatedTokenTree, Spacing)) -> AttrAnnotatedTokenStream {
+        AttrAnnotatedTokenStream::new(vec![(tree, spacing)])
+    }
+}
+
 impl From<TokenTree> for TokenStream {
     fn from(tree: TokenTree) -> TokenStream {
         TokenStream::new(vec![(tree, Spacing::Alone)])
@@ -457,6 +603,10 @@ impl Cursor {
         }
     }
 
+    pub fn index(&self) -> usize {
+        self.index
+    }
+
     pub fn append(&mut self, new_stream: TokenStream) {
         if new_stream.is_empty() {
             return;
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index be56f97af8a..44056df4ab9 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -37,8 +37,8 @@
 #![recursion_limit = "256"]
 
 use rustc_ast::node_id::NodeMap;
-use rustc_ast::token::{self, DelimToken, Nonterminal, Token};
-use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, DelimSpan, TokenStream, TokenTree};
+use rustc_ast::token::{self, Token};
+use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree};
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
 use rustc_ast::walk_list;
 use rustc_ast::{self as ast, *};
@@ -56,7 +56,7 @@ use rustc_hir::{ConstArg, GenericArg, ParamName};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_session::lint::builtin::{BARE_TRAIT_OBJECTS, MISSING_ABI};
 use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
-use rustc_session::parse::ParseSess;
+use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
 use rustc_session::Session;
 use rustc_span::hygiene::ExpnId;
 use rustc_span::source_map::{respan, DesugaringKind};
@@ -93,7 +93,7 @@ struct LoweringContext<'a, 'hir: 'a> {
 
     /// HACK(Centril): there is a cyclic dependency between the parser and lowering
     /// if we don't have this function pointer. To avoid that dependency so that
-    /// librustc_middle is independent of the parser, we use dynamic dispatch here.
+    /// `rustc_middle` is independent of the parser, we use dynamic dispatch here.
     nt_to_tokenstream: NtToTokenstream,
 
     /// Used to allocate HIR nodes.
@@ -213,8 +213,6 @@ pub trait ResolverAstLowering {
     ) -> LocalDefId;
 }
 
-type NtToTokenstream = fn(&Nonterminal, &ParseSess, CanSynthesizeMissingTokens) -> TokenStream;
-
 /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
 /// and if so, what meaning it has.
 #[derive(Debug)]
@@ -403,42 +401,6 @@ enum AnonymousLifetimeMode {
     PassThrough,
 }
 
-struct TokenStreamLowering<'a> {
-    parse_sess: &'a ParseSess,
-    synthesize_tokens: CanSynthesizeMissingTokens,
-    nt_to_tokenstream: NtToTokenstream,
-}
-
-impl<'a> TokenStreamLowering<'a> {
-    fn lower_token_stream(&mut self, tokens: TokenStream) -> TokenStream {
-        tokens.into_trees().flat_map(|tree| self.lower_token_tree(tree).into_trees()).collect()
-    }
-
-    fn lower_token_tree(&mut self, tree: TokenTree) -> TokenStream {
-        match tree {
-            TokenTree::Token(token) => self.lower_token(token),
-            TokenTree::Delimited(span, delim, tts) => {
-                TokenTree::Delimited(span, delim, self.lower_token_stream(tts)).into()
-            }
-        }
-    }
-
-    fn lower_token(&mut self, token: Token) -> TokenStream {
-        match token.kind {
-            token::Interpolated(nt) => {
-                let tts = (self.nt_to_tokenstream)(&nt, self.parse_sess, self.synthesize_tokens);
-                TokenTree::Delimited(
-                    DelimSpan::from_single(token.span),
-                    DelimToken::NoDelim,
-                    self.lower_token_stream(tts),
-                )
-                .into()
-            }
-            _ => TokenTree::Token(token).into(),
-        }
-    }
-}
-
 impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_crate(mut self, c: &Crate) -> hir::Crate<'hir> {
         /// Full-crate AST visitor that inserts into a fresh
@@ -1037,12 +999,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     }
                 }
 
-                let tokens = TokenStreamLowering {
+                let tokens = FlattenNonterminals {
                     parse_sess: &self.sess.parse_sess,
                     synthesize_tokens: CanSynthesizeMissingTokens::Yes,
                     nt_to_tokenstream: self.nt_to_tokenstream,
                 }
-                .lower_token(token.clone());
+                .process_token(token.clone());
                 MacArgs::Eq(eq_span, unwrap_single_token(self.sess, tokens, token.span))
             }
         }
@@ -1053,12 +1015,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         tokens: TokenStream,
         synthesize_tokens: CanSynthesizeMissingTokens,
     ) -> TokenStream {
-        TokenStreamLowering {
+        FlattenNonterminals {
             parse_sess: &self.sess.parse_sess,
             synthesize_tokens,
             nt_to_tokenstream: self.nt_to_tokenstream,
         }
-        .lower_token_stream(tokens)
+        .process_token_stream(tokens)
     }
 
     /// Given an associated type constraint like one of these:
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 3724438cc6e..87c4bfae1af 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -196,6 +196,14 @@ impl<'a> PostExpansionVisitor<'a> {
                     "thiscall-unwind ABI is experimental and subject to change"
                 );
             }
+            "wasm" => {
+                gate_feature_post!(
+                    &self,
+                    wasm_abi,
+                    span,
+                    "wasm ABI is experimental and subject to change"
+                );
+            }
             abi => self
                 .sess
                 .parse_sess
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index 025872df017..79dc857074d 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -1,11 +1,18 @@
 use crate::util::check_builtin_macro_attribute;
 
-use rustc_ast::mut_visit::{self, MutVisitor};
-use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, AstLike};
+use rustc_ast as ast;
+use rustc_ast::mut_visit::MutVisitor;
+use rustc_ast::tokenstream::CanSynthesizeMissingTokens;
+use rustc_ast::visit::Visitor;
+use rustc_ast::{mut_visit, visit};
+use rustc_ast::{AstLike, Attribute};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_expand::config::StripUnconfigured;
 use rustc_expand::configure;
+use rustc_parse::parser::ForceCollect;
+use rustc_session::utils::FlattenNonterminals;
+
+use rustc_ast::ptr::P;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use smallvec::SmallVec;
@@ -22,74 +29,179 @@ crate fn expand(
 
 crate fn cfg_eval(ecx: &ExtCtxt<'_>, annotatable: Annotatable) -> Vec<Annotatable> {
     let mut visitor = CfgEval {
-        cfg: StripUnconfigured { sess: ecx.sess, features: ecx.ecfg.features, modified: false },
+        cfg: &mut StripUnconfigured {
+            sess: ecx.sess,
+            features: ecx.ecfg.features,
+            config_tokens: true,
+        },
     };
-    let mut annotatable = visitor.configure_annotatable(annotatable);
-    if visitor.cfg.modified {
-        // Erase the tokens if cfg-stripping modified the item
-        // This will cause us to synthesize fake tokens
-        // when `nt_to_tokenstream` is called on this item.
-        if let Some(tokens) = annotatable.tokens_mut() {
-            *tokens = None;
+    let annotatable = visitor.configure_annotatable(annotatable);
+    vec![annotatable]
+}
+
+struct CfgEval<'a, 'b> {
+    cfg: &'a mut StripUnconfigured<'b>,
+}
+
+fn flat_map_annotatable(vis: &mut impl MutVisitor, annotatable: Annotatable) -> Annotatable {
+    // Since the item itself has already been configured by the InvocationCollector,
+    // we know that fold result vector will contain exactly one element
+    match annotatable {
+        Annotatable::Item(item) => Annotatable::Item(vis.flat_map_item(item).pop().unwrap()),
+        Annotatable::TraitItem(item) => {
+            Annotatable::TraitItem(vis.flat_map_trait_item(item).pop().unwrap())
+        }
+        Annotatable::ImplItem(item) => {
+            Annotatable::ImplItem(vis.flat_map_impl_item(item).pop().unwrap())
+        }
+        Annotatable::ForeignItem(item) => {
+            Annotatable::ForeignItem(vis.flat_map_foreign_item(item).pop().unwrap())
         }
+        Annotatable::Stmt(stmt) => {
+            Annotatable::Stmt(stmt.map(|stmt| vis.flat_map_stmt(stmt).pop().unwrap()))
+        }
+        Annotatable::Expr(mut expr) => Annotatable::Expr({
+            vis.visit_expr(&mut expr);
+            expr
+        }),
+        Annotatable::Arm(arm) => Annotatable::Arm(vis.flat_map_arm(arm).pop().unwrap()),
+        Annotatable::ExprField(field) => {
+            Annotatable::ExprField(vis.flat_map_expr_field(field).pop().unwrap())
+        }
+        Annotatable::PatField(fp) => {
+            Annotatable::PatField(vis.flat_map_pat_field(fp).pop().unwrap())
+        }
+        Annotatable::GenericParam(param) => {
+            Annotatable::GenericParam(vis.flat_map_generic_param(param).pop().unwrap())
+        }
+        Annotatable::Param(param) => Annotatable::Param(vis.flat_map_param(param).pop().unwrap()),
+        Annotatable::FieldDef(sf) => {
+            Annotatable::FieldDef(vis.flat_map_field_def(sf).pop().unwrap())
+        }
+        Annotatable::Variant(v) => Annotatable::Variant(vis.flat_map_variant(v).pop().unwrap()),
+    }
+}
+
+struct CfgFinder {
+    has_cfg_or_cfg_attr: bool,
+}
+
+impl CfgFinder {
+    fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool {
+        let mut finder = CfgFinder { has_cfg_or_cfg_attr: false };
+        match annotatable {
+            Annotatable::Item(item) => finder.visit_item(&item),
+            Annotatable::TraitItem(item) => finder.visit_assoc_item(&item, visit::AssocCtxt::Trait),
+            Annotatable::ImplItem(item) => finder.visit_assoc_item(&item, visit::AssocCtxt::Impl),
+            Annotatable::ForeignItem(item) => finder.visit_foreign_item(&item),
+            Annotatable::Stmt(stmt) => finder.visit_stmt(&stmt),
+            Annotatable::Expr(expr) => finder.visit_expr(&expr),
+            Annotatable::Arm(arm) => finder.visit_arm(&arm),
+            Annotatable::ExprField(field) => finder.visit_expr_field(&field),
+            Annotatable::PatField(field) => finder.visit_pat_field(&field),
+            Annotatable::GenericParam(param) => finder.visit_generic_param(&param),
+            Annotatable::Param(param) => finder.visit_param(&param),
+            Annotatable::FieldDef(field) => finder.visit_field_def(&field),
+            Annotatable::Variant(variant) => finder.visit_variant(&variant),
+        };
+        finder.has_cfg_or_cfg_attr
     }
-    vec![annotatable]
 }
 
-struct CfgEval<'a> {
-    cfg: StripUnconfigured<'a>,
+impl<'ast> visit::Visitor<'ast> for CfgFinder {
+    fn visit_attribute(&mut self, attr: &'ast Attribute) {
+        // We want short-circuiting behavior, so don't use the '|=' operator.
+        self.has_cfg_or_cfg_attr = self.has_cfg_or_cfg_attr
+            || attr
+                .ident()
+                .map_or(false, |ident| ident.name == sym::cfg || ident.name == sym::cfg_attr);
+    }
 }
 
-impl CfgEval<'_> {
+impl CfgEval<'_, '_> {
     fn configure<T: AstLike>(&mut self, node: T) -> Option<T> {
         self.cfg.configure(node)
     }
 
-    fn configure_annotatable(&mut self, annotatable: Annotatable) -> Annotatable {
-        // Since the item itself has already been configured by the InvocationCollector,
-        // we know that fold result vector will contain exactly one element
-        match annotatable {
-            Annotatable::Item(item) => Annotatable::Item(self.flat_map_item(item).pop().unwrap()),
-            Annotatable::TraitItem(item) => {
-                Annotatable::TraitItem(self.flat_map_trait_item(item).pop().unwrap())
-            }
-            Annotatable::ImplItem(item) => {
-                Annotatable::ImplItem(self.flat_map_impl_item(item).pop().unwrap())
-            }
-            Annotatable::ForeignItem(item) => {
-                Annotatable::ForeignItem(self.flat_map_foreign_item(item).pop().unwrap())
-            }
-            Annotatable::Stmt(stmt) => {
-                Annotatable::Stmt(stmt.map(|stmt| self.flat_map_stmt(stmt).pop().unwrap()))
-            }
-            Annotatable::Expr(mut expr) => Annotatable::Expr({
-                self.visit_expr(&mut expr);
-                expr
-            }),
-            Annotatable::Arm(arm) => Annotatable::Arm(self.flat_map_arm(arm).pop().unwrap()),
-            Annotatable::ExprField(field) => {
-                Annotatable::ExprField(self.flat_map_expr_field(field).pop().unwrap())
-            }
-            Annotatable::PatField(fp) => {
-                Annotatable::PatField(self.flat_map_pat_field(fp).pop().unwrap())
-            }
-            Annotatable::GenericParam(param) => {
-                Annotatable::GenericParam(self.flat_map_generic_param(param).pop().unwrap())
-            }
-            Annotatable::Param(param) => {
-                Annotatable::Param(self.flat_map_param(param).pop().unwrap())
-            }
-            Annotatable::FieldDef(sf) => {
-                Annotatable::FieldDef(self.flat_map_field_def(sf).pop().unwrap())
+    pub fn configure_annotatable(&mut self, mut annotatable: Annotatable) -> Annotatable {
+        // Tokenizing and re-parsing the `Annotatable` can have a significant
+        // performance impact, so try to avoid it if possible
+        if !CfgFinder::has_cfg_or_cfg_attr(&annotatable) {
+            return annotatable;
+        }
+
+        // The majority of parsed attribute targets will never need to have early cfg-expansion
+        // run (e.g. they are not part of a `#[derive]` or `#[cfg_eval]` macro inoput).
+        // Therefore, we normally do not capture the necessary information about `#[cfg]`
+        // and `#[cfg_attr]` attributes during parsing.
+        //
+        // Therefore, when we actually *do* run early cfg-expansion, we need to tokenize
+        // and re-parse the attribute target, this time capturing information about
+        // the location of `#[cfg]` and `#[cfg_attr]` in the token stream. The tokenization
+        // process is lossless, so this process is invisible to proc-macros.
+
+        // FIXME - get rid of this clone
+        let nt = annotatable.clone().into_nonterminal();
+
+        let mut orig_tokens = rustc_parse::nt_to_tokenstream(
+            &nt,
+            &self.cfg.sess.parse_sess,
+            CanSynthesizeMissingTokens::No,
+        );
+
+        // 'Flatten' all nonterminals (i.e. `TokenKind::Interpolated`)
+        // to `None`-delimited groups containing the corresponding tokens. This
+        // is normally delayed until the proc-macro server actually needs to
+        // provide a `TokenKind::Interpolated` to a proc-macro. We do this earlier,
+        // so that we can handle cases like:
+        //
+        // ```rust
+        // #[cfg_eval] #[cfg] $item
+        //```
+        //
+        // where `$item` is `#[cfg_attr] struct Foo {}`. We want to make
+        // sure to evaluate *all* `#[cfg]` and `#[cfg_attr]` attributes - the simplest
+        // way to do this is to do a single parse of a stream without any nonterminals.
+        let mut flatten = FlattenNonterminals {
+            nt_to_tokenstream: rustc_parse::nt_to_tokenstream,
+            parse_sess: &self.cfg.sess.parse_sess,
+            synthesize_tokens: CanSynthesizeMissingTokens::No,
+        };
+        orig_tokens = flatten.process_token_stream(orig_tokens);
+
+        // Re-parse the tokens, setting the `capture_cfg` flag to save extra information
+        // to the captured `AttrAnnotatedTokenStream` (specifically, we capture
+        // `AttrAnnotatedTokenTree::AttributesData` for all occurences of `#[cfg]` and `#[cfg_attr]`)
+        let mut parser =
+            rustc_parse::stream_to_parser(&self.cfg.sess.parse_sess, orig_tokens, None);
+        parser.capture_cfg = true;
+        annotatable = match annotatable {
+            Annotatable::Item(_) => {
+                Annotatable::Item(parser.parse_item(ForceCollect::Yes).unwrap().unwrap())
             }
-            Annotatable::Variant(v) => {
-                Annotatable::Variant(self.flat_map_variant(v).pop().unwrap())
+            Annotatable::TraitItem(_) => Annotatable::TraitItem(
+                parser.parse_trait_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
+            ),
+            Annotatable::ImplItem(_) => Annotatable::ImplItem(
+                parser.parse_impl_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
+            ),
+            Annotatable::ForeignItem(_) => Annotatable::ForeignItem(
+                parser.parse_foreign_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
+            ),
+            Annotatable::Stmt(_) => {
+                Annotatable::Stmt(P(parser.parse_stmt(ForceCollect::Yes).unwrap().unwrap()))
             }
-        }
+            Annotatable::Expr(_) => Annotatable::Expr(parser.parse_expr_force_collect().unwrap()),
+            _ => unreachable!(),
+        };
+
+        // Now that we have our re-parsed `AttrAnnotatedTokenStream`, recursively configuring
+        // our attribute target will correctly the tokens as well.
+        flat_map_annotatable(self, annotatable)
     }
 }
 
-impl MutVisitor for CfgEval<'_> {
+impl MutVisitor for CfgEval<'_, '_> {
     fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
         self.cfg.configure_expr(expr);
         mut_visit::noop_visit_expr(expr, self);
diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs
index 4d2551a061b..9053d1aa1b0 100644
--- a/compiler/rustc_codegen_cranelift/src/vtable.rs
+++ b/compiler/rustc_codegen_cranelift/src/vtable.rs
@@ -1,6 +1,6 @@
 //! Codegen vtables and vtable accesses.
 //!
-//! See librustc_codegen_llvm/meth.rs for reference
+//! See `rustc_codegen_ssa/src/meth.rs` for reference.
 // FIXME dedup this logic between miri, cg_llvm and cg_clif
 
 use crate::prelude::*;
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index e06c1c825f6..9e5e2b1039e 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -13,6 +13,7 @@ use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::config::OptLevel;
 use rustc_session::Session;
+use rustc_target::spec::abi::Abi;
 use rustc_target::spec::{SanitizerSet, StackProbeType};
 
 use crate::attributes;
@@ -293,7 +294,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
     // The target doesn't care; the subtarget reads our attribute.
     apply_tune_cpu_attr(cx, llfn);
 
-    let function_features = codegen_fn_attrs
+    let mut function_features = codegen_fn_attrs
         .target_features
         .iter()
         .map(|f| {
@@ -305,23 +306,10 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
             InstructionSetAttr::ArmT32 => "+thumb-mode".to_string(),
         }))
         .collect::<Vec<String>>();
-    if !function_features.is_empty() {
-        let mut global_features = llvm_util::llvm_global_features(cx.tcx.sess);
-        global_features.extend(function_features.into_iter());
-        let features = global_features.join(",");
-        let val = CString::new(features).unwrap();
-        llvm::AddFunctionAttrStringValue(
-            llfn,
-            llvm::AttributePlace::Function,
-            cstr!("target-features"),
-            &val,
-        );
-    }
 
-    // Note that currently the `wasm-import-module` doesn't do anything, but
-    // eventually LLVM 7 should read this and ferry the appropriate import
-    // module to the output file.
     if cx.tcx.sess.target.is_like_wasm {
+        // If this function is an import from the environment but the wasm
+        // import has a specific module/name, apply them here.
         if let Some(module) = wasm_import_module(cx.tcx, instance.def_id()) {
             llvm::AddFunctionAttrStringValue(
                 llfn,
@@ -340,6 +328,30 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
                 &name,
             );
         }
+
+        // The `"wasm"` abi on wasm targets automatically enables the
+        // `+multivalue` feature because the purpose of the wasm abi is to match
+        // the WebAssembly specification, which has this feature. This won't be
+        // needed when LLVM enables this `multivalue` feature by default.
+        if !cx.tcx.is_closure(instance.def_id()) {
+            let abi = cx.tcx.fn_sig(instance.def_id()).abi();
+            if abi == Abi::Wasm {
+                function_features.push("+multivalue".to_string());
+            }
+        }
+    }
+
+    if !function_features.is_empty() {
+        let mut global_features = llvm_util::llvm_global_features(cx.tcx.sess);
+        global_features.extend(function_features.into_iter());
+        let features = global_features.join(",");
+        let val = CString::new(features).unwrap();
+        llvm::AddFunctionAttrStringValue(
+            llfn,
+            llvm::AttributePlace::Function,
+            cstr!("target-features"),
+            &val,
+        );
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 70f78c07c65..54a8249b175 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -2128,7 +2128,13 @@ extern "C" {
     pub fn LLVMRustHasFeature(T: &TargetMachine, s: *const c_char) -> bool;
 
     pub fn LLVMRustPrintTargetCPUs(T: &TargetMachine);
-    pub fn LLVMRustPrintTargetFeatures(T: &TargetMachine);
+    pub fn LLVMRustGetTargetFeaturesCount(T: &TargetMachine) -> size_t;
+    pub fn LLVMRustGetTargetFeature(
+        T: &TargetMachine,
+        Index: size_t,
+        Feature: &mut *const c_char,
+        Desc: &mut *const c_char,
+    );
 
     pub fn LLVMRustGetHostCPUName(len: *mut usize) -> *const c_char;
     pub fn LLVMRustCreateTargetMachine(
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index e80de2bc902..b44553e4f6d 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -10,6 +10,7 @@ use rustc_span::symbol::Symbol;
 use rustc_target::spec::{MergeFunctions, PanicStrategy};
 use std::ffi::{CStr, CString};
 
+use std::ptr;
 use std::slice;
 use std::str;
 use std::sync::atomic::{AtomicBool, Ordering};
@@ -192,15 +193,77 @@ pub fn print_passes() {
     }
 }
 
+fn llvm_target_features(tm: &llvm::TargetMachine) -> Vec<(&str, &str)> {
+    let len = unsafe { llvm::LLVMRustGetTargetFeaturesCount(tm) };
+    let mut ret = Vec::with_capacity(len);
+    for i in 0..len {
+        unsafe {
+            let mut feature = ptr::null();
+            let mut desc = ptr::null();
+            llvm::LLVMRustGetTargetFeature(tm, i, &mut feature, &mut desc);
+            if feature.is_null() || desc.is_null() {
+                bug!("LLVM returned a `null` target feature string");
+            }
+            let feature = CStr::from_ptr(feature).to_str().unwrap_or_else(|e| {
+                bug!("LLVM returned a non-utf8 feature string: {}", e);
+            });
+            let desc = CStr::from_ptr(desc).to_str().unwrap_or_else(|e| {
+                bug!("LLVM returned a non-utf8 feature string: {}", e);
+            });
+            ret.push((feature, desc));
+        }
+    }
+    ret
+}
+
+fn print_target_features(sess: &Session, tm: &llvm::TargetMachine) {
+    let mut target_features = llvm_target_features(tm);
+    let mut rustc_target_features = supported_target_features(sess)
+        .iter()
+        .filter_map(|(feature, _gate)| {
+            let llvm_feature = to_llvm_feature(sess, *feature);
+            // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings.
+            target_features.binary_search_by_key(&llvm_feature, |(f, _d)| *f).ok().map(|index| {
+                let (_f, desc) = target_features.remove(index);
+                (*feature, desc)
+            })
+        })
+        .collect::<Vec<_>>();
+    rustc_target_features.extend_from_slice(&[(
+        "crt-static",
+        "Enables C Run-time Libraries to be statically linked",
+    )]);
+    let max_feature_len = target_features
+        .iter()
+        .chain(rustc_target_features.iter())
+        .map(|(feature, _desc)| feature.len())
+        .max()
+        .unwrap_or(0);
+
+    println!("Features supported by rustc for this target:");
+    for (feature, desc) in &rustc_target_features {
+        println!("    {1:0$} - {2}.", max_feature_len, feature, desc);
+    }
+    println!("\nCode-generation features supported by LLVM for this target:");
+    for (feature, desc) in &target_features {
+        println!("    {1:0$} - {2}.", max_feature_len, feature, desc);
+    }
+    if target_features.len() == 0 {
+        println!("    Target features listing is not supported by this LLVM version.");
+    }
+    println!("\nUse +feature to enable a feature, or -feature to disable it.");
+    println!("For example, rustc -C target-cpu=mycpu -C target-feature=+feature1,-feature2\n");
+    println!("Code-generation features cannot be used in cfg or #[target_feature],");
+    println!("and may be renamed or removed in a future version of LLVM or rustc.\n");
+}
+
 pub(crate) fn print(req: PrintRequest, sess: &Session) {
     require_inited();
     let tm = create_informational_target_machine(sess);
-    unsafe {
-        match req {
-            PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
-            PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
-            _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
-        }
+    match req {
+        PrintRequest::TargetCPUs => unsafe { llvm::LLVMRustPrintTargetCPUs(tm) },
+        PrintRequest::TargetFeatures => print_target_features(sess, tm),
+        _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
     }
 }
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index a3f20abc82d..6bb20545f07 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -6,7 +6,7 @@ use rustc_middle::ty;
 use rustc_session::config::DebugInfo;
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::{BytePos, Span};
-use rustc_target::abi::{LayoutOf, Size};
+use rustc_target::abi::Size;
 
 use super::operand::{OperandRef, OperandValue};
 use super::place::PlaceRef;
@@ -265,33 +265,25 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 None => continue,
             };
 
-            let mut layout = base.layout;
             let mut direct_offset = Size::ZERO;
             // FIXME(eddyb) use smallvec here.
             let mut indirect_offsets = vec![];
+            let mut place = base;
 
             for elem in &var.projection[..] {
                 match *elem {
                     mir::ProjectionElem::Deref => {
                         indirect_offsets.push(Size::ZERO);
-                        layout = bx.cx().layout_of(
-                            layout
-                                .ty
-                                .builtin_deref(true)
-                                .unwrap_or_else(|| {
-                                    span_bug!(var.source_info.span, "cannot deref `{}`", layout.ty)
-                                })
-                                .ty,
-                        );
+                        place = place.project_deref(bx);
                     }
                     mir::ProjectionElem::Field(field, _) => {
                         let i = field.index();
                         let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset);
-                        *offset += layout.fields.offset(i);
-                        layout = layout.field(bx.cx(), i);
+                        *offset += place.layout.fields.offset(i);
+                        place = place.project_field(bx, i);
                     }
                     mir::ProjectionElem::Downcast(_, variant) => {
-                        layout = layout.for_variant(bx.cx(), variant);
+                        place = place.project_downcast(bx, variant);
                     }
                     _ => span_bug!(
                         var.source_info.span,
@@ -301,7 +293,39 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 }
             }
 
-            bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, direct_offset, &indirect_offsets);
+            // When targeting MSVC, create extra allocas for arguments instead of pointing multiple
+            // dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records
+            // not DWARF and LLVM doesn't support translating the resulting
+            // [DW_OP_deref, DW_OP_plus_uconst, offset, DW_OP_deref] debug info to CodeView.
+            // Creating extra allocas on the stack makes the resulting debug info simple enough
+            // that LLVM can generate correct CodeView records and thus the values appear in the
+            // debugger. (#83709)
+            let should_create_individual_allocas = bx.cx().sess().target.is_like_msvc
+                && self.mir.local_kind(local) == mir::LocalKind::Arg
+                // LLVM can handle simple things but anything more complex than just a direct
+                // offset or one indirect offset of 0 is too complex for it to generate CV records
+                // correctly.
+                && (direct_offset != Size::ZERO
+                    || !matches!(&indirect_offsets[..], [Size::ZERO] | []));
+
+            if should_create_individual_allocas {
+                // Create a variable which will be a pointer to the actual value
+                let ptr_ty = bx.tcx().mk_ty(ty::RawPtr(ty::TypeAndMut {
+                    mutbl: mir::Mutability::Mut,
+                    ty: place.layout.ty,
+                }));
+                let ptr_layout = bx.layout_of(ptr_ty);
+                let alloca = PlaceRef::alloca(bx, ptr_layout);
+                bx.set_var_name(alloca.llval, &(var.name.to_string() + ".dbg.spill"));
+
+                // Write the pointer to the variable
+                bx.store(place.llval, alloca.llval, alloca.align);
+
+                // Point the debug info to `*alloca` for the current variable
+                bx.dbg_var_addr(dbg_var, dbg_loc, alloca.llval, Size::ZERO, &[Size::ZERO]);
+            } else {
+                bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, direct_offset, &indirect_offsets);
+            }
         }
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 66d9d1a1e0c..a9e7ebf6d43 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -402,6 +402,18 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
         downcast
     }
 
+    pub fn project_deref<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) -> Self {
+        let target_ty = self.layout.ty.builtin_deref(true).expect("failed to deref");
+        let layout = bx.layout_of(target_ty.ty);
+
+        PlaceRef {
+            llval: bx.load(self.llval, self.align),
+            llextra: None,
+            layout,
+            align: layout.align.abi,
+        }
+    }
+
     pub fn storage_live<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) {
         bx.lifetime_start(self.llval, self.layout.size);
     }
diff --git a/compiler/rustc_data_structures/src/svh.rs b/compiler/rustc_data_structures/src/svh.rs
index 02103de2e8d..ce90fbacaa4 100644
--- a/compiler/rustc_data_structures/src/svh.rs
+++ b/compiler/rustc_data_structures/src/svh.rs
@@ -19,7 +19,7 @@ pub struct Svh {
 impl Svh {
     /// Creates a new `Svh` given the hash. If you actually want to
     /// compute the SVH from some HIR, you want the `calculate_svh`
-    /// function found in `librustc_incremental`.
+    /// function found in `rustc_incremental`.
     pub fn new(hash: u64) -> Svh {
         Svh { hash }
     }
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index a2035ee3c6e..59505842816 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -3,7 +3,7 @@ use crate::module::DirOwnership;
 
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Nonterminal};
-use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, LazyTokenStream, TokenStream};
+use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream};
 use rustc_ast::visit::{AssocCtxt, Visitor};
 use rustc_ast::{self as ast, AstLike, Attribute, Item, NodeId, PatKind};
 use rustc_attr::{self as attr, Deprecation, Stability};
@@ -46,26 +46,26 @@ pub enum Annotatable {
     Variant(ast::Variant),
 }
 
-impl AstLike for Annotatable {
-    fn attrs(&self) -> &[Attribute] {
+impl Annotatable {
+    pub fn span(&self) -> Span {
         match *self {
-            Annotatable::Item(ref item) => &item.attrs,
-            Annotatable::TraitItem(ref trait_item) => &trait_item.attrs,
-            Annotatable::ImplItem(ref impl_item) => &impl_item.attrs,
-            Annotatable::ForeignItem(ref foreign_item) => &foreign_item.attrs,
-            Annotatable::Stmt(ref stmt) => stmt.attrs(),
-            Annotatable::Expr(ref expr) => &expr.attrs,
-            Annotatable::Arm(ref arm) => &arm.attrs,
-            Annotatable::ExprField(ref field) => &field.attrs,
-            Annotatable::PatField(ref fp) => &fp.attrs,
-            Annotatable::GenericParam(ref gp) => &gp.attrs,
-            Annotatable::Param(ref p) => &p.attrs,
-            Annotatable::FieldDef(ref sf) => &sf.attrs,
-            Annotatable::Variant(ref v) => &v.attrs(),
+            Annotatable::Item(ref item) => item.span,
+            Annotatable::TraitItem(ref trait_item) => trait_item.span,
+            Annotatable::ImplItem(ref impl_item) => impl_item.span,
+            Annotatable::ForeignItem(ref foreign_item) => foreign_item.span,
+            Annotatable::Stmt(ref stmt) => stmt.span,
+            Annotatable::Expr(ref expr) => expr.span,
+            Annotatable::Arm(ref arm) => arm.span,
+            Annotatable::ExprField(ref field) => field.span,
+            Annotatable::PatField(ref fp) => fp.pat.span,
+            Annotatable::GenericParam(ref gp) => gp.ident.span,
+            Annotatable::Param(ref p) => p.span,
+            Annotatable::FieldDef(ref sf) => sf.span,
+            Annotatable::Variant(ref v) => v.span,
         }
     }
 
-    fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
+    pub fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
         match self {
             Annotatable::Item(item) => item.visit_attrs(f),
             Annotatable::TraitItem(trait_item) => trait_item.visit_attrs(f),
@@ -83,44 +83,6 @@ impl AstLike for Annotatable {
         }
     }
 
-    fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
-        match self {
-            Annotatable::Item(item) => item.tokens_mut(),
-            Annotatable::TraitItem(trait_item) => trait_item.tokens_mut(),
-            Annotatable::ImplItem(impl_item) => impl_item.tokens_mut(),
-            Annotatable::ForeignItem(foreign_item) => foreign_item.tokens_mut(),
-            Annotatable::Stmt(stmt) => stmt.tokens_mut(),
-            Annotatable::Expr(expr) => expr.tokens_mut(),
-            Annotatable::Arm(arm) => arm.tokens_mut(),
-            Annotatable::ExprField(field) => field.tokens_mut(),
-            Annotatable::PatField(fp) => fp.tokens_mut(),
-            Annotatable::GenericParam(gp) => gp.tokens_mut(),
-            Annotatable::Param(p) => p.tokens_mut(),
-            Annotatable::FieldDef(sf) => sf.tokens_mut(),
-            Annotatable::Variant(v) => v.tokens_mut(),
-        }
-    }
-}
-
-impl Annotatable {
-    pub fn span(&self) -> Span {
-        match *self {
-            Annotatable::Item(ref item) => item.span,
-            Annotatable::TraitItem(ref trait_item) => trait_item.span,
-            Annotatable::ImplItem(ref impl_item) => impl_item.span,
-            Annotatable::ForeignItem(ref foreign_item) => foreign_item.span,
-            Annotatable::Stmt(ref stmt) => stmt.span,
-            Annotatable::Expr(ref expr) => expr.span,
-            Annotatable::Arm(ref arm) => arm.span,
-            Annotatable::ExprField(ref field) => field.span,
-            Annotatable::PatField(ref fp) => fp.pat.span,
-            Annotatable::GenericParam(ref gp) => gp.ident.span,
-            Annotatable::Param(ref p) => p.span,
-            Annotatable::FieldDef(ref sf) => sf.span,
-            Annotatable::Variant(ref v) => v.span,
-        }
-    }
-
     pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) {
         match self {
             Annotatable::Item(item) => visitor.visit_item(item),
@@ -139,7 +101,7 @@ impl Annotatable {
         }
     }
 
-    crate fn into_nonterminal(self) -> Nonterminal {
+    pub fn into_nonterminal(self) -> Nonterminal {
         match self {
             Annotatable::Item(item) => token::NtItem(item),
             Annotatable::TraitItem(item) | Annotatable::ImplItem(item) => {
@@ -161,10 +123,7 @@ impl Annotatable {
     }
 
     crate fn into_tokens(self, sess: &ParseSess) -> TokenStream {
-        // Tokens of an attribute target may be invalidated by some outer `#[derive]` performing
-        // "full configuration" (attributes following derives on the same item should be the most
-        // common case), that's why synthesizing tokens is allowed.
-        nt_to_tokenstream(&self.into_nonterminal(), sess, CanSynthesizeMissingTokens::Yes)
+        nt_to_tokenstream(&self.into_nonterminal(), sess, CanSynthesizeMissingTokens::No)
     }
 
     pub fn expect_item(self) -> P<ast::Item> {
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index a23731cf309..03c83f9c07b 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -2,8 +2,10 @@
 
 use rustc_ast::ptr::P;
 use rustc_ast::token::{DelimToken, Token, TokenKind};
-use rustc_ast::tokenstream::{DelimSpan, LazyTokenStream, Spacing, TokenStream, TokenTree};
-use rustc_ast::{self as ast, AstLike, AttrItem, Attribute, MetaItem};
+use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree};
+use rustc_ast::tokenstream::{DelimSpan, Spacing};
+use rustc_ast::tokenstream::{LazyTokenStream, TokenTree};
+use rustc_ast::{self as ast, AstLike, AttrItem, AttrStyle, Attribute, MetaItem};
 use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::map_in_place::MapInPlace;
@@ -23,7 +25,10 @@ use rustc_span::{Span, DUMMY_SP};
 pub struct StripUnconfigured<'a> {
     pub sess: &'a Session,
     pub features: Option<&'a Features>,
-    pub modified: bool,
+    /// If `true`, perform cfg-stripping on attached tokens.
+    /// This is only used for the input to derive macros,
+    /// which needs eager expansion of `cfg` and `cfg_attr`
+    pub config_tokens: bool,
 }
 
 fn get_features(
@@ -194,7 +199,7 @@ fn get_features(
 
 // `cfg_attr`-process the crate's attributes and compute the crate's features.
 pub fn features(sess: &Session, mut krate: ast::Crate) -> (ast::Crate, Features) {
-    let mut strip_unconfigured = StripUnconfigured { sess, features: None, modified: false };
+    let mut strip_unconfigured = StripUnconfigured { sess, features: None, config_tokens: false };
 
     let unconfigured_attrs = krate.attrs.clone();
     let diag = &sess.parse_sess.span_diagnostic;
@@ -241,24 +246,83 @@ impl<'a> StripUnconfigured<'a> {
     pub fn configure<T: AstLike>(&mut self, mut node: T) -> Option<T> {
         self.process_cfg_attrs(&mut node);
         if self.in_cfg(node.attrs()) {
+            self.try_configure_tokens(&mut node);
             Some(node)
         } else {
-            self.modified = true;
             None
         }
     }
 
+    fn try_configure_tokens<T: AstLike>(&mut self, node: &mut T) {
+        if self.config_tokens {
+            if let Some(Some(tokens)) = node.tokens_mut() {
+                let attr_annotated_tokens = tokens.create_token_stream();
+                *tokens = LazyTokenStream::new(self.configure_tokens(&attr_annotated_tokens));
+            }
+        }
+    }
+
     fn configure_krate_attrs(
         &mut self,
         mut attrs: Vec<ast::Attribute>,
     ) -> Option<Vec<ast::Attribute>> {
         attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
-        if self.in_cfg(&attrs) {
-            Some(attrs)
-        } else {
-            self.modified = true;
-            None
+        if self.in_cfg(&attrs) { Some(attrs) } else { None }
+    }
+
+    /// Performs cfg-expansion on `stream`, producing a new `AttrAnnotatedTokenStream`.
+    /// This is only used during the invocation of `derive` proc-macros,
+    /// which require that we cfg-expand their entire input.
+    /// Normal cfg-expansion operates on parsed AST nodes via the `configure` method
+    fn configure_tokens(&mut self, stream: &AttrAnnotatedTokenStream) -> AttrAnnotatedTokenStream {
+        fn can_skip(stream: &AttrAnnotatedTokenStream) -> bool {
+            stream.0.iter().all(|(tree, _spacing)| match tree {
+                AttrAnnotatedTokenTree::Attributes(_) => false,
+                AttrAnnotatedTokenTree::Token(_) => true,
+                AttrAnnotatedTokenTree::Delimited(_, _, inner) => can_skip(inner),
+            })
+        }
+
+        if can_skip(stream) {
+            return stream.clone();
         }
+
+        let trees: Vec<_> = stream
+            .0
+            .iter()
+            .flat_map(|(tree, spacing)| match tree.clone() {
+                AttrAnnotatedTokenTree::Attributes(mut data) => {
+                    let mut attrs: Vec<_> = std::mem::take(&mut data.attrs).into();
+                    attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
+                    data.attrs = attrs.into();
+
+                    if self.in_cfg(&data.attrs) {
+                        data.tokens = LazyTokenStream::new(
+                            self.configure_tokens(&data.tokens.create_token_stream()),
+                        );
+                        Some((AttrAnnotatedTokenTree::Attributes(data), *spacing)).into_iter()
+                    } else {
+                        None.into_iter()
+                    }
+                }
+                AttrAnnotatedTokenTree::Delimited(sp, delim, mut inner) => {
+                    inner = self.configure_tokens(&inner);
+                    Some((AttrAnnotatedTokenTree::Delimited(sp, delim, inner), *spacing))
+                        .into_iter()
+                }
+                AttrAnnotatedTokenTree::Token(token) => {
+                    if let TokenKind::Interpolated(nt) = token.kind {
+                        panic!(
+                            "Nonterminal should have been flattened at {:?}: {:?}",
+                            token.span, nt
+                        );
+                    } else {
+                        Some((AttrAnnotatedTokenTree::Token(token), *spacing)).into_iter()
+                    }
+                }
+            })
+            .collect();
+        AttrAnnotatedTokenStream::new(trees)
     }
 
     /// Parse and expand all `cfg_attr` attributes into a list of attributes
@@ -285,9 +349,6 @@ impl<'a> StripUnconfigured<'a> {
             return vec![attr];
         }
 
-        // A `#[cfg_attr]` either gets removed, or replaced with a new attribute
-        self.modified = true;
-
         let (cfg_predicate, expanded_attrs) = match self.parse_cfg_attr(&attr) {
             None => return vec![],
             Some(r) => r,
@@ -311,7 +372,7 @@ impl<'a> StripUnconfigured<'a> {
         expanded_attrs
             .into_iter()
             .flat_map(|(item, span)| {
-                let orig_tokens = attr.tokens();
+                let orig_tokens = attr.tokens().to_tokenstream();
 
                 // We are taking an attribute of the form `#[cfg_attr(pred, attr)]`
                 // and producing an attribute of the form `#[attr]`. We
@@ -321,25 +382,34 @@ impl<'a> StripUnconfigured<'a> {
 
                 // Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token
                 // for `attr` when we expand it to `#[attr]`
-                let pound_token = orig_tokens.trees().next().unwrap();
-                if !matches!(pound_token, TokenTree::Token(Token { kind: TokenKind::Pound, .. })) {
-                    panic!("Bad tokens for attribute {:?}", attr);
+                let mut orig_trees = orig_tokens.trees();
+                let pound_token = match orig_trees.next().unwrap() {
+                    TokenTree::Token(token @ Token { kind: TokenKind::Pound, .. }) => token,
+                    _ => panic!("Bad tokens for attribute {:?}", attr),
+                };
+                let pound_span = pound_token.span;
+
+                let mut trees = vec![(AttrAnnotatedTokenTree::Token(pound_token), Spacing::Alone)];
+                if attr.style == AttrStyle::Inner {
+                    // For inner attributes, we do the same thing for the `!` in `#![some_attr]`
+                    let bang_token = match orig_trees.next().unwrap() {
+                        TokenTree::Token(token @ Token { kind: TokenKind::Not, .. }) => token,
+                        _ => panic!("Bad tokens for attribute {:?}", attr),
+                    };
+                    trees.push((AttrAnnotatedTokenTree::Token(bang_token), Spacing::Alone));
                 }
                 // We don't really have a good span to use for the syntheized `[]`
                 // in `#[attr]`, so just use the span of the `#` token.
-                let bracket_group = TokenTree::Delimited(
-                    DelimSpan::from_single(pound_token.span()),
+                let bracket_group = AttrAnnotatedTokenTree::Delimited(
+                    DelimSpan::from_single(pound_span),
                     DelimToken::Bracket,
                     item.tokens
                         .as_ref()
                         .unwrap_or_else(|| panic!("Missing tokens for {:?}", item))
                         .create_token_stream(),
                 );
-                let tokens = Some(LazyTokenStream::new(TokenStream::new(vec![
-                    (pound_token, Spacing::Alone),
-                    (bracket_group, Spacing::Alone),
-                ])));
-
+                trees.push((bracket_group, Spacing::Alone));
+                let tokens = Some(LazyTokenStream::new(AttrAnnotatedTokenStream::new(trees)));
                 self.process_cfg_attr(attr::mk_attr_from_item(item, tokens, attr.style, span))
             })
             .collect()
@@ -457,7 +527,8 @@ impl<'a> StripUnconfigured<'a> {
             self.sess.parse_sess.span_diagnostic.span_err(attr.span, msg);
         }
 
-        self.process_cfg_attrs(expr)
+        self.process_cfg_attrs(expr);
+        self.try_configure_tokens(&mut *expr);
     }
 }
 
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 0f4441d020b..529ef7e4611 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -12,7 +12,7 @@ use rustc_ast::ptr::P;
 use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
-use rustc_ast::{AstLike, AttrItem, AttrStyle, Block, Inline, ItemKind, LitKind, MacArgs};
+use rustc_ast::{AstLike, AttrItem, Block, Inline, ItemKind, LitKind, MacArgs};
 use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem};
 use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe};
 use rustc_ast_pretty::pprust;
@@ -491,6 +491,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             let fragment_kind = invoc.fragment_kind;
             let (expanded_fragment, new_invocations) = match self.expand_invoc(invoc, &ext.kind) {
                 ExpandResult::Ready(fragment) => {
+                    let mut derive_invocations = Vec::new();
                     let derive_placeholders = self
                         .cx
                         .resolver
@@ -512,14 +513,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                                 _ => unreachable!(),
                             };
 
-                            invocations.reserve(derives.len());
+                            derive_invocations.reserve(derives.len());
                             derives
                                 .into_iter()
                                 .map(|(path, _exts)| {
                                     // FIXME: Consider using the derive resolutions (`_exts`)
                                     // instead of enqueuing the derives to be resolved again later.
                                     let expn_id = ExpnId::fresh(None);
-                                    invocations.push((
+                                    derive_invocations.push((
                                         Invocation {
                                             kind: InvocationKind::Derive {
                                                 path,
@@ -546,7 +547,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         })
                         .unwrap_or_default();
 
-                    self.collect_invocations(fragment, &derive_placeholders)
+                    let (fragment, collected_invocations) =
+                        self.collect_invocations(fragment, &derive_placeholders);
+                    // We choose to expand any derive invocations associated with this macro invocation
+                    // *before* any macro invocations collected from the output fragment
+                    derive_invocations.extend(collected_invocations);
+                    (fragment, derive_invocations)
                 }
                 ExpandResult::Retry(invoc) => {
                     if force {
@@ -605,10 +611,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
 
         let invocations = {
             let mut collector = InvocationCollector {
+                // Non-derive macro invocations cannot see the results of cfg expansion - they
+                // will either be removed along with the item, or invoked before the cfg/cfg_attr
+                // attribute is expanded. Therefore, we don't need to configure the tokens
+                // Derive macros *can* see the results of cfg-expansion - they are handled
+                // specially in `fully_expand_fragment`
                 cfg: StripUnconfigured {
                     sess: &self.cx.sess,
                     features: self.cx.ecfg.features,
-                    modified: false,
+                    config_tokens: false,
                 },
                 cx: self.cx,
                 invocations: Vec::new(),
@@ -703,13 +714,26 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 SyntaxExtensionKind::Attr(expander) => {
                     self.gate_proc_macro_input(&item);
                     self.gate_proc_macro_attr_item(span, &item);
-                    let tokens = match attr.style {
-                        AttrStyle::Outer => item.into_tokens(&self.cx.sess.parse_sess),
-                        // FIXME: Properly collect tokens for inner attributes
-                        AttrStyle::Inner => rustc_parse::fake_token_stream(
+                    let mut fake_tokens = false;
+                    if let Annotatable::Item(item_inner) = &item {
+                        if let ItemKind::Mod(_, mod_kind) = &item_inner.kind {
+                            // FIXME: Collect tokens and use them instead of generating
+                            // fake ones. These are unstable, so it needs to be
+                            // fixed prior to stabilization
+                            // Fake tokens when we are invoking an inner attribute, and:
+                            fake_tokens = matches!(attr.style, ast::AttrStyle::Inner) &&
+                                // We are invoking an attribute on the crate root, or an outline
+                                // module
+                                (item_inner.ident.name.is_empty() || !matches!(mod_kind, ast::ModKind::Loaded(_, Inline::Yes, _)));
+                        }
+                    }
+                    let tokens = if fake_tokens {
+                        rustc_parse::fake_token_stream(
                             &self.cx.sess.parse_sess,
                             &item.into_nonterminal(),
-                        ),
+                        )
+                    } else {
+                        item.into_tokens(&self.cx.sess.parse_sess)
                     };
                     let attr_item = attr.unwrap_normal_item();
                     if let MacArgs::Eq(..) = attr_item.args {
@@ -891,21 +915,21 @@ pub fn parse_ast_fragment<'a>(
         }
         AstFragmentKind::TraitItems => {
             let mut items = SmallVec::new();
-            while let Some(item) = this.parse_trait_item()? {
+            while let Some(item) = this.parse_trait_item(ForceCollect::No)? {
                 items.extend(item);
             }
             AstFragment::TraitItems(items)
         }
         AstFragmentKind::ImplItems => {
             let mut items = SmallVec::new();
-            while let Some(item) = this.parse_impl_item()? {
+            while let Some(item) = this.parse_impl_item(ForceCollect::No)? {
                 items.extend(item);
             }
             AstFragment::ImplItems(items)
         }
         AstFragmentKind::ForeignItems => {
             let mut items = SmallVec::new();
-            while let Some(item) = this.parse_foreign_item()? {
+            while let Some(item) = this.parse_foreign_item(ForceCollect::No)? {
                 items.extend(item);
             }
             AstFragment::ForeignItems(items)
diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs
index 61b776ff2d2..3f84979ac05 100644
--- a/compiler/rustc_expand/src/proc_macro.rs
+++ b/compiler/rustc_expand/src/proc_macro.rs
@@ -94,7 +94,7 @@ impl MultiItemModifier for ProcMacroDerive {
         {
             TokenTree::token(token::Interpolated(Lrc::new(item)), DUMMY_SP).into()
         } else {
-            nt_to_tokenstream(&item, &ecx.sess.parse_sess, CanSynthesizeMissingTokens::Yes)
+            nt_to_tokenstream(&item, &ecx.sess.parse_sess, CanSynthesizeMissingTokens::No)
         };
 
         let server = proc_macro_server::Rustc::new(ecx);
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 93de4891ec7..1a91eb600a9 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -645,6 +645,9 @@ declare_features! (
     /// Allows using `#[repr(align(...))]` on function items
     (active, fn_align, "1.53.0", Some(82232), None),
 
+    /// Allows `extern "wasm" fn`
+    (active, wasm_abi, "1.53.0", Some(83788), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index 2a7c2a02fba..654d2408580 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -1,7 +1,7 @@
 //! # Feature gates
 //!
 //! This crate declares the set of past and present unstable features in the compiler.
-//! Feature gate checking itself is done in `librustc_ast_passes/feature_gate.rs`
+//! Feature gate checking itself is done in `rustc_ast_passes/src/feature_gate.rs`
 //! at the moment.
 //!
 //! Features are enabled in programs via the crate-level attributes of
diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs
index 55e87663a1e..0232654aaa5 100644
--- a/compiler/rustc_hir/src/stable_hash_impls.rs
+++ b/compiler/rustc_hir/src/stable_hash_impls.rs
@@ -9,7 +9,7 @@ use rustc_span::def_id::{DefPathHash, LocalDefId};
 
 /// Requirements for a `StableHashingContext` to be used in this crate.
 /// This is a hack to allow using the `HashStable_Generic` derive macro
-/// instead of implementing everything in librustc_middle.
+/// instead of implementing everything in `rustc_middle`.
 pub trait HashStableContext:
     rustc_ast::HashStableContext + rustc_target::HashStableContext
 {
diff --git a/compiler/rustc_hir/src/weak_lang_items.rs b/compiler/rustc_hir/src/weak_lang_items.rs
index b8cd15e7f00..58c3065240c 100644
--- a/compiler/rustc_hir/src/weak_lang_items.rs
+++ b/compiler/rustc_hir/src/weak_lang_items.rs
@@ -18,8 +18,8 @@ pub static WEAK_ITEMS_REFS: SyncLazy<StableMap<Symbol, LangItem>> = SyncLazy::ne
     map
 });
 
-/// The `check_name` argument avoids the need for `librustc_hir` to depend on
-/// `librustc_session`.
+/// The `check_name` argument avoids the need for `rustc_hir` to depend on
+/// `rustc_session`.
 pub fn link_name<'a, F>(check_name: F, attrs: &'a [ast::Attribute]) -> Option<Symbol>
 where
     F: Fn(&'a ast::Attribute, Symbol) -> bool
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index d352214b579..25a262d7e48 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -2,7 +2,7 @@
 //!
 //! - **Type inference.** The type inference code can be found in the `infer` module;
 //!   this code handles low-level equality and subtyping operations. The
-//!   type check pass in the compiler is found in the `librustc_typeck` crate.
+//!   type check pass in the compiler is found in the `rustc_typeck` crate.
 //!
 //! For more information about how rustc works, see the [rustc dev guide].
 //!
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index 44fc4db7dc1..b9781581ff7 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -1,13 +1,13 @@
 //! Low-level Rust lexer.
 //!
-//! The idea with `librustc_lexer` is to make a reusable library,
+//! The idea with `rustc_lexer` is to make a reusable library,
 //! by separating out pure lexing and rustc-specific concerns, like spans,
 //! error reporting, and interning.  So, rustc_lexer operates directly on `&str`,
 //! produces simple tokens which are a pair of type-tag and a bit of original text,
 //! and does not report errors, instead storing them as flags on the token.
 //!
 //! Tokens produced by this lexer are not yet ready for parsing the Rust syntax.
-//! For that see [`librustc_parse::lexer`], which converts this basic token stream
+//! For that see [`rustc_parse::lexer`], which converts this basic token stream
 //! into wide tokens used by actual parser.
 //!
 //! The purpose of this crate is to convert raw sources into a labeled sequence
@@ -17,7 +17,7 @@
 //! The main entity of this crate is the [`TokenKind`] enum which represents common
 //! lexeme types.
 //!
-//! [`librustc_parse::lexer`]: ../rustc_parse/lexer/index.html
+//! [`rustc_parse::lexer`]: ../rustc_parse/lexer/index.html
 // We want to be able to build this crate with a stable compiler, so no
 // `#![feature]` attributes should be added.
 
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index b9de144b0eb..0b49e6562f9 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -2280,7 +2280,7 @@ declare_lint! {
 }
 
 declare_lint_pass!(
-    /// Check for used feature gates in `INCOMPLETE_FEATURES` in `librustc_feature/active.rs`.
+    /// Check for used feature gates in `INCOMPLETE_FEATURES` in `rustc_feature/src/active.rs`.
     IncompleteFeatures => [INCOMPLETE_FEATURES]
 );
 
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 863023fa7b5..e0857ad1eb9 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -464,15 +464,16 @@ impl<'s> LintLevelsBuilder<'s> {
                 // we don't warn about the name change.
                 if let CheckLintNameResult::Warning(_, Some(new_name)) = lint_result {
                     // Ignore any errors or warnings that happen because the new name is inaccurate
-                    if let CheckLintNameResult::Ok(ids) =
-                        store.check_lint_name(&new_name, tool_name)
-                    {
+                    // NOTE: `new_name` already includes the tool name, so we don't have to add it again.
+                    if let CheckLintNameResult::Ok(ids) = store.check_lint_name(&new_name, None) {
                         let src =
                             LintLevelSource::Node(Symbol::intern(&new_name), li.span(), reason);
                         for &id in ids {
                             self.check_gated_lint(id, attr.span);
                             self.insert_spec(&mut specs, id, (level, src));
                         }
+                    } else {
+                        panic!("renamed lint does not exist: {}", new_name);
                     }
                 }
             }
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index b8d5b50dcb5..617b2ed970e 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -404,26 +404,21 @@ extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM) {
   printf("\n");
 }
 
-extern "C" void LLVMRustPrintTargetFeatures(LLVMTargetMachineRef TM) {
+extern "C" size_t LLVMRustGetTargetFeaturesCount(LLVMTargetMachineRef TM) {
   const TargetMachine *Target = unwrap(TM);
   const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
   const ArrayRef<SubtargetFeatureKV> FeatTable = MCInfo->getFeatureTable();
-  unsigned MaxFeatLen = getLongestEntryLength(FeatTable);
-
-  printf("Available features for this target:\n");
-  for (auto &Feature : FeatTable)
-    printf("    %-*s - %s.\n", MaxFeatLen, Feature.Key, Feature.Desc);
-  printf("\nRust-specific features:\n");
-  printf("    %-*s - %s.\n",
-    MaxFeatLen,
-    "crt-static",
-    "Enables libraries with C Run-time Libraries(CRT) to be statically linked"
-  );
-  printf("\n");
+  return FeatTable.size();
+}
 
-  printf("Use +feature to enable a feature, or -feature to disable it.\n"
-         "For example, rustc -C -target-cpu=mycpu -C "
-         "target-feature=+feature1,-feature2\n\n");
+extern "C" void LLVMRustGetTargetFeature(LLVMTargetMachineRef TM, size_t Index,
+                                         const char** Feature, const char** Desc) {
+  const TargetMachine *Target = unwrap(TM);
+  const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
+  const ArrayRef<SubtargetFeatureKV> FeatTable = MCInfo->getFeatureTable();
+  const SubtargetFeatureKV Feat = FeatTable[Index];
+  *Feature = Feat.Key;
+  *Desc = Feat.Desc;
 }
 
 #else
@@ -432,9 +427,11 @@ extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef) {
   printf("Target CPU help is not supported by this LLVM version.\n\n");
 }
 
-extern "C" void LLVMRustPrintTargetFeatures(LLVMTargetMachineRef) {
-  printf("Target features help is not supported by this LLVM version.\n\n");
+extern "C" size_t LLVMRustGetTargetFeaturesCount(LLVMTargetMachineRef) {
+  return 0;
 }
+
+extern "C" void LLVMRustGetTargetFeature(LLVMTargetMachineRef, const char**, const char**) {}
 #endif
 
 extern "C" const char* LLVMRustGetHostCPUName(size_t *len) {
diff --git a/compiler/rustc_middle/src/ich/impls_syntax.rs b/compiler/rustc_middle/src/ich/impls_syntax.rs
index 31374429940..b93b25d6b5c 100644
--- a/compiler/rustc_middle/src/ich/impls_syntax.rs
+++ b/compiler/rustc_middle/src/ich/impls_syntax.rs
@@ -1,5 +1,5 @@
 //! This module contains `HashStable` implementations for various data types
-//! from librustc_ast in no particular order.
+//! from `rustc_ast` in no particular order.
 
 use crate::ich::StableHashingContext;
 
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index b2b969e9b34..3b8a4adfb93 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -46,7 +46,7 @@ static_assert_size!(InterpErrorInfo<'_>, 8);
 /// Packages the kind of error we got from the const code interpreter
 /// up with a Rust-level backtrace of where the error occurred.
 /// Thsese should always be constructed by calling `.into()` on
-/// a `InterpError`. In `librustc_mir::interpret`, we have `throw_err_*`
+/// a `InterpError`. In `rustc_mir::interpret`, we have `throw_err_*`
 /// macros for this.
 #[derive(Debug)]
 pub struct InterpErrorInfo<'tcx>(Box<InterpErrorInfoInner<'tcx>>);
diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs
index eac3ab7282f..b0ab0c9ae52 100644
--- a/compiler/rustc_middle/src/traits/query.rs
+++ b/compiler/rustc_middle/src/traits/query.rs
@@ -3,7 +3,7 @@
 //! which makes a canonical query by replacing unbound inference
 //! variables and regions, so that results can be reused more broadly.
 //! The providers for the queries defined here can be found in
-//! `librustc_traits`.
+//! `rustc_traits`.
 
 use crate::ich::StableHashingContext;
 use crate::infer::canonical::{Canonical, QueryResponse};
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index 13f2d83ddf3..eb6d163312c 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -44,7 +44,7 @@ use std::ops::ControlFlow;
 /// This trait is implemented for every type that can be folded.
 /// Basically, every type that has a corresponding method in `TypeFolder`.
 ///
-/// To implement this conveniently, use the derive macro located in librustc_macros.
+/// To implement this conveniently, use the derive macro located in `rustc_macros`.
 pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
     fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self;
     fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index e7bbdc3cceb..c2e9dba6c8e 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -2630,6 +2630,7 @@ fn fn_can_unwind(
                 | AvrInterrupt
                 | AvrNonBlockingInterrupt
                 | CCmseNonSecureCall
+                | Wasm
                 | RustIntrinsic
                 | PlatformIntrinsic
                 | Unadjusted => false,
@@ -2712,6 +2713,7 @@ where
             AmdGpuKernel => Conv::AmdGpuKernel,
             AvrInterrupt => Conv::AvrInterrupt,
             AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt,
+            Wasm => Conv::C,
 
             // These API constants ought to be more specific...
             Cdecl => Conv::C,
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index f697cd51930..1989c91a879 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1804,29 +1804,94 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
         define_scoped_cx!(self);
 
         let mut region_index = self.region_index;
-        let new_value = self.tcx.replace_late_bound_regions(value.clone(), |br| {
-            let _ = start_or_continue(&mut self, "for<", ", ");
-            let kind = match br.kind {
-                ty::BrNamed(_, name) => {
-                    let _ = write!(self, "{}", name);
-                    br.kind
-                }
-                ty::BrAnon(_) | ty::BrEnv => {
-                    let name = loop {
-                        let name = name_by_region_index(region_index);
-                        region_index += 1;
-                        if !self.used_region_names.contains(&name) {
-                            break name;
-                        }
-                    };
-                    let _ = write!(self, "{}", name);
-                    ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
+        // If we want to print verbosly, then print *all* binders, even if they
+        // aren't named. Eventually, we might just want this as the default, but
+        // this is not *quite* right and changes the ordering of some output
+        // anyways.
+        let new_value = if self.tcx().sess.verbose() {
+            // anon index + 1 (BrEnv takes 0) -> name
+            let mut region_map: BTreeMap<u32, Symbol> = BTreeMap::default();
+            let bound_vars = value.bound_vars();
+            for var in bound_vars {
+                match var {
+                    ty::BoundVariableKind::Region(ty::BrNamed(_, name)) => {
+                        let _ = start_or_continue(&mut self, "for<", ", ");
+                        let _ = write!(self, "{}", name);
+                    }
+                    ty::BoundVariableKind::Region(ty::BrAnon(i)) => {
+                        let _ = start_or_continue(&mut self, "for<", ", ");
+                        let name = loop {
+                            let name = name_by_region_index(region_index);
+                            region_index += 1;
+                            if !self.used_region_names.contains(&name) {
+                                break name;
+                            }
+                        };
+                        let _ = write!(self, "{}", name);
+                        region_map.insert(i + 1, name);
+                    }
+                    ty::BoundVariableKind::Region(ty::BrEnv) => {
+                        let _ = start_or_continue(&mut self, "for<", ", ");
+                        let name = loop {
+                            let name = name_by_region_index(region_index);
+                            region_index += 1;
+                            if !self.used_region_names.contains(&name) {
+                                break name;
+                            }
+                        };
+                        let _ = write!(self, "{}", name);
+                        region_map.insert(0, name);
+                    }
+                    _ => continue,
                 }
-            };
-            self.tcx
-                .mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind }))
-        });
-        start_or_continue(&mut self, "", "> ")?;
+            }
+            start_or_continue(&mut self, "", "> ")?;
+
+            self.tcx.replace_late_bound_regions(value.clone(), |br| {
+                let kind = match br.kind {
+                    ty::BrNamed(_, _) => br.kind,
+                    ty::BrAnon(i) => {
+                        let name = region_map[&(i + 1)];
+                        ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
+                    }
+                    ty::BrEnv => {
+                        let name = region_map[&0];
+                        ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
+                    }
+                };
+                self.tcx.mk_region(ty::ReLateBound(
+                    ty::INNERMOST,
+                    ty::BoundRegion { var: br.var, kind },
+                ))
+            })
+        } else {
+            let new_value = self.tcx.replace_late_bound_regions(value.clone(), |br| {
+                let _ = start_or_continue(&mut self, "for<", ", ");
+                let kind = match br.kind {
+                    ty::BrNamed(_, name) => {
+                        let _ = write!(self, "{}", name);
+                        br.kind
+                    }
+                    ty::BrAnon(_) | ty::BrEnv => {
+                        let name = loop {
+                            let name = name_by_region_index(region_index);
+                            region_index += 1;
+                            if !self.used_region_names.contains(&name) {
+                                break name;
+                            }
+                        };
+                        let _ = write!(self, "{}", name);
+                        ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
+                    }
+                };
+                self.tcx.mk_region(ty::ReLateBound(
+                    ty::INNERMOST,
+                    ty::BoundRegion { var: br.var, kind },
+                ))
+            });
+            start_or_continue(&mut self, "", "> ")?;
+            new_value
+        };
 
         self.binder_depth += 1;
         self.region_index = region_index;
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index e352d0bc756..691bfcc98d1 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -80,7 +80,7 @@ impl BoundRegionKind {
 /// Defines the kinds of types.
 ///
 /// N.B., if you change this, you'll probably want to change the corresponding
-/// AST structure in `librustc_ast/ast.rs` as well.
+/// AST structure in `rustc_ast/src/ast.rs` as well.
 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable, Debug)]
 #[derive(HashStable)]
 #[rustc_diagnostic_item = "TyKind"]
@@ -2116,7 +2116,7 @@ impl<'tcx> TyS<'tcx> {
     ///
     /// Note that during type checking, we use an inference variable
     /// to represent the closure kind, because it has not yet been
-    /// inferred. Once upvar inference (in `src/librustc_typeck/check/upvar.rs`)
+    /// inferred. Once upvar inference (in `rustc_typeck/src/check/upvar.rs`)
     /// is complete, that type variable will be unified.
     pub fn to_opt_closure_kind(&self) -> Option<ty::ClosureKind> {
         match self.kind() {
diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs b/compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs
index a272e922a50..7156612f473 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs
+++ b/compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs
@@ -1,5 +1,5 @@
 //! This module provides linkage between RegionInferenceContext and
-//! librustc_graphviz traits, specialized to attaching borrowck analysis
+//! `rustc_graphviz` traits, specialized to attaching borrowck analysis
 //! data to rendered labels.
 
 use std::borrow::Cow;
diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs
index c85e9b9b932..003003a8abb 100644
--- a/compiler/rustc_mir/src/transform/generator.rs
+++ b/compiler/rustc_mir/src/transform/generator.rs
@@ -751,9 +751,10 @@ fn sanitize_witness<'tcx>(
             span_bug!(
                 body.span,
                 "Broken MIR: generator contains type {} in MIR, \
-                       but typeck only knows about {}",
-                decl.ty,
-                witness,
+                       but typeck only knows about {} and {:?}",
+                decl_ty,
+                allowed,
+                allowed_upvars
             );
         }
     }
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index c90f94c6d63..3a189e6b33d 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -609,6 +609,7 @@ fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: LocalDefId, abi: Abi) -> bo
                 | AvrInterrupt
                 | AvrNonBlockingInterrupt
                 | CCmseNonSecureCall
+                | Wasm
                 | RustIntrinsic
                 | PlatformIntrinsic
                 | Unadjusted => true,
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 4bf870eb7ce..bd8dfd678a9 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -128,7 +128,7 @@ impl<'a> StringReader<'a> {
     }
 
     /// Turns simple `rustc_lexer::TokenKind` enum into a rich
-    /// `librustc_ast::TokenKind`. This turns strings into interned
+    /// `rustc_ast::TokenKind`. This turns strings into interned
     /// symbols and runs additional validation.
     fn cook_lexer_token(&self, token: rustc_lexer::TokenKind, start: BytePos) -> Option<TokenKind> {
         Some(match token {
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 9fead30c4a1..905077a48e2 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -1,5 +1,6 @@
 //! The main parser interface.
 
+#![feature(array_windows)]
 #![feature(crate_visibility_modifier)]
 #![feature(bindings_after_at)]
 #![feature(iter_order_by)]
@@ -9,9 +10,12 @@
 #![recursion_limit = "256"]
 
 use rustc_ast as ast;
-use rustc_ast::token::{self, Nonterminal};
-use rustc_ast::tokenstream::{self, CanSynthesizeMissingTokens, LazyTokenStream, TokenStream};
+use rustc_ast::token::{self, Nonterminal, Token, TokenKind};
+use rustc_ast::tokenstream::{self, AttributesData, CanSynthesizeMissingTokens, LazyTokenStream};
+use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree};
+use rustc_ast::tokenstream::{Spacing, TokenStream};
 use rustc_ast::AstLike;
+use rustc_ast::Attribute;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Diagnostic, FatalError, Level, PResult};
@@ -21,8 +25,6 @@ use rustc_span::{FileName, SourceFile, Span};
 use std::path::Path;
 use std::str;
 
-use tracing::debug;
-
 pub const MACRO_ARGUMENTS: Option<&str> = Some("macro arguments");
 
 #[macro_use]
@@ -255,19 +257,23 @@ pub fn nt_to_tokenstream(
     // before we fall back to the stringification.
 
     let convert_tokens =
-        |tokens: Option<&LazyTokenStream>| tokens.as_ref().map(|t| t.create_token_stream());
+        |tokens: Option<&LazyTokenStream>| Some(tokens?.create_token_stream().to_tokenstream());
 
     let tokens = match *nt {
-        Nonterminal::NtItem(ref item) => prepend_attrs(sess, &item.attrs, nt, item.tokens.as_ref()),
+        Nonterminal::NtItem(ref item) => prepend_attrs(&item.attrs, item.tokens.as_ref()),
         Nonterminal::NtBlock(ref block) => convert_tokens(block.tokens.as_ref()),
         Nonterminal::NtStmt(ref stmt) => {
-            let do_prepend = |tokens| prepend_attrs(sess, stmt.attrs(), nt, tokens);
             if let ast::StmtKind::Empty = stmt.kind {
-                let tokens: TokenStream =
-                    tokenstream::TokenTree::token(token::Semi, stmt.span).into();
-                do_prepend(Some(&LazyTokenStream::new(tokens)))
+                let tokens = AttrAnnotatedTokenStream::new(vec![(
+                    tokenstream::AttrAnnotatedTokenTree::Token(Token::new(
+                        TokenKind::Semi,
+                        stmt.span,
+                    )),
+                    Spacing::Alone,
+                )]);
+                prepend_attrs(&stmt.attrs(), Some(&LazyTokenStream::new(tokens)))
             } else {
-                do_prepend(stmt.tokens())
+                prepend_attrs(&stmt.attrs(), stmt.tokens())
             }
         }
         Nonterminal::NtPat(ref pat) => convert_tokens(pat.tokens.as_ref()),
@@ -283,10 +289,7 @@ pub fn nt_to_tokenstream(
         Nonterminal::NtVis(ref vis) => convert_tokens(vis.tokens.as_ref()),
         Nonterminal::NtTT(ref tt) => Some(tt.clone().into()),
         Nonterminal::NtExpr(ref expr) | Nonterminal::NtLiteral(ref expr) => {
-            if expr.tokens.is_none() {
-                debug!("missing tokens for expr {:?}", expr);
-            }
-            prepend_attrs(sess, &expr.attrs, nt, expr.tokens.as_ref())
+            prepend_attrs(&expr.attrs, expr.tokens.as_ref())
         }
     };
 
@@ -295,34 +298,30 @@ pub fn nt_to_tokenstream(
     } else if matches!(synthesize_tokens, CanSynthesizeMissingTokens::Yes) {
         return fake_token_stream(sess, nt);
     } else {
-        panic!("Missing tokens for nt at {:?}: {:?}", nt.span(), pprust::nonterminal_to_string(nt));
+        panic!(
+            "Missing tokens for nt {:?} at {:?}: {:?}",
+            nt,
+            nt.span(),
+            pprust::nonterminal_to_string(nt)
+        );
     }
 }
 
+fn prepend_attrs(attrs: &[Attribute], tokens: Option<&LazyTokenStream>) -> Option<TokenStream> {
+    let tokens = tokens?;
+    if attrs.is_empty() {
+        return Some(tokens.create_token_stream().to_tokenstream());
+    }
+    let attr_data = AttributesData { attrs: attrs.to_vec().into(), tokens: tokens.clone() };
+    let wrapped = AttrAnnotatedTokenStream::new(vec![(
+        AttrAnnotatedTokenTree::Attributes(attr_data),
+        Spacing::Alone,
+    )]);
+    Some(wrapped.to_tokenstream())
+}
+
 pub fn fake_token_stream(sess: &ParseSess, nt: &Nonterminal) -> TokenStream {
     let source = pprust::nonterminal_to_string(nt);
     let filename = FileName::macro_expansion_source_code(&source);
     parse_stream_from_source_str(filename, source, sess, Some(nt.span()))
 }
-
-fn prepend_attrs(
-    sess: &ParseSess,
-    attrs: &[ast::Attribute],
-    nt: &Nonterminal,
-    tokens: Option<&tokenstream::LazyTokenStream>,
-) -> Option<tokenstream::TokenStream> {
-    if attrs.is_empty() {
-        return Some(tokens?.create_token_stream());
-    }
-    let mut builder = tokenstream::TokenStreamBuilder::new();
-    for attr in attrs {
-        // FIXME: Correctly handle tokens for inner attributes.
-        // For now, we fall back to reparsing the original AST node
-        if attr.style == ast::AttrStyle::Inner {
-            return Some(fake_token_stream(sess, nt));
-        }
-        builder.push(attr.tokens());
-    }
-    builder.push(tokens?.create_token_stream());
-    Some(builder.build())
-}
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 95d4a48b845..ee6ff4dba39 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -1,10 +1,11 @@
-use super::{AttrWrapper, Parser, PathStyle};
+use super::{AttrWrapper, Capturing, Parser, PathStyle};
 use rustc_ast as ast;
 use rustc_ast::attr;
 use rustc_ast::token::{self, Nonterminal};
 use rustc_ast_pretty::pprust;
 use rustc_errors::{error_code, PResult};
 use rustc_span::{sym, Span};
+use std::convert::TryInto;
 
 use tracing::debug;
 
@@ -29,6 +30,7 @@ impl<'a> Parser<'a> {
     pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, AttrWrapper> {
         let mut attrs: Vec<ast::Attribute> = Vec::new();
         let mut just_parsed_doc_comment = false;
+        let start_pos = self.token_cursor.num_next_calls;
         loop {
             debug!("parse_outer_attributes: self.token={:?}", self.token);
             let attr = if self.check(&token::Pound) {
@@ -74,7 +76,7 @@ impl<'a> Parser<'a> {
                 break;
             }
         }
-        Ok(AttrWrapper::new(attrs))
+        Ok(AttrWrapper::new(attrs.into(), start_pos))
     }
 
     /// Matches `attribute = # ! [ meta_item ]`.
@@ -177,6 +179,7 @@ impl<'a> Parser<'a> {
     crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
         let mut attrs: Vec<ast::Attribute> = vec![];
         loop {
+            let start_pos: u32 = self.token_cursor.num_next_calls.try_into().unwrap();
             // Only try to parse if it is an inner attribute (has `!`).
             let attr = if self.check(&token::Pound) && self.look_ahead(1, |t| t == &token::Not) {
                 Some(self.parse_attribute(InnerAttrPolicy::Permitted)?)
@@ -191,6 +194,18 @@ impl<'a> Parser<'a> {
                 None
             };
             if let Some(attr) = attr {
+                let end_pos: u32 = self.token_cursor.num_next_calls.try_into().unwrap();
+                // If we are currently capturing tokens, mark the location of this inner attribute.
+                // If capturing ends up creating a `LazyTokenStream`, we will include
+                // this replace range with it, removing the inner attribute from the final
+                // `AttrAnnotatedTokenStream`. Inner attributes are stored in the parsed AST note.
+                // During macro expansion, they are selectively inserted back into the
+                // token stream (the first inner attribute is remoevd each time we invoke the
+                // corresponding macro).
+                let range = start_pos..end_pos;
+                if let Capturing::Yes = self.capture_state.capturing {
+                    self.capture_state.inner_attr_ranges.insert(attr.id, (range, vec![]));
+                }
                 attrs.push(attr);
             } else {
                 break;
@@ -311,6 +326,9 @@ pub fn maybe_needs_tokens(attrs: &[ast::Attribute]) -> bool {
     // One of the attributes may either itself be a macro,
     // or expand to macro attributes (`cfg_attr`).
     attrs.iter().any(|attr| {
+        if attr.is_doc_comment() {
+            return false;
+        }
         attr.ident().map_or(true, |ident| {
             ident.name == sym::cfg_attr || !rustc_feature::is_builtin_attr_name(ident.name)
         })
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index 36a0fda6458..35759a396e8 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -1,12 +1,14 @@
-use super::attr;
-use super::{ForceCollect, Parser, TokenCursor, TrailingToken};
-use rustc_ast::token::{self, Token, TokenKind};
-use rustc_ast::tokenstream::{CreateTokenStream, TokenStream, TokenTree, TreeAndSpacing};
-use rustc_ast::tokenstream::{DelimSpan, LazyTokenStream, Spacing};
-use rustc_ast::AstLike;
+use super::{Capturing, FlatToken, ForceCollect, Parser, ReplaceRange, TokenCursor, TrailingToken};
+use rustc_ast::token::{self, DelimToken, Token, TokenKind};
+use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttributesData, CreateTokenStream};
+use rustc_ast::tokenstream::{AttrAnnotatedTokenTree, DelimSpan, LazyTokenStream, Spacing};
 use rustc_ast::{self as ast};
+use rustc_ast::{AstLike, AttrVec, Attribute};
 use rustc_errors::PResult;
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::{sym, Span, DUMMY_SP};
+
+use std::convert::TryInto;
+use std::ops::Range;
 
 /// A wrapper type to ensure that the parser handles outer attributes correctly.
 /// When we parse outer attributes, we need to ensure that we capture tokens
@@ -23,23 +25,158 @@ use rustc_span::{Span, DUMMY_SP};
 /// cannot directly access the `attrs` field
 #[derive(Debug, Clone)]
 pub struct AttrWrapper {
-    attrs: Vec<ast::Attribute>,
+    attrs: AttrVec,
+    // The start of the outer attributes in the token cursor.
+    // This allows us to create a `ReplaceRange` for the entire attribute
+    // target, including outer attributes.
+    start_pos: usize,
 }
 
+// This struct is passed around very frequently,
+// so make sure it doesn't accidentally get larger
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(AttrWrapper, 16);
+
 impl AttrWrapper {
-    pub fn empty() -> AttrWrapper {
-        AttrWrapper { attrs: vec![] }
+    pub(super) fn new(attrs: AttrVec, start_pos: usize) -> AttrWrapper {
+        AttrWrapper { attrs, start_pos }
     }
-    pub fn new(attrs: Vec<ast::Attribute>) -> AttrWrapper {
-        AttrWrapper { attrs }
+    pub fn empty() -> AttrWrapper {
+        AttrWrapper { attrs: AttrVec::new(), start_pos: usize::MAX }
     }
     // FIXME: Delay span bug here?
-    pub(crate) fn take_for_recovery(self) -> Vec<ast::Attribute> {
+    pub(crate) fn take_for_recovery(self) -> AttrVec {
         self.attrs
     }
+
+    // FIXME: require passing an NT to prevent misuse of this method
+    pub(crate) fn prepend_to_nt_inner(self, attrs: &mut Vec<Attribute>) {
+        let mut self_attrs: Vec<_> = self.attrs.into();
+        std::mem::swap(attrs, &mut self_attrs);
+        attrs.extend(self_attrs);
+    }
+
     pub fn is_empty(&self) -> bool {
         self.attrs.is_empty()
     }
+
+    pub fn maybe_needs_tokens(&self) -> bool {
+        crate::parser::attr::maybe_needs_tokens(&self.attrs)
+    }
+}
+
+/// Returns `true` if `attrs` contains a `cfg` or `cfg_attr` attribute
+fn has_cfg_or_cfg_attr(attrs: &[Attribute]) -> bool {
+    // NOTE: Builtin attributes like `cfg` and `cfg_attr` cannot be renamed via imports.
+    // Therefore, the absence of a literal `cfg` or `cfg_attr` guarantees that
+    // we don't need to do any eager expansion.
+    attrs.iter().any(|attr| {
+        attr.ident().map_or(false, |ident| ident.name == sym::cfg || ident.name == sym::cfg_attr)
+    })
+}
+
+// Produces a `TokenStream` on-demand. Using `cursor_snapshot`
+// and `num_calls`, we can reconstruct the `TokenStream` seen
+// by the callback. This allows us to avoid producing a `TokenStream`
+// if it is never needed - for example, a captured `macro_rules!`
+// argument that is never passed to a proc macro.
+// In practice token stream creation happens rarely compared to
+// calls to `collect_tokens` (see some statistics in #78736),
+// so we are doing as little up-front work as possible.
+//
+// This also makes `Parser` very cheap to clone, since
+// there is no intermediate collection buffer to clone.
+#[derive(Clone)]
+struct LazyTokenStreamImpl {
+    start_token: (Token, Spacing),
+    cursor_snapshot: TokenCursor,
+    num_calls: usize,
+    break_last_token: bool,
+    replace_ranges: Box<[ReplaceRange]>,
+}
+
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(LazyTokenStreamImpl, 144);
+
+impl CreateTokenStream for LazyTokenStreamImpl {
+    fn create_token_stream(&self) -> AttrAnnotatedTokenStream {
+        // The token produced by the final call to `next` or `next_desugared`
+        // was not actually consumed by the callback. The combination
+        // of chaining the initial token and using `take` produces the desired
+        // result - we produce an empty `TokenStream` if no calls were made,
+        // and omit the final token otherwise.
+        let mut cursor_snapshot = self.cursor_snapshot.clone();
+        let tokens =
+            std::iter::once((FlatToken::Token(self.start_token.0.clone()), self.start_token.1))
+                .chain((0..self.num_calls).map(|_| {
+                    let token = if cursor_snapshot.desugar_doc_comments {
+                        cursor_snapshot.next_desugared()
+                    } else {
+                        cursor_snapshot.next()
+                    };
+                    (FlatToken::Token(token.0), token.1)
+                }))
+                .take(self.num_calls);
+
+        if !self.replace_ranges.is_empty() {
+            let mut tokens: Vec<_> = tokens.collect();
+            let mut replace_ranges = self.replace_ranges.clone();
+            replace_ranges.sort_by_key(|(range, _)| range.start);
+
+            #[cfg(debug_assertions)]
+            {
+                for [(range, tokens), (next_range, next_tokens)] in replace_ranges.array_windows() {
+                    assert!(
+                        range.end <= next_range.start || range.end >= next_range.end,
+                        "Replace ranges should either be disjoint or nested: ({:?}, {:?}) ({:?}, {:?})",
+                        range,
+                        tokens,
+                        next_range,
+                        next_tokens,
+                    );
+                }
+            }
+
+            // Process the replace ranges, starting from the highest start
+            // position and working our way back. If have tokens like:
+            //
+            // `#[cfg(FALSE)]` struct Foo { #[cfg(FALSE)] field: bool }`
+            //
+            // Then we will generate replace ranges for both
+            // the `#[cfg(FALSE)] field: bool` and the entire
+            // `#[cfg(FALSE)]` struct Foo { #[cfg(FALSE)] field: bool }`
+            //
+            // By starting processing from the replace range with the greatest
+            // start position, we ensure that any replace range which encloses
+            // another replace range will capture the *replaced* tokens for the inner
+            // range, not the original tokens.
+            for (range, new_tokens) in replace_ranges.iter().rev() {
+                assert!(!range.is_empty(), "Cannot replace an empty range: {:?}", range);
+                // Replace ranges are only allowed to decrease the number of tokens.
+                assert!(
+                    range.len() >= new_tokens.len(),
+                    "Range {:?} has greater len than {:?}",
+                    range,
+                    new_tokens
+                );
+
+                // Replace any removed tokens with `FlatToken::Empty`.
+                // This keeps the total length of `tokens` constant throughout the
+                // replacement process, allowing us to use all of the `ReplaceRanges` entries
+                // without adjusting indices.
+                let filler = std::iter::repeat((FlatToken::Empty, Spacing::Alone))
+                    .take(range.len() - new_tokens.len());
+
+                tokens.splice(
+                    (range.start as usize)..(range.end as usize),
+                    new_tokens.clone().into_iter().chain(filler),
+                );
+            }
+            make_token_stream(tokens.into_iter(), self.break_last_token)
+        } else {
+            make_token_stream(tokens, self.break_last_token)
+        }
+    }
 }
 
 impl<'a> Parser<'a> {
@@ -65,106 +202,195 @@ impl<'a> Parser<'a> {
         force_collect: ForceCollect,
         f: impl FnOnce(&mut Self, Vec<ast::Attribute>) -> PResult<'a, (R, TrailingToken)>,
     ) -> PResult<'a, R> {
-        if matches!(force_collect, ForceCollect::No) && !attr::maybe_needs_tokens(&attrs.attrs) {
-            return Ok(f(self, attrs.attrs)?.0);
+        // We only bail out when nothing could possibly observe the collected tokens:
+        // 1. We cannot be force collecting tokens (since force-collecting requires tokens
+        //    by definition
+        if matches!(force_collect, ForceCollect::No)
+            // None of our outer attributes can require tokens (e.g. a proc-macro)
+            && !attrs.maybe_needs_tokens()
+            // If our target supports custom inner attributes, then we cannot bail
+            // out early, since we may need to capture tokens for a custom inner attribute
+            // invocation.
+            && !R::SUPPORTS_CUSTOM_INNER_ATTRS
+            // Never bail out early in `capture_cfg` mode, since there might be `#[cfg]`
+            // or `#[cfg_attr]` attributes.
+            && !self.capture_cfg
+        {
+            return Ok(f(self, attrs.attrs.into())?.0);
         }
+
         let start_token = (self.token.clone(), self.token_spacing);
         let cursor_snapshot = self.token_cursor.clone();
 
-        let (mut ret, trailing_token) = f(self, attrs.attrs)?;
-        let tokens = match ret.tokens_mut() {
-            Some(tokens) if tokens.is_none() => tokens,
-            _ => return Ok(ret),
-        };
+        let has_outer_attrs = !attrs.attrs.is_empty();
+        let prev_capturing = std::mem::replace(&mut self.capture_state.capturing, Capturing::Yes);
+        let replace_ranges_start = self.capture_state.replace_ranges.len();
+
+        let ret = f(self, attrs.attrs.into());
+
+        self.capture_state.capturing = prev_capturing;
+
+        let (mut ret, trailing) = ret?;
 
-        // Produces a `TokenStream` on-demand. Using `cursor_snapshot`
-        // and `num_calls`, we can reconstruct the `TokenStream` seen
-        // by the callback. This allows us to avoid producing a `TokenStream`
-        // if it is never needed - for example, a captured `macro_rules!`
-        // argument that is never passed to a proc macro.
-        // In practice token stream creation happens rarely compared to
-        // calls to `collect_tokens` (see some statistics in #78736),
-        // so we are doing as little up-front work as possible.
-        //
-        // This also makes `Parser` very cheap to clone, since
-        // there is no intermediate collection buffer to clone.
-        #[derive(Clone)]
-        struct LazyTokenStreamImpl {
-            start_token: (Token, Spacing),
-            cursor_snapshot: TokenCursor,
-            num_calls: usize,
-            desugar_doc_comments: bool,
-            append_unglued_token: Option<TreeAndSpacing>,
+        // When we're not in `capture-cfg` mode, then bail out early if:
+        // 1. Our target doesn't support tokens at all (e.g we're parsing an `NtIdent`)
+        //    so there's nothing for us to do.
+        // 2. Our target already has tokens set (e.g. we've parsed something
+        // like `#[my_attr] $item`. The actual parsing code takes care of prepending
+        // any attributes to the nonterminal, so we don't need to modify the
+        // already captured tokens.
+        // Note that this check is independent of `force_collect`- if we already
+        // have tokens, or can't even store them, then there's never a need to
+        // force collection of new tokens.
+        if !self.capture_cfg && matches!(ret.tokens_mut(), None | Some(Some(_))) {
+            return Ok(ret);
+        }
+
+        // This is very similar to the bail out check at the start of this function.
+        // Now that we've parsed an AST node, we have more information available.
+        if matches!(force_collect, ForceCollect::No)
+            // We now have inner attributes available, so this check is more precise
+            // than `attrs.maybe_needs_tokens()` at the start of the function.
+            // As a result, we don't need to check `R::SUPPORTS_CUSTOM_INNER_ATTRS`
+            && !crate::parser::attr::maybe_needs_tokens(ret.attrs())
+            // Subtle: We call `has_cfg_or_cfg_attr` with the attrs from `ret`.
+            // This ensures that we consider inner attributes (e.g. `#![cfg]`),
+            // which require us to have tokens available
+            // We also call `has_cfg_or_cfg_attr` at the beginning of this function,
+            // but we only bail out if there's no possibility of inner attributes
+            // (!R::SUPPORTS_CUSTOM_INNER_ATTRS)
+            // We only catpure about `#[cfg]` or `#[cfg_attr]` in `capture_cfg`
+            // mode - during normal parsing, we don't need any special capturing
+            // for those attributes, since they're builtin.
+            && !(self.capture_cfg && has_cfg_or_cfg_attr(ret.attrs()))
+        {
+            return Ok(ret);
         }
-        impl CreateTokenStream for LazyTokenStreamImpl {
-            fn create_token_stream(&self) -> TokenStream {
-                if self.num_calls == 0 {
-                    return TokenStream::new(vec![]);
-                }
 
-                let mut cursor_snapshot = self.cursor_snapshot.clone();
-                // Don't skip `None` delimiters, since we want to pass them to
-                // proc macros. Normally, we'll end up capturing `TokenKind::Interpolated`,
-                // which gets converted to a `None`-delimited group when we invoke
-                // a proc-macro. However, it's possible to already have a `None`-delimited
-                // group in the stream (such as when parsing the output of a proc-macro,
-                // or in certain unusual cases with cross-crate `macro_rules!` macros).
-                cursor_snapshot.skip_none_delims = false;
-
-                // The token produced by the final call to `next` or `next_desugared`
-                // was not actually consumed by the callback.
-                let num_calls = self.num_calls - 1;
-                let mut i = 0;
-                let tokens =
-                    std::iter::once(self.start_token.clone()).chain(std::iter::from_fn(|| {
-                        if i >= num_calls {
-                            return None;
-                        }
-
-                        let token = if self.desugar_doc_comments {
-                            cursor_snapshot.next_desugared()
-                        } else {
-                            cursor_snapshot.next()
-                        };
-
-                        // When the `LazyTokenStreamImpl` was original produced, we did *not*
-                        // include `NoDelim` tokens in `num_calls`, since they are normally ignored
-                        // by the parser. Therefore, we only increment our counter for other types of tokens.
-                        if !matches!(
-                            token.0.kind,
-                            token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim)
-                        ) {
-                            i += 1;
-                        }
-                        Some(token)
-                    }));
-
-                make_token_stream(tokens, self.append_unglued_token.clone())
+        let mut inner_attr_replace_ranges = Vec::new();
+        // Take the captured ranges for any inner attributes that we parsed.
+        for inner_attr in ret.attrs().iter().filter(|a| a.style == ast::AttrStyle::Inner) {
+            if let Some(attr_range) = self.capture_state.inner_attr_ranges.remove(&inner_attr.id) {
+                inner_attr_replace_ranges.push(attr_range);
+            } else {
+                self.sess
+                    .span_diagnostic
+                    .delay_span_bug(inner_attr.span, "Missing token range for attribute");
             }
         }
 
-        let mut num_calls = self.token_cursor.num_next_calls - cursor_snapshot.num_next_calls;
-        match trailing_token {
+        let replace_ranges_end = self.capture_state.replace_ranges.len();
+
+        let cursor_snapshot_next_calls = cursor_snapshot.num_next_calls;
+        let mut end_pos = self.token_cursor.num_next_calls;
+
+        // Capture a trailing token if requested by the callback 'f'
+        match trailing {
             TrailingToken::None => {}
             TrailingToken::Semi => {
                 assert_eq!(self.token.kind, token::Semi);
-                num_calls += 1;
+                end_pos += 1;
             }
             TrailingToken::MaybeComma => {
                 if self.token.kind == token::Comma {
-                    num_calls += 1;
+                    end_pos += 1;
                 }
             }
         }
 
-        *tokens = Some(LazyTokenStream::new(LazyTokenStreamImpl {
+        // If we 'broke' the last token (e.g. breaking a '>>' token to two '>' tokens),
+        // then extend the range of captured tokens to include it, since the parser
+        // was not actually bumped past it. When the `LazyTokenStream` gets converted
+        // into a `AttrAnnotatedTokenStream`, we will create the proper token.
+        if self.token_cursor.break_last_token {
+            assert_eq!(
+                trailing,
+                TrailingToken::None,
+                "Cannot set `break_last_token` and have trailing token"
+            );
+            end_pos += 1;
+        }
+
+        let num_calls = end_pos - cursor_snapshot_next_calls;
+
+        // If we have no attributes, then we will never need to
+        // use any replace ranges.
+        let replace_ranges: Box<[ReplaceRange]> = if ret.attrs().is_empty() && !self.capture_cfg {
+            Box::new([])
+        } else {
+            // Grab any replace ranges that occur *inside* the current AST node.
+            // We will perform the actual replacement when we convert the `LazyTokenStream`
+            // to a `AttrAnnotatedTokenStream`
+            let start_calls: u32 = cursor_snapshot_next_calls.try_into().unwrap();
+            self.capture_state.replace_ranges[replace_ranges_start..replace_ranges_end]
+                .iter()
+                .cloned()
+                .chain(inner_attr_replace_ranges.clone().into_iter())
+                .map(|(range, tokens)| {
+                    ((range.start - start_calls)..(range.end - start_calls), tokens)
+                })
+                .collect()
+        };
+
+        let tokens = LazyTokenStream::new(LazyTokenStreamImpl {
             start_token,
             num_calls,
             cursor_snapshot,
-            desugar_doc_comments: self.desugar_doc_comments,
-            append_unglued_token: self.token_cursor.append_unglued_token.clone(),
-        }));
+            break_last_token: self.token_cursor.break_last_token,
+            replace_ranges,
+        });
+
+        // If we support tokens at all
+        if let Some(target_tokens) = ret.tokens_mut() {
+            if let Some(target_tokens) = target_tokens {
+                assert!(
+                    !self.capture_cfg,
+                    "Encountered existing tokens with capture_cfg set: {:?}",
+                    target_tokens
+                );
+            } else {
+                // Store se our newly captured tokens into the AST node
+                *target_tokens = Some(tokens.clone());
+            };
+        }
 
+        let final_attrs = ret.attrs();
+
+        // If `capture_cfg` is set and we're inside a recursive call to
+        // `collect_tokens_trailing_token`, then we need to register a replace range
+        // if we have `#[cfg]` or `#[cfg_attr]`. This allows us to run eager cfg-expansion
+        // on the captured token stream.
+        if self.capture_cfg
+            && matches!(self.capture_state.capturing, Capturing::Yes)
+            && has_cfg_or_cfg_attr(&final_attrs)
+        {
+            let attr_data = AttributesData { attrs: final_attrs.to_vec().into(), tokens };
+
+            // Replace the entire AST node that we just parsed, including attributes,
+            // with a `FlatToken::AttrTarget`. If this AST node is inside an item
+            // that has `#[derive]`, then this will allow us to cfg-expand this
+            // AST node.
+            let start_pos =
+                if has_outer_attrs { attrs.start_pos } else { cursor_snapshot_next_calls };
+            let new_tokens = vec![(FlatToken::AttrTarget(attr_data), Spacing::Alone)];
+
+            assert!(
+                !self.token_cursor.break_last_token,
+                "Should not have unglued last token with cfg attr"
+            );
+            let range: Range<u32> = (start_pos.try_into().unwrap())..(end_pos.try_into().unwrap());
+            self.capture_state.replace_ranges.push((range, new_tokens));
+            self.capture_state.replace_ranges.extend(inner_attr_replace_ranges);
+        }
+
+        // Only clear our `replace_ranges` when we're finished capturing entirely.
+        if matches!(self.capture_state.capturing, Capturing::No) {
+            self.capture_state.replace_ranges.clear();
+            // We don't clear `inner_attr_ranges`, as doing so repeatedly
+            // had a measureable performance impact. Most inner attributes that
+            // we insert will get removed - when we drop the parser, we'll free
+            // up the memory used by any attributes that we didn't remove from the map.
+        }
         Ok(ret)
     }
 }
@@ -172,43 +398,112 @@ impl<'a> Parser<'a> {
 /// Converts a flattened iterator of tokens (including open and close delimiter tokens)
 /// into a `TokenStream`, creating a `TokenTree::Delimited` for each matching pair
 /// of open and close delims.
+// FIXME(#67062): Currently, we don't parse `None`-delimited groups correctly,
+// which can cause us to end up with mismatched `None` delimiters in our
+// captured tokens. This function contains several hacks to work around this -
+// essentially, we throw away mismatched `None` delimiters when we encounter them.
+// Once we properly parse `None` delimiters, they can be captured just like any
+// other tokens, and these hacks can be removed.
 fn make_token_stream(
-    tokens: impl Iterator<Item = (Token, Spacing)>,
-    append_unglued_token: Option<TreeAndSpacing>,
-) -> TokenStream {
+    mut iter: impl Iterator<Item = (FlatToken, Spacing)>,
+    break_last_token: bool,
+) -> AttrAnnotatedTokenStream {
     #[derive(Debug)]
     struct FrameData {
         open: Span,
-        inner: Vec<(TokenTree, Spacing)>,
+        open_delim: DelimToken,
+        inner: Vec<(AttrAnnotatedTokenTree, Spacing)>,
     }
-    let mut stack = vec![FrameData { open: DUMMY_SP, inner: vec![] }];
-    for (token, spacing) in tokens {
+    let mut stack =
+        vec![FrameData { open: DUMMY_SP, open_delim: DelimToken::NoDelim, inner: vec![] }];
+    let mut token_and_spacing = iter.next();
+    while let Some((token, spacing)) = token_and_spacing {
         match token {
-            Token { kind: TokenKind::OpenDelim(_), span } => {
-                stack.push(FrameData { open: span, inner: vec![] });
+            FlatToken::Token(Token { kind: TokenKind::OpenDelim(delim), span }) => {
+                stack.push(FrameData { open: span, open_delim: delim, inner: vec![] });
             }
-            Token { kind: TokenKind::CloseDelim(delim), span } => {
-                let frame_data = stack.pop().expect("Token stack was empty!");
+            FlatToken::Token(Token { kind: TokenKind::CloseDelim(delim), span }) => {
+                // HACK: If we enconter a mismatched `None` delimiter at the top
+                // level, just ignore it.
+                if matches!(delim, DelimToken::NoDelim)
+                    && (stack.len() == 1
+                        || !matches!(stack.last_mut().unwrap().open_delim, DelimToken::NoDelim))
+                {
+                    token_and_spacing = iter.next();
+                    continue;
+                }
+                let frame_data = stack
+                    .pop()
+                    .unwrap_or_else(|| panic!("Token stack was empty for token: {:?}", token));
+
+                // HACK: If our current frame has a mismatched opening `None` delimiter,
+                // merge our current frame with the one above it. That is, transform
+                // `[ { < first second } third ]` into `[ { first second } third ]`
+                if !matches!(delim, DelimToken::NoDelim)
+                    && matches!(frame_data.open_delim, DelimToken::NoDelim)
+                {
+                    stack.last_mut().unwrap().inner.extend(frame_data.inner);
+                    // Process our closing delimiter again, this time at the previous
+                    // frame in the stack
+                    token_and_spacing = Some((token, spacing));
+                    continue;
+                }
+
+                assert_eq!(
+                    frame_data.open_delim, delim,
+                    "Mismatched open/close delims: open={:?} close={:?}",
+                    frame_data.open, span
+                );
                 let dspan = DelimSpan::from_pair(frame_data.open, span);
-                let stream = TokenStream::new(frame_data.inner);
-                let delimited = TokenTree::Delimited(dspan, delim, stream);
+                let stream = AttrAnnotatedTokenStream::new(frame_data.inner);
+                let delimited = AttrAnnotatedTokenTree::Delimited(dspan, delim, stream);
                 stack
                     .last_mut()
-                    .unwrap_or_else(|| panic!("Bottom token frame is missing for tokens!"))
+                    .unwrap_or_else(|| {
+                        panic!("Bottom token frame is missing for token: {:?}", token)
+                    })
                     .inner
                     .push((delimited, Spacing::Alone));
             }
-            token => {
-                stack
-                    .last_mut()
-                    .expect("Bottom token frame is missing!")
-                    .inner
-                    .push((TokenTree::Token(token), spacing));
-            }
+            FlatToken::Token(token) => stack
+                .last_mut()
+                .expect("Bottom token frame is missing!")
+                .inner
+                .push((AttrAnnotatedTokenTree::Token(token), spacing)),
+            FlatToken::AttrTarget(data) => stack
+                .last_mut()
+                .expect("Bottom token frame is missing!")
+                .inner
+                .push((AttrAnnotatedTokenTree::Attributes(data), spacing)),
+            FlatToken::Empty => {}
         }
+        token_and_spacing = iter.next();
+    }
+    // HACK: If we don't have a closing `None` delimiter for our last
+    // frame, merge the frame with the top-level frame. That is,
+    // turn `< first second` into `first second`
+    if stack.len() == 2 && stack[1].open_delim == DelimToken::NoDelim {
+        let temp_buf = stack.pop().unwrap();
+        stack.last_mut().unwrap().inner.extend(temp_buf.inner);
     }
     let mut final_buf = stack.pop().expect("Missing final buf!");
-    final_buf.inner.extend(append_unglued_token);
+    if break_last_token {
+        let (last_token, spacing) = final_buf.inner.pop().unwrap();
+        if let AttrAnnotatedTokenTree::Token(last_token) = last_token {
+            let unglued_first = last_token.kind.break_two_token_op().unwrap().0;
+
+            // A 'unglued' token is always two ASCII characters
+            let mut first_span = last_token.span.shrink_to_lo();
+            first_span = first_span.with_hi(first_span.lo() + rustc_span::BytePos(1));
+
+            final_buf.inner.push((
+                AttrAnnotatedTokenTree::Token(Token::new(unglued_first, first_span)),
+                spacing,
+            ));
+        } else {
+            panic!("Unexpected last token {:?}", last_token)
+        }
+    }
     assert!(stack.is_empty(), "Stack should be empty: final_buf={:?} stack={:?}", final_buf, stack);
-    TokenStream::new(final_buf.inner)
+    AttrAnnotatedTokenStream::new(final_buf.inner)
 }
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 02ee268b88c..e155b3fa773 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -2581,19 +2581,17 @@ impl<'a> Parser<'a> {
         attrs: AttrWrapper,
         f: impl FnOnce(&mut Self, Vec<ast::Attribute>) -> PResult<'a, P<Expr>>,
     ) -> PResult<'a, P<Expr>> {
-        // FIXME - come up with a nice way to properly forward `ForceCollect`from
-        // the nonterminal parsing code. TThis approach iscorrect, but will cause
-        // us to unnecessarily capture tokens for exprs that have only builtin
-        // attributes. Revisit this before #![feature(stmt_expr_attributes)] is stabilized
-        let force_collect = if attrs.is_empty() { ForceCollect::No } else { ForceCollect::Yes };
-        self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| {
+        self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
             let res = f(this, attrs)?;
             let trailing = if this.restrictions.contains(Restrictions::STMT_EXPR)
                 && this.token.kind == token::Semi
             {
                 TrailingToken::Semi
             } else {
-                TrailingToken::None
+                // FIXME - pass this through from the place where we know
+                // we need a comma, rather than assuming that `#[attr] expr,`
+                // always captures a trailing comma
+                TrailingToken::MaybeComma
             };
             Ok((res, trailing))
         })
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 70dbaa53d38..2b7b58459c0 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -103,20 +103,11 @@ impl<'a> Parser<'a> {
         // over when we bump the parser
         if let token::Interpolated(nt) = &self.token.kind {
             if let token::NtItem(item) = &**nt {
-                let item = item.clone();
-
-                return self.collect_tokens_trailing_token(
-                    attrs,
-                    force_collect,
-                    |this, mut attrs| {
-                        let mut item = item;
-                        mem::swap(&mut item.attrs, &mut attrs);
-                        item.attrs.extend(attrs);
-                        // Bump the parser so the we capture the token::Interpolated
-                        this.bump();
-                        Ok((Some(item.into_inner()), TrailingToken::None))
-                    },
-                );
+                let mut item = item.clone();
+                self.bump();
+
+                attrs.prepend_to_nt_inner(&mut item.attrs);
+                return Ok(Some(item.into_inner()));
             }
         };
 
@@ -530,7 +521,7 @@ impl<'a> Parser<'a> {
 
         generics.where_clause = self.parse_where_clause()?;
 
-        let impl_items = self.parse_item_list(attrs, |p| p.parse_impl_item())?;
+        let impl_items = self.parse_item_list(attrs, |p| p.parse_impl_item(ForceCollect::No))?;
 
         let item_kind = match ty_second {
             Some(ty_second) => {
@@ -718,22 +709,32 @@ impl<'a> Parser<'a> {
         } else {
             // It's a normal trait.
             tps.where_clause = self.parse_where_clause()?;
-            let items = self.parse_item_list(attrs, |p| p.parse_trait_item())?;
+            let items = self.parse_item_list(attrs, |p| p.parse_trait_item(ForceCollect::No))?;
             Ok((ident, ItemKind::Trait(box TraitKind(is_auto, unsafety, tps, bounds, items))))
         }
     }
 
-    pub fn parse_impl_item(&mut self) -> PResult<'a, Option<Option<P<AssocItem>>>> {
-        self.parse_assoc_item(|_| true)
+    pub fn parse_impl_item(
+        &mut self,
+        force_collect: ForceCollect,
+    ) -> PResult<'a, Option<Option<P<AssocItem>>>> {
+        self.parse_assoc_item(|_| true, force_collect)
     }
 
-    pub fn parse_trait_item(&mut self) -> PResult<'a, Option<Option<P<AssocItem>>>> {
-        self.parse_assoc_item(|edition| edition >= Edition::Edition2018)
+    pub fn parse_trait_item(
+        &mut self,
+        force_collect: ForceCollect,
+    ) -> PResult<'a, Option<Option<P<AssocItem>>>> {
+        self.parse_assoc_item(|edition| edition >= Edition::Edition2018, force_collect)
     }
 
     /// Parses associated items.
-    fn parse_assoc_item(&mut self, req_name: ReqName) -> PResult<'a, Option<Option<P<AssocItem>>>> {
-        Ok(self.parse_item_(req_name, ForceCollect::No)?.map(
+    fn parse_assoc_item(
+        &mut self,
+        req_name: ReqName,
+        force_collect: ForceCollect,
+    ) -> PResult<'a, Option<Option<P<AssocItem>>>> {
+        Ok(self.parse_item_(req_name, force_collect)?.map(
             |Item { attrs, id, span, vis, ident, kind, tokens }| {
                 let kind = match AssocItemKind::try_from(kind) {
                     Ok(kind) => kind,
@@ -918,14 +919,17 @@ impl<'a> Parser<'a> {
         unsafety: Unsafe,
     ) -> PResult<'a, ItemInfo> {
         let abi = self.parse_abi(); // ABI?
-        let items = self.parse_item_list(attrs, |p| p.parse_foreign_item())?;
+        let items = self.parse_item_list(attrs, |p| p.parse_foreign_item(ForceCollect::No))?;
         let module = ast::ForeignMod { unsafety, abi, items };
         Ok((Ident::invalid(), ItemKind::ForeignMod(module)))
     }
 
     /// Parses a foreign item (one in an `extern { ... }` block).
-    pub fn parse_foreign_item(&mut self) -> PResult<'a, Option<Option<P<ForeignItem>>>> {
-        Ok(self.parse_item_(|_| true, ForceCollect::No)?.map(
+    pub fn parse_foreign_item(
+        &mut self,
+        force_collect: ForceCollect,
+    ) -> PResult<'a, Option<Option<P<ForeignItem>>>> {
+        Ok(self.parse_item_(|_| true, force_collect)?.map(
             |Item { attrs, id, span, vis, ident, kind, tokens }| {
                 let kind = match ForeignItemKind::try_from(kind) {
                     Ok(kind) => kind,
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 748a8e2bb49..4b97c8b0a81 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -19,13 +19,16 @@ pub use path::PathStyle;
 
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, DelimToken, Token, TokenKind};
+use rustc_ast::tokenstream::AttributesData;
 use rustc_ast::tokenstream::{self, DelimSpan, Spacing};
-use rustc_ast::tokenstream::{TokenStream, TokenTree, TreeAndSpacing};
+use rustc_ast::tokenstream::{TokenStream, TokenTree};
+use rustc_ast::AttrId;
 use rustc_ast::DUMMY_NODE_ID;
 use rustc_ast::{self as ast, AnonConst, AstLike, AttrStyle, AttrVec, Const, CrateSugar, Extern};
 use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacDelimiter, Mutability, StrLit, Unsafe};
 use rustc_ast::{Visibility, VisibilityKind};
 use rustc_ast_pretty::pprust;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::PResult;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError};
@@ -34,6 +37,7 @@ use rustc_span::source_map::{Span, DUMMY_SP};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use tracing::debug;
 
+use std::ops::Range;
 use std::{cmp, mem, slice};
 
 bitflags::bitflags! {
@@ -64,6 +68,7 @@ pub enum ForceCollect {
     No,
 }
 
+#[derive(Debug, Eq, PartialEq)]
 pub enum TrailingToken {
     None,
     Semi,
@@ -111,6 +116,7 @@ pub struct Parser<'a> {
     pub token_spacing: Spacing,
     /// The previous token.
     pub prev_token: Token,
+    pub capture_cfg: bool,
     restrictions: Restrictions,
     expected_tokens: Vec<TokenType>,
     // Important: This must only be advanced from `next_tok`
@@ -134,6 +140,44 @@ pub struct Parser<'a> {
     pub last_type_ascription: Option<(Span, bool /* likely path typo */)>,
     /// If present, this `Parser` is not parsing Rust code but rather a macro call.
     subparser_name: Option<&'static str>,
+    capture_state: CaptureState,
+}
+
+/// Indicates a range of tokens that should be replaced by
+/// the tokens in the provided vector. This is used in two
+/// places during token collection:
+///
+/// 1. During the parsing of an AST node that may have a `#[derive]`
+/// attribute, we parse a nested AST node that has `#[cfg]` or `#[cfg_attr]`
+/// In this case, we use a `ReplaceRange` to replace the entire inner AST node
+/// with `FlatToken::AttrTarget`, allowing us to perform eager cfg-expansion
+/// on a `AttrAnnotatedTokenStream`
+///
+/// 2. When we parse an inner attribute while collecting tokens. We
+/// remove inner attributes from the token stream entirely, and
+/// instead track them through the `attrs` field on the AST node.
+/// This allows us to easily manipulate them (for example, removing
+/// the first macro inner attribute to invoke a proc-macro).
+/// When create a `TokenStream`, the inner attributes get inserted
+/// into the proper place in the token stream.
+pub type ReplaceRange = (Range<u32>, Vec<(FlatToken, Spacing)>);
+
+/// Controls how we capture tokens. Capturing can be expensive,
+/// so we try to avoid performing capturing in cases where
+/// we will never need a `AttrAnnotatedTokenStream`
+#[derive(Copy, Clone)]
+pub enum Capturing {
+    /// We aren't performing any capturing - this is the default mode.
+    No,
+    /// We are capturing tokens
+    Yes,
+}
+
+#[derive(Clone)]
+struct CaptureState {
+    capturing: Capturing,
+    replace_ranges: Vec<ReplaceRange>,
+    inner_attr_ranges: FxHashMap<AttrId, ReplaceRange>,
 }
 
 impl<'a> Drop for Parser<'a> {
@@ -167,18 +211,11 @@ struct TokenCursor {
     // want to capture just the first 'unglued' token.
     // For example, capturing the `Vec<u8>`
     // in `Option<Vec<u8>>` requires us to unglue
-    // the trailing `>>` token. The `append_unglued_token`
+    // the trailing `>>` token. The `break_last_token`
     // field is used to track this token - it gets
     // appended to the captured stream when
     // we evaluate a `LazyTokenStream`
-    append_unglued_token: Option<TreeAndSpacing>,
-    // If `true`, skip the delimiters for `None`-delimited groups,
-    // and just yield the inner tokens. This is `true` during
-    // normal parsing, since the parser code is not currently prepared
-    // to handle `None` delimiters. When capturing a `TokenStream`,
-    // however, we want to handle `None`-delimiters, since
-    // proc-macros always see `None`-delimited groups.
-    skip_none_delims: bool,
+    break_last_token: bool,
 }
 
 #[derive(Clone)]
@@ -191,13 +228,13 @@ struct TokenCursorFrame {
 }
 
 impl TokenCursorFrame {
-    fn new(span: DelimSpan, delim: DelimToken, tts: TokenStream, skip_none_delims: bool) -> Self {
+    fn new(span: DelimSpan, delim: DelimToken, tts: TokenStream) -> Self {
         TokenCursorFrame {
             delim,
             span,
-            open_delim: delim == token::NoDelim && skip_none_delims,
+            open_delim: false,
             tree_cursor: tts.into_trees(),
-            close_delim: delim == token::NoDelim && skip_none_delims,
+            close_delim: false,
         }
     }
 }
@@ -225,7 +262,7 @@ impl TokenCursor {
                     return (token, spacing);
                 }
                 TokenTree::Delimited(sp, delim, tts) => {
-                    let frame = TokenCursorFrame::new(sp, delim, tts, self.skip_none_delims);
+                    let frame = TokenCursorFrame::new(sp, delim, tts);
                     self.stack.push(mem::replace(&mut self.frame, frame));
                 }
             }
@@ -283,7 +320,6 @@ impl TokenCursor {
                         .cloned()
                         .collect::<TokenStream>()
                 },
-                self.skip_none_delims,
             ),
         ));
 
@@ -372,26 +408,24 @@ impl<'a> Parser<'a> {
         desugar_doc_comments: bool,
         subparser_name: Option<&'static str>,
     ) -> Self {
+        let mut start_frame = TokenCursorFrame::new(DelimSpan::dummy(), token::NoDelim, tokens);
+        start_frame.open_delim = true;
+        start_frame.close_delim = true;
+
         let mut parser = Parser {
             sess,
             token: Token::dummy(),
             token_spacing: Spacing::Alone,
             prev_token: Token::dummy(),
+            capture_cfg: false,
             restrictions: Restrictions::empty(),
             expected_tokens: Vec::new(),
-            // Skip over the delimiters for `None`-delimited groups
             token_cursor: TokenCursor {
-                frame: TokenCursorFrame::new(
-                    DelimSpan::dummy(),
-                    token::NoDelim,
-                    tokens,
-                    /* skip_none_delims */ true,
-                ),
+                frame: start_frame,
                 stack: Vec::new(),
                 num_next_calls: 0,
                 desugar_doc_comments,
-                append_unglued_token: None,
-                skip_none_delims: true,
+                break_last_token: false,
             },
             desugar_doc_comments,
             unmatched_angle_bracket_count: 0,
@@ -400,6 +434,11 @@ impl<'a> Parser<'a> {
             last_unexpected_token_span: None,
             last_type_ascription: None,
             subparser_name,
+            capture_state: CaptureState {
+                capturing: Capturing::No,
+                replace_ranges: Vec::new(),
+                inner_attr_ranges: Default::default(),
+            },
         };
 
         // Make parser point to the first token.
@@ -409,21 +448,29 @@ impl<'a> Parser<'a> {
     }
 
     fn next_tok(&mut self, fallback_span: Span) -> (Token, Spacing) {
-        let (mut next, spacing) = if self.desugar_doc_comments {
-            self.token_cursor.next_desugared()
-        } else {
-            self.token_cursor.next()
-        };
-        self.token_cursor.num_next_calls += 1;
-        // We've retrieved an token from the underlying
-        // cursor, so we no longer need to worry about
-        // an unglued token. See `break_and_eat` for more details
-        self.token_cursor.append_unglued_token = None;
-        if next.span.is_dummy() {
-            // Tweak the location for better diagnostics, but keep syntactic context intact.
-            next.span = fallback_span.with_ctxt(next.span.ctxt());
+        loop {
+            let (mut next, spacing) = if self.desugar_doc_comments {
+                self.token_cursor.next_desugared()
+            } else {
+                self.token_cursor.next()
+            };
+            self.token_cursor.num_next_calls += 1;
+            // We've retrieved an token from the underlying
+            // cursor, so we no longer need to worry about
+            // an unglued token. See `break_and_eat` for more details
+            self.token_cursor.break_last_token = false;
+            if next.span.is_dummy() {
+                // Tweak the location for better diagnostics, but keep syntactic context intact.
+                next.span = fallback_span.with_ctxt(next.span.ctxt());
+            }
+            if matches!(
+                next.kind,
+                token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim)
+            ) {
+                continue;
+            }
+            return (next, spacing);
         }
-        (next, spacing)
     }
 
     pub fn unexpected<T>(&mut self) -> PResult<'a, T> {
@@ -621,8 +668,7 @@ impl<'a> Parser<'a> {
                 // If we consume any additional tokens, then this token
                 // is not needed (we'll capture the entire 'glued' token),
                 // and `next_tok` will set this field to `None`
-                self.token_cursor.append_unglued_token =
-                    Some((TokenTree::Token(self.token.clone()), Spacing::Alone));
+                self.token_cursor.break_last_token = true;
                 // Use the spacing of the glued token as the spacing
                 // of the unglued second token.
                 self.bump_with((Token::new(second, second_span), self.token_spacing));
@@ -703,6 +749,8 @@ impl<'a> Parser<'a> {
         let mut recovered = false;
         let mut trailing = false;
         let mut v = vec![];
+        let unclosed_delims = !self.unclosed_delims.is_empty();
+
         while !self.expect_any_with_type(kets, expect) {
             if let token::CloseDelim(..) | token::Eof = self.token.kind {
                 break;
@@ -723,7 +771,7 @@ impl<'a> Parser<'a> {
 
                             // Attempt to keep parsing if it was a similar separator.
                             if let Some(ref tokens) = t.similar_tokens() {
-                                if tokens.contains(&self.token.kind) {
+                                if tokens.contains(&self.token.kind) && !unclosed_delims {
                                     self.bump();
                                 }
                             }
@@ -1302,3 +1350,24 @@ pub fn emit_unclosed_delims(unclosed_delims: &mut Vec<UnmatchedBrace>, sess: &Pa
         }
     }
 }
+
+/// A helper struct used when building a `AttrAnnotatedTokenStream` from
+/// a `LazyTokenStream`. Both delimiter and non-delimited tokens
+/// are stored as `FlatToken::Token`. A vector of `FlatToken`s
+/// is then 'parsed' to build up a `AttrAnnotatedTokenStream` with nested
+/// `AttrAnnotatedTokenTree::Delimited` tokens
+#[derive(Debug, Clone)]
+pub enum FlatToken {
+    /// A token - this holds both delimiter (e.g. '{' and '}')
+    /// and non-delimiter tokens
+    Token(Token),
+    /// Holds the `AttributesData` for an AST node. The
+    /// `AttributesData` is inserted directly into the
+    /// constructed `AttrAnnotatedTokenStream` as
+    /// a `AttrAnnotatedTokenTree::Attributes`
+    AttrTarget(AttributesData),
+    /// A special 'empty' token that is ignored during the conversion
+    /// to a `AttrAnnotatedTokenStream`. This is used to simplify the
+    /// handling of replace ranges.
+    Empty,
+}
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index 0c49d103583..5c4a2785d6e 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -153,9 +153,7 @@ impl<'a> Parser<'a> {
             NonterminalKind::Path => token::NtPath(
                 self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?,
             ),
-            NonterminalKind::Meta => {
-                token::NtMeta(P(self.collect_tokens_no_attrs(|this| this.parse_attr_item(false))?))
-            }
+            NonterminalKind::Meta => token::NtMeta(P(self.parse_attr_item(true)?)),
             NonterminalKind::TT => token::NtTT(self.parse_token_tree()),
             NonterminalKind::Vis => token::NtVis(
                 self.collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?,
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 24fb4301cc2..592f64f4a39 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -48,39 +48,26 @@ impl<'a> Parser<'a> {
         if let token::Interpolated(nt) = &self.token.kind {
             if let token::NtStmt(stmt) = &**nt {
                 let mut stmt = stmt.clone();
-                return self.collect_tokens_trailing_token(
-                    attrs,
-                    force_collect,
-                    |this, mut attrs| {
-                        stmt.visit_attrs(|stmt_attrs| {
-                            mem::swap(stmt_attrs, &mut attrs);
-                            stmt_attrs.extend(attrs);
-                        });
-                        // Make sure we capture the token::Interpolated
-                        this.bump();
-                        Ok((Some(stmt), TrailingToken::None))
-                    },
-                );
+                self.bump();
+                stmt.visit_attrs(|stmt_attrs| {
+                    attrs.prepend_to_nt_inner(stmt_attrs);
+                });
+                return Ok(Some(stmt));
             }
         }
 
         Ok(Some(if self.token.is_keyword(kw::Let) {
             self.parse_local_mk(lo, attrs, capture_semi, force_collect)?
         } else if self.is_kw_followed_by_ident(kw::Mut) {
-            self.recover_stmt_local(
-                lo,
-                attrs.take_for_recovery().into(),
-                "missing keyword",
-                "let mut",
-            )?
+            self.recover_stmt_local(lo, attrs, "missing keyword", "let mut")?
         } else if self.is_kw_followed_by_ident(kw::Auto) {
             self.bump(); // `auto`
             let msg = "write `let` instead of `auto` to introduce a new variable";
-            self.recover_stmt_local(lo, attrs.take_for_recovery().into(), msg, "let")?
+            self.recover_stmt_local(lo, attrs, msg, "let")?
         } else if self.is_kw_followed_by_ident(sym::var) {
             self.bump(); // `var`
             let msg = "write `let` instead of `var` to introduce a new variable";
-            self.recover_stmt_local(lo, attrs.take_for_recovery().into(), msg, "let")?
+            self.recover_stmt_local(lo, attrs, msg, "let")?
         } else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() {
             // We have avoided contextual keywords like `union`, items with `crate` visibility,
             // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
@@ -112,7 +99,7 @@ impl<'a> Parser<'a> {
         attrs: AttrWrapper,
         force_collect: ForceCollect,
     ) -> PResult<'a, Stmt> {
-        self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| {
+        let stmt = self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| {
             let path = this.parse_path(PathStyle::Expr)?;
 
             if this.eat(&token::Not) {
@@ -132,14 +119,22 @@ impl<'a> Parser<'a> {
             };
 
             let expr = this.with_res(Restrictions::STMT_EXPR, |this| {
-                let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs)?;
+                this.parse_dot_or_call_expr_with(expr, lo, attrs)
+            })?;
+            // `DUMMY_SP` will get overwritten later in this function
+            Ok((this.mk_stmt(rustc_span::DUMMY_SP, StmtKind::Expr(expr)), TrailingToken::None))
+        })?;
+
+        if let StmtKind::Expr(expr) = stmt.kind {
+            // Perform this outside of the `collect_tokens_trailing_token` closure,
+            // since our outer attributes do not apply to this part of the expression
+            let expr = self.with_res(Restrictions::STMT_EXPR, |this| {
                 this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr))
             })?;
-            Ok((
-                this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Expr(expr)),
-                TrailingToken::None,
-            ))
-        })
+            Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr)))
+        } else {
+            Ok(stmt)
+        }
     }
 
     /// Parses a statement macro `mac!(args)` provided a `path` representing `mac`.
@@ -183,7 +178,7 @@ impl<'a> Parser<'a> {
     fn recover_stmt_local(
         &mut self,
         lo: Span,
-        attrs: AttrVec,
+        attrs: AttrWrapper,
         msg: &str,
         sugg: &str,
     ) -> PResult<'a, Stmt> {
@@ -213,9 +208,15 @@ impl<'a> Parser<'a> {
         })
     }
 
-    fn recover_local_after_let(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, Stmt> {
-        let local = self.parse_local(attrs)?;
-        Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Local(local)))
+    fn recover_local_after_let(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a, Stmt> {
+        self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
+            let local = this.parse_local(attrs.into())?;
+            // FIXME - maybe capture semicolon in recovery?
+            Ok((
+                this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Local(local)),
+                TrailingToken::None,
+            ))
+        })
     }
 
     /// Parses a local variable declaration.
diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
index f55e2f777a2..59ef6052a60 100644
--- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
@@ -26,7 +26,7 @@
 //!   could not be instantiated because the current compilation session
 //!   contained no `DefId` for thing that had been removed.
 //!
-//! `DepNode` definition happens in `librustc_middle` with the `define_dep_nodes!()` macro.
+//! `DepNode` definition happens in `rustc_middle` with the `define_dep_nodes!()` macro.
 //! This macro defines the `DepKind` enum and a corresponding `DepConstructor` enum. The
 //! `DepConstructor` enum links a `DepKind` to the parameters that are needed at runtime in order
 //! to construct a valid `DepNode` fingerprint.
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 1377bb781d0..9321f11f659 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1031,7 +1031,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             }
 
             ItemKind::Static(ref ty, _, ref expr) | ItemKind::Const(_, ref ty, ref expr) => {
-                debug!("resolve_item ItemKind::Const");
                 self.with_item_rib(HasGenericParams::No, |this| {
                     this.visit_ty(ty);
                     if let Some(expr) = expr {
@@ -1597,6 +1596,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                         .try_resolve_as_non_binding(pat_src, pat, bmode, ident, has_sub)
                         .unwrap_or_else(|| self.fresh_binding(ident, pat.id, pat_src, bindings));
                     self.r.record_partial_res(pat.id, PartialRes::new(res));
+                    self.r.record_pat_span(pat.id, pat.span);
                 }
                 PatKind::TupleStruct(ref path, ref sub_patterns) => {
                     self.smart_resolve_path(
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index b89ad867f46..91bc8ab5ef4 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -72,8 +72,8 @@ impl RegionExt for Region {
         let def_id = hir_map.local_def_id(param.hir_id);
         let origin = LifetimeDefOrigin::from_param(param);
         debug!(
-            "Region::late: param={:?} depth={:?} def_id={:?} origin={:?}",
-            param, depth, def_id, origin,
+            "Region::late: idx={:?}, param={:?} depth={:?} def_id={:?} origin={:?}",
+            idx, param, depth, def_id, origin,
         );
         (
             param.name.normalize_to_macros_2_0(),
@@ -326,6 +326,10 @@ enum Scope<'a> {
         s: ScopeRef<'a>,
     },
 
+    TraitRefBoundary {
+        s: ScopeRef<'a>,
+    },
+
     Root,
 }
 
@@ -374,6 +378,7 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
                 .field("lifetimes", lifetimes)
                 .field("s", &"..")
                 .finish(),
+            Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
             Scope::Root => f.debug_struct("Root").finish(),
         }
     }
@@ -877,9 +882,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
             }
             hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
                 debug!(?bounds, ?lifetime, "TraitObject");
-                for bound in bounds {
-                    self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
-                }
+                let scope = Scope::TraitRefBoundary { s: self.scope };
+                self.with(scope, |_, this| {
+                    for bound in bounds {
+                        this.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
+                    }
+                });
                 match lifetime.name {
                     LifetimeName::Implicit => {
                         // For types like `dyn Foo`, we should
@@ -1058,9 +1066,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         };
                         this.with(scope, |_old_scope, this| {
                             this.visit_generics(generics);
-                            for bound in bounds {
-                                this.visit_param_bound(bound);
-                            }
+                            let scope = Scope::TraitRefBoundary { s: this.scope };
+                            this.with(scope, |_, this| {
+                                for bound in bounds {
+                                    this.visit_param_bound(bound);
+                                }
+                            })
                         });
                     });
                 } else {
@@ -1074,10 +1085,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         from_poly_trait_ref: false,
                     };
                     self.with(scope, |_old_scope, this| {
-                        this.visit_generics(generics);
-                        for bound in bounds {
-                            this.visit_param_bound(bound);
-                        }
+                        let scope = Scope::TraitRefBoundary { s: this.scope };
+                        this.with(scope, |_, this| {
+                            this.visit_generics(generics);
+                            for bound in bounds {
+                                this.visit_param_bound(bound);
+                            }
+                        })
                     });
                 }
             }
@@ -1131,13 +1145,16 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 };
                 self.with(scope, |old_scope, this| {
                     this.check_lifetime_params(old_scope, &generics.params);
-                    this.visit_generics(generics);
-                    for bound in bounds {
-                        this.visit_param_bound(bound);
-                    }
-                    if let Some(ty) = ty {
-                        this.visit_ty(ty);
-                    }
+                    let scope = Scope::TraitRefBoundary { s: this.scope };
+                    this.with(scope, |_, this| {
+                        this.visit_generics(generics);
+                        for bound in bounds {
+                            this.visit_param_bound(bound);
+                        }
+                        if let Some(ty) = ty {
+                            this.visit_ty(ty);
+                        }
+                    })
                 });
                 self.missing_named_lifetime_spots.pop();
             }
@@ -1197,8 +1214,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 };
                 self.with(scope, |old_scope, this| {
                     this.check_lifetime_params(old_scope, &generics.params);
-                    this.visit_generics(generics);
-                    this.visit_ty(ty);
+                    let scope = Scope::TraitRefBoundary { s: this.scope };
+                    this.with(scope, |_, this| {
+                        this.visit_generics(generics);
+                        this.visit_ty(ty);
+                    })
                 });
                 self.missing_named_lifetime_spots.pop();
             }
@@ -1292,29 +1312,31 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                             })
                             .unzip();
                     self.map.late_bound_vars.insert(bounded_ty.hir_id, binders.clone());
-                    if !lifetimes.is_empty() {
-                        let next_early_index = self.next_early_index();
-                        let scope = Scope::Binder {
-                            hir_id: bounded_ty.hir_id,
-                            lifetimes,
-                            s: self.scope,
-                            next_early_index,
-                            track_lifetime_uses: true,
-                            opaque_type_parent: false,
-                            from_poly_trait_ref: true,
-                        };
-                        let result = self.with(scope, |old_scope, this| {
-                            this.check_lifetime_params(old_scope, &bound_generic_params);
+                    let scope = Scope::TraitRefBoundary { s: self.scope };
+                    self.with(scope, |_, this| {
+                        if !lifetimes.is_empty() {
+                            let next_early_index = this.next_early_index();
+                            let scope = Scope::Binder {
+                                hir_id: bounded_ty.hir_id,
+                                lifetimes,
+                                s: this.scope,
+                                next_early_index,
+                                track_lifetime_uses: true,
+                                opaque_type_parent: false,
+                                from_poly_trait_ref: true,
+                            };
+                            this.with(scope, |old_scope, this| {
+                                this.check_lifetime_params(old_scope, &bound_generic_params);
+                                this.visit_ty(&bounded_ty);
+                                this.trait_ref_hack = Some(bounded_ty.hir_id);
+                                walk_list!(this, visit_param_bound, bounds);
+                                this.trait_ref_hack = None;
+                            })
+                        } else {
                             this.visit_ty(&bounded_ty);
-                            this.trait_ref_hack = Some(bounded_ty.hir_id);
                             walk_list!(this, visit_param_bound, bounds);
-                            this.trait_ref_hack = None;
-                        });
-                        result
-                    } else {
-                        self.visit_ty(&bounded_ty);
-                        walk_list!(self, visit_param_bound, bounds);
-                    }
+                        }
+                    })
                 }
                 &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
                     ref lifetime,
@@ -1438,6 +1460,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         scope = s;
                     }
 
+                    Scope::TraitRefBoundary { .. } => {
+                        // We should only see super trait lifetimes if there is a `Binder` above
+                        assert!(supertrait_lifetimes.is_empty());
+                        break vec![];
+                    }
+
                     Scope::Binder { hir_id, from_poly_trait_ref, .. } => {
                         if !from_poly_trait_ref {
                             // We should only see super trait lifetimes if there is a `Binder` above
@@ -1653,7 +1681,8 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body<'_>) {
                 | Scope::Elision { s, .. }
                 | Scope::ObjectLifetimeDefault { s, .. }
                 | Scope::TraitRefHackInner { s, .. }
-                | Scope::Supertrait { s, .. } => {
+                | Scope::Supertrait { s, .. }
+                | Scope::TraitRefBoundary { s, .. } => {
                     scope = s;
                 }
 
@@ -2261,7 +2290,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                 | Scope::Elision { s, .. }
                 | Scope::ObjectLifetimeDefault { s, .. }
                 | Scope::TraitRefHackInner { s, .. }
-                | Scope::Supertrait { s, .. } => scope = s,
+                | Scope::Supertrait { s, .. }
+                | Scope::TraitRefBoundary { s, .. } => scope = s,
             }
         }
     }
@@ -2311,6 +2341,24 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     break None;
                 }
 
+                Scope::TraitRefBoundary { s, .. } => {
+                    // We've exited nested poly trait refs; mark that we are no longer in nested trait refs.
+                    // We don't increase the late depth because this isn't a `Binder` scope.
+                    //
+                    // This came up in #83737, which boiled down to a case like this:
+                    //
+                    // ```
+                    // F: for<> Fn(&()) -> Box<dyn for<> Future<Output = ()> + Unpin>,
+                    //                         //  ^^^^^
+
+                    // ```
+                    //
+                    // Here, as we traverse upwards from the `dyn for<>` binder, we want to reset `in_poly_trait_ref`
+                    // to false, so that we avoid excess contaenation when we encounter the outer `for<>`  binder.
+                    in_poly_trait_ref = false;
+                    scope = s;
+                }
+
                 Scope::Binder { ref lifetimes, from_poly_trait_ref, s, .. } => {
                     match lifetime_ref.name {
                         LifetimeName::Param(param_name) => {
@@ -2332,6 +2380,17 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                         // We've already seen a binder that is a poly trait ref and this one is too,
                         // that means that they are nested and we are concatenating the bound vars;
                         // don't increase the late depth.
+                        //
+                        // This happens specifically with associated trait bounds like the following:
+                        //
+                        // ```
+                        // for<'a> T: Iterator<Item: for<'b> Foo<'a, 'b>>
+                        // ```
+                        //
+                        // In this case, as we traverse `for<'b>`, we would increment `late_depth` but
+                        // set `in_poly_trait_ref` to true. Then when we traverse `for<'a>`, we would
+                        // not increment `late_depth` again. (NB: Niko thinks this logic is actually
+                        // wrong.)
                         (true, true) => {}
                         // We've exited nested poly trait refs; add one to the late depth and mark
                         // that we are no longer in nested trait refs
@@ -2504,7 +2563,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                         | Scope::Elision { s, .. }
                         | Scope::ObjectLifetimeDefault { s, .. }
                         | Scope::TraitRefHackInner { s, .. }
-                        | Scope::Supertrait { s, .. } => {
+                        | Scope::Supertrait { s, .. }
+                        | Scope::TraitRefBoundary { s, .. } => {
                             scope = s;
                         }
                     }
@@ -2700,7 +2760,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                 Scope::Body { id, .. } => break id.hir_id,
                 Scope::ObjectLifetimeDefault { ref s, .. }
                 | Scope::Elision { ref s, .. }
-                | Scope::Supertrait { ref s, .. } => {
+                | Scope::Supertrait { ref s, .. }
+                | Scope::TraitRefBoundary { ref s, .. } => {
                     scope = *s;
                 }
                 Scope::Root => bug!("In fn_like_elision without appropriate scope above"),
@@ -2982,6 +3043,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                             self.have_bound_regions = true;
                         }
                         _ => {
+                            // FIXME(jackh726): nested trait refs?
                             self.lifetimes.insert(lifetime.shifted_out_to_binder(self.outer_index));
                         }
                     }
@@ -3047,6 +3109,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
 
                 Scope::Root => break None,
 
+                Scope::TraitRefBoundary { s, .. } => {
+                    // We've exited nested poly trait refs; mark that we are no longer in nested trait refs.
+                    // We don't increase the late depth because this isn't a `Binder` scope
+                    in_poly_trait_ref = false;
+                    scope = s;
+                }
+
                 Scope::Binder { s, ref lifetimes, from_poly_trait_ref, .. } => {
                     // collect named lifetimes for suggestions
                     for name in lifetimes.keys() {
@@ -3100,7 +3169,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                                         scope = s;
                                     }
                                     Scope::ObjectLifetimeDefault { ref s, .. }
-                                    | Scope::Elision { ref s, .. } => {
+                                    | Scope::Elision { ref s, .. }
+                                    | Scope::TraitRefBoundary { ref s, .. } => {
                                         scope = s;
                                     }
                                     _ => break,
@@ -3228,6 +3298,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         let mut scope = self.scope;
         let lifetime = loop {
             match *scope {
+                Scope::TraitRefBoundary { s, .. } => {
+                    // We've exited nested poly trait refs; mark that we are no longer in nested trait refs.
+                    // We don't increase the late depth because this isn't a `Binder` scope
+                    in_poly_trait_ref = false;
+                    scope = s;
+                }
+
                 Scope::Binder { s, from_poly_trait_ref, .. } => {
                     match (from_poly_trait_ref, in_poly_trait_ref) {
                         (true, false) => {
@@ -3380,7 +3457,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                 | Scope::Elision { s, .. }
                 | Scope::ObjectLifetimeDefault { s, .. }
                 | Scope::TraitRefHackInner { s, .. }
-                | Scope::Supertrait { s, .. } => {
+                | Scope::Supertrait { s, .. }
+                | Scope::TraitRefBoundary { s, .. } => {
                     old_scope = s;
                 }
 
@@ -3438,7 +3516,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
 
                 Scope::ObjectLifetimeDefault { s, .. }
                 | Scope::TraitRefHackInner { s, .. }
-                | Scope::Supertrait { s, .. } => scope = s,
+                | Scope::Supertrait { s, .. }
+                | Scope::TraitRefBoundary { s, .. } => scope = s,
             }
         }
     }
@@ -3492,13 +3571,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
 /// "Constrained" basically means that it appears in any type but
 /// not amongst the inputs to a projection. In other words, `<&'a
 /// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`.
+#[tracing::instrument(level = "debug", skip(map))]
 fn insert_late_bound_lifetimes(
     map: &mut NamedRegionMap,
     decl: &hir::FnDecl<'_>,
     generics: &hir::Generics<'_>,
 ) {
-    debug!("insert_late_bound_lifetimes(decl={:?}, generics={:?})", decl, generics);
-
     let mut constrained_by_input = ConstrainedCollector::default();
     for arg_ty in decl.inputs {
         constrained_by_input.visit_ty(arg_ty);
@@ -3507,7 +3585,7 @@ fn insert_late_bound_lifetimes(
     let mut appears_in_output = AllCollector::default();
     intravisit::walk_fn_ret_ty(&mut appears_in_output, &decl.output);
 
-    debug!("insert_late_bound_lifetimes: constrained_by_input={:?}", constrained_by_input.regions);
+    debug!(?constrained_by_input.regions);
 
     // Walk the lifetimes that appear in where clauses.
     //
@@ -3527,10 +3605,7 @@ fn insert_late_bound_lifetimes(
         }
     }
 
-    debug!(
-        "insert_late_bound_lifetimes: appears_in_where_clause={:?}",
-        appears_in_where_clause.regions
-    );
+    debug!(?appears_in_where_clause.regions);
 
     // Late bound regions are those that:
     // - appear in the inputs
@@ -3557,11 +3632,7 @@ fn insert_late_bound_lifetimes(
             continue;
         }
 
-        debug!(
-            "insert_late_bound_lifetimes: lifetime {:?} with id {:?} is late-bound",
-            param.name.ident(),
-            param.hir_id
-        );
+        debug!("lifetime {:?} with id {:?} is late-bound", param.name.ident(), param.hir_id);
 
         let inserted = map.late_bound.insert(param.hir_id);
         assert!(inserted, "visited lifetime {:?} twice", param.hir_id);
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 1c5f8996e1b..129954381c9 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -6,7 +6,7 @@
 //! Paths in macros, imports, expressions, types, patterns are resolved here.
 //! Label and lifetime names are resolved here as well.
 //!
-//! Type-relative name resolution (methods, fields, associated items) happens in `librustc_typeck`.
+//! Type-relative name resolution (methods, fields, associated items) happens in `rustc_typeck`.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(box_patterns)]
@@ -891,6 +891,10 @@ pub struct Resolver<'a> {
     /// "self-confirming" import resolutions during import validation.
     unusable_binding: Option<&'a NameBinding<'a>>,
 
+    // Spans for local variables found during pattern resolution.
+    // Used for suggestions during error reporting.
+    pat_span_map: NodeMap<Span>,
+
     /// Resolutions for nodes that have a single resolution.
     partial_res_map: NodeMap<PartialRes>,
     /// Resolutions for import nodes, which have multiple resolutions in different namespaces.
@@ -1270,6 +1274,7 @@ impl<'a> Resolver<'a> {
             last_import_segment: false,
             unusable_binding: None,
 
+            pat_span_map: Default::default(),
             partial_res_map: Default::default(),
             import_res_map: Default::default(),
             label_res_map: Default::default(),
@@ -1917,7 +1922,6 @@ impl<'a> Resolver<'a> {
                 return Some(LexicalScopeBinding::Item(binding));
             }
         }
-
         self.early_resolve_ident_in_lexical_scope(
             orig_ident,
             ScopeSet::Late(ns, module, record_used_id),
@@ -2394,7 +2398,59 @@ impl<'a> Resolver<'a> {
                             .next()
                             .map_or(false, |c| c.is_ascii_uppercase())
                         {
-                            (format!("use of undeclared type `{}`", ident), None)
+                            // Check whether the name refers to an item in the value namespace.
+                            let suggestion = if ribs.is_some() {
+                                let match_span = match self.resolve_ident_in_lexical_scope(
+                                    ident,
+                                    ValueNS,
+                                    parent_scope,
+                                    None,
+                                    path_span,
+                                    &ribs.unwrap()[ValueNS],
+                                ) {
+                                    // Name matches a local variable. For example:
+                                    // ```
+                                    // fn f() {
+                                    //     let Foo: &str = "";
+                                    //     println!("{}", Foo::Bar); // Name refers to local
+                                    //                               // variable `Foo`.
+                                    // }
+                                    // ```
+                                    Some(LexicalScopeBinding::Res(Res::Local(id))) => {
+                                        Some(*self.pat_span_map.get(&id).unwrap())
+                                    }
+
+                                    // Name matches item from a local name binding
+                                    // created by `use` declaration. For example:
+                                    // ```
+                                    // pub Foo: &str = "";
+                                    //
+                                    // mod submod {
+                                    //     use super::Foo;
+                                    //     println!("{}", Foo::Bar); // Name refers to local
+                                    //                               // binding `Foo`.
+                                    // }
+                                    // ```
+                                    Some(LexicalScopeBinding::Item(name_binding)) => {
+                                        Some(name_binding.span)
+                                    }
+                                    _ => None,
+                                };
+
+                                if let Some(span) = match_span {
+                                    Some((
+                                        vec![(span, String::from(""))],
+                                        format!("`{}` is defined here, but is not a type", ident),
+                                        Applicability::MaybeIncorrect,
+                                    ))
+                                } else {
+                                    None
+                                }
+                            } else {
+                                None
+                            };
+
+                            (format!("use of undeclared type `{}`", ident), suggestion)
                         } else {
                             (format!("use of undeclared crate or module `{}`", ident), None)
                         }
@@ -2805,6 +2861,11 @@ impl<'a> Resolver<'a> {
         }
     }
 
+    fn record_pat_span(&mut self, node: NodeId, span: Span) {
+        debug!("(recording pat) recording {:?} for {:?}", node, span);
+        self.pat_span_map.insert(node, span);
+    }
+
     fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool {
         vis.is_accessible_from(module.nearest_parent_mod, self)
     }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 75bd8880b34..b6b349e4a80 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -18,7 +18,7 @@ use rustc_serialize::json;
 
 use crate::parse::CrateConfig;
 use rustc_feature::UnstableFeatures;
-use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST};
+use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
 use rustc_span::source_map::{FileName, FilePathMapping};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::SourceFileHashAlgorithm;
@@ -1320,13 +1320,16 @@ pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
     };
 
     if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
-        early_error(
-            ErrorOutputType::default(),
-            &format!(
-                "edition {} is unstable and only available with -Z unstable-options.",
-                edition,
-            ),
-        )
+        let is_nightly = nightly_options::match_is_nightly_build(matches);
+        let msg = if !is_nightly {
+            format!(
+                "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
+                edition, LATEST_STABLE_EDITION
+            )
+        } else {
+            format!("edition {} is unstable and only available with -Z unstable-options", edition)
+        };
+        early_error(ErrorOutputType::default(), &msg)
     }
 
     edition
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 3488efacd11..cc2583be944 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -807,8 +807,11 @@ impl Session {
         // This is used to control the emission of the `uwtable` attribute on
         // LLVM functions.
         //
-        // At the very least, unwind tables are needed when compiling with
-        // `-C panic=unwind`.
+        // Unwind tables are needed when compiling with `-C panic=unwind`, but
+        // LLVM won't omit unwind tables unless the function is also marked as
+        // `nounwind`, so users are allowed to disable `uwtable` emission.
+        // Historically rustc always emits `uwtable` attributes by default, so
+        // even they can be disabled, they're still emitted by default.
         //
         // On some targets (including windows), however, exceptions include
         // other events such as illegal instructions, segfaults, etc. This means
@@ -821,13 +824,10 @@ impl Session {
         // If a target requires unwind tables, then they must be emitted.
         // Otherwise, we can defer to the `-C force-unwind-tables=<yes/no>`
         // value, if it is provided, or disable them, if not.
-        if self.panic_strategy() == PanicStrategy::Unwind {
-            true
-        } else if self.target.requires_uwtable {
-            true
-        } else {
-            self.opts.cg.force_unwind_tables.unwrap_or(self.target.default_uwtable)
-        }
+        self.target.requires_uwtable
+            || self.opts.cg.force_unwind_tables.unwrap_or(
+                self.panic_strategy() == PanicStrategy::Unwind || self.target.default_uwtable,
+            )
     }
 
     /// Returns the symbol name for the registrar function,
@@ -1483,13 +1483,6 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
 
     // Unwind tables cannot be disabled if the target requires them.
     if let Some(include_uwtables) = sess.opts.cg.force_unwind_tables {
-        if sess.panic_strategy() == PanicStrategy::Unwind && !include_uwtables {
-            sess.err(
-                "panic=unwind requires unwind tables, they cannot be disabled \
-                     with `-C force-unwind-tables=no`.",
-            );
-        }
-
         if sess.target.requires_uwtable && !include_uwtables {
             sess.err(
                 "target requires unwind tables, they cannot be disabled with \
diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs
index f3d33309124..e9d597d1ba6 100644
--- a/compiler/rustc_session/src/utils.rs
+++ b/compiler/rustc_session/src/utils.rs
@@ -1,7 +1,13 @@
+use crate::parse::ParseSess;
 use crate::session::Session;
+use rustc_ast::token::{self, DelimToken, Nonterminal, Token};
+use rustc_ast::tokenstream::CanSynthesizeMissingTokens;
+use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
 use rustc_data_structures::profiling::VerboseTimingGuard;
 use std::path::{Path, PathBuf};
 
+pub type NtToTokenstream = fn(&Nonterminal, &ParseSess, CanSynthesizeMissingTokens) -> TokenStream;
+
 impl Session {
     pub fn timer<'a>(&'a self, what: &'static str) -> VerboseTimingGuard<'a> {
         self.prof.verbose_generic_activity(what)
@@ -53,3 +59,52 @@ impl CanonicalizedPath {
         &self.original
     }
 }
+
+// FIXME: Find a better spot for this - it needs to be accessible from `rustc_ast_lowering`,
+// and needs to access `ParseSess
+pub struct FlattenNonterminals<'a> {
+    pub parse_sess: &'a ParseSess,
+    pub synthesize_tokens: CanSynthesizeMissingTokens,
+    pub nt_to_tokenstream: NtToTokenstream,
+}
+
+impl<'a> FlattenNonterminals<'a> {
+    pub fn process_token_stream(&mut self, tokens: TokenStream) -> TokenStream {
+        fn can_skip(stream: &TokenStream) -> bool {
+            stream.trees().all(|tree| match tree {
+                TokenTree::Token(token) => !matches!(token.kind, token::Interpolated(_)),
+                TokenTree::Delimited(_, _, inner) => can_skip(&inner),
+            })
+        }
+
+        if can_skip(&tokens) {
+            return tokens;
+        }
+
+        tokens.into_trees().flat_map(|tree| self.process_token_tree(tree).into_trees()).collect()
+    }
+
+    pub fn process_token_tree(&mut self, tree: TokenTree) -> TokenStream {
+        match tree {
+            TokenTree::Token(token) => self.process_token(token),
+            TokenTree::Delimited(span, delim, tts) => {
+                TokenTree::Delimited(span, delim, self.process_token_stream(tts)).into()
+            }
+        }
+    }
+
+    pub fn process_token(&mut self, token: Token) -> TokenStream {
+        match token.kind {
+            token::Interpolated(nt) => {
+                let tts = (self.nt_to_tokenstream)(&nt, self.parse_sess, self.synthesize_tokens);
+                TokenTree::Delimited(
+                    DelimSpan::from_single(token.span),
+                    DelimToken::NoDelim,
+                    self.process_token_stream(tts),
+                )
+                .into()
+            }
+            _ => TokenTree::Token(token).into(),
+        }
+    }
+}
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 03fe5bcd297..ee1d206095e 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1295,6 +1295,7 @@ symbols! {
         vreg,
         vreg_low16,
         warn,
+        wasm_abi,
         wasm_import_module,
         wasm_target_feature,
         while_let,
diff --git a/compiler/rustc_target/README.md b/compiler/rustc_target/README.md
index ac1e03385d1..ca72a89da5a 100644
--- a/compiler/rustc_target/README.md
+++ b/compiler/rustc_target/README.md
@@ -1,4 +1,4 @@
-`librustc_target` contains some very low-level details that are
+`rustc_target` contains some very low-level details that are
 specific to different compilation targets and so forth.
 
 For more information about how rustc works, see the [rustc dev guide].
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 395235399ea..d9d7d467d92 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -18,9 +18,7 @@ mod riscv;
 mod s390x;
 mod sparc;
 mod sparc64;
-mod wasm32;
-mod wasm32_bindgen_compat;
-mod wasm64;
+mod wasm;
 mod x86;
 mod x86_64;
 mod x86_win64;
@@ -648,12 +646,14 @@ impl<'a, Ty> FnAbi<'a, Ty> {
             "nvptx64" => nvptx64::compute_abi_info(self),
             "hexagon" => hexagon::compute_abi_info(self),
             "riscv32" | "riscv64" => riscv::compute_abi_info(cx, self),
-            "wasm32" => match cx.target_spec().os.as_str() {
-                "emscripten" | "wasi" => wasm32::compute_abi_info(cx, self),
-                _ => wasm32_bindgen_compat::compute_abi_info(self),
-            },
-            "asmjs" => wasm32::compute_abi_info(cx, self),
-            "wasm64" => wasm64::compute_abi_info(cx, self),
+            "wasm32" | "wasm64" => {
+                if cx.target_spec().adjust_abi(abi) == spec::abi::Abi::Wasm {
+                    wasm::compute_wasm_abi_info(self)
+                } else {
+                    wasm::compute_c_abi_info(cx, self)
+                }
+            }
+            "asmjs" => wasm::compute_c_abi_info(cx, self),
             a => return Err(format!("unrecognized arch \"{}\" in target specification", a)),
         }
 
diff --git a/compiler/rustc_target/src/abi/call/wasm32.rs b/compiler/rustc_target/src/abi/call/wasm.rs
index ff2c0e9bb6f..bf2c08bb166 100644
--- a/compiler/rustc_target/src/abi/call/wasm32.rs
+++ b/compiler/rustc_target/src/abi/call/wasm.rs
@@ -40,7 +40,8 @@ where
     }
 }
 
-pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
+/// The purpose of this ABI is to match the C ABI (aka clang) exactly.
+pub fn compute_c_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
 where
     Ty: TyAndLayoutMethods<'a, C> + Copy,
     C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
@@ -56,3 +57,27 @@ where
         classify_arg(cx, arg);
     }
 }
+
+/// The purpose of this ABI is for matching the WebAssembly standard. This
+/// intentionally diverges from the C ABI and is specifically crafted to take
+/// advantage of LLVM's support of multiple returns in WebAssembly.
+pub fn compute_wasm_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
+    if !fn_abi.ret.is_ignore() {
+        classify_ret(&mut fn_abi.ret);
+    }
+
+    for arg in &mut fn_abi.args {
+        if arg.is_ignore() {
+            continue;
+        }
+        classify_arg(arg);
+    }
+
+    fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
+        ret.extend_integer_width_to(32);
+    }
+
+    fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
+        arg.extend_integer_width_to(32);
+    }
+}
diff --git a/compiler/rustc_target/src/abi/call/wasm32_bindgen_compat.rs b/compiler/rustc_target/src/abi/call/wasm32_bindgen_compat.rs
deleted file mode 100644
index 59571fd9d48..00000000000
--- a/compiler/rustc_target/src/abi/call/wasm32_bindgen_compat.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-// This is not and has never been a correct C ABI for WebAssembly, but
-// for a long time this was the C ABI that Rust used. wasm-bindgen
-// depends on ABI details for this ABI and is incompatible with the
-// correct C ABI, so this ABI is being kept around until wasm-bindgen
-// can be fixed to work with the correct ABI. See #63649 for further
-// discussion.
-
-use crate::abi::call::{ArgAbi, FnAbi};
-
-fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
-    ret.extend_integer_width_to(32);
-}
-
-fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
-    arg.extend_integer_width_to(32);
-}
-
-pub fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
-    if !fn_abi.ret.is_ignore() {
-        classify_ret(&mut fn_abi.ret);
-    }
-
-    for arg in &mut fn_abi.args {
-        if arg.is_ignore() {
-            continue;
-        }
-        classify_arg(arg);
-    }
-}
diff --git a/compiler/rustc_target/src/abi/call/wasm64.rs b/compiler/rustc_target/src/abi/call/wasm64.rs
deleted file mode 100644
index 46d670d1689..00000000000
--- a/compiler/rustc_target/src/abi/call/wasm64.rs
+++ /dev/null
@@ -1,58 +0,0 @@
-use crate::abi::call::{ArgAbi, FnAbi, Uniform};
-use crate::abi::{HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods};
-
-fn unwrap_trivial_aggregate<'a, Ty, C>(cx: &C, val: &mut ArgAbi<'a, Ty>) -> bool
-where
-    Ty: TyAndLayoutMethods<'a, C> + Copy,
-    C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
-{
-    if val.layout.is_aggregate() {
-        if let Some(unit) = val.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()) {
-            let size = val.layout.size;
-            if unit.size == size {
-                val.cast_to(Uniform { unit, total: size });
-                return true;
-            }
-        }
-    }
-    false
-}
-
-fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>)
-where
-    Ty: TyAndLayoutMethods<'a, C> + Copy,
-    C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
-{
-    ret.extend_integer_width_to(64);
-    if ret.layout.is_aggregate() && !unwrap_trivial_aggregate(cx, ret) {
-        ret.make_indirect();
-    }
-}
-
-fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
-where
-    Ty: TyAndLayoutMethods<'a, C> + Copy,
-    C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
-{
-    arg.extend_integer_width_to(64);
-    if arg.layout.is_aggregate() && !unwrap_trivial_aggregate(cx, arg) {
-        arg.make_indirect_byval();
-    }
-}
-
-pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
-where
-    Ty: TyAndLayoutMethods<'a, C> + Copy,
-    C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
-{
-    if !fn_abi.ret.is_ignore() {
-        classify_ret(cx, &mut fn_abi.ret);
-    }
-
-    for arg in &mut fn_abi.args {
-        if arg.is_ignore() {
-            continue;
-        }
-        classify_arg(cx, arg);
-    }
-}
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index fb747dfcbd3..b54764b9e32 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -28,5 +28,5 @@ pub mod spec;
 
 /// Requirements for a `StableHashingContext` to be used in this crate.
 /// This is a hack to allow using the `HashStable_Generic` derive macro
-/// instead of implementing everything in librustc_middle.
+/// instead of implementing everything in `rustc_middle`.
 pub trait HashStableContext {}
diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs
index 17eb33b8f2e..a026a623f78 100644
--- a/compiler/rustc_target/src/spec/abi.rs
+++ b/compiler/rustc_target/src/spec/abi.rs
@@ -34,6 +34,7 @@ pub enum Abi {
     AvrInterrupt,
     AvrNonBlockingInterrupt,
     CCmseNonSecureCall,
+    Wasm,
 
     // Multiplatform / generic ABIs
     System { unwind: bool },
@@ -83,6 +84,7 @@ const AbiDatas: &[AbiData] = &[
         generic: false,
     },
     AbiData { abi: Abi::CCmseNonSecureCall, name: "C-cmse-nonsecure-call", generic: false },
+    AbiData { abi: Abi::Wasm, name: "wasm", generic: false },
     // Cross-platform ABIs
     AbiData { abi: Abi::System { unwind: false }, name: "system", generic: true },
     AbiData { abi: Abi::System { unwind: true }, name: "system-unwind", generic: true },
@@ -131,13 +133,14 @@ impl Abi {
             AvrInterrupt => 18,
             AvrNonBlockingInterrupt => 19,
             CCmseNonSecureCall => 20,
+            Wasm => 21,
             // Cross-platform ABIs
-            System { unwind: false } => 21,
-            System { unwind: true } => 22,
-            RustIntrinsic => 23,
-            RustCall => 24,
-            PlatformIntrinsic => 25,
-            Unadjusted => 26,
+            System { unwind: false } => 22,
+            System { unwind: true } => 23,
+            RustIntrinsic => 24,
+            RustCall => 25,
+            PlatformIntrinsic => 26,
+            Unadjusted => 27,
         };
         debug_assert!(
             AbiDatas
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 801cdd3ebe9..57b0a36e009 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1254,6 +1254,9 @@ pub struct TargetOptions {
     /// enabled can generated on this target, but the necessary supporting libraries are not
     /// distributed with the target, the sanitizer should still appear in this list for the target.
     pub supported_sanitizers: SanitizerSet,
+
+    /// If present it's a default value to use for adjusting the C ABI.
+    pub default_adjusted_cabi: Option<Abi>,
 }
 
 impl Default for TargetOptions {
@@ -1357,6 +1360,7 @@ impl Default for TargetOptions {
             has_thumb_interworking: false,
             split_debuginfo: SplitDebuginfo::Off,
             supported_sanitizers: SanitizerSet::empty(),
+            default_adjusted_cabi: None,
         }
     }
 }
@@ -1408,6 +1412,9 @@ impl Target {
                     Abi::C { unwind: false }
                 }
             }
+
+            Abi::C { unwind } => self.default_adjusted_cabi.unwrap_or(Abi::C { unwind }),
+
             abi => abi,
         }
     }
@@ -1742,6 +1749,16 @@ impl Target {
                     }
                 }
             } );
+            ($key_name:ident, Option<Abi>) => ( {
+                let name = (stringify!($key_name)).replace("_", "-");
+                obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                    match lookup_abi(s) {
+                        Some(abi) => base.$key_name = Some(abi),
+                        _ => return Some(Err(format!("'{}' is not a valid value for abi", s))),
+                    }
+                    Some(Ok(()))
+                })).unwrap_or(Ok(()))
+            } );
         }
 
         if let Some(s) = obj.find("target-endian").and_then(Json::as_string) {
@@ -1841,6 +1858,7 @@ impl Target {
         key!(has_thumb_interworking, bool);
         key!(split_debuginfo, SplitDebuginfo)?;
         key!(supported_sanitizers, SanitizerSet)?;
+        key!(default_adjusted_cabi, Option<Abi>)?;
 
         // NB: The old name is deprecated, but support for it is retained for
         // compatibility.
@@ -2081,6 +2099,10 @@ impl ToJson for Target {
         target_option_val!(split_debuginfo);
         target_option_val!(supported_sanitizers);
 
+        if let Some(abi) = self.default_adjusted_cabi {
+            d.insert("default-adjusted-cabi".to_string(), Abi::name(abi).to_json());
+        }
+
         if default.unsupported_abis != self.unsupported_abis {
             d.insert(
                 "unsupported-abis".to_string(),
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
index 0a88ee42629..834c4dbfc05 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
@@ -12,11 +12,23 @@
 
 use super::wasm_base;
 use super::{LinkerFlavor, LldFlavor, Target};
+use crate::spec::abi::Abi;
 
 pub fn target() -> Target {
     let mut options = wasm_base::options();
     options.os = "unknown".to_string();
     options.linker_flavor = LinkerFlavor::Lld(LldFlavor::Wasm);
+
+    // This is a default for backwards-compatibility with the original
+    // definition of this target oh-so-long-ago. Once the "wasm" ABI is
+    // stable and the wasm-bindgen project has switched to using it then there's
+    // no need for this and it can be removed.
+    //
+    // Currently this is the reason that this target's ABI is mismatched with
+    // clang's ABI. This means that, in the limit, you can't merge C and Rust
+    // code on this target due to this ABI mismatch.
+    options.default_adjusted_cabi = Some(Abi::Wasm);
+
     let clang_args = options.pre_link_args.entry(LinkerFlavor::Gcc).or_default();
 
     // Make sure clang uses LLD as its linker and is configured appropriately
diff --git a/compiler/rustc_trait_selection/src/traits/query/mod.rs b/compiler/rustc_trait_selection/src/traits/query/mod.rs
index 01f4f09e238..f6f42814d3f 100644
--- a/compiler/rustc_trait_selection/src/traits/query/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/mod.rs
@@ -3,7 +3,7 @@
 //! which makes a canonical query by replacing unbound inference
 //! variables and regions, so that results can be reused more broadly.
 //! The providers for the queries defined here can be found in
-//! `librustc_traits`.
+//! `rustc_traits`.
 
 pub mod dropck_outlives;
 pub mod evaluate_obligation;
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index 68a923a55eb..37538267b86 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -1440,9 +1440,8 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
         // as prior return coercions would not be relevant (#57664).
         let parent_id = fcx.tcx.hir().get_parent_node(id);
         let fn_decl = if let Some((expr, blk_id)) = expression {
-            pointing_at_return_type = fcx.suggest_mismatched_types_on_tail(
-                &mut err, expr, expected, found, cause.span, blk_id,
-            );
+            pointing_at_return_type =
+                fcx.suggest_mismatched_types_on_tail(&mut err, expr, expected, found, blk_id);
             let parent = fcx.tcx.hir().get(parent_id);
             if let (Some(cond_expr), true, false) = (
                 fcx.tcx.hir().get_if_cause(expr.hir_id),
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 60c40da8f31..991c2ba693d 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -603,7 +603,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         &cause,
                         &mut |mut err| {
                             self.suggest_mismatched_types_on_tail(
-                                &mut err, expr, ty, e_ty, cause.span, target_id,
+                                &mut err, expr, ty, e_ty, target_id,
                             );
                             if let Some(val) = ty_kind_suggestion(ty) {
                                 let label = destination
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index c87a808243d..b7583344845 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -41,15 +41,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expr: &'tcx hir::Expr<'tcx>,
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
-        cause_span: Span,
         blk_id: hir::HirId,
     ) -> bool {
         let expr = expr.peel_drop_temps();
         // If the expression is from an external macro, then do not suggest
         // adding a semicolon, because there's nowhere to put it.
         // See issue #81943.
-        if expr.can_have_side_effects() && !in_external_macro(self.tcx.sess, cause_span) {
-            self.suggest_missing_semicolon(err, expr, expected, cause_span);
+        if expr.can_have_side_effects() && !in_external_macro(self.tcx.sess, expr.span) {
+            self.suggest_missing_semicolon(err, expr, expected);
         }
         let mut pointing_at_return_type = false;
         if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
@@ -389,7 +388,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         err: &mut DiagnosticBuilder<'_>,
         expression: &'tcx hir::Expr<'tcx>,
         expected: Ty<'tcx>,
-        cause_span: Span,
     ) {
         if expected.is_unit() {
             // `BlockTailExpression` only relevant if the tail expr would be
@@ -404,7 +402,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     if expression.can_have_side_effects() =>
                 {
                     err.span_suggestion(
-                        cause_span.shrink_to_hi(),
+                        expression.span.shrink_to_hi(),
                         "consider using a semicolon here",
                         ";".to_string(),
                         Applicability::MachineApplicable,
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 04033905728..ef37fef0455 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -793,7 +793,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     /// use std::alloc::{Allocator, Layout, System};
     ///
     /// unsafe {
-    ///     let ptr = System.allocate(Layout::new::<i32>())?.as_mut_ptr();
+    ///     let ptr = System.allocate(Layout::new::<i32>())?.as_mut_ptr() as *mut i32;
     ///     // In general .write is required to avoid attempting to destruct
     ///     // the (uninitialized) previous contents of `ptr`, though for this
     ///     // simple example `*ptr = 5` would have worked as well.
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index 1dbf47206e4..67dd1d83415 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -982,6 +982,9 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
     #[stable(feature = "rust1", since = "1.0.0")]
     fn le(&self, other: &Rhs) -> bool {
         // Pattern `Some(Less | Eq)` optimizes worse than negating `None | Some(Greater)`.
+        // FIXME: The root cause was fixed upstream in LLVM with:
+        // https://github.com/llvm/llvm-project/commit/9bad7de9a3fb844f1ca2965f35d0c2a3d1e11775
+        // Revert this workaround once support for LLVM 12 gets dropped.
         !matches!(self.partial_cmp(other), None | Some(Greater))
     }
 
diff --git a/library/core/src/iter/adapters/peekable.rs b/library/core/src/iter/adapters/peekable.rs
index 43301444e3e..21386e28a96 100644
--- a/library/core/src/iter/adapters/peekable.rs
+++ b/library/core/src/iter/adapters/peekable.rs
@@ -233,7 +233,6 @@ impl<I: Iterator> Peekable<I> {
     /// Basic usage:
     ///
     /// ```
-    /// #![feature(peekable_peek_mut)]
     /// let mut iter = [1, 2, 3].iter().peekable();
     ///
     /// // Like with `peek()`, we can see into the future without advancing the iterator.
@@ -251,7 +250,7 @@ impl<I: Iterator> Peekable<I> {
     /// assert_eq!(iter.collect::<Vec<_>>(), vec![&5, &3]);
     /// ```
     #[inline]
-    #[unstable(feature = "peekable_peek_mut", issue = "78302")]
+    #[stable(feature = "peekable_peek_mut", since = "1.53.0")]
     pub fn peek_mut(&mut self) -> Option<&mut I::Item> {
         let iter = &mut self.iter;
         self.peeked.get_or_insert_with(|| iter.next()).as_mut()
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index d5d0c287992..abd44b47f98 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -937,20 +937,16 @@ pub trait Iterator {
         Enumerate::new(self)
     }
 
-    /// Creates an iterator which can use [`peek`] to look at the next element of
-    /// the iterator without consuming it.
+    /// Creates an iterator which can use the [`peek`] and [`peek_mut`] methods
+    /// to look at the next element of the iterator without consuming it. See
+    /// their documentation for more information.
     ///
-    /// Adds a [`peek`] method to an iterator. See its documentation for
-    /// more information.
+    /// Note that the underlying iterator is still advanced when [`peek`] or
+    /// [`peek_mut`] are called for the first time: In order to retrieve the
+    /// next element, [`next`] is called on the underlying iterator, hence any
+    /// side effects (i.e. anything other than fetching the next value) of
+    /// the [`next`] method will occur.
     ///
-    /// Note that the underlying iterator is still advanced when [`peek`] is
-    /// called for the first time: In order to retrieve the next element,
-    /// [`next`] is called on the underlying iterator, hence any side effects (i.e.
-    /// anything other than fetching the next value) of the [`next`] method
-    /// will occur.
-    ///
-    /// [`peek`]: Peekable::peek
-    /// [`next`]: Iterator::next
     ///
     /// # Examples
     ///
@@ -977,6 +973,32 @@ pub trait Iterator {
     /// assert_eq!(iter.peek(), None);
     /// assert_eq!(iter.next(), None);
     /// ```
+    ///
+    /// Using [`peek_mut`] to mutate the next item without advancing the
+    /// iterator:
+    ///
+    /// ```
+    /// let xs = [1, 2, 3];
+    ///
+    /// let mut iter = xs.iter().peekable();
+    ///
+    /// // `peek_mut()` lets us see into the future
+    /// assert_eq!(iter.peek_mut(), Some(&mut &1));
+    /// assert_eq!(iter.peek_mut(), Some(&mut &1));
+    /// assert_eq!(iter.next(), Some(&1));
+    ///
+    /// if let Some(mut p) = iter.peek_mut() {
+    ///     assert_eq!(*p, &2);
+    ///     // put a value into the iterator
+    ///     *p = &1000;
+    /// }
+    ///
+    /// // The value reappears as the iterator continues
+    /// assert_eq!(iter.collect::<Vec<_>>(), vec![&1000, &3]);
+    /// ```
+    /// [`peek`]: Peekable::peek
+    /// [`peek_mut`]: Peekable::peek_mut
+    /// [`next`]: Iterator::next
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn peekable(self) -> Peekable<Self>
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 013e98a8660..760b8d8cbb0 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -298,7 +298,8 @@ pub mod primitive;
     unused_imports,
     unsafe_op_in_unsafe_fn
 )]
-#[allow(rustdoc::non_autolinks)]
+#[cfg_attr(bootstrap, allow(rustdoc::non_autolinks))]
+#[cfg_attr(not(bootstrap), allow(rustdoc::bare_urls))]
 // FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_declarations is
 // merged. It currently cannot because bootstrap fails as the lint hasn't been defined yet.
 #[allow(clashing_extern_declarations)]
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index 64342de6341..4d7d47579ee 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -736,22 +736,22 @@ impl<T> MaybeUninit<T> {
     /// #![feature(maybe_uninit_ref)]
     /// use std::mem::MaybeUninit;
     ///
-    /// # unsafe extern "C" fn initialize_buffer(buf: *mut [u8; 2048]) { *buf = [0; 2048] }
+    /// # unsafe extern "C" fn initialize_buffer(buf: *mut [u8; 1024]) { *buf = [0; 1024] }
     /// # #[cfg(FALSE)]
     /// extern "C" {
     ///     /// Initializes *all* the bytes of the input buffer.
-    ///     fn initialize_buffer(buf: *mut [u8; 2048]);
+    ///     fn initialize_buffer(buf: *mut [u8; 1024]);
     /// }
     ///
-    /// let mut buf = MaybeUninit::<[u8; 2048]>::uninit();
+    /// let mut buf = MaybeUninit::<[u8; 1024]>::uninit();
     ///
     /// // Initialize `buf`:
     /// unsafe { initialize_buffer(buf.as_mut_ptr()); }
     /// // Now we know that `buf` has been initialized, so we could `.assume_init()` it.
-    /// // However, using `.assume_init()` may trigger a `memcpy` of the 2048 bytes.
+    /// // However, using `.assume_init()` may trigger a `memcpy` of the 1024 bytes.
     /// // To assert our buffer has been initialized without copying it, we upgrade
-    /// // the `&mut MaybeUninit<[u8; 2048]>` to a `&mut [u8; 2048]`:
-    /// let buf: &mut [u8; 2048] = unsafe {
+    /// // the `&mut MaybeUninit<[u8; 1024]>` to a `&mut [u8; 1024]`:
+    /// let buf: &mut [u8; 1024] = unsafe {
     ///     // SAFETY: `buf` has been initialized.
     ///     buf.assume_init_mut()
     /// };
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index b2de0e16a17..3d888299485 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -6,7 +6,7 @@
 //! as moving an object with pointers to itself will invalidate them, which could cause undefined
 //! behavior.
 //!
-//! At a high level, a [`Pin<P>`] ensures that the pointee of any pointer type
+//! At a high level, a <code>[Pin]\<P></code> ensures that the pointee of any pointer type
 //! `P` has a stable location in memory, meaning it cannot be moved elsewhere
 //! and its memory cannot be deallocated until it gets dropped. We say that the
 //! pointee is "pinned". Things get more subtle when discussing types that
@@ -14,13 +14,15 @@
 //! for more details.
 //!
 //! By default, all types in Rust are movable. Rust allows passing all types by-value,
-//! and common smart-pointer types such as [`Box<T>`] and `&mut T` allow replacing and
-//! moving the values they contain: you can move out of a [`Box<T>`], or you can use [`mem::swap`].
-//! [`Pin<P>`] wraps a pointer type `P`, so [`Pin`]`<`[`Box`]`<T>>` functions much like a regular
-//! [`Box<T>`]: when a [`Pin`]`<`[`Box`]`<T>>` gets dropped, so do its contents, and the memory gets
-//! deallocated. Similarly, [`Pin`]`<&mut T>` is a lot like `&mut T`. However, [`Pin<P>`] does
-//! not let clients actually obtain a [`Box<T>`] or `&mut T` to pinned data, which implies that you
-//! cannot use operations such as [`mem::swap`]:
+//! and common smart-pointer types such as <code>[Box]\<T></code> and <code>[&mut] T</code> allow
+//! replacing and moving the values they contain: you can move out of a <code>[Box]\<T></code>,
+//! or you can use [`mem::swap`]. <code>[Pin]\<P></code> wraps a pointer type `P`, so
+//! <code>[Pin]<[Box]\<T>></code> functions much like a regular <code>[Box]\<T></code>:
+//! when a <code>[Pin]<[Box]\<T>></code> gets dropped, so do its contents, and the memory gets
+//! deallocated. Similarly, <code>[Pin]<[&mut] T></code> is a lot like <code>[&mut] T</code>.
+//! However, <code>[Pin]\<P></code> does not let clients actually obtain a <code>[Box]\<T></code>
+//! or <code>[&mut] T</code> to pinned data, which implies that you cannot use operations such
+//! as [`mem::swap`]:
 //!
 //! ```
 //! use std::pin::Pin;
@@ -32,18 +34,18 @@
 //! }
 //! ```
 //!
-//! It is worth reiterating that [`Pin<P>`] does *not* change the fact that a Rust compiler
-//! considers all types movable. [`mem::swap`] remains callable for any `T`. Instead, [`Pin<P>`]
-//! prevents certain *values* (pointed to by pointers wrapped in [`Pin<P>`]) from being
-//! moved by making it impossible to call methods that require `&mut T` on them
-//! (like [`mem::swap`]).
-//!
-//! [`Pin<P>`] can be used to wrap any pointer type `P`, and as such it interacts with
-//! [`Deref`] and [`DerefMut`]. A [`Pin<P>`] where `P: Deref` should be considered
-//! as a "`P`-style pointer" to a pinned `P::Target` -- so, a [`Pin`]`<`[`Box`]`<T>>` is
-//! an owned pointer to a pinned `T`, and a [`Pin`]`<`[`Rc`]`<T>>` is a reference-counted
-//! pointer to a pinned `T`.
-//! For correctness, [`Pin<P>`] relies on the implementations of [`Deref`] and
+//! It is worth reiterating that <code>[Pin]\<P></code> does *not* change the fact that a Rust
+//! compiler considers all types movable. [`mem::swap`] remains callable for any `T`. Instead,
+//! <code>[Pin]\<P></code> prevents certain *values* (pointed to by pointers wrapped in
+//! <code>[Pin]\<P></code>) from being moved by making it impossible to call methods that require
+//! <code>[&mut] T</code> on them (like [`mem::swap`]).
+//!
+//! <code>[Pin]\<P></code> can be used to wrap any pointer type `P`, and as such it interacts with
+//! [`Deref`] and [`DerefMut`]. A <code>[Pin]\<P></code> where <code>P: [Deref]</code> should be
+//! considered as a "`P`-style pointer" to a pinned <code>P::[Target]</code> – so, a
+//! <code>[Pin]<[Box]\<T>></code> is an owned pointer to a pinned `T`, and a
+//! <code>[Pin]<[Rc]\<T>></code> is a reference-counted pointer to a pinned `T`.
+//! For correctness, <code>[Pin]\<P></code> relies on the implementations of [`Deref`] and
 //! [`DerefMut`] not to move out of their `self` parameter, and only ever to
 //! return a pointer to pinned data when they are called on a pinned pointer.
 //!
@@ -53,19 +55,19 @@
 //! rely on having a stable address. This includes all the basic types (like
 //! [`bool`], [`i32`], and references) as well as types consisting solely of these
 //! types. Types that do not care about pinning implement the [`Unpin`]
-//! auto-trait, which cancels the effect of [`Pin<P>`]. For `T: Unpin`,
-//! [`Pin`]`<`[`Box`]`<T>>` and [`Box<T>`] function identically, as do [`Pin`]`<&mut T>` and
-//! `&mut T`.
+//! auto-trait, which cancels the effect of <code>[Pin]\<P></code>. For <code>T: [Unpin]</code>,
+//! <code>[Pin]<[Box]\<T>></code> and <code>[Box]\<T></code> function identically, as do
+//! <code>[Pin]<[&mut] T></code> and <code>[&mut] T</code>.
 //!
-//! Note that pinning and [`Unpin`] only affect the pointed-to type `P::Target`, not the pointer
-//! type `P` itself that got wrapped in [`Pin<P>`]. For example, whether or not [`Box<T>`] is
-//! [`Unpin`] has no effect on the behavior of [`Pin`]`<`[`Box`]`<T>>` (here, `T` is the
-//! pointed-to type).
+//! Note that pinning and [`Unpin`] only affect the pointed-to type <code>P::[Target]</code>,
+//! not the pointer type `P` itself that got wrapped in <code>[Pin]\<P></code>. For example,
+//! whether or not <code>[Box]\<T></code> is [`Unpin`] has no effect on the behavior of
+//! <code>[Pin]<[Box]\<T>></code> (here, `T` is the pointed-to type).
 //!
 //! # Example: self-referential struct
 //!
 //! Before we go into more details to explain the guarantees and choices
-//! associated with `Pin<T>`, we discuss some examples for how it might be used.
+//! associated with <code>[Pin]\<P></code>, we discuss some examples for how it might be used.
 //! Feel free to [skip to where the theoretical discussion continues](#drop-guarantee).
 //!
 //! ```rust
@@ -129,7 +131,7 @@
 //!
 //! To make this work, every element has pointers to its predecessor and successor in
 //! the list. Elements can only be added when they are pinned, because moving the elements
-//! around would invalidate the pointers. Moreover, the [`Drop`] implementation of a linked
+//! around would invalidate the pointers. Moreover, the [`Drop`][Drop] implementation of a linked
 //! list element will patch the pointers of its predecessor and successor to remove itself
 //! from the list.
 //!
@@ -149,8 +151,8 @@
 //! when [`drop`] is called*.  Only once [`drop`] returns or panics, the memory may be reused.
 //!
 //! Memory can be "invalidated" by deallocation, but also by
-//! replacing a [`Some(v)`] by [`None`], or calling [`Vec::set_len`] to "kill" some elements
-//! off of a vector. It can be repurposed by using [`ptr::write`] to overwrite it without
+//! replacing a <code>[Some]\(v)</code> by [`None`], or calling [`Vec::set_len`] to "kill" some
+//! elements off of a vector. It can be repurposed by using [`ptr::write`] to overwrite it without
 //! calling the destructor first. None of this is allowed for pinned data without calling [`drop`].
 //!
 //! This is exactly the kind of guarantee that the intrusive linked list from the previous
@@ -158,25 +160,25 @@
 //!
 //! Notice that this guarantee does *not* mean that memory does not leak! It is still
 //! completely okay not ever to call [`drop`] on a pinned element (e.g., you can still
-//! call [`mem::forget`] on a [`Pin`]`<`[`Box`]`<T>>`). In the example of the doubly-linked
+//! call [`mem::forget`] on a <code>[Pin]<[Box]\<T>></code>). In the example of the doubly-linked
 //! list, that element would just stay in the list. However you may not free or reuse the storage
 //! *without calling [`drop`]*.
 //!
 //! # `Drop` implementation
 //!
 //! If your type uses pinning (such as the two examples above), you have to be careful
-//! when implementing [`Drop`]. The [`drop`] function takes `&mut self`, but this
+//! when implementing [`Drop`][Drop]. The [`drop`] function takes <code>[&mut] self</code>, but this
 //! is called *even if your type was previously pinned*! It is as if the
 //! compiler automatically called [`Pin::get_unchecked_mut`].
 //!
 //! This can never cause a problem in safe code because implementing a type that
 //! relies on pinning requires unsafe code, but be aware that deciding to make
 //! use of pinning in your type (for example by implementing some operation on
-//! [`Pin`]`<&Self>` or [`Pin`]`<&mut Self>`) has consequences for your [`Drop`]
-//! implementation as well: if an element of your type could have been pinned,
-//! you must treat [`Drop`] as implicitly taking [`Pin`]`<&mut Self>`.
+//! <code>[Pin]<[&]Self></code> or <code>[Pin]<[&mut] Self></code>) has consequences for your
+//! [`Drop`][Drop]implementation as well: if an element of your type could have been pinned,
+//! you must treat [`Drop`][Drop] as implicitly taking <code>[Pin]<[&mut] Self></code>.
 //!
-//! For example, you could implement `Drop` as follows:
+//! For example, you could implement [`Drop`][Drop] as follows:
 //!
 //! ```rust,no_run
 //! # use std::pin::Pin;
@@ -204,18 +206,18 @@
 //! # Projections and Structural Pinning
 //!
 //! When working with pinned structs, the question arises how one can access the
-//! fields of that struct in a method that takes just [`Pin`]`<&mut Struct>`.
+//! fields of that struct in a method that takes just <code>[Pin]<[&mut] Struct></code>.
 //! The usual approach is to write helper methods (so called *projections*)
-//! that turn [`Pin`]`<&mut Struct>` into a reference to the field, but what
-//! type should that reference have? Is it [`Pin`]`<&mut Field>` or `&mut Field`?
+//! that turn <code>[Pin]<[&mut] Struct></code> into a reference to the field, but what type should
+//! that reference have? Is it <code>[Pin]<[&mut] Field></code> or <code>[&mut] Field</code>?
 //! The same question arises with the fields of an `enum`, and also when considering
-//! container/wrapper types such as [`Vec<T>`], [`Box<T>`], or [`RefCell<T>`].
-//! (This question applies to both mutable and shared references, we just
-//! use the more common case of mutable references here for illustration.)
+//! container/wrapper types such as <code>[Vec]\<T></code>, <code>[Box]\<T></code>,
+//! or <code>[RefCell]\<T></code>. (This question applies to both mutable and shared references,
+//! we just use the more common case of mutable references here for illustration.)
 //!
-//! It turns out that it is actually up to the author of the data structure
-//! to decide whether the pinned projection for a particular field turns
-//! [`Pin`]`<&mut Struct>` into [`Pin`]`<&mut Field>` or `&mut Field`. There are some
+//! It turns out that it is actually up to the author of the data structure to decide whether
+//! the pinned projection for a particular field turns <code>[Pin]<[&mut] Struct></code>
+//! into <code>[Pin]<[&mut] Field></code> or <code>[&mut] Field</code>. There are some
 //! constraints though, and the most important constraint is *consistency*:
 //! every field can be *either* projected to a pinned reference, *or* have
 //! pinning removed as part of the projection. If both are done for the same field,
@@ -230,12 +232,12 @@
 //! ## Pinning *is not* structural for `field`
 //!
 //! It may seem counter-intuitive that the field of a pinned struct might not be pinned,
-//! but that is actually the easiest choice: if a [`Pin`]`<&mut Field>` is never created,
+//! but that is actually the easiest choice: if a <code>[Pin]<[&mut] Field></code> is never created,
 //! nothing can go wrong! So, if you decide that some field does not have structural pinning,
 //! all you have to ensure is that you never create a pinned reference to that field.
 //!
 //! Fields without structural pinning may have a projection method that turns
-//! [`Pin`]`<&mut Struct>` into `&mut Field`:
+//! <code>[Pin]<[&mut] Struct></code> into <code>[&mut] Field</code>:
 //!
 //! ```rust,no_run
 //! # use std::pin::Pin;
@@ -249,16 +251,16 @@
 //! }
 //! ```
 //!
-//! You may also `impl Unpin for Struct` *even if* the type of `field`
+//! You may also <code>impl [Unpin] for Struct</code> *even if* the type of `field`
 //! is not [`Unpin`]. What that type thinks about pinning is not relevant
-//! when no [`Pin`]`<&mut Field>` is ever created.
+//! when no <code>[Pin]<[&mut] Field></code> is ever created.
 //!
 //! ## Pinning *is* structural for `field`
 //!
 //! The other option is to decide that pinning is "structural" for `field`,
 //! meaning that if the struct is pinned then so is the field.
 //!
-//! This allows writing a projection that creates a [`Pin`]`<&mut Field>`, thus
+//! This allows writing a projection that creates a <code>[Pin]<[&mut] Field></code>, thus
 //! witnessing that the field is pinned:
 //!
 //! ```rust,no_run
@@ -278,34 +280,36 @@
 //! 1.  The struct must only be [`Unpin`] if all the structural fields are
 //!     [`Unpin`]. This is the default, but [`Unpin`] is a safe trait, so as the author of
 //!     the struct it is your responsibility *not* to add something like
-//!     `impl<T> Unpin for Struct<T>`. (Notice that adding a projection operation
+//!     <code>impl\<T> [Unpin] for Struct\<T></code>. (Notice that adding a projection operation
 //!     requires unsafe code, so the fact that [`Unpin`] is a safe trait does not break
-//!     the principle that you only have to worry about any of this if you use `unsafe`.)
+//!     the principle that you only have to worry about any of this if you use [`unsafe`].)
 //! 2.  The destructor of the struct must not move structural fields out of its argument. This
-//!     is the exact point that was raised in the [previous section][drop-impl]: `drop` takes
-//!     `&mut self`, but the struct (and hence its fields) might have been pinned before.
-//!     You have to guarantee that you do not move a field inside your [`Drop`] implementation.
-//!     In particular, as explained previously, this means that your struct must *not*
-//!     be `#[repr(packed)]`.
+//!     is the exact point that was raised in the [previous section][drop-impl]: [`drop`] takes
+//!     <code>[&mut] self</code>, but the struct (and hence its fields) might have been pinned
+//!     before. You have to guarantee that you do not move a field inside your [`Drop`][Drop]
+//!     implementation. In particular, as explained previously, this means that your struct
+//!     must *not* be `#[repr(packed)]`.
 //!     See that section for how to write [`drop`] in a way that the compiler can help you
 //!     not accidentally break pinning.
 //! 3.  You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]:
 //!     once your struct is pinned, the memory that contains the
 //!     content is not overwritten or deallocated without calling the content's destructors.
-//!     This can be tricky, as witnessed by [`VecDeque<T>`]: the destructor of [`VecDeque<T>`]
-//!     can fail to call [`drop`] on all elements if one of the destructors panics. This violates
-//!     the [`Drop`] guarantee, because it can lead to elements being deallocated without
-//!     their destructor being called. ([`VecDeque<T>`] has no pinning projections, so this
+//!     This can be tricky, as witnessed by <code>[VecDeque]\<T></code>: the destructor of
+//!     <code>[VecDeque]\<T></code> can fail to call [`drop`] on all elements if one of the
+//!     destructors panics. This violates the [`Drop`][Drop] guarantee, because it can lead to
+//!     elements being deallocated without their destructor being called.
+//!     (<code>[VecDeque]\<T></code> has no pinning projections, so this
 //!     does not cause unsoundness.)
 //! 4.  You must not offer any other operations that could lead to data being moved out of
 //!     the structural fields when your type is pinned. For example, if the struct contains an
-//!     [`Option<T>`] and there is a `take`-like operation with type
-//!     `fn(Pin<&mut Struct<T>>) -> Option<T>`,
-//!     that operation can be used to move a `T` out of a pinned `Struct<T>` -- which means
+//!     <code>[Option]\<T></code> and there is a [`take`][Option::take]-like operation with type
+//!     <code>fn([Pin]<[&mut] Struct\<T>>) -> [Option]\<T></code>,
+//!     that operation can be used to move a `T` out of a pinned `Struct<T>` – which means
 //!     pinning cannot be structural for the field holding this data.
 //!
-//!     For a more complex example of moving data out of a pinned type, imagine if [`RefCell<T>`]
-//!     had a method `fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T>`.
+//!     For a more complex example of moving data out of a pinned type,
+//!     imagine if <code>[RefCell]\<T></code> had a method
+//!     <code>fn get_pin_mut(self: [Pin]<[&mut] Self>) -> [Pin]<[&mut] T></code>.
 //!     Then we could do the following:
 //!     ```compile_fail
 //!     fn exploit_ref_cell<T>(rc: Pin<&mut RefCell<T>>) {
@@ -315,60 +319,65 @@
 //!         let content = &mut *b; // And here we have `&mut T` to the same data.
 //!     }
 //!     ```
-//!     This is catastrophic, it means we can first pin the content of the [`RefCell<T>`]
-//!     (using `RefCell::get_pin_mut`) and then move that content using the mutable
-//!     reference we got later.
+//!     This is catastrophic, it means we can first pin the content of the
+//!     <code>[RefCell]\<T></code> (using <code>[RefCell]::get_pin_mut</code>) and then move that
+//!     content using the mutable reference we got later.
 //!
 //! ## Examples
 //!
-//! For a type like [`Vec<T>`], both possibilities (structural pinning or not) make sense.
-//! A [`Vec<T>`] with structural pinning could have `get_pin`/`get_pin_mut` methods to get
-//! pinned references to elements. However, it could *not* allow calling
-//! [`pop`][Vec::pop] on a pinned [`Vec<T>`] because that would move the (structurally pinned)
-//! contents! Nor could it allow [`push`][Vec::push], which might reallocate and thus also move the
-//! contents.
+//! For a type like <code>[Vec]\<T></code>, both possibilities (structural pinning or not) make
+//! sense. A <code>[Vec]\<T></code> with structural pinning could have `get_pin`/`get_pin_mut`
+//! methods to get pinned references to elements. However, it could *not* allow calling
+//! [`pop`][Vec::pop] on a pinned <code>[Vec]\<T></code> because that would move the (structurally
+//! pinned) contents! Nor could it allow [`push`][Vec::push], which might reallocate and thus also
+//! move the contents.
 //!
-//! A [`Vec<T>`] without structural pinning could `impl<T> Unpin for Vec<T>`, because the contents
-//! are never pinned and the [`Vec<T>`] itself is fine with being moved as well.
+//! A <code>[Vec]\<T></code> without structural pinning could
+//! <code>impl\<T> [Unpin] for [Vec]\<T></code>, because the contents are never pinned
+//! and the <code>[Vec]\<T></code> itself is fine with being moved as well.
 //! At that point pinning just has no effect on the vector at all.
 //!
 //! In the standard library, pointer types generally do not have structural pinning,
-//! and thus they do not offer pinning projections. This is why `Box<T>: Unpin` holds for all `T`.
-//! It makes sense to do this for pointer types, because moving the `Box<T>`
-//! does not actually move the `T`: the [`Box<T>`] can be freely movable (aka `Unpin`) even if
-//! the `T` is not. In fact, even [`Pin`]`<`[`Box`]`<T>>` and [`Pin`]`<&mut T>` are always
-//! [`Unpin`] themselves, for the same reason: their contents (the `T`) are pinned, but the
-//! pointers themselves can be moved without moving the pinned data. For both [`Box<T>`] and
-//! [`Pin`]`<`[`Box`]`<T>>`, whether the content is pinned is entirely independent of whether the
+//! and thus they do not offer pinning projections. This is why <code>[Box]\<T>: [Unpin]</code>
+//! holds for all `T`. It makes sense to do this for pointer types, because moving the
+//! <code>[Box]\<T></code> does not actually move the `T`: the <code>[Box]\<T></code> can be freely
+//! movable (aka [`Unpin`]) even if the `T` is not. In fact, even <code>[Pin]<[Box]\<T>></code> and
+//! <code>[Pin]<[&mut] T></code> are always [`Unpin`] themselves, for the same reason:
+//! their contents (the `T`) are pinned, but the pointers themselves can be moved without moving
+//! the pinned data. For both <code>[Box]\<T></code> and <code>[Pin]<[Box]\<T>></code>,
+//! whether the content is pinned is entirely independent of whether the
 //! pointer is pinned, meaning pinning is *not* structural.
 //!
 //! When implementing a [`Future`] combinator, you will usually need structural pinning
 //! for the nested futures, as you need to get pinned references to them to call [`poll`].
 //! But if your combinator contains any other data that does not need to be pinned,
 //! you can make those fields not structural and hence freely access them with a
-//! mutable reference even when you just have [`Pin`]`<&mut Self>` (such as in your own
+//! mutable reference even when you just have <code>[Pin]<[&mut] Self></code> (such as in your own
 //! [`poll`] implementation).
 //!
-//! [`Deref`]: crate::ops::Deref
-//! [`DerefMut`]: crate::ops::DerefMut
-//! [`mem::swap`]: crate::mem::swap
-//! [`mem::forget`]: crate::mem::forget
-//! [`Box<T>`]: ../../std/boxed/struct.Box.html
-//! [`Vec<T>`]: ../../std/vec/struct.Vec.html
-//! [`Vec::set_len`]: ../../std/vec/struct.Vec.html#method.set_len
-//! [`Box`]: ../../std/boxed/struct.Box.html
-//! [Vec::pop]: ../../std/vec/struct.Vec.html#method.pop
-//! [Vec::push]: ../../std/vec/struct.Vec.html#method.push
-//! [`Rc`]: ../../std/rc/struct.Rc.html
-//! [`RefCell<T>`]: crate::cell::RefCell
-//! [`drop`]: Drop::drop
-//! [`VecDeque<T>`]: ../../std/collections/struct.VecDeque.html
-//! [`Some(v)`]: Some
-//! [`ptr::write`]: crate::ptr::write
-//! [`Future`]: crate::future::Future
+//! [Deref]: crate::ops::Deref "ops::Deref"
+//! [`Deref`]: crate::ops::Deref "ops::Deref"
+//! [Target]: crate::ops::Deref::Target "ops::Deref::Target"
+//! [`DerefMut`]: crate::ops::DerefMut "ops::DerefMut"
+//! [`mem::swap`]: crate::mem::swap "mem::swap"
+//! [`mem::forget`]: crate::mem::forget "mem::forget"
+//! [Vec]: ../../std/vec/struct.Vec.html "Vec"
+//! [`Vec::set_len`]: ../../std/vec/struct.Vec.html#method.set_len "Vec::set_len"
+//! [Box]: ../../std/boxed/struct.Box.html "Box"
+//! [Vec::pop]: ../../std/vec/struct.Vec.html#method.pop "Vec::pop"
+//! [Vec::push]: ../../std/vec/struct.Vec.html#method.push "Vec::push"
+//! [Rc]: ../../std/rc/struct.Rc.html "rc::Rc"
+//! [RefCell]: crate::cell::RefCell "cell::RefCell"
+//! [`drop`]: Drop::drop "Drop::drop"
+//! [VecDeque]: ../../std/collections/struct.VecDeque.html "collections::VecDeque"
+//! [`ptr::write`]: crate::ptr::write "ptr::write"
+//! [`Future`]: crate::future::Future "future::Future"
 //! [drop-impl]: #drop-implementation
 //! [drop-guarantee]: #drop-guarantee
-//! [`poll`]: crate::future::Future::poll
+//! [`poll`]: crate::future::Future::poll "future::Future::poll"
+//! [&]: ../../std/primitive.reference.html "shared reference"
+//! [&mut]: ../../std/primitive.reference.html "mutable reference"
+//! [`unsafe`]: ../../std/keyword.unsafe.html "keyword unsafe"
 
 #![stable(feature = "pin", since = "1.33.0")]
 
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index f18387d020d..4571ba154ea 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -724,7 +724,7 @@ impl<T: ?Sized> *const T {
     /// #![feature(set_ptr_value)]
     /// # use core::fmt::Debug;
     /// let arr: [i32; 3] = [1, 2, 3];
-    /// let mut ptr = &arr[0] as *const dyn Debug;
+    /// let mut ptr = arr.as_ptr() as *const dyn Debug;
     /// let thin = ptr as *const u8;
     /// unsafe {
     ///     ptr = ptr.set_ptr_value(thin.add(8));
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 3c6f1978283..ba08823e343 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -830,7 +830,7 @@ impl<T: ?Sized> *mut T {
     /// #![feature(set_ptr_value)]
     /// # use core::fmt::Debug;
     /// let mut arr: [i32; 3] = [1, 2, 3];
-    /// let mut ptr = &mut arr[0] as *mut dyn Debug;
+    /// let mut ptr = arr.as_mut_ptr() as *mut dyn Debug;
     /// let thin = ptr as *mut u8;
     /// unsafe {
     ///     ptr = ptr.set_ptr_value(thin.add(8));
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index bf70b28579c..9085d5c7b97 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -78,7 +78,7 @@
 //! ```
 //! use std::sync::Arc;
 //! use std::sync::atomic::{AtomicUsize, Ordering};
-//! use std::thread;
+//! use std::{hint, thread};
 //!
 //! fn main() {
 //!     let spinlock = Arc::new(AtomicUsize::new(1));
@@ -89,7 +89,9 @@
 //!     });
 //!
 //!     // Wait for the other thread to release the lock
-//!     while spinlock.load(Ordering::SeqCst) != 0 {}
+//!     while spinlock.load(Ordering::SeqCst) != 0 {
+//!         hint::spin_loop();
+//!     }
 //!
 //!     if let Err(panic) = thread.join() {
 //!         println!("Thread had an error: {:?}", panic);
@@ -898,8 +900,10 @@ impl<T> AtomicPtr<T> {
     /// ```
     /// use std::sync::atomic::{AtomicPtr, Ordering};
     ///
-    /// let mut atomic_ptr = AtomicPtr::new(&mut 10);
-    /// *atomic_ptr.get_mut() = &mut 5;
+    /// let mut data = 10;
+    /// let mut atomic_ptr = AtomicPtr::new(&mut data);
+    /// let mut other_data = 5;
+    /// *atomic_ptr.get_mut() = &mut other_data;
     /// assert_eq!(unsafe { *atomic_ptr.load(Ordering::SeqCst) }, 5);
     /// ```
     #[inline]
@@ -916,9 +920,11 @@ impl<T> AtomicPtr<T> {
     /// #![feature(atomic_from_mut)]
     /// use std::sync::atomic::{AtomicPtr, Ordering};
     ///
-    /// let mut some_ptr = &mut 123 as *mut i32;
+    /// let mut data = 123;
+    /// let mut some_ptr = &mut data as *mut i32;
     /// let a = AtomicPtr::from_mut(&mut some_ptr);
-    /// a.store(&mut 456, Ordering::Relaxed);
+    /// let mut other_data = 456;
+    /// a.store(&mut other_data, Ordering::Relaxed);
     /// assert_eq!(unsafe { *some_ptr }, 456);
     /// ```
     #[inline]
@@ -944,7 +950,8 @@ impl<T> AtomicPtr<T> {
     /// ```
     /// use std::sync::atomic::AtomicPtr;
     ///
-    /// let atomic_ptr = AtomicPtr::new(&mut 5);
+    /// let mut data = 5;
+    /// let atomic_ptr = AtomicPtr::new(&mut data);
     /// assert_eq!(unsafe { *atomic_ptr.into_inner() }, 5);
     /// ```
     #[inline]
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index a96520680e3..7dc6e220c08 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -66,7 +66,6 @@
 #![feature(unwrap_infallible)]
 #![feature(option_result_unwrap_unchecked)]
 #![feature(result_into_ok_or_err)]
-#![feature(peekable_peek_mut)]
 #![feature(ptr_metadata)]
 #![feature(once_cell)]
 #![feature(unsized_tuple_coercion)]
diff --git a/library/panic_abort/Cargo.toml b/library/panic_abort/Cargo.toml
index caa89aa30d0..bdab664cd64 100644
--- a/library/panic_abort/Cargo.toml
+++ b/library/panic_abort/Cargo.toml
@@ -13,6 +13,7 @@ bench = false
 doc = false
 
 [dependencies]
+alloc = { path = "../alloc" }
 cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] }
 core = { path = "../core" }
 libc = { version = "0.2", default-features = false }
diff --git a/library/panic_abort/src/android.rs b/library/panic_abort/src/android.rs
new file mode 100644
index 00000000000..34d77502eab
--- /dev/null
+++ b/library/panic_abort/src/android.rs
@@ -0,0 +1,49 @@
+use alloc::string::String;
+use core::mem::transmute;
+use core::panic::BoxMeUp;
+use core::ptr::copy_nonoverlapping;
+
+const ANDROID_SET_ABORT_MESSAGE: &[u8] = b"android_set_abort_message\0";
+type SetAbortMessageType = unsafe extern "C" fn(*const libc::c_char) -> ();
+
+// Forward the abort message to libc's android_set_abort_message. We try our best to populate the
+// message but as this function may already be called as part of a failed allocation, it may not be
+// possible to do so.
+//
+// Some methods of core are on purpose avoided (such as try_reserve) as these rely on the correct
+// resolution of rust_eh_personality which is loosely defined in panic_abort.
+//
+// Weakly resolve the symbol for android_set_abort_message. This function is only available
+// for API >= 21.
+pub(crate) unsafe fn android_set_abort_message(payload: *mut &mut dyn BoxMeUp) {
+    let func_addr =
+        libc::dlsym(libc::RTLD_DEFAULT, ANDROID_SET_ABORT_MESSAGE.as_ptr() as *const libc::c_char)
+            as usize;
+    if func_addr == 0 {
+        return;
+    }
+
+    let payload = (*payload).get();
+    let msg = match payload.downcast_ref::<&'static str>() {
+        Some(msg) => msg.as_bytes(),
+        None => match payload.downcast_ref::<String>() {
+            Some(msg) => msg.as_bytes(),
+            None => &[],
+        },
+    };
+    if msg.is_empty() {
+        return;
+    }
+
+    // Allocate a new buffer to append the null byte.
+    let size = msg.len() + 1usize;
+    let buf = libc::malloc(size) as *mut libc::c_char;
+    if buf.is_null() {
+        return; // allocation failure
+    }
+    copy_nonoverlapping(msg.as_ptr(), buf as *mut u8, msg.len());
+    buf.offset(msg.len() as isize).write(0);
+
+    let func = transmute::<usize, SetAbortMessageType>(func_addr);
+    func(buf);
+}
diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs
index eb2277d8baa..5dcd1e6af36 100644
--- a/library/panic_abort/src/lib.rs
+++ b/library/panic_abort/src/lib.rs
@@ -19,6 +19,9 @@
 #![feature(rustc_attrs)]
 #![feature(asm)]
 
+#[cfg(target_os = "android")]
+mod android;
+
 use core::any::Any;
 use core::panic::BoxMeUp;
 
@@ -31,6 +34,10 @@ pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Sen
 // "Leak" the payload and shim to the relevant abort on the platform in question.
 #[rustc_std_internal_symbol]
 pub unsafe extern "C" fn __rust_start_panic(_payload: *mut &mut dyn BoxMeUp) -> u32 {
+    // Android has the ability to attach a message as part of the abort.
+    #[cfg(target_os = "android")]
+    android::android_set_abort_message(_payload);
+
     abort();
 
     cfg_if::cfg_if! {
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 23af00d6293..4111420e474 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -429,7 +429,7 @@ class RustBuild(object):
             lib_dir = "{}/lib".format(bin_root)
             for lib in os.listdir(lib_dir):
                 if lib.endswith(".so"):
-                    self.fix_bin_or_dylib(os.path.join(lib_dir, lib), rpath_libz=True)
+                    self.fix_bin_or_dylib(os.path.join(lib_dir, lib))
             with output(self.rustc_stamp(stage0)) as rust_stamp:
                 rust_stamp.write(key)
 
@@ -477,10 +477,10 @@ class RustBuild(object):
             if self.program_out_of_date(self.llvm_stamp(), llvm_sha + str(llvm_assertions)):
                 self._download_ci_llvm(llvm_sha, llvm_assertions)
                 for binary in ["llvm-config", "FileCheck"]:
-                    self.fix_bin_or_dylib(os.path.join(llvm_root, "bin", binary), rpath_libz=True)
+                    self.fix_bin_or_dylib(os.path.join(llvm_root, "bin", binary))
                 for lib in os.listdir(llvm_lib):
                     if lib.endswith(".so"):
-                        self.fix_bin_or_dylib(os.path.join(llvm_lib, lib), rpath_libz=True)
+                        self.fix_bin_or_dylib(os.path.join(llvm_lib, lib))
                 with output(self.llvm_stamp()) as llvm_stamp:
                     llvm_stamp.write(llvm_sha + str(llvm_assertions))
 
@@ -548,7 +548,7 @@ class RustBuild(object):
                 match="rust-dev",
                 verbose=self.verbose)
 
-    def fix_bin_or_dylib(self, fname, rpath_libz=False):
+    def fix_bin_or_dylib(self, fname):
         """Modifies the interpreter section of 'fname' to fix the dynamic linker,
         or the RPATH section, to fix the dynamic library search path
 
@@ -583,56 +583,49 @@ class RustBuild(object):
         # Only build `.nix-deps` once.
         nix_deps_dir = self.nix_deps_dir
         if not nix_deps_dir:
-            nix_deps_dir = ".nix-deps"
-            if not os.path.exists(nix_deps_dir):
-                os.makedirs(nix_deps_dir)
-
-            nix_deps = [
-                # Needed for the path of `ld-linux.so` (via `nix-support/dynamic-linker`).
-                "stdenv.cc.bintools",
-
-                # Needed as a system dependency of `libLLVM-*.so`.
-                "zlib",
-
-                # Needed for patching ELF binaries (see doc comment above).
-                "patchelf",
-            ]
-
             # Run `nix-build` to "build" each dependency (which will likely reuse
             # the existing `/nix/store` copy, or at most download a pre-built copy).
-            # Importantly, we don't rely on `nix-build` printing the `/nix/store`
-            # path on stdout, but use `-o` to symlink it into `stage0/.nix-deps/$dep`,
-            # ensuring garbage collection will never remove the `/nix/store` path
-            # (which would break our patched binaries that hardcode those paths).
-            for dep in nix_deps:
-                try:
-                    subprocess.check_output([
-                        "nix-build", "<nixpkgs>",
-                        "-A", dep,
-                        "-o", "{}/{}".format(nix_deps_dir, dep),
-                    ])
-                except subprocess.CalledProcessError as reason:
-                    print("warning: failed to call nix-build:", reason)
-                    return
-
+            #
+            # Importantly, we create a gc-root called `.nix-deps` in the `build/`
+            # directory, but still reference the actual `/nix/store` path in the rpath
+            # as it makes it significantly more robust against changes to the location of
+            # the `.nix-deps` location.
+            #
+            # bintools: Needed for the path of `ld-linux.so` (via `nix-support/dynamic-linker`).
+            # zlib: Needed as a system dependency of `libLLVM-*.so`.
+            # patchelf: Needed for patching ELF binaries (see doc comment above).
+            nix_deps_dir = "{}/{}".format(self.build_dir, ".nix-deps")
+            nix_expr = '''
+            with (import <nixpkgs> {});
+            symlinkJoin {
+              name = "rust-stage0-dependencies";
+              paths = [
+                zlib
+                patchelf
+                stdenv.cc.bintools
+              ];
+            }
+            '''
+            try:
+                subprocess.check_output([
+                    "nix-build", "-E", nix_expr, "-o", nix_deps_dir,
+                ])
+            except subprocess.CalledProcessError as reason:
+                print("warning: failed to call nix-build:", reason)
+                return
             self.nix_deps_dir = nix_deps_dir
 
-        patchelf = "{}/patchelf/bin/patchelf".format(nix_deps_dir)
-        patchelf_args = []
-
-        if rpath_libz:
-            # Patch RPATH to add `zlib` dependency that stems from LLVM
-            dylib_deps = ["zlib"]
-            rpath_entries = [
-                # Relative default, all binary and dynamic libraries we ship
-                # appear to have this (even when `../lib` is redundant).
-                "$ORIGIN/../lib",
-            ] + ["{}/{}/lib".format(nix_deps_dir, dep) for dep in dylib_deps]
-            patchelf_args += ["--set-rpath", ":".join(rpath_entries)]
+        patchelf = "{}/bin/patchelf".format(nix_deps_dir)
+        rpath_entries = [
+            # Relative default, all binary and dynamic libraries we ship
+            # appear to have this (even when `../lib` is redundant).
+            "$ORIGIN/../lib",
+            os.path.join(os.path.realpath(nix_deps_dir), "lib")
+        ]
+        patchelf_args = ["--set-rpath", ":".join(rpath_entries)]
         if not fname.endswith(".so"):
             # Finally, set the corret .interp for binaries
-            bintools_dir = "{}/stdenv.cc.bintools".format(nix_deps_dir)
-            with open("{}/nix-support/dynamic-linker".format(bintools_dir)) as dynamic_linker:
+            with open("{}/nix-support/dynamic-linker".format(nix_deps_dir)) as dynamic_linker:
                 patchelf_args += ["--set-interpreter", dynamic_linker.read().rstrip()]
 
         try:
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 117201ab3cd..b9d7ecf8c0e 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -1232,6 +1232,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the
         hostflags.push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display()));
         if builder.is_fuse_ld_lld(compiler.host) {
             hostflags.push("-Clink-args=-fuse-ld=lld".to_string());
+            hostflags.push("-Clink-arg=-Wl,--threads=1".to_string());
         }
         cmd.arg("--host-rustcflags").arg(hostflags.join(" "));
 
@@ -1239,6 +1240,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the
         targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display()));
         if builder.is_fuse_ld_lld(target) {
             targetflags.push("-Clink-args=-fuse-ld=lld".to_string());
+            targetflags.push("-Clink-arg=-Wl,--threads=1".to_string());
         }
         cmd.arg("--target-rustcflags").arg(targetflags.join(" "));
 
diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile
index f5fe546cdc6..ad0e8e9f928 100644
--- a/src/ci/docker/host-x86_64/test-various/Dockerfile
+++ b/src/ci/docker/host-x86_64/test-various/Dockerfile
@@ -18,7 +18,7 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-ins
   wget \
   patch
 
-RUN curl -sL https://nodejs.org/dist/v14.4.0/node-v14.4.0-linux-x64.tar.xz | \
+RUN curl -sL https://nodejs.org/dist/v15.14.0/node-v15.14.0-linux-x64.tar.xz | \
   tar -xJ
 
 WORKDIR /build/
@@ -31,7 +31,7 @@ RUN sh /scripts/sccache.sh
 
 ENV RUST_CONFIGURE_ARGS \
   --musl-root-x86_64=/usr/local/x86_64-linux-musl \
-  --set build.nodejs=/node-v14.4.0-linux-x64/bin/node \
+  --set build.nodejs=/node-v15.14.0-linux-x64/bin/node \
   --set rust.lld
 
 # Some run-make tests have assertions about code size, and enabling debug
diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md
index 174db711bce..a6626679a7d 100644
--- a/src/doc/rustdoc/src/lints.md
+++ b/src/doc/rustdoc/src/lints.md
@@ -294,17 +294,14 @@ warning: unclosed HTML tag `h1`
 warning: 2 warnings emitted
 ```
 
-## non_autolinks
+## bare_urls
 
-This lint is **nightly-only** and **warns by default**. It detects links which
-could use the "automatic" link syntax. For example:
+This lint is **warn-by-default**. It detects URLs which are not links.
+For example:
 
 ```rust
 /// http://example.org
-/// [http://example.com](http://example.com)
 /// [http://example.net]
-///
-/// [http://example.com]: http://example.com
 pub fn foo() {}
 ```
 
@@ -312,22 +309,18 @@ Which will give:
 
 ```text
 warning: this URL is not a hyperlink
- --> foo.rs:1:5
+ --> links.rs:1:5
   |
 1 | /// http://example.org
   |     ^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://example.org>`
   |
-  = note: `#[warn(rustdoc::non_autolinks)]` on by default
-
-warning: unneeded long form for URL
- --> foo.rs:2:5
-  |
-2 | /// [http://example.com](http://example.com)
-  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://example.com>`
+  = note: `#[warn(rustdoc::bare_urls)]` on by default
 
 warning: this URL is not a hyperlink
- --> foo.rs:3:6
+ --> links.rs:3:6
   |
 3 | /// [http://example.net]
   |      ^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://example.net>`
+
+warning: 2 warnings emitted
 ```
diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md
index 946c354fd9d..4f9033cedc3 100644
--- a/src/doc/unstable-book/src/library-features/asm.md
+++ b/src/doc/unstable-book/src/library-features/asm.md
@@ -35,7 +35,7 @@ Inline assembly is currently supported on the following architectures:
 Let us start with the simplest possible example:
 
 ```rust,allow_fail
-# #![feature(asm)]
+#![feature(asm)]
 unsafe {
     asm!("nop");
 }
@@ -52,7 +52,7 @@ Now inserting an instruction that does nothing is rather boring. Let us do somet
 actually acts on data:
 
 ```rust,allow_fail
-# #![feature(asm)]
+#![feature(asm)]
 let x: u64;
 unsafe {
     asm!("mov {}, 5", out(reg) x);
@@ -74,7 +74,7 @@ the template and will read the variable from there after the inline assembly fin
 Let us see another example that also uses an input:
 
 ```rust,allow_fail
-# #![feature(asm)]
+#![feature(asm)]
 let i: u64 = 3;
 let o: u64;
 unsafe {
@@ -114,7 +114,7 @@ readability, and allows reordering instructions without changing the argument or
 We can further refine the above example to avoid the `mov` instruction:
 
 ```rust,allow_fail
-# #![feature(asm)]
+#![feature(asm)]
 let mut x: u64 = 3;
 unsafe {
     asm!("add {0}, {number}", inout(reg) x, number = const 5);
@@ -128,7 +128,7 @@ This is different from specifying an input and output separately in that it is g
 It is also possible to specify different variables for the input and output parts of an `inout` operand:
 
 ```rust,allow_fail
-# #![feature(asm)]
+#![feature(asm)]
 let x: u64 = 3;
 let y: u64;
 unsafe {
@@ -150,7 +150,7 @@ There is also a `inlateout` variant of this specifier.
 Here is an example where `inlateout` *cannot* be used:
 
 ```rust,allow_fail
-# #![feature(asm)]
+#![feature(asm)]
 let mut a: u64 = 4;
 let b: u64 = 4;
 let c: u64 = 4;
@@ -171,7 +171,7 @@ Here the compiler is free to allocate the same register for inputs `b` and `c` s
 However the following example can use `inlateout` since the output is only modified after all input registers have been read:
 
 ```rust,allow_fail
-# #![feature(asm)]
+#![feature(asm)]
 let mut a: u64 = 4;
 let b: u64 = 4;
 unsafe {
@@ -190,7 +190,7 @@ While `reg` is generally available on any architecture, these are highly archite
 among others can be addressed by their name.
 
 ```rust,allow_fail,no_run
-# #![feature(asm)]
+#![feature(asm)]
 let cmd = 0xd1;
 unsafe {
     asm!("out 0x64, eax", in("eax") cmd);
@@ -206,7 +206,7 @@ Note that unlike other operand types, explicit register operands cannot be used
 Consider this example which uses the x86 `mul` instruction:
 
 ```rust,allow_fail
-# #![feature(asm)]
+#![feature(asm)]
 fn mul(a: u64, b: u64) -> u128 {
     let lo: u64;
     let hi: u64;
@@ -242,7 +242,7 @@ We need to tell the compiler about this since it may need to save and restore th
 around the inline assembly block.
 
 ```rust,allow_fail
-# #![feature(asm)]
+#![feature(asm)]
 let ebx: u32;
 let ecx: u32;
 
@@ -272,7 +272,7 @@ However we still need to tell the compiler that `eax` and `edx` have been modifi
 This can also be used with a general register class (e.g. `reg`) to obtain a scratch register for use inside the asm code:
 
 ```rust,allow_fail
-# #![feature(asm)]
+#![feature(asm)]
 // Multiply x by 6 using shifts and adds
 let mut x: u64 = 4;
 unsafe {
@@ -294,7 +294,7 @@ A special operand type, `sym`, allows you to use the symbol name of a `fn` or `s
 This allows you to call a function or access a global variable without needing to keep its address in a register.
 
 ```rust,allow_fail
-# #![feature(asm)]
+#![feature(asm)]
 extern "C" fn foo(arg: i32) {
     println!("arg = {}", arg);
 }
@@ -316,7 +316,7 @@ fn call_foo(arg: i32) {
             // Also mark AVX-512 registers as clobbered. This is accepted by the
             // compiler even if AVX-512 is not enabled on the current target.
             out("xmm16") _, out("xmm17") _, out("xmm18") _, out("xmm19") _,
-            out("xmm20") _, out("xmm21") _, out("xmm22") _, out("xmm13") _,
+            out("xmm20") _, out("xmm21") _, out("xmm22") _, out("xmm23") _,
             out("xmm24") _, out("xmm25") _, out("xmm26") _, out("xmm27") _,
             out("xmm28") _, out("xmm29") _, out("xmm30") _, out("xmm31") _,
         )
@@ -336,7 +336,7 @@ By default the compiler will always choose the name that refers to the full regi
 This default can be overriden by using modifiers on the template string operands, just like you would with format strings:
 
 ```rust,allow_fail
-# #![feature(asm)]
+#![feature(asm)]
 let mut x: u16 = 0xab;
 
 unsafe {
@@ -361,7 +361,7 @@ For example, in x86/x86_64 and intel assembly syntax, you should wrap inputs/out
 to indicate they are memory operands:
 
 ```rust,allow_fail
-# #![feature(asm, llvm_asm)]
+#![feature(asm, llvm_asm)]
 # fn load_fpu_control_word(control: u16) {
 unsafe {
     asm!("fldcw [{}]", in(reg) &control, options(nostack));
@@ -372,6 +372,43 @@ unsafe {
 # }
 ```
 
+## Labels
+
+The compiler is allowed to instantiate multiple copies an `asm!` block, for example when the function containing it is inlined in multiple places. As a consequence, you should only use GNU assembler [local labels] inside inline assembly code. Defining symbols in assembly code may lead to assembler and/or linker errors due to duplicate symbol definitions.
+
+Moreover, due to [an llvm bug], you shouldn't use labels exclusively made of `0` and `1` digits, e.g. `0`, `11` or `101010`, as they may end up being interpreted as binary values.
+
+```rust,allow_fail
+#![feature(asm)]
+
+let mut a = 0;
+unsafe {
+    asm!(
+        "mov {0}, 10",
+        "2:",
+        "sub {0}, 1",
+        "cmp {0}, 3",
+        "jle 2f",
+        "jmp 2b",
+        "2:",
+        "add {0}, 2",
+        out(reg) a
+    );
+}
+assert_eq!(a, 5);
+```
+
+This will decrement the `{0}` register value from 10 to 3, then add 2 and store it in `a`.
+
+This example show a few thing:
+
+First that the same number can be used as a label multiple times in the same inline block.
+
+Second, that when a numeric label is used as a reference (as an instruction operand, for example), the suffixes b (“backward”) or f (“forward”) should be added to the numeric label. It will then refer to the nearest label defined by this number in this direction.
+
+[local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels
+[an llvm bug]: https://bugs.llvm.org/show_bug.cgi?id=36144
+
 ## Options
 
 By default, an inline assembly block is treated the same way as an external FFI function call with a custom calling convention: it may read/write memory, have observable side effects, etc. However in many cases, it is desirable to give the compiler more information about what the assembly code is actually doing so that it can optimize better.
@@ -379,7 +416,7 @@ By default, an inline assembly block is treated the same way as an external FFI
 Let's take our previous example of an `add` instruction:
 
 ```rust,allow_fail
-# #![feature(asm)]
+#![feature(asm)]
 let mut a: u64 = 4;
 let b: u64 = 4;
 unsafe {
@@ -787,8 +824,5 @@ The compiler performs some additional checks on options:
     - You are responsible for switching any target-specific state (e.g. thread-local storage, stack bounds).
     - The set of memory locations that you may access is the intersection of those allowed by the `asm!` blocks you entered and exited.
 - You cannot assume that an `asm!` block will appear exactly once in the output binary. The compiler is allowed to instantiate multiple copies of the `asm!` block, for example when the function containing it is inlined in multiple places.
-  - As a consequence, you should only use [local labels] inside inline assembly code. Defining symbols in assembly code may lead to assembler and/or linker errors due to duplicate symbol definitions.
 
 > **Note**: As a general rule, the flags covered by `preserves_flags` are those which are *not* preserved when performing a function call.
-
-[local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 3a4319d5d9a..0030ef67c07 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -136,6 +136,16 @@ impl Iterator for TokenIter<'a> {
     }
 }
 
+fn get_real_ident_class(text: &str, edition: Edition) -> Class {
+    match text {
+        "ref" | "mut" => Class::RefKeyWord,
+        "self" | "Self" => Class::Self_,
+        "false" | "true" => Class::Bool,
+        _ if Symbol::intern(text).is_reserved(|| edition) => Class::KeyWord,
+        _ => Class::Ident,
+    }
+}
+
 /// Processes program tokens, classifying strings of text by highlighting
 /// category (`Class`).
 struct Classifier<'a> {
@@ -144,6 +154,8 @@ struct Classifier<'a> {
     in_macro: bool,
     in_macro_nonterminal: bool,
     edition: Edition,
+    byte_pos: u32,
+    src: &'a str,
 }
 
 impl<'a> Classifier<'a> {
@@ -155,6 +167,68 @@ impl<'a> Classifier<'a> {
             in_macro: false,
             in_macro_nonterminal: false,
             edition,
+            byte_pos: 0,
+            src,
+        }
+    }
+
+    /// Concatenate colons and idents as one when possible.
+    fn get_full_ident_path(&mut self) -> Vec<(TokenKind, usize, usize)> {
+        let start = self.byte_pos as usize;
+        let mut pos = start;
+        let mut has_ident = false;
+        let edition = self.edition;
+
+        loop {
+            let mut nb = 0;
+            while let Some((TokenKind::Colon, _)) = self.tokens.peek() {
+                self.tokens.next();
+                nb += 1;
+            }
+            // Ident path can start with "::" but if we already have content in the ident path,
+            // the "::" is mandatory.
+            if has_ident && nb == 0 {
+                return vec![(TokenKind::Ident, start, pos)];
+            } else if nb != 0 && nb != 2 {
+                if has_ident {
+                    return vec![(TokenKind::Ident, start, pos), (TokenKind::Colon, pos, pos + nb)];
+                } else {
+                    return vec![(TokenKind::Colon, pos, pos + nb)];
+                }
+            }
+
+            if let Some((Class::Ident, text)) = self.tokens.peek().map(|(token, text)| {
+                if *token == TokenKind::Ident {
+                    let class = get_real_ident_class(text, edition);
+                    (class, text)
+                } else {
+                    // Doesn't matter which Class we put in here...
+                    (Class::Comment, text)
+                }
+            }) {
+                // We only "add" the colon if there is an ident behind.
+                pos += text.len() + nb;
+                has_ident = true;
+                self.tokens.next();
+            } else if nb > 0 && has_ident {
+                return vec![(TokenKind::Ident, start, pos), (TokenKind::Colon, pos, pos + nb)];
+            } else if nb > 0 {
+                return vec![(TokenKind::Colon, pos, pos + nb)];
+            } else if has_ident {
+                return vec![(TokenKind::Ident, start, pos)];
+            } else {
+                return Vec::new();
+            }
+        }
+    }
+
+    /// Wraps the tokens iteration to ensure that the byte_pos is always correct.
+    fn next(&mut self) -> Option<(TokenKind, &'a str)> {
+        if let Some((kind, text)) = self.tokens.next() {
+            self.byte_pos += text.len() as u32;
+            Some((kind, text))
+        } else {
+            None
         }
     }
 
@@ -165,8 +239,25 @@ impl<'a> Classifier<'a> {
     /// token is used.
     fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'a>)) {
         with_default_session_globals(|| {
-            while let Some((token, text)) = self.tokens.next() {
-                self.advance(token, text, sink);
+            loop {
+                if self
+                    .tokens
+                    .peek()
+                    .map(|t| matches!(t.0, TokenKind::Colon | TokenKind::Ident))
+                    .unwrap_or(false)
+                {
+                    let tokens = self.get_full_ident_path();
+                    for (token, start, end) in tokens {
+                        let text = &self.src[start..end];
+                        self.advance(token, text, sink);
+                        self.byte_pos += text.len() as u32;
+                    }
+                }
+                if let Some((token, text)) = self.next() {
+                    self.advance(token, text, sink);
+                } else {
+                    break;
+                }
             }
         })
     }
@@ -203,12 +294,12 @@ impl<'a> Classifier<'a> {
             },
             TokenKind::And => match lookahead {
                 Some(TokenKind::And) => {
-                    let _and = self.tokens.next();
+                    self.next();
                     sink(Highlight::Token { text: "&&", class: Some(Class::Op) });
                     return;
                 }
                 Some(TokenKind::Eq) => {
-                    let _eq = self.tokens.next();
+                    self.next();
                     sink(Highlight::Token { text: "&=", class: Some(Class::Op) });
                     return;
                 }
@@ -260,7 +351,7 @@ impl<'a> Classifier<'a> {
                 match lookahead {
                     // Case 1: #![inner_attribute]
                     Some(TokenKind::Bang) => {
-                        let _not = self.tokens.next().unwrap();
+                        self.next();
                         if let Some(TokenKind::OpenBracket) = self.peek() {
                             self.in_attribute = true;
                             sink(Highlight::EnterSpan { class: Class::Attribute });
@@ -304,19 +395,17 @@ impl<'a> Classifier<'a> {
                 sink(Highlight::Token { text, class: None });
                 return;
             }
-            TokenKind::Ident => match text {
-                "ref" | "mut" => Class::RefKeyWord,
-                "self" | "Self" => Class::Self_,
-                "false" | "true" => Class::Bool,
-                "Option" | "Result" => Class::PreludeTy,
-                "Some" | "None" | "Ok" | "Err" => Class::PreludeVal,
-                // Keywords are also included in the identifier set.
-                _ if Symbol::intern(text).is_reserved(|| self.edition) => Class::KeyWord,
-                _ if self.in_macro_nonterminal => {
-                    self.in_macro_nonterminal = false;
-                    Class::MacroNonTerminal
-                }
-                _ => Class::Ident,
+            TokenKind::Ident => match get_real_ident_class(text, self.edition) {
+                Class::Ident => match text {
+                    "Option" | "Result" => Class::PreludeTy,
+                    "Some" | "None" | "Ok" | "Err" => Class::PreludeVal,
+                    _ if self.in_macro_nonterminal => {
+                        self.in_macro_nonterminal = false;
+                        Class::MacroNonTerminal
+                    }
+                    _ => Class::Ident,
+                },
+                c => c,
             },
             TokenKind::RawIdent => Class::Ident,
             TokenKind::Lifetime { .. } => Class::Lifetime,
diff --git a/src/librustdoc/html/highlight/fixtures/sample.html b/src/librustdoc/html/highlight/fixtures/sample.html
index 4966e0ac6bb..8d23477bbcb 100644
--- a/src/librustdoc/html/highlight/fixtures/sample.html
+++ b/src/librustdoc/html/highlight/fixtures/sample.html
@@ -10,6 +10,8 @@
 </style>
 <pre><code><span class="attribute">#![<span class="ident">crate_type</span> <span class="op">=</span> <span class="string">&quot;lib&quot;</span>]</span>
 
+<span class="kw">use</span> <span class="ident">std::path</span>::{<span class="ident">Path</span>, <span class="ident">PathBuf</span>};
+
 <span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">target_os</span> <span class="op">=</span> <span class="string">&quot;linux&quot;</span>)]</span>
 <span class="kw">fn</span> <span class="ident">main</span>() {
     <span class="kw">let</span> <span class="ident">foo</span> <span class="op">=</span> <span class="bool-val">true</span> <span class="op">&amp;&amp;</span> <span class="bool-val">false</span> <span class="op">|</span><span class="op">|</span> <span class="bool-val">true</span>;
@@ -19,6 +21,14 @@
     <span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="kw-2">*</span><span class="ident">foo</span>;
     <span class="macro">mac!</span>(<span class="ident">foo</span>, <span class="kw-2">&amp;</span><span class="kw-2">mut</span> <span class="ident">bar</span>);
     <span class="macro">assert!</span>(<span class="self">self</span>.<span class="ident">length</span> <span class="op">&lt;</span> <span class="ident">N</span> <span class="op">&amp;&amp;</span> <span class="ident">index</span> <span class="op">&lt;</span><span class="op">=</span> <span class="self">self</span>.<span class="ident">length</span>);
+    <span class="ident">::std::env::var</span>(<span class="string">&quot;gateau&quot;</span>).<span class="ident">is_ok</span>();
+    <span class="attribute">#[<span class="ident">rustfmt::skip</span>]</span>
+    <span class="kw">let</span> <span class="ident">s</span>:<span class="ident">std</span><span class="ident">::path::PathBuf</span> <span class="op">=</span> <span class="ident">std::path::PathBuf::new</span>();
+    <span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">s</span> <span class="op">=</span> <span class="ident">String::new</span>();
+
+    <span class="kw">match</span> <span class="kw-2">&amp;</span><span class="ident">s</span> {
+        <span class="kw-2">ref</span> <span class="kw-2">mut</span> <span class="ident">x</span> <span class="op">=</span><span class="op">&gt;</span> {}
+    }
 }
 
 <span class="macro">macro_rules!</span> <span class="ident">bar</span> {
diff --git a/src/librustdoc/html/highlight/fixtures/sample.rs b/src/librustdoc/html/highlight/fixtures/sample.rs
index 956fdbe090b..b027203655d 100644
--- a/src/librustdoc/html/highlight/fixtures/sample.rs
+++ b/src/librustdoc/html/highlight/fixtures/sample.rs
@@ -1,5 +1,7 @@
 #![crate_type = "lib"]
 
+use std::path::{Path, PathBuf};
+
 #[cfg(target_os = "linux")]
 fn main() {
     let foo = true && false || true;
@@ -9,6 +11,14 @@ fn main() {
     let _ = *foo;
     mac!(foo, &mut bar);
     assert!(self.length < N && index <= self.length);
+    ::std::env::var("gateau").is_ok();
+    #[rustfmt::skip]
+    let s:std::path::PathBuf = std::path::PathBuf::new();
+    let mut s = String::new();
+
+    match &s {
+        ref mut x => {}
+    }
 }
 
 macro_rules! bar {
diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs
index ffa2f7a47fd..1b79811d4b0 100644
--- a/src/librustdoc/lint.rs
+++ b/src/librustdoc/lint.rs
@@ -148,14 +148,13 @@ declare_rustdoc_lint! {
 }
 
 declare_rustdoc_lint! {
-    /// The `non_autolinks` lint detects when a URL could be written using
-    /// only angle brackets. This is a `rustdoc` only lint, see the
-    /// documentation in the [rustdoc book].
+    /// The `bare_urls` lint detects when a URL is not a hyperlink.
+    /// This is a `rustdoc` only lint, see the documentation in the [rustdoc book].
     ///
-    /// [rustdoc book]: ../../../rustdoc/lints.html#non_autolinks
-    NON_AUTOLINKS,
+    /// [rustdoc book]: ../../../rustdoc/lints.html#bare_urls
+    BARE_URLS,
     Warn,
-    "detects URLs that could be written using only angle brackets"
+    "detects URLs that are not hyperlinks"
 }
 
 crate static RUSTDOC_LINTS: Lazy<Vec<&'static Lint>> = Lazy::new(|| {
@@ -166,7 +165,7 @@ crate static RUSTDOC_LINTS: Lazy<Vec<&'static Lint>> = Lazy::new(|| {
         PRIVATE_DOC_TESTS,
         INVALID_CODEBLOCK_ATTRIBUTES,
         INVALID_HTML_TAGS,
-        NON_AUTOLINKS,
+        BARE_URLS,
         MISSING_CRATE_LEVEL_DOCS,
     ]
 });
@@ -185,4 +184,6 @@ crate fn register_lints(_sess: &Session, lint_store: &mut LintStore) {
     }
     lint_store
         .register_renamed("intra_doc_link_resolution_failure", "rustdoc::broken_intra_doc_links");
+    lint_store.register_renamed("non_autolinks", "rustdoc::bare_urls");
+    lint_store.register_renamed("rustdoc::non_autolinks", "rustdoc::bare_urls");
 }
diff --git a/src/librustdoc/passes/non_autolinks.rs b/src/librustdoc/passes/bare_urls.rs
index 9761a78577d..524f266bcad 100644
--- a/src/librustdoc/passes/non_autolinks.rs
+++ b/src/librustdoc/passes/bare_urls.rs
@@ -4,37 +4,42 @@ use crate::core::DocContext;
 use crate::fold::DocFolder;
 use crate::html::markdown::opts;
 use core::ops::Range;
-use pulldown_cmark::{Event, LinkType, Parser, Tag};
+use pulldown_cmark::{Event, Parser, Tag};
 use regex::Regex;
 use rustc_errors::Applicability;
+use std::lazy::SyncLazy;
+use std::mem;
 
-crate const CHECK_NON_AUTOLINKS: Pass = Pass {
-    name: "check-non-autolinks",
-    run: check_non_autolinks,
-    description: "detects URLs that could be linkified",
+crate const CHECK_BARE_URLS: Pass = Pass {
+    name: "check-bare-urls",
+    run: check_bare_urls,
+    description: "detects URLs that are not hyperlinks",
 };
 
-const URL_REGEX: &str = concat!(
-    r"https?://",                          // url scheme
-    r"([-a-zA-Z0-9@:%._\+~#=]{2,256}\.)+", // one or more subdomains
-    r"[a-zA-Z]{2,63}",                     // root domain
-    r"\b([-a-zA-Z0-9@:%_\+.~#?&/=]*)"      // optional query or url fragments
-);
+static URL_REGEX: SyncLazy<Regex> = SyncLazy::new(|| {
+    Regex::new(concat!(
+        r"https?://",                          // url scheme
+        r"([-a-zA-Z0-9@:%._\+~#=]{2,256}\.)+", // one or more subdomains
+        r"[a-zA-Z]{2,63}",                     // root domain
+        r"\b([-a-zA-Z0-9@:%_\+.~#?&/=]*)"      // optional query or url fragments
+    ))
+    .expect("failed to build regex")
+});
 
-struct NonAutolinksLinter<'a, 'tcx> {
+struct BareUrlsLinter<'a, 'tcx> {
     cx: &'a mut DocContext<'tcx>,
-    regex: Regex,
 }
 
-impl<'a, 'tcx> NonAutolinksLinter<'a, 'tcx> {
+impl<'a, 'tcx> BareUrlsLinter<'a, 'tcx> {
     fn find_raw_urls(
         &self,
         text: &str,
         range: Range<usize>,
         f: &impl Fn(&DocContext<'_>, &str, &str, Range<usize>),
     ) {
+        trace!("looking for raw urls in {}", text);
         // For now, we only check "full" URLs (meaning, starting with "http://" or "https://").
-        for match_ in self.regex.find_iter(&text) {
+        for match_ in URL_REGEX.find_iter(&text) {
             let url = match_.as_str();
             let url_range = match_.range();
             f(
@@ -47,18 +52,11 @@ impl<'a, 'tcx> NonAutolinksLinter<'a, 'tcx> {
     }
 }
 
-crate fn check_non_autolinks(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
-    if !cx.tcx.sess.is_nightly_build() {
-        krate
-    } else {
-        let mut coll =
-            NonAutolinksLinter { cx, regex: Regex::new(URL_REGEX).expect("failed to build regex") };
-
-        coll.fold_crate(krate)
-    }
+crate fn check_bare_urls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
+    BareUrlsLinter { cx }.fold_crate(krate)
 }
 
-impl<'a, 'tcx> DocFolder for NonAutolinksLinter<'a, 'tcx> {
+impl<'a, 'tcx> DocFolder for BareUrlsLinter<'a, 'tcx> {
     fn fold_item(&mut self, item: Item) -> Option<Item> {
         let hir_id = match DocContext::as_local_hir_id(self.cx.tcx, item.def_id) {
             Some(hir_id) => hir_id,
@@ -73,7 +71,7 @@ impl<'a, 'tcx> DocFolder for NonAutolinksLinter<'a, 'tcx> {
                 let sp = super::source_span_for_markdown_range(cx.tcx, &dox, &range, &item.attrs)
                     .or_else(|| span_of_attrs(&item.attrs))
                     .unwrap_or(item.span.inner());
-                cx.tcx.struct_span_lint_hir(crate::lint::NON_AUTOLINKS, hir_id, sp, |lint| {
+                cx.tcx.struct_span_lint_hir(crate::lint::BARE_URLS, hir_id, sp, |lint| {
                     lint.build(msg)
                         .span_suggestion(
                             sp,
@@ -89,37 +87,16 @@ impl<'a, 'tcx> DocFolder for NonAutolinksLinter<'a, 'tcx> {
 
             while let Some((event, range)) = p.next() {
                 match event {
-                    Event::Start(Tag::Link(kind, _, _)) => {
-                        let ignore = matches!(kind, LinkType::Autolink | LinkType::Email);
-                        let mut title = String::new();
-
-                        while let Some((event, range)) = p.next() {
-                            match event {
-                                Event::End(Tag::Link(_, url, _)) => {
-                                    // NOTE: links cannot be nested, so we don't need to
-                                    // check `kind`
-                                    if url.as_ref() == title && !ignore && self.regex.is_match(&url)
-                                    {
-                                        report_diag(
-                                            self.cx,
-                                            "unneeded long form for URL",
-                                            &url,
-                                            range,
-                                        );
-                                    }
-                                    break;
-                                }
-                                Event::Text(s) if !ignore => title.push_str(&s),
-                                _ => {}
-                            }
-                        }
-                    }
                     Event::Text(s) => self.find_raw_urls(&s, range, &report_diag),
-                    Event::Start(Tag::CodeBlock(_)) => {
-                        // We don't want to check the text inside the code blocks.
+                    // We don't want to check the text inside code blocks or links.
+                    Event::Start(tag @ (Tag::CodeBlock(_) | Tag::Link(..))) => {
                         while let Some((event, _)) = p.next() {
                             match event {
-                                Event::End(Tag::CodeBlock(_)) => break,
+                                Event::End(end)
+                                    if mem::discriminant(&end) == mem::discriminant(&tag) =>
+                                {
+                                    break;
+                                }
                                 _ => {}
                             }
                         }
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index ad269413ac6..fdac33fd60e 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -7,7 +7,6 @@ use crate::passes::Pass;
 use rustc_lint::builtin::MISSING_DOCS;
 use rustc_middle::lint::LintLevelSource;
 use rustc_session::lint;
-use rustc_span::symbol::sym;
 use rustc_span::FileName;
 use serde::Serialize;
 
@@ -193,48 +192,13 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> {
                 // don't count items in stripped modules
                 return Some(i);
             }
-            clean::ImportItem(..) | clean::ExternCrateItem { .. } => {
-                // docs on `use` and `extern crate` statements are not displayed, so they're not
-                // worth counting
-                return Some(i);
-            }
-            clean::ImplItem(ref impl_)
-                if i.attrs
-                    .other_attrs
-                    .iter()
-                    .any(|item| item.has_name(sym::automatically_derived))
-                    || impl_.synthetic
-                    || impl_.blanket_impl.is_some() =>
-            {
-                // built-in derives get the `#[automatically_derived]` attribute, and
-                // synthetic/blanket impls are made up by rustdoc and can't be documented
-                // FIXME(misdreavus): need to also find items that came out of a derive macro
-                return Some(i);
-            }
-            clean::ImplItem(ref impl_) => {
-                let filename = i.span.filename(self.ctx.sess());
-                if let Some(ref tr) = impl_.trait_ {
-                    debug!(
-                        "impl {:#} for {:#} in {}",
-                        tr.print(&self.ctx.cache, self.ctx.tcx),
-                        impl_.for_.print(&self.ctx.cache, self.ctx.tcx),
-                        filename,
-                    );
-
-                    // don't count trait impls, the missing-docs lint doesn't so we shouldn't
-                    // either
-                    return Some(i);
-                } else {
-                    // inherent impls *can* be documented, and those docs show up, but in most
-                    // cases it doesn't make sense, as all methods on a type are in one single
-                    // impl block
-                    debug!(
-                        "impl {:#} in {}",
-                        impl_.for_.print(&self.ctx.cache, self.ctx.tcx),
-                        filename
-                    );
-                }
-            }
+            // docs on `use` and `extern crate` statements are not displayed, so they're not
+            // worth counting
+            clean::ImportItem(..) | clean::ExternCrateItem { .. } => {}
+            // Don't count trait impls, the missing-docs lint doesn't so we shouldn't either.
+            // Inherent impls *can* be documented, and those docs show up, but in most cases it
+            // doesn't make sense, as all methods on a type are in one single impl block
+            clean::ImplItem(_) => {}
             _ => {
                 let has_docs = !i.attrs.doc_strings.is_empty();
                 let mut tests = Tests { found_tests: 0 };
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index 755217a4629..0e86fe45640 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -12,8 +12,8 @@ use crate::core::DocContext;
 mod stripper;
 crate use stripper::*;
 
-mod non_autolinks;
-crate use self::non_autolinks::CHECK_NON_AUTOLINKS;
+mod bare_urls;
+crate use self::bare_urls::CHECK_BARE_URLS;
 
 mod strip_hidden;
 crate use self::strip_hidden::STRIP_HIDDEN;
@@ -90,7 +90,7 @@ crate const PASSES: &[Pass] = &[
     COLLECT_TRAIT_IMPLS,
     CALCULATE_DOC_COVERAGE,
     CHECK_INVALID_HTML_TAGS,
-    CHECK_NON_AUTOLINKS,
+    CHECK_BARE_URLS,
 ];
 
 /// The list of passes run by default.
@@ -105,12 +105,11 @@ crate const DEFAULT_PASSES: &[ConditionalPass] = &[
     ConditionalPass::always(CHECK_CODE_BLOCK_SYNTAX),
     ConditionalPass::always(CHECK_INVALID_HTML_TAGS),
     ConditionalPass::always(PROPAGATE_DOC_CFG),
-    ConditionalPass::always(CHECK_NON_AUTOLINKS),
+    ConditionalPass::always(CHECK_BARE_URLS),
 ];
 
 /// The list of default passes run when `--doc-coverage` is passed to rustdoc.
 crate const COVERAGE_PASSES: &[ConditionalPass] = &[
-    ConditionalPass::always(COLLECT_TRAIT_IMPLS),
     ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden),
     ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate),
     ConditionalPass::always(CALCULATE_DOC_COVERAGE),
diff --git a/src/llvm-project b/src/llvm-project
-Subproject 171991e30966695fd118c90ebbb2eeec5098ccc
+Subproject 5ef9f9948fca7cb39dd6c1935ca4e819fb7a0db
diff --git a/src/test/assembly/panic-no-unwind-no-uwtable.rs b/src/test/assembly/panic-no-unwind-no-uwtable.rs
new file mode 100644
index 00000000000..499d4e69867
--- /dev/null
+++ b/src/test/assembly/panic-no-unwind-no-uwtable.rs
@@ -0,0 +1,8 @@
+// assembly-output: emit-asm
+// only-x86_64-unknown-linux-gnu
+// compile-flags: -C panic=unwind -C force-unwind-tables=n -O
+
+#![crate_type = "lib"]
+
+// CHECK-NOT: .cfi_startproc
+pub fn foo() {}
diff --git a/src/test/assembly/panic-unwind-no-uwtable.rs b/src/test/assembly/panic-unwind-no-uwtable.rs
new file mode 100644
index 00000000000..8eed72b2fca
--- /dev/null
+++ b/src/test/assembly/panic-unwind-no-uwtable.rs
@@ -0,0 +1,12 @@
+// assembly-output: emit-asm
+// only-x86_64-unknown-linux-gnu
+// compile-flags: -C panic=unwind -C force-unwind-tables=n
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: foo:
+// CHECK: .cfi_startproc
+#[no_mangle]
+fn foo() {
+    panic!();
+}
diff --git a/src/test/codegen/force-no-unwind-tables.rs b/src/test/codegen/force-no-unwind-tables.rs
index dc77e6cb709..3ee23f05eb2 100644
--- a/src/test/codegen/force-no-unwind-tables.rs
+++ b/src/test/codegen/force-no-unwind-tables.rs
@@ -3,5 +3,9 @@
 
 #![crate_type="lib"]
 
+// CHECK-LABEL: define{{.*}}void @foo
 // CHECK-NOT: attributes #{{.*}} uwtable
-pub fn foo() {}
+#[no_mangle]
+fn foo() {
+    panic!();
+}
diff --git a/src/test/codegen/panic-unwind-default-uwtable.rs b/src/test/codegen/panic-unwind-default-uwtable.rs
new file mode 100644
index 00000000000..4c85008cf35
--- /dev/null
+++ b/src/test/codegen/panic-unwind-default-uwtable.rs
@@ -0,0 +1,6 @@
+// compile-flags: -C panic=unwind -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+// CHECK: attributes #{{.*}} uwtable
+pub fn foo() {}
diff --git a/src/test/debuginfo/var-captured-in-nested-closure.rs b/src/test/debuginfo/var-captured-in-nested-closure.rs
index 8ab6d141731..695cdc4f41f 100644
--- a/src/test/debuginfo/var-captured-in-nested-closure.rs
+++ b/src/test/debuginfo/var-captured-in-nested-closure.rs
@@ -83,6 +83,55 @@
 // lldbr-check:(isize) closure_local = 8
 // lldb-command:continue
 
+
+// === CDB TESTS ===================================================================================
+
+// cdb-command: g
+
+// cdb-command: dx variable
+// cdb-check:variable         : 1 [Type: [...]]
+// cdb-command: dx constant
+// cdb-check:constant         : 2 [Type: [...]]
+// cdb-command: dx a_struct
+// cdb-check:a_struct         [Type: var_captured_in_nested_closure::Struct]
+// cdb-check:    [+0x[...]] a                : -3 [Type: [...]]
+// cdb-check:    [+0x[...]] b                : 4.500000 [Type: [...]]
+// cdb-check:    [+0x[...]] c                : 0x5 [Type: unsigned [...]]
+// cdb-command: dx struct_ref
+// cdb-check:struct_ref       : 0x[...] [Type: var_captured_in_nested_closure::Struct *]
+// cdb-check:    [+0x[...]] a                : -3 [Type: [...]]
+// cdb-check:    [+0x[...]] b                : 4.500000 [Type: [...]]
+// cdb-check:    [+0x[...]] c                : 0x5 [Type: unsigned [...]]
+// cdb-command: dx owned
+// cdb-check:owned            : 0x[...] : 6 [Type: [...] *]
+// cdb-check:    6 [Type: [...]]
+// cdb-command: dx closure_local
+// cdb-check:closure_local    : 8 [Type: [...]]
+// cdb-command: dx nested_closure
+// cdb-check:nested_closure   [Type: var_captured_in_nested_closure::main::{{closure}}::closure-0]
+
+// cdb-command: g
+
+// cdb-command: dx variable
+// cdb-check:variable         : 1 [Type: [...]]
+// cdb-command: dx constant
+// cdb-check:constant         : 2 [Type: [...]]
+// cdb-command: dx a_struct
+// cdb-check:a_struct         [Type: var_captured_in_nested_closure::Struct]
+// cdb-check:    [+0x[...]] a                : -3 [Type: [...]]
+// cdb-check:    [+0x[...]] b                : 4.500000 [Type: [...]]
+// cdb-check:    [+0x[...]] c                : 0x5 [Type: unsigned [...]]
+// cdb-command: dx struct_ref
+// cdb-check:struct_ref       : 0x[...] [Type: var_captured_in_nested_closure::Struct *]
+// cdb-check:    [+0x[...]] a                : -3 [Type: [...]]
+// cdb-check:    [+0x[...]] b                : 4.500000 [Type: [...]]
+// cdb-check:    [+0x[...]] c                : 0x5 [Type: unsigned [...]]
+// cdb-command: dx owned
+// cdb-check:owned            : 0x[...] : 6 [Type: [...] *]
+// cdb-check:    6 [Type: [...]]
+// cdb-command: dx closure_local
+// cdb-check:closure_local    : 8 [Type: [...]]
+
 #![allow(unused_variables)]
 #![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
diff --git a/src/test/debuginfo/var-captured-in-stack-closure.rs b/src/test/debuginfo/var-captured-in-stack-closure.rs
index f53f8aaa670..1bbb79c37a4 100644
--- a/src/test/debuginfo/var-captured-in-stack-closure.rs
+++ b/src/test/debuginfo/var-captured-in-stack-closure.rs
@@ -73,6 +73,48 @@
 // lldbg-check:[...]$9 = 6
 // lldbr-check:(isize) *owned = 6
 
+
+// === CDB TESTS ===================================================================================
+
+// cdb-command: g
+
+// cdb-command: dx variable
+// cdb-check:variable         : 1 [Type: [...]]
+// cdb-command: dx constant
+// cdb-check:constant         : 2 [Type: [...]]
+// cdb-command: dx a_struct
+// cdb-check:a_struct         [Type: var_captured_in_stack_closure::Struct]
+// cdb-check:    [+0x[...]] a                : -3 [Type: [...]]
+// cdb-check:    [+0x[...]] b                : 4.500000 [Type: [...]]
+// cdb-check:    [+0x[...]] c                : 0x5 [Type: unsigned [...]]
+// cdb-command: dx struct_ref
+// cdb-check:struct_ref       : 0x[...] [Type: var_captured_in_stack_closure::Struct *]
+// cdb-check:    [+0x[...]] a                : -3 [Type: [...]]
+// cdb-check:    [+0x[...]] b                : 4.500000 [Type: [...]]
+// cdb-check:    [+0x[...]] c                : 0x5 [Type: unsigned [...]]
+// cdb-command: dx owned
+// cdb-check:owned            : 0x[...] : 6 [Type: [...] *]
+
+
+// cdb-command: g
+
+// cdb-command: dx variable
+// cdb-check:variable         : 2 [Type: [...]]
+// cdb-command: dx constant
+// cdb-check:constant         : 2 [Type: [...]]
+// cdb-command: dx a_struct
+// cdb-check:a_struct         [Type: var_captured_in_stack_closure::Struct]
+// cdb-check:    [+0x[...]] a                : -3 [Type: [...]]
+// cdb-check:    [+0x[...]] b                : 4.500000 [Type: [...]]
+// cdb-check:    [+0x[...]] c                : 0x5 [Type: unsigned [...]]
+// cdb-command: dx struct_ref
+// cdb-check:struct_ref       : 0x[...] [Type: var_captured_in_stack_closure::Struct *]
+// cdb-check:    [+0x[...]] a                : -3 [Type: [...]]
+// cdb-check:    [+0x[...]] b                : 4.500000 [Type: [...]]
+// cdb-check:    [+0x[...]] c                : 0x5 [Type: unsigned [...]]
+// cdb-command: dx owned
+// cdb-check:owned            : 0x[...] : 6 [Type: [...] *]
+
 #![feature(box_syntax)]
 #![allow(unused_variables)]
 #![feature(omit_gdb_pretty_printer_section)]
diff --git a/src/test/run-make/wasm-abi/Makefile b/src/test/run-make/wasm-abi/Makefile
new file mode 100644
index 00000000000..61fc4e8f57f
--- /dev/null
+++ b/src/test/run-make/wasm-abi/Makefile
@@ -0,0 +1,7 @@
+-include ../../run-make-fulldeps/tools.mk
+
+# only-wasm32-bare
+
+all:
+	$(RUSTC) foo.rs --target wasm32-unknown-unknown
+	$(NODE) foo.js $(TMPDIR)/foo.wasm
diff --git a/src/test/run-make/wasm-abi/foo.js b/src/test/run-make/wasm-abi/foo.js
new file mode 100644
index 00000000000..9e9a65401af
--- /dev/null
+++ b/src/test/run-make/wasm-abi/foo.js
@@ -0,0 +1,22 @@
+const fs = require('fs');
+const process = require('process');
+const assert = require('assert');
+const buffer = fs.readFileSync(process.argv[2]);
+
+const m = new WebAssembly.Module(buffer);
+const i = new WebAssembly.Instance(m, {
+  host: {
+    two_i32: () => [100, 101],
+    two_i64: () => [102n, 103n],
+    two_f32: () => [104, 105],
+    two_f64: () => [106, 107],
+    mishmash: () => [108, 109, 110, 111n, 112, 113],
+  }
+});
+
+assert.deepEqual(i.exports.return_two_i32(), [1, 2])
+assert.deepEqual(i.exports.return_two_i64(), [3, 4])
+assert.deepEqual(i.exports.return_two_f32(), [5, 6])
+assert.deepEqual(i.exports.return_two_f64(), [7, 8])
+assert.deepEqual(i.exports.return_mishmash(), [9, 10, 11, 12, 13, 14])
+i.exports.call_imports();
diff --git a/src/test/run-make/wasm-abi/foo.rs b/src/test/run-make/wasm-abi/foo.rs
new file mode 100644
index 00000000000..0678eb3ff51
--- /dev/null
+++ b/src/test/run-make/wasm-abi/foo.rs
@@ -0,0 +1,87 @@
+#![crate_type = "cdylib"]
+#![deny(warnings)]
+#![feature(wasm_abi)]
+
+#[repr(C)]
+#[derive(PartialEq, Debug)]
+pub struct TwoI32 {
+    pub a: i32,
+    pub b: i32,
+}
+
+#[no_mangle]
+pub extern "wasm" fn return_two_i32() -> TwoI32 {
+    TwoI32 { a: 1, b: 2 }
+}
+
+#[repr(C)]
+#[derive(PartialEq, Debug)]
+pub struct TwoI64 {
+    pub a: i64,
+    pub b: i64,
+}
+
+#[no_mangle]
+pub extern "wasm" fn return_two_i64() -> TwoI64 {
+    TwoI64 { a: 3, b: 4 }
+}
+
+#[repr(C)]
+#[derive(PartialEq, Debug)]
+pub struct TwoF32 {
+    pub a: f32,
+    pub b: f32,
+}
+
+#[no_mangle]
+pub extern "wasm" fn return_two_f32() -> TwoF32 {
+    TwoF32 { a: 5., b: 6. }
+}
+
+#[repr(C)]
+#[derive(PartialEq, Debug)]
+pub struct TwoF64 {
+    pub a: f64,
+    pub b: f64,
+}
+
+#[no_mangle]
+pub extern "wasm" fn return_two_f64() -> TwoF64 {
+    TwoF64 { a: 7., b: 8. }
+}
+
+#[repr(C)]
+#[derive(PartialEq, Debug)]
+pub struct Mishmash {
+    pub a: f64,
+    pub b: f32,
+    pub c: i32,
+    pub d: i64,
+    pub e: TwoI32,
+}
+
+#[no_mangle]
+pub extern "wasm" fn return_mishmash() -> Mishmash {
+    Mishmash { a: 9., b: 10., c: 11, d: 12, e: TwoI32 { a: 13, b: 14 } }
+}
+
+#[link(wasm_import_module = "host")]
+extern "wasm" {
+    fn two_i32() -> TwoI32;
+    fn two_i64() -> TwoI64;
+    fn two_f32() -> TwoF32;
+    fn two_f64() -> TwoF64;
+    fn mishmash() -> Mishmash;
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn call_imports() {
+    assert_eq!(two_i32(), TwoI32 { a: 100, b: 101 });
+    assert_eq!(two_i64(), TwoI64 { a: 102, b: 103 });
+    assert_eq!(two_f32(), TwoF32 { a: 104., b: 105. });
+    assert_eq!(two_f64(), TwoF64 { a: 106., b: 107. });
+    assert_eq!(
+        mishmash(),
+        Mishmash { a: 108., b: 109., c: 110, d: 111, e: TwoI32 { a: 112, b: 113 } }
+    );
+}
diff --git a/src/test/rustdoc-ui/coverage/traits.rs b/src/test/rustdoc-ui/coverage/traits.rs
index 7d5cf049e7f..2a108dac2a5 100644
--- a/src/test/rustdoc-ui/coverage/traits.rs
+++ b/src/test/rustdoc-ui/coverage/traits.rs
@@ -2,6 +2,7 @@
 // check-pass
 
 #![feature(trait_alias)]
+#![feature(min_type_alias_impl_trait)]
 
 /// look at this trait right here
 pub trait ThisTrait {
@@ -16,6 +17,7 @@ pub trait ThisTrait {
 }
 
 /// so what happens if we take some struct...
+#[derive(Clone)]
 pub struct SomeStruct;
 
 /// ...and slap this trait on it?
@@ -29,10 +31,8 @@ impl ThisTrait for SomeStruct {
 /// but what about those aliases? i hear they're pretty exotic
 pub trait MyAlias = ThisTrait + Send + Sync;
 
-// FIXME(58624): once rustdoc can process opaque `impl Trait` types,
-// we need to make sure they're counted
-// /// woah, getting all opaque in here
-// pub type ThisExists = impl ThisTrait;
-//
-// /// why don't we get a little more concrete
-// pub fn defines() -> ThisExists { SomeStruct {} }
+/// woah, getting all opaque in here
+pub type ThisExists = impl ThisTrait;
+
+/// why don't we get a little more concrete
+pub fn defines() -> ThisExists { SomeStruct {} }
diff --git a/src/test/rustdoc-ui/coverage/traits.stdout b/src/test/rustdoc-ui/coverage/traits.stdout
index e04d48b4980..5053d02090c 100644
--- a/src/test/rustdoc-ui/coverage/traits.stdout
+++ b/src/test/rustdoc-ui/coverage/traits.stdout
@@ -1,7 +1,7 @@
 +-------------------------------------+------------+------------+------------+------------+
 | File                                | Documented | Percentage |   Examples | Percentage |
 +-------------------------------------+------------+------------+------------+------------+
-| ...st/rustdoc-ui/coverage/traits.rs |          6 |      85.7% |          0 |       0.0% |
+| ...st/rustdoc-ui/coverage/traits.rs |          8 |      88.9% |          0 |       0.0% |
 +-------------------------------------+------------+------------+------------+------------+
-| Total                               |          6 |      85.7% |          0 |       0.0% |
+| Total                               |          8 |      88.9% |          0 |       0.0% |
 +-------------------------------------+------------+------------+------------+------------+
diff --git a/src/test/rustdoc-ui/renamed-lint-still-applies.rs b/src/test/rustdoc-ui/renamed-lint-still-applies.rs
index 8c61c1ccb6a..05a32d3cc31 100644
--- a/src/test/rustdoc-ui/renamed-lint-still-applies.rs
+++ b/src/test/rustdoc-ui/renamed-lint-still-applies.rs
@@ -4,3 +4,8 @@
 // stable channel.
 //! [x]
 //~^ ERROR unresolved link
+
+#![deny(rustdoc::non_autolinks)]
+//~^ WARNING renamed to `rustdoc::bare_urls`
+//! http://example.com
+//~^ ERROR not a hyperlink
diff --git a/src/test/rustdoc-ui/renamed-lint-still-applies.stderr b/src/test/rustdoc-ui/renamed-lint-still-applies.stderr
index 8a12991558a..19c253b366b 100644
--- a/src/test/rustdoc-ui/renamed-lint-still-applies.stderr
+++ b/src/test/rustdoc-ui/renamed-lint-still-applies.stderr
@@ -1,3 +1,11 @@
+warning: lint `rustdoc::non_autolinks` has been renamed to `rustdoc::bare_urls`
+  --> $DIR/renamed-lint-still-applies.rs:8:9
+   |
+LL | #![deny(rustdoc::non_autolinks)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `rustdoc::bare_urls`
+   |
+   = note: `#[warn(renamed_and_removed_lints)]` on by default
+
 error: unresolved link to `x`
   --> $DIR/renamed-lint-still-applies.rs:5:6
    |
@@ -12,5 +20,17 @@ LL | #![deny(broken_intra_doc_links)]
    = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(broken_intra_doc_links)]`
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-error: aborting due to previous error
+error: this URL is not a hyperlink
+  --> $DIR/renamed-lint-still-applies.rs:10:5
+   |
+LL | //! http://example.com
+   |     ^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://example.com>`
+   |
+note: the lint level is defined here
+  --> $DIR/renamed-lint-still-applies.rs:8:9
+   |
+LL | #![deny(rustdoc::non_autolinks)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/src/test/rustdoc-ui/unknown-renamed-lints.rs b/src/test/rustdoc-ui/unknown-renamed-lints.rs
index a05c0c81168..9096cce1276 100644
--- a/src/test/rustdoc-ui/unknown-renamed-lints.rs
+++ b/src/test/rustdoc-ui/unknown-renamed-lints.rs
@@ -8,8 +8,12 @@
 //~^ ERROR unknown lint: `rustdoc::x`
 #![deny(intra_doc_link_resolution_failure)]
 //~^ ERROR renamed to `rustdoc::broken_intra_doc_links`
-
 #![deny(non_autolinks)]
+//~^ ERROR renamed to `rustdoc::bare_urls`
+#![deny(rustdoc::non_autolinks)]
+//~^ ERROR renamed to `rustdoc::bare_urls`
+
+#![deny(private_doc_tests)]
 // FIXME: the old names for rustdoc lints should warn by default once `rustdoc::` makes it to the
 // stable channel.
 
diff --git a/src/test/rustdoc-ui/unknown-renamed-lints.stderr b/src/test/rustdoc-ui/unknown-renamed-lints.stderr
index 98bfb83c704..51e06821cf7 100644
--- a/src/test/rustdoc-ui/unknown-renamed-lints.stderr
+++ b/src/test/rustdoc-ui/unknown-renamed-lints.stderr
@@ -28,19 +28,31 @@ note: the lint level is defined here
 LL | #![deny(renamed_and_removed_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error: lint `non_autolinks` has been renamed to `rustdoc::bare_urls`
+  --> $DIR/unknown-renamed-lints.rs:11:9
+   |
+LL | #![deny(non_autolinks)]
+   |         ^^^^^^^^^^^^^ help: use the new name: `rustdoc::bare_urls`
+
+error: lint `rustdoc::non_autolinks` has been renamed to `rustdoc::bare_urls`
+  --> $DIR/unknown-renamed-lints.rs:13:9
+   |
+LL | #![deny(rustdoc::non_autolinks)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `rustdoc::bare_urls`
+
 error: lint `rustdoc` has been removed: use `rustdoc::all` instead
-  --> $DIR/unknown-renamed-lints.rs:16:9
+  --> $DIR/unknown-renamed-lints.rs:20:9
    |
 LL | #![deny(rustdoc)]
    |         ^^^^^^^
 
 error: unknown lint: `rustdoc::intra_doc_link_resolution_failure`
-  --> $DIR/unknown-renamed-lints.rs:20:9
+  --> $DIR/unknown-renamed-lints.rs:24:9
    |
 LL | #![deny(rustdoc::intra_doc_link_resolution_failure)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: Compilation failed, aborting rustdoc
 
-error: aborting due to 6 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/src/test/rustdoc-ui/url-improvements.rs b/src/test/rustdoc-ui/url-improvements.rs
index d0b43de2f0e..43a13b02d0a 100644
--- a/src/test/rustdoc-ui/url-improvements.rs
+++ b/src/test/rustdoc-ui/url-improvements.rs
@@ -1,14 +1,4 @@
-#![deny(rustdoc::non_autolinks)]
-
-/// [http://aa.com](http://aa.com)
-//~^ ERROR unneeded long form for URL
-/// [http://bb.com]
-//~^ ERROR unneeded long form for URL
-///
-/// [http://bb.com]: http://bb.com
-///
-/// [http://c.com][http://c.com]
-pub fn a() {}
+#![deny(rustdoc::bare_urls)]
 
 /// https://somewhere.com
 //~^ ERROR this URL is not a hyperlink
@@ -54,12 +44,14 @@ pub fn c() {}
 ///
 /// ```
 /// This link should not be linted: http://example.com
+///
+/// Nor this one: <http://example.com> or this one: [x](http://example.com)
 /// ```
 ///
 /// [should_not.lint](should_not.lint)
 pub fn everything_is_fine_here() {}
 
-#[allow(rustdoc::non_autolinks)]
+#[allow(rustdoc::bare_urls)]
 pub mod foo {
     /// https://somewhere.com/a?hello=12&bye=11#xyz
     pub fn bar() {}
diff --git a/src/test/rustdoc-ui/url-improvements.stderr b/src/test/rustdoc-ui/url-improvements.stderr
index f377973656a..3d5ebd8be6b 100644
--- a/src/test/rustdoc-ui/url-improvements.stderr
+++ b/src/test/rustdoc-ui/url-improvements.stderr
@@ -1,122 +1,110 @@
-error: unneeded long form for URL
+error: this URL is not a hyperlink
   --> $DIR/url-improvements.rs:3:5
    |
-LL | /// [http://aa.com](http://aa.com)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://aa.com>`
+LL | /// https://somewhere.com
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com>`
    |
 note: the lint level is defined here
   --> $DIR/url-improvements.rs:1:9
    |
-LL | #![deny(rustdoc::non_autolinks)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^
-
-error: unneeded long form for URL
-  --> $DIR/url-improvements.rs:5:5
-   |
-LL | /// [http://bb.com]
-   |     ^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://bb.com>`
+LL | #![deny(rustdoc::bare_urls)]
+   |         ^^^^^^^^^^^^^^^^^^
 
 error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:13:5
-   |
-LL | /// https://somewhere.com
-   |     ^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com>`
-
-error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:15:5
+  --> $DIR/url-improvements.rs:5:5
    |
 LL | /// https://somewhere.com/a
    |     ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a>`
 
 error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:17:5
+  --> $DIR/url-improvements.rs:7:5
    |
 LL | /// https://www.somewhere.com
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://www.somewhere.com>`
 
 error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:19:5
+  --> $DIR/url-improvements.rs:9:5
    |
 LL | /// https://www.somewhere.com/a
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://www.somewhere.com/a>`
 
 error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:21:5
+  --> $DIR/url-improvements.rs:11:5
    |
 LL | /// https://subdomain.example.com
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://subdomain.example.com>`
 
 error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:23:5
+  --> $DIR/url-improvements.rs:13:5
    |
 LL | /// https://somewhere.com?
    |     ^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?>`
 
 error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:25:5
+  --> $DIR/url-improvements.rs:15:5
    |
 LL | /// https://somewhere.com/a?
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?>`
 
 error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:27:5
+  --> $DIR/url-improvements.rs:17:5
    |
 LL | /// https://somewhere.com?hello=12
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12>`
 
 error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:29:5
+  --> $DIR/url-improvements.rs:19:5
    |
 LL | /// https://somewhere.com/a?hello=12
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12>`
 
 error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:31:5
+  --> $DIR/url-improvements.rs:21:5
    |
 LL | /// https://example.com?hello=12#xyz
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com?hello=12#xyz>`
 
 error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:33:5
+  --> $DIR/url-improvements.rs:23:5
    |
 LL | /// https://example.com/a?hello=12#xyz
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com/a?hello=12#xyz>`
 
 error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:35:5
+  --> $DIR/url-improvements.rs:25:5
    |
 LL | /// https://example.com#xyz
    |     ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com#xyz>`
 
 error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:37:5
+  --> $DIR/url-improvements.rs:27:5
    |
 LL | /// https://example.com/a#xyz
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com/a#xyz>`
 
 error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:39:5
+  --> $DIR/url-improvements.rs:29:5
    |
 LL | /// https://somewhere.com?hello=12&bye=11
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12&bye=11>`
 
 error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:41:5
+  --> $DIR/url-improvements.rs:31:5
    |
 LL | /// https://somewhere.com/a?hello=12&bye=11
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12&bye=11>`
 
 error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:43:5
+  --> $DIR/url-improvements.rs:33:5
    |
 LL | /// https://somewhere.com?hello=12&bye=11#xyz
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12&bye=11#xyz>`
 
 error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:45:10
+  --> $DIR/url-improvements.rs:35:10
    |
 LL | /// hey! https://somewhere.com/a?hello=12&bye=11#xyz
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12&bye=11#xyz>`
 
-error: aborting due to 19 previous errors
+error: aborting due to 17 previous errors
 
diff --git a/src/test/ui/asm/sym.rs b/src/test/ui/asm/sym.rs
index 634ef010e6f..18be201d640 100644
--- a/src/test/ui/asm/sym.rs
+++ b/src/test/ui/asm/sym.rs
@@ -1,4 +1,6 @@
 // min-llvm-version: 10.0.1
+// FIXME(#84025): codegen-units=1 leads to linkage errors
+// compile-flags: -C codegen-units=2
 // only-x86_64
 // only-linux
 // run-pass
diff --git a/src/test/ui/codemap_tests/unicode.stderr b/src/test/ui/codemap_tests/unicode.stderr
index b7ba4fa46d9..357dd25389e 100644
--- a/src/test/ui/codemap_tests/unicode.stderr
+++ b/src/test/ui/codemap_tests/unicode.stderr
@@ -4,7 +4,7 @@ error[E0703]: invalid ABI: found `路濫狼á́́`
 LL | extern "路濫狼á́́" fn foo() {}
    |        ^^^^^^^^^ invalid ABI
    |
-   = help: valid ABIs: Rust, C, C-unwind, cdecl, stdcall, stdcall-unwind, fastcall, vectorcall, thiscall, thiscall-unwind, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, system, system-unwind, rust-intrinsic, rust-call, platform-intrinsic, unadjusted
+   = help: valid ABIs: Rust, C, C-unwind, cdecl, stdcall, stdcall-unwind, fastcall, vectorcall, thiscall, thiscall-unwind, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, wasm, system, system-unwind, rust-intrinsic, rust-call, platform-intrinsic, unadjusted
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs b/src/test/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs
index 74c6e501c91..7b731a1d71d 100644
--- a/src/test/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs
+++ b/src/test/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs
@@ -19,7 +19,9 @@
 
 // revisions: no thin fat
 //[no]compile-flags: -C lto=no
-//[thin]compile-flags: -C lto=thin
+// FIXME(#83854) running this revision with 1 CGU triggers llvm assert in register allocator
+//  when executed in i686-gnu-nopt runner.
+//[thin]compile-flags: -C lto=thin -Ccodegen-units=2
 //[fat]compile-flags: -C lto=fat
 
 #![feature(core_panic)]
diff --git a/src/test/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs b/src/test/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs
index bc15fcb0e39..32e6d0c90b2 100644
--- a/src/test/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs
+++ b/src/test/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs
@@ -40,7 +40,9 @@
 //[no1]compile-flags: -C opt-level=1 -C lto=no
 //[no2]compile-flags: -C opt-level=2 -C lto=no
 //[no3]compile-flags: -C opt-level=3 -C lto=no
-//[thin0]compile-flags: -C opt-level=0 -C lto=thin
+// FIXME(#83854) running this revision with 1 CGU triggers llvm assert in register allocator
+//  when executed in dist-i586-gnu-i586-i686-musl runner.
+//[thin0]compile-flags: -C opt-level=0 -C lto=thin -Ccodegen-units=2
 //[thin1]compile-flags: -C opt-level=1 -C lto=thin
 //[thin2]compile-flags: -C opt-level=2 -C lto=thin
 //[thin3]compile-flags: -C opt-level=3 -C lto=thin
diff --git a/src/test/ui/feature-gates/feature-gate-abi.rs b/src/test/ui/feature-gates/feature-gate-abi.rs
index 3883106a3af..49cf2e158ed 100644
--- a/src/test/ui/feature-gates/feature-gate-abi.rs
+++ b/src/test/ui/feature-gates/feature-gate-abi.rs
@@ -10,9 +10,9 @@
 
 // Functions
 extern "rust-intrinsic" fn f1() {} //~ ERROR intrinsics are subject to change
-//~^ ERROR intrinsic must be in
+                                   //~^ ERROR intrinsic must be in
 extern "platform-intrinsic" fn f2() {} //~ ERROR platform intrinsics are experimental
-//~^ ERROR intrinsic must be in
+                                       //~^ ERROR intrinsic must be in
 extern "vectorcall" fn f3() {} //~ ERROR vectorcall is experimental and subject to change
 extern "rust-call" fn f4(_: ()) {} //~ ERROR rust-call ABI is subject to change
 extern "msp430-interrupt" fn f5() {} //~ ERROR msp430-interrupt ABI is experimental
@@ -21,13 +21,14 @@ extern "x86-interrupt" fn f7() {} //~ ERROR x86-interrupt ABI is experimental
 extern "thiscall" fn f8() {} //~ ERROR thiscall is experimental and subject to change
 extern "amdgpu-kernel" fn f9() {} //~ ERROR amdgpu-kernel ABI is experimental and subject to change
 extern "efiapi" fn f10() {} //~ ERROR efiapi ABI is experimental and subject to change
+extern "wasm" fn f11() {} //~ ERROR wasm ABI is experimental and subject to change
 
 // Methods in trait definition
 trait Tr {
     extern "rust-intrinsic" fn m1(); //~ ERROR intrinsics are subject to change
-    //~^ ERROR intrinsic must be in
+                                     //~^ ERROR intrinsic must be in
     extern "platform-intrinsic" fn m2(); //~ ERROR platform intrinsics are experimental
-    //~^ ERROR intrinsic must be in
+                                         //~^ ERROR intrinsic must be in
     extern "vectorcall" fn m3(); //~ ERROR vectorcall is experimental and subject to change
     extern "rust-call" fn m4(_: ()); //~ ERROR rust-call ABI is subject to change
     extern "msp430-interrupt" fn m5(); //~ ERROR msp430-interrupt ABI is experimental
@@ -36,6 +37,7 @@ trait Tr {
     extern "thiscall" fn m8(); //~ ERROR thiscall is experimental and subject to change
     extern "amdgpu-kernel" fn m9(); //~ ERROR amdgpu-kernel ABI is experimental and subject to change
     extern "efiapi" fn m10(); //~ ERROR efiapi ABI is experimental and subject to change
+    extern "wasm" fn m11() {} //~ ERROR wasm ABI is experimental and subject to change
 
     extern "vectorcall" fn dm3() {} //~ ERROR vectorcall is experimental and subject to change
     extern "rust-call" fn dm4(_: ()) {} //~ ERROR rust-call ABI is subject to change
@@ -45,6 +47,7 @@ trait Tr {
     extern "thiscall" fn dm8() {} //~ ERROR thiscall is experimental and subject to change
     extern "amdgpu-kernel" fn dm9() {} //~ ERROR amdgpu-kernel ABI is experimental and subject to change
     extern "efiapi" fn dm10() {} //~ ERROR efiapi ABI is experimental and subject to change
+    extern "wasm" fn dm11() {} //~ ERROR wasm ABI is experimental and subject to change
 }
 
 struct S;
@@ -52,9 +55,9 @@ struct S;
 // Methods in trait impl
 impl Tr for S {
     extern "rust-intrinsic" fn m1() {} //~ ERROR intrinsics are subject to change
-    //~^ ERROR intrinsic must be in
+                                       //~^ ERROR intrinsic must be in
     extern "platform-intrinsic" fn m2() {} //~ ERROR platform intrinsics are experimental
-    //~^ ERROR intrinsic must be in
+                                           //~^ ERROR intrinsic must be in
     extern "vectorcall" fn m3() {} //~ ERROR vectorcall is experimental and subject to change
     extern "rust-call" fn m4(_: ()) {} //~ ERROR rust-call ABI is subject to change
     extern "msp430-interrupt" fn m5() {} //~ ERROR msp430-interrupt ABI is experimental
@@ -63,14 +66,15 @@ impl Tr for S {
     extern "thiscall" fn m8() {} //~ ERROR thiscall is experimental and subject to change
     extern "amdgpu-kernel" fn m9() {} //~ ERROR amdgpu-kernel ABI is experimental and subject to change
     extern "efiapi" fn m10() {} //~ ERROR efiapi ABI is experimental and subject to change
+    extern "wasm" fn m11() {} //~ ERROR wasm ABI is experimental and subject to change
 }
 
 // Methods in inherent impl
 impl S {
     extern "rust-intrinsic" fn im1() {} //~ ERROR intrinsics are subject to change
-    //~^ ERROR intrinsic must be in
+                                        //~^ ERROR intrinsic must be in
     extern "platform-intrinsic" fn im2() {} //~ ERROR platform intrinsics are experimental
-    //~^ ERROR intrinsic must be in
+                                            //~^ ERROR intrinsic must be in
     extern "vectorcall" fn im3() {} //~ ERROR vectorcall is experimental and subject to change
     extern "rust-call" fn im4(_: ()) {} //~ ERROR rust-call ABI is subject to change
     extern "msp430-interrupt" fn im5() {} //~ ERROR msp430-interrupt ABI is experimental
@@ -79,6 +83,7 @@ impl S {
     extern "thiscall" fn im8() {} //~ ERROR thiscall is experimental and subject to change
     extern "amdgpu-kernel" fn im9() {} //~ ERROR amdgpu-kernel ABI is experimental and subject to change
     extern "efiapi" fn im10() {} //~ ERROR efiapi ABI is experimental and subject to change
+    extern "wasm" fn im11() {} //~ ERROR wasm ABI is experimental and subject to change
 }
 
 // Function pointer types
@@ -87,11 +92,12 @@ type A2 = extern "platform-intrinsic" fn(); //~ ERROR platform intrinsics are ex
 type A3 = extern "vectorcall" fn(); //~ ERROR vectorcall is experimental and subject to change
 type A4 = extern "rust-call" fn(_: ()); //~ ERROR rust-call ABI is subject to change
 type A5 = extern "msp430-interrupt" fn(); //~ ERROR msp430-interrupt ABI is experimental
-type A6 = extern "ptx-kernel" fn (); //~ ERROR PTX ABIs are experimental and subject to change
+type A6 = extern "ptx-kernel" fn(); //~ ERROR PTX ABIs are experimental and subject to change
 type A7 = extern "x86-interrupt" fn(); //~ ERROR x86-interrupt ABI is experimental
 type A8 = extern "thiscall" fn(); //~ ERROR thiscall is experimental and subject to change
 type A9 = extern "amdgpu-kernel" fn(); //~ ERROR amdgpu-kernel ABI is experimental and subject to change
 type A10 = extern "efiapi" fn(); //~ ERROR efiapi ABI is experimental and subject to change
+type A11 = extern "wasm" fn(); //~ ERROR wasm ABI is experimental and subject to change
 
 // Foreign modules
 extern "rust-intrinsic" {} //~ ERROR intrinsics are subject to change
@@ -104,5 +110,6 @@ extern "x86-interrupt" {} //~ ERROR x86-interrupt ABI is experimental
 extern "thiscall" {} //~ ERROR thiscall is experimental and subject to change
 extern "amdgpu-kernel" {} //~ ERROR amdgpu-kernel ABI is experimental and subject to change
 extern "efiapi" {} //~ ERROR efiapi ABI is experimental and subject to change
+extern "wasm" {} //~ ERROR wasm ABI is experimental and subject to change
 
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-abi.stderr b/src/test/ui/feature-gates/feature-gate-abi.stderr
index eeeb349c662..078d21ad36f 100644
--- a/src/test/ui/feature-gates/feature-gate-abi.stderr
+++ b/src/test/ui/feature-gates/feature-gate-abi.stderr
@@ -85,8 +85,17 @@ LL | extern "efiapi" fn f10() {}
    = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
    = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
 
+error[E0658]: wasm ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi.rs:24:8
+   |
+LL | extern "wasm" fn f11() {}
+   |        ^^^^^^
+   |
+   = note: see issue #83788 <https://github.com/rust-lang/rust/issues/83788> for more information
+   = help: add `#![feature(wasm_abi)]` to the crate attributes to enable
+
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:27:12
+  --> $DIR/feature-gate-abi.rs:28:12
    |
 LL |     extern "rust-intrinsic" fn m1();
    |            ^^^^^^^^^^^^^^^^
@@ -94,7 +103,7 @@ LL |     extern "rust-intrinsic" fn m1();
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:29:12
+  --> $DIR/feature-gate-abi.rs:30:12
    |
 LL |     extern "platform-intrinsic" fn m2();
    |            ^^^^^^^^^^^^^^^^^^^^
@@ -103,7 +112,7 @@ LL |     extern "platform-intrinsic" fn m2();
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: vectorcall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:31:12
+  --> $DIR/feature-gate-abi.rs:32:12
    |
 LL |     extern "vectorcall" fn m3();
    |            ^^^^^^^^^^^^
@@ -111,7 +120,7 @@ LL |     extern "vectorcall" fn m3();
    = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:32:12
+  --> $DIR/feature-gate-abi.rs:33:12
    |
 LL |     extern "rust-call" fn m4(_: ());
    |            ^^^^^^^^^^^
@@ -120,7 +129,7 @@ LL |     extern "rust-call" fn m4(_: ());
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: msp430-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:33:12
+  --> $DIR/feature-gate-abi.rs:34:12
    |
 LL |     extern "msp430-interrupt" fn m5();
    |            ^^^^^^^^^^^^^^^^^^
@@ -129,7 +138,7 @@ LL |     extern "msp430-interrupt" fn m5();
    = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable
 
 error[E0658]: PTX ABIs are experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:34:12
+  --> $DIR/feature-gate-abi.rs:35:12
    |
 LL |     extern "ptx-kernel" fn m6();
    |            ^^^^^^^^^^^^
@@ -138,7 +147,7 @@ LL |     extern "ptx-kernel" fn m6();
    = help: add `#![feature(abi_ptx)]` to the crate attributes to enable
 
 error[E0658]: x86-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:35:12
+  --> $DIR/feature-gate-abi.rs:36:12
    |
 LL |     extern "x86-interrupt" fn m7();
    |            ^^^^^^^^^^^^^^^
@@ -147,7 +156,7 @@ LL |     extern "x86-interrupt" fn m7();
    = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable
 
 error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:36:12
+  --> $DIR/feature-gate-abi.rs:37:12
    |
 LL |     extern "thiscall" fn m8();
    |            ^^^^^^^^^^
@@ -155,7 +164,7 @@ LL |     extern "thiscall" fn m8();
    = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
 
 error[E0658]: amdgpu-kernel ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:37:12
+  --> $DIR/feature-gate-abi.rs:38:12
    |
 LL |     extern "amdgpu-kernel" fn m9();
    |            ^^^^^^^^^^^^^^^
@@ -164,7 +173,7 @@ LL |     extern "amdgpu-kernel" fn m9();
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
 error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:38:12
+  --> $DIR/feature-gate-abi.rs:39:12
    |
 LL |     extern "efiapi" fn m10();
    |            ^^^^^^^^
@@ -172,16 +181,25 @@ LL |     extern "efiapi" fn m10();
    = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
    = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
 
-error[E0658]: vectorcall is experimental and subject to change
+error[E0658]: wasm ABI is experimental and subject to change
   --> $DIR/feature-gate-abi.rs:40:12
    |
+LL |     extern "wasm" fn m11() {}
+   |            ^^^^^^
+   |
+   = note: see issue #83788 <https://github.com/rust-lang/rust/issues/83788> for more information
+   = help: add `#![feature(wasm_abi)]` to the crate attributes to enable
+
+error[E0658]: vectorcall is experimental and subject to change
+  --> $DIR/feature-gate-abi.rs:42:12
+   |
 LL |     extern "vectorcall" fn dm3() {}
    |            ^^^^^^^^^^^^
    |
    = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:41:12
+  --> $DIR/feature-gate-abi.rs:43:12
    |
 LL |     extern "rust-call" fn dm4(_: ()) {}
    |            ^^^^^^^^^^^
@@ -190,7 +208,7 @@ LL |     extern "rust-call" fn dm4(_: ()) {}
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: msp430-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:42:12
+  --> $DIR/feature-gate-abi.rs:44:12
    |
 LL |     extern "msp430-interrupt" fn dm5() {}
    |            ^^^^^^^^^^^^^^^^^^
@@ -199,7 +217,7 @@ LL |     extern "msp430-interrupt" fn dm5() {}
    = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable
 
 error[E0658]: PTX ABIs are experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:43:12
+  --> $DIR/feature-gate-abi.rs:45:12
    |
 LL |     extern "ptx-kernel" fn dm6() {}
    |            ^^^^^^^^^^^^
@@ -208,7 +226,7 @@ LL |     extern "ptx-kernel" fn dm6() {}
    = help: add `#![feature(abi_ptx)]` to the crate attributes to enable
 
 error[E0658]: x86-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:44:12
+  --> $DIR/feature-gate-abi.rs:46:12
    |
 LL |     extern "x86-interrupt" fn dm7() {}
    |            ^^^^^^^^^^^^^^^
@@ -217,7 +235,7 @@ LL |     extern "x86-interrupt" fn dm7() {}
    = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable
 
 error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:45:12
+  --> $DIR/feature-gate-abi.rs:47:12
    |
 LL |     extern "thiscall" fn dm8() {}
    |            ^^^^^^^^^^
@@ -225,7 +243,7 @@ LL |     extern "thiscall" fn dm8() {}
    = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
 
 error[E0658]: amdgpu-kernel ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:46:12
+  --> $DIR/feature-gate-abi.rs:48:12
    |
 LL |     extern "amdgpu-kernel" fn dm9() {}
    |            ^^^^^^^^^^^^^^^
@@ -234,7 +252,7 @@ LL |     extern "amdgpu-kernel" fn dm9() {}
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
 error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:47:12
+  --> $DIR/feature-gate-abi.rs:49:12
    |
 LL |     extern "efiapi" fn dm10() {}
    |            ^^^^^^^^
@@ -242,8 +260,17 @@ LL |     extern "efiapi" fn dm10() {}
    = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
    = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
 
+error[E0658]: wasm ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi.rs:50:12
+   |
+LL |     extern "wasm" fn dm11() {}
+   |            ^^^^^^
+   |
+   = note: see issue #83788 <https://github.com/rust-lang/rust/issues/83788> for more information
+   = help: add `#![feature(wasm_abi)]` to the crate attributes to enable
+
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:54:12
+  --> $DIR/feature-gate-abi.rs:57:12
    |
 LL |     extern "rust-intrinsic" fn m1() {}
    |            ^^^^^^^^^^^^^^^^
@@ -251,7 +278,7 @@ LL |     extern "rust-intrinsic" fn m1() {}
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:56:12
+  --> $DIR/feature-gate-abi.rs:59:12
    |
 LL |     extern "platform-intrinsic" fn m2() {}
    |            ^^^^^^^^^^^^^^^^^^^^
@@ -260,7 +287,7 @@ LL |     extern "platform-intrinsic" fn m2() {}
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: vectorcall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:58:12
+  --> $DIR/feature-gate-abi.rs:61:12
    |
 LL |     extern "vectorcall" fn m3() {}
    |            ^^^^^^^^^^^^
@@ -268,7 +295,7 @@ LL |     extern "vectorcall" fn m3() {}
    = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:59:12
+  --> $DIR/feature-gate-abi.rs:62:12
    |
 LL |     extern "rust-call" fn m4(_: ()) {}
    |            ^^^^^^^^^^^
@@ -277,7 +304,7 @@ LL |     extern "rust-call" fn m4(_: ()) {}
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: msp430-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:60:12
+  --> $DIR/feature-gate-abi.rs:63:12
    |
 LL |     extern "msp430-interrupt" fn m5() {}
    |            ^^^^^^^^^^^^^^^^^^
@@ -286,7 +313,7 @@ LL |     extern "msp430-interrupt" fn m5() {}
    = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable
 
 error[E0658]: PTX ABIs are experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:61:12
+  --> $DIR/feature-gate-abi.rs:64:12
    |
 LL |     extern "ptx-kernel" fn m6() {}
    |            ^^^^^^^^^^^^
@@ -295,7 +322,7 @@ LL |     extern "ptx-kernel" fn m6() {}
    = help: add `#![feature(abi_ptx)]` to the crate attributes to enable
 
 error[E0658]: x86-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:62:12
+  --> $DIR/feature-gate-abi.rs:65:12
    |
 LL |     extern "x86-interrupt" fn m7() {}
    |            ^^^^^^^^^^^^^^^
@@ -304,7 +331,7 @@ LL |     extern "x86-interrupt" fn m7() {}
    = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable
 
 error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:63:12
+  --> $DIR/feature-gate-abi.rs:66:12
    |
 LL |     extern "thiscall" fn m8() {}
    |            ^^^^^^^^^^
@@ -312,7 +339,7 @@ LL |     extern "thiscall" fn m8() {}
    = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
 
 error[E0658]: amdgpu-kernel ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:64:12
+  --> $DIR/feature-gate-abi.rs:67:12
    |
 LL |     extern "amdgpu-kernel" fn m9() {}
    |            ^^^^^^^^^^^^^^^
@@ -321,7 +348,7 @@ LL |     extern "amdgpu-kernel" fn m9() {}
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
 error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:65:12
+  --> $DIR/feature-gate-abi.rs:68:12
    |
 LL |     extern "efiapi" fn m10() {}
    |            ^^^^^^^^
@@ -329,8 +356,17 @@ LL |     extern "efiapi" fn m10() {}
    = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
    = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
 
+error[E0658]: wasm ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi.rs:69:12
+   |
+LL |     extern "wasm" fn m11() {}
+   |            ^^^^^^
+   |
+   = note: see issue #83788 <https://github.com/rust-lang/rust/issues/83788> for more information
+   = help: add `#![feature(wasm_abi)]` to the crate attributes to enable
+
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:70:12
+  --> $DIR/feature-gate-abi.rs:74:12
    |
 LL |     extern "rust-intrinsic" fn im1() {}
    |            ^^^^^^^^^^^^^^^^
@@ -338,7 +374,7 @@ LL |     extern "rust-intrinsic" fn im1() {}
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:72:12
+  --> $DIR/feature-gate-abi.rs:76:12
    |
 LL |     extern "platform-intrinsic" fn im2() {}
    |            ^^^^^^^^^^^^^^^^^^^^
@@ -347,7 +383,7 @@ LL |     extern "platform-intrinsic" fn im2() {}
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: vectorcall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:74:12
+  --> $DIR/feature-gate-abi.rs:78:12
    |
 LL |     extern "vectorcall" fn im3() {}
    |            ^^^^^^^^^^^^
@@ -355,7 +391,7 @@ LL |     extern "vectorcall" fn im3() {}
    = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:75:12
+  --> $DIR/feature-gate-abi.rs:79:12
    |
 LL |     extern "rust-call" fn im4(_: ()) {}
    |            ^^^^^^^^^^^
@@ -364,7 +400,7 @@ LL |     extern "rust-call" fn im4(_: ()) {}
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: msp430-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:76:12
+  --> $DIR/feature-gate-abi.rs:80:12
    |
 LL |     extern "msp430-interrupt" fn im5() {}
    |            ^^^^^^^^^^^^^^^^^^
@@ -373,7 +409,7 @@ LL |     extern "msp430-interrupt" fn im5() {}
    = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable
 
 error[E0658]: PTX ABIs are experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:77:12
+  --> $DIR/feature-gate-abi.rs:81:12
    |
 LL |     extern "ptx-kernel" fn im6() {}
    |            ^^^^^^^^^^^^
@@ -382,7 +418,7 @@ LL |     extern "ptx-kernel" fn im6() {}
    = help: add `#![feature(abi_ptx)]` to the crate attributes to enable
 
 error[E0658]: x86-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:78:12
+  --> $DIR/feature-gate-abi.rs:82:12
    |
 LL |     extern "x86-interrupt" fn im7() {}
    |            ^^^^^^^^^^^^^^^
@@ -391,7 +427,7 @@ LL |     extern "x86-interrupt" fn im7() {}
    = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable
 
 error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:79:12
+  --> $DIR/feature-gate-abi.rs:83:12
    |
 LL |     extern "thiscall" fn im8() {}
    |            ^^^^^^^^^^
@@ -399,7 +435,7 @@ LL |     extern "thiscall" fn im8() {}
    = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
 
 error[E0658]: amdgpu-kernel ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:80:12
+  --> $DIR/feature-gate-abi.rs:84:12
    |
 LL |     extern "amdgpu-kernel" fn im9() {}
    |            ^^^^^^^^^^^^^^^
@@ -408,7 +444,7 @@ LL |     extern "amdgpu-kernel" fn im9() {}
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
 error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:81:12
+  --> $DIR/feature-gate-abi.rs:85:12
    |
 LL |     extern "efiapi" fn im10() {}
    |            ^^^^^^^^
@@ -416,8 +452,17 @@ LL |     extern "efiapi" fn im10() {}
    = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
    = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
 
+error[E0658]: wasm ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi.rs:86:12
+   |
+LL |     extern "wasm" fn im11() {}
+   |            ^^^^^^
+   |
+   = note: see issue #83788 <https://github.com/rust-lang/rust/issues/83788> for more information
+   = help: add `#![feature(wasm_abi)]` to the crate attributes to enable
+
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:85:18
+  --> $DIR/feature-gate-abi.rs:90:18
    |
 LL | type A1 = extern "rust-intrinsic" fn();
    |                  ^^^^^^^^^^^^^^^^
@@ -425,7 +470,7 @@ LL | type A1 = extern "rust-intrinsic" fn();
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:86:18
+  --> $DIR/feature-gate-abi.rs:91:18
    |
 LL | type A2 = extern "platform-intrinsic" fn();
    |                  ^^^^^^^^^^^^^^^^^^^^
@@ -434,7 +479,7 @@ LL | type A2 = extern "platform-intrinsic" fn();
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: vectorcall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:87:18
+  --> $DIR/feature-gate-abi.rs:92:18
    |
 LL | type A3 = extern "vectorcall" fn();
    |                  ^^^^^^^^^^^^
@@ -442,7 +487,7 @@ LL | type A3 = extern "vectorcall" fn();
    = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:88:18
+  --> $DIR/feature-gate-abi.rs:93:18
    |
 LL | type A4 = extern "rust-call" fn(_: ());
    |                  ^^^^^^^^^^^
@@ -451,7 +496,7 @@ LL | type A4 = extern "rust-call" fn(_: ());
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: msp430-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:89:18
+  --> $DIR/feature-gate-abi.rs:94:18
    |
 LL | type A5 = extern "msp430-interrupt" fn();
    |                  ^^^^^^^^^^^^^^^^^^
@@ -460,16 +505,16 @@ LL | type A5 = extern "msp430-interrupt" fn();
    = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable
 
 error[E0658]: PTX ABIs are experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:90:18
+  --> $DIR/feature-gate-abi.rs:95:18
    |
-LL | type A6 = extern "ptx-kernel" fn ();
+LL | type A6 = extern "ptx-kernel" fn();
    |                  ^^^^^^^^^^^^
    |
    = note: see issue #38788 <https://github.com/rust-lang/rust/issues/38788> for more information
    = help: add `#![feature(abi_ptx)]` to the crate attributes to enable
 
 error[E0658]: x86-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:91:18
+  --> $DIR/feature-gate-abi.rs:96:18
    |
 LL | type A7 = extern "x86-interrupt" fn();
    |                  ^^^^^^^^^^^^^^^
@@ -478,7 +523,7 @@ LL | type A7 = extern "x86-interrupt" fn();
    = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable
 
 error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:92:18
+  --> $DIR/feature-gate-abi.rs:97:18
    |
 LL | type A8 = extern "thiscall" fn();
    |                  ^^^^^^^^^^
@@ -486,7 +531,7 @@ LL | type A8 = extern "thiscall" fn();
    = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
 
 error[E0658]: amdgpu-kernel ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:93:18
+  --> $DIR/feature-gate-abi.rs:98:18
    |
 LL | type A9 = extern "amdgpu-kernel" fn();
    |                  ^^^^^^^^^^^^^^^
@@ -495,7 +540,7 @@ LL | type A9 = extern "amdgpu-kernel" fn();
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
 error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:94:19
+  --> $DIR/feature-gate-abi.rs:99:19
    |
 LL | type A10 = extern "efiapi" fn();
    |                   ^^^^^^^^
@@ -503,8 +548,17 @@ LL | type A10 = extern "efiapi" fn();
    = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
    = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
 
+error[E0658]: wasm ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi.rs:100:19
+   |
+LL | type A11 = extern "wasm" fn();
+   |                   ^^^^^^
+   |
+   = note: see issue #83788 <https://github.com/rust-lang/rust/issues/83788> for more information
+   = help: add `#![feature(wasm_abi)]` to the crate attributes to enable
+
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:97:8
+  --> $DIR/feature-gate-abi.rs:103:8
    |
 LL | extern "rust-intrinsic" {}
    |        ^^^^^^^^^^^^^^^^
@@ -512,7 +566,7 @@ LL | extern "rust-intrinsic" {}
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:98:8
+  --> $DIR/feature-gate-abi.rs:104:8
    |
 LL | extern "platform-intrinsic" {}
    |        ^^^^^^^^^^^^^^^^^^^^
@@ -521,7 +575,7 @@ LL | extern "platform-intrinsic" {}
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: vectorcall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:99:8
+  --> $DIR/feature-gate-abi.rs:105:8
    |
 LL | extern "vectorcall" {}
    |        ^^^^^^^^^^^^
@@ -529,7 +583,7 @@ LL | extern "vectorcall" {}
    = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:100:8
+  --> $DIR/feature-gate-abi.rs:106:8
    |
 LL | extern "rust-call" {}
    |        ^^^^^^^^^^^
@@ -538,7 +592,7 @@ LL | extern "rust-call" {}
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: msp430-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:101:8
+  --> $DIR/feature-gate-abi.rs:107:8
    |
 LL | extern "msp430-interrupt" {}
    |        ^^^^^^^^^^^^^^^^^^
@@ -547,7 +601,7 @@ LL | extern "msp430-interrupt" {}
    = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable
 
 error[E0658]: PTX ABIs are experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:102:8
+  --> $DIR/feature-gate-abi.rs:108:8
    |
 LL | extern "ptx-kernel" {}
    |        ^^^^^^^^^^^^
@@ -556,7 +610,7 @@ LL | extern "ptx-kernel" {}
    = help: add `#![feature(abi_ptx)]` to the crate attributes to enable
 
 error[E0658]: x86-interrupt ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:103:8
+  --> $DIR/feature-gate-abi.rs:109:8
    |
 LL | extern "x86-interrupt" {}
    |        ^^^^^^^^^^^^^^^
@@ -565,7 +619,7 @@ LL | extern "x86-interrupt" {}
    = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable
 
 error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:104:8
+  --> $DIR/feature-gate-abi.rs:110:8
    |
 LL | extern "thiscall" {}
    |        ^^^^^^^^^^
@@ -573,7 +627,7 @@ LL | extern "thiscall" {}
    = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
 
 error[E0658]: amdgpu-kernel ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:105:8
+  --> $DIR/feature-gate-abi.rs:111:8
    |
 LL | extern "amdgpu-kernel" {}
    |        ^^^^^^^^^^^^^^^
@@ -582,7 +636,7 @@ LL | extern "amdgpu-kernel" {}
    = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable
 
 error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:106:8
+  --> $DIR/feature-gate-abi.rs:112:8
    |
 LL | extern "efiapi" {}
    |        ^^^^^^^^
@@ -590,14 +644,23 @@ LL | extern "efiapi" {}
    = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information
    = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
 
+error[E0658]: wasm ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi.rs:113:8
+   |
+LL | extern "wasm" {}
+   |        ^^^^^^
+   |
+   = note: see issue #83788 <https://github.com/rust-lang/rust/issues/83788> for more information
+   = help: add `#![feature(wasm_abi)]` to the crate attributes to enable
+
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:27:32
+  --> $DIR/feature-gate-abi.rs:28:32
    |
 LL |     extern "rust-intrinsic" fn m1();
    |                                ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:29:36
+  --> $DIR/feature-gate-abi.rs:30:36
    |
 LL |     extern "platform-intrinsic" fn m2();
    |                                    ^^
@@ -615,29 +678,29 @@ LL | extern "platform-intrinsic" fn f2() {}
    |                                     ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:54:37
+  --> $DIR/feature-gate-abi.rs:57:37
    |
 LL |     extern "rust-intrinsic" fn m1() {}
    |                                     ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:56:41
+  --> $DIR/feature-gate-abi.rs:59:41
    |
 LL |     extern "platform-intrinsic" fn m2() {}
    |                                         ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:70:38
+  --> $DIR/feature-gate-abi.rs:74:38
    |
 LL |     extern "rust-intrinsic" fn im1() {}
    |                                      ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:72:42
+  --> $DIR/feature-gate-abi.rs:76:42
    |
 LL |     extern "platform-intrinsic" fn im2() {}
    |                                          ^^
 
-error: aborting due to 76 previous errors
+error: aborting due to 83 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-wasm_abi.rs b/src/test/ui/feature-gates/feature-gate-wasm_abi.rs
new file mode 100644
index 00000000000..8c8de076365
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-wasm_abi.rs
@@ -0,0 +1,7 @@
+extern "wasm" fn foo() {
+    //~^ ERROR: wasm ABI is experimental and subject to change
+}
+
+fn main() {
+    foo();
+}
diff --git a/src/test/ui/feature-gates/feature-gate-wasm_abi.stderr b/src/test/ui/feature-gates/feature-gate-wasm_abi.stderr
new file mode 100644
index 00000000000..c4113fd6af9
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-wasm_abi.stderr
@@ -0,0 +1,12 @@
+error[E0658]: wasm ABI is experimental and subject to change
+  --> $DIR/feature-gate-wasm_abi.rs:1:8
+   |
+LL | extern "wasm" fn foo() {
+   |        ^^^^^^
+   |
+   = note: see issue #83788 <https://github.com/rust-lang/rust/issues/83788> for more information
+   = help: add `#![feature(wasm_abi)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/issues/issue-69225-SCEVAddExpr-wrap-flag.rs b/src/test/ui/issues/issue-69225-SCEVAddExpr-wrap-flag.rs
index 6e030f1cc48..e04dec24e44 100644
--- a/src/test/ui/issues/issue-69225-SCEVAddExpr-wrap-flag.rs
+++ b/src/test/ui/issues/issue-69225-SCEVAddExpr-wrap-flag.rs
@@ -1,5 +1,6 @@
 // run-fail
 // compile-flags: -C opt-level=3
+// min-llvm-version: 11.0
 // error-pattern: index out of bounds: the len is 0 but the index is 16777216
 // ignore-wasm no panic or subprocess support
 // ignore-emscripten no panic or subprocess support
diff --git a/src/test/ui/lifetimes/issue-83737-binders-across-types.rs b/src/test/ui/lifetimes/issue-83737-binders-across-types.rs
new file mode 100644
index 00000000000..e130561e466
--- /dev/null
+++ b/src/test/ui/lifetimes/issue-83737-binders-across-types.rs
@@ -0,0 +1,14 @@
+// build-pass
+// compile-flags: --edition 2018
+// compile-flags: --crate-type rlib
+
+use std::future::Future;
+
+async fn handle<F>(slf: &F)
+where
+    F: Fn(&()) -> Box<dyn Future<Output = ()> + Unpin>,
+{
+    (slf)(&()).await;
+}
+
+fn main() {}
diff --git a/src/test/ui/linkage-attr/linkage-detect-extern-generated-name-collision.rs b/src/test/ui/linkage-attr/linkage-detect-extern-generated-name-collision.rs
index 7b2f5365aca..3a0910658b7 100644
--- a/src/test/ui/linkage-attr/linkage-detect-extern-generated-name-collision.rs
+++ b/src/test/ui/linkage-attr/linkage-detect-extern-generated-name-collision.rs
@@ -4,6 +4,8 @@
 
 // build-fail
 // aux-build:def_colliding_external.rs
+// FIXME(#83838) codegen-units=1 triggers llvm asserts
+// compile-flags: -Ccodegen-units=16
 
 extern crate def_colliding_external as dep1;
 
diff --git a/src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.rs b/src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.rs
index b712f3225ed..c1df9ccef22 100644
--- a/src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.rs
+++ b/src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.rs
@@ -1,5 +1,6 @@
 // build-fail
-
+// FIXME(#83838) codegen-units=1 triggers llvm asserts
+// compile-flags: -Ccodegen-units=16
 #![feature(linkage)]
 
 mod dep1 {
diff --git a/src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.stderr b/src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.stderr
index d008acc6e7c..7e395e67378 100644
--- a/src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.stderr
+++ b/src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.stderr
@@ -1,5 +1,5 @@
 error: symbol `collision` is already defined
-  --> $DIR/linkage-detect-local-generated-name-collision.rs:9:9
+  --> $DIR/linkage-detect-local-generated-name-collision.rs:10:9
    |
 LL |         pub static collision: *const i32;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/macros/builtin-std-paths-fail.stderr b/src/test/ui/macros/builtin-std-paths-fail.stderr
index 4f1a76b0d6e..ba626101190 100644
--- a/src/test/ui/macros/builtin-std-paths-fail.stderr
+++ b/src/test/ui/macros/builtin-std-paths-fail.stderr
@@ -10,6 +10,18 @@ error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
 LL |     core::RustcDecodable,
    |           ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
 
+error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
+  --> $DIR/builtin-std-paths-fail.rs:2:11
+   |
+LL |     core::RustcDecodable,
+   |           ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
+
+error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
+  --> $DIR/builtin-std-paths-fail.rs:4:11
+   |
+LL |     core::RustcDecodable,
+   |           ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
+
 error[E0433]: failed to resolve: could not find `bench` in `core`
   --> $DIR/builtin-std-paths-fail.rs:7:9
    |
@@ -34,17 +46,17 @@ error[E0433]: failed to resolve: could not find `test` in `core`
 LL | #[core::test]
    |         ^^^^ could not find `test` in `core`
 
-error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
-  --> $DIR/builtin-std-paths-fail.rs:4:11
+error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
+  --> $DIR/builtin-std-paths-fail.rs:14:10
    |
-LL |     core::RustcDecodable,
-   |           ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
+LL |     std::RustcDecodable,
+   |          ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std`
 
-error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
-  --> $DIR/builtin-std-paths-fail.rs:2:11
+error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
+  --> $DIR/builtin-std-paths-fail.rs:16:10
    |
-LL |     core::RustcDecodable,
-   |           ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
+LL |     std::RustcDecodable,
+   |          ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std`
 
 error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
   --> $DIR/builtin-std-paths-fail.rs:14:10
@@ -82,18 +94,6 @@ error[E0433]: failed to resolve: could not find `test` in `std`
 LL | #[std::test]
    |        ^^^^ could not find `test` in `std`
 
-error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
-  --> $DIR/builtin-std-paths-fail.rs:16:10
-   |
-LL |     std::RustcDecodable,
-   |          ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std`
-
-error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
-  --> $DIR/builtin-std-paths-fail.rs:14:10
-   |
-LL |     std::RustcDecodable,
-   |          ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std`
-
 error: aborting due to 16 previous errors
 
 For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/panic-runtime/unwind-tables-panic-required.rs b/src/test/ui/panic-runtime/unwind-tables-panic-required.rs
deleted file mode 100644
index 79e91879051..00000000000
--- a/src/test/ui/panic-runtime/unwind-tables-panic-required.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-// Tests that the compiler errors if the user tries to turn off unwind tables
-// when they are required.
-//
-// dont-check-compiler-stderr
-// compile-flags: -C panic=unwind -C force-unwind-tables=no
-//
-// error-pattern: panic=unwind requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`.
-
-pub fn main() {
-}
diff --git a/src/test/ui/parser/issue-63116.stderr b/src/test/ui/parser/issue-63116.stderr
index e249a93df92..4766dfafea1 100644
--- a/src/test/ui/parser/issue-63116.stderr
+++ b/src/test/ui/parser/issue-63116.stderr
@@ -12,11 +12,11 @@ error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `;`
 LL | impl W <s(f;Y(;]
    |            ^ expected one of 7 possible tokens
 
-error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `->`, `...`, `::`, `:`, `<`, `=`, `>`, `?`, `[`, `_`, `async`, `const`, `dyn`, `extern`, `fn`, `for`, `impl`, `unsafe`, lifetime, or path, found `;`
-  --> $DIR/issue-63116.rs:3:15
+error: mismatched closing delimiter: `]`
+  --> $DIR/issue-63116.rs:3:16
    |
 LL | impl W <s(f;Y(;]
-   |              -^ help: `)` may belong here
+   |              - ^ mismatched closing delimiter
    |              |
    |              unclosed delimiter
 
diff --git a/src/test/ui/parser/issue-8537.stderr b/src/test/ui/parser/issue-8537.stderr
index 85e2b77d867..5a29ce2221f 100644
--- a/src/test/ui/parser/issue-8537.stderr
+++ b/src/test/ui/parser/issue-8537.stderr
@@ -4,7 +4,7 @@ error[E0703]: invalid ABI: found `invalid-ab_isize`
 LL |   "invalid-ab_isize"
    |   ^^^^^^^^^^^^^^^^^^ invalid ABI
    |
-   = help: valid ABIs: Rust, C, C-unwind, cdecl, stdcall, stdcall-unwind, fastcall, vectorcall, thiscall, thiscall-unwind, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, system, system-unwind, rust-intrinsic, rust-call, platform-intrinsic, unadjusted
+   = help: valid ABIs: Rust, C, C-unwind, cdecl, stdcall, stdcall-unwind, fastcall, vectorcall, thiscall, thiscall-unwind, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, wasm, system, system-unwind, rust-intrinsic, rust-call, platform-intrinsic, unadjusted
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/use-unclosed-brace.rs b/src/test/ui/parser/use-unclosed-brace.rs
new file mode 100644
index 00000000000..41742f37f3c
--- /dev/null
+++ b/src/test/ui/parser/use-unclosed-brace.rs
@@ -0,0 +1,12 @@
+// error-pattern: expected one of `,`, `::`, `as`, or `}`, found `;`
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: expected item, found `}`
+use foo::{bar, baz;
+
+use std::fmt::Display;
+
+mod bar { }
+
+mod baz { }
+
+fn main() {}
diff --git a/src/test/ui/parser/use-unclosed-brace.stderr b/src/test/ui/parser/use-unclosed-brace.stderr
new file mode 100644
index 00000000000..d29a68f8214
--- /dev/null
+++ b/src/test/ui/parser/use-unclosed-brace.stderr
@@ -0,0 +1,27 @@
+error: this file contains an unclosed delimiter
+  --> $DIR/use-unclosed-brace.rs:12:14
+   |
+LL | use foo::{bar, baz;
+   |          - unclosed delimiter
+...
+LL | fn main() {}
+   |              ^
+
+error: expected one of `,`, `::`, `as`, or `}`, found `;`
+  --> $DIR/use-unclosed-brace.rs:4:19
+   |
+LL | use foo::{bar, baz;
+   |          -        ^
+   |          |        |
+   |          |        expected one of `,`, `::`, `as`, or `}`
+   |          |        help: `}` may belong here
+   |          unclosed delimiter
+
+error: expected item, found `}`
+  --> $DIR/use-unclosed-brace.rs:12:14
+   |
+LL | fn main() {}
+   |              ^ expected item
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/proc-macro/attr-complex-fn.stdout b/src/test/ui/proc-macro/attr-complex-fn.stdout
index a395a9ac3e8..72783efe08d 100644
--- a/src/test/ui/proc-macro/attr-complex-fn.stdout
+++ b/src/test/ui/proc-macro/attr-complex-fn.stdout
@@ -80,67 +80,67 @@ PRINT-ATTR INPUT (DISPLAY): impl < T > MyTrait < T > for MyStruct < { true } > {
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "impl",
-        span: $DIR/attr-complex-fn.rs:21:1: 24:2 (#0),
+        span: $DIR/attr-complex-fn.rs:21:1: 21:5 (#0),
     },
     Punct {
         ch: '<',
         spacing: Alone,
-        span: $DIR/attr-complex-fn.rs:21:1: 24:2 (#0),
+        span: $DIR/attr-complex-fn.rs:21:5: 21:6 (#0),
     },
     Ident {
         ident: "T",
-        span: $DIR/attr-complex-fn.rs:21:1: 24:2 (#0),
+        span: $DIR/attr-complex-fn.rs:21:6: 21:7 (#0),
     },
     Punct {
         ch: '>',
         spacing: Alone,
-        span: $DIR/attr-complex-fn.rs:21:1: 24:2 (#0),
+        span: $DIR/attr-complex-fn.rs:21:7: 21:8 (#0),
     },
     Ident {
         ident: "MyTrait",
-        span: $DIR/attr-complex-fn.rs:21:1: 24:2 (#0),
+        span: $DIR/attr-complex-fn.rs:21:9: 21:16 (#0),
     },
     Punct {
         ch: '<',
         spacing: Alone,
-        span: $DIR/attr-complex-fn.rs:21:1: 24:2 (#0),
+        span: $DIR/attr-complex-fn.rs:21:16: 21:17 (#0),
     },
     Ident {
         ident: "T",
-        span: $DIR/attr-complex-fn.rs:21:1: 24:2 (#0),
+        span: $DIR/attr-complex-fn.rs:21:17: 21:18 (#0),
     },
     Punct {
         ch: '>',
         spacing: Alone,
-        span: $DIR/attr-complex-fn.rs:21:1: 24:2 (#0),
+        span: $DIR/attr-complex-fn.rs:21:18: 21:19 (#0),
     },
     Ident {
         ident: "for",
-        span: $DIR/attr-complex-fn.rs:21:1: 24:2 (#0),
+        span: $DIR/attr-complex-fn.rs:21:20: 21:23 (#0),
     },
     Ident {
         ident: "MyStruct",
-        span: $DIR/attr-complex-fn.rs:21:1: 24:2 (#0),
+        span: $DIR/attr-complex-fn.rs:21:24: 21:32 (#0),
     },
     Punct {
         ch: '<',
         spacing: Alone,
-        span: $DIR/attr-complex-fn.rs:21:1: 24:2 (#0),
+        span: $DIR/attr-complex-fn.rs:21:32: 21:33 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [
             Ident {
                 ident: "true",
-                span: $DIR/attr-complex-fn.rs:21:1: 24:2 (#0),
+                span: $DIR/attr-complex-fn.rs:21:34: 21:38 (#0),
             },
         ],
-        span: $DIR/attr-complex-fn.rs:21:1: 24:2 (#0),
+        span: $DIR/attr-complex-fn.rs:21:33: 21:39 (#0),
     },
     Punct {
         ch: '>',
         spacing: Alone,
-        span: $DIR/attr-complex-fn.rs:21:1: 24:2 (#0),
+        span: $DIR/attr-complex-fn.rs:21:39: 21:40 (#0),
     },
     Group {
         delimiter: Brace,
@@ -148,24 +148,24 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/attr-complex-fn.rs:21:1: 24:2 (#0),
+                span: $DIR/attr-complex-fn.rs:23:5: 23:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/attr-complex-fn.rs:21:1: 24:2 (#0),
+                span: $DIR/attr-complex-fn.rs:23:6: 23:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "rustc_dummy",
-                        span: $DIR/attr-complex-fn.rs:21:1: 24:2 (#0),
+                        span: $DIR/attr-complex-fn.rs:23:8: 23:19 (#0),
                     },
                 ],
-                span: $DIR/attr-complex-fn.rs:21:1: 24:2 (#0),
+                span: $DIR/attr-complex-fn.rs:23:7: 23:20 (#0),
             },
         ],
-        span: $DIR/attr-complex-fn.rs:21:1: 24:2 (#0),
+        span: $DIR/attr-complex-fn.rs:21:41: 24:2 (#0),
     },
 ]
diff --git a/src/test/ui/proc-macro/attribute-after-derive.stdout b/src/test/ui/proc-macro/attribute-after-derive.stdout
index 11f49235327..4c48e41ff33 100644
--- a/src/test/ui/proc-macro/attribute-after-derive.stdout
+++ b/src/test/ui/proc-macro/attribute-after-derive.stdout
@@ -87,32 +87,16 @@ PRINT-DERIVE INPUT (DISPLAY): struct AttributeDerive { }
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
-        span: $DIR/attribute-after-derive.rs:18:1: 21:2 (#0),
+        span: $DIR/attribute-after-derive.rs:18:1: 18:7 (#0),
     },
     Ident {
         ident: "AttributeDerive",
-        span: $DIR/attribute-after-derive.rs:18:1: 21:2 (#0),
-    },
-    Group {
-        delimiter: Brace,
-        stream: TokenStream [],
-        span: $DIR/attribute-after-derive.rs:18:1: 21:2 (#0),
-    },
-]
-PRINT-ATTR INPUT (DISPLAY): struct DeriveAttribute { }
-PRINT-ATTR INPUT (DEBUG): TokenStream [
-    Ident {
-        ident: "struct",
-        span: $DIR/attribute-after-derive.rs:25:1: 28:2 (#0),
-    },
-    Ident {
-        ident: "DeriveAttribute",
-        span: $DIR/attribute-after-derive.rs:25:1: 28:2 (#0),
+        span: $DIR/attribute-after-derive.rs:18:8: 18:23 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [],
-        span: $DIR/attribute-after-derive.rs:25:1: 28:2 (#0),
+        span: $DIR/attribute-after-derive.rs:18:24: 21:2 (#0),
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): #[print_attr] struct DeriveAttribute { }
@@ -120,29 +104,45 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/attribute-after-derive.rs:25:1: 28:2 (#0),
+        span: $DIR/attribute-after-derive.rs:24:1: 24:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "print_attr",
-                span: $DIR/attribute-after-derive.rs:25:1: 28:2 (#0),
+                span: $DIR/attribute-after-derive.rs:24:3: 24:13 (#0),
             },
         ],
-        span: $DIR/attribute-after-derive.rs:25:1: 28:2 (#0),
+        span: $DIR/attribute-after-derive.rs:24:2: 24:14 (#0),
+    },
+    Ident {
+        ident: "struct",
+        span: $DIR/attribute-after-derive.rs:25:1: 25:7 (#0),
+    },
+    Ident {
+        ident: "DeriveAttribute",
+        span: $DIR/attribute-after-derive.rs:25:8: 25:23 (#0),
     },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [],
+        span: $DIR/attribute-after-derive.rs:25:24: 28:2 (#0),
+    },
+]
+PRINT-ATTR INPUT (DISPLAY): struct DeriveAttribute { }
+PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
-        span: $DIR/attribute-after-derive.rs:25:1: 28:2 (#0),
+        span: $DIR/attribute-after-derive.rs:25:1: 25:7 (#0),
     },
     Ident {
         ident: "DeriveAttribute",
-        span: $DIR/attribute-after-derive.rs:25:1: 28:2 (#0),
+        span: $DIR/attribute-after-derive.rs:25:8: 25:23 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [],
-        span: $DIR/attribute-after-derive.rs:25:1: 28:2 (#0),
+        span: $DIR/attribute-after-derive.rs:25:24: 28:2 (#0),
     },
 ]
diff --git a/src/test/ui/proc-macro/auxiliary/multiple-derives.rs b/src/test/ui/proc-macro/auxiliary/multiple-derives.rs
new file mode 100644
index 00000000000..e3f6607b2ae
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/multiple-derives.rs
@@ -0,0 +1,22 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+macro_rules! make_derives {
+    ($($name:ident),*) => {
+        $(
+            #[proc_macro_derive($name)]
+            pub fn $name(input: TokenStream) -> TokenStream {
+                println!("Derive {}: {}", stringify!($name), input);
+                TokenStream::new()
+            }
+        )*
+    }
+}
+
+make_derives!(First, Second, Third, Fourth, Fifth);
diff --git a/src/test/ui/proc-macro/auxiliary/nonterminal-recollect-attr.rs b/src/test/ui/proc-macro/auxiliary/nonterminal-recollect-attr.rs
index a6903283aa1..ea5ff466570 100644
--- a/src/test/ui/proc-macro/auxiliary/nonterminal-recollect-attr.rs
+++ b/src/test/ui/proc-macro/auxiliary/nonterminal-recollect-attr.rs
@@ -10,6 +10,7 @@ use proc_macro::{TokenStream, quote};
 #[proc_macro_attribute]
 pub fn first_attr(_: TokenStream, input: TokenStream) -> TokenStream {
     let recollected: TokenStream = input.into_iter().collect();
+    println!("First recollected: {:#?}", recollected);
     quote! {
         #[second_attr]
         $recollected
@@ -18,6 +19,7 @@ pub fn first_attr(_: TokenStream, input: TokenStream) -> TokenStream {
 
 #[proc_macro_attribute]
 pub fn second_attr(_: TokenStream, input: TokenStream) -> TokenStream {
-    let _recollected: TokenStream = input.into_iter().collect();
+    let recollected: TokenStream = input.into_iter().collect();
+    println!("Second recollected: {:#?}", recollected);
     TokenStream::new()
 }
diff --git a/src/test/ui/proc-macro/cfg-eval-inner.rs b/src/test/ui/proc-macro/cfg-eval-inner.rs
new file mode 100644
index 00000000000..5fd3ca0d163
--- /dev/null
+++ b/src/test/ui/proc-macro/cfg-eval-inner.rs
@@ -0,0 +1,39 @@
+// compile-flags: -Z span-debug
+// aux-build:test-macros.rs
+// check-pass
+
+#![feature(cfg_eval)]
+#![feature(custom_inner_attributes)]
+#![feature(stmt_expr_attributes)]
+#![feature(rustc_attrs)]
+
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
+#[macro_use]
+extern crate test_macros;
+
+struct Foo<T>(T);
+
+impl Foo<[u8; {
+    #![cfg_attr(not(FALSE), rustc_dummy(cursed_inner))]
+    #![allow(unused)]
+    struct Inner {
+        field: [u8; {
+            #![cfg_attr(not(FALSE), rustc_dummy(another_cursed_inner))]
+            1
+        }]
+    }
+
+    0
+}]> {
+    #![cfg_eval]
+    #![print_attr]
+    #![cfg_attr(not(FALSE), rustc_dummy(evaluated_attr))]
+
+    fn bar() {
+        #[cfg(FALSE)] let a = 1;
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/proc-macro/cfg-eval-inner.stdout b/src/test/ui/proc-macro/cfg-eval-inner.stdout
new file mode 100644
index 00000000000..1f2b0039589
--- /dev/null
+++ b/src/test/ui/proc-macro/cfg-eval-inner.stdout
@@ -0,0 +1,247 @@
+PRINT-ATTR INPUT (DISPLAY): impl Foo <
+[u8 ;
+ {
+     # ! [rustc_dummy(cursed_inner)] # ! [allow(unused)] struct Inner
+     { field : [u8 ; { # ! [rustc_dummy(another_cursed_inner)] 1 }] } 0
+ }] > { # ! [rustc_dummy(evaluated_attr)] fn bar() { } }
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "impl",
+        span: $DIR/cfg-eval-inner.rs:18:1: 18:5 (#0),
+    },
+    Ident {
+        ident: "Foo",
+        span: $DIR/cfg-eval-inner.rs:18:6: 18:9 (#0),
+    },
+    Punct {
+        ch: '<',
+        spacing: Alone,
+        span: $DIR/cfg-eval-inner.rs:18:9: 18:10 (#0),
+    },
+    Group {
+        delimiter: Bracket,
+        stream: TokenStream [
+            Ident {
+                ident: "u8",
+                span: $DIR/cfg-eval-inner.rs:18:11: 18:13 (#0),
+            },
+            Punct {
+                ch: ';',
+                spacing: Alone,
+                span: $DIR/cfg-eval-inner.rs:18:13: 18:14 (#0),
+            },
+            Group {
+                delimiter: Brace,
+                stream: TokenStream [
+                    Punct {
+                        ch: '#',
+                        spacing: Alone,
+                        span: $DIR/cfg-eval-inner.rs:19:5: 19:6 (#0),
+                    },
+                    Punct {
+                        ch: '!',
+                        spacing: Alone,
+                        span: $DIR/cfg-eval-inner.rs:19:6: 19:7 (#0),
+                    },
+                    Group {
+                        delimiter: Bracket,
+                        stream: TokenStream [
+                            Ident {
+                                ident: "rustc_dummy",
+                                span: $DIR/cfg-eval-inner.rs:19:29: 19:40 (#0),
+                            },
+                            Group {
+                                delimiter: Parenthesis,
+                                stream: TokenStream [
+                                    Ident {
+                                        ident: "cursed_inner",
+                                        span: $DIR/cfg-eval-inner.rs:19:41: 19:53 (#0),
+                                    },
+                                ],
+                                span: $DIR/cfg-eval-inner.rs:19:40: 19:54 (#0),
+                            },
+                        ],
+                        span: $DIR/cfg-eval-inner.rs:19:5: 19:6 (#0),
+                    },
+                    Punct {
+                        ch: '#',
+                        spacing: Joint,
+                        span: $DIR/cfg-eval-inner.rs:20:5: 20:6 (#0),
+                    },
+                    Punct {
+                        ch: '!',
+                        spacing: Alone,
+                        span: $DIR/cfg-eval-inner.rs:20:6: 20:7 (#0),
+                    },
+                    Group {
+                        delimiter: Bracket,
+                        stream: TokenStream [
+                            Ident {
+                                ident: "allow",
+                                span: $DIR/cfg-eval-inner.rs:20:8: 20:13 (#0),
+                            },
+                            Group {
+                                delimiter: Parenthesis,
+                                stream: TokenStream [
+                                    Ident {
+                                        ident: "unused",
+                                        span: $DIR/cfg-eval-inner.rs:20:14: 20:20 (#0),
+                                    },
+                                ],
+                                span: $DIR/cfg-eval-inner.rs:20:13: 20:21 (#0),
+                            },
+                        ],
+                        span: $DIR/cfg-eval-inner.rs:20:7: 20:22 (#0),
+                    },
+                    Ident {
+                        ident: "struct",
+                        span: $DIR/cfg-eval-inner.rs:21:5: 21:11 (#0),
+                    },
+                    Ident {
+                        ident: "Inner",
+                        span: $DIR/cfg-eval-inner.rs:21:12: 21:17 (#0),
+                    },
+                    Group {
+                        delimiter: Brace,
+                        stream: TokenStream [
+                            Ident {
+                                ident: "field",
+                                span: $DIR/cfg-eval-inner.rs:22:9: 22:14 (#0),
+                            },
+                            Punct {
+                                ch: ':',
+                                spacing: Alone,
+                                span: $DIR/cfg-eval-inner.rs:22:14: 22:15 (#0),
+                            },
+                            Group {
+                                delimiter: Bracket,
+                                stream: TokenStream [
+                                    Ident {
+                                        ident: "u8",
+                                        span: $DIR/cfg-eval-inner.rs:22:17: 22:19 (#0),
+                                    },
+                                    Punct {
+                                        ch: ';',
+                                        spacing: Alone,
+                                        span: $DIR/cfg-eval-inner.rs:22:19: 22:20 (#0),
+                                    },
+                                    Group {
+                                        delimiter: Brace,
+                                        stream: TokenStream [
+                                            Punct {
+                                                ch: '#',
+                                                spacing: Alone,
+                                                span: $DIR/cfg-eval-inner.rs:23:13: 23:14 (#0),
+                                            },
+                                            Punct {
+                                                ch: '!',
+                                                spacing: Alone,
+                                                span: $DIR/cfg-eval-inner.rs:23:14: 23:15 (#0),
+                                            },
+                                            Group {
+                                                delimiter: Bracket,
+                                                stream: TokenStream [
+                                                    Ident {
+                                                        ident: "rustc_dummy",
+                                                        span: $DIR/cfg-eval-inner.rs:23:37: 23:48 (#0),
+                                                    },
+                                                    Group {
+                                                        delimiter: Parenthesis,
+                                                        stream: TokenStream [
+                                                            Ident {
+                                                                ident: "another_cursed_inner",
+                                                                span: $DIR/cfg-eval-inner.rs:23:49: 23:69 (#0),
+                                                            },
+                                                        ],
+                                                        span: $DIR/cfg-eval-inner.rs:23:48: 23:70 (#0),
+                                                    },
+                                                ],
+                                                span: $DIR/cfg-eval-inner.rs:23:13: 23:14 (#0),
+                                            },
+                                            Literal {
+                                                kind: Integer,
+                                                symbol: "1",
+                                                suffix: None,
+                                                span: $DIR/cfg-eval-inner.rs:24:13: 24:14 (#0),
+                                            },
+                                        ],
+                                        span: $DIR/cfg-eval-inner.rs:22:21: 25:10 (#0),
+                                    },
+                                ],
+                                span: $DIR/cfg-eval-inner.rs:22:16: 25:11 (#0),
+                            },
+                        ],
+                        span: $DIR/cfg-eval-inner.rs:21:18: 26:6 (#0),
+                    },
+                    Literal {
+                        kind: Integer,
+                        symbol: "0",
+                        suffix: None,
+                        span: $DIR/cfg-eval-inner.rs:28:5: 28:6 (#0),
+                    },
+                ],
+                span: $DIR/cfg-eval-inner.rs:18:15: 29:2 (#0),
+            },
+        ],
+        span: $DIR/cfg-eval-inner.rs:18:10: 29:3 (#0),
+    },
+    Punct {
+        ch: '>',
+        spacing: Alone,
+        span: $DIR/cfg-eval-inner.rs:29:3: 29:4 (#0),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [
+            Punct {
+                ch: '#',
+                spacing: Alone,
+                span: $DIR/cfg-eval-inner.rs:32:5: 32:6 (#0),
+            },
+            Punct {
+                ch: '!',
+                spacing: Alone,
+                span: $DIR/cfg-eval-inner.rs:32:6: 32:7 (#0),
+            },
+            Group {
+                delimiter: Bracket,
+                stream: TokenStream [
+                    Ident {
+                        ident: "rustc_dummy",
+                        span: $DIR/cfg-eval-inner.rs:32:29: 32:40 (#0),
+                    },
+                    Group {
+                        delimiter: Parenthesis,
+                        stream: TokenStream [
+                            Ident {
+                                ident: "evaluated_attr",
+                                span: $DIR/cfg-eval-inner.rs:32:41: 32:55 (#0),
+                            },
+                        ],
+                        span: $DIR/cfg-eval-inner.rs:32:40: 32:56 (#0),
+                    },
+                ],
+                span: $DIR/cfg-eval-inner.rs:32:5: 32:6 (#0),
+            },
+            Ident {
+                ident: "fn",
+                span: $DIR/cfg-eval-inner.rs:34:5: 34:7 (#0),
+            },
+            Ident {
+                ident: "bar",
+                span: $DIR/cfg-eval-inner.rs:34:8: 34:11 (#0),
+            },
+            Group {
+                delimiter: Parenthesis,
+                stream: TokenStream [],
+                span: $DIR/cfg-eval-inner.rs:34:11: 34:13 (#0),
+            },
+            Group {
+                delimiter: Brace,
+                stream: TokenStream [],
+                span: $DIR/cfg-eval-inner.rs:34:14: 36:6 (#0),
+            },
+        ],
+        span: $DIR/cfg-eval-inner.rs:29:5: 37:2 (#0),
+    },
+]
diff --git a/src/test/ui/proc-macro/cfg-eval.rs b/src/test/ui/proc-macro/cfg-eval.rs
index ea397df5452..fa6d015e48e 100644
--- a/src/test/ui/proc-macro/cfg-eval.rs
+++ b/src/test/ui/proc-macro/cfg-eval.rs
@@ -5,7 +5,7 @@
 #![feature(cfg_eval)]
 #![feature(proc_macro_hygiene)]
 #![feature(stmt_expr_attributes)]
-
+#![feature(rustc_attrs)]
 #![no_std] // Don't load unnecessary hygiene information from std
 extern crate std;
 
@@ -28,5 +28,10 @@ struct S1 {
 struct S2 {}
 
 fn main() {
-    let _ = #[cfg_eval] #[print_attr](#[cfg(FALSE)] 0, #[cfg(all(/*true*/))] 1);
+    // Subtle - we need a trailing comma after the '1' - otherwise, `#[cfg_eval]` will
+    // turn this into `(#[cfg(all())] 1)`, which is a parenthesized expression, not a tuple
+    // expression. `#[cfg]` is not supported inside parenthesized expressions, so this will
+    // produce an error when attribute collection runs.
+    let _ = #[cfg_eval] #[print_attr] #[cfg_attr(not(FALSE), rustc_dummy)]
+    (#[cfg(FALSE)] 0, #[cfg(all(/*true*/))] 1,);
 }
diff --git a/src/test/ui/proc-macro/cfg-eval.stdout b/src/test/ui/proc-macro/cfg-eval.stdout
index b98e8961bfe..6732caf08dd 100644
--- a/src/test/ui/proc-macro/cfg-eval.stdout
+++ b/src/test/ui/proc-macro/cfg-eval.stdout
@@ -2,11 +2,11 @@ PRINT-ATTR INPUT (DISPLAY): struct S1 { #[cfg(all())] #[allow()] field_true : u8
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
-        span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+        span: $DIR/cfg-eval.rs:17:1: 17:7 (#0),
     },
     Ident {
         ident: "S1",
-        span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+        span: $DIR/cfg-eval.rs:17:8: 17:10 (#0),
     },
     Group {
         delimiter: Brace,
@@ -14,122 +14,137 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Alone,
-                span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+                span: $DIR/cfg-eval.rs:20:5: 20:6 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "cfg",
-                        span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+                        span: $DIR/cfg-eval.rs:20:7: 20:10 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "all",
-                                span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+                                span: $DIR/cfg-eval.rs:20:11: 20:14 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
                                 stream: TokenStream [],
-                                span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+                                span: $DIR/cfg-eval.rs:20:14: 20:24 (#0),
                             },
                         ],
-                        span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+                        span: $DIR/cfg-eval.rs:20:10: 20:25 (#0),
                     },
                 ],
-                span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+                span: $DIR/cfg-eval.rs:20:6: 20:26 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Alone,
-                span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+                span: $DIR/cfg-eval.rs:22:5: 22:6 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "allow",
-                        span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+                        span: $DIR/cfg-eval.rs:22:31: 22:36 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [],
-                        span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+                        span: $DIR/cfg-eval.rs:22:36: 22:38 (#0),
                     },
                 ],
-                span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+                span: $DIR/cfg-eval.rs:22:5: 22:6 (#0),
             },
             Ident {
                 ident: "field_true",
-                span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+                span: $DIR/cfg-eval.rs:23:5: 23:15 (#0),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+                span: $DIR/cfg-eval.rs:23:15: 23:16 (#0),
             },
             Ident {
                 ident: "u8",
-                span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+                span: $DIR/cfg-eval.rs:23:17: 23:19 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+                span: $DIR/cfg-eval.rs:23:19: 23:20 (#0),
             },
         ],
-        span: $DIR/cfg-eval.rs:17:1: 24:2 (#0),
+        span: $DIR/cfg-eval.rs:17:11: 24:2 (#0),
     },
 ]
-PRINT-ATTR INPUT (DISPLAY): (#[cfg(all())] 1,)
+PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] (#[cfg(all())] 1,)
 PRINT-ATTR INPUT (DEBUG): TokenStream [
+    Punct {
+        ch: '#',
+        spacing: Alone,
+        span: $DIR/cfg-eval.rs:35:39: 35:40 (#0),
+    },
+    Group {
+        delimiter: Bracket,
+        stream: TokenStream [
+            Ident {
+                ident: "rustc_dummy",
+                span: $DIR/cfg-eval.rs:35:62: 35:73 (#0),
+            },
+        ],
+        span: $DIR/cfg-eval.rs:35:39: 35:40 (#0),
+    },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [
             Punct {
                 ch: '#',
                 spacing: Alone,
-                span: $DIR/cfg-eval.rs:31:38: 31:80 (#0),
+                span: $DIR/cfg-eval.rs:36:23: 36:24 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "cfg",
-                        span: $DIR/cfg-eval.rs:31:38: 31:80 (#0),
+                        span: $DIR/cfg-eval.rs:36:25: 36:28 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "all",
-                                span: $DIR/cfg-eval.rs:31:38: 31:80 (#0),
+                                span: $DIR/cfg-eval.rs:36:29: 36:32 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
                                 stream: TokenStream [],
-                                span: $DIR/cfg-eval.rs:31:38: 31:80 (#0),
+                                span: $DIR/cfg-eval.rs:36:32: 36:42 (#0),
                             },
                         ],
-                        span: $DIR/cfg-eval.rs:31:38: 31:80 (#0),
+                        span: $DIR/cfg-eval.rs:36:28: 36:43 (#0),
                     },
                 ],
-                span: $DIR/cfg-eval.rs:31:38: 31:80 (#0),
+                span: $DIR/cfg-eval.rs:36:24: 36:44 (#0),
             },
             Literal {
                 kind: Integer,
                 symbol: "1",
                 suffix: None,
-                span: $DIR/cfg-eval.rs:31:38: 31:80 (#0),
+                span: $DIR/cfg-eval.rs:36:45: 36:46 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/cfg-eval.rs:31:38: 31:80 (#0),
+                span: $DIR/cfg-eval.rs:36:46: 36:47 (#0),
             },
         ],
-        span: $DIR/cfg-eval.rs:31:38: 31:80 (#0),
+        span: $DIR/cfg-eval.rs:36:5: 36:48 (#0),
     },
 ]
diff --git a/src/test/ui/proc-macro/derive-expand-order.rs b/src/test/ui/proc-macro/derive-expand-order.rs
new file mode 100644
index 00000000000..0cf1ceb91de
--- /dev/null
+++ b/src/test/ui/proc-macro/derive-expand-order.rs
@@ -0,0 +1,14 @@
+// run-pass
+// aux-build:multiple-derives.rs
+
+extern crate multiple_derives;
+
+use multiple_derives::*;
+
+#[derive(First)]
+#[derive(Second)]
+#[derive(Third, Fourth)]
+#[derive(Fifth)]
+pub struct Foo {}
+
+fn main() {}
diff --git a/src/test/ui/proc-macro/derive-expand-order.stdout b/src/test/ui/proc-macro/derive-expand-order.stdout
new file mode 100644
index 00000000000..3ac1adf92c2
--- /dev/null
+++ b/src/test/ui/proc-macro/derive-expand-order.stdout
@@ -0,0 +1,5 @@
+Derive First: #[derive(Second)] #[derive(Third, Fourth)] #[derive(Fifth)] pub struct Foo { }
+Derive Second: #[derive(Third, Fourth)] #[derive(Fifth)] pub struct Foo { }
+Derive Third: #[derive(Fifth)] pub struct Foo { }
+Derive Fourth: #[derive(Fifth)] pub struct Foo { }
+Derive Fifth: pub struct Foo { }
diff --git a/src/test/ui/proc-macro/expand-to-derive.stdout b/src/test/ui/proc-macro/expand-to-derive.stdout
index 7eb68643342..a6437982a37 100644
--- a/src/test/ui/proc-macro/expand-to-derive.stdout
+++ b/src/test/ui/proc-macro/expand-to-derive.stdout
@@ -1,40 +1,40 @@
 PRINT-DERIVE INPUT (DISPLAY): struct Foo
 {
     field :
-    [bool ; { #[rustc_dummy] struct Inner { other_inner_field : u8, } 0 }],
+    [bool ; { #[rustc_dummy] struct Inner { other_inner_field : u8, } 0 }]
 }
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
-        span: $DIR/expand-to-derive.rs:16:9: 22:10 (#4),
+        span: $DIR/expand-to-derive.rs:16:9: 16:15 (#4),
     },
     Ident {
         ident: "Foo",
-        span: $DIR/expand-to-derive.rs:16:9: 22:10 (#4),
+        span: $DIR/expand-to-derive.rs:16:16: 16:19 (#4),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [
             Ident {
                 ident: "field",
-                span: $DIR/expand-to-derive.rs:16:9: 22:10 (#4),
+                span: $DIR/expand-to-derive.rs:18:13: 18:18 (#4),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/expand-to-derive.rs:16:9: 22:10 (#4),
+                span: $DIR/expand-to-derive.rs:18:18: 18:19 (#4),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "bool",
-                        span: $DIR/expand-to-derive.rs:16:9: 22:10 (#4),
+                        span: $DIR/expand-to-derive.rs:18:21: 18:25 (#4),
                     },
                     Punct {
                         ch: ';',
                         spacing: Alone,
-                        span: $DIR/expand-to-derive.rs:16:9: 22:10 (#4),
+                        span: $DIR/expand-to-derive.rs:18:25: 18:26 (#4),
                     },
                     Group {
                         delimiter: Brace,
@@ -42,68 +42,63 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/expand-to-derive.rs:16:9: 22:10 (#4),
+                                span: $DIR/expand-to-derive.rs:27:5: 27:6 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "rustc_dummy",
-                                        span: $DIR/expand-to-derive.rs:16:9: 22:10 (#4),
+                                        span: $DIR/expand-to-derive.rs:27:28: 27:39 (#0),
                                     },
                                 ],
-                                span: $DIR/expand-to-derive.rs:16:9: 22:10 (#4),
+                                span: $DIR/expand-to-derive.rs:27:5: 27:6 (#0),
                             },
                             Ident {
                                 ident: "struct",
-                                span: $DIR/expand-to-derive.rs:16:9: 22:10 (#4),
+                                span: $DIR/expand-to-derive.rs:28:5: 28:11 (#0),
                             },
                             Ident {
                                 ident: "Inner",
-                                span: $DIR/expand-to-derive.rs:16:9: 22:10 (#4),
+                                span: $DIR/expand-to-derive.rs:28:12: 28:17 (#0),
                             },
                             Group {
                                 delimiter: Brace,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "other_inner_field",
-                                        span: $DIR/expand-to-derive.rs:16:9: 22:10 (#4),
+                                        span: $DIR/expand-to-derive.rs:30:9: 30:26 (#0),
                                     },
                                     Punct {
                                         ch: ':',
                                         spacing: Alone,
-                                        span: $DIR/expand-to-derive.rs:16:9: 22:10 (#4),
+                                        span: $DIR/expand-to-derive.rs:30:26: 30:27 (#0),
                                     },
                                     Ident {
                                         ident: "u8",
-                                        span: $DIR/expand-to-derive.rs:16:9: 22:10 (#4),
+                                        span: $DIR/expand-to-derive.rs:30:28: 30:30 (#0),
                                     },
                                     Punct {
                                         ch: ',',
                                         spacing: Alone,
-                                        span: $DIR/expand-to-derive.rs:16:9: 22:10 (#4),
+                                        span: $DIR/expand-to-derive.rs:30:30: 30:31 (#0),
                                     },
                                 ],
-                                span: $DIR/expand-to-derive.rs:16:9: 22:10 (#4),
+                                span: $DIR/expand-to-derive.rs:28:18: 31:6 (#0),
                             },
                             Literal {
                                 kind: Integer,
                                 symbol: "0",
                                 suffix: None,
-                                span: $DIR/expand-to-derive.rs:16:9: 22:10 (#4),
+                                span: $DIR/expand-to-derive.rs:20:17: 20:18 (#4),
                             },
                         ],
-                        span: $DIR/expand-to-derive.rs:16:9: 22:10 (#4),
+                        span: $DIR/expand-to-derive.rs:18:27: 21:14 (#4),
                     },
                 ],
-                span: $DIR/expand-to-derive.rs:16:9: 22:10 (#4),
-            },
-            Punct {
-                ch: ',',
-                spacing: Alone,
-                span: $DIR/expand-to-derive.rs:16:9: 22:10 (#4),
+                span: $DIR/expand-to-derive.rs:18:20: 21:15 (#4),
             },
         ],
-        span: $DIR/expand-to-derive.rs:16:9: 22:10 (#4),
+        span: $DIR/expand-to-derive.rs:16:20: 22:10 (#4),
     },
 ]
diff --git a/src/test/ui/proc-macro/inner-attrs.rs b/src/test/ui/proc-macro/inner-attrs.rs
index 5707621f80e..14ec57ad626 100644
--- a/src/test/ui/proc-macro/inner-attrs.rs
+++ b/src/test/ui/proc-macro/inner-attrs.rs
@@ -1,6 +1,6 @@
 // compile-flags: -Z span-debug --error-format human
 // aux-build:test-macros.rs
-
+// edition:2018
 #![feature(custom_inner_attributes)]
 #![feature(proc_macro_hygiene)]
 #![feature(stmt_expr_attributes)]
@@ -19,10 +19,32 @@ fn foo() {
     #![print_target_and_args(fourth)]
 }
 
+#[print_target_and_args(mod_first)]
+#[print_target_and_args(mod_second)]
+mod inline_mod {
+    #![print_target_and_args(mod_third)]
+    #![print_target_and_args(mod_fourth)]
+}
+
 struct MyStruct {
     field: bool
 }
 
+#[derive(Print)]
+struct MyDerivePrint {
+    field: [u8; {
+        match true {
+            #![cfg_attr(not(FALSE), rustc_dummy(first))]
+            #![cfg_attr(not(FALSE), rustc_dummy(second))]
+            _ => {
+                #![cfg_attr(not(FALSE), rustc_dummy(third))]
+                true
+            }
+        };
+        0
+    }]
+}
+
 fn bar() {
     (#![print_target_and_args(fifth)] 1, 2);
     //~^ ERROR expected non-macro inner attribute, found attribute macro
@@ -40,6 +62,19 @@ fn bar() {
         true; 0
     ];
 
+    #[print_target_and_args(tuple_attrs)] (
+        #![cfg_attr(FALSE, rustc_dummy)]
+        3, 4, {
+            #![cfg_attr(not(FALSE), rustc_dummy(innermost))]
+            5
+        }
+    );
+
+    #[print_target_and_args(array_attrs)] [
+        #![rustc_dummy(inner)]
+        true; 0
+    ];
+
     [#![print_target_and_args(sixth)] 1 , 2];
     //~^ ERROR expected non-macro inner attribute, found attribute macro
     [#![print_target_and_args(seventh)] true ; 5];
@@ -53,8 +88,25 @@ fn bar() {
 
     MyStruct { #![print_target_and_args(ninth)] field: true };
     //~^ ERROR expected non-macro inner attribute, found attribute macro
+
+    for _ in &[true] {
+        #![print_attr] //~ ERROR expected non-macro inner attribute
+    }
+
+    let _ = {
+        #![print_attr] //~ ERROR expected non-macro inner attribute
+    };
+
+    let _ = async {
+        #![print_attr] //~ ERROR expected non-macro inner attribute
+    };
+
+    {
+        #![print_attr] //~ ERROR expected non-macro inner attribute
+    };
 }
 
+
 extern {
     fn weird_extern() {
         #![print_target_and_args_consume(tenth)]
diff --git a/src/test/ui/proc-macro/inner-attrs.stderr b/src/test/ui/proc-macro/inner-attrs.stderr
index db774cbfb8f..7f22c5f30d6 100644
--- a/src/test/ui/proc-macro/inner-attrs.stderr
+++ b/src/test/ui/proc-macro/inner-attrs.stderr
@@ -1,32 +1,56 @@
 error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
-  --> $DIR/inner-attrs.rs:27:9
+  --> $DIR/inner-attrs.rs:49:9
    |
 LL |     (#![print_target_and_args(fifth)] 1, 2);
    |         ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
 
 error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
-  --> $DIR/inner-attrs.rs:43:9
+  --> $DIR/inner-attrs.rs:78:9
    |
 LL |     [#![print_target_and_args(sixth)] 1 , 2];
    |         ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
 
 error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
-  --> $DIR/inner-attrs.rs:45:9
+  --> $DIR/inner-attrs.rs:80:9
    |
 LL |     [#![print_target_and_args(seventh)] true ; 5];
    |         ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
 
 error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
-  --> $DIR/inner-attrs.rs:49:12
+  --> $DIR/inner-attrs.rs:84:12
    |
 LL |         #![print_target_and_args(eighth)]
    |            ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
 
 error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
-  --> $DIR/inner-attrs.rs:54:19
+  --> $DIR/inner-attrs.rs:89:19
    |
 LL |     MyStruct { #![print_target_and_args(ninth)] field: true };
    |                   ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
 
-error: aborting due to 5 previous errors
+error: expected non-macro inner attribute, found attribute macro `print_attr`
+  --> $DIR/inner-attrs.rs:93:12
+   |
+LL |         #![print_attr]
+   |            ^^^^^^^^^^ not a non-macro inner attribute
+
+error: expected non-macro inner attribute, found attribute macro `print_attr`
+  --> $DIR/inner-attrs.rs:97:12
+   |
+LL |         #![print_attr]
+   |            ^^^^^^^^^^ not a non-macro inner attribute
+
+error: expected non-macro inner attribute, found attribute macro `print_attr`
+  --> $DIR/inner-attrs.rs:101:12
+   |
+LL |         #![print_attr]
+   |            ^^^^^^^^^^ not a non-macro inner attribute
+
+error: expected non-macro inner attribute, found attribute macro `print_attr`
+  --> $DIR/inner-attrs.rs:105:12
+   |
+LL |         #![print_attr]
+   |            ^^^^^^^^^^ not a non-macro inner attribute
+
+error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/proc-macro/inner-attrs.stdout b/src/test/ui/proc-macro/inner-attrs.stdout
index ae04544e533..2f442e83002 100644
--- a/src/test/ui/proc-macro/inner-attrs.stdout
+++ b/src/test/ui/proc-macro/inner-attrs.stdout
@@ -11,40 +11,40 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:16:1: 16:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "print_target_and_args",
-                span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                span: $DIR/inner-attrs.rs:16:3: 16:24 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "second",
-                        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                        span: $DIR/inner-attrs.rs:16:25: 16:31 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                span: $DIR/inner-attrs.rs:16:24: 16:32 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:16:2: 16:33 (#0),
     },
     Ident {
         ident: "fn",
-        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:17:1: 17:3 (#0),
     },
     Ident {
         ident: "foo",
-        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:17:4: 17:7 (#0),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:17:7: 17:9 (#0),
     },
     Group {
         delimiter: Brace,
@@ -52,72 +52,72 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                span: $DIR/inner-attrs.rs:18:5: 18:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                span: $DIR/inner-attrs.rs:18:6: 18:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                        span: $DIR/inner-attrs.rs:18:8: 18:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "third",
-                                span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                                span: $DIR/inner-attrs.rs:18:30: 18:35 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                        span: $DIR/inner-attrs.rs:18:29: 18:36 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                span: $DIR/inner-attrs.rs:18:7: 18:37 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                span: $DIR/inner-attrs.rs:19:5: 19:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                span: $DIR/inner-attrs.rs:19:6: 19:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                        span: $DIR/inner-attrs.rs:19:8: 19:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "fourth",
-                                span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                                span: $DIR/inner-attrs.rs:19:30: 19:36 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                        span: $DIR/inner-attrs.rs:19:29: 19:37 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                span: $DIR/inner-attrs.rs:19:7: 19:38 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:17:10: 20:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): second
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "second",
-        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:16:25: 16:31 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): fn foo()
@@ -125,16 +125,16 @@ PRINT-ATTR INPUT (DISPLAY): fn foo()
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "fn",
-        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:17:1: 17:3 (#0),
     },
     Ident {
         ident: "foo",
-        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:17:4: 17:7 (#0),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:17:7: 17:9 (#0),
     },
     Group {
         delimiter: Brace,
@@ -142,88 +142,88 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                span: $DIR/inner-attrs.rs:18:5: 18:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                span: $DIR/inner-attrs.rs:18:6: 18:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                        span: $DIR/inner-attrs.rs:18:8: 18:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "third",
-                                span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                                span: $DIR/inner-attrs.rs:18:30: 18:35 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                        span: $DIR/inner-attrs.rs:18:29: 18:36 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                span: $DIR/inner-attrs.rs:18:7: 18:37 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                span: $DIR/inner-attrs.rs:19:5: 19:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                span: $DIR/inner-attrs.rs:19:6: 19:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                        span: $DIR/inner-attrs.rs:19:8: 19:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "fourth",
-                                span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                                span: $DIR/inner-attrs.rs:19:30: 19:36 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                        span: $DIR/inner-attrs.rs:19:29: 19:37 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                span: $DIR/inner-attrs.rs:19:7: 19:38 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:17:10: 20:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): third
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "third",
-        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:18:30: 18:35 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): fn foo() { # ! [print_target_and_args(fourth)] }
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "fn",
-        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:17:1: 17:3 (#0),
     },
     Ident {
         ident: "foo",
-        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:17:4: 17:7 (#0),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:17:7: 17:9 (#0),
     },
     Group {
         delimiter: Brace,
@@ -231,138 +231,753 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                span: $DIR/inner-attrs.rs:19:5: 19:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                span: $DIR/inner-attrs.rs:19:6: 19:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                        span: $DIR/inner-attrs.rs:19:8: 19:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "fourth",
-                                span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                                span: $DIR/inner-attrs.rs:19:30: 19:36 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                        span: $DIR/inner-attrs.rs:19:29: 19:37 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+                span: $DIR/inner-attrs.rs:19:7: 19:38 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:17:10: 20:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): fourth
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "fourth",
-        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:19:30: 19:36 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): fn foo() { }
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "fn",
-        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:17:1: 17:3 (#0),
     },
     Ident {
         ident: "foo",
-        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:17:4: 17:7 (#0),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:17:7: 17:9 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:17:10: 20:2 (#0),
     },
 ]
-PRINT-ATTR_ARGS INPUT (DISPLAY): tuple_attrs
+PRINT-ATTR_ARGS INPUT (DISPLAY): mod_first
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
-        ident: "tuple_attrs",
-        span: $DIR/inner-attrs.rs:30:29: 30:40 (#0),
+        ident: "mod_first",
+        span: $DIR/inner-attrs.rs:22:25: 22:34 (#0),
     },
 ]
-PRINT-ATTR INPUT (DISPLAY): (# ! [cfg_attr(FALSE, rustc_dummy)] 3, 4,
- { # ! [cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }) ;
+PRINT-ATTR INPUT (DISPLAY): #[print_target_and_args(mod_second)] mod inline_mod
+{
+    # ! [print_target_and_args(mod_third)] # !
+    [print_target_and_args(mod_fourth)]
+}
 PRINT-ATTR INPUT (DEBUG): TokenStream [
+    Punct {
+        ch: '#',
+        spacing: Alone,
+        span: $DIR/inner-attrs.rs:23:1: 23:2 (#0),
+    },
     Group {
-        delimiter: Parenthesis,
+        delimiter: Bracket,
+        stream: TokenStream [
+            Ident {
+                ident: "print_target_and_args",
+                span: $DIR/inner-attrs.rs:23:3: 23:24 (#0),
+            },
+            Group {
+                delimiter: Parenthesis,
+                stream: TokenStream [
+                    Ident {
+                        ident: "mod_second",
+                        span: $DIR/inner-attrs.rs:23:25: 23:35 (#0),
+                    },
+                ],
+                span: $DIR/inner-attrs.rs:23:24: 23:36 (#0),
+            },
+        ],
+        span: $DIR/inner-attrs.rs:23:2: 23:37 (#0),
+    },
+    Ident {
+        ident: "mod",
+        span: $DIR/inner-attrs.rs:24:1: 24:4 (#0),
+    },
+    Ident {
+        ident: "inline_mod",
+        span: $DIR/inner-attrs.rs:24:5: 24:15 (#0),
+    },
+    Group {
+        delimiter: Brace,
         stream: TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:31:9: 31:10 (#0),
+                span: $DIR/inner-attrs.rs:25:5: 25:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:31:10: 31:11 (#0),
+                span: $DIR/inner-attrs.rs:25:6: 25:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
-                        ident: "cfg_attr",
-                        span: $DIR/inner-attrs.rs:31:12: 31:20 (#0),
+                        ident: "print_target_and_args",
+                        span: $DIR/inner-attrs.rs:25:8: 25:29 (#0),
+                    },
+                    Group {
+                        delimiter: Parenthesis,
+                        stream: TokenStream [
+                            Ident {
+                                ident: "mod_third",
+                                span: $DIR/inner-attrs.rs:25:30: 25:39 (#0),
+                            },
+                        ],
+                        span: $DIR/inner-attrs.rs:25:29: 25:40 (#0),
+                    },
+                ],
+                span: $DIR/inner-attrs.rs:25:7: 25:41 (#0),
+            },
+            Punct {
+                ch: '#',
+                spacing: Joint,
+                span: $DIR/inner-attrs.rs:26:5: 26:6 (#0),
+            },
+            Punct {
+                ch: '!',
+                spacing: Alone,
+                span: $DIR/inner-attrs.rs:26:6: 26:7 (#0),
+            },
+            Group {
+                delimiter: Bracket,
+                stream: TokenStream [
+                    Ident {
+                        ident: "print_target_and_args",
+                        span: $DIR/inner-attrs.rs:26:8: 26:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
-                                ident: "FALSE",
-                                span: $DIR/inner-attrs.rs:31:21: 31:26 (#0),
+                                ident: "mod_fourth",
+                                span: $DIR/inner-attrs.rs:26:30: 26:40 (#0),
+                            },
+                        ],
+                        span: $DIR/inner-attrs.rs:26:29: 26:41 (#0),
+                    },
+                ],
+                span: $DIR/inner-attrs.rs:26:7: 26:42 (#0),
+            },
+        ],
+        span: $DIR/inner-attrs.rs:24:16: 27:2 (#0),
+    },
+]
+PRINT-ATTR_ARGS INPUT (DISPLAY): mod_second
+PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "mod_second",
+        span: $DIR/inner-attrs.rs:23:25: 23:35 (#0),
+    },
+]
+PRINT-ATTR INPUT (DISPLAY): mod inline_mod
+{
+    # ! [print_target_and_args(mod_third)] # !
+    [print_target_and_args(mod_fourth)]
+}
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "mod",
+        span: $DIR/inner-attrs.rs:24:1: 24:4 (#0),
+    },
+    Ident {
+        ident: "inline_mod",
+        span: $DIR/inner-attrs.rs:24:5: 24:15 (#0),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [
+            Punct {
+                ch: '#',
+                spacing: Joint,
+                span: $DIR/inner-attrs.rs:25:5: 25:6 (#0),
+            },
+            Punct {
+                ch: '!',
+                spacing: Alone,
+                span: $DIR/inner-attrs.rs:25:6: 25:7 (#0),
+            },
+            Group {
+                delimiter: Bracket,
+                stream: TokenStream [
+                    Ident {
+                        ident: "print_target_and_args",
+                        span: $DIR/inner-attrs.rs:25:8: 25:29 (#0),
+                    },
+                    Group {
+                        delimiter: Parenthesis,
+                        stream: TokenStream [
+                            Ident {
+                                ident: "mod_third",
+                                span: $DIR/inner-attrs.rs:25:30: 25:39 (#0),
+                            },
+                        ],
+                        span: $DIR/inner-attrs.rs:25:29: 25:40 (#0),
+                    },
+                ],
+                span: $DIR/inner-attrs.rs:25:7: 25:41 (#0),
+            },
+            Punct {
+                ch: '#',
+                spacing: Joint,
+                span: $DIR/inner-attrs.rs:26:5: 26:6 (#0),
+            },
+            Punct {
+                ch: '!',
+                spacing: Alone,
+                span: $DIR/inner-attrs.rs:26:6: 26:7 (#0),
+            },
+            Group {
+                delimiter: Bracket,
+                stream: TokenStream [
+                    Ident {
+                        ident: "print_target_and_args",
+                        span: $DIR/inner-attrs.rs:26:8: 26:29 (#0),
+                    },
+                    Group {
+                        delimiter: Parenthesis,
+                        stream: TokenStream [
+                            Ident {
+                                ident: "mod_fourth",
+                                span: $DIR/inner-attrs.rs:26:30: 26:40 (#0),
+                            },
+                        ],
+                        span: $DIR/inner-attrs.rs:26:29: 26:41 (#0),
+                    },
+                ],
+                span: $DIR/inner-attrs.rs:26:7: 26:42 (#0),
+            },
+        ],
+        span: $DIR/inner-attrs.rs:24:16: 27:2 (#0),
+    },
+]
+PRINT-ATTR_ARGS INPUT (DISPLAY): mod_third
+PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "mod_third",
+        span: $DIR/inner-attrs.rs:25:30: 25:39 (#0),
+    },
+]
+PRINT-ATTR INPUT (DISPLAY): mod inline_mod { # ! [print_target_and_args(mod_fourth)] }
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "mod",
+        span: $DIR/inner-attrs.rs:24:1: 24:4 (#0),
+    },
+    Ident {
+        ident: "inline_mod",
+        span: $DIR/inner-attrs.rs:24:5: 24:15 (#0),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [
+            Punct {
+                ch: '#',
+                spacing: Joint,
+                span: $DIR/inner-attrs.rs:26:5: 26:6 (#0),
+            },
+            Punct {
+                ch: '!',
+                spacing: Alone,
+                span: $DIR/inner-attrs.rs:26:6: 26:7 (#0),
+            },
+            Group {
+                delimiter: Bracket,
+                stream: TokenStream [
+                    Ident {
+                        ident: "print_target_and_args",
+                        span: $DIR/inner-attrs.rs:26:8: 26:29 (#0),
+                    },
+                    Group {
+                        delimiter: Parenthesis,
+                        stream: TokenStream [
+                            Ident {
+                                ident: "mod_fourth",
+                                span: $DIR/inner-attrs.rs:26:30: 26:40 (#0),
+                            },
+                        ],
+                        span: $DIR/inner-attrs.rs:26:29: 26:41 (#0),
+                    },
+                ],
+                span: $DIR/inner-attrs.rs:26:7: 26:42 (#0),
+            },
+        ],
+        span: $DIR/inner-attrs.rs:24:16: 27:2 (#0),
+    },
+]
+PRINT-ATTR_ARGS INPUT (DISPLAY): mod_fourth
+PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "mod_fourth",
+        span: $DIR/inner-attrs.rs:26:30: 26:40 (#0),
+    },
+]
+PRINT-ATTR INPUT (DISPLAY): mod inline_mod { }
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "mod",
+        span: $DIR/inner-attrs.rs:24:1: 24:4 (#0),
+    },
+    Ident {
+        ident: "inline_mod",
+        span: $DIR/inner-attrs.rs:24:5: 24:15 (#0),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [],
+        span: $DIR/inner-attrs.rs:24:16: 27:2 (#0),
+    },
+]
+PRINT-DERIVE INPUT (DISPLAY): struct MyDerivePrint
+{
+    field :
+    [u8 ;
+     {
+         match true
+         {
+             # ! [rustc_dummy(first)] # ! [rustc_dummy(second)] _ =>
+             { # ! [rustc_dummy(third)] true }
+         } ; 0
+     }]
+}
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "struct",
+        span: $DIR/inner-attrs.rs:34:1: 34:7 (#0),
+    },
+    Ident {
+        ident: "MyDerivePrint",
+        span: $DIR/inner-attrs.rs:34:8: 34:21 (#0),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [
+            Ident {
+                ident: "field",
+                span: $DIR/inner-attrs.rs:35:5: 35:10 (#0),
+            },
+            Punct {
+                ch: ':',
+                spacing: Alone,
+                span: $DIR/inner-attrs.rs:35:10: 35:11 (#0),
+            },
+            Group {
+                delimiter: Bracket,
+                stream: TokenStream [
+                    Ident {
+                        ident: "u8",
+                        span: $DIR/inner-attrs.rs:35:13: 35:15 (#0),
+                    },
+                    Punct {
+                        ch: ';',
+                        spacing: Alone,
+                        span: $DIR/inner-attrs.rs:35:15: 35:16 (#0),
+                    },
+                    Group {
+                        delimiter: Brace,
+                        stream: TokenStream [
+                            Ident {
+                                ident: "match",
+                                span: $DIR/inner-attrs.rs:36:9: 36:14 (#0),
+                            },
+                            Ident {
+                                ident: "true",
+                                span: $DIR/inner-attrs.rs:36:15: 36:19 (#0),
+                            },
+                            Group {
+                                delimiter: Brace,
+                                stream: TokenStream [
+                                    Punct {
+                                        ch: '#',
+                                        spacing: Alone,
+                                        span: $DIR/inner-attrs.rs:37:13: 37:14 (#0),
+                                    },
+                                    Punct {
+                                        ch: '!',
+                                        spacing: Alone,
+                                        span: $DIR/inner-attrs.rs:37:14: 37:15 (#0),
+                                    },
+                                    Group {
+                                        delimiter: Bracket,
+                                        stream: TokenStream [
+                                            Ident {
+                                                ident: "rustc_dummy",
+                                                span: $DIR/inner-attrs.rs:37:37: 37:48 (#0),
+                                            },
+                                            Group {
+                                                delimiter: Parenthesis,
+                                                stream: TokenStream [
+                                                    Ident {
+                                                        ident: "first",
+                                                        span: $DIR/inner-attrs.rs:37:49: 37:54 (#0),
+                                                    },
+                                                ],
+                                                span: $DIR/inner-attrs.rs:37:48: 37:55 (#0),
+                                            },
+                                        ],
+                                        span: $DIR/inner-attrs.rs:37:13: 37:14 (#0),
+                                    },
+                                    Punct {
+                                        ch: '#',
+                                        spacing: Alone,
+                                        span: $DIR/inner-attrs.rs:38:13: 38:14 (#0),
+                                    },
+                                    Punct {
+                                        ch: '!',
+                                        spacing: Alone,
+                                        span: $DIR/inner-attrs.rs:38:14: 38:15 (#0),
+                                    },
+                                    Group {
+                                        delimiter: Bracket,
+                                        stream: TokenStream [
+                                            Ident {
+                                                ident: "rustc_dummy",
+                                                span: $DIR/inner-attrs.rs:38:37: 38:48 (#0),
+                                            },
+                                            Group {
+                                                delimiter: Parenthesis,
+                                                stream: TokenStream [
+                                                    Ident {
+                                                        ident: "second",
+                                                        span: $DIR/inner-attrs.rs:38:49: 38:55 (#0),
+                                                    },
+                                                ],
+                                                span: $DIR/inner-attrs.rs:38:48: 38:56 (#0),
+                                            },
+                                        ],
+                                        span: $DIR/inner-attrs.rs:38:13: 38:14 (#0),
+                                    },
+                                    Ident {
+                                        ident: "_",
+                                        span: $DIR/inner-attrs.rs:39:13: 39:14 (#0),
+                                    },
+                                    Punct {
+                                        ch: '=',
+                                        spacing: Joint,
+                                        span: $DIR/inner-attrs.rs:39:15: 39:17 (#0),
+                                    },
+                                    Punct {
+                                        ch: '>',
+                                        spacing: Alone,
+                                        span: $DIR/inner-attrs.rs:39:15: 39:17 (#0),
+                                    },
+                                    Group {
+                                        delimiter: Brace,
+                                        stream: TokenStream [
+                                            Punct {
+                                                ch: '#',
+                                                spacing: Alone,
+                                                span: $DIR/inner-attrs.rs:40:17: 40:18 (#0),
+                                            },
+                                            Punct {
+                                                ch: '!',
+                                                spacing: Alone,
+                                                span: $DIR/inner-attrs.rs:40:18: 40:19 (#0),
+                                            },
+                                            Group {
+                                                delimiter: Bracket,
+                                                stream: TokenStream [
+                                                    Ident {
+                                                        ident: "rustc_dummy",
+                                                        span: $DIR/inner-attrs.rs:40:41: 40:52 (#0),
+                                                    },
+                                                    Group {
+                                                        delimiter: Parenthesis,
+                                                        stream: TokenStream [
+                                                            Ident {
+                                                                ident: "third",
+                                                                span: $DIR/inner-attrs.rs:40:53: 40:58 (#0),
+                                                            },
+                                                        ],
+                                                        span: $DIR/inner-attrs.rs:40:52: 40:59 (#0),
+                                                    },
+                                                ],
+                                                span: $DIR/inner-attrs.rs:40:17: 40:18 (#0),
+                                            },
+                                            Ident {
+                                                ident: "true",
+                                                span: $DIR/inner-attrs.rs:41:17: 41:21 (#0),
+                                            },
+                                        ],
+                                        span: $DIR/inner-attrs.rs:39:18: 42:14 (#0),
+                                    },
+                                ],
+                                span: $DIR/inner-attrs.rs:36:20: 43:10 (#0),
                             },
                             Punct {
-                                ch: ',',
+                                ch: ';',
                                 spacing: Alone,
-                                span: $DIR/inner-attrs.rs:31:26: 31:27 (#0),
+                                span: $DIR/inner-attrs.rs:43:10: 43:11 (#0),
+                            },
+                            Literal {
+                                kind: Integer,
+                                symbol: "0",
+                                suffix: None,
+                                span: $DIR/inner-attrs.rs:44:9: 44:10 (#0),
+                            },
+                        ],
+                        span: $DIR/inner-attrs.rs:35:17: 45:6 (#0),
+                    },
+                ],
+                span: $DIR/inner-attrs.rs:35:12: 45:7 (#0),
+            },
+        ],
+        span: $DIR/inner-attrs.rs:34:22: 46:2 (#0),
+    },
+]
+PRINT-ATTR_ARGS INPUT (DISPLAY): tuple_attrs
+PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "tuple_attrs",
+        span: $DIR/inner-attrs.rs:52:29: 52:40 (#0),
+    },
+]
+PRINT-ATTR INPUT (DISPLAY): (3, 4, { # ! [cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }) ;
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+    Group {
+        delimiter: Parenthesis,
+        stream: TokenStream [
+            Literal {
+                kind: Integer,
+                symbol: "3",
+                suffix: None,
+                span: $DIR/inner-attrs.rs:54:9: 54:10 (#0),
+            },
+            Punct {
+                ch: ',',
+                spacing: Alone,
+                span: $DIR/inner-attrs.rs:54:10: 54:11 (#0),
+            },
+            Literal {
+                kind: Integer,
+                symbol: "4",
+                suffix: None,
+                span: $DIR/inner-attrs.rs:54:12: 54:13 (#0),
+            },
+            Punct {
+                ch: ',',
+                spacing: Alone,
+                span: $DIR/inner-attrs.rs:54:13: 54:14 (#0),
+            },
+            Group {
+                delimiter: Brace,
+                stream: TokenStream [
+                    Punct {
+                        ch: '#',
+                        spacing: Joint,
+                        span: $DIR/inner-attrs.rs:55:13: 55:14 (#0),
+                    },
+                    Punct {
+                        ch: '!',
+                        spacing: Alone,
+                        span: $DIR/inner-attrs.rs:55:14: 55:15 (#0),
+                    },
+                    Group {
+                        delimiter: Bracket,
+                        stream: TokenStream [
+                            Ident {
+                                ident: "cfg_attr",
+                                span: $DIR/inner-attrs.rs:55:16: 55:24 (#0),
+                            },
+                            Group {
+                                delimiter: Parenthesis,
+                                stream: TokenStream [
+                                    Ident {
+                                        ident: "not",
+                                        span: $DIR/inner-attrs.rs:55:25: 55:28 (#0),
+                                    },
+                                    Group {
+                                        delimiter: Parenthesis,
+                                        stream: TokenStream [
+                                            Ident {
+                                                ident: "FALSE",
+                                                span: $DIR/inner-attrs.rs:55:29: 55:34 (#0),
+                                            },
+                                        ],
+                                        span: $DIR/inner-attrs.rs:55:28: 55:35 (#0),
+                                    },
+                                    Punct {
+                                        ch: ',',
+                                        spacing: Alone,
+                                        span: $DIR/inner-attrs.rs:55:35: 55:36 (#0),
+                                    },
+                                    Ident {
+                                        ident: "rustc_dummy",
+                                        span: $DIR/inner-attrs.rs:55:37: 55:48 (#0),
+                                    },
+                                    Group {
+                                        delimiter: Parenthesis,
+                                        stream: TokenStream [
+                                            Ident {
+                                                ident: "innermost",
+                                                span: $DIR/inner-attrs.rs:55:49: 55:58 (#0),
+                                            },
+                                        ],
+                                        span: $DIR/inner-attrs.rs:55:48: 55:59 (#0),
+                                    },
+                                ],
+                                span: $DIR/inner-attrs.rs:55:24: 55:60 (#0),
                             },
+                        ],
+                        span: $DIR/inner-attrs.rs:55:15: 55:61 (#0),
+                    },
+                    Literal {
+                        kind: Integer,
+                        symbol: "5",
+                        suffix: None,
+                        span: $DIR/inner-attrs.rs:56:13: 56:14 (#0),
+                    },
+                ],
+                span: $DIR/inner-attrs.rs:54:15: 57:10 (#0),
+            },
+        ],
+        span: $DIR/inner-attrs.rs:52:43: 58:6 (#0),
+    },
+    Punct {
+        ch: ';',
+        spacing: Alone,
+        span: $DIR/inner-attrs.rs:58:6: 58:7 (#0),
+    },
+]
+PRINT-ATTR_ARGS INPUT (DISPLAY): array_attrs
+PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "array_attrs",
+        span: $DIR/inner-attrs.rs:60:29: 60:40 (#0),
+    },
+]
+PRINT-ATTR INPUT (DISPLAY): [# ! [rustc_dummy(inner)] true ; 0] ;
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+    Group {
+        delimiter: Bracket,
+        stream: TokenStream [
+            Punct {
+                ch: '#',
+                spacing: Joint,
+                span: $DIR/inner-attrs.rs:61:9: 61:10 (#0),
+            },
+            Punct {
+                ch: '!',
+                spacing: Alone,
+                span: $DIR/inner-attrs.rs:61:10: 61:11 (#0),
+            },
+            Group {
+                delimiter: Bracket,
+                stream: TokenStream [
+                    Ident {
+                        ident: "rustc_dummy",
+                        span: $DIR/inner-attrs.rs:61:12: 61:23 (#0),
+                    },
+                    Group {
+                        delimiter: Parenthesis,
+                        stream: TokenStream [
                             Ident {
-                                ident: "rustc_dummy",
-                                span: $DIR/inner-attrs.rs:31:28: 31:39 (#0),
+                                ident: "inner",
+                                span: $DIR/inner-attrs.rs:61:24: 61:29 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:31:20: 31:40 (#0),
+                        span: $DIR/inner-attrs.rs:61:23: 61:30 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:31:11: 31:41 (#0),
+                span: $DIR/inner-attrs.rs:61:11: 61:31 (#0),
+            },
+            Ident {
+                ident: "true",
+                span: $DIR/inner-attrs.rs:62:9: 62:13 (#0),
+            },
+            Punct {
+                ch: ';',
+                spacing: Alone,
+                span: $DIR/inner-attrs.rs:62:13: 62:14 (#0),
             },
             Literal {
                 kind: Integer,
+                symbol: "0",
+                suffix: None,
+                span: $DIR/inner-attrs.rs:62:15: 62:16 (#0),
+            },
+        ],
+        span: $DIR/inner-attrs.rs:60:43: 63:6 (#0),
+    },
+    Punct {
+        ch: ';',
+        spacing: Alone,
+        span: $DIR/inner-attrs.rs:63:6: 63:7 (#0),
+    },
+]
+PRINT-ATTR_ARGS INPUT (DISPLAY): tuple_attrs
+PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "tuple_attrs",
+        span: $DIR/inner-attrs.rs:65:29: 65:40 (#0),
+    },
+]
+PRINT-ATTR INPUT (DISPLAY): (3, 4, { # ! [cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }) ;
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+    Group {
+        delimiter: Parenthesis,
+        stream: TokenStream [
+            Literal {
+                kind: Integer,
                 symbol: "3",
                 suffix: None,
-                span: $DIR/inner-attrs.rs:32:9: 32:10 (#0),
+                span: $DIR/inner-attrs.rs:67:9: 67:10 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:32:10: 32:11 (#0),
+                span: $DIR/inner-attrs.rs:67:10: 67:11 (#0),
             },
             Literal {
                 kind: Integer,
                 symbol: "4",
                 suffix: None,
-                span: $DIR/inner-attrs.rs:32:12: 32:13 (#0),
+                span: $DIR/inner-attrs.rs:67:12: 67:13 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:32:13: 32:14 (#0),
+                span: $DIR/inner-attrs.rs:67:13: 67:14 (#0),
             },
             Group {
                 delimiter: Brace,
@@ -370,85 +985,85 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                     Punct {
                         ch: '#',
                         spacing: Joint,
-                        span: $DIR/inner-attrs.rs:33:13: 33:14 (#0),
+                        span: $DIR/inner-attrs.rs:68:13: 68:14 (#0),
                     },
                     Punct {
                         ch: '!',
                         spacing: Alone,
-                        span: $DIR/inner-attrs.rs:33:14: 33:15 (#0),
+                        span: $DIR/inner-attrs.rs:68:14: 68:15 (#0),
                     },
                     Group {
                         delimiter: Bracket,
                         stream: TokenStream [
                             Ident {
                                 ident: "cfg_attr",
-                                span: $DIR/inner-attrs.rs:33:16: 33:24 (#0),
+                                span: $DIR/inner-attrs.rs:68:16: 68:24 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "not",
-                                        span: $DIR/inner-attrs.rs:33:25: 33:28 (#0),
+                                        span: $DIR/inner-attrs.rs:68:25: 68:28 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "FALSE",
-                                                span: $DIR/inner-attrs.rs:33:29: 33:34 (#0),
+                                                span: $DIR/inner-attrs.rs:68:29: 68:34 (#0),
                                             },
                                         ],
-                                        span: $DIR/inner-attrs.rs:33:28: 33:35 (#0),
+                                        span: $DIR/inner-attrs.rs:68:28: 68:35 (#0),
                                     },
                                     Punct {
                                         ch: ',',
                                         spacing: Alone,
-                                        span: $DIR/inner-attrs.rs:33:35: 33:36 (#0),
+                                        span: $DIR/inner-attrs.rs:68:35: 68:36 (#0),
                                     },
                                     Ident {
                                         ident: "rustc_dummy",
-                                        span: $DIR/inner-attrs.rs:33:37: 33:48 (#0),
+                                        span: $DIR/inner-attrs.rs:68:37: 68:48 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "innermost",
-                                                span: $DIR/inner-attrs.rs:33:49: 33:58 (#0),
+                                                span: $DIR/inner-attrs.rs:68:49: 68:58 (#0),
                                             },
                                         ],
-                                        span: $DIR/inner-attrs.rs:33:48: 33:59 (#0),
+                                        span: $DIR/inner-attrs.rs:68:48: 68:59 (#0),
                                     },
                                 ],
-                                span: $DIR/inner-attrs.rs:33:24: 33:60 (#0),
+                                span: $DIR/inner-attrs.rs:68:24: 68:60 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:33:15: 33:61 (#0),
+                        span: $DIR/inner-attrs.rs:68:15: 68:61 (#0),
                     },
                     Literal {
                         kind: Integer,
                         symbol: "5",
                         suffix: None,
-                        span: $DIR/inner-attrs.rs:34:13: 34:14 (#0),
+                        span: $DIR/inner-attrs.rs:69:13: 69:14 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:32:15: 35:10 (#0),
+                span: $DIR/inner-attrs.rs:67:15: 70:10 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:30:43: 36:6 (#0),
+        span: $DIR/inner-attrs.rs:65:43: 71:6 (#0),
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: $DIR/inner-attrs.rs:36:6: 36:7 (#0),
+        span: $DIR/inner-attrs.rs:71:6: 71:7 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): array_attrs
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "array_attrs",
-        span: $DIR/inner-attrs.rs:38:29: 38:40 (#0),
+        span: $DIR/inner-attrs.rs:73:29: 73:40 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): [# ! [rustc_dummy(inner)] true ; 0] ;
@@ -459,82 +1074,82 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:38:43: 41:7 (#0),
+                span: $DIR/inner-attrs.rs:74:9: 74:10 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:38:43: 41:7 (#0),
+                span: $DIR/inner-attrs.rs:74:10: 74:11 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "rustc_dummy",
-                        span: $DIR/inner-attrs.rs:38:43: 41:7 (#0),
+                        span: $DIR/inner-attrs.rs:74:12: 74:23 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "inner",
-                                span: $DIR/inner-attrs.rs:38:43: 41:7 (#0),
+                                span: $DIR/inner-attrs.rs:74:24: 74:29 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:38:43: 41:7 (#0),
+                        span: $DIR/inner-attrs.rs:74:23: 74:30 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:38:43: 41:7 (#0),
+                span: $DIR/inner-attrs.rs:74:11: 74:31 (#0),
             },
             Ident {
                 ident: "true",
-                span: $DIR/inner-attrs.rs:38:43: 41:7 (#0),
+                span: $DIR/inner-attrs.rs:75:9: 75:13 (#0),
             },
             Punct {
                 ch: ';',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:38:43: 41:7 (#0),
+                span: $DIR/inner-attrs.rs:75:13: 75:14 (#0),
             },
             Literal {
                 kind: Integer,
                 symbol: "0",
                 suffix: None,
-                span: $DIR/inner-attrs.rs:38:43: 41:7 (#0),
+                span: $DIR/inner-attrs.rs:75:15: 75:16 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:38:43: 41:7 (#0),
+        span: $DIR/inner-attrs.rs:73:43: 76:6 (#0),
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: $DIR/inner-attrs.rs:38:43: 41:7 (#0),
+        span: $DIR/inner-attrs.rs:76:6: 76:7 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): tenth
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "tenth",
-        span: $DIR/inner-attrs.rs:60:42: 60:47 (#0),
+        span: $DIR/inner-attrs.rs:112:42: 112:47 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): fn weird_extern() { }
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "fn",
-        span: $DIR/inner-attrs.rs:59:5: 61:6 (#0),
+        span: $DIR/inner-attrs.rs:111:5: 111:7 (#0),
     },
     Ident {
         ident: "weird_extern",
-        span: $DIR/inner-attrs.rs:59:5: 61:6 (#0),
+        span: $DIR/inner-attrs.rs:111:8: 111:20 (#0),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:59:5: 61:6 (#0),
+        span: $DIR/inner-attrs.rs:111:20: 111:22 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:59:5: 61:6 (#0),
+        span: $DIR/inner-attrs.rs:111:23: 113:6 (#0),
     },
 ]
diff --git a/src/test/ui/proc-macro/issue-36935.stderr b/src/test/ui/proc-macro/issue-36935.stderr
index 2b2e28fdb2f..079e134c6f8 100644
--- a/src/test/ui/proc-macro/issue-36935.stderr
+++ b/src/test/ui/proc-macro/issue-36935.stderr
@@ -1,11 +1,3 @@
-error: proc-macro derive panicked
-  --> $DIR/issue-36935.rs:6:20
-   |
-LL | #[derive(Identity, Panic)]
-   |                    ^^^^^
-   |
-   = help: message: panic-derive
-
 error[E0428]: the name `Baz` is defined multiple times
   --> $DIR/issue-36935.rs:7:1
    |
@@ -17,6 +9,14 @@ LL | struct Baz {
    |
    = note: `Baz` must be defined only once in the type namespace of this module
 
+error: proc-macro derive panicked
+  --> $DIR/issue-36935.rs:6:20
+   |
+LL | #[derive(Identity, Panic)]
+   |                    ^^^^^
+   |
+   = help: message: panic-derive
+
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0428`.
diff --git a/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout b/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout
index 7cbc0c669a5..d7adc5331cd 100644
--- a/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout
+++ b/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout
@@ -1279,152 +1279,152 @@ PRINT-DERIVE INPUT (DISPLAY): #[print_helper(a)] #[allow(dead_code)] #[print_hel
     [u8 ;
      {
          #[cfg(not(FALSE))] struct Inner ; match true
-         { #[allow(warnings)] false => { } _ => { } } ; #[print_helper(c)]
+         { #[allow(warnings)] false => { }, _ => { } } ; #[print_helper(c)]
          #[cfg(not(FALSE))] fn kept_fn()
          { # ! [cfg(not(FALSE))] let my_val = true ; } enum TupleEnum
-         { Foo(#[cfg(not(FALSE))] i32, u8), } struct
+         { Foo(#[cfg(not(FALSE))] i32, u8) } struct
          TupleStruct(#[cfg(not(FALSE))] i32, u8) ; 0
-     }], #[print_helper(d)] fourth : B,
+     }], #[print_helper(d)] fourth : B
 }
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:19:1: 19:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "print_helper",
-                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:19:3: 19:15 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "a",
-                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:19:16: 19:17 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:19:15: 19:18 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:19:2: 19:19 (#0),
     },
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:21:1: 21:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "allow",
-                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:21:24: 21:29 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "dead_code",
-                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:21:30: 21:39 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:21:29: 21:40 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:21:1: 21:2 (#0),
     },
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:24:1: 24:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "print_helper",
-                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:24:3: 24:15 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "b",
-                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:24:16: 24:17 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:24:15: 24:18 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:24:2: 24:19 (#0),
     },
     Ident {
         ident: "struct",
-        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:25:1: 25:7 (#0),
     },
     Ident {
         ident: "Foo",
-        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:25:8: 25:11 (#0),
     },
     Punct {
         ch: '<',
-        spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+        spacing: Joint,
+        span: $DIR/issue-75930-derive-cfg.rs:25:11: 25:12 (#0),
     },
     Ident {
         ident: "B",
-        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:25:29: 25:30 (#0),
     },
     Punct {
         ch: '>',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:25:30: 25:31 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [
             Ident {
                 ident: "second",
-                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:27:40: 27:46 (#0),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:27:46: 27:47 (#0),
             },
             Ident {
                 ident: "bool",
-                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:27:48: 27:52 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:27:52: 27:53 (#0),
             },
             Ident {
                 ident: "third",
-                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:28:5: 28:10 (#0),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:28:10: 28:11 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "u8",
-                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:28:13: 28:15 (#0),
                     },
                     Punct {
                         ch: ';',
                         spacing: Alone,
-                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:28:15: 28:16 (#0),
                     },
                     Group {
                         delimiter: Brace,
@@ -1432,58 +1432,58 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:30:9: 30:10 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "cfg",
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:30:11: 30:14 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "not",
-                                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:30:15: 30:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "FALSE",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:30:19: 30:24 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:30:18: 30:25 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:30:14: 30:26 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:30:10: 30:27 (#0),
                             },
                             Ident {
                                 ident: "struct",
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:30:28: 30:34 (#0),
                             },
                             Ident {
                                 ident: "Inner",
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:30:35: 30:40 (#0),
                             },
                             Punct {
                                 ch: ';',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:30:40: 30:41 (#0),
                             },
                             Ident {
                                 ident: "match",
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:32:9: 32:14 (#0),
                             },
                             Ident {
                                 ident: "true",
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:32:15: 32:19 (#0),
                             },
                             Group {
                                 delimiter: Brace,
@@ -1491,146 +1491,151 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                                     Punct {
                                         ch: '#',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:34:13: 34:14 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "allow",
-                                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:34:36: 34:41 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "warnings",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:34:42: 34:50 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:34:41: 34:51 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:34:13: 34:14 (#0),
                                     },
                                     Ident {
                                         ident: "false",
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:34:54: 34:59 (#0),
                                     },
                                     Punct {
                                         ch: '=',
                                         spacing: Joint,
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:34:60: 34:62 (#0),
                                     },
                                     Punct {
                                         ch: '>',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:34:60: 34:62 (#0),
                                     },
                                     Group {
                                         delimiter: Brace,
                                         stream: TokenStream [],
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:34:63: 34:65 (#0),
+                                    },
+                                    Punct {
+                                        ch: ',',
+                                        spacing: Alone,
+                                        span: $DIR/issue-75930-derive-cfg.rs:34:65: 34:66 (#0),
                                     },
                                     Ident {
                                         ident: "_",
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:35:13: 35:14 (#0),
                                     },
                                     Punct {
                                         ch: '=',
                                         spacing: Joint,
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:35:15: 35:17 (#0),
                                     },
                                     Punct {
                                         ch: '>',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:35:15: 35:17 (#0),
                                     },
                                     Group {
                                         delimiter: Brace,
                                         stream: TokenStream [],
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:35:18: 35:20 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:32:20: 36:10 (#0),
                             },
                             Punct {
                                 ch: ';',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:36:10: 36:11 (#0),
                             },
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:43:9: 43:10 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "print_helper",
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:43:11: 43:23 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "c",
-                                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:43:24: 43:25 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:43:23: 43:26 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:43:10: 43:27 (#0),
                             },
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:43:28: 43:29 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "cfg",
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:43:30: 43:33 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "not",
-                                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:43:34: 43:37 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "FALSE",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:43:38: 43:43 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:43:37: 43:44 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:43:33: 43:45 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:43:29: 43:46 (#0),
                             },
                             Ident {
                                 ident: "fn",
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:43:47: 43:49 (#0),
                             },
                             Ident {
                                 ident: "kept_fn",
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:43:50: 43:57 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
                                 stream: TokenStream [],
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:43:57: 43:59 (#0),
                             },
                             Group {
                                 delimiter: Brace,
@@ -1638,82 +1643,82 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                                     Punct {
                                         ch: '#',
                                         spacing: Joint,
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:44:13: 44:14 (#0),
                                     },
                                     Punct {
                                         ch: '!',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:44:14: 44:15 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "cfg",
-                                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:44:16: 44:19 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "not",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:44:20: 44:23 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "FALSE",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:44:24: 44:29 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:44:23: 44:30 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:44:19: 44:31 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:44:15: 44:32 (#0),
                                     },
                                     Ident {
                                         ident: "let",
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:45:13: 45:16 (#0),
                                     },
                                     Ident {
                                         ident: "my_val",
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:45:17: 45:23 (#0),
                                     },
                                     Punct {
                                         ch: '=',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:45:24: 45:25 (#0),
                                     },
                                     Ident {
                                         ident: "true",
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:45:26: 45:30 (#0),
                                     },
                                     Punct {
                                         ch: ';',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:45:30: 45:31 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:43:60: 46:10 (#0),
                             },
                             Ident {
                                 ident: "enum",
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:48:9: 48:13 (#0),
                             },
                             Ident {
                                 ident: "TupleEnum",
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:48:14: 48:23 (#0),
                             },
                             Group {
                                 delimiter: Brace,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "Foo",
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:49:13: 49:16 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
@@ -1721,69 +1726,64 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                                             Punct {
                                                 ch: '#',
                                                 spacing: Alone,
-                                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:52:17: 52:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Bracket,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "cfg",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:52:19: 52:22 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "not",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:52:23: 52:26 (#0),
                                                             },
                                                             Group {
                                                                 delimiter: Parenthesis,
                                                                 stream: TokenStream [
                                                                     Ident {
                                                                         ident: "FALSE",
-                                                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                                        span: $DIR/issue-75930-derive-cfg.rs:52:27: 52:32 (#0),
                                                                     },
                                                                 ],
-                                                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:52:26: 52:33 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:52:22: 52:34 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:52:18: 52:35 (#0),
                                             },
                                             Ident {
                                                 ident: "i32",
-                                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:52:36: 52:39 (#0),
                                             },
                                             Punct {
                                                 ch: ',',
                                                 spacing: Alone,
-                                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:52:39: 52:40 (#0),
                                             },
                                             Ident {
                                                 ident: "u8",
-                                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:53:39: 53:41 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
-                                    },
-                                    Punct {
-                                        ch: ',',
-                                        spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:49:16: 54:14 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:48:24: 55:10 (#0),
                             },
                             Ident {
                                 ident: "struct",
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:57:9: 57:15 (#0),
                             },
                             Ident {
                                 ident: "TupleStruct",
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:57:16: 57:27 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
@@ -1791,120 +1791,115 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                                     Punct {
                                         ch: '#',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:59:13: 59:14 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "cfg",
-                                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:59:15: 59:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "not",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:59:19: 59:22 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "FALSE",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:59:23: 59:28 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:59:22: 59:29 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:59:18: 59:30 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:59:14: 59:31 (#0),
                                     },
                                     Ident {
                                         ident: "i32",
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:59:32: 59:35 (#0),
                                     },
                                     Punct {
                                         ch: ',',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:59:35: 59:36 (#0),
                                     },
                                     Ident {
                                         ident: "u8",
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:61:13: 61:15 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:57:27: 62:10 (#0),
                             },
                             Punct {
                                 ch: ';',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:62:10: 62:11 (#0),
                             },
                             Literal {
                                 kind: Integer,
                                 symbol: "0",
                                 suffix: None,
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:68:9: 68:10 (#0),
                             },
                         ],
-                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:28:17: 69:6 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:28:12: 69:7 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:69:7: 69:8 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:70:5: 70:6 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_helper",
-                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:70:7: 70:19 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "d",
-                                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:70:20: 70:21 (#0),
                             },
                         ],
-                        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:70:19: 70:22 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:70:6: 70:23 (#0),
             },
             Ident {
                 ident: "fourth",
-                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:71:5: 71:11 (#0),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:71:11: 71:12 (#0),
             },
             Ident {
                 ident: "B",
-                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
-            },
-            Punct {
-                ch: ',',
-                spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:71:13: 71:14 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:25:1: 72:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:25:32: 72:2 (#0),
     },
 ]
diff --git a/src/test/ui/proc-macro/issue-78675-captured-inner-attrs.stdout b/src/test/ui/proc-macro/issue-78675-captured-inner-attrs.stdout
index 9b467a5970b..607c2954c7c 100644
--- a/src/test/ui/proc-macro/issue-78675-captured-inner-attrs.stdout
+++ b/src/test/ui/proc-macro/issue-78675-captured-inner-attrs.stdout
@@ -35,48 +35,48 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
                 stream: TokenStream [
                     Ident {
                         ident: "mod",
-                        span: $DIR/issue-78675-captured-inner-attrs.rs:27:5: 29:6 (#0),
+                        span: $DIR/issue-78675-captured-inner-attrs.rs:27:5: 27:8 (#0),
                     },
                     Ident {
                         ident: "bar",
-                        span: $DIR/issue-78675-captured-inner-attrs.rs:27:5: 29:6 (#0),
+                        span: $DIR/issue-78675-captured-inner-attrs.rs:27:9: 27:12 (#0),
                     },
                     Group {
                         delimiter: Brace,
                         stream: TokenStream [
                             Punct {
                                 ch: '#',
-                                spacing: Joint,
-                                span: $DIR/issue-78675-captured-inner-attrs.rs:27:5: 29:6 (#0),
+                                spacing: Alone,
+                                span: $DIR/issue-78675-captured-inner-attrs.rs:28:9: 28:16 (#0),
                             },
                             Punct {
                                 ch: '!',
                                 spacing: Alone,
-                                span: $DIR/issue-78675-captured-inner-attrs.rs:27:5: 29:6 (#0),
+                                span: $DIR/issue-78675-captured-inner-attrs.rs:28:9: 28:16 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "doc",
-                                        span: $DIR/issue-78675-captured-inner-attrs.rs:27:5: 29:6 (#0),
+                                        span: $DIR/issue-78675-captured-inner-attrs.rs:28:9: 28:16 (#0),
                                     },
                                     Punct {
                                         ch: '=',
                                         spacing: Alone,
-                                        span: $DIR/issue-78675-captured-inner-attrs.rs:27:5: 29:6 (#0),
+                                        span: $DIR/issue-78675-captured-inner-attrs.rs:28:9: 28:16 (#0),
                                     },
                                     Literal {
                                         kind: StrRaw(0),
                                         symbol: " Foo",
                                         suffix: None,
-                                        span: $DIR/issue-78675-captured-inner-attrs.rs:27:5: 29:6 (#0),
+                                        span: $DIR/issue-78675-captured-inner-attrs.rs:28:9: 28:16 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-78675-captured-inner-attrs.rs:27:5: 29:6 (#0),
+                                span: $DIR/issue-78675-captured-inner-attrs.rs:28:9: 28:16 (#0),
                             },
                         ],
-                        span: $DIR/issue-78675-captured-inner-attrs.rs:27:5: 29:6 (#0),
+                        span: $DIR/issue-78675-captured-inner-attrs.rs:27:13: 29:6 (#0),
                     },
                 ],
                 span: $DIR/issue-78675-captured-inner-attrs.rs:22:13: 22:18 (#4),
diff --git a/src/test/ui/proc-macro/macro-rules-derive-cfg.stdout b/src/test/ui/proc-macro/macro-rules-derive-cfg.stdout
index 5db18590bdf..a0b0cbb19e4 100644
--- a/src/test/ui/proc-macro/macro-rules-derive-cfg.stdout
+++ b/src/test/ui/proc-macro/macro-rules-derive-cfg.stdout
@@ -5,172 +5,167 @@ PRINT-DERIVE INPUT (DISPLAY): struct Foo
      {
          let a = #[rustc_dummy(first)] #[rustc_dummy(second)]
          { # ! [allow(unused)] 30 } ; 0
-     }],
+     }]
 }
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
-        span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+        span: $DIR/macro-rules-derive-cfg.rs:17:9: 17:15 (#4),
     },
     Ident {
         ident: "Foo",
-        span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+        span: $DIR/macro-rules-derive-cfg.rs:17:16: 17:19 (#4),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [
             Ident {
                 ident: "val",
-                span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                span: $DIR/macro-rules-derive-cfg.rs:18:13: 18:16 (#4),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                span: $DIR/macro-rules-derive-cfg.rs:18:16: 18:17 (#4),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "bool",
-                        span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                        span: $DIR/macro-rules-derive-cfg.rs:18:19: 18:23 (#4),
                     },
                     Punct {
                         ch: ';',
                         spacing: Alone,
-                        span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                        span: $DIR/macro-rules-derive-cfg.rs:18:23: 18:24 (#4),
                     },
                     Group {
                         delimiter: Brace,
                         stream: TokenStream [
                             Ident {
                                 ident: "let",
-                                span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                                span: $DIR/macro-rules-derive-cfg.rs:19:17: 19:20 (#4),
                             },
                             Ident {
                                 ident: "a",
-                                span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                                span: $DIR/macro-rules-derive-cfg.rs:19:21: 19:22 (#4),
                             },
                             Punct {
                                 ch: '=',
                                 spacing: Alone,
-                                span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                                span: $DIR/macro-rules-derive-cfg.rs:19:23: 19:24 (#4),
                             },
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                                span: $DIR/macro-rules-derive-cfg.rs:19:25: 19:26 (#4),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "rustc_dummy",
-                                        span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                                        span: $DIR/macro-rules-derive-cfg.rs:19:48: 19:59 (#4),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "first",
-                                                span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                                                span: $DIR/macro-rules-derive-cfg.rs:19:60: 19:65 (#4),
                                             },
                                         ],
-                                        span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                                        span: $DIR/macro-rules-derive-cfg.rs:19:59: 19:66 (#4),
                                     },
                                 ],
-                                span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                                span: $DIR/macro-rules-derive-cfg.rs:19:25: 19:26 (#4),
                             },
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                                span: $DIR/macro-rules-derive-cfg.rs:26:13: 26:14 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "rustc_dummy",
-                                        span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                                        span: $DIR/macro-rules-derive-cfg.rs:26:36: 26:47 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "second",
-                                                span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                                                span: $DIR/macro-rules-derive-cfg.rs:26:48: 26:54 (#0),
                                             },
                                         ],
-                                        span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                                        span: $DIR/macro-rules-derive-cfg.rs:26:47: 26:55 (#0),
                                     },
                                 ],
-                                span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                                span: $DIR/macro-rules-derive-cfg.rs:26:13: 26:14 (#0),
                             },
                             Group {
                                 delimiter: Brace,
                                 stream: TokenStream [
                                     Punct {
                                         ch: '#',
-                                        spacing: Joint,
-                                        span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                                        spacing: Alone,
+                                        span: $DIR/macro-rules-derive-cfg.rs:27:5: 27:6 (#0),
                                     },
                                     Punct {
                                         ch: '!',
                                         spacing: Alone,
-                                        span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                                        span: $DIR/macro-rules-derive-cfg.rs:27:6: 27:7 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "allow",
-                                                span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                                                span: $DIR/macro-rules-derive-cfg.rs:27:29: 27:34 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "unused",
-                                                        span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                                                        span: $DIR/macro-rules-derive-cfg.rs:27:35: 27:41 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                                                span: $DIR/macro-rules-derive-cfg.rs:27:34: 27:42 (#0),
                                             },
                                         ],
-                                        span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                                        span: $DIR/macro-rules-derive-cfg.rs:27:5: 27:6 (#0),
                                     },
                                     Literal {
                                         kind: Integer,
                                         symbol: "30",
                                         suffix: None,
-                                        span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                                        span: $DIR/macro-rules-derive-cfg.rs:28:5: 28:7 (#0),
                                     },
                                 ],
-                                span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                                span: $DIR/macro-rules-derive-cfg.rs:26:58: 29:2 (#0),
                             },
                             Punct {
                                 ch: ';',
                                 spacing: Alone,
-                                span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                                span: $DIR/macro-rules-derive-cfg.rs:19:74: 19:75 (#4),
                             },
                             Literal {
                                 kind: Integer,
                                 symbol: "0",
                                 suffix: None,
-                                span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                                span: $DIR/macro-rules-derive-cfg.rs:20:17: 20:18 (#4),
                             },
                         ],
-                        span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                        span: $DIR/macro-rules-derive-cfg.rs:18:25: 21:14 (#4),
                     },
                 ],
-                span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
-            },
-            Punct {
-                ch: ',',
-                spacing: Alone,
-                span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+                span: $DIR/macro-rules-derive-cfg.rs:18:18: 21:15 (#4),
             },
         ],
-        span: $DIR/macro-rules-derive-cfg.rs:17:9: 22:10 (#4),
+        span: $DIR/macro-rules-derive-cfg.rs:17:20: 22:10 (#4),
     },
 ]
diff --git a/src/test/ui/proc-macro/nested-derive-cfg.stdout b/src/test/ui/proc-macro/nested-derive-cfg.stdout
index cf4e5d94d8a..9a562c971c8 100644
--- a/src/test/ui/proc-macro/nested-derive-cfg.stdout
+++ b/src/test/ui/proc-macro/nested-derive-cfg.stdout
@@ -1,94 +1,81 @@
 PRINT-DERIVE INPUT (DISPLAY): struct Foo
-{
-    my_array :
-    [bool ; { struct Inner { non_removed_inner_field : usize, } 0 }],
-}
+{ my_array : [bool ; { struct Inner { non_removed_inner_field : usize } 0 }] }
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
-        span: $DIR/nested-derive-cfg.rs:12:1: 21:2 (#0),
+        span: $DIR/nested-derive-cfg.rs:12:1: 12:7 (#0),
     },
     Ident {
         ident: "Foo",
-        span: $DIR/nested-derive-cfg.rs:12:1: 21:2 (#0),
+        span: $DIR/nested-derive-cfg.rs:12:8: 12:11 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [
             Ident {
                 ident: "my_array",
-                span: $DIR/nested-derive-cfg.rs:12:1: 21:2 (#0),
+                span: $DIR/nested-derive-cfg.rs:14:5: 14:13 (#0),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/nested-derive-cfg.rs:12:1: 21:2 (#0),
+                span: $DIR/nested-derive-cfg.rs:14:13: 14:14 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "bool",
-                        span: $DIR/nested-derive-cfg.rs:12:1: 21:2 (#0),
+                        span: $DIR/nested-derive-cfg.rs:14:16: 14:20 (#0),
                     },
                     Punct {
                         ch: ';',
                         spacing: Alone,
-                        span: $DIR/nested-derive-cfg.rs:12:1: 21:2 (#0),
+                        span: $DIR/nested-derive-cfg.rs:14:20: 14:21 (#0),
                     },
                     Group {
                         delimiter: Brace,
                         stream: TokenStream [
                             Ident {
                                 ident: "struct",
-                                span: $DIR/nested-derive-cfg.rs:12:1: 21:2 (#0),
+                                span: $DIR/nested-derive-cfg.rs:15:9: 15:15 (#0),
                             },
                             Ident {
                                 ident: "Inner",
-                                span: $DIR/nested-derive-cfg.rs:12:1: 21:2 (#0),
+                                span: $DIR/nested-derive-cfg.rs:15:16: 15:21 (#0),
                             },
                             Group {
                                 delimiter: Brace,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "non_removed_inner_field",
-                                        span: $DIR/nested-derive-cfg.rs:12:1: 21:2 (#0),
+                                        span: $DIR/nested-derive-cfg.rs:17:13: 17:36 (#0),
                                     },
                                     Punct {
                                         ch: ':',
                                         spacing: Alone,
-                                        span: $DIR/nested-derive-cfg.rs:12:1: 21:2 (#0),
+                                        span: $DIR/nested-derive-cfg.rs:17:36: 17:37 (#0),
                                     },
                                     Ident {
                                         ident: "usize",
-                                        span: $DIR/nested-derive-cfg.rs:12:1: 21:2 (#0),
-                                    },
-                                    Punct {
-                                        ch: ',',
-                                        spacing: Alone,
-                                        span: $DIR/nested-derive-cfg.rs:12:1: 21:2 (#0),
+                                        span: $DIR/nested-derive-cfg.rs:17:38: 17:43 (#0),
                                     },
                                 ],
-                                span: $DIR/nested-derive-cfg.rs:12:1: 21:2 (#0),
+                                span: $DIR/nested-derive-cfg.rs:15:22: 18:10 (#0),
                             },
                             Literal {
                                 kind: Integer,
                                 symbol: "0",
                                 suffix: None,
-                                span: $DIR/nested-derive-cfg.rs:12:1: 21:2 (#0),
+                                span: $DIR/nested-derive-cfg.rs:19:9: 19:10 (#0),
                             },
                         ],
-                        span: $DIR/nested-derive-cfg.rs:12:1: 21:2 (#0),
+                        span: $DIR/nested-derive-cfg.rs:14:22: 20:6 (#0),
                     },
                 ],
-                span: $DIR/nested-derive-cfg.rs:12:1: 21:2 (#0),
-            },
-            Punct {
-                ch: ',',
-                spacing: Alone,
-                span: $DIR/nested-derive-cfg.rs:12:1: 21:2 (#0),
+                span: $DIR/nested-derive-cfg.rs:14:15: 20:7 (#0),
             },
         ],
-        span: $DIR/nested-derive-cfg.rs:12:1: 21:2 (#0),
+        span: $DIR/nested-derive-cfg.rs:12:12: 21:2 (#0),
     },
 ]
diff --git a/src/test/ui/proc-macro/nonterminal-recollect-attr.rs b/src/test/ui/proc-macro/nonterminal-recollect-attr.rs
index 5d4649b78c2..79c4ad4cd2a 100644
--- a/src/test/ui/proc-macro/nonterminal-recollect-attr.rs
+++ b/src/test/ui/proc-macro/nonterminal-recollect-attr.rs
@@ -1,6 +1,10 @@
 // check-pass
+// compile-flags: -Z span-debug
 // aux-build:nonterminal-recollect-attr.rs
 
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
 extern crate nonterminal_recollect_attr;
 use nonterminal_recollect_attr::*;
 
diff --git a/src/test/ui/proc-macro/nonterminal-recollect-attr.stdout b/src/test/ui/proc-macro/nonterminal-recollect-attr.stdout
new file mode 100644
index 00000000000..7331a25abd3
--- /dev/null
+++ b/src/test/ui/proc-macro/nonterminal-recollect-attr.stdout
@@ -0,0 +1,72 @@
+First recollected: TokenStream [
+    Group {
+        delimiter: None,
+        stream: TokenStream [
+            Ident {
+                ident: "pub",
+                span: $DIR/nonterminal-recollect-attr.rs:20:11: 20:14 (#0),
+            },
+        ],
+        span: $DIR/nonterminal-recollect-attr.rs:14:9: 14:11 (#4),
+    },
+    Ident {
+        ident: "struct",
+        span: $DIR/nonterminal-recollect-attr.rs:14:12: 14:18 (#4),
+    },
+    Ident {
+        ident: "Foo",
+        span: $DIR/nonterminal-recollect-attr.rs:14:19: 14:22 (#4),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [
+            Ident {
+                ident: "field",
+                span: $DIR/nonterminal-recollect-attr.rs:15:13: 15:18 (#4),
+            },
+            Punct {
+                ch: ':',
+                spacing: Alone,
+                span: $DIR/nonterminal-recollect-attr.rs:15:18: 15:19 (#4),
+            },
+            Ident {
+                ident: "u8",
+                span: $DIR/nonterminal-recollect-attr.rs:15:20: 15:22 (#4),
+            },
+        ],
+        span: $DIR/nonterminal-recollect-attr.rs:14:23: 16:10 (#4),
+    },
+]
+Second recollected: TokenStream [
+    Ident {
+        ident: "pub",
+        span: $DIR/nonterminal-recollect-attr.rs:20:11: 20:14 (#0),
+    },
+    Ident {
+        ident: "struct",
+        span: $DIR/nonterminal-recollect-attr.rs:14:12: 14:18 (#4),
+    },
+    Ident {
+        ident: "Foo",
+        span: $DIR/nonterminal-recollect-attr.rs:14:19: 14:22 (#4),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [
+            Ident {
+                ident: "field",
+                span: $DIR/nonterminal-recollect-attr.rs:15:13: 15:18 (#4),
+            },
+            Punct {
+                ch: ':',
+                spacing: Alone,
+                span: $DIR/nonterminal-recollect-attr.rs:15:18: 15:19 (#4),
+            },
+            Ident {
+                ident: "u8",
+                span: $DIR/nonterminal-recollect-attr.rs:15:20: 15:22 (#4),
+            },
+        ],
+        span: $DIR/nonterminal-recollect-attr.rs:14:23: 16:10 (#4),
+    },
+]
diff --git a/src/test/ui/proc-macro/simple-tuple.rs b/src/test/ui/proc-macro/simple-tuple.rs
new file mode 100644
index 00000000000..c94c5877e22
--- /dev/null
+++ b/src/test/ui/proc-macro/simple-tuple.rs
@@ -0,0 +1,19 @@
+// check-pass
+// compile-flags: -Z span-debug --error-format human
+// aux-build:test-macros.rs
+// edition:2018
+
+#![feature(proc_macro_hygiene)]
+
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
+#[macro_use]
+extern crate test_macros;
+
+fn main() {
+    #[print_target_and_args(my_arg)] (
+        #![cfg_attr(not(FALSE), allow(unused))]
+        1, 2, 3
+    );
+}
diff --git a/src/test/ui/proc-macro/simple-tuple.stdout b/src/test/ui/proc-macro/simple-tuple.stdout
new file mode 100644
index 00000000000..1cc8579a467
--- /dev/null
+++ b/src/test/ui/proc-macro/simple-tuple.stdout
@@ -0,0 +1,79 @@
+PRINT-ATTR_ARGS INPUT (DISPLAY): my_arg
+PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "my_arg",
+        span: $DIR/simple-tuple.rs:15:29: 15:35 (#0),
+    },
+]
+PRINT-ATTR INPUT (DISPLAY): (# ! [allow(unused)] 1, 2, 3) ;
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+    Group {
+        delimiter: Parenthesis,
+        stream: TokenStream [
+            Punct {
+                ch: '#',
+                spacing: Alone,
+                span: $DIR/simple-tuple.rs:16:9: 16:10 (#0),
+            },
+            Punct {
+                ch: '!',
+                spacing: Alone,
+                span: $DIR/simple-tuple.rs:16:10: 16:11 (#0),
+            },
+            Group {
+                delimiter: Bracket,
+                stream: TokenStream [
+                    Ident {
+                        ident: "allow",
+                        span: $DIR/simple-tuple.rs:16:33: 16:38 (#0),
+                    },
+                    Group {
+                        delimiter: Parenthesis,
+                        stream: TokenStream [
+                            Ident {
+                                ident: "unused",
+                                span: $DIR/simple-tuple.rs:16:39: 16:45 (#0),
+                            },
+                        ],
+                        span: $DIR/simple-tuple.rs:16:38: 16:46 (#0),
+                    },
+                ],
+                span: $DIR/simple-tuple.rs:16:9: 16:10 (#0),
+            },
+            Literal {
+                kind: Integer,
+                symbol: "1",
+                suffix: None,
+                span: $DIR/simple-tuple.rs:17:9: 17:10 (#0),
+            },
+            Punct {
+                ch: ',',
+                spacing: Alone,
+                span: $DIR/simple-tuple.rs:17:10: 17:11 (#0),
+            },
+            Literal {
+                kind: Integer,
+                symbol: "2",
+                suffix: None,
+                span: $DIR/simple-tuple.rs:17:12: 17:13 (#0),
+            },
+            Punct {
+                ch: ',',
+                spacing: Alone,
+                span: $DIR/simple-tuple.rs:17:13: 17:14 (#0),
+            },
+            Literal {
+                kind: Integer,
+                symbol: "3",
+                suffix: None,
+                span: $DIR/simple-tuple.rs:17:15: 17:16 (#0),
+            },
+        ],
+        span: $DIR/simple-tuple.rs:15:38: 18:6 (#0),
+    },
+    Punct {
+        ch: ';',
+        spacing: Alone,
+        span: $DIR/simple-tuple.rs:18:6: 18:7 (#0),
+    },
+]
diff --git a/src/test/ui/proc-macro/weird-braces.stdout b/src/test/ui/proc-macro/weird-braces.stdout
index 25f0eaf0dd4..990829456e8 100644
--- a/src/test/ui/proc-macro/weird-braces.stdout
+++ b/src/test/ui/proc-macro/weird-braces.stdout
@@ -15,40 +15,40 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:17:1: 17:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "print_target_and_args",
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:17:3: 17:24 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "second_outer",
-                        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                        span: $DIR/weird-braces.rs:17:25: 17:37 (#0),
                     },
                 ],
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:17:24: 17:38 (#0),
             },
         ],
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:17:2: 17:39 (#0),
     },
     Ident {
         ident: "impl",
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:1: 18:5 (#0),
     },
     Ident {
         ident: "Bar",
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:6: 18:9 (#0),
     },
     Punct {
         ch: '<',
         spacing: Alone,
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:9: 18:10 (#0),
     },
     Group {
         delimiter: Brace,
@@ -57,54 +57,54 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                 kind: Integer,
                 symbol: "1",
                 suffix: None,
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:18:11: 18:12 (#0),
             },
             Punct {
                 ch: '>',
                 spacing: Alone,
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:18:13: 18:14 (#0),
             },
             Literal {
                 kind: Integer,
                 symbol: "0",
                 suffix: None,
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:18:15: 18:16 (#0),
             },
         ],
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:10: 18:17 (#0),
     },
     Punct {
         ch: '>',
         spacing: Alone,
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:17: 18:18 (#0),
     },
     Ident {
         ident: "for",
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:19: 18:22 (#0),
     },
     Ident {
         ident: "Foo",
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:23: 18:26 (#0),
     },
     Punct {
         ch: '<',
         spacing: Alone,
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:26: 18:27 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [
             Ident {
                 ident: "true",
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:18:28: 18:32 (#0),
             },
         ],
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:27: 18:33 (#0),
     },
     Punct {
         ch: '>',
         spacing: Alone,
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:33: 18:34 (#0),
     },
     Group {
         delimiter: Brace,
@@ -112,72 +112,72 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:19:5: 19:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:19:6: 19:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                        span: $DIR/weird-braces.rs:19:8: 19:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "first_inner",
-                                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                                span: $DIR/weird-braces.rs:19:30: 19:41 (#0),
                             },
                         ],
-                        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                        span: $DIR/weird-braces.rs:19:29: 19:42 (#0),
                     },
                 ],
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:19:7: 19:43 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:20:5: 20:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:20:6: 20:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                        span: $DIR/weird-braces.rs:20:8: 20:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "second_inner",
-                                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                                span: $DIR/weird-braces.rs:20:30: 20:42 (#0),
                             },
                         ],
-                        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                        span: $DIR/weird-braces.rs:20:29: 20:43 (#0),
                     },
                 ],
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:20:7: 20:44 (#0),
             },
         ],
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:35: 21:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): second_outer
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "second_outer",
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:17:25: 17:37 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): impl Bar < { 1 > 0 } > for Foo < { true } >
@@ -188,16 +188,16 @@ PRINT-ATTR INPUT (DISPLAY): impl Bar < { 1 > 0 } > for Foo < { true } >
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "impl",
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:1: 18:5 (#0),
     },
     Ident {
         ident: "Bar",
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:6: 18:9 (#0),
     },
     Punct {
         ch: '<',
         spacing: Alone,
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:9: 18:10 (#0),
     },
     Group {
         delimiter: Brace,
@@ -206,54 +206,54 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                 kind: Integer,
                 symbol: "1",
                 suffix: None,
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:18:11: 18:12 (#0),
             },
             Punct {
                 ch: '>',
                 spacing: Alone,
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:18:13: 18:14 (#0),
             },
             Literal {
                 kind: Integer,
                 symbol: "0",
                 suffix: None,
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:18:15: 18:16 (#0),
             },
         ],
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:10: 18:17 (#0),
     },
     Punct {
         ch: '>',
         spacing: Alone,
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:17: 18:18 (#0),
     },
     Ident {
         ident: "for",
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:19: 18:22 (#0),
     },
     Ident {
         ident: "Foo",
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:23: 18:26 (#0),
     },
     Punct {
         ch: '<',
         spacing: Alone,
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:26: 18:27 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [
             Ident {
                 ident: "true",
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:18:28: 18:32 (#0),
             },
         ],
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:27: 18:33 (#0),
     },
     Punct {
         ch: '>',
         spacing: Alone,
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:33: 18:34 (#0),
     },
     Group {
         delimiter: Brace,
@@ -261,72 +261,72 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:19:5: 19:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:19:6: 19:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                        span: $DIR/weird-braces.rs:19:8: 19:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "first_inner",
-                                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                                span: $DIR/weird-braces.rs:19:30: 19:41 (#0),
                             },
                         ],
-                        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                        span: $DIR/weird-braces.rs:19:29: 19:42 (#0),
                     },
                 ],
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:19:7: 19:43 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:20:5: 20:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:20:6: 20:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                        span: $DIR/weird-braces.rs:20:8: 20:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "second_inner",
-                                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                                span: $DIR/weird-braces.rs:20:30: 20:42 (#0),
                             },
                         ],
-                        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                        span: $DIR/weird-braces.rs:20:29: 20:43 (#0),
                     },
                 ],
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:20:7: 20:44 (#0),
             },
         ],
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:35: 21:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): first_inner
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "first_inner",
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:19:30: 19:41 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): impl Bar < { 1 > 0 } > for Foo < { true } >
@@ -334,16 +334,16 @@ PRINT-ATTR INPUT (DISPLAY): impl Bar < { 1 > 0 } > for Foo < { true } >
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "impl",
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:1: 18:5 (#0),
     },
     Ident {
         ident: "Bar",
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:6: 18:9 (#0),
     },
     Punct {
         ch: '<',
         spacing: Alone,
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:9: 18:10 (#0),
     },
     Group {
         delimiter: Brace,
@@ -352,54 +352,54 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                 kind: Integer,
                 symbol: "1",
                 suffix: None,
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:18:11: 18:12 (#0),
             },
             Punct {
                 ch: '>',
                 spacing: Alone,
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:18:13: 18:14 (#0),
             },
             Literal {
                 kind: Integer,
                 symbol: "0",
                 suffix: None,
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:18:15: 18:16 (#0),
             },
         ],
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:10: 18:17 (#0),
     },
     Punct {
         ch: '>',
         spacing: Alone,
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:17: 18:18 (#0),
     },
     Ident {
         ident: "for",
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:19: 18:22 (#0),
     },
     Ident {
         ident: "Foo",
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:23: 18:26 (#0),
     },
     Punct {
         ch: '<',
         spacing: Alone,
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:26: 18:27 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [
             Ident {
                 ident: "true",
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:18:28: 18:32 (#0),
             },
         ],
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:27: 18:33 (#0),
     },
     Punct {
         ch: '>',
         spacing: Alone,
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:33: 18:34 (#0),
     },
     Group {
         delimiter: Brace,
@@ -407,58 +407,58 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:20:5: 20:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:20:6: 20:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                        span: $DIR/weird-braces.rs:20:8: 20:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "second_inner",
-                                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                                span: $DIR/weird-braces.rs:20:30: 20:42 (#0),
                             },
                         ],
-                        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                        span: $DIR/weird-braces.rs:20:29: 20:43 (#0),
                     },
                 ],
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:20:7: 20:44 (#0),
             },
         ],
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:35: 21:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): second_inner
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "second_inner",
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:20:30: 20:42 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): impl Bar < { 1 > 0 } > for Foo < { true } > { }
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "impl",
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:1: 18:5 (#0),
     },
     Ident {
         ident: "Bar",
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:6: 18:9 (#0),
     },
     Punct {
         ch: '<',
         spacing: Alone,
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:9: 18:10 (#0),
     },
     Group {
         delimiter: Brace,
@@ -467,58 +467,58 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                 kind: Integer,
                 symbol: "1",
                 suffix: None,
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:18:11: 18:12 (#0),
             },
             Punct {
                 ch: '>',
                 spacing: Alone,
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:18:13: 18:14 (#0),
             },
             Literal {
                 kind: Integer,
                 symbol: "0",
                 suffix: None,
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:18:15: 18:16 (#0),
             },
         ],
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:10: 18:17 (#0),
     },
     Punct {
         ch: '>',
         spacing: Alone,
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:17: 18:18 (#0),
     },
     Ident {
         ident: "for",
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:19: 18:22 (#0),
     },
     Ident {
         ident: "Foo",
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:23: 18:26 (#0),
     },
     Punct {
         ch: '<',
         spacing: Alone,
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:26: 18:27 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [
             Ident {
                 ident: "true",
-                span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+                span: $DIR/weird-braces.rs:18:28: 18:32 (#0),
             },
         ],
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:27: 18:33 (#0),
     },
     Punct {
         ch: '>',
         spacing: Alone,
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:33: 18:34 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [],
-        span: $DIR/weird-braces.rs:18:1: 21:2 (#0),
+        span: $DIR/weird-braces.rs:18:35: 21:2 (#0),
     },
 ]
diff --git a/src/test/ui/resolve/issue-81508.rs b/src/test/ui/resolve/issue-81508.rs
new file mode 100644
index 00000000000..23605cd2fd9
--- /dev/null
+++ b/src/test/ui/resolve/issue-81508.rs
@@ -0,0 +1,22 @@
+// Confusing diagnostic when using variable as a type:
+//
+// Previous warnings indicate Foo is not used, when in fact it is
+// used improperly as a variable or constant. New warning points
+// out user may be trying to use variable as a type. Test demonstrates
+// cases for both local variable and const.
+
+fn main() {
+    let Baz: &str = "";
+
+    println!("{}", Baz::Bar); //~ ERROR: failed to resolve: use of undeclared type `Baz`
+}
+
+#[allow(non_upper_case_globals)]
+pub const Foo: &str = "";
+
+mod submod {
+    use super::Foo;
+    fn function() {
+        println!("{}", Foo::Bar); //~ ERROR: failed to resolve: use of undeclared type `Foo`
+    }
+}
diff --git a/src/test/ui/resolve/issue-81508.stderr b/src/test/ui/resolve/issue-81508.stderr
new file mode 100644
index 00000000000..15555631b90
--- /dev/null
+++ b/src/test/ui/resolve/issue-81508.stderr
@@ -0,0 +1,21 @@
+error[E0433]: failed to resolve: use of undeclared type `Baz`
+  --> $DIR/issue-81508.rs:11:20
+   |
+LL |     let Baz: &str = "";
+   |         --- help: `Baz` is defined here, but is not a type
+LL | 
+LL |     println!("{}", Baz::Bar);
+   |                    ^^^ use of undeclared type `Baz`
+
+error[E0433]: failed to resolve: use of undeclared type `Foo`
+  --> $DIR/issue-81508.rs:20:24
+   |
+LL |     use super::Foo;
+   |         ---------- help: `Foo` is defined here, but is not a type
+LL |     fn function() {
+LL |         println!("{}", Foo::Bar);
+   |                        ^^^ use of undeclared type `Foo`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/sanitize/hwaddress.rs b/src/test/ui/sanitize/hwaddress.rs
index ad5d0245457..88769b7cb45 100644
--- a/src/test/ui/sanitize/hwaddress.rs
+++ b/src/test/ui/sanitize/hwaddress.rs
@@ -1,7 +1,8 @@
 // needs-sanitizer-support
 // needs-sanitizer-hwaddress
 //
-// compile-flags: -Z sanitizer=hwaddress -O -g
+// FIXME(#83989): codegen-units=1 triggers linker errors on aarch64-gnu
+// compile-flags: -Z sanitizer=hwaddress -O -g -C codegen-units=16
 //
 // run-fail
 // error-pattern: HWAddressSanitizer: tag-mismatch
diff --git a/src/test/ui/suggestions/issue-83892.fixed b/src/test/ui/suggestions/issue-83892.fixed
new file mode 100644
index 00000000000..dd093a7a0e3
--- /dev/null
+++ b/src/test/ui/suggestions/issue-83892.fixed
@@ -0,0 +1,11 @@
+// run-rustfix
+
+fn func() -> u8 {
+    0
+}
+
+fn main() {
+    match () {
+        () => func() //~ ERROR mismatched types
+    };
+}
diff --git a/src/test/ui/suggestions/issue-83892.rs b/src/test/ui/suggestions/issue-83892.rs
new file mode 100644
index 00000000000..1d56ecee868
--- /dev/null
+++ b/src/test/ui/suggestions/issue-83892.rs
@@ -0,0 +1,11 @@
+// run-rustfix
+
+fn func() -> u8 {
+    0
+}
+
+fn main() {
+    match () {
+        () => func() //~ ERROR mismatched types
+    }
+}
diff --git a/src/test/ui/suggestions/issue-83892.stderr b/src/test/ui/suggestions/issue-83892.stderr
new file mode 100644
index 00000000000..baf6b1447e6
--- /dev/null
+++ b/src/test/ui/suggestions/issue-83892.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-83892.rs:9:15
+   |
+LL | fn main() {
+   |           - expected `()` because of default return type
+LL |     match () {
+LL |         () => func()
+   |               ^^^^^^ expected `()`, found `u8`
+LL |     }
+   |      - help: consider using a semicolon here: `;`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/traits/associated_type_bound/issue-51446.rs b/src/test/ui/traits/associated_type_bound/issue-51446.rs
new file mode 100644
index 00000000000..7dd95de73ba
--- /dev/null
+++ b/src/test/ui/traits/associated_type_bound/issue-51446.rs
@@ -0,0 +1,34 @@
+// Regression test for #51446.
+// check-pass
+
+trait Foo {
+    type Item;
+    fn get(&self) -> Self::Item;
+}
+
+fn blah<T, F>(x: T, f: F) -> B<T::Item, impl Fn(T::Item)>
+where
+    T: Foo,
+    F: Fn(T::Item),
+{
+    B { x: x.get(), f }
+}
+
+pub struct B<T, F>
+where
+    F: Fn(T),
+{
+    pub x: T,
+    pub f: F,
+}
+
+impl Foo for i32 {
+    type Item = i32;
+    fn get(&self) -> i32 {
+        *self
+    }
+}
+
+fn main() {
+    let _ = blah(0, |_| ());
+}
diff --git a/src/test/ui/union/union-derive.stderr b/src/test/ui/union/union-derive.stderr
index 919c6d5ceda..6ef72c901a5 100644
--- a/src/test/ui/union/union-derive.stderr
+++ b/src/test/ui/union/union-derive.stderr
@@ -1,20 +1,14 @@
 error: this trait cannot be derived for unions
-  --> $DIR/union-derive.rs:9:5
-   |
-LL |     Debug,
-   |     ^^^^^
-
-error: this trait cannot be derived for unions
-  --> $DIR/union-derive.rs:8:5
+  --> $DIR/union-derive.rs:4:5
    |
-LL |     Default,
-   |     ^^^^^^^
+LL |     PartialEq,
+   |     ^^^^^^^^^
 
 error: this trait cannot be derived for unions
-  --> $DIR/union-derive.rs:7:5
+  --> $DIR/union-derive.rs:5:5
    |
-LL |     Hash,
-   |     ^^^^
+LL |     PartialOrd,
+   |     ^^^^^^^^^^
 
 error: this trait cannot be derived for unions
   --> $DIR/union-derive.rs:6:5
@@ -23,16 +17,22 @@ LL |     Ord,
    |     ^^^
 
 error: this trait cannot be derived for unions
-  --> $DIR/union-derive.rs:5:5
+  --> $DIR/union-derive.rs:7:5
    |
-LL |     PartialOrd,
-   |     ^^^^^^^^^^
+LL |     Hash,
+   |     ^^^^
 
 error: this trait cannot be derived for unions
-  --> $DIR/union-derive.rs:4:5
+  --> $DIR/union-derive.rs:8:5
    |
-LL |     PartialEq,
-   |     ^^^^^^^^^
+LL |     Default,
+   |     ^^^^^^^
+
+error: this trait cannot be derived for unions
+  --> $DIR/union-derive.rs:9:5
+   |
+LL |     Debug,
+   |     ^^^^^
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/unwind-no-uwtable.rs b/src/test/ui/unwind-no-uwtable.rs
new file mode 100644
index 00000000000..f249d3f4574
--- /dev/null
+++ b/src/test/ui/unwind-no-uwtable.rs
@@ -0,0 +1,34 @@
+// run-pass
+// ignore-windows target requires uwtable
+// ignore-wasm32-bare no proper panic=unwind support
+// compile-flags: -C panic=unwind -C force-unwind-tables=n
+
+use std::panic::{self, AssertUnwindSafe};
+
+struct Increase<'a>(&'a mut u8);
+
+impl Drop for Increase<'_> {
+    fn drop(&mut self) {
+        *self.0 += 1;
+    }
+}
+
+#[inline(never)]
+fn unwind() {
+    panic!();
+}
+
+#[inline(never)]
+fn increase(count: &mut u8) {
+    let _increase = Increase(count);
+    unwind();
+}
+
+fn main() {
+    let mut count = 0;
+    assert!(panic::catch_unwind(AssertUnwindSafe(
+        #[inline(never)]
+        || increase(&mut count)
+    )).is_err());
+    assert_eq!(count, 1);
+}
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index f7916511edf..73997192ae0 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,11 +6,146 @@ document.
 
 ## Unreleased / In Rust Nightly
 
-[3e41797...master](https://github.com/rust-lang/rust-clippy/compare/3e41797...master)
+[6ed6f1e...master](https://github.com/rust-lang/rust-clippy/compare/6ed6f1e...master)
+
+## Rust 1.52
+
+Current beta, release 2021-05-06
+
+[3e41797...6ed6f1e](https://github.com/rust-lang/rust-clippy/compare/3e41797...6ed6f1e)
+
+### New Lints
+
+* [`from_str_radix_10`]
+  [#6717](https://github.com/rust-lang/rust-clippy/pull/6717)
+* [`implicit_clone`]
+  [#6730](https://github.com/rust-lang/rust-clippy/pull/6730)
+* [`semicolon_if_nothing_returned`]
+  [#6681](https://github.com/rust-lang/rust-clippy/pull/6681)
+* [`manual_flatten`]
+  [#6646](https://github.com/rust-lang/rust-clippy/pull/6646)
+* [`inconsistent_struct_constructor`]
+  [#6769](https://github.com/rust-lang/rust-clippy/pull/6769)
+* [`iter_count`]
+  [#6791](https://github.com/rust-lang/rust-clippy/pull/6791)
+* [`default_numeric_fallback`]
+  [#6662](https://github.com/rust-lang/rust-clippy/pull/6662)
+* [`bytes_nth`]
+  [#6695](https://github.com/rust-lang/rust-clippy/pull/6695)
+* [`filter_map_identity`]
+  [#6685](https://github.com/rust-lang/rust-clippy/pull/6685)
+* [`manual_map`]
+  [#6573](https://github.com/rust-lang/rust-clippy/pull/6573)
+
+### Moves and Deprecations
+
+* Moved [`upper_case_acronyms`] to `pedantic`
+  [#6775](https://github.com/rust-lang/rust-clippy/pull/6775)
+* Moved [`manual_map`] to `nursery`
+  [#6796](https://github.com/rust-lang/rust-clippy/pull/6796)
+* Moved [`unnecessary_wraps`] to `pedantic`
+  [#6765](https://github.com/rust-lang/rust-clippy/pull/6765)
+* Moved [`trivial_regex`] to `nursery`
+  [#6696](https://github.com/rust-lang/rust-clippy/pull/6696)
+* Moved [`naive_bytecount`] to `pedantic`
+  [#6825](https://github.com/rust-lang/rust-clippy/pull/6825)
+* Moved [`upper_case_acronyms`] to `style`
+  [#6788](https://github.com/rust-lang/rust-clippy/pull/6788)
+* Moved [`manual_map`] to `style`
+  [#6801](https://github.com/rust-lang/rust-clippy/pull/6801)
+
+### Enhancements
+
+* [`disallowed_method`]: Now supports functions in addition to methods
+  [#6674](https://github.com/rust-lang/rust-clippy/pull/6674)
+* [`upper_case_acronyms`]: Added a new configuration `upper-case-acronyms-aggressive` to
+  trigger the lint if there is more than one uppercase character next to each other
+  [#6788](https://github.com/rust-lang/rust-clippy/pull/6788)
+* [`collapsible_match`]: Now supports block comparison with different value names
+  [#6754](https://github.com/rust-lang/rust-clippy/pull/6754)
+* [`unnecessary_wraps`]: Will now suggest removing unnecessary wrapped return unit type, like `Option<()>`
+  [#6665](https://github.com/rust-lang/rust-clippy/pull/6665)
+* Improved value usage detection in closures
+  [#6698](https://github.com/rust-lang/rust-clippy/pull/6698)
+
+### False Positive Fixes
+
+* [`use_self`]: No longer lints in macros
+  [#6833](https://github.com/rust-lang/rust-clippy/pull/6833)
+* [`use_self`]: Fixed multiple false positives for: generics, associated types and derive implementations
+  [#6179](https://github.com/rust-lang/rust-clippy/pull/6179)
+* [`missing_inline_in_public_items`]: No longer lints for procedural macros
+  [#6814](https://github.com/rust-lang/rust-clippy/pull/6814)
+* [`inherent_to_string`]: No longer lints on functions with function generics
+  [#6771](https://github.com/rust-lang/rust-clippy/pull/6771)
+* [`doc_markdown`]: Add `OpenDNS` to the default configuration as an allowed identifier
+  [#6783](https://github.com/rust-lang/rust-clippy/pull/6783)
+* [`missing_panics_doc`]: No longer lints on [`unreachable!`](https://doc.rust-lang.org/std/macro.unreachable.html)
+  [#6700](https://github.com/rust-lang/rust-clippy/pull/6700)
+* [`collapsible_if`]: No longer lints on if statements with attributes
+  [#6701](https://github.com/rust-lang/rust-clippy/pull/6701)
+* [`match_same_arms`]: Only considers empty blocks as equal if the tokens contained are the same
+  [#6843](https://github.com/rust-lang/rust-clippy/pull/6843)
+* [`redundant_closure`]: Now ignores macros
+  [#6871](https://github.com/rust-lang/rust-clippy/pull/6871)
+* [`manual_map`]: Fixed false positives when control flow statements like `return`, `break` etc. are used
+  [#6801](https://github.com/rust-lang/rust-clippy/pull/6801)
+* [`vec_init_then_push`]: Fixed false positives for loops and if statements
+  [#6697](https://github.com/rust-lang/rust-clippy/pull/6697)
+* [`len_without_is_empty`]: Will now consider multiple impl blocks and `#[allow]` on
+  the `len` method as well as the type definition.
+  [#6853](https://github.com/rust-lang/rust-clippy/pull/6853)
+* [`let_underscore_drop`]: Only lints on types which implement `Drop`
+  [#6682](https://github.com/rust-lang/rust-clippy/pull/6682)
+* [`unit_arg`]: No longer lints on unit arguments when they come from a path expression.
+  [#6601](https://github.com/rust-lang/rust-clippy/pull/6601)
+* [`cargo_common_metadata`]: No longer lints if 
+  [`publish = false`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field)
+  is defined in the manifest
+  [#6650](https://github.com/rust-lang/rust-clippy/pull/6650)
+
+### Suggestion Fixes/Improvements
+
+* [`collapsible_match`]: Fixed lint message capitalization
+  [#6766](https://github.com/rust-lang/rust-clippy/pull/6766)
+* [`or_fun_call`]: Improved suggestions for `or_insert(vec![])`
+  [#6790](https://github.com/rust-lang/rust-clippy/pull/6790)
+* [`manual_map`]: No longer expands macros in the suggestions
+  [#6801](https://github.com/rust-lang/rust-clippy/pull/6801)
+* Aligned Clippy's lint messages with the rustc dev guide
+  [#6787](https://github.com/rust-lang/rust-clippy/pull/6787)
+
+### ICE Fixes
+
+* [`zero_sized_map_values`]
+  [#6866](https://github.com/rust-lang/rust-clippy/pull/6866)
+
+### Documentation Improvements
+
+* [`useless_format`]: Improved the documentation example
+  [#6854](https://github.com/rust-lang/rust-clippy/pull/6854)
+* Clippy's [`README.md`]: Includes a new subsection on running Clippy as a rustc wrapper 
+  [#6782](https://github.com/rust-lang/rust-clippy/pull/6782)
+
+### Others
+* Running `cargo clippy` after `cargo check` now works as expected 
+  (`cargo clippy` and `cargo check` no longer shares the same build cache)
+  [#6687](https://github.com/rust-lang/rust-clippy/pull/6687)
+* Cargo now re-runs Clippy if arguments after `--` provided to `cargo clippy` are changed.
+  [#6834](https://github.com/rust-lang/rust-clippy/pull/6834)
+* Extracted Clippy's `utils` module into the new `clippy_utils` crate
+  [#6756](https://github.com/rust-lang/rust-clippy/pull/6756)
+* Clippy lintcheck tool improvements
+  [#6800](https://github.com/rust-lang/rust-clippy/pull/6800)
+  [#6735](https://github.com/rust-lang/rust-clippy/pull/6735)
+  [#6764](https://github.com/rust-lang/rust-clippy/pull/6764)
+  [#6708](https://github.com/rust-lang/rust-clippy/pull/6708)
+  [#6780](https://github.com/rust-lang/rust-clippy/pull/6780)
+  [#6686](https://github.com/rust-lang/rust-clippy/pull/6686)
 
 ## Rust 1.51
 
-Current beta, release 2021-03-25
+Current stable, released 2021-03-25
 
 [4911ab1...3e41797](https://github.com/rust-lang/rust-clippy/compare/4911ab1...3e41797)
 
@@ -125,7 +260,7 @@ Current beta, release 2021-03-25
 
 ## Rust 1.50
 
-Current stable, released 2021-02-11
+Released 2021-02-11
 
 [b20d4c1...4bd77a1](https://github.com/rust-lang/rust-clippy/compare/b20d4c1...4bd77a1)
 
@@ -1970,6 +2105,7 @@ Released 2018-09-13
 [configuration file]: ./rust-clippy#configuration
 [pull3665]: https://github.com/rust-lang/rust-clippy/pull/3665
 [adding_lints]: https://github.com/rust-lang/rust-clippy/blob/master/doc/adding_lints.md
+[`README.md`]: https://github.com/rust-lang/rust-clippy/blob/master/README.md
 
 <!-- lint disable no-unused-definitions -->
 <!-- begin autogenerated links to lint list -->
@@ -1993,6 +2129,7 @@ Released 2018-09-13
 [`borrowed_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrowed_box
 [`box_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_vec
 [`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
+[`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code
 [`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow
 [`bytes_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_nth
 [`cargo_common_metadata`]: https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata
@@ -2233,6 +2370,7 @@ Released 2018-09-13
 [`needless_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_collect
 [`needless_continue`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_continue
 [`needless_doctest_main`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_doctest_main
+[`needless_for_each`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_for_each
 [`needless_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
 [`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value
 [`needless_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark
@@ -2246,6 +2384,7 @@ Released 2018-09-13
 [`new_without_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default
 [`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect
 [`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
+[`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions
 [`nonminimal_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool
 [`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options
 [`not_unsafe_ptr_arg_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#not_unsafe_ptr_arg_deref
@@ -2253,6 +2392,7 @@ Released 2018-09-13
 [`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref
 [`option_as_ref_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref
 [`option_env_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_env_unwrap
+[`option_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_filter_map
 [`option_if_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else
 [`option_map_or_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_none
 [`option_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unit_fn
diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md
index 63057609bb6..8c0c16c443d 100644
--- a/src/tools/clippy/README.md
+++ b/src/tools/clippy/README.md
@@ -5,7 +5,7 @@
 
 A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
 
-[There are over 400 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
+[There are over 450 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
 
 Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html).
 You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category.
diff --git a/src/tools/clippy/clippy_dev/src/fmt.rs b/src/tools/clippy/clippy_dev/src/fmt.rs
index 111c79c332d..1517cdc9419 100644
--- a/src/tools/clippy/clippy_dev/src/fmt.rs
+++ b/src/tools/clippy/clippy_dev/src/fmt.rs
@@ -68,7 +68,7 @@ pub fn run(check: bool, verbose: bool) {
                 continue;
             }
 
-            success &= rustfmt(context, &path)?;
+            success &= rustfmt(context, path)?;
         }
 
         Ok(success)
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index a5e94683878..1e5a140e964 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -101,7 +101,7 @@ impl Lint {
 #[must_use]
 pub fn gen_lint_group_list<'a>(lints: impl Iterator<Item = &'a Lint>) -> Vec<String> {
     lints
-        .map(|l| format!("        LintId::of(&{}::{}),", l.module, l.name.to_uppercase()))
+        .map(|l| format!("        LintId::of({}::{}),", l.module, l.name.to_uppercase()))
         .sorted()
         .collect::<Vec<String>>()
 }
@@ -154,17 +154,17 @@ pub fn gen_register_lint_list<'a>(
     let header = "    store.register_lints(&[".to_string();
     let footer = "    ]);".to_string();
     let internal_lints = internal_lints
-        .sorted_by_key(|l| format!("        &{}::{},", l.module, l.name.to_uppercase()))
+        .sorted_by_key(|l| format!("        {}::{},", l.module, l.name.to_uppercase()))
         .map(|l| {
             format!(
-                "        #[cfg(feature = \"internal-lints\")]\n        &{}::{},",
+                "        #[cfg(feature = \"internal-lints\")]\n        {}::{},",
                 l.module,
                 l.name.to_uppercase()
             )
         });
     let other_lints = usable_lints
-        .sorted_by_key(|l| format!("        &{}::{},", l.module, l.name.to_uppercase()))
-        .map(|l| format!("        &{}::{},", l.module, l.name.to_uppercase()))
+        .sorted_by_key(|l| format!("        {}::{},", l.module, l.name.to_uppercase()))
+        .map(|l| format!("        {}::{},", l.module, l.name.to_uppercase()))
         .sorted();
     let mut lint_list = vec![header];
     lint_list.extend(internal_lints);
@@ -550,9 +550,9 @@ fn test_gen_lint_group_list() {
         Lint::new("internal", "internal_style", "abc", None, "module_name"),
     ];
     let expected = vec![
-        "        LintId::of(&module_name::ABC),".to_string(),
-        "        LintId::of(&module_name::INTERNAL),".to_string(),
-        "        LintId::of(&module_name::SHOULD_ASSERT_EQ),".to_string(),
+        "        LintId::of(module_name::ABC),".to_string(),
+        "        LintId::of(module_name::INTERNAL),".to_string(),
+        "        LintId::of(module_name::SHOULD_ASSERT_EQ),".to_string(),
     ];
     assert_eq!(expected, gen_lint_group_list(lints.iter()));
 }
diff --git a/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs b/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs
new file mode 100644
index 00000000000..5fbf4bdbd18
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs
@@ -0,0 +1,173 @@
+use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+use crate::consts::{constant, Constant};
+
+use clippy_utils::comparisons::{normalize_comparison, Rel};
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::source::snippet;
+use clippy_utils::ty::is_isize_or_usize;
+use clippy_utils::{clip, int_bits, unsext};
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for comparisons where one side of the relation is
+    /// either the minimum or maximum value for its type and warns if it involves a
+    /// case that is always true or always false. Only integer and boolean types are
+    /// checked.
+    ///
+    /// **Why is this bad?** An expression like `min <= x` may misleadingly imply
+    /// that it is possible for `x` to be less than the minimum. Expressions like
+    /// `max < x` are probably mistakes.
+    ///
+    /// **Known problems:** For `usize` the size of the current compile target will
+    /// be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such
+    /// a comparison to detect target pointer width will trigger this lint. One can
+    /// use `mem::sizeof` and compare its value or conditional compilation
+    /// attributes
+    /// like `#[cfg(target_pointer_width = "64")] ..` instead.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let vec: Vec<isize> = Vec::new();
+    /// if vec.len() <= 0 {}
+    /// if 100 > i32::MAX {}
+    /// ```
+    pub ABSURD_EXTREME_COMPARISONS,
+    correctness,
+    "a comparison with a maximum or minimum value that is always true or false"
+}
+
+declare_lint_pass!(AbsurdExtremeComparisons => [ABSURD_EXTREME_COMPARISONS]);
+
+impl<'tcx> LateLintPass<'tcx> for AbsurdExtremeComparisons {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if let ExprKind::Binary(ref cmp, lhs, rhs) = expr.kind {
+            if let Some((culprit, result)) = detect_absurd_comparison(cx, cmp.node, lhs, rhs) {
+                if !expr.span.from_expansion() {
+                    let msg = "this comparison involving the minimum or maximum element for this \
+                               type contains a case that is always true or always false";
+
+                    let conclusion = match result {
+                        AbsurdComparisonResult::AlwaysFalse => "this comparison is always false".to_owned(),
+                        AbsurdComparisonResult::AlwaysTrue => "this comparison is always true".to_owned(),
+                        AbsurdComparisonResult::InequalityImpossible => format!(
+                            "the case where the two sides are not equal never occurs, consider using `{} == {}` \
+                             instead",
+                            snippet(cx, lhs.span, "lhs"),
+                            snippet(cx, rhs.span, "rhs")
+                        ),
+                    };
+
+                    let help = format!(
+                        "because `{}` is the {} value for this type, {}",
+                        snippet(cx, culprit.expr.span, "x"),
+                        match culprit.which {
+                            ExtremeType::Minimum => "minimum",
+                            ExtremeType::Maximum => "maximum",
+                        },
+                        conclusion
+                    );
+
+                    span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, &help);
+                }
+            }
+        }
+    }
+}
+
+enum ExtremeType {
+    Minimum,
+    Maximum,
+}
+
+struct ExtremeExpr<'a> {
+    which: ExtremeType,
+    expr: &'a Expr<'a>,
+}
+
+enum AbsurdComparisonResult {
+    AlwaysFalse,
+    AlwaysTrue,
+    InequalityImpossible,
+}
+
+fn is_cast_between_fixed_and_target<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
+    if let ExprKind::Cast(cast_exp, _) = expr.kind {
+        let precast_ty = cx.typeck_results().expr_ty(cast_exp);
+        let cast_ty = cx.typeck_results().expr_ty(expr);
+
+        return is_isize_or_usize(precast_ty) != is_isize_or_usize(cast_ty);
+    }
+
+    false
+}
+
+fn detect_absurd_comparison<'tcx>(
+    cx: &LateContext<'tcx>,
+    op: BinOpKind,
+    lhs: &'tcx Expr<'_>,
+    rhs: &'tcx Expr<'_>,
+) -> Option<(ExtremeExpr<'tcx>, AbsurdComparisonResult)> {
+    use AbsurdComparisonResult::{AlwaysFalse, AlwaysTrue, InequalityImpossible};
+    use ExtremeType::{Maximum, Minimum};
+    // absurd comparison only makes sense on primitive types
+    // primitive types don't implement comparison operators with each other
+    if cx.typeck_results().expr_ty(lhs) != cx.typeck_results().expr_ty(rhs) {
+        return None;
+    }
+
+    // comparisons between fix sized types and target sized types are considered unanalyzable
+    if is_cast_between_fixed_and_target(cx, lhs) || is_cast_between_fixed_and_target(cx, rhs) {
+        return None;
+    }
+
+    let (rel, normalized_lhs, normalized_rhs) = normalize_comparison(op, lhs, rhs)?;
+
+    let lx = detect_extreme_expr(cx, normalized_lhs);
+    let rx = detect_extreme_expr(cx, normalized_rhs);
+
+    Some(match rel {
+        Rel::Lt => {
+            match (lx, rx) {
+                (Some(l @ ExtremeExpr { which: Maximum, .. }), _) => (l, AlwaysFalse), // max < x
+                (_, Some(r @ ExtremeExpr { which: Minimum, .. })) => (r, AlwaysFalse), // x < min
+                _ => return None,
+            }
+        },
+        Rel::Le => {
+            match (lx, rx) {
+                (Some(l @ ExtremeExpr { which: Minimum, .. }), _) => (l, AlwaysTrue), // min <= x
+                (Some(l @ ExtremeExpr { which: Maximum, .. }), _) => (l, InequalityImpossible), // max <= x
+                (_, Some(r @ ExtremeExpr { which: Minimum, .. })) => (r, InequalityImpossible), // x <= min
+                (_, Some(r @ ExtremeExpr { which: Maximum, .. })) => (r, AlwaysTrue), // x <= max
+                _ => return None,
+            }
+        },
+        Rel::Ne | Rel::Eq => return None,
+    })
+}
+
+fn detect_extreme_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<ExtremeExpr<'tcx>> {
+    let ty = cx.typeck_results().expr_ty(expr);
+
+    let cv = constant(cx, cx.typeck_results(), expr)?.0;
+
+    let which = match (ty.kind(), cv) {
+        (&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => ExtremeType::Minimum,
+        (&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MIN >> (128 - int_bits(cx.tcx, ity)), ity) => {
+            ExtremeType::Minimum
+        },
+
+        (&ty::Bool, Constant::Bool(true)) => ExtremeType::Maximum,
+        (&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MAX >> (128 - int_bits(cx.tcx, ity)), ity) => {
+            ExtremeType::Maximum
+        },
+        (&ty::Uint(uty), Constant::Int(i)) if clip(cx.tcx, u128::MAX, uty) == i => ExtremeType::Maximum,
+
+        _ => return None,
+    };
+    Some(ExtremeExpr { which, expr })
+}
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
index 16905781c56..a0993bb6913 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
@@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
                 return;
             }
             if_chain! {
-                if let ExprKind::Unary(_, ref lit) = e.kind;
+                if let ExprKind::Unary(_, lit) = e.kind;
                 if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), lit);
                 if is_true;
                 then {
@@ -82,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
             if assert_span.from_expansion() {
                 return;
             }
-            if let Some(assert_match) = match_assert_with_message(&cx, e) {
+            if let Some(assert_match) = match_assert_with_message(cx, e) {
                 match assert_match {
                     // matched assert but not message
                     AssertKind::WithoutMessage(false) => lint_false_without_message(),
@@ -113,17 +113,17 @@ enum AssertKind {
 /// where `message` is any expression and `c` is a constant bool.
 fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<AssertKind> {
     if_chain! {
-        if let ExprKind::If(ref cond, ref then, _) = expr.kind;
-        if let ExprKind::Unary(UnOp::Not, ref expr) = cond.kind;
+        if let ExprKind::If(cond, then, _) = expr.kind;
+        if let ExprKind::Unary(UnOp::Not, expr) = cond.kind;
         // bind the first argument of the `assert!` macro
         if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), expr);
         // block
-        if let ExprKind::Block(ref block, _) = then.kind;
+        if let ExprKind::Block(block, _) = then.kind;
         if block.stmts.is_empty();
         if let Some(block_expr) = &block.expr;
         // inner block is optional. unwrap it if it exists, or use the expression as is otherwise.
         if let Some(begin_panic_call) = match block_expr.kind {
-            ExprKind::Block(ref inner_block, _) => &inner_block.expr,
+            ExprKind::Block(inner_block, _) => &inner_block.expr,
             _ => &block.expr,
         };
         // function call
diff --git a/src/tools/clippy/clippy_lints/src/atomic_ordering.rs b/src/tools/clippy/clippy_lints/src/atomic_ordering.rs
index dfb18199325..7ceb01f5590 100644
--- a/src/tools/clippy/clippy_lints/src/atomic_ordering.rs
+++ b/src/tools/clippy/clippy_lints/src/atomic_ordering.rs
@@ -85,7 +85,7 @@ fn match_ordering_def_path(cx: &LateContext<'_>, did: DefId, orderings: &[&str])
 
 fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if_chain! {
-        if let ExprKind::MethodCall(ref method_path, _, args, _) = &expr.kind;
+        if let ExprKind::MethodCall(method_path, _, args, _) = &expr.kind;
         let method = method_path.ident.name.as_str();
         if type_is_atomic(cx, &args[0]);
         if method == "load" || method == "store";
@@ -120,7 +120,7 @@ fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) {
 
 fn check_memory_fence(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if_chain! {
-        if let ExprKind::Call(ref func, ref args) = expr.kind;
+        if let ExprKind::Call(func, args) = expr.kind;
         if let ExprKind::Path(ref func_qpath) = func.kind;
         if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
         if ["fence", "compiler_fence"]
@@ -152,7 +152,7 @@ fn opt_ordering_defid(cx: &LateContext<'_>, ord_arg: &Expr<'_>) -> Option<DefId>
 
 fn check_atomic_compare_exchange(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if_chain! {
-        if let ExprKind::MethodCall(ref method_path, _, args, _) = &expr.kind;
+        if let ExprKind::MethodCall(method_path, _, args, _) = &expr.kind;
         let method = method_path.ident.name.as_str();
         if type_is_atomic(cx, &args[0]);
         if method == "compare_exchange" || method == "compare_exchange_weak" || method == "fetch_update";
diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs
index 3cef8d2a78b..c5b01461c1c 100644
--- a/src/tools/clippy/clippy_lints/src/attrs.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs.rs
@@ -250,12 +250,8 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
     fn check_attribute(&mut self, cx: &LateContext<'tcx>, attr: &'tcx Attribute) {
         if let Some(items) = &attr.meta_item_list() {
             if let Some(ident) = attr.ident() {
-                let ident = &*ident.as_str();
-                match ident {
-                    "allow" | "warn" | "deny" | "forbid" => {
-                        check_clippy_lint_names(cx, ident, items);
-                    },
-                    _ => {},
+                if is_lint_level(ident.name) {
+                    check_clippy_lint_names(cx, ident.name, items);
                 }
                 if items.is_empty() || !attr.has_name(sym::deprecated) {
                     return;
@@ -288,60 +284,54 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
                         return;
                     }
                     if let Some(lint_list) = &attr.meta_item_list() {
-                        if let Some(ident) = attr.ident() {
-                            match &*ident.as_str() {
-                                "allow" | "warn" | "deny" | "forbid" => {
-                                    // permit `unused_imports`, `deprecated`, `unreachable_pub`,
-                                    // `clippy::wildcard_imports`, and `clippy::enum_glob_use` for `use` items
-                                    // and `unused_imports` for `extern crate` items with `macro_use`
-                                    for lint in lint_list {
-                                        match item.kind {
-                                            ItemKind::Use(..) => {
-                                                if is_word(lint, sym!(unused_imports))
-                                                    || is_word(lint, sym::deprecated)
-                                                    || is_word(lint, sym!(unreachable_pub))
-                                                    || is_word(lint, sym!(unused))
-                                                    || extract_clippy_lint(lint)
-                                                        .map_or(false, |s| s == "wildcard_imports")
-                                                    || extract_clippy_lint(lint).map_or(false, |s| s == "enum_glob_use")
-                                                {
-                                                    return;
-                                                }
-                                            },
-                                            ItemKind::ExternCrate(..) => {
-                                                if is_word(lint, sym!(unused_imports)) && skip_unused_imports {
-                                                    return;
-                                                }
-                                                if is_word(lint, sym!(unused_extern_crates)) {
-                                                    return;
-                                                }
-                                            },
-                                            _ => {},
+                        if attr.ident().map_or(false, |ident| is_lint_level(ident.name)) {
+                            // permit `unused_imports`, `deprecated`, `unreachable_pub`,
+                            // `clippy::wildcard_imports`, and `clippy::enum_glob_use` for `use` items
+                            // and `unused_imports` for `extern crate` items with `macro_use`
+                            for lint in lint_list {
+                                match item.kind {
+                                    ItemKind::Use(..) => {
+                                        if is_word(lint, sym!(unused_imports))
+                                            || is_word(lint, sym::deprecated)
+                                            || is_word(lint, sym!(unreachable_pub))
+                                            || is_word(lint, sym!(unused))
+                                            || extract_clippy_lint(lint).map_or(false, |s| s == "wildcard_imports")
+                                            || extract_clippy_lint(lint).map_or(false, |s| s == "enum_glob_use")
+                                        {
+                                            return;
+                                        }
+                                    },
+                                    ItemKind::ExternCrate(..) => {
+                                        if is_word(lint, sym!(unused_imports)) && skip_unused_imports {
+                                            return;
                                         }
-                                    }
-                                    let line_span = first_line_of_span(cx, attr.span);
-
-                                    if let Some(mut sugg) = snippet_opt(cx, line_span) {
-                                        if sugg.contains("#[") {
-                                            span_lint_and_then(
-                                                cx,
-                                                USELESS_ATTRIBUTE,
+                                        if is_word(lint, sym!(unused_extern_crates)) {
+                                            return;
+                                        }
+                                    },
+                                    _ => {},
+                                }
+                            }
+                            let line_span = first_line_of_span(cx, attr.span);
+
+                            if let Some(mut sugg) = snippet_opt(cx, line_span) {
+                                if sugg.contains("#[") {
+                                    span_lint_and_then(
+                                        cx,
+                                        USELESS_ATTRIBUTE,
+                                        line_span,
+                                        "useless lint attribute",
+                                        |diag| {
+                                            sugg = sugg.replacen("#[", "#![", 1);
+                                            diag.span_suggestion(
                                                 line_span,
-                                                "useless lint attribute",
-                                                |diag| {
-                                                    sugg = sugg.replacen("#[", "#![", 1);
-                                                    diag.span_suggestion(
-                                                        line_span,
-                                                        "if you just forgot a `!`, use",
-                                                        sugg,
-                                                        Applicability::MaybeIncorrect,
-                                                    );
-                                                },
+                                                "if you just forgot a `!`, use",
+                                                sugg,
+                                                Applicability::MaybeIncorrect,
                                             );
-                                        }
-                                    }
-                                },
-                                _ => {},
+                                        },
+                                    );
+                                }
                             }
                         }
                     }
@@ -371,18 +361,18 @@ fn extract_clippy_lint(lint: &NestedMetaItem) -> Option<SymbolStr> {
         if meta_item.path.segments.len() > 1;
         if let tool_name = meta_item.path.segments[0].ident;
         if tool_name.name == sym::clippy;
-        let lint_name = meta_item.path.segments.last().unwrap().ident.name;
         then {
+            let lint_name = meta_item.path.segments.last().unwrap().ident.name;
             return Some(lint_name.as_str());
         }
     }
     None
 }
 
-fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMetaItem]) {
+fn check_clippy_lint_names(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem]) {
     for lint in items {
         if let Some(lint_name) = extract_clippy_lint(lint) {
-            if lint_name == "restriction" && ident != "allow" {
+            if lint_name == "restriction" && name != sym::allow {
                 span_lint_and_help(
                     cx,
                     BLANKET_CLIPPY_RESTRICTION_LINTS,
@@ -602,7 +592,7 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) {
             if let NestedMetaItem::MetaItem(meta) = item {
                 match &meta.kind {
                     MetaItemKind::List(list) => {
-                        mismatched.extend(find_mismatched_target_os(&list));
+                        mismatched.extend(find_mismatched_target_os(list));
                     },
                     MetaItemKind::Word => {
                         if_chain! {
@@ -629,7 +619,7 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) {
         then {
             let mess = "operating system used in target family position";
 
-            span_lint_and_then(cx, MISMATCHED_TARGET_OS, attr.span, &mess, |diag| {
+            span_lint_and_then(cx, MISMATCHED_TARGET_OS, attr.span, mess, |diag| {
                 // Avoid showing the unix suggestion multiple times in case
                 // we have more than one mismatch for unix-like systems
                 let mut unix_suggested = false;
@@ -647,3 +637,7 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) {
         }
     }
 }
+
+fn is_lint_level(symbol: Symbol) -> bool {
+    matches!(symbol, sym::allow | sym::warn | sym::deny | sym::forbid)
+}
diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
index 68eee0520b3..1739a57a240 100644
--- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
+++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
@@ -101,7 +101,7 @@ impl LateLintPass<'_> for AwaitHolding {
             let typeck_results = cx.tcx.typeck_body(body_id);
             check_interior_types(
                 cx,
-                &typeck_results.generator_interior_types.as_ref().skip_binder(),
+                typeck_results.generator_interior_types.as_ref().skip_binder(),
                 body.value.span,
             );
         }
diff --git a/src/tools/clippy/clippy_lints/src/bytecount.rs b/src/tools/clippy/clippy_lints/src/bytecount.rs
index 846ac08e93a..877ae002d36 100644
--- a/src/tools/clippy/clippy_lints/src/bytecount.rs
+++ b/src/tools/clippy/clippy_lints/src/bytecount.rs
@@ -38,59 +38,55 @@ declare_lint_pass!(ByteCount => [NAIVE_BYTECOUNT]);
 impl<'tcx> LateLintPass<'tcx> for ByteCount {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         if_chain! {
-            if let ExprKind::MethodCall(ref count, _, ref count_args, _) = expr.kind;
+            if let ExprKind::MethodCall(count, _, count_args, _) = expr.kind;
             if count.ident.name == sym!(count);
             if count_args.len() == 1;
-            if let ExprKind::MethodCall(ref filter, _, ref filter_args, _) = count_args[0].kind;
+            if let ExprKind::MethodCall(filter, _, filter_args, _) = count_args[0].kind;
             if filter.ident.name == sym!(filter);
             if filter_args.len() == 2;
             if let ExprKind::Closure(_, _, body_id, _, _) = filter_args[1].kind;
+            let body = cx.tcx.hir().body(body_id);
+            if body.params.len() == 1;
+            if let Some(argname) = get_pat_name(body.params[0].pat);
+            if let ExprKind::Binary(ref op, l, r) = body.value.kind;
+            if op.node == BinOpKind::Eq;
+            if match_type(cx,
+                       cx.typeck_results().expr_ty(&filter_args[0]).peel_refs(),
+                       &paths::SLICE_ITER);
             then {
-                let body = cx.tcx.hir().body(body_id);
-                if_chain! {
-                    if body.params.len() == 1;
-                    if let Some(argname) = get_pat_name(&body.params[0].pat);
-                    if let ExprKind::Binary(ref op, ref l, ref r) = body.value.kind;
-                    if op.node == BinOpKind::Eq;
-                    if match_type(cx,
-                               cx.typeck_results().expr_ty(&filter_args[0]).peel_refs(),
-                               &paths::SLICE_ITER);
-                    then {
-                        let needle = match get_path_name(l) {
-                            Some(name) if check_arg(name, argname, r) => r,
-                            _ => match get_path_name(r) {
-                                Some(name) if check_arg(name, argname, l) => l,
-                                _ => { return; }
-                            }
-                        };
-                        if ty::Uint(UintTy::U8) != *cx.typeck_results().expr_ty(needle).peel_refs().kind() {
-                            return;
-                        }
-                        let haystack = if let ExprKind::MethodCall(ref path, _, ref args, _) =
-                                filter_args[0].kind {
-                            let p = path.ident.name;
-                            if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 {
-                                &args[0]
-                            } else {
-                                &filter_args[0]
-                            }
-                        } else {
-                            &filter_args[0]
-                        };
-                        let mut applicability = Applicability::MaybeIncorrect;
-                        span_lint_and_sugg(
-                            cx,
-                            NAIVE_BYTECOUNT,
-                            expr.span,
-                            "you appear to be counting bytes the naive way",
-                            "consider using the bytecount crate",
-                            format!("bytecount::count({}, {})",
-                                    snippet_with_applicability(cx, haystack.span, "..", &mut applicability),
-                                    snippet_with_applicability(cx, needle.span, "..", &mut applicability)),
-                            applicability,
-                        );
+                let needle = match get_path_name(l) {
+                    Some(name) if check_arg(name, argname, r) => r,
+                    _ => match get_path_name(r) {
+                        Some(name) if check_arg(name, argname, l) => l,
+                        _ => { return; }
                     }
                 };
+                if ty::Uint(UintTy::U8) != *cx.typeck_results().expr_ty(needle).peel_refs().kind() {
+                    return;
+                }
+                let haystack = if let ExprKind::MethodCall(path, _, args, _) =
+                        filter_args[0].kind {
+                    let p = path.ident.name;
+                    if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 {
+                        &args[0]
+                    } else {
+                        &filter_args[0]
+                    }
+                } else {
+                    &filter_args[0]
+                };
+                let mut applicability = Applicability::MaybeIncorrect;
+                span_lint_and_sugg(
+                    cx,
+                    NAIVE_BYTECOUNT,
+                    expr.span,
+                    "you appear to be counting bytes the naive way",
+                    "consider using the bytecount crate",
+                    format!("bytecount::count({}, {})",
+                            snippet_with_applicability(cx, haystack.span, "..", &mut applicability),
+                            snippet_with_applicability(cx, needle.span, "..", &mut applicability)),
+                    applicability,
+                );
             }
         };
     }
@@ -102,10 +98,10 @@ fn check_arg(name: Symbol, arg: Symbol, needle: &Expr<'_>) -> bool {
 
 fn get_path_name(expr: &Expr<'_>) -> Option<Symbol> {
     match expr.kind {
-        ExprKind::Box(ref e) | ExprKind::AddrOf(BorrowKind::Ref, _, ref e) | ExprKind::Unary(UnOp::Deref, ref e) => {
+        ExprKind::Box(e) | ExprKind::AddrOf(BorrowKind::Ref, _, e) | ExprKind::Unary(UnOp::Deref, e) => {
             get_path_name(e)
         },
-        ExprKind::Block(ref b, _) => {
+        ExprKind::Block(b, _) => {
             if b.stmts.is_empty() {
                 b.expr.as_ref().and_then(|p| get_path_name(p))
             } else {
diff --git a/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs b/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs
index fce5c559672..8097a1c8326 100644
--- a/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs
@@ -20,11 +20,10 @@ declare_clippy_lint! {
     ///
     /// **Example:**
     /// ```toml
-    /// # This `Cargo.toml` is missing an authors field:
+    /// # This `Cargo.toml` is missing a description field:
     /// [package]
     /// name = "clippy"
     /// version = "0.0.212"
-    /// description = "A bunch of helpful lints to avoid common pitfalls in Rust"
     /// repository = "https://github.com/rust-lang/rust-clippy"
     /// readme = "README.md"
     /// license = "MIT OR Apache-2.0"
@@ -32,14 +31,13 @@ declare_clippy_lint! {
     /// categories = ["development-tools", "development-tools::cargo-plugins"]
     /// ```
     ///
-    /// Should include an authors field like:
+    /// Should include a description field like:
     ///
     /// ```toml
     /// # This `Cargo.toml` includes all common metadata
     /// [package]
     /// name = "clippy"
     /// version = "0.0.212"
-    /// authors = ["Someone <someone@rust-lang.org>"]
     /// description = "A bunch of helpful lints to avoid common pitfalls in Rust"
     /// repository = "https://github.com/rust-lang/rust-clippy"
     /// readme = "README.md"
@@ -97,10 +95,6 @@ impl LateLintPass<'_> for CargoCommonMetadata {
             // only run the lint if publish is `None` (`publish = true` or skipped entirely)
             // or if the vector isn't empty (`publish = ["something"]`)
             if package.publish.as_ref().filter(|publish| publish.is_empty()).is_none() || self.ignore_publish {
-                if is_empty_vec(&package.authors) {
-                    missing_warning(cx, &package, "package.authors");
-                }
-
                 if is_empty_str(&package.description) {
                     missing_warning(cx, &package, "package.description");
                 }
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
index 5208156ffd2..62a119d662b 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
@@ -10,7 +10,7 @@ use rustc_target::abi::LayoutOf;
 use super::CAST_PTR_ALIGNMENT;
 
 pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-    if let ExprKind::Cast(ref cast_expr, cast_to) = expr.kind {
+    if let ExprKind::Cast(cast_expr, cast_to) = expr.kind {
         if is_hir_ty_cfg_dependant(cx, cast_to) {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
index bf722d0a3f4..040e0ca8864 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
@@ -30,7 +30,7 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast
             }
 
             // Don't lint for positive constants.
-            let const_val = constant(cx, &cx.typeck_results(), cast_op);
+            let const_val = constant(cx, cx.typeck_results(), cast_op);
             if_chain! {
                 if let Some((Constant::Int(n), _)) = const_val;
                 if let ty::Int(ity) = *cast_from.kind();
@@ -41,14 +41,14 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast
             }
 
             // Don't lint for the result of methods that always return non-negative values.
-            if let ExprKind::MethodCall(ref path, _, _, _) = cast_op.kind {
+            if let ExprKind::MethodCall(path, _, _, _) = cast_op.kind {
                 let mut method_name = path.ident.name.as_str();
                 let allowed_methods = ["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"];
 
                 if_chain! {
                     if method_name == "unwrap";
                     if let Some(arglist) = method_chain_args(cast_op, &["unwrap"]);
-                    if let ExprKind::MethodCall(ref inner_path, _, _, _) = &arglist[0][0].kind;
+                    if let ExprKind::MethodCall(inner_path, _, _, _) = &arglist[0][0].kind;
                     then {
                         method_name = inner_path.ident.name.as_str();
                     }
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index d9e172c01a7..ae4fdd12c41 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -372,7 +372,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
             return;
         }
 
-        if let ExprKind::Cast(ref cast_expr, cast_to) = expr.kind {
+        if let ExprKind::Cast(cast_expr, cast_to) = expr.kind {
             if is_hir_ty_cfg_dependant(cx, cast_to) {
                 return;
             }
diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
index ed46cac493a..d7136f84cc3 100644
--- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
@@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for CheckedConversions {
 
         let result = if_chain! {
             if !in_external_macro(cx.sess(), item.span);
-            if let ExprKind::Binary(op, ref left, ref right) = &item.kind;
+            if let ExprKind::Binary(op, left, right) = &item.kind;
 
             then {
                 match op.node {
@@ -200,7 +200,7 @@ impl ConversionType {
 /// Check for `expr <= (to_type::MAX as from_type)`
 fn check_upper_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
     if_chain! {
-         if let ExprKind::Binary(ref op, ref left, ref right) = &expr.kind;
+         if let ExprKind::Binary(ref op, left, right) = &expr.kind;
          if let Some((candidate, check)) = normalize_le_ge(op, left, right);
          if let Some((from, to)) = get_types_from_cast(check, INTS, "max_value", "MAX");
 
@@ -219,7 +219,7 @@ fn check_lower_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
     }
 
     // First of we need a binary containing the expression & the cast
-    if let ExprKind::Binary(ref op, ref left, ref right) = &expr.kind {
+    if let ExprKind::Binary(ref op, left, right) = &expr.kind {
         normalize_le_ge(op, right, left).and_then(|(l, r)| check_function(l, r))
     } else {
         None
@@ -260,7 +260,7 @@ fn get_types_from_cast<'a>(
     // or `to_type::MAX as from_type`
     let call_from_cast: Option<(&Expr<'_>, &str)> = if_chain! {
         // to_type::max_value(), from_type
-        if let ExprKind::Cast(ref limit, ref from_type) = &expr.kind;
+        if let ExprKind::Cast(limit, from_type) = &expr.kind;
         if let TyKind::Path(ref from_type_path) = &from_type.kind;
         if let Some(from_sym) = int_ty_to_sym(from_type_path);
 
@@ -275,7 +275,7 @@ fn get_types_from_cast<'a>(
     let limit_from: Option<(&Expr<'_>, &str)> = call_from_cast.or_else(|| {
         if_chain! {
             // `from_type::from, to_type::max_value()`
-            if let ExprKind::Call(ref from_func, ref args) = &expr.kind;
+            if let ExprKind::Call(from_func, args) = &expr.kind;
             // `to_type::max_value()`
             if args.len() == 1;
             if let limit = &args[0];
@@ -317,13 +317,12 @@ fn get_types_from_cast<'a>(
 /// Gets the type which implements the called function
 fn get_implementing_type<'a>(path: &QPath<'_>, candidates: &'a [&str], function: &str) -> Option<&'a str> {
     if_chain! {
-        if let QPath::TypeRelative(ref ty, ref path) = &path;
+        if let QPath::TypeRelative(ty, path) = &path;
         if path.ident.name.as_str() == function;
-        if let TyKind::Path(QPath::Resolved(None, ref tp)) = &ty.kind;
+        if let TyKind::Path(QPath::Resolved(None, tp)) = &ty.kind;
         if let [int] = &*tp.segments;
-        let name = &int.ident.name.as_str();
-
         then {
+            let name = &int.ident.name.as_str();
             candidates.iter().find(|c| name == *c).cloned()
         } else {
             None
@@ -334,11 +333,10 @@ fn get_implementing_type<'a>(path: &QPath<'_>, candidates: &'a [&str], function:
 /// Gets the type as a string, if it is a supported integer
 fn int_ty_to_sym<'tcx>(path: &QPath<'_>) -> Option<&'tcx str> {
     if_chain! {
-        if let QPath::Resolved(_, ref path) = *path;
+        if let QPath::Resolved(_, path) = *path;
         if let [ty] = &*path.segments;
-        let name = &ty.ident.name.as_str();
-
         then {
+            let name = &ty.ident.name.as_str();
             INTS.iter().find(|c| name == *c).cloned()
         } else {
             None
diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
index 4cc542f723c..f62c6a9c325 100644
--- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
@@ -152,7 +152,7 @@ impl<'tcx> Visitor<'tcx> for CcHelper {
             ExprKind::If(_, _, _) => {
                 self.cc += 1;
             },
-            ExprKind::Match(_, ref arms, _) => {
+            ExprKind::Match(_, arms, _) => {
                 if arms.len() > 1 {
                     self.cc += 1;
                 }
diff --git a/src/tools/clippy/clippy_lints/src/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/collapsible_match.rs
index e2b3686ddf0..04fff237bb4 100644
--- a/src/tools/clippy/clippy_lints/src/collapsible_match.rs
+++ b/src/tools/clippy/clippy_lints/src/collapsible_match.rs
@@ -62,8 +62,8 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleMatch {
 }
 
 fn check_arm<'tcx>(arm: &Arm<'tcx>, wild_outer_arm: &Arm<'tcx>, cx: &LateContext<'tcx>) {
+    let expr = strip_singleton_blocks(arm.body);
     if_chain! {
-        let expr = strip_singleton_blocks(arm.body);
         if let ExprKind::Match(expr_in, arms_inner, _) = expr.kind;
         // the outer arm pattern and the inner match
         if expr_in.span.ctxt() == arm.pat.span.ctxt();
diff --git a/src/tools/clippy/clippy_lints/src/comparison_chain.rs b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
index d601cb7c224..31ae63b5184 100644
--- a/src/tools/clippy/clippy_lints/src/comparison_chain.rs
+++ b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
@@ -71,10 +71,8 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain {
         }
 
         for cond in conds.windows(2) {
-            if let (
-                &ExprKind::Binary(ref kind1, ref lhs1, ref rhs1),
-                &ExprKind::Binary(ref kind2, ref lhs2, ref rhs2),
-            ) = (&cond[0].kind, &cond[1].kind)
+            if let (&ExprKind::Binary(ref kind1, lhs1, rhs1), &ExprKind::Binary(ref kind2, lhs2, rhs2)) =
+                (&cond[0].kind, &cond[1].kind)
             {
                 if !kind_is_cmp(kind1.node) || !kind_is_cmp(kind2.node) {
                     return;
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index 46093a16571..8b503c9a030 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -1,9 +1,19 @@
-use clippy_utils::diagnostics::span_lint_and_note;
-use clippy_utils::{eq_expr_value, in_macro, search_same, SpanlessEq, SpanlessHash};
-use clippy_utils::{get_parent_expr, if_sequence};
-use rustc_hir::{Block, Expr, ExprKind};
+use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then};
+use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, snippet_opt};
+use clippy_utils::{
+    both, count_eq, eq_expr_value, get_enclosing_block, get_parent_expr, if_sequence, in_macro, parent_node_is_if_expr,
+    run_lints, search_same, ContainsName, SpanlessEq, SpanlessHash,
+};
+use if_chain::if_chain;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::{Applicability, DiagnosticBuilder};
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::{Block, Expr, ExprKind, HirId};
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::map::Map;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{source_map::Span, symbol::Symbol, BytePos};
+use std::borrow::Cow;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for consecutive `if`s with the same condition.
@@ -104,47 +114,457 @@ declare_clippy_lint! {
     "`if` with the same `then` and `else` blocks"
 }
 
-declare_lint_pass!(CopyAndPaste => [IFS_SAME_COND, SAME_FUNCTIONS_IN_IF_CONDITION, IF_SAME_THEN_ELSE]);
+declare_clippy_lint! {
+    /// **What it does:** Checks if the `if` and `else` block contain shared code that can be
+    /// moved out of the blocks.
+    ///
+    /// **Why is this bad?** Duplicate code is less maintainable.
+    ///
+    /// **Known problems:** Hopefully none.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// let foo = if … {
+    ///     println!("Hello World");
+    ///     13
+    /// } else {
+    ///     println!("Hello World");
+    ///     42
+    /// };
+    /// ```
+    ///
+    /// Could be written as:
+    /// ```ignore
+    /// println!("Hello World");
+    /// let foo = if … {
+    ///     13
+    /// } else {
+    ///     42
+    /// };
+    /// ```
+    pub BRANCHES_SHARING_CODE,
+    complexity,
+    "`if` statement with shared code in all blocks"
+}
+
+declare_lint_pass!(CopyAndPaste => [
+    IFS_SAME_COND,
+    SAME_FUNCTIONS_IN_IF_CONDITION,
+    IF_SAME_THEN_ELSE,
+    BRANCHES_SHARING_CODE
+]);
 
 impl<'tcx> LateLintPass<'tcx> for CopyAndPaste {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if !expr.span.from_expansion() {
-            // skip ifs directly in else, it will be checked in the parent if
-            if let Some(&Expr {
-                kind: ExprKind::If(_, _, Some(ref else_expr)),
-                ..
-            }) = get_parent_expr(cx, expr)
-            {
-                if else_expr.hir_id == expr.hir_id {
-                    return;
+            if let ExprKind::If(_, _, _) = expr.kind {
+                // skip ifs directly in else, it will be checked in the parent if
+                if let Some(&Expr {
+                    kind: ExprKind::If(_, _, Some(else_expr)),
+                    ..
+                }) = get_parent_expr(cx, expr)
+                {
+                    if else_expr.hir_id == expr.hir_id {
+                        return;
+                    }
                 }
+
+                let (conds, blocks) = if_sequence(expr);
+                // Conditions
+                lint_same_cond(cx, &conds);
+                lint_same_fns_in_if_cond(cx, &conds);
+                // Block duplication
+                lint_same_then_else(cx, &blocks, conds.len() == blocks.len(), expr);
             }
+        }
+    }
+}
 
-            let (conds, blocks) = if_sequence(expr);
-            lint_same_then_else(cx, &blocks);
-            lint_same_cond(cx, &conds);
-            lint_same_fns_in_if_cond(cx, &conds);
+/// Implementation of `BRANCHES_SHARING_CODE` and `IF_SAME_THEN_ELSE` if the blocks are equal.
+fn lint_same_then_else<'tcx>(
+    cx: &LateContext<'tcx>,
+    blocks: &[&Block<'tcx>],
+    has_conditional_else: bool,
+    expr: &'tcx Expr<'_>,
+) {
+    // We only lint ifs with multiple blocks
+    if blocks.len() < 2 || parent_node_is_if_expr(expr, cx) {
+        return;
+    }
+
+    // Check if each block has shared code
+    let has_expr = blocks[0].expr.is_some();
+    let (start_eq, mut end_eq, expr_eq) = scan_block_for_eq(cx, blocks);
+
+    // BRANCHES_SHARING_CODE prerequisites
+    if has_conditional_else || (start_eq == 0 && end_eq == 0 && (has_expr && !expr_eq)) {
+        return;
+    }
+
+    // Only the start is the same
+    if start_eq != 0 && end_eq == 0 && (!has_expr || !expr_eq) {
+        let block = blocks[0];
+        let start_stmts = block.stmts.split_at(start_eq).0;
+
+        let mut start_walker = UsedValueFinderVisitor::new(cx);
+        for stmt in start_stmts {
+            intravisit::walk_stmt(&mut start_walker, stmt);
         }
+
+        emit_branches_sharing_code_lint(
+            cx,
+            start_eq,
+            0,
+            false,
+            check_for_warn_of_moved_symbol(cx, &start_walker.def_symbols, expr),
+            blocks,
+            expr,
+        );
+    } else if end_eq != 0 || (has_expr && expr_eq) {
+        let block = blocks[blocks.len() - 1];
+        let (start_stmts, block_stmts) = block.stmts.split_at(start_eq);
+        let (block_stmts, end_stmts) = block_stmts.split_at(block_stmts.len() - end_eq);
+
+        // Scan start
+        let mut start_walker = UsedValueFinderVisitor::new(cx);
+        for stmt in start_stmts {
+            intravisit::walk_stmt(&mut start_walker, stmt);
+        }
+        let mut moved_syms = start_walker.def_symbols;
+
+        // Scan block
+        let mut block_walker = UsedValueFinderVisitor::new(cx);
+        for stmt in block_stmts {
+            intravisit::walk_stmt(&mut block_walker, stmt);
+        }
+        let mut block_defs = block_walker.defs;
+
+        // Scan moved stmts
+        let mut moved_start: Option<usize> = None;
+        let mut end_walker = UsedValueFinderVisitor::new(cx);
+        for (index, stmt) in end_stmts.iter().enumerate() {
+            intravisit::walk_stmt(&mut end_walker, stmt);
+
+            for value in &end_walker.uses {
+                // Well we can't move this and all prev statements. So reset
+                if block_defs.contains(value) {
+                    moved_start = Some(index + 1);
+                    end_walker.defs.drain().for_each(|x| {
+                        block_defs.insert(x);
+                    });
+
+                    end_walker.def_symbols.clear();
+                }
+            }
+
+            end_walker.uses.clear();
+        }
+
+        if let Some(moved_start) = moved_start {
+            end_eq -= moved_start;
+        }
+
+        let end_linable = block.expr.map_or_else(
+            || end_eq != 0,
+            |expr| {
+                intravisit::walk_expr(&mut end_walker, expr);
+                end_walker.uses.iter().any(|x| !block_defs.contains(x))
+            },
+        );
+
+        if end_linable {
+            end_walker.def_symbols.drain().for_each(|x| {
+                moved_syms.insert(x);
+            });
+        }
+
+        emit_branches_sharing_code_lint(
+            cx,
+            start_eq,
+            end_eq,
+            end_linable,
+            check_for_warn_of_moved_symbol(cx, &moved_syms, expr),
+            blocks,
+            expr,
+        );
     }
 }
 
-/// Implementation of `IF_SAME_THEN_ELSE`.
-fn lint_same_then_else(cx: &LateContext<'_>, blocks: &[&Block<'_>]) {
-    let eq: &dyn Fn(&&Block<'_>, &&Block<'_>) -> bool =
-        &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).eq_block(lhs, rhs) };
+fn scan_block_for_eq(cx: &LateContext<'tcx>, blocks: &[&Block<'tcx>]) -> (usize, usize, bool) {
+    let mut start_eq = usize::MAX;
+    let mut end_eq = usize::MAX;
+    let mut expr_eq = true;
+    for win in blocks.windows(2) {
+        let l_stmts = win[0].stmts;
+        let r_stmts = win[1].stmts;
 
-    if let Some((i, j)) = search_same_sequenced(blocks, eq) {
-        span_lint_and_note(
+        // `SpanlessEq` now keeps track of the locals and is therefore context sensitive clippy#6752.
+        // The comparison therefore needs to be done in a way that builds the correct context.
+        let mut evaluator = SpanlessEq::new(cx);
+        let mut evaluator = evaluator.inter_expr();
+
+        let current_start_eq = count_eq(&mut l_stmts.iter(), &mut r_stmts.iter(), |l, r| evaluator.eq_stmt(l, r));
+
+        let current_end_eq = {
+            // We skip the middle statements which can't be equal
+            let end_comparison_count = l_stmts.len().min(r_stmts.len()) - current_start_eq;
+            let it1 = l_stmts.iter().skip(l_stmts.len() - end_comparison_count);
+            let it2 = r_stmts.iter().skip(r_stmts.len() - end_comparison_count);
+            it1.zip(it2)
+                .fold(0, |acc, (l, r)| if evaluator.eq_stmt(l, r) { acc + 1 } else { 0 })
+        };
+        let block_expr_eq = both(&win[0].expr, &win[1].expr, |l, r| evaluator.eq_expr(l, r));
+
+        // IF_SAME_THEN_ELSE
+        if_chain! {
+            if block_expr_eq;
+            if l_stmts.len() == r_stmts.len();
+            if l_stmts.len() == current_start_eq;
+            if run_lints(cx, &[IF_SAME_THEN_ELSE], win[0].hir_id);
+            if run_lints(cx, &[IF_SAME_THEN_ELSE], win[1].hir_id);
+            then {
+                span_lint_and_note(
+                    cx,
+                    IF_SAME_THEN_ELSE,
+                    win[0].span,
+                    "this `if` has identical blocks",
+                    Some(win[1].span),
+                    "same as this",
+                );
+
+                return (0, 0, false);
+            }
+        }
+
+        start_eq = start_eq.min(current_start_eq);
+        end_eq = end_eq.min(current_end_eq);
+        expr_eq &= block_expr_eq;
+    }
+
+    let has_expr = blocks[0].expr.is_some();
+    if has_expr && !expr_eq {
+        end_eq = 0;
+    }
+
+    // Check if the regions are overlapping. Set `end_eq` to prevent the overlap
+    let min_block_size = blocks.iter().map(|x| x.stmts.len()).min().unwrap();
+    if (start_eq + end_eq) > min_block_size {
+        end_eq = min_block_size - start_eq;
+    }
+
+    (start_eq, end_eq, expr_eq)
+}
+
+fn check_for_warn_of_moved_symbol(
+    cx: &LateContext<'tcx>,
+    symbols: &FxHashSet<Symbol>,
+    if_expr: &'tcx Expr<'_>,
+) -> bool {
+    get_enclosing_block(cx, if_expr.hir_id).map_or(false, |block| {
+        let ignore_span = block.span.shrink_to_lo().to(if_expr.span);
+
+        symbols
+            .iter()
+            .filter(|sym| !sym.as_str().starts_with('_'))
+            .any(move |sym| {
+                let mut walker = ContainsName {
+                    name: *sym,
+                    result: false,
+                };
+
+                // Scan block
+                block
+                    .stmts
+                    .iter()
+                    .filter(|stmt| !ignore_span.overlaps(stmt.span))
+                    .for_each(|stmt| intravisit::walk_stmt(&mut walker, stmt));
+
+                if let Some(expr) = block.expr {
+                    intravisit::walk_expr(&mut walker, expr);
+                }
+
+                walker.result
+            })
+    })
+}
+
+fn emit_branches_sharing_code_lint(
+    cx: &LateContext<'tcx>,
+    start_stmts: usize,
+    end_stmts: usize,
+    lint_end: bool,
+    warn_about_moved_symbol: bool,
+    blocks: &[&Block<'tcx>],
+    if_expr: &'tcx Expr<'_>,
+) {
+    if start_stmts == 0 && !lint_end {
+        return;
+    }
+
+    // (help, span, suggestion)
+    let mut suggestions: Vec<(&str, Span, String)> = vec![];
+    let mut add_expr_note = false;
+
+    // Construct suggestions
+    if start_stmts > 0 {
+        let block = blocks[0];
+        let span_start = first_line_of_span(cx, if_expr.span).shrink_to_lo();
+        let span_end = block.stmts[start_stmts - 1].span.source_callsite();
+
+        let cond_span = first_line_of_span(cx, if_expr.span).until(block.span);
+        let cond_snippet = reindent_multiline(snippet(cx, cond_span, "_"), false, None);
+        let cond_indent = indent_of(cx, cond_span);
+        let moved_span = block.stmts[0].span.source_callsite().to(span_end);
+        let moved_snippet = reindent_multiline(snippet(cx, moved_span, "_"), true, None);
+        let suggestion = moved_snippet.to_string() + "\n" + &cond_snippet + "{";
+        let suggestion = reindent_multiline(Cow::Borrowed(&suggestion), true, cond_indent);
+
+        let span = span_start.to(span_end);
+        suggestions.push(("start", span, suggestion.to_string()));
+    }
+
+    if lint_end {
+        let block = blocks[blocks.len() - 1];
+        let span_end = block.span.shrink_to_hi();
+
+        let moved_start = if end_stmts == 0 && block.expr.is_some() {
+            block.expr.unwrap().span
+        } else {
+            block.stmts[block.stmts.len() - end_stmts].span
+        }
+        .source_callsite();
+        let moved_end = block
+            .expr
+            .map_or_else(|| block.stmts[block.stmts.len() - 1].span, |expr| expr.span)
+            .source_callsite();
+
+        let moved_span = moved_start.to(moved_end);
+        let moved_snipped = reindent_multiline(snippet(cx, moved_span, "_"), true, None);
+        let indent = indent_of(cx, if_expr.span.shrink_to_hi());
+        let suggestion = "}\n".to_string() + &moved_snipped;
+        let suggestion = reindent_multiline(Cow::Borrowed(&suggestion), true, indent);
+
+        let mut span = moved_start.to(span_end);
+        // Improve formatting if the inner block has indention (i.e. normal Rust formatting)
+        let test_span = Span::new(span.lo() - BytePos(4), span.lo(), span.ctxt());
+        if snippet_opt(cx, test_span)
+            .map(|snip| snip == "    ")
+            .unwrap_or_default()
+        {
+            span = span.with_lo(test_span.lo());
+        }
+
+        suggestions.push(("end", span, suggestion.to_string()));
+        add_expr_note = !cx.typeck_results().expr_ty(if_expr).is_unit()
+    }
+
+    let add_optional_msgs = |diag: &mut DiagnosticBuilder<'_>| {
+        if add_expr_note {
+            diag.note("The end suggestion probably needs some adjustments to use the expression result correctly");
+        }
+
+        if warn_about_moved_symbol {
+            diag.warn("Some moved values might need to be renamed to avoid wrong references");
+        }
+    };
+
+    // Emit lint
+    if suggestions.len() == 1 {
+        let (place_str, span, sugg) = suggestions.pop().unwrap();
+        let msg = format!("all if blocks contain the same code at the {}", place_str);
+        let help = format!("consider moving the {} statements out like this", place_str);
+        span_lint_and_then(cx, BRANCHES_SHARING_CODE, span, msg.as_str(), |diag| {
+            diag.span_suggestion(span, help.as_str(), sugg, Applicability::Unspecified);
+
+            add_optional_msgs(diag);
+        });
+    } else if suggestions.len() == 2 {
+        let (_, end_span, end_sugg) = suggestions.pop().unwrap();
+        let (_, start_span, start_sugg) = suggestions.pop().unwrap();
+        span_lint_and_then(
             cx,
-            IF_SAME_THEN_ELSE,
-            j.span,
-            "this `if` has identical blocks",
-            Some(i.span),
-            "same as this",
+            BRANCHES_SHARING_CODE,
+            start_span,
+            "all if blocks contain the same code at the start and the end. Here at the start",
+            move |diag| {
+                diag.span_note(end_span, "and here at the end");
+
+                diag.span_suggestion(
+                    start_span,
+                    "consider moving the start statements out like this",
+                    start_sugg,
+                    Applicability::Unspecified,
+                );
+
+                diag.span_suggestion(
+                    end_span,
+                    "and consider moving the end statements out like this",
+                    end_sugg,
+                    Applicability::Unspecified,
+                );
+
+                add_optional_msgs(diag);
+            },
         );
     }
 }
 
+/// This visitor collects `HirId`s and Symbols of defined symbols and `HirId`s of used values.
+struct UsedValueFinderVisitor<'a, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+
+    /// The `HirId`s of defined values in the scanned statements
+    defs: FxHashSet<HirId>,
+
+    /// The Symbols of the defined symbols in the scanned statements
+    def_symbols: FxHashSet<Symbol>,
+
+    /// The `HirId`s of the used values
+    uses: FxHashSet<HirId>,
+}
+
+impl<'a, 'tcx> UsedValueFinderVisitor<'a, 'tcx> {
+    fn new(cx: &'a LateContext<'tcx>) -> Self {
+        UsedValueFinderVisitor {
+            cx,
+            defs: FxHashSet::default(),
+            def_symbols: FxHashSet::default(),
+            uses: FxHashSet::default(),
+        }
+    }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for UsedValueFinderVisitor<'a, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::All(self.cx.tcx.hir())
+    }
+
+    fn visit_local(&mut self, l: &'tcx rustc_hir::Local<'tcx>) {
+        let local_id = l.pat.hir_id;
+        self.defs.insert(local_id);
+
+        if let Some(sym) = l.pat.simple_ident() {
+            self.def_symbols.insert(sym.name);
+        }
+
+        if let Some(expr) = l.init {
+            intravisit::walk_expr(self, expr);
+        }
+    }
+
+    fn visit_qpath(&mut self, qpath: &'tcx rustc_hir::QPath<'tcx>, id: HirId, _span: rustc_span::Span) {
+        if let rustc_hir::QPath::Resolved(_, path) = *qpath {
+            if path.segments.len() == 1 {
+                if let rustc_hir::def::Res::Local(var) = self.cx.qpath_res(qpath, id) {
+                    self.uses.insert(var);
+                }
+            }
+        }
+    }
+}
+
 /// Implementation of `IFS_SAME_COND`.
 fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) {
     let hash: &dyn Fn(&&Expr<'_>) -> u64 = &|expr| -> u64 {
@@ -198,15 +618,3 @@ fn lint_same_fns_in_if_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) {
         );
     }
 }
-
-fn search_same_sequenced<T, Eq>(exprs: &[T], eq: Eq) -> Option<(&T, &T)>
-where
-    Eq: Fn(&T, &T) -> bool,
-{
-    for win in exprs.windows(2) {
-        if eq(&win[0], &win[1]) {
-            return Some((&win[0], &win[1]));
-        }
-    }
-    None
-}
diff --git a/src/tools/clippy/clippy_lints/src/create_dir.rs b/src/tools/clippy/clippy_lints/src/create_dir.rs
index ac890c90c97..7b5cce6462a 100644
--- a/src/tools/clippy/clippy_lints/src/create_dir.rs
+++ b/src/tools/clippy/clippy_lints/src/create_dir.rs
@@ -33,7 +33,7 @@ declare_lint_pass!(CreateDir => [CREATE_DIR]);
 impl LateLintPass<'_> for CreateDir {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         if_chain! {
-            if let ExprKind::Call(ref func, ref args) = expr.kind;
+            if let ExprKind::Call(func, args) = expr.kind;
             if let ExprKind::Path(ref path) = func.kind;
             if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id();
             if match_def_path(cx, def_id, &paths::STD_FS_CREATE_DIR);
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index 568a174445c..710da8fe9e0 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -77,29 +77,28 @@ impl LateLintPass<'_> for Default {
         if_chain! {
             // Avoid cases already linted by `field_reassign_with_default`
             if !self.reassigned_linted.contains(&expr.span);
-            if let ExprKind::Call(ref path, ..) = expr.kind;
+            if let ExprKind::Call(path, ..) = expr.kind;
             if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id);
             if let ExprKind::Path(ref qpath) = path.kind;
             if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
             if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD);
             // Detect and ignore <Foo as Default>::default() because these calls do explicitly name the type.
             if let QPath::Resolved(None, _path) = qpath;
+            let expr_ty = cx.typeck_results().expr_ty(expr);
+            if let ty::Adt(def, ..) = expr_ty.kind();
             then {
-                let expr_ty = cx.typeck_results().expr_ty(expr);
-                if let ty::Adt(def, ..) = expr_ty.kind() {
-                    // TODO: Work out a way to put "whatever the imported way of referencing
-                    // this type in this file" rather than a fully-qualified type.
-                    let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did));
-                    span_lint_and_sugg(
-                        cx,
-                        DEFAULT_TRAIT_ACCESS,
-                        expr.span,
-                        &format!("calling `{}` is more clear than this expression", replacement),
-                        "try",
-                        replacement,
-                        Applicability::Unspecified, // First resolve the TODO above
-                    );
-                }
+                // TODO: Work out a way to put "whatever the imported way of referencing
+                // this type in this file" rather than a fully-qualified type.
+                let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did));
+                span_lint_and_sugg(
+                    cx,
+                    DEFAULT_TRAIT_ACCESS,
+                    expr.span,
+                    &format!("calling `{}` is more clear than this expression", replacement),
+                    "try",
+                    replacement,
+                    Applicability::Unspecified, // First resolve the TODO above
+                );
             }
         }
     }
@@ -202,14 +201,14 @@ impl LateLintPass<'_> for Default {
                 let binding_type = if_chain! {
                     if let ty::Adt(adt_def, substs) = binding_type.kind();
                     if !substs.is_empty();
-                    let adt_def_ty_name = cx.tcx.item_name(adt_def.did);
-                    let generic_args = substs.iter().collect::<Vec<_>>();
-                    let tys_str = generic_args
-                        .iter()
-                        .map(ToString::to_string)
-                        .collect::<Vec<_>>()
-                        .join(", ");
                     then {
+                        let adt_def_ty_name = cx.tcx.item_name(adt_def.did);
+                        let generic_args = substs.iter().collect::<Vec<_>>();
+                        let tys_str = generic_args
+                            .iter()
+                            .map(ToString::to_string)
+                            .collect::<Vec<_>>()
+                            .join(", ");
                         format!("{}::<{}>", adt_def_ty_name, &tys_str)
                     } else {
                         binding_type.to_string()
@@ -247,7 +246,7 @@ impl LateLintPass<'_> for Default {
 /// Checks if the given expression is the `default` method belonging to the `Default` trait.
 fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool {
     if_chain! {
-        if let ExprKind::Call(ref fn_expr, _) = &expr.kind;
+        if let ExprKind::Call(fn_expr, _) = &expr.kind;
         if let ExprKind::Path(qpath) = &fn_expr.kind;
         if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id);
         then {
@@ -263,11 +262,11 @@ fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool
 fn field_reassigned_by_stmt<'tcx>(this: &Stmt<'tcx>, binding_name: Symbol) -> Option<(Ident, &'tcx Expr<'tcx>)> {
     if_chain! {
         // only take assignments
-        if let StmtKind::Semi(ref later_expr) = this.kind;
-        if let ExprKind::Assign(ref assign_lhs, ref assign_rhs, _) = later_expr.kind;
+        if let StmtKind::Semi(later_expr) = this.kind;
+        if let ExprKind::Assign(assign_lhs, assign_rhs, _) = later_expr.kind;
         // only take assignments to fields where the left-hand side field is a field of
         // the same binding as the previous statement
-        if let ExprKind::Field(ref binding, field_ident) = assign_lhs.kind;
+        if let ExprKind::Field(binding, field_ident) = assign_lhs.kind;
         if let ExprKind::Path(QPath::Resolved(_, path)) = binding.kind;
         if let Some(second_binding_name) = path.segments.last();
         if second_binding_name.ident.name == binding_name;
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index 73f71d88b05..6e883942680 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -131,8 +131,8 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
             },
 
             ExprKind::Struct(_, fields, base) => {
+                let ty = self.cx.typeck_results().expr_ty(expr);
                 if_chain! {
-                    let ty = self.cx.typeck_results().expr_ty(expr);
                     if let Some(adt_def) = ty.ty_adt_def();
                     if adt_def.is_struct();
                     if let Some(variant) = adt_def.variants.iter().next();
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 834136f910d..647af3bdc04 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_then};
 use clippy_utils::paths;
-use clippy_utils::ty::is_copy;
+use clippy_utils::ty::{implements_trait, is_copy};
 use clippy_utils::{get_trait_def_id, is_allowed, is_automatically_derived, match_def_path};
 use if_chain::if_chain;
 use rustc_hir::def_id::DefId;
@@ -12,7 +12,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Span;
+use rustc_span::{def_id::LOCAL_CRATE, source_map::Span};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for deriving `Hash` but implementing `PartialEq`
@@ -199,7 +199,7 @@ fn check_hash_peq<'tcx>(
         then {
             // Look for the PartialEq implementations for `ty`
             cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| {
-                let peq_is_automatically_derived = is_automatically_derived(&cx.tcx.get_attrs(impl_id));
+                let peq_is_automatically_derived = is_automatically_derived(cx.tcx.get_attrs(impl_id));
 
                 if peq_is_automatically_derived == hash_is_automatically_derived {
                     return;
@@ -253,7 +253,7 @@ fn check_ord_partial_ord<'tcx>(
         then {
             // Look for the PartialOrd implementations for `ty`
             cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| {
-                let partial_ord_is_automatically_derived = is_automatically_derived(&cx.tcx.get_attrs(impl_id));
+                let partial_ord_is_automatically_derived = is_automatically_derived(cx.tcx.get_attrs(impl_id));
 
                 if partial_ord_is_automatically_derived == ord_is_automatically_derived {
                     return;
@@ -293,48 +293,53 @@ fn check_ord_partial_ord<'tcx>(
 
 /// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint.
 fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &TraitRef<'_>, ty: Ty<'tcx>) {
-    if cx
-        .tcx
-        .lang_items()
-        .clone_trait()
-        .map_or(false, |id| Some(id) == trait_ref.trait_def_id())
-    {
-        if !is_copy(cx, ty) {
+    let clone_id = match cx.tcx.lang_items().clone_trait() {
+        Some(id) if trait_ref.trait_def_id() == Some(id) => id,
+        _ => return,
+    };
+    let copy_id = match cx.tcx.lang_items().copy_trait() {
+        Some(id) => id,
+        None => return,
+    };
+    let (ty_adt, ty_subs) = match *ty.kind() {
+        // Unions can't derive clone.
+        ty::Adt(adt, subs) if !adt.is_union() => (adt, subs),
+        _ => return,
+    };
+    // If the current self type doesn't implement Copy (due to generic constraints), search to see if
+    // there's a Copy impl for any instance of the adt.
+    if !is_copy(cx, ty) {
+        if ty_subs.non_erasable_generics().next().is_some() {
+            let has_copy_impl = cx
+                .tcx
+                .all_local_trait_impls(LOCAL_CRATE)
+                .get(&copy_id)
+                .map_or(false, |impls| {
+                    impls
+                        .iter()
+                        .any(|&id| matches!(cx.tcx.type_of(id).kind(), ty::Adt(adt, _) if ty_adt.did == adt.did))
+                });
+            if !has_copy_impl {
+                return;
+            }
+        } else {
             return;
         }
-
-        match *ty.kind() {
-            ty::Adt(def, _) if def.is_union() => return,
-
-            // Some types are not Clone by default but could be cloned “by hand” if necessary
-            ty::Adt(def, substs) => {
-                for variant in &def.variants {
-                    for field in &variant.fields {
-                        if let ty::FnDef(..) = field.ty(cx.tcx, substs).kind() {
-                            return;
-                        }
-                    }
-                    for subst in substs {
-                        if let ty::subst::GenericArgKind::Type(subst) = subst.unpack() {
-                            if let ty::Param(_) = subst.kind() {
-                                return;
-                            }
-                        }
-                    }
-                }
-            },
-            _ => (),
-        }
-
-        span_lint_and_note(
-            cx,
-            EXPL_IMPL_CLONE_ON_COPY,
-            item.span,
-            "you are implementing `Clone` explicitly on a `Copy` type",
-            Some(item.span),
-            "consider deriving `Clone` or removing `Copy`",
-        );
     }
+    // Derive constrains all generic types to requiring Clone. Check if any type is not constrained for
+    // this impl.
+    if ty_subs.types().any(|ty| !implements_trait(cx, ty, clone_id, &[])) {
+        return;
+    }
+
+    span_lint_and_note(
+        cx,
+        EXPL_IMPL_CLONE_ON_COPY,
+        item.span,
+        "you are implementing `Clone` explicitly on a `Copy` type",
+        Some(item.span),
+        "consider deriving `Clone` or removing `Copy`",
+    );
 }
 
 /// Implementation of the `UNSAFE_DERIVE_DESERIALIZE` lint.
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index 14338ac8faf..fb53b55ebd6 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -11,7 +11,7 @@ use rustc_errors::emitter::EmitterWriter;
 use rustc_errors::Handler;
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc_hir::{Expr, ExprKind, QPath};
+use rustc_hir::{AnonConst, Expr, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::map::Map;
 use rustc_middle::lint::in_external_macro;
@@ -710,16 +710,22 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
 
         // check for `begin_panic`
         if_chain! {
-            if let ExprKind::Call(ref func_expr, _) = expr.kind;
-            if let ExprKind::Path(QPath::Resolved(_, ref path)) = func_expr.kind;
+            if let ExprKind::Call(func_expr, _) = expr.kind;
+            if let ExprKind::Path(QPath::Resolved(_, path)) = func_expr.kind;
             if let Some(path_def_id) = path.res.opt_def_id();
             if match_panic_def_id(self.cx, path_def_id);
             if is_expn_of(expr.span, "unreachable").is_none();
+            if !is_expn_of_debug_assertions(expr.span);
             then {
                 self.panic_span = Some(expr.span);
             }
         }
 
+        // check for `assert_eq` or `assert_ne`
+        if is_expn_of(expr.span, "assert_eq").is_some() || is_expn_of(expr.span, "assert_ne").is_some() {
+            self.panic_span = Some(expr.span);
+        }
+
         // check for `unwrap`
         if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
             let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
@@ -734,7 +740,15 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
         intravisit::walk_expr(self, expr);
     }
 
+    // Panics in const blocks will cause compilation to fail.
+    fn visit_anon_const(&mut self, _: &'tcx AnonConst) {}
+
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
         NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
     }
 }
+
+fn is_expn_of_debug_assertions(span: Span) -> bool {
+    const MACRO_NAMES: &[&str] = &["debug_assert", "debug_assert_eq", "debug_assert_ne"];
+    MACRO_NAMES.iter().any(|name| is_expn_of(span, name).is_some())
+}
diff --git a/src/tools/clippy/clippy_lints/src/double_comparison.rs b/src/tools/clippy/clippy_lints/src/double_comparison.rs
index 1d291565ec1..58543ae6e4e 100644
--- a/src/tools/clippy/clippy_lints/src/double_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/double_comparison.rs
@@ -47,7 +47,7 @@ impl<'tcx> DoubleComparisons {
             },
             _ => return,
         };
-        if !(eq_expr_value(cx, &llhs, &rlhs) && eq_expr_value(cx, &lrhs, &rrhs)) {
+        if !(eq_expr_value(cx, llhs, rlhs) && eq_expr_value(cx, lrhs, rrhs)) {
             return;
         }
         macro_rules! lint_double_comparison {
@@ -88,7 +88,7 @@ impl<'tcx> DoubleComparisons {
 
 impl<'tcx> LateLintPass<'tcx> for DoubleComparisons {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = expr.kind {
+        if let ExprKind::Binary(ref kind, lhs, rhs) = expr.kind {
             Self::check_binop(cx, kind.node, lhs, rhs, expr.span);
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/double_parens.rs b/src/tools/clippy/clippy_lints/src/double_parens.rs
index 5afdcb3c09f..e4e4a93b011 100644
--- a/src/tools/clippy/clippy_lints/src/double_parens.rs
+++ b/src/tools/clippy/clippy_lints/src/double_parens.rs
@@ -50,7 +50,7 @@ impl EarlyLintPass for DoubleParens {
         match expr.kind {
             ExprKind::Paren(ref in_paren) => match in_paren.kind {
                 ExprKind::Paren(_) | ExprKind::Tup(_) => {
-                    span_lint(cx, DOUBLE_PARENS, expr.span, &msg);
+                    span_lint(cx, DOUBLE_PARENS, expr.span, msg);
                 },
                 _ => {},
             },
@@ -58,7 +58,7 @@ impl EarlyLintPass for DoubleParens {
                 if params.len() == 1 {
                     let param = &params[0];
                     if let ExprKind::Paren(_) = param.kind {
-                        span_lint(cx, DOUBLE_PARENS, param.span, &msg);
+                        span_lint(cx, DOUBLE_PARENS, param.span, msg);
                     }
                 }
             },
@@ -66,7 +66,7 @@ impl EarlyLintPass for DoubleParens {
                 if params.len() == 2 {
                     let param = &params[1];
                     if let ExprKind::Paren(_) = param.kind {
-                        span_lint(cx, DOUBLE_PARENS, param.span, &msg);
+                        span_lint(cx, DOUBLE_PARENS, param.span, msg);
                     }
                 }
             },
diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
index 7e7ec017bbb..b5b29760636 100644
--- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
@@ -113,7 +113,7 @@ declare_lint_pass!(DropForgetRef => [DROP_REF, FORGET_REF, DROP_COPY, FORGET_COP
 impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
-            if let ExprKind::Call(ref path, ref args) = expr.kind;
+            if let ExprKind::Call(path, args) = expr.kind;
             if let ExprKind::Path(ref qpath) = path.kind;
             if args.len() == 1;
             if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
diff --git a/src/tools/clippy/clippy_lints/src/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/duration_subsec.rs
index 746c1f6df91..529807770f3 100644
--- a/src/tools/clippy/clippy_lints/src/duration_subsec.rs
+++ b/src/tools/clippy/clippy_lints/src/duration_subsec.rs
@@ -43,8 +43,8 @@ declare_lint_pass!(DurationSubsec => [DURATION_SUBSEC]);
 impl<'tcx> LateLintPass<'tcx> for DurationSubsec {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
-            if let ExprKind::Binary(Spanned { node: BinOpKind::Div, .. }, ref left, ref right) = expr.kind;
-            if let ExprKind::MethodCall(ref method_path, _ , ref args, _) = left.kind;
+            if let ExprKind::Binary(Spanned { node: BinOpKind::Div, .. }, left, right) = expr.kind;
+            if let ExprKind::MethodCall(method_path, _ , args, _) = left.kind;
             if match_type(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), &paths::DURATION);
             if let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right);
             then {
diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs
index 25eb048448c..a815df1691a 100644
--- a/src/tools/clippy/clippy_lints/src/entry.rs
+++ b/src/tools/clippy/clippy_lints/src/entry.rs
@@ -57,14 +57,14 @@ declare_lint_pass!(HashMapPass => [MAP_ENTRY]);
 
 impl<'tcx> LateLintPass<'tcx> for HashMapPass {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let ExprKind::If(ref check, ref then_block, ref else_block) = expr.kind {
-            if let ExprKind::Unary(UnOp::Not, ref check) = check.kind {
+        if let ExprKind::If(check, then_block, ref else_block) = expr.kind {
+            if let ExprKind::Unary(UnOp::Not, check) = check.kind {
                 if let Some((ty, map, key)) = check_cond(cx, check) {
                     // in case of `if !m.contains_key(&k) { m.insert(k, v); }`
                     // we can give a better error message
                     let sole_expr = {
                         else_block.is_none()
-                            && if let ExprKind::Block(ref then_block, _) = then_block.kind {
+                            && if let ExprKind::Block(then_block, _) = then_block.kind {
                                 (then_block.expr.is_some() as usize) + then_block.stmts.len() == 1
                             } else {
                                 true
@@ -81,9 +81,9 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
                         sole_expr,
                     };
 
-                    walk_expr(&mut visitor, &**then_block);
+                    walk_expr(&mut visitor, then_block);
                 }
-            } else if let Some(ref else_block) = *else_block {
+            } else if let Some(else_block) = *else_block {
                 if let Some((ty, map, key)) = check_cond(cx, check) {
                     let mut visitor = InsertVisitor {
                         cx,
@@ -103,10 +103,10 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
 
 fn check_cond<'a>(cx: &LateContext<'_>, check: &'a Expr<'a>) -> Option<(&'static str, &'a Expr<'a>, &'a Expr<'a>)> {
     if_chain! {
-        if let ExprKind::MethodCall(ref path, _, ref params, _) = check.kind;
+        if let ExprKind::MethodCall(path, _, params, _) = check.kind;
         if params.len() >= 2;
         if path.ident.name == sym!(contains_key);
-        if let ExprKind::AddrOf(BorrowKind::Ref, _, ref key) = params[1].kind;
+        if let ExprKind::AddrOf(BorrowKind::Ref, _, key) = params[1].kind;
         then {
             let map = &params[0];
             let obj_ty = cx.typeck_results().expr_ty(map).peel_refs();
@@ -140,7 +140,7 @@ impl<'a, 'tcx, 'b> Visitor<'tcx> for InsertVisitor<'a, 'tcx, 'b> {
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         if_chain! {
-            if let ExprKind::MethodCall(ref path, _, ref params, _) = expr.kind;
+            if let ExprKind::MethodCall(path, _, params, _) = expr.kind;
             if params.len() == 3;
             if path.ident.name == sym!(insert);
             if get_item_name(self.cx, self.map) == get_item_name(self.cx, &params[0]);
diff --git a/src/tools/clippy/clippy_lints/src/eq_op.rs b/src/tools/clippy/clippy_lints/src/eq_op.rs
index 6d7046ac8b7..90f391b5f5c 100644
--- a/src/tools/clippy/clippy_lints/src/eq_op.rs
+++ b/src/tools/clippy/clippy_lints/src/eq_op.rs
@@ -65,12 +65,12 @@ const ASSERT_MACRO_NAMES: [&str; 4] = ["assert_eq", "assert_ne", "debug_assert_e
 impl<'tcx> LateLintPass<'tcx> for EqOp {
     #[allow(clippy::similar_names, clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        if let ExprKind::Block(ref block, _) = e.kind {
+        if let ExprKind::Block(block, _) = e.kind {
             for stmt in block.stmts {
                 for amn in &ASSERT_MACRO_NAMES {
                     if_chain! {
                         if is_expn_of(stmt.span, amn).is_some();
-                        if let StmtKind::Semi(ref matchexpr) = stmt.kind;
+                        if let StmtKind::Semi(matchexpr) = stmt.kind;
                         if let Some(macro_args) = higher::extract_assert_macro_args(matchexpr);
                         if macro_args.len() == 2;
                         let (lhs, rhs) = (macro_args[0], macro_args[1]);
@@ -88,12 +88,12 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
                 }
             }
         }
-        if let ExprKind::Binary(op, ref left, ref right) = e.kind {
+        if let ExprKind::Binary(op, left, right) = e.kind {
             if e.span.from_expansion() {
                 return;
             }
             let macro_with_not_op = |expr_kind: &ExprKind<'_>| {
-                if let ExprKind::Unary(_, ref expr) = *expr_kind {
+                if let ExprKind::Unary(_, expr) = *expr_kind {
                     in_macro(expr.span)
                 } else {
                     false
@@ -135,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
                     // do not suggest to dereference literals
                     (&ExprKind::Lit(..), _) | (_, &ExprKind::Lit(..)) => {},
                     // &foo == &bar
-                    (&ExprKind::AddrOf(BorrowKind::Ref, _, ref l), &ExprKind::AddrOf(BorrowKind::Ref, _, ref r)) => {
+                    (&ExprKind::AddrOf(BorrowKind::Ref, _, l), &ExprKind::AddrOf(BorrowKind::Ref, _, r)) => {
                         let lty = cx.typeck_results().expr_ty(l);
                         let rty = cx.typeck_results().expr_ty(r);
                         let lcpy = is_copy(cx, lty);
@@ -198,7 +198,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
                         }
                     },
                     // &foo == bar
-                    (&ExprKind::AddrOf(BorrowKind::Ref, _, ref l), _) => {
+                    (&ExprKind::AddrOf(BorrowKind::Ref, _, l), _) => {
                         let lty = cx.typeck_results().expr_ty(l);
                         let lcpy = is_copy(cx, lty);
                         if (requires_ref || lcpy)
@@ -222,7 +222,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
                         }
                     },
                     // foo == &bar
-                    (_, &ExprKind::AddrOf(BorrowKind::Ref, _, ref r)) => {
+                    (_, &ExprKind::AddrOf(BorrowKind::Ref, _, r)) => {
                         let rty = cx.typeck_results().expr_ty(r);
                         let rcpy = is_copy(cx, rty);
                         if (requires_ref || rcpy)
diff --git a/src/tools/clippy/clippy_lints/src/erasing_op.rs b/src/tools/clippy/clippy_lints/src/erasing_op.rs
index 59602616781..f95ca86a2d0 100644
--- a/src/tools/clippy/clippy_lints/src/erasing_op.rs
+++ b/src/tools/clippy/clippy_lints/src/erasing_op.rs
@@ -34,7 +34,7 @@ impl<'tcx> LateLintPass<'tcx> for ErasingOp {
         if e.span.from_expansion() {
             return;
         }
-        if let ExprKind::Binary(ref cmp, ref left, ref right) = e.kind {
+        if let ExprKind::Binary(ref cmp, left, right) = e.kind {
             match cmp.node {
                 BinOpKind::Mul | BinOpKind::BitAnd => {
                     check(cx, left, e.span);
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 99253555a95..2f1aa53236d 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -87,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
 }
 
 fn check_closure(cx: &LateContext<'_>, expr: &Expr<'_>) {
-    if let ExprKind::Closure(_, ref decl, eid, _, _) = expr.kind {
+    if let ExprKind::Closure(_, decl, eid, _, _) = expr.kind {
         let body = cx.tcx.hir().body(eid);
         let ex = &body.value;
 
@@ -109,7 +109,7 @@ fn check_closure(cx: &LateContext<'_>, expr: &Expr<'_>) {
         }
 
         if_chain!(
-            if let ExprKind::Call(ref caller, ref args) = ex.kind;
+            if let ExprKind::Call(caller, args) = ex.kind;
 
             if let ExprKind::Path(_) = caller.kind;
 
@@ -142,7 +142,7 @@ fn check_closure(cx: &LateContext<'_>, expr: &Expr<'_>) {
         );
 
         if_chain!(
-            if let ExprKind::MethodCall(ref path, _, ref args, _) = ex.kind;
+            if let ExprKind::MethodCall(path, _, args, _) = ex.kind;
 
             // Not the same number of arguments, there is no way the closure is the same as the function return;
             if args.len() == decl.inputs.len();
@@ -178,7 +178,7 @@ fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: def_id::DefId, self_a
     let actual_type_of_self = &cx.typeck_results().node_type(self_arg.hir_id);
 
     if let Some(trait_id) = cx.tcx.trait_of_item(method_def_id) {
-        if match_borrow_depth(expected_type_of_self, &actual_type_of_self)
+        if match_borrow_depth(expected_type_of_self, actual_type_of_self)
             && implements_trait(cx, actual_type_of_self, trait_id, &[])
         {
             return Some(cx.tcx.def_path_str(trait_id));
@@ -187,8 +187,8 @@ fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: def_id::DefId, self_a
 
     cx.tcx.impl_of_method(method_def_id).and_then(|_| {
         //a type may implicitly implement other type's methods (e.g. Deref)
-        if match_types(expected_type_of_self, &actual_type_of_self) {
-            return Some(get_type_name(cx, &actual_type_of_self));
+        if match_types(expected_type_of_self, actual_type_of_self) {
+            return Some(get_type_name(cx, actual_type_of_self));
         }
         None
     })
@@ -196,7 +196,7 @@ fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: def_id::DefId, self_a
 
 fn match_borrow_depth(lhs: Ty<'_>, rhs: Ty<'_>) -> bool {
     match (&lhs.kind(), &rhs.kind()) {
-        (ty::Ref(_, t1, mut1), ty::Ref(_, t2, mut2)) => mut1 == mut2 && match_borrow_depth(&t1, &t2),
+        (ty::Ref(_, t1, mut1), ty::Ref(_, t2, mut2)) => mut1 == mut2 && match_borrow_depth(t1, t2),
         (l, r) => !matches!((l, r), (ty::Ref(_, _, _), _) | (_, ty::Ref(_, _, _))),
     }
 }
@@ -218,7 +218,7 @@ fn match_types(lhs: Ty<'_>, rhs: Ty<'_>) -> bool {
 fn get_type_name(cx: &LateContext<'_>, ty: Ty<'_>) -> String {
     match ty.kind() {
         ty::Adt(t, _) => cx.tcx.def_path_str(t.did),
-        ty::Ref(_, r, _) => get_type_name(cx, &r),
+        ty::Ref(_, r, _) => get_type_name(cx, r),
         _ => ty.to_string(),
     }
 }
@@ -230,7 +230,7 @@ fn compare_inputs(
     for (closure_input, function_arg) in closure_inputs.zip(call_args) {
         if let PatKind::Binding(_, _, ident, _) = closure_input.pat.kind {
             // XXXManishearth Should I be checking the binding mode here?
-            if let ExprKind::Path(QPath::Resolved(None, ref p)) = function_arg.kind {
+            if let ExprKind::Path(QPath::Resolved(None, p)) = function_arg.kind {
                 if p.segments.len() != 1 {
                     // If it's a proper path, it can't be a local variable
                     return false;
diff --git a/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs b/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs
index ea33a4d98fd..762f64fe37a 100644
--- a/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs
+++ b/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs
@@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         // Find a write to a local variable.
         match expr.kind {
-            ExprKind::Assign(ref lhs, ..) | ExprKind::AssignOp(_, ref lhs, _) => {
+            ExprKind::Assign(lhs, ..) | ExprKind::AssignOp(_, lhs, _) => {
                 if let Some(var) = path_to_local(lhs) {
                     let mut visitor = ReadVisitor {
                         cx,
@@ -87,12 +87,12 @@ impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence {
     }
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         match stmt.kind {
-            StmtKind::Local(ref local) => {
-                if let Local { init: Some(ref e), .. } = **local {
+            StmtKind::Local(local) => {
+                if let Local { init: Some(e), .. } = local {
                     DivergenceVisitor { cx }.visit_expr(e);
                 }
             },
-            StmtKind::Expr(ref e) | StmtKind::Semi(ref e) => DivergenceVisitor { cx }.maybe_walk_expr(e),
+            StmtKind::Expr(e) | StmtKind::Semi(e) => DivergenceVisitor { cx }.maybe_walk_expr(e),
             StmtKind::Item(..) => {},
         }
     }
@@ -106,7 +106,7 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
     fn maybe_walk_expr(&mut self, e: &'tcx Expr<'_>) {
         match e.kind {
             ExprKind::Closure(..) => {},
-            ExprKind::Match(ref e, arms, _) => {
+            ExprKind::Match(e, arms, _) => {
                 self.visit_expr(e);
                 for arm in arms {
                     if let Some(Guard::If(if_expr)) = arm.guard {
@@ -130,7 +130,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
         match e.kind {
             ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => self.report_diverging_sub_expr(e),
-            ExprKind::Call(ref func, _) => {
+            ExprKind::Call(func, _) => {
                 let typ = self.cx.typeck_results().expr_ty(func);
                 match typ.kind() {
                     ty::FnDef(..) | ty::FnPtr(_) => {
@@ -266,10 +266,10 @@ fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr<'_>) -
 
 fn check_stmt<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, stmt: &'tcx Stmt<'_>) -> StopEarly {
     match stmt.kind {
-        StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => check_expr(vis, expr),
+        StmtKind::Expr(expr) | StmtKind::Semi(expr) => check_expr(vis, expr),
         // If the declaration is of a local variable, check its initializer
         // expression if it has one. Otherwise, keep going.
-        StmtKind::Local(ref local) => local
+        StmtKind::Local(local) => local
             .init
             .as_ref()
             .map_or(StopEarly::KeepGoing, |expr| check_expr(vis, expr)),
@@ -343,7 +343,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> {
 /// Returns `true` if `expr` is the LHS of an assignment, like `expr = ...`.
 fn is_in_assignment_position(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     if let Some(parent) = get_parent_expr(cx, expr) {
-        if let ExprKind::Assign(ref lhs, ..) = parent.kind {
+        if let ExprKind::Assign(lhs, ..) = parent.kind {
             return lhs.hir_id == expr.hir_id;
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
index 6c9652fd87d..249ee27330b 100644
--- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs
+++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
@@ -1,9 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::{attr_by_name, in_macro, match_path_ast};
+use clippy_utils::{in_macro, match_path_ast};
 use rustc_ast::ast::{AssocItemKind, Extern, FnKind, FnSig, ImplKind, Item, ItemKind, TraitKind, Ty, TyKind};
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::Span;
+use rustc_span::{sym, Span};
 
 use std::convert::TryInto;
 
@@ -138,7 +138,7 @@ impl EarlyLintPass for ExcessiveBools {
         }
         match &item.kind {
             ItemKind::Struct(variant_data, _) => {
-                if attr_by_name(&item.attrs, "repr").is_some() {
+                if item.attrs.iter().any(|attr| attr.has_name(sym::repr)) {
                     return;
                 }
 
diff --git a/src/tools/clippy/clippy_lints/src/exit.rs b/src/tools/clippy/clippy_lints/src/exit.rs
index 635b6d83eab..16246e548b6 100644
--- a/src/tools/clippy/clippy_lints/src/exit.rs
+++ b/src/tools/clippy/clippy_lints/src/exit.rs
@@ -28,20 +28,18 @@ declare_lint_pass!(Exit => [EXIT]);
 impl<'tcx> LateLintPass<'tcx> for Exit {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         if_chain! {
-            if let ExprKind::Call(ref path_expr, ref _args) = e.kind;
+            if let ExprKind::Call(path_expr, _args) = e.kind;
             if let ExprKind::Path(ref path) = path_expr.kind;
             if let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id();
             if match_def_path(cx, def_id, &paths::EXIT);
+            let parent = cx.tcx.hir().get_parent_item(e.hir_id);
+            if let Some(Node::Item(Item{kind: ItemKind::Fn(..), ..})) = cx.tcx.hir().find(parent);
+            // If the next item up is a function we check if it is an entry point
+            // and only then emit a linter warning
+            let def_id = cx.tcx.hir().local_def_id(parent);
+            if !is_entrypoint_fn(cx, def_id.to_def_id());
             then {
-                let parent = cx.tcx.hir().get_parent_item(e.hir_id);
-                if let Some(Node::Item(Item{kind: ItemKind::Fn(..), ..})) = cx.tcx.hir().find(parent) {
-                    // If the next item up is a function we check if it is an entry point
-                    // and only then emit a linter warning
-                    let def_id = cx.tcx.hir().local_def_id(parent);
-                    if !is_entrypoint_fn(cx, def_id.to_def_id()) {
-                        span_lint(cx, EXIT, e.span, "usage of `process::exit`");
-                    }
-                }
+                span_lint(cx, EXIT, e.span, "usage of `process::exit`");
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs
index 4146b7baa10..da4936ff25b 100644
--- a/src/tools/clippy/clippy_lints/src/explicit_write.rs
+++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs
@@ -34,11 +34,11 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
             // match call to unwrap
-            if let ExprKind::MethodCall(ref unwrap_fun, _, ref unwrap_args, _) = expr.kind;
+            if let ExprKind::MethodCall(unwrap_fun, _, unwrap_args, _) = expr.kind;
             if unwrap_fun.ident.name == sym::unwrap;
             // match call to write_fmt
             if !unwrap_args.is_empty();
-            if let ExprKind::MethodCall(ref write_fun, _, write_args, _) =
+            if let ExprKind::MethodCall(write_fun, _, write_args, _) =
                 unwrap_args[0].kind;
             if write_fun.ident.name == sym!(write_fmt);
             // match calls to std::io::stdout() / std::io::stderr ()
@@ -135,10 +135,10 @@ fn write_output_string(write_args: &[Expr<'_>]) -> Option<String> {
     if_chain! {
         // Obtain the string that should be printed
         if write_args.len() > 1;
-        if let ExprKind::Call(_, ref output_args) = write_args[1].kind;
+        if let ExprKind::Call(_, output_args) = write_args[1].kind;
         if !output_args.is_empty();
-        if let ExprKind::AddrOf(BorrowKind::Ref, _, ref output_string_expr) = output_args[0].kind;
-        if let ExprKind::Array(ref string_exprs) = output_string_expr.kind;
+        if let ExprKind::AddrOf(BorrowKind::Ref, _, output_string_expr) = output_args[0].kind;
+        if let ExprKind::Array(string_exprs) = output_string_expr.kind;
         // we only want to provide an automatic suggestion for simple (non-format) strings
         if string_exprs.len() == 1;
         if let ExprKind::Lit(ref lit) = string_exprs[0].kind;
diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
index 52a5a7acf0d..2937fcb9ca0 100644
--- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
+++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
@@ -81,8 +81,8 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h
         fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
             // check for `begin_panic`
             if_chain! {
-                if let ExprKind::Call(ref func_expr, _) = expr.kind;
-                if let ExprKind::Path(QPath::Resolved(_, ref path)) = func_expr.kind;
+                if let ExprKind::Call(func_expr, _) = expr.kind;
+                if let ExprKind::Path(QPath::Resolved(_, path)) = func_expr.kind;
                 if let Some(path_def_id) = path.res.opt_def_id();
                 if match_panic_def_id(self.lcx, path_def_id);
                 if is_expn_of(expr.span, "unreachable").is_none();
diff --git a/src/tools/clippy/clippy_lints/src/float_equality_without_abs.rs b/src/tools/clippy/clippy_lints/src/float_equality_without_abs.rs
index 0c59db360f9..b5ebe5f90ba 100644
--- a/src/tools/clippy/clippy_lints/src/float_equality_without_abs.rs
+++ b/src/tools/clippy/clippy_lints/src/float_equality_without_abs.rs
@@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatEqualityWithoutAbs {
         let rhs;
 
         // check if expr is a binary expression with a lt or gt operator
-        if let ExprKind::Binary(op, ref left, ref right) = expr.kind {
+        if let ExprKind::Binary(op, left, right) = expr.kind {
             match op.node {
                 BinOpKind::Lt => {
                     lhs = left;
@@ -88,8 +88,8 @@ impl<'tcx> LateLintPass<'tcx> for FloatEqualityWithoutAbs {
             if let ty::Float(_) = t_val_r.kind();
 
             then {
-                let sug_l = sugg::Sugg::hir(cx, &val_l, "..");
-                let sug_r = sugg::Sugg::hir(cx, &val_r, "..");
+                let sug_l = sugg::Sugg::hir(cx, val_l, "..");
+                let sug_r = sugg::Sugg::hir(cx, val_r, "..");
                 // format the suggestion
                 let suggestion = format!("{}.abs()", sugg::make_assoc(AssocOp::Subtract, &sug_l, &sug_r).maybe_par());
                 // spans the lint
diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs
index 1ca5c685a75..7968e7b764d 100644
--- a/src/tools/clippy/clippy_lints/src/float_literal.rs
+++ b/src/tools/clippy/clippy_lints/src/float_literal.rs
@@ -61,8 +61,8 @@ declare_lint_pass!(FloatLiteral => [EXCESSIVE_PRECISION, LOSSY_FLOAT_LITERAL]);
 
 impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+        let ty = cx.typeck_results().expr_ty(expr);
         if_chain! {
-            let ty = cx.typeck_results().expr_ty(expr);
             if let ty::Float(fty) = *ty.kind();
             if let hir::ExprKind::Lit(ref lit) = expr.kind;
             if let LitKind::Float(sym, lit_float_ty) = lit.node;
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index 0b5f0379ce6..e0b687b0205 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -131,7 +131,7 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su
     let mut suggestion = Sugg::hir(cx, expr, "..");
 
     if let ExprKind::Unary(UnOp::Neg, inner_expr) = &expr.kind {
-        expr = &inner_expr;
+        expr = inner_expr;
     }
 
     if_chain! {
@@ -313,8 +313,8 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
                     Spanned {
                         node: BinOpKind::Add, ..
                     },
-                    ref lhs,
-                    ref rhs,
+                    lhs,
+                    rhs,
                 ) = parent.kind
                 {
                     let other_addend = if lhs.hir_id == expr.hir_id { rhs } else { lhs };
@@ -329,7 +329,7 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
                             "{}.mul_add({}, {})",
                             Sugg::hir(cx, &args[0], ".."),
                             Sugg::hir(cx, &args[0], ".."),
-                            Sugg::hir(cx, &other_addend, ".."),
+                            Sugg::hir(cx, other_addend, ".."),
                         ),
                         Applicability::MachineApplicable,
                     );
@@ -356,18 +356,18 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
         Spanned {
             node: BinOpKind::Add, ..
         },
-        ref add_lhs,
-        ref add_rhs,
+        add_lhs,
+        add_rhs,
     ) = args[0].kind
     {
         // check if expression of the form x * x + y * y
         if_chain! {
-            if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref lmul_lhs, ref lmul_rhs) = add_lhs.kind;
-            if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref rmul_lhs, ref rmul_rhs) = add_rhs.kind;
+            if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, lmul_lhs, lmul_rhs) = add_lhs.kind;
+            if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, rmul_lhs, rmul_rhs) = add_rhs.kind;
             if eq_expr_value(cx, lmul_lhs, lmul_rhs);
             if eq_expr_value(cx, rmul_lhs, rmul_rhs);
             then {
-                return Some(format!("{}.hypot({})", Sugg::hir(cx, &lmul_lhs, ".."), Sugg::hir(cx, &rmul_lhs, "..")));
+                return Some(format!("{}.hypot({})", Sugg::hir(cx, lmul_lhs, ".."), Sugg::hir(cx, rmul_lhs, "..")));
             }
         }
 
@@ -376,13 +376,13 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
             if let ExprKind::MethodCall(
                 PathSegment { ident: lmethod_name, .. },
                 ref _lspan,
-                ref largs,
+                largs,
                 _
             ) = add_lhs.kind;
             if let ExprKind::MethodCall(
                 PathSegment { ident: rmethod_name, .. },
                 ref _rspan,
-                ref rargs,
+                rargs,
                 _
             ) = add_rhs.kind;
             if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi";
@@ -416,11 +416,11 @@ fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
 // and suggest usage of `x.exp_m1() - (y - 1)` instead
 fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if_chain! {
-        if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, ref lhs, ref rhs) = expr.kind;
+        if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, lhs, rhs) = expr.kind;
         if cx.typeck_results().expr_ty(lhs).is_floating_point();
         if let Some((value, _)) = constant(cx, cx.typeck_results(), rhs);
         if F32(1.0) == value || F64(1.0) == value;
-        if let ExprKind::MethodCall(ref path, _, ref method_args, _) = lhs.kind;
+        if let ExprKind::MethodCall(path, _, method_args, _) = lhs.kind;
         if cx.typeck_results().expr_ty(&method_args[0]).is_floating_point();
         if path.ident.name.as_str() == "exp";
         then {
@@ -442,7 +442,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
 
 fn is_float_mul_expr<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> {
     if_chain! {
-        if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref lhs, ref rhs) = &expr.kind;
+        if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, lhs, rhs) = &expr.kind;
         if cx.typeck_results().expr_ty(lhs).is_floating_point();
         if cx.typeck_results().expr_ty(rhs).is_floating_point();
         then {
@@ -604,8 +604,8 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
 
 fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool {
     if_chain! {
-        if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, _, ref args_a, _) = expr_a.kind;
-        if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, ref args_b, _) = expr_b.kind;
+        if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, _, args_a, _) = expr_a.kind;
+        if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, args_b, _) = expr_b.kind;
         then {
             return method_name_a.as_str() == method_name_b.as_str() &&
                 args_a.len() == args_b.len() &&
@@ -630,8 +630,8 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) {
             rhs,
         ) = &expr.kind;
         if are_same_base_logs(cx, lhs, rhs);
-        if let ExprKind::MethodCall(_, _, ref largs, _) = lhs.kind;
-        if let ExprKind::MethodCall(_, _, ref rargs, _) = rhs.kind;
+        if let ExprKind::MethodCall(_, _, largs, _) = lhs.kind;
+        if let ExprKind::MethodCall(_, _, rargs, _) = rhs.kind;
         then {
             span_lint_and_sugg(
                 cx,
@@ -675,7 +675,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
                     expr.span,
                     "conversion to degrees can be done more accurately",
                     "consider using",
-                    format!("{}.to_degrees()", Sugg::hir(cx, &mul_lhs, "..")),
+                    format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..")),
                     Applicability::MachineApplicable,
                 );
             } else if
@@ -688,7 +688,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
                     expr.span,
                     "conversion to radians can be done more accurately",
                     "consider using",
-                    format!("{}.to_radians()", Sugg::hir(cx, &mul_lhs, "..")),
+                    format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..")),
                     Applicability::MachineApplicable,
                 );
             }
@@ -698,7 +698,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
 
 impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let ExprKind::MethodCall(ref path, _, args, _) = &expr.kind {
+        if let ExprKind::MethodCall(path, _, args, _) = &expr.kind {
             let recv_ty = cx.typeck_results().expr_ty(&args[0]);
 
             if recv_ty.is_floating_point() {
diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs
index a33f987b423..4729abbd8e3 100644
--- a/src/tools/clippy/clippy_lints/src/format.rs
+++ b/src/tools/clippy/clippy_lints/src/format.rs
@@ -78,8 +78,8 @@ fn span_useless_format<T: LintContext>(cx: &T, span: Span, help: &str, mut sugg:
 
 fn on_argumentv1_new<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) -> Option<String> {
     if_chain! {
-        if let ExprKind::AddrOf(BorrowKind::Ref, _, ref format_args) = expr.kind;
-        if let ExprKind::Array(ref elems) = arms[0].body.kind;
+        if let ExprKind::AddrOf(BorrowKind::Ref, _, format_args) = expr.kind;
+        if let ExprKind::Array(elems) = arms[0].body.kind;
         if elems.len() == 1;
         if let Some(args) = match_function_call(cx, &elems[0], &paths::FMT_ARGUMENTV1_NEW);
         // matches `core::fmt::Display::fmt`
@@ -88,10 +88,10 @@ fn on_argumentv1_new<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arms: &
         if let Some(did) = cx.qpath_res(qpath, args[1].hir_id).opt_def_id();
         if match_def_path(cx, did, &paths::DISPLAY_FMT_METHOD);
         // check `(arg0,)` in match block
-        if let PatKind::Tuple(ref pats, None) = arms[0].pat.kind;
+        if let PatKind::Tuple(pats, None) = arms[0].pat.kind;
         if pats.len() == 1;
         then {
-            let ty = cx.typeck_results().pat_ty(&pats[0]).peel_refs();
+            let ty = cx.typeck_results().pat_ty(pats[0]).peel_refs();
             if *ty.kind() != rustc_middle::ty::Str && !is_type_diagnostic_item(cx, ty, sym::string_type) {
                 return None;
             }
@@ -101,7 +101,7 @@ fn on_argumentv1_new<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arms: &
                 }
             } else {
                 let snip = snippet(cx, format_args.span, "<arg>");
-                if let ExprKind::MethodCall(ref path, _, _, _) = format_args.kind {
+                if let ExprKind::MethodCall(path, _, _, _) = format_args.kind {
                     if path.ident.name == sym!(to_string) {
                         return Some(format!("{}", snip));
                     }
@@ -120,16 +120,16 @@ fn on_new_v1<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<Strin
         if let Some(args) = match_function_call(cx, expr, &paths::FMT_ARGUMENTS_NEW_V1);
         if args.len() == 2;
         // Argument 1 in `new_v1()`
-        if let ExprKind::AddrOf(BorrowKind::Ref, _, ref arr) = args[0].kind;
-        if let ExprKind::Array(ref pieces) = arr.kind;
+        if let ExprKind::AddrOf(BorrowKind::Ref, _, arr) = args[0].kind;
+        if let ExprKind::Array(pieces) = arr.kind;
         if pieces.len() == 1;
         if let ExprKind::Lit(ref lit) = pieces[0].kind;
         if let LitKind::Str(ref s, _) = lit.node;
         // Argument 2 in `new_v1()`
-        if let ExprKind::AddrOf(BorrowKind::Ref, _, ref arg1) = args[1].kind;
-        if let ExprKind::Match(ref matchee, ref arms, MatchSource::Normal) = arg1.kind;
+        if let ExprKind::AddrOf(BorrowKind::Ref, _, arg1) = args[1].kind;
+        if let ExprKind::Match(matchee, arms, MatchSource::Normal) = arg1.kind;
         if arms.len() == 1;
-        if let ExprKind::Tup(ref tup) = matchee.kind;
+        if let ExprKind::Tup(tup) = matchee.kind;
         then {
             // `format!("foo")` expansion contains `match () { () => [], }`
             if tup.is_empty() {
@@ -152,16 +152,16 @@ fn on_new_v1_fmt<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<S
         if args.len() == 3;
         if check_unformatted(&args[2]);
         // Argument 1 in `new_v1_formatted()`
-        if let ExprKind::AddrOf(BorrowKind::Ref, _, ref arr) = args[0].kind;
-        if let ExprKind::Array(ref pieces) = arr.kind;
+        if let ExprKind::AddrOf(BorrowKind::Ref, _, arr) = args[0].kind;
+        if let ExprKind::Array(pieces) = arr.kind;
         if pieces.len() == 1;
         if let ExprKind::Lit(ref lit) = pieces[0].kind;
         if let LitKind::Str(..) = lit.node;
         // Argument 2 in `new_v1_formatted()`
-        if let ExprKind::AddrOf(BorrowKind::Ref, _, ref arg1) = args[1].kind;
-        if let ExprKind::Match(ref matchee, ref arms, MatchSource::Normal) = arg1.kind;
+        if let ExprKind::AddrOf(BorrowKind::Ref, _, arg1) = args[1].kind;
+        if let ExprKind::Match(matchee, arms, MatchSource::Normal) = arg1.kind;
         if arms.len() == 1;
-        if let ExprKind::Tup(ref tup) = matchee.kind;
+        if let ExprKind::Tup(tup) = matchee.kind;
         then {
             return on_argumentv1_new(cx, &tup[0], arms);
         }
@@ -182,14 +182,14 @@ fn on_new_v1_fmt<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<S
 /// ```
 fn check_unformatted(expr: &Expr<'_>) -> bool {
     if_chain! {
-        if let ExprKind::AddrOf(BorrowKind::Ref, _, ref expr) = expr.kind;
-        if let ExprKind::Array(ref exprs) = expr.kind;
+        if let ExprKind::AddrOf(BorrowKind::Ref, _, expr) = expr.kind;
+        if let ExprKind::Array(exprs) = expr.kind;
         if exprs.len() == 1;
         // struct `core::fmt::rt::v1::Argument`
-        if let ExprKind::Struct(_, ref fields, _) = exprs[0].kind;
+        if let ExprKind::Struct(_, fields, _) = exprs[0].kind;
         if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format);
         // struct `core::fmt::rt::v1::FormatSpec`
-        if let ExprKind::Struct(_, ref fields, _) = format_field.expr.kind;
+        if let ExprKind::Struct(_, fields, _) = format_field.expr.kind;
         if let Some(precision_field) = fields.iter().find(|f| f.ident.name == sym::precision);
         if let ExprKind::Path(ref precision_path) = precision_field.expr.kind;
         if last_path_segment(precision_path).ident.name == sym::Implied;
diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs
index b10e83c0ea8..48612befc68 100644
--- a/src/tools/clippy/clippy_lints/src/formatting.rs
+++ b/src/tools/clippy/clippy_lints/src/formatting.rs
@@ -217,9 +217,8 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) {
         if let Some(else_snippet) = snippet_opt(cx, else_span);
         if let Some(else_pos) = else_snippet.find("else");
         if else_snippet[else_pos..].contains('\n');
-        let else_desc = if is_if(else_) { "if" } else { "{..}" };
-
         then {
+            let else_desc = if is_if(else_) { "if" } else { "{..}" };
             span_lint_and_note(
                 cx,
                 SUSPICIOUS_ELSE_FORMATTING,
diff --git a/src/tools/clippy/clippy_lints/src/functions.rs b/src/tools/clippy/clippy_lints/src/functions.rs
deleted file mode 100644
index 5fe46065348..00000000000
--- a/src/tools/clippy/clippy_lints/src/functions.rs
+++ /dev/null
@@ -1,738 +0,0 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_then};
-use clippy_utils::source::{snippet, snippet_opt};
-use clippy_utils::ty::{is_must_use_ty, is_type_diagnostic_item, type_is_unsafe_function};
-use clippy_utils::{
-    attr_by_name, attrs::is_proc_macro, is_trait_impl_item, iter_input_pats, match_def_path, must_use_attr,
-    path_to_local, return_ty, trait_ref_of_method,
-};
-use if_chain::if_chain;
-use rustc_ast::ast::Attribute;
-use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::Applicability;
-use rustc_hir as hir;
-use rustc_hir::intravisit;
-use rustc_hir::{def::Res, def_id::DefId, QPath};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::hir::map::Map;
-use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{self, Ty};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::source_map::Span;
-use rustc_span::sym;
-use rustc_target::spec::abi::Abi;
-use rustc_typeck::hir_ty_to_ty;
-
-declare_clippy_lint! {
-    /// **What it does:** Checks for functions with too many parameters.
-    ///
-    /// **Why is this bad?** Functions with lots of parameters are considered bad
-    /// style and reduce readability (“what does the 5th parameter mean?”). Consider
-    /// grouping some parameters into a new type.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    /// ```rust
-    /// # struct Color;
-    /// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) {
-    ///     // ..
-    /// }
-    /// ```
-    pub TOO_MANY_ARGUMENTS,
-    complexity,
-    "functions with too many arguments"
-}
-
-declare_clippy_lint! {
-    /// **What it does:** Checks for functions with a large amount of lines.
-    ///
-    /// **Why is this bad?** Functions with a lot of lines are harder to understand
-    /// due to having to look at a larger amount of code to understand what the
-    /// function is doing. Consider splitting the body of the function into
-    /// multiple functions.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    /// ```rust
-    /// fn im_too_long() {
-    ///     println!("");
-    ///     // ... 100 more LoC
-    ///     println!("");
-    /// }
-    /// ```
-    pub TOO_MANY_LINES,
-    pedantic,
-    "functions with too many lines"
-}
-
-declare_clippy_lint! {
-    /// **What it does:** Checks for public functions that dereference raw pointer
-    /// arguments but are not marked unsafe.
-    ///
-    /// **Why is this bad?** The function should probably be marked `unsafe`, since
-    /// for an arbitrary raw pointer, there is no way of telling for sure if it is
-    /// valid.
-    ///
-    /// **Known problems:**
-    ///
-    /// * It does not check functions recursively so if the pointer is passed to a
-    /// private non-`unsafe` function which does the dereferencing, the lint won't
-    /// trigger.
-    /// * It only checks for arguments whose type are raw pointers, not raw pointers
-    /// got from an argument in some other way (`fn foo(bar: &[*const u8])` or
-    /// `some_argument.get_raw_ptr()`).
-    ///
-    /// **Example:**
-    /// ```rust,ignore
-    /// // Bad
-    /// pub fn foo(x: *const u8) {
-    ///     println!("{}", unsafe { *x });
-    /// }
-    ///
-    /// // Good
-    /// pub unsafe fn foo(x: *const u8) {
-    ///     println!("{}", unsafe { *x });
-    /// }
-    /// ```
-    pub NOT_UNSAFE_PTR_ARG_DEREF,
-    correctness,
-    "public functions dereferencing raw pointer arguments but not marked `unsafe`"
-}
-
-declare_clippy_lint! {
-    /// **What it does:** Checks for a [`#[must_use]`] attribute on
-    /// unit-returning functions and methods.
-    ///
-    /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
-    ///
-    /// **Why is this bad?** Unit values are useless. The attribute is likely
-    /// a remnant of a refactoring that removed the return type.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Examples:**
-    /// ```rust
-    /// #[must_use]
-    /// fn useless() { }
-    /// ```
-    pub MUST_USE_UNIT,
-    style,
-    "`#[must_use]` attribute on a unit-returning function / method"
-}
-
-declare_clippy_lint! {
-    /// **What it does:** Checks for a [`#[must_use]`] attribute without
-    /// further information on functions and methods that return a type already
-    /// marked as `#[must_use]`.
-    ///
-    /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
-    ///
-    /// **Why is this bad?** The attribute isn't needed. Not using the result
-    /// will already be reported. Alternatively, one can add some text to the
-    /// attribute to improve the lint message.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Examples:**
-    /// ```rust
-    /// #[must_use]
-    /// fn double_must_use() -> Result<(), ()> {
-    ///     unimplemented!();
-    /// }
-    /// ```
-    pub DOUBLE_MUST_USE,
-    style,
-    "`#[must_use]` attribute on a `#[must_use]`-returning function / method"
-}
-
-declare_clippy_lint! {
-    /// **What it does:** Checks for public functions that have no
-    /// [`#[must_use]`] attribute, but return something not already marked
-    /// must-use, have no mutable arg and mutate no statics.
-    ///
-    /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
-    ///
-    /// **Why is this bad?** Not bad at all, this lint just shows places where
-    /// you could add the attribute.
-    ///
-    /// **Known problems:** The lint only checks the arguments for mutable
-    /// types without looking if they are actually changed. On the other hand,
-    /// it also ignores a broad range of potentially interesting side effects,
-    /// because we cannot decide whether the programmer intends the function to
-    /// be called for the side effect or the result. Expect many false
-    /// positives. At least we don't lint if the result type is unit or already
-    /// `#[must_use]`.
-    ///
-    /// **Examples:**
-    /// ```rust
-    /// // this could be annotated with `#[must_use]`.
-    /// fn id<T>(t: T) -> T { t }
-    /// ```
-    pub MUST_USE_CANDIDATE,
-    pedantic,
-    "function or method that could take a `#[must_use]` attribute"
-}
-
-declare_clippy_lint! {
-    /// **What it does:** Checks for public functions that return a `Result`
-    /// with an `Err` type of `()`. It suggests using a custom type that
-    /// implements [`std::error::Error`].
-    ///
-    /// **Why is this bad?** Unit does not implement `Error` and carries no
-    /// further information about what went wrong.
-    ///
-    /// **Known problems:** Of course, this lint assumes that `Result` is used
-    /// for a fallible operation (which is after all the intended use). However
-    /// code may opt to (mis)use it as a basic two-variant-enum. In that case,
-    /// the suggestion is misguided, and the code should use a custom enum
-    /// instead.
-    ///
-    /// **Examples:**
-    /// ```rust
-    /// pub fn read_u8() -> Result<u8, ()> { Err(()) }
-    /// ```
-    /// should become
-    /// ```rust,should_panic
-    /// use std::fmt;
-    ///
-    /// #[derive(Debug)]
-    /// pub struct EndOfStream;
-    ///
-    /// impl fmt::Display for EndOfStream {
-    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    ///         write!(f, "End of Stream")
-    ///     }
-    /// }
-    ///
-    /// impl std::error::Error for EndOfStream { }
-    ///
-    /// pub fn read_u8() -> Result<u8, EndOfStream> { Err(EndOfStream) }
-    ///# fn main() {
-    ///#     read_u8().unwrap();
-    ///# }
-    /// ```
-    ///
-    /// Note that there are crates that simplify creating the error type, e.g.
-    /// [`thiserror`](https://docs.rs/thiserror).
-    pub RESULT_UNIT_ERR,
-    style,
-    "public function returning `Result` with an `Err` type of `()`"
-}
-
-#[derive(Copy, Clone)]
-pub struct Functions {
-    threshold: u64,
-    max_lines: u64,
-}
-
-impl Functions {
-    pub fn new(threshold: u64, max_lines: u64) -> Self {
-        Self { threshold, max_lines }
-    }
-}
-
-impl_lint_pass!(Functions => [
-    TOO_MANY_ARGUMENTS,
-    TOO_MANY_LINES,
-    NOT_UNSAFE_PTR_ARG_DEREF,
-    MUST_USE_UNIT,
-    DOUBLE_MUST_USE,
-    MUST_USE_CANDIDATE,
-    RESULT_UNIT_ERR,
-]);
-
-impl<'tcx> LateLintPass<'tcx> for Functions {
-    fn check_fn(
-        &mut self,
-        cx: &LateContext<'tcx>,
-        kind: intravisit::FnKind<'tcx>,
-        decl: &'tcx hir::FnDecl<'_>,
-        body: &'tcx hir::Body<'_>,
-        span: Span,
-        hir_id: hir::HirId,
-    ) {
-        let unsafety = match kind {
-            intravisit::FnKind::ItemFn(_, _, hir::FnHeader { unsafety, .. }, _) => unsafety,
-            intravisit::FnKind::Method(_, sig, _) => sig.header.unsafety,
-            intravisit::FnKind::Closure => return,
-        };
-
-        // don't warn for implementations, it's not their fault
-        if !is_trait_impl_item(cx, hir_id) {
-            // don't lint extern functions decls, it's not their fault either
-            match kind {
-                intravisit::FnKind::Method(
-                    _,
-                    &hir::FnSig {
-                        header: hir::FnHeader { abi: Abi::Rust, .. },
-                        ..
-                    },
-                    _,
-                )
-                | intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }, _) => {
-                    self.check_arg_number(cx, decl, span.with_hi(decl.output.span().hi()))
-                },
-                _ => {},
-            }
-        }
-
-        Self::check_raw_ptr(cx, unsafety, decl, body, hir_id);
-        self.check_line_number(cx, span, body);
-    }
-
-    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
-        let attrs = cx.tcx.hir().attrs(item.hir_id());
-        let attr = must_use_attr(attrs);
-        if let hir::ItemKind::Fn(ref sig, ref _generics, ref body_id) = item.kind {
-            let is_public = cx.access_levels.is_exported(item.hir_id());
-            let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
-            if is_public {
-                check_result_unit_err(cx, &sig.decl, item.span, fn_header_span);
-            }
-            if let Some(attr) = attr {
-                check_needless_must_use(cx, &sig.decl, item.hir_id(), item.span, fn_header_span, attr);
-                return;
-            }
-            if is_public && !is_proc_macro(cx.sess(), attrs) && attr_by_name(attrs, "no_mangle").is_none() {
-                check_must_use_candidate(
-                    cx,
-                    &sig.decl,
-                    cx.tcx.hir().body(*body_id),
-                    item.span,
-                    item.hir_id(),
-                    item.span.with_hi(sig.decl.output.span().hi()),
-                    "this function could have a `#[must_use]` attribute",
-                );
-            }
-        }
-    }
-
-    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
-        if let hir::ImplItemKind::Fn(ref sig, ref body_id) = item.kind {
-            let is_public = cx.access_levels.is_exported(item.hir_id());
-            let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
-            if is_public && trait_ref_of_method(cx, item.hir_id()).is_none() {
-                check_result_unit_err(cx, &sig.decl, item.span, fn_header_span);
-            }
-            let attrs = cx.tcx.hir().attrs(item.hir_id());
-            let attr = must_use_attr(attrs);
-            if let Some(attr) = attr {
-                check_needless_must_use(cx, &sig.decl, item.hir_id(), item.span, fn_header_span, attr);
-            } else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.hir_id()).is_none()
-            {
-                check_must_use_candidate(
-                    cx,
-                    &sig.decl,
-                    cx.tcx.hir().body(*body_id),
-                    item.span,
-                    item.hir_id(),
-                    item.span.with_hi(sig.decl.output.span().hi()),
-                    "this method could have a `#[must_use]` attribute",
-                );
-            }
-        }
-    }
-
-    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
-        if let hir::TraitItemKind::Fn(ref sig, ref eid) = item.kind {
-            // don't lint extern functions decls, it's not their fault
-            if sig.header.abi == Abi::Rust {
-                self.check_arg_number(cx, &sig.decl, item.span.with_hi(sig.decl.output.span().hi()));
-            }
-            let is_public = cx.access_levels.is_exported(item.hir_id());
-            let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
-            if is_public {
-                check_result_unit_err(cx, &sig.decl, item.span, fn_header_span);
-            }
-
-            let attrs = cx.tcx.hir().attrs(item.hir_id());
-            let attr = must_use_attr(attrs);
-            if let Some(attr) = attr {
-                check_needless_must_use(cx, &sig.decl, item.hir_id(), item.span, fn_header_span, attr);
-            }
-            if let hir::TraitFn::Provided(eid) = *eid {
-                let body = cx.tcx.hir().body(eid);
-                Self::check_raw_ptr(cx, sig.header.unsafety, &sig.decl, body, item.hir_id());
-
-                if attr.is_none() && is_public && !is_proc_macro(cx.sess(), attrs) {
-                    check_must_use_candidate(
-                        cx,
-                        &sig.decl,
-                        body,
-                        item.span,
-                        item.hir_id(),
-                        item.span.with_hi(sig.decl.output.span().hi()),
-                        "this method could have a `#[must_use]` attribute",
-                    );
-                }
-            }
-        }
-    }
-}
-
-impl<'tcx> Functions {
-    fn check_arg_number(self, cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, fn_span: Span) {
-        let args = decl.inputs.len() as u64;
-        if args > self.threshold {
-            span_lint(
-                cx,
-                TOO_MANY_ARGUMENTS,
-                fn_span,
-                &format!("this function has too many arguments ({}/{})", args, self.threshold),
-            );
-        }
-    }
-
-    fn check_line_number(self, cx: &LateContext<'_>, span: Span, body: &'tcx hir::Body<'_>) {
-        if in_external_macro(cx.sess(), span) {
-            return;
-        }
-
-        let code_snippet = snippet(cx, body.value.span, "..");
-        let mut line_count: u64 = 0;
-        let mut in_comment = false;
-        let mut code_in_line;
-
-        // Skip the surrounding function decl.
-        let start_brace_idx = code_snippet.find('{').map_or(0, |i| i + 1);
-        let end_brace_idx = code_snippet.rfind('}').unwrap_or_else(|| code_snippet.len());
-        let function_lines = code_snippet[start_brace_idx..end_brace_idx].lines();
-
-        for mut line in function_lines {
-            code_in_line = false;
-            loop {
-                line = line.trim_start();
-                if line.is_empty() {
-                    break;
-                }
-                if in_comment {
-                    if let Some(i) = line.find("*/") {
-                        line = &line[i + 2..];
-                        in_comment = false;
-                        continue;
-                    }
-                } else {
-                    let multi_idx = line.find("/*").unwrap_or_else(|| line.len());
-                    let single_idx = line.find("//").unwrap_or_else(|| line.len());
-                    code_in_line |= multi_idx > 0 && single_idx > 0;
-                    // Implies multi_idx is below line.len()
-                    if multi_idx < single_idx {
-                        line = &line[multi_idx + 2..];
-                        in_comment = true;
-                        continue;
-                    }
-                }
-                break;
-            }
-            if code_in_line {
-                line_count += 1;
-            }
-        }
-
-        if line_count > self.max_lines {
-            span_lint(
-                cx,
-                TOO_MANY_LINES,
-                span,
-                &format!("this function has too many lines ({}/{})", line_count, self.max_lines),
-            )
-        }
-    }
-
-    fn check_raw_ptr(
-        cx: &LateContext<'tcx>,
-        unsafety: hir::Unsafety,
-        decl: &'tcx hir::FnDecl<'_>,
-        body: &'tcx hir::Body<'_>,
-        hir_id: hir::HirId,
-    ) {
-        let expr = &body.value;
-        if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(hir_id) {
-            let raw_ptrs = iter_input_pats(decl, body)
-                .zip(decl.inputs.iter())
-                .filter_map(|(arg, ty)| raw_ptr_arg(arg, ty))
-                .collect::<FxHashSet<_>>();
-
-            if !raw_ptrs.is_empty() {
-                let typeck_results = cx.tcx.typeck_body(body.id());
-                let mut v = DerefVisitor {
-                    cx,
-                    ptrs: raw_ptrs,
-                    typeck_results,
-                };
-
-                intravisit::walk_expr(&mut v, expr);
-            }
-        }
-    }
-}
-
-fn check_result_unit_err(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, item_span: Span, fn_header_span: Span) {
-    if_chain! {
-        if !in_external_macro(cx.sess(), item_span);
-        if let hir::FnRetTy::Return(ref ty) = decl.output;
-        let ty = hir_ty_to_ty(cx.tcx, ty);
-        if is_type_diagnostic_item(cx, ty, sym::result_type);
-        if let ty::Adt(_, substs) = ty.kind();
-        let err_ty = substs.type_at(1);
-        if err_ty.is_unit();
-        then {
-            span_lint_and_help(
-                cx,
-                RESULT_UNIT_ERR,
-                fn_header_span,
-                "this returns a `Result<_, ()>",
-                None,
-                "use a custom Error type instead",
-            );
-        }
-    }
-}
-
-fn check_needless_must_use(
-    cx: &LateContext<'_>,
-    decl: &hir::FnDecl<'_>,
-    item_id: hir::HirId,
-    item_span: Span,
-    fn_header_span: Span,
-    attr: &Attribute,
-) {
-    if in_external_macro(cx.sess(), item_span) {
-        return;
-    }
-    if returns_unit(decl) {
-        span_lint_and_then(
-            cx,
-            MUST_USE_UNIT,
-            fn_header_span,
-            "this unit-returning function has a `#[must_use]` attribute",
-            |diag| {
-                diag.span_suggestion(
-                    attr.span,
-                    "remove the attribute",
-                    "".into(),
-                    Applicability::MachineApplicable,
-                );
-            },
-        );
-    } else if !attr.value_str().is_some() && is_must_use_ty(cx, return_ty(cx, item_id)) {
-        span_lint_and_help(
-            cx,
-            DOUBLE_MUST_USE,
-            fn_header_span,
-            "this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]`",
-            None,
-            "either add some descriptive text or remove the attribute",
-        );
-    }
-}
-
-fn check_must_use_candidate<'tcx>(
-    cx: &LateContext<'tcx>,
-    decl: &'tcx hir::FnDecl<'_>,
-    body: &'tcx hir::Body<'_>,
-    item_span: Span,
-    item_id: hir::HirId,
-    fn_span: Span,
-    msg: &str,
-) {
-    if has_mutable_arg(cx, body)
-        || mutates_static(cx, body)
-        || in_external_macro(cx.sess(), item_span)
-        || returns_unit(decl)
-        || !cx.access_levels.is_exported(item_id)
-        || is_must_use_ty(cx, return_ty(cx, item_id))
-    {
-        return;
-    }
-    span_lint_and_then(cx, MUST_USE_CANDIDATE, fn_span, msg, |diag| {
-        if let Some(snippet) = snippet_opt(cx, fn_span) {
-            diag.span_suggestion(
-                fn_span,
-                "add the attribute",
-                format!("#[must_use] {}", snippet),
-                Applicability::MachineApplicable,
-            );
-        }
-    });
-}
-
-fn returns_unit(decl: &hir::FnDecl<'_>) -> bool {
-    match decl.output {
-        hir::FnRetTy::DefaultReturn(_) => true,
-        hir::FnRetTy::Return(ref ty) => match ty.kind {
-            hir::TyKind::Tup(ref tys) => tys.is_empty(),
-            hir::TyKind::Never => true,
-            _ => false,
-        },
-    }
-}
-
-fn has_mutable_arg(cx: &LateContext<'_>, body: &hir::Body<'_>) -> bool {
-    let mut tys = FxHashSet::default();
-    body.params.iter().any(|param| is_mutable_pat(cx, &param.pat, &mut tys))
-}
-
-fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut FxHashSet<DefId>) -> bool {
-    if let hir::PatKind::Wild = pat.kind {
-        return false; // ignore `_` patterns
-    }
-    if cx.tcx.has_typeck_results(pat.hir_id.owner.to_def_id()) {
-        is_mutable_ty(cx, &cx.tcx.typeck(pat.hir_id.owner).pat_ty(pat), pat.span, tys)
-    } else {
-        false
-    }
-}
-
-static KNOWN_WRAPPER_TYS: &[&[&str]] = &[&["alloc", "rc", "Rc"], &["std", "sync", "Arc"]];
-
-fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &mut FxHashSet<DefId>) -> bool {
-    match *ty.kind() {
-        // primitive types are never mutable
-        ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false,
-        ty::Adt(ref adt, ref substs) => {
-            tys.insert(adt.did) && !ty.is_freeze(cx.tcx.at(span), cx.param_env)
-                || KNOWN_WRAPPER_TYS.iter().any(|path| match_def_path(cx, adt.did, path))
-                    && substs.types().any(|ty| is_mutable_ty(cx, ty, span, tys))
-        },
-        ty::Tuple(ref substs) => substs.types().any(|ty| is_mutable_ty(cx, ty, span, tys)),
-        ty::Array(ty, _) | ty::Slice(ty) => is_mutable_ty(cx, ty, span, tys),
-        ty::RawPtr(ty::TypeAndMut { ty, mutbl }) | ty::Ref(_, ty, mutbl) => {
-            mutbl == hir::Mutability::Mut || is_mutable_ty(cx, ty, span, tys)
-        },
-        // calling something constitutes a side effect, so return true on all callables
-        // also never calls need not be used, so return true for them, too
-        _ => true,
-    }
-}
-
-fn raw_ptr_arg(arg: &hir::Param<'_>, ty: &hir::Ty<'_>) -> Option<hir::HirId> {
-    if let (&hir::PatKind::Binding(_, id, _, _), &hir::TyKind::Ptr(_)) = (&arg.pat.kind, &ty.kind) {
-        Some(id)
-    } else {
-        None
-    }
-}
-
-struct DerefVisitor<'a, 'tcx> {
-    cx: &'a LateContext<'tcx>,
-    ptrs: FxHashSet<hir::HirId>,
-    typeck_results: &'a ty::TypeckResults<'tcx>,
-}
-
-impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
-    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
-        match expr.kind {
-            hir::ExprKind::Call(ref f, args) => {
-                let ty = self.typeck_results.expr_ty(f);
-
-                if type_is_unsafe_function(self.cx, ty) {
-                    for arg in args {
-                        self.check_arg(arg);
-                    }
-                }
-            },
-            hir::ExprKind::MethodCall(_, _, args, _) => {
-                let def_id = self.typeck_results.type_dependent_def_id(expr.hir_id).unwrap();
-                let base_type = self.cx.tcx.type_of(def_id);
-
-                if type_is_unsafe_function(self.cx, base_type) {
-                    for arg in args {
-                        self.check_arg(arg);
-                    }
-                }
-            },
-            hir::ExprKind::Unary(hir::UnOp::Deref, ref ptr) => self.check_arg(ptr),
-            _ => (),
-        }
-
-        intravisit::walk_expr(self, expr);
-    }
-
-    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-        intravisit::NestedVisitorMap::None
-    }
-}
-
-impl<'a, 'tcx> DerefVisitor<'a, 'tcx> {
-    fn check_arg(&self, ptr: &hir::Expr<'_>) {
-        if let Some(id) = path_to_local(ptr) {
-            if self.ptrs.contains(&id) {
-                span_lint(
-                    self.cx,
-                    NOT_UNSAFE_PTR_ARG_DEREF,
-                    ptr.span,
-                    "this public function dereferences a raw pointer but is not marked `unsafe`",
-                );
-            }
-        }
-    }
-}
-
-struct StaticMutVisitor<'a, 'tcx> {
-    cx: &'a LateContext<'tcx>,
-    mutates_static: bool,
-}
-
-impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
-    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
-        use hir::ExprKind::{AddrOf, Assign, AssignOp, Call, MethodCall};
-
-        if self.mutates_static {
-            return;
-        }
-        match expr.kind {
-            Call(_, args) | MethodCall(_, _, args, _) => {
-                let mut tys = FxHashSet::default();
-                for arg in args {
-                    if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
-                        && is_mutable_ty(
-                            self.cx,
-                            self.cx.tcx.typeck(arg.hir_id.owner).expr_ty(arg),
-                            arg.span,
-                            &mut tys,
-                        )
-                        && is_mutated_static(arg)
-                    {
-                        self.mutates_static = true;
-                        return;
-                    }
-                    tys.clear();
-                }
-            },
-            Assign(ref target, ..) | AssignOp(_, ref target, _) | AddrOf(_, hir::Mutability::Mut, ref target) => {
-                self.mutates_static |= is_mutated_static(target)
-            },
-            _ => {},
-        }
-    }
-
-    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-        intravisit::NestedVisitorMap::None
-    }
-}
-
-fn is_mutated_static(e: &hir::Expr<'_>) -> bool {
-    use hir::ExprKind::{Field, Index, Path};
-
-    match e.kind {
-        Path(QPath::Resolved(_, path)) => !matches!(path.res, Res::Local(_)),
-        Path(_) => true,
-        Field(ref inner, _) | Index(ref inner, _) => is_mutated_static(inner),
-        _ => false,
-    }
-}
-
-fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bool {
-    let mut v = StaticMutVisitor {
-        cx,
-        mutates_static: false,
-    };
-    intravisit::walk_expr(&mut v, &body.value);
-    v.mutates_static
-}
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs
new file mode 100644
index 00000000000..2beb9bc94bf
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs
@@ -0,0 +1,267 @@
+mod must_use;
+mod not_unsafe_ptr_arg_deref;
+mod result_unit_err;
+mod too_many_arguments;
+mod too_many_lines;
+
+use rustc_hir as hir;
+use rustc_hir::intravisit;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for functions with too many parameters.
+    ///
+    /// **Why is this bad?** Functions with lots of parameters are considered bad
+    /// style and reduce readability (“what does the 5th parameter mean?”). Consider
+    /// grouping some parameters into a new type.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # struct Color;
+    /// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) {
+    ///     // ..
+    /// }
+    /// ```
+    pub TOO_MANY_ARGUMENTS,
+    complexity,
+    "functions with too many arguments"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for functions with a large amount of lines.
+    ///
+    /// **Why is this bad?** Functions with a lot of lines are harder to understand
+    /// due to having to look at a larger amount of code to understand what the
+    /// function is doing. Consider splitting the body of the function into
+    /// multiple functions.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// fn im_too_long() {
+    ///     println!("");
+    ///     // ... 100 more LoC
+    ///     println!("");
+    /// }
+    /// ```
+    pub TOO_MANY_LINES,
+    pedantic,
+    "functions with too many lines"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for public functions that dereference raw pointer
+    /// arguments but are not marked `unsafe`.
+    ///
+    /// **Why is this bad?** The function should probably be marked `unsafe`, since
+    /// for an arbitrary raw pointer, there is no way of telling for sure if it is
+    /// valid.
+    ///
+    /// **Known problems:**
+    ///
+    /// * It does not check functions recursively so if the pointer is passed to a
+    /// private non-`unsafe` function which does the dereferencing, the lint won't
+    /// trigger.
+    /// * It only checks for arguments whose type are raw pointers, not raw pointers
+    /// got from an argument in some other way (`fn foo(bar: &[*const u8])` or
+    /// `some_argument.get_raw_ptr()`).
+    ///
+    /// **Example:**
+    /// ```rust,ignore
+    /// // Bad
+    /// pub fn foo(x: *const u8) {
+    ///     println!("{}", unsafe { *x });
+    /// }
+    ///
+    /// // Good
+    /// pub unsafe fn foo(x: *const u8) {
+    ///     println!("{}", unsafe { *x });
+    /// }
+    /// ```
+    pub NOT_UNSAFE_PTR_ARG_DEREF,
+    correctness,
+    "public functions dereferencing raw pointer arguments but not marked `unsafe`"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for a [`#[must_use]`] attribute on
+    /// unit-returning functions and methods.
+    ///
+    /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
+    ///
+    /// **Why is this bad?** Unit values are useless. The attribute is likely
+    /// a remnant of a refactoring that removed the return type.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Examples:**
+    /// ```rust
+    /// #[must_use]
+    /// fn useless() { }
+    /// ```
+    pub MUST_USE_UNIT,
+    style,
+    "`#[must_use]` attribute on a unit-returning function / method"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for a [`#[must_use]`] attribute without
+    /// further information on functions and methods that return a type already
+    /// marked as `#[must_use]`.
+    ///
+    /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
+    ///
+    /// **Why is this bad?** The attribute isn't needed. Not using the result
+    /// will already be reported. Alternatively, one can add some text to the
+    /// attribute to improve the lint message.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Examples:**
+    /// ```rust
+    /// #[must_use]
+    /// fn double_must_use() -> Result<(), ()> {
+    ///     unimplemented!();
+    /// }
+    /// ```
+    pub DOUBLE_MUST_USE,
+    style,
+    "`#[must_use]` attribute on a `#[must_use]`-returning function / method"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for public functions that have no
+    /// [`#[must_use]`] attribute, but return something not already marked
+    /// must-use, have no mutable arg and mutate no statics.
+    ///
+    /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
+    ///
+    /// **Why is this bad?** Not bad at all, this lint just shows places where
+    /// you could add the attribute.
+    ///
+    /// **Known problems:** The lint only checks the arguments for mutable
+    /// types without looking if they are actually changed. On the other hand,
+    /// it also ignores a broad range of potentially interesting side effects,
+    /// because we cannot decide whether the programmer intends the function to
+    /// be called for the side effect or the result. Expect many false
+    /// positives. At least we don't lint if the result type is unit or already
+    /// `#[must_use]`.
+    ///
+    /// **Examples:**
+    /// ```rust
+    /// // this could be annotated with `#[must_use]`.
+    /// fn id<T>(t: T) -> T { t }
+    /// ```
+    pub MUST_USE_CANDIDATE,
+    pedantic,
+    "function or method that could take a `#[must_use]` attribute"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for public functions that return a `Result`
+    /// with an `Err` type of `()`. It suggests using a custom type that
+    /// implements `std::error::Error`.
+    ///
+    /// **Why is this bad?** Unit does not implement `Error` and carries no
+    /// further information about what went wrong.
+    ///
+    /// **Known problems:** Of course, this lint assumes that `Result` is used
+    /// for a fallible operation (which is after all the intended use). However
+    /// code may opt to (mis)use it as a basic two-variant-enum. In that case,
+    /// the suggestion is misguided, and the code should use a custom enum
+    /// instead.
+    ///
+    /// **Examples:**
+    /// ```rust
+    /// pub fn read_u8() -> Result<u8, ()> { Err(()) }
+    /// ```
+    /// should become
+    /// ```rust,should_panic
+    /// use std::fmt;
+    ///
+    /// #[derive(Debug)]
+    /// pub struct EndOfStream;
+    ///
+    /// impl fmt::Display for EndOfStream {
+    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    ///         write!(f, "End of Stream")
+    ///     }
+    /// }
+    ///
+    /// impl std::error::Error for EndOfStream { }
+    ///
+    /// pub fn read_u8() -> Result<u8, EndOfStream> { Err(EndOfStream) }
+    ///# fn main() {
+    ///#     read_u8().unwrap();
+    ///# }
+    /// ```
+    ///
+    /// Note that there are crates that simplify creating the error type, e.g.
+    /// [`thiserror`](https://docs.rs/thiserror).
+    pub RESULT_UNIT_ERR,
+    style,
+    "public function returning `Result` with an `Err` type of `()`"
+}
+
+#[derive(Copy, Clone)]
+pub struct Functions {
+    too_many_arguments_threshold: u64,
+    too_many_lines_threshold: u64,
+}
+
+impl Functions {
+    pub fn new(too_many_arguments_threshold: u64, too_many_lines_threshold: u64) -> Self {
+        Self {
+            too_many_arguments_threshold,
+            too_many_lines_threshold,
+        }
+    }
+}
+
+impl_lint_pass!(Functions => [
+    TOO_MANY_ARGUMENTS,
+    TOO_MANY_LINES,
+    NOT_UNSAFE_PTR_ARG_DEREF,
+    MUST_USE_UNIT,
+    DOUBLE_MUST_USE,
+    MUST_USE_CANDIDATE,
+    RESULT_UNIT_ERR,
+]);
+
+impl<'tcx> LateLintPass<'tcx> for Functions {
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        kind: intravisit::FnKind<'tcx>,
+        decl: &'tcx hir::FnDecl<'_>,
+        body: &'tcx hir::Body<'_>,
+        span: Span,
+        hir_id: hir::HirId,
+    ) {
+        too_many_arguments::check_fn(cx, kind, decl, span, hir_id, self.too_many_arguments_threshold);
+        too_many_lines::check_fn(cx, span, body, self.too_many_lines_threshold);
+        not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, hir_id);
+    }
+
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
+        must_use::check_item(cx, item);
+        result_unit_err::check_item(cx, item);
+    }
+
+    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
+        must_use::check_impl_item(cx, item);
+        result_unit_err::check_impl_item(cx, item);
+    }
+
+    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
+        too_many_arguments::check_trait_item(cx, item, self.too_many_arguments_threshold);
+        not_unsafe_ptr_arg_deref::check_trait_item(cx, item);
+        must_use::check_trait_item(cx, item);
+        result_unit_err::check_trait_item(cx, item);
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
new file mode 100644
index 00000000000..20288427b4a
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -0,0 +1,272 @@
+use rustc_ast::ast::Attribute;
+use rustc_errors::Applicability;
+use rustc_hir::def_id::DefIdSet;
+use rustc_hir::{self as hir, def::Res, intravisit, QPath};
+use rustc_lint::{LateContext, LintContext};
+use rustc_middle::{
+    hir::map::Map,
+    lint::in_external_macro,
+    ty::{self, Ty},
+};
+use rustc_span::{sym, Span};
+
+use clippy_utils::attrs::is_proc_macro;
+use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
+use clippy_utils::source::snippet_opt;
+use clippy_utils::ty::is_must_use_ty;
+use clippy_utils::{match_def_path, must_use_attr, return_ty, trait_ref_of_method};
+
+use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT};
+
+pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
+    let attrs = cx.tcx.hir().attrs(item.hir_id());
+    let attr = must_use_attr(attrs);
+    if let hir::ItemKind::Fn(ref sig, ref _generics, ref body_id) = item.kind {
+        let is_public = cx.access_levels.is_exported(item.hir_id());
+        let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
+        if let Some(attr) = attr {
+            check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
+            return;
+        } else if is_public && !is_proc_macro(cx.sess(), attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) {
+            check_must_use_candidate(
+                cx,
+                sig.decl,
+                cx.tcx.hir().body(*body_id),
+                item.span,
+                item.hir_id(),
+                item.span.with_hi(sig.decl.output.span().hi()),
+                "this function could have a `#[must_use]` attribute",
+            );
+        }
+    }
+}
+
+pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
+    if let hir::ImplItemKind::Fn(ref sig, ref body_id) = item.kind {
+        let is_public = cx.access_levels.is_exported(item.hir_id());
+        let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
+        let attrs = cx.tcx.hir().attrs(item.hir_id());
+        let attr = must_use_attr(attrs);
+        if let Some(attr) = attr {
+            check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
+        } else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.hir_id()).is_none() {
+            check_must_use_candidate(
+                cx,
+                sig.decl,
+                cx.tcx.hir().body(*body_id),
+                item.span,
+                item.hir_id(),
+                item.span.with_hi(sig.decl.output.span().hi()),
+                "this method could have a `#[must_use]` attribute",
+            );
+        }
+    }
+}
+
+pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
+    if let hir::TraitItemKind::Fn(ref sig, ref eid) = item.kind {
+        let is_public = cx.access_levels.is_exported(item.hir_id());
+        let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
+
+        let attrs = cx.tcx.hir().attrs(item.hir_id());
+        let attr = must_use_attr(attrs);
+        if let Some(attr) = attr {
+            check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
+        } else if let hir::TraitFn::Provided(eid) = *eid {
+            let body = cx.tcx.hir().body(eid);
+            if attr.is_none() && is_public && !is_proc_macro(cx.sess(), attrs) {
+                check_must_use_candidate(
+                    cx,
+                    sig.decl,
+                    body,
+                    item.span,
+                    item.hir_id(),
+                    item.span.with_hi(sig.decl.output.span().hi()),
+                    "this method could have a `#[must_use]` attribute",
+                );
+            }
+        }
+    }
+}
+
+fn check_needless_must_use(
+    cx: &LateContext<'_>,
+    decl: &hir::FnDecl<'_>,
+    item_id: hir::HirId,
+    item_span: Span,
+    fn_header_span: Span,
+    attr: &Attribute,
+) {
+    if in_external_macro(cx.sess(), item_span) {
+        return;
+    }
+    if returns_unit(decl) {
+        span_lint_and_then(
+            cx,
+            MUST_USE_UNIT,
+            fn_header_span,
+            "this unit-returning function has a `#[must_use]` attribute",
+            |diag| {
+                diag.span_suggestion(
+                    attr.span,
+                    "remove the attribute",
+                    "".into(),
+                    Applicability::MachineApplicable,
+                );
+            },
+        );
+    } else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) {
+        span_lint_and_help(
+            cx,
+            DOUBLE_MUST_USE,
+            fn_header_span,
+            "this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]`",
+            None,
+            "either add some descriptive text or remove the attribute",
+        );
+    }
+}
+
+fn check_must_use_candidate<'tcx>(
+    cx: &LateContext<'tcx>,
+    decl: &'tcx hir::FnDecl<'_>,
+    body: &'tcx hir::Body<'_>,
+    item_span: Span,
+    item_id: hir::HirId,
+    fn_span: Span,
+    msg: &str,
+) {
+    if has_mutable_arg(cx, body)
+        || mutates_static(cx, body)
+        || in_external_macro(cx.sess(), item_span)
+        || returns_unit(decl)
+        || !cx.access_levels.is_exported(item_id)
+        || is_must_use_ty(cx, return_ty(cx, item_id))
+    {
+        return;
+    }
+    span_lint_and_then(cx, MUST_USE_CANDIDATE, fn_span, msg, |diag| {
+        if let Some(snippet) = snippet_opt(cx, fn_span) {
+            diag.span_suggestion(
+                fn_span,
+                "add the attribute",
+                format!("#[must_use] {}", snippet),
+                Applicability::MachineApplicable,
+            );
+        }
+    });
+}
+
+fn returns_unit(decl: &hir::FnDecl<'_>) -> bool {
+    match decl.output {
+        hir::FnRetTy::DefaultReturn(_) => true,
+        hir::FnRetTy::Return(ty) => match ty.kind {
+            hir::TyKind::Tup(tys) => tys.is_empty(),
+            hir::TyKind::Never => true,
+            _ => false,
+        },
+    }
+}
+
+fn has_mutable_arg(cx: &LateContext<'_>, body: &hir::Body<'_>) -> bool {
+    let mut tys = DefIdSet::default();
+    body.params.iter().any(|param| is_mutable_pat(cx, param.pat, &mut tys))
+}
+
+fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut DefIdSet) -> bool {
+    if let hir::PatKind::Wild = pat.kind {
+        return false; // ignore `_` patterns
+    }
+    if cx.tcx.has_typeck_results(pat.hir_id.owner.to_def_id()) {
+        is_mutable_ty(cx, cx.tcx.typeck(pat.hir_id.owner).pat_ty(pat), pat.span, tys)
+    } else {
+        false
+    }
+}
+
+static KNOWN_WRAPPER_TYS: &[&[&str]] = &[&["alloc", "rc", "Rc"], &["std", "sync", "Arc"]];
+
+fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &mut DefIdSet) -> bool {
+    match *ty.kind() {
+        // primitive types are never mutable
+        ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false,
+        ty::Adt(adt, substs) => {
+            tys.insert(adt.did) && !ty.is_freeze(cx.tcx.at(span), cx.param_env)
+                || KNOWN_WRAPPER_TYS.iter().any(|path| match_def_path(cx, adt.did, path))
+                    && substs.types().any(|ty| is_mutable_ty(cx, ty, span, tys))
+        },
+        ty::Tuple(substs) => substs.types().any(|ty| is_mutable_ty(cx, ty, span, tys)),
+        ty::Array(ty, _) | ty::Slice(ty) => is_mutable_ty(cx, ty, span, tys),
+        ty::RawPtr(ty::TypeAndMut { ty, mutbl }) | ty::Ref(_, ty, mutbl) => {
+            mutbl == hir::Mutability::Mut || is_mutable_ty(cx, ty, span, tys)
+        },
+        // calling something constitutes a side effect, so return true on all callables
+        // also never calls need not be used, so return true for them, too
+        _ => true,
+    }
+}
+
+struct StaticMutVisitor<'a, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+    mutates_static: bool,
+}
+
+impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
+        use hir::ExprKind::{AddrOf, Assign, AssignOp, Call, MethodCall};
+
+        if self.mutates_static {
+            return;
+        }
+        match expr.kind {
+            Call(_, args) | MethodCall(_, _, args, _) => {
+                let mut tys = DefIdSet::default();
+                for arg in args {
+                    if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
+                        && is_mutable_ty(
+                            self.cx,
+                            self.cx.tcx.typeck(arg.hir_id.owner).expr_ty(arg),
+                            arg.span,
+                            &mut tys,
+                        )
+                        && is_mutated_static(arg)
+                    {
+                        self.mutates_static = true;
+                        return;
+                    }
+                    tys.clear();
+                }
+            },
+            Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) => {
+                self.mutates_static |= is_mutated_static(target)
+            },
+            _ => {},
+        }
+    }
+
+    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
+        intravisit::NestedVisitorMap::None
+    }
+}
+
+fn is_mutated_static(e: &hir::Expr<'_>) -> bool {
+    use hir::ExprKind::{Field, Index, Path};
+
+    match e.kind {
+        Path(QPath::Resolved(_, path)) => !matches!(path.res, Res::Local(_)),
+        Path(_) => true,
+        Field(inner, _) | Index(inner, _) => is_mutated_static(inner),
+        _ => false,
+    }
+}
+
+fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bool {
+    let mut v = StaticMutVisitor {
+        cx,
+        mutates_static: false,
+    };
+    intravisit::walk_expr(&mut v, &body.value);
+    v.mutates_static
+}
diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
new file mode 100644
index 00000000000..b8ea6990866
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
@@ -0,0 +1,124 @@
+use rustc_hir::{self as hir, intravisit, HirIdSet};
+use rustc_lint::LateContext;
+use rustc_middle::{hir::map::Map, ty};
+
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::ty::type_is_unsafe_function;
+use clippy_utils::{iter_input_pats, path_to_local};
+
+use super::NOT_UNSAFE_PTR_ARG_DEREF;
+
+pub(super) fn check_fn(
+    cx: &LateContext<'tcx>,
+    kind: intravisit::FnKind<'tcx>,
+    decl: &'tcx hir::FnDecl<'tcx>,
+    body: &'tcx hir::Body<'tcx>,
+    hir_id: hir::HirId,
+) {
+    let unsafety = match kind {
+        intravisit::FnKind::ItemFn(_, _, hir::FnHeader { unsafety, .. }, _) => unsafety,
+        intravisit::FnKind::Method(_, sig, _) => sig.header.unsafety,
+        intravisit::FnKind::Closure => return,
+    };
+
+    check_raw_ptr(cx, unsafety, decl, body, hir_id);
+}
+
+pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
+    if let hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(eid)) = item.kind {
+        let body = cx.tcx.hir().body(eid);
+        check_raw_ptr(cx, sig.header.unsafety, sig.decl, body, item.hir_id());
+    }
+}
+
+fn check_raw_ptr(
+    cx: &LateContext<'tcx>,
+    unsafety: hir::Unsafety,
+    decl: &'tcx hir::FnDecl<'tcx>,
+    body: &'tcx hir::Body<'tcx>,
+    hir_id: hir::HirId,
+) {
+    let expr = &body.value;
+    if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(hir_id) {
+        let raw_ptrs = iter_input_pats(decl, body)
+            .zip(decl.inputs.iter())
+            .filter_map(|(arg, ty)| raw_ptr_arg(arg, ty))
+            .collect::<HirIdSet>();
+
+        if !raw_ptrs.is_empty() {
+            let typeck_results = cx.tcx.typeck_body(body.id());
+            let mut v = DerefVisitor {
+                cx,
+                ptrs: raw_ptrs,
+                typeck_results,
+            };
+
+            intravisit::walk_expr(&mut v, expr);
+        }
+    }
+}
+
+fn raw_ptr_arg(arg: &hir::Param<'_>, ty: &hir::Ty<'_>) -> Option<hir::HirId> {
+    if let (&hir::PatKind::Binding(_, id, _, _), &hir::TyKind::Ptr(_)) = (&arg.pat.kind, &ty.kind) {
+        Some(id)
+    } else {
+        None
+    }
+}
+
+struct DerefVisitor<'a, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+    ptrs: HirIdSet,
+    typeck_results: &'a ty::TypeckResults<'tcx>,
+}
+
+impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
+        match expr.kind {
+            hir::ExprKind::Call(f, args) => {
+                let ty = self.typeck_results.expr_ty(f);
+
+                if type_is_unsafe_function(self.cx, ty) {
+                    for arg in args {
+                        self.check_arg(arg);
+                    }
+                }
+            },
+            hir::ExprKind::MethodCall(_, _, args, _) => {
+                let def_id = self.typeck_results.type_dependent_def_id(expr.hir_id).unwrap();
+                let base_type = self.cx.tcx.type_of(def_id);
+
+                if type_is_unsafe_function(self.cx, base_type) {
+                    for arg in args {
+                        self.check_arg(arg);
+                    }
+                }
+            },
+            hir::ExprKind::Unary(hir::UnOp::Deref, ptr) => self.check_arg(ptr),
+            _ => (),
+        }
+
+        intravisit::walk_expr(self, expr);
+    }
+
+    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
+        intravisit::NestedVisitorMap::None
+    }
+}
+
+impl<'a, 'tcx> DerefVisitor<'a, 'tcx> {
+    fn check_arg(&self, ptr: &hir::Expr<'_>) {
+        if let Some(id) = path_to_local(ptr) {
+            if self.ptrs.contains(&id) {
+                span_lint(
+                    self.cx,
+                    NOT_UNSAFE_PTR_ARG_DEREF,
+                    ptr.span,
+                    "this public function dereferences a raw pointer but is not marked `unsafe`",
+                );
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/functions/result_unit_err.rs b/src/tools/clippy/clippy_lints/src/functions/result_unit_err.rs
new file mode 100644
index 00000000000..c073f312d38
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/functions/result_unit_err.rs
@@ -0,0 +1,66 @@
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty;
+use rustc_span::{sym, Span};
+use rustc_typeck::hir_ty_to_ty;
+
+use if_chain::if_chain;
+
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::trait_ref_of_method;
+use clippy_utils::ty::is_type_diagnostic_item;
+
+use super::RESULT_UNIT_ERR;
+
+pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
+    if let hir::ItemKind::Fn(ref sig, ref _generics, _) = item.kind {
+        let is_public = cx.access_levels.is_exported(item.hir_id());
+        let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
+        if is_public {
+            check_result_unit_err(cx, sig.decl, item.span, fn_header_span);
+        }
+    }
+}
+
+pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
+    if let hir::ImplItemKind::Fn(ref sig, _) = item.kind {
+        let is_public = cx.access_levels.is_exported(item.hir_id());
+        let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
+        if is_public && trait_ref_of_method(cx, item.hir_id()).is_none() {
+            check_result_unit_err(cx, sig.decl, item.span, fn_header_span);
+        }
+    }
+}
+
+pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
+    if let hir::TraitItemKind::Fn(ref sig, _) = item.kind {
+        let is_public = cx.access_levels.is_exported(item.hir_id());
+        let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
+        if is_public {
+            check_result_unit_err(cx, sig.decl, item.span, fn_header_span);
+        }
+    }
+}
+
+fn check_result_unit_err(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, item_span: Span, fn_header_span: Span) {
+    if_chain! {
+        if !in_external_macro(cx.sess(), item_span);
+        if let hir::FnRetTy::Return(ty) = decl.output;
+        let ty = hir_ty_to_ty(cx.tcx, ty);
+        if is_type_diagnostic_item(cx, ty, sym::result_type);
+        if let ty::Adt(_, substs) = ty.kind();
+        let err_ty = substs.type_at(1);
+        if err_ty.is_unit();
+        then {
+            span_lint_and_help(
+                cx,
+                RESULT_UNIT_ERR,
+                fn_header_span,
+                "this returns a `Result<_, ()>`",
+                None,
+                "use a custom `Error` type instead",
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs
new file mode 100644
index 00000000000..63a14d8d4cd
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs
@@ -0,0 +1,73 @@
+use rustc_hir::{self as hir, intravisit};
+use rustc_lint::LateContext;
+use rustc_span::Span;
+use rustc_target::spec::abi::Abi;
+
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::is_trait_impl_item;
+
+use super::TOO_MANY_ARGUMENTS;
+
+pub(super) fn check_fn(
+    cx: &LateContext<'tcx>,
+    kind: intravisit::FnKind<'tcx>,
+    decl: &'tcx hir::FnDecl<'_>,
+    span: Span,
+    hir_id: hir::HirId,
+    too_many_arguments_threshold: u64,
+) {
+    // don't warn for implementations, it's not their fault
+    if !is_trait_impl_item(cx, hir_id) {
+        // don't lint extern functions decls, it's not their fault either
+        match kind {
+            intravisit::FnKind::Method(
+                _,
+                &hir::FnSig {
+                    header: hir::FnHeader { abi: Abi::Rust, .. },
+                    ..
+                },
+                _,
+            )
+            | intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }, _) => check_arg_number(
+                cx,
+                decl,
+                span.with_hi(decl.output.span().hi()),
+                too_many_arguments_threshold,
+            ),
+            _ => {},
+        }
+    }
+}
+
+pub(super) fn check_trait_item(
+    cx: &LateContext<'tcx>,
+    item: &'tcx hir::TraitItem<'_>,
+    too_many_arguments_threshold: u64,
+) {
+    if let hir::TraitItemKind::Fn(ref sig, _) = item.kind {
+        // don't lint extern functions decls, it's not their fault
+        if sig.header.abi == Abi::Rust {
+            check_arg_number(
+                cx,
+                sig.decl,
+                item.span.with_hi(sig.decl.output.span().hi()),
+                too_many_arguments_threshold,
+            );
+        }
+    }
+}
+
+fn check_arg_number(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, fn_span: Span, too_many_arguments_threshold: u64) {
+    let args = decl.inputs.len() as u64;
+    if args > too_many_arguments_threshold {
+        span_lint(
+            cx,
+            TOO_MANY_ARGUMENTS,
+            fn_span,
+            &format!(
+                "this function has too many arguments ({}/{})",
+                args, too_many_arguments_threshold
+            ),
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
new file mode 100644
index 00000000000..aa5494d5a7d
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
@@ -0,0 +1,68 @@
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_span::Span;
+
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::source::snippet;
+
+use super::TOO_MANY_LINES;
+
+pub(super) fn check_fn(cx: &LateContext<'_>, span: Span, body: &'tcx hir::Body<'_>, too_many_lines_threshold: u64) {
+    if in_external_macro(cx.sess(), span) {
+        return;
+    }
+
+    let code_snippet = snippet(cx, body.value.span, "..");
+    let mut line_count: u64 = 0;
+    let mut in_comment = false;
+    let mut code_in_line;
+
+    // Skip the surrounding function decl.
+    let start_brace_idx = code_snippet.find('{').map_or(0, |i| i + 1);
+    let end_brace_idx = code_snippet.rfind('}').unwrap_or_else(|| code_snippet.len());
+    let function_lines = code_snippet[start_brace_idx..end_brace_idx].lines();
+
+    for mut line in function_lines {
+        code_in_line = false;
+        loop {
+            line = line.trim_start();
+            if line.is_empty() {
+                break;
+            }
+            if in_comment {
+                if let Some(i) = line.find("*/") {
+                    line = &line[i + 2..];
+                    in_comment = false;
+                    continue;
+                }
+            } else {
+                let multi_idx = line.find("/*").unwrap_or_else(|| line.len());
+                let single_idx = line.find("//").unwrap_or_else(|| line.len());
+                code_in_line |= multi_idx > 0 && single_idx > 0;
+                // Implies multi_idx is below line.len()
+                if multi_idx < single_idx {
+                    line = &line[multi_idx + 2..];
+                    in_comment = true;
+                    continue;
+                }
+            }
+            break;
+        }
+        if code_in_line {
+            line_count += 1;
+        }
+    }
+
+    if line_count > too_many_lines_threshold {
+        span_lint(
+            cx,
+            TOO_MANY_LINES,
+            span,
+            &format!(
+                "this function has too many lines ({}/{})",
+                line_count, too_many_lines_threshold
+            ),
+        )
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/get_last_with_len.rs b/src/tools/clippy/clippy_lints/src/get_last_with_len.rs
index cbcef567c53..3707e792177 100644
--- a/src/tools/clippy/clippy_lints/src/get_last_with_len.rs
+++ b/src/tools/clippy/clippy_lints/src/get_last_with_len.rs
@@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for GetLastWithLen {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
             // Is a method call
-            if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind;
+            if let ExprKind::MethodCall(path, _, args, _) = expr.kind;
 
             // Method name is "get"
             if path.ident.name == sym!(get);
diff --git a/src/tools/clippy/clippy_lints/src/identity_op.rs b/src/tools/clippy/clippy_lints/src/identity_op.rs
index 8bed5e1bf64..366b3b46a8a 100644
--- a/src/tools/clippy/clippy_lints/src/identity_op.rs
+++ b/src/tools/clippy/clippy_lints/src/identity_op.rs
@@ -35,7 +35,7 @@ impl<'tcx> LateLintPass<'tcx> for IdentityOp {
         if e.span.from_expansion() {
             return;
         }
-        if let ExprKind::Binary(cmp, ref left, ref right) = e.kind {
+        if let ExprKind::Binary(cmp, left, right) = e.kind {
             if is_allowed(cx, cmp, left, right) {
                 return;
             }
diff --git a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
index 4aab43256bf..f661f7ede82 100644
--- a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
+++ b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
@@ -55,8 +55,8 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
             cx,
         };
         if let ExprKind::Match(
-            ref op,
-            ref arms,
+            op,
+            arms,
             MatchSource::IfLetDesugar {
                 contains_else_clause: true,
             },
@@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
         {
             op_visit.visit_expr(op);
             if op_visit.mutex_lock_called {
-                for arm in *arms {
+                for arm in arms {
                     arm_visit.visit_arm(arm);
                 }
 
@@ -94,13 +94,10 @@ impl<'tcx> Visitor<'tcx> for OppVisitor<'_, 'tcx> {
     type Map = Map<'tcx>;
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
-        if_chain! {
-            if let Some(mutex) = is_mutex_lock_call(self.cx, expr);
-            then {
-                self.found_mutex = Some(mutex);
-                self.mutex_lock_called = true;
-                return;
-            }
+        if let Some(mutex) = is_mutex_lock_call(self.cx, expr) {
+            self.found_mutex = Some(mutex);
+            self.mutex_lock_called = true;
+            return;
         }
         visit::walk_expr(self, expr);
     }
@@ -121,13 +118,10 @@ impl<'tcx> Visitor<'tcx> for ArmVisitor<'_, 'tcx> {
     type Map = Map<'tcx>;
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
-        if_chain! {
-            if let Some(mutex) = is_mutex_lock_call(self.cx, expr);
-            then {
-                self.found_mutex = Some(mutex);
-                self.mutex_lock_called = true;
-                return;
-            }
+        if let Some(mutex) = is_mutex_lock_call(self.cx, expr) {
+            self.found_mutex = Some(mutex);
+            self.mutex_lock_called = true;
+            return;
         }
         visit::walk_expr(self, expr);
     }
diff --git a/src/tools/clippy/clippy_lints/src/if_let_some_result.rs b/src/tools/clippy/clippy_lints/src/if_let_some_result.rs
index 6e9280c8c7e..611da3744ee 100644
--- a/src/tools/clippy/clippy_lints/src/if_let_some_result.rs
+++ b/src/tools/clippy/clippy_lints/src/if_let_some_result.rs
@@ -44,9 +44,9 @@ declare_lint_pass!(OkIfLet => [IF_LET_SOME_RESULT]);
 impl<'tcx> LateLintPass<'tcx> for OkIfLet {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! { //begin checking variables
-            if let ExprKind::Match(ref op, ref body, MatchSource::IfLetDesugar { .. }) = expr.kind; //test if expr is if let
-            if let ExprKind::MethodCall(_, ok_span, ref result_types, _) = op.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
-            if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _)  = body[0].pat.kind; //get operation
+            if let ExprKind::Match(op, body, MatchSource::IfLetDesugar { .. }) = expr.kind; //test if expr is if let
+            if let ExprKind::MethodCall(_, ok_span, result_types, _) = op.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
+            if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _)  = body[0].pat.kind; //get operation
             if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
             if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&result_types[0]), sym::result_type);
             if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some";
diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
index 0b5bf060d4c..ee16519692f 100644
--- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
+++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
@@ -72,15 +72,15 @@ impl LateLintPass<'_> for IfThenSomeElseNone {
         }
 
         if_chain! {
-            if let ExprKind::If(ref cond, ref then, Some(ref els)) = expr.kind;
-            if let ExprKind::Block(ref then_block, _) = then.kind;
-            if let Some(ref then_expr) = then_block.expr;
-            if let ExprKind::Call(ref then_call, [then_arg]) = then_expr.kind;
+            if let ExprKind::If(cond, then, Some(els)) = expr.kind;
+            if let ExprKind::Block(then_block, _) = then.kind;
+            if let Some(then_expr) = then_block.expr;
+            if let ExprKind::Call(then_call, [then_arg]) = then_expr.kind;
             if let ExprKind::Path(ref then_call_qpath) = then_call.kind;
             if match_qpath(then_call_qpath, &clippy_utils::paths::OPTION_SOME);
-            if let ExprKind::Block(ref els_block, _) = els.kind;
+            if let ExprKind::Block(els_block, _) = els.kind;
             if els_block.stmts.is_empty();
-            if let Some(ref els_expr) = els_block.expr;
+            if let Some(els_expr) = els_block.expr;
             if let ExprKind::Path(ref els_call_qpath) = els_expr.kind;
             if match_qpath(els_call_qpath, &clippy_utils::paths::OPTION_NONE);
             then {
diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
new file mode 100644
index 00000000000..77a38544edc
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
@@ -0,0 +1,377 @@
+#![allow(rustc::default_hash_types)]
+
+use std::borrow::Cow;
+use std::collections::BTreeMap;
+
+use rustc_errors::DiagnosticBuilder;
+use rustc_hir as hir;
+use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, NestedVisitorMap, Visitor};
+use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::hir::map::Map;
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty::{Ty, TyS, TypeckResults};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::source_map::Span;
+use rustc_span::symbol::sym;
+use rustc_typeck::hir_ty_to_ty;
+
+use if_chain::if_chain;
+
+use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::paths;
+use clippy_utils::source::{snippet, snippet_opt};
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{differing_macro_contexts, match_path};
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for public `impl` or `fn` missing generalization
+    /// over different hashers and implicitly defaulting to the default hashing
+    /// algorithm (`SipHash`).
+    ///
+    /// **Why is this bad?** `HashMap` or `HashSet` with custom hashers cannot be
+    /// used with them.
+    ///
+    /// **Known problems:** Suggestions for replacing constructors can contain
+    /// false-positives. Also applying suggestions can require modification of other
+    /// pieces of code, possibly including external crates.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # use std::collections::HashMap;
+    /// # use std::hash::{Hash, BuildHasher};
+    /// # trait Serialize {};
+    /// impl<K: Hash + Eq, V> Serialize for HashMap<K, V> { }
+    ///
+    /// pub fn foo(map: &mut HashMap<i32, i32>) { }
+    /// ```
+    /// could be rewritten as
+    /// ```rust
+    /// # use std::collections::HashMap;
+    /// # use std::hash::{Hash, BuildHasher};
+    /// # trait Serialize {};
+    /// impl<K: Hash + Eq, V, S: BuildHasher> Serialize for HashMap<K, V, S> { }
+    ///
+    /// pub fn foo<S: BuildHasher>(map: &mut HashMap<i32, i32, S>) { }
+    /// ```
+    pub IMPLICIT_HASHER,
+    pedantic,
+    "missing generalization over different hashers"
+}
+
+declare_lint_pass!(ImplicitHasher => [IMPLICIT_HASHER]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
+    #[allow(clippy::cast_possible_truncation, clippy::too_many_lines)]
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
+        use rustc_span::BytePos;
+
+        fn suggestion<'tcx>(
+            cx: &LateContext<'tcx>,
+            diag: &mut DiagnosticBuilder<'_>,
+            generics_span: Span,
+            generics_suggestion_span: Span,
+            target: &ImplicitHasherType<'_>,
+            vis: ImplicitHasherConstructorVisitor<'_, '_, '_>,
+        ) {
+            let generics_snip = snippet(cx, generics_span, "");
+            // trim `<` `>`
+            let generics_snip = if generics_snip.is_empty() {
+                ""
+            } else {
+                &generics_snip[1..generics_snip.len() - 1]
+            };
+
+            multispan_sugg(
+                diag,
+                "consider adding a type parameter",
+                vec![
+                    (
+                        generics_suggestion_span,
+                        format!(
+                            "<{}{}S: ::std::hash::BuildHasher{}>",
+                            generics_snip,
+                            if generics_snip.is_empty() { "" } else { ", " },
+                            if vis.suggestions.is_empty() {
+                                ""
+                            } else {
+                                // request users to add `Default` bound so that generic constructors can be used
+                                " + Default"
+                            },
+                        ),
+                    ),
+                    (
+                        target.span(),
+                        format!("{}<{}, S>", target.type_name(), target.type_arguments(),),
+                    ),
+                ],
+            );
+
+            if !vis.suggestions.is_empty() {
+                multispan_sugg(diag, "...and use generic constructor", vis.suggestions);
+            }
+        }
+
+        if !cx.access_levels.is_exported(item.hir_id()) {
+            return;
+        }
+
+        match item.kind {
+            ItemKind::Impl(ref impl_) => {
+                let mut vis = ImplicitHasherTypeVisitor::new(cx);
+                vis.visit_ty(impl_.self_ty);
+
+                for target in &vis.found {
+                    if differing_macro_contexts(item.span, target.span()) {
+                        return;
+                    }
+
+                    let generics_suggestion_span = impl_.generics.span.substitute_dummy({
+                        let pos = snippet_opt(cx, item.span.until(target.span()))
+                            .and_then(|snip| Some(item.span.lo() + BytePos(snip.find("impl")? as u32 + 4)));
+                        if let Some(pos) = pos {
+                            Span::new(pos, pos, item.span.data().ctxt)
+                        } else {
+                            return;
+                        }
+                    });
+
+                    let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
+                    for item in impl_.items.iter().map(|item| cx.tcx.hir().impl_item(item.id)) {
+                        ctr_vis.visit_impl_item(item);
+                    }
+
+                    span_lint_and_then(
+                        cx,
+                        IMPLICIT_HASHER,
+                        target.span(),
+                        &format!(
+                            "impl for `{}` should be generalized over different hashers",
+                            target.type_name()
+                        ),
+                        move |diag| {
+                            suggestion(cx, diag, impl_.generics.span, generics_suggestion_span, target, ctr_vis);
+                        },
+                    );
+                }
+            },
+            ItemKind::Fn(ref sig, ref generics, body_id) => {
+                let body = cx.tcx.hir().body(body_id);
+
+                for ty in sig.decl.inputs {
+                    let mut vis = ImplicitHasherTypeVisitor::new(cx);
+                    vis.visit_ty(ty);
+
+                    for target in &vis.found {
+                        if in_external_macro(cx.sess(), generics.span) {
+                            continue;
+                        }
+                        let generics_suggestion_span = generics.span.substitute_dummy({
+                            let pos = snippet_opt(cx, item.span.until(body.params[0].pat.span))
+                                .and_then(|snip| {
+                                    let i = snip.find("fn")?;
+                                    Some(item.span.lo() + BytePos((i + (&snip[i..]).find('(')?) as u32))
+                                })
+                                .expect("failed to create span for type parameters");
+                            Span::new(pos, pos, item.span.data().ctxt)
+                        });
+
+                        let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
+                        ctr_vis.visit_body(body);
+
+                        span_lint_and_then(
+                            cx,
+                            IMPLICIT_HASHER,
+                            target.span(),
+                            &format!(
+                                "parameter of type `{}` should be generalized over different hashers",
+                                target.type_name()
+                            ),
+                            move |diag| {
+                                suggestion(cx, diag, generics.span, generics_suggestion_span, target, ctr_vis);
+                            },
+                        );
+                    }
+                }
+            },
+            _ => {},
+        }
+    }
+}
+
+enum ImplicitHasherType<'tcx> {
+    HashMap(Span, Ty<'tcx>, Cow<'static, str>, Cow<'static, str>),
+    HashSet(Span, Ty<'tcx>, Cow<'static, str>),
+}
+
+impl<'tcx> ImplicitHasherType<'tcx> {
+    /// Checks that `ty` is a target type without a `BuildHasher`.
+    fn new(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'_>) -> Option<Self> {
+        if let TyKind::Path(QPath::Resolved(None, path)) = hir_ty.kind {
+            let params: Vec<_> = path
+                .segments
+                .last()
+                .as_ref()?
+                .args
+                .as_ref()?
+                .args
+                .iter()
+                .filter_map(|arg| match arg {
+                    GenericArg::Type(ty) => Some(ty),
+                    _ => None,
+                })
+                .collect();
+            let params_len = params.len();
+
+            let ty = hir_ty_to_ty(cx.tcx, hir_ty);
+
+            if is_type_diagnostic_item(cx, ty, sym::hashmap_type) && params_len == 2 {
+                Some(ImplicitHasherType::HashMap(
+                    hir_ty.span,
+                    ty,
+                    snippet(cx, params[0].span, "K"),
+                    snippet(cx, params[1].span, "V"),
+                ))
+            } else if is_type_diagnostic_item(cx, ty, sym::hashset_type) && params_len == 1 {
+                Some(ImplicitHasherType::HashSet(
+                    hir_ty.span,
+                    ty,
+                    snippet(cx, params[0].span, "T"),
+                ))
+            } else {
+                None
+            }
+        } else {
+            None
+        }
+    }
+
+    fn type_name(&self) -> &'static str {
+        match *self {
+            ImplicitHasherType::HashMap(..) => "HashMap",
+            ImplicitHasherType::HashSet(..) => "HashSet",
+        }
+    }
+
+    fn type_arguments(&self) -> String {
+        match *self {
+            ImplicitHasherType::HashMap(.., ref k, ref v) => format!("{}, {}", k, v),
+            ImplicitHasherType::HashSet(.., ref t) => format!("{}", t),
+        }
+    }
+
+    fn ty(&self) -> Ty<'tcx> {
+        match *self {
+            ImplicitHasherType::HashMap(_, ty, ..) | ImplicitHasherType::HashSet(_, ty, ..) => ty,
+        }
+    }
+
+    fn span(&self) -> Span {
+        match *self {
+            ImplicitHasherType::HashMap(span, ..) | ImplicitHasherType::HashSet(span, ..) => span,
+        }
+    }
+}
+
+struct ImplicitHasherTypeVisitor<'a, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+    found: Vec<ImplicitHasherType<'tcx>>,
+}
+
+impl<'a, 'tcx> ImplicitHasherTypeVisitor<'a, 'tcx> {
+    fn new(cx: &'a LateContext<'tcx>) -> Self {
+        Self { cx, found: vec![] }
+    }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'a, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn visit_ty(&mut self, t: &'tcx hir::Ty<'_>) {
+        if let Some(target) = ImplicitHasherType::new(self.cx, t) {
+            self.found.push(target);
+        }
+
+        walk_ty(self, t);
+    }
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::None
+    }
+}
+
+/// Looks for default-hasher-dependent constructors like `HashMap::new`.
+struct ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+    maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
+    target: &'b ImplicitHasherType<'tcx>,
+    suggestions: BTreeMap<Span, String>,
+}
+
+impl<'a, 'b, 'tcx> ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
+    fn new(cx: &'a LateContext<'tcx>, target: &'b ImplicitHasherType<'tcx>) -> Self {
+        Self {
+            cx,
+            maybe_typeck_results: cx.maybe_typeck_results(),
+            target,
+            suggestions: BTreeMap::new(),
+        }
+    }
+}
+
+impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn visit_body(&mut self, body: &'tcx Body<'_>) {
+        let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body.id()));
+        walk_body(self, body);
+        self.maybe_typeck_results = old_maybe_typeck_results;
+    }
+
+    fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
+        if_chain! {
+            if let ExprKind::Call(fun, args) = e.kind;
+            if let ExprKind::Path(QPath::TypeRelative(ty, method)) = fun.kind;
+            if let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind;
+            then {
+                if !TyS::same_type(self.target.ty(), self.maybe_typeck_results.unwrap().expr_ty(e)) {
+                    return;
+                }
+
+                if match_path(ty_path, &paths::HASHMAP) {
+                    if method.ident.name == sym::new {
+                        self.suggestions
+                            .insert(e.span, "HashMap::default()".to_string());
+                    } else if method.ident.name == sym!(with_capacity) {
+                        self.suggestions.insert(
+                            e.span,
+                            format!(
+                                "HashMap::with_capacity_and_hasher({}, Default::default())",
+                                snippet(self.cx, args[0].span, "capacity"),
+                            ),
+                        );
+                    }
+                } else if match_path(ty_path, &paths::HASHSET) {
+                    if method.ident.name == sym::new {
+                        self.suggestions
+                            .insert(e.span, "HashSet::default()".to_string());
+                    } else if method.ident.name == sym!(with_capacity) {
+                        self.suggestions.insert(
+                            e.span,
+                            format!(
+                                "HashSet::with_capacity_and_hasher({}, Default::default())",
+                                snippet(self.cx, args[0].span, "capacity"),
+                            ),
+                        );
+                    }
+                }
+            }
+        }
+
+        walk_expr(self, e);
+    }
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs
index 6863645a92d..6b379b0d59b 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_return.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs
@@ -100,10 +100,10 @@ fn expr_match(cx: &LateContext<'_>, expr: &Expr<'_>) {
 
             if check_all_arms {
                 for arm in arms {
-                    expr_match(cx, &arm.body);
+                    expr_match(cx, arm.body);
                 }
             } else {
-                expr_match(cx, &arms.first().expect("`if let` doesn't have a single arm").body);
+                expr_match(cx, arms.first().expect("`if let` doesn't have a single arm").body);
             }
         },
         // skip if it already has a return statement
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
index 5207c628987..cba3183e869 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
@@ -46,21 +46,21 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
             if let ExprKind::If(cond, then, None) = &expr.kind;
 
             // Check if the conditional expression is a binary operation
-            if let ExprKind::Binary(ref cond_op, ref cond_left, ref cond_right) = cond.kind;
+            if let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind;
 
             // Ensure that the binary operator is >, != and <
             if BinOpKind::Ne == cond_op.node || BinOpKind::Gt == cond_op.node || BinOpKind::Lt == cond_op.node;
 
             // Check if the true condition block has only one statement
-            if let ExprKind::Block(ref block, _) = then.kind;
+            if let ExprKind::Block(block, _) = then.kind;
             if block.stmts.len() == 1 && block.expr.is_none();
 
             // Check if assign operation is done
-            if let StmtKind::Semi(ref e) = block.stmts[0].kind;
+            if let StmtKind::Semi(e) = block.stmts[0].kind;
             if let Some(target) = subtracts_one(cx, e);
 
             // Extracting out the variable name
-            if let ExprKind::Path(QPath::Resolved(_, ref ares_path)) = target.kind;
+            if let ExprKind::Path(QPath::Resolved(_, ares_path)) = target.kind;
 
             then {
                 // Handle symmetric conditions in the if statement
@@ -104,7 +104,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
                             print_lint_and_sugg(cx, &var_name, expr);
                         };
                     },
-                    ExprKind::Call(ref func, _) => {
+                    ExprKind::Call(func, _) => {
                         if let ExprKind::Path(ref cond_num_path) = func.kind {
                             if INT_TYPES.iter().any(|int_type| match_qpath(cond_num_path, &[int_type, "min_value"])) {
                                 print_lint_and_sugg(cx, &var_name, expr);
@@ -120,7 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
 
 fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &Expr<'a>) -> Option<&'a Expr<'a>> {
     match expr.kind {
-        ExprKind::AssignOp(ref op1, ref target, ref value) => {
+        ExprKind::AssignOp(ref op1, target, value) => {
             if_chain! {
                 if BinOpKind::Sub == op1.node;
                 // Check if literal being subtracted is one
@@ -133,9 +133,9 @@ fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &Expr<'a>) -> Option<&'a Expr<'
                 }
             }
         },
-        ExprKind::Assign(ref target, ref value, _) => {
+        ExprKind::Assign(target, value, _) => {
             if_chain! {
-                if let ExprKind::Binary(ref op1, ref left1, ref right1) = value.kind;
+                if let ExprKind::Binary(ref op1, left1, right1) = value.kind;
                 if BinOpKind::Sub == op1.node;
 
                 if SpanlessEq::new(cx).eq_expr(left1, target);
diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
index 94d39019608..1c54599abc4 100644
--- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
@@ -88,7 +88,7 @@ declare_lint_pass!(IndexingSlicing => [INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING]
 
 impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let ExprKind::Index(ref array, ref index) = &expr.kind {
+        if let ExprKind::Index(array, index) = &expr.kind {
             let ty = cx.typeck_results().expr_ty(array).peel_refs();
             if let Some(range) = higher::range(index) {
                 // Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..]
diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
index fb35bc1e780..bbb4ddc613a 100644
--- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
@@ -139,7 +139,7 @@ const HEURISTICS: [(&str, usize, Heuristic, Finiteness); 19] = [
 
 fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
     match expr.kind {
-        ExprKind::MethodCall(ref method, _, ref args, _) => {
+        ExprKind::MethodCall(method, _, args, _) => {
             for &(name, len, heuristic, cap) in &HEURISTICS {
                 if method.ident.name.as_str() == name && args.len() == len {
                     return (match heuristic {
@@ -159,9 +159,9 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
             }
             Finite
         },
-        ExprKind::Block(ref block, _) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)),
-        ExprKind::Box(ref e) | ExprKind::AddrOf(BorrowKind::Ref, _, ref e) => is_infinite(cx, e),
-        ExprKind::Call(ref path, _) => {
+        ExprKind::Block(block, _) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)),
+        ExprKind::Box(e) | ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e),
+        ExprKind::Call(path, _) => {
             if let ExprKind::Path(ref qpath) = path.kind {
                 match_qpath(qpath, &paths::REPEAT).into()
             } else {
@@ -215,7 +215,7 @@ const INFINITE_COLLECTORS: [&[&str]; 8] = [
 
 fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
     match expr.kind {
-        ExprKind::MethodCall(ref method, _, ref args, _) => {
+        ExprKind::MethodCall(method, _, args, _) => {
             for &(name, len) in &COMPLETING_METHODS {
                 if method.ident.name.as_str() == name && args.len() == len {
                     return is_infinite(cx, &args[0]);
@@ -240,7 +240,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
                 }
             }
         },
-        ExprKind::Binary(op, ref l, ref r) => {
+        ExprKind::Binary(op, l, r) => {
             if op.node.is_comparison() {
                 return is_infinite(cx, l).and(is_infinite(cx, r)).and(MaybeInfinite);
             }
diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
index 5b2e70e3ce9..c31013e49be 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
@@ -2,7 +2,7 @@
 
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::in_macro;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::def_id::DefIdMap;
 use rustc_hir::{def_id, Crate, Impl, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -43,7 +43,7 @@ declare_clippy_lint! {
 #[allow(clippy::module_name_repetitions)]
 #[derive(Default)]
 pub struct MultipleInherentImpl {
-    impls: FxHashMap<def_id::DefId, Span>,
+    impls: DefIdMap<Span>,
 }
 
 impl_lint_pass!(MultipleInherentImpl => [MULTIPLE_INHERENT_IMPL]);
diff --git a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
new file mode 100644
index 00000000000..c67c02eefa5
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
@@ -0,0 +1,221 @@
+use std::cmp::Ordering;
+
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::{self, IntTy, UintTy};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+use rustc_target::abi::LayoutOf;
+
+use crate::consts::{constant, Constant};
+
+use clippy_utils::comparisons::Rel;
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::source::snippet;
+use clippy_utils::{comparisons, sext};
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for comparisons where the relation is always either
+    /// true or false, but where one side has been upcast so that the comparison is
+    /// necessary. Only integer types are checked.
+    ///
+    /// **Why is this bad?** An expression like `let x : u8 = ...; (x as u32) > 300`
+    /// will mistakenly imply that it is possible for `x` to be outside the range of
+    /// `u8`.
+    ///
+    /// **Known problems:**
+    /// https://github.com/rust-lang/rust-clippy/issues/886
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x: u8 = 1;
+    /// (x as u32) > 300;
+    /// ```
+    pub INVALID_UPCAST_COMPARISONS,
+    pedantic,
+    "a comparison involving an upcast which is always true or false"
+}
+
+declare_lint_pass!(InvalidUpcastComparisons => [INVALID_UPCAST_COMPARISONS]);
+
+#[derive(Copy, Clone, Debug, Eq)]
+enum FullInt {
+    S(i128),
+    U(u128),
+}
+
+impl FullInt {
+    #[allow(clippy::cast_sign_loss)]
+    #[must_use]
+    fn cmp_s_u(s: i128, u: u128) -> Ordering {
+        if s < 0 {
+            Ordering::Less
+        } else if u > (i128::MAX as u128) {
+            Ordering::Greater
+        } else {
+            (s as u128).cmp(&u)
+        }
+    }
+}
+
+impl PartialEq for FullInt {
+    #[must_use]
+    fn eq(&self, other: &Self) -> bool {
+        self.partial_cmp(other).expect("`partial_cmp` only returns `Some(_)`") == Ordering::Equal
+    }
+}
+
+impl PartialOrd for FullInt {
+    #[must_use]
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(match (self, other) {
+            (&Self::S(s), &Self::S(o)) => s.cmp(&o),
+            (&Self::U(s), &Self::U(o)) => s.cmp(&o),
+            (&Self::S(s), &Self::U(o)) => Self::cmp_s_u(s, o),
+            (&Self::U(s), &Self::S(o)) => Self::cmp_s_u(o, s).reverse(),
+        })
+    }
+}
+
+impl Ord for FullInt {
+    #[must_use]
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.partial_cmp(other)
+            .expect("`partial_cmp` for FullInt can never return `None`")
+    }
+}
+
+fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> {
+    if let ExprKind::Cast(cast_exp, _) = expr.kind {
+        let pre_cast_ty = cx.typeck_results().expr_ty(cast_exp);
+        let cast_ty = cx.typeck_results().expr_ty(expr);
+        // if it's a cast from i32 to u32 wrapping will invalidate all these checks
+        if cx.layout_of(pre_cast_ty).ok().map(|l| l.size) == cx.layout_of(cast_ty).ok().map(|l| l.size) {
+            return None;
+        }
+        match pre_cast_ty.kind() {
+            ty::Int(int_ty) => Some(match int_ty {
+                IntTy::I8 => (FullInt::S(i128::from(i8::MIN)), FullInt::S(i128::from(i8::MAX))),
+                IntTy::I16 => (FullInt::S(i128::from(i16::MIN)), FullInt::S(i128::from(i16::MAX))),
+                IntTy::I32 => (FullInt::S(i128::from(i32::MIN)), FullInt::S(i128::from(i32::MAX))),
+                IntTy::I64 => (FullInt::S(i128::from(i64::MIN)), FullInt::S(i128::from(i64::MAX))),
+                IntTy::I128 => (FullInt::S(i128::MIN), FullInt::S(i128::MAX)),
+                IntTy::Isize => (FullInt::S(isize::MIN as i128), FullInt::S(isize::MAX as i128)),
+            }),
+            ty::Uint(uint_ty) => Some(match uint_ty {
+                UintTy::U8 => (FullInt::U(u128::from(u8::MIN)), FullInt::U(u128::from(u8::MAX))),
+                UintTy::U16 => (FullInt::U(u128::from(u16::MIN)), FullInt::U(u128::from(u16::MAX))),
+                UintTy::U32 => (FullInt::U(u128::from(u32::MIN)), FullInt::U(u128::from(u32::MAX))),
+                UintTy::U64 => (FullInt::U(u128::from(u64::MIN)), FullInt::U(u128::from(u64::MAX))),
+                UintTy::U128 => (FullInt::U(u128::MIN), FullInt::U(u128::MAX)),
+                UintTy::Usize => (FullInt::U(usize::MIN as u128), FullInt::U(usize::MAX as u128)),
+            }),
+            _ => None,
+        }
+    } else {
+        None
+    }
+}
+
+fn node_as_const_fullint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<FullInt> {
+    let val = constant(cx, cx.typeck_results(), expr)?.0;
+    if let Constant::Int(const_int) = val {
+        match *cx.typeck_results().expr_ty(expr).kind() {
+            ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
+            ty::Uint(_) => Some(FullInt::U(const_int)),
+            _ => None,
+        }
+    } else {
+        None
+    }
+}
+
+fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, always: bool) {
+    if let ExprKind::Cast(cast_val, _) = expr.kind {
+        span_lint(
+            cx,
+            INVALID_UPCAST_COMPARISONS,
+            span,
+            &format!(
+                "because of the numeric bounds on `{}` prior to casting, this expression is always {}",
+                snippet(cx, cast_val.span, "the expression"),
+                if always { "true" } else { "false" },
+            ),
+        );
+    }
+}
+
+fn upcast_comparison_bounds_err<'tcx>(
+    cx: &LateContext<'tcx>,
+    span: Span,
+    rel: comparisons::Rel,
+    lhs_bounds: Option<(FullInt, FullInt)>,
+    lhs: &'tcx Expr<'_>,
+    rhs: &'tcx Expr<'_>,
+    invert: bool,
+) {
+    if let Some((lb, ub)) = lhs_bounds {
+        if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) {
+            if rel == Rel::Eq || rel == Rel::Ne {
+                if norm_rhs_val < lb || norm_rhs_val > ub {
+                    err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);
+                }
+            } else if match rel {
+                Rel::Lt => {
+                    if invert {
+                        norm_rhs_val < lb
+                    } else {
+                        ub < norm_rhs_val
+                    }
+                },
+                Rel::Le => {
+                    if invert {
+                        norm_rhs_val <= lb
+                    } else {
+                        ub <= norm_rhs_val
+                    }
+                },
+                Rel::Eq | Rel::Ne => unreachable!(),
+            } {
+                err_upcast_comparison(cx, span, lhs, true)
+            } else if match rel {
+                Rel::Lt => {
+                    if invert {
+                        norm_rhs_val >= ub
+                    } else {
+                        lb >= norm_rhs_val
+                    }
+                },
+                Rel::Le => {
+                    if invert {
+                        norm_rhs_val > ub
+                    } else {
+                        lb > norm_rhs_val
+                    }
+                },
+                Rel::Eq | Rel::Ne => unreachable!(),
+            } {
+                err_upcast_comparison(cx, span, lhs, false)
+            }
+        }
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for InvalidUpcastComparisons {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if let ExprKind::Binary(ref cmp, lhs, rhs) = expr.kind {
+            let normalized = comparisons::normalize_comparison(cmp.node, lhs, rhs);
+            let (rel, normalized_lhs, normalized_rhs) = if let Some(val) = normalized {
+                val
+            } else {
+                return;
+            };
+
+            let lhs_bounds = numeric_cast_precast_bounds(cx, normalized_lhs);
+            let rhs_bounds = numeric_cast_precast_bounds(cx, normalized_rhs);
+
+            upcast_comparison_bounds_err(cx, expr.span, rel, lhs_bounds, normalized_lhs, normalized_rhs, false);
+            upcast_comparison_bounds_err(cx, expr.span, rel, rhs_bounds, normalized_rhs, normalized_lhs, true);
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
index 76584dc1822..f166748d86b 100644
--- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
+++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
@@ -113,7 +113,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
                             );
                             if variant.fields.len() == 1 {
                                 let span = match def.variants[i].data {
-                                    VariantData::Struct(ref fields, ..) | VariantData::Tuple(ref fields, ..) => {
+                                    VariantData::Struct(fields, ..) | VariantData::Tuple(fields, ..) => {
                                         fields[0].ty.span
                                     },
                                     VariantData::Unit(..) => unreachable!(),
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 717f2ea84f4..bb57adff7be 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -3,16 +3,19 @@ use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{get_item_name, get_parent_as_impl, is_allowed};
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
-use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
+use rustc_hir::def_id::DefIdSet;
 use rustc_hir::{
     def_id::DefId, AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, ImplItem, ImplItemKind, ImplicitSelfKind, Item,
     ItemKind, Mutability, Node, TraitItemRef, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, AssocKind, FnSig};
+use rustc_middle::ty::{self, AssocKind, FnSig, Ty, TyS};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::{Span, Spanned, Symbol};
+use rustc_span::{
+    source_map::{Span, Spanned, Symbol},
+    symbol::sym,
+};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for getting the length of something via `.len()`
@@ -118,7 +121,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
             return;
         }
 
-        if let ItemKind::Trait(_, _, _, _, ref trait_items) = item.kind {
+        if let ItemKind::Trait(_, _, _, _, trait_items) = item.kind {
             check_trait_items(cx, item, trait_items);
         }
     }
@@ -137,6 +140,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
             if let Some(local_id) = ty_id.as_local();
             let ty_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id);
             if !is_allowed(cx, LEN_WITHOUT_IS_EMPTY, ty_hir_id);
+            if let Some(output) = parse_len_output(cx, cx.tcx.fn_sig(item.def_id).skip_binder());
             then {
                 let (name, kind) = match cx.tcx.hir().find(ty_hir_id) {
                     Some(Node::ForeignItem(x)) => (x.ident.name, "extern type"),
@@ -148,7 +152,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
                     }
                     _ => return,
                 };
-                check_for_is_empty(cx, sig.span, sig.decl.implicit_self, ty_id, name, kind)
+                check_for_is_empty(cx, sig.span, sig.decl.implicit_self, output, ty_id, name, kind)
             }
         }
     }
@@ -158,7 +162,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
             return;
         }
 
-        if let ExprKind::Binary(Spanned { node: cmp, .. }, ref left, ref right) = expr.kind {
+        if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind {
             match cmp {
                 BinOpKind::Eq => {
                     check_cmp(cx, expr.span, left, right, "", 0); // len == 0
@@ -195,7 +199,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items
     }
 
     // fill the set with current and super traits
-    fn fill_trait_set(traitt: DefId, set: &mut FxHashSet<DefId>, cx: &LateContext<'_>) {
+    fn fill_trait_set(traitt: DefId, set: &mut DefIdSet, cx: &LateContext<'_>) {
         if set.insert(traitt) {
             for supertrait in rustc_trait_selection::traits::supertrait_def_ids(cx.tcx, traitt) {
                 fill_trait_set(supertrait, set, cx);
@@ -204,7 +208,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items
     }
 
     if cx.access_levels.is_exported(visited_trait.hir_id()) && trait_items.iter().any(|i| is_named_self(cx, i, "len")) {
-        let mut current_and_super_traits = FxHashSet::default();
+        let mut current_and_super_traits = DefIdSet::default();
         fill_trait_set(visited_trait.def_id.to_def_id(), &mut current_and_super_traits, cx);
 
         let is_empty_method_found = current_and_super_traits
@@ -231,10 +235,62 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items
     }
 }
 
+#[derive(Debug, Clone, Copy)]
+enum LenOutput<'tcx> {
+    Integral,
+    Option(DefId),
+    Result(DefId, Ty<'tcx>),
+}
+fn parse_len_output(cx: &LateContext<'_>, sig: FnSig<'tcx>) -> Option<LenOutput<'tcx>> {
+    match *sig.output().kind() {
+        ty::Int(_) | ty::Uint(_) => Some(LenOutput::Integral),
+        ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::option_type, adt.did) => {
+            subs.type_at(0).is_integral().then(|| LenOutput::Option(adt.did))
+        },
+        ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::result_type, adt.did) => subs
+            .type_at(0)
+            .is_integral()
+            .then(|| LenOutput::Result(adt.did, subs.type_at(1))),
+        _ => None,
+    }
+}
+
+impl LenOutput<'_> {
+    fn matches_is_empty_output(self, ty: Ty<'_>) -> bool {
+        match (self, ty.kind()) {
+            (_, &ty::Bool) => true,
+            (Self::Option(id), &ty::Adt(adt, subs)) if id == adt.did => subs.type_at(0).is_bool(),
+            (Self::Result(id, err_ty), &ty::Adt(adt, subs)) if id == adt.did => {
+                subs.type_at(0).is_bool() && TyS::same_type(subs.type_at(1), err_ty)
+            },
+            _ => false,
+        }
+    }
+
+    fn expected_sig(self, self_kind: ImplicitSelfKind) -> String {
+        let self_ref = match self_kind {
+            ImplicitSelfKind::ImmRef => "&",
+            ImplicitSelfKind::MutRef => "&mut ",
+            _ => "",
+        };
+        match self {
+            Self::Integral => format!("expected signature: `({}self) -> bool`", self_ref),
+            Self::Option(_) => format!(
+                "expected signature: `({}self) -> bool` or `({}self) -> Option<bool>",
+                self_ref, self_ref
+            ),
+            Self::Result(..) => format!(
+                "expected signature: `({}self) -> bool` or `({}self) -> Result<bool>",
+                self_ref, self_ref
+            ),
+        }
+    }
+}
+
 /// Checks if the given signature matches the expectations for `is_empty`
-fn check_is_empty_sig(cx: &LateContext<'_>, sig: FnSig<'_>, self_kind: ImplicitSelfKind) -> bool {
+fn check_is_empty_sig(sig: FnSig<'_>, self_kind: ImplicitSelfKind, len_output: LenOutput<'_>) -> bool {
     match &**sig.inputs_and_output {
-        [arg, res] if *res == cx.tcx.types.bool => {
+        [arg, res] if len_output.matches_is_empty_output(res) => {
             matches!(
                 (arg.kind(), self_kind),
                 (ty::Ref(_, _, Mutability::Not), ImplicitSelfKind::ImmRef)
@@ -250,6 +306,7 @@ fn check_for_is_empty(
     cx: &LateContext<'_>,
     span: Span,
     self_kind: ImplicitSelfKind,
+    output: LenOutput<'_>,
     impl_ty: DefId,
     item_name: Symbol,
     item_kind: &str,
@@ -289,7 +346,7 @@ fn check_for_is_empty(
         },
         Some(is_empty)
             if !(is_empty.fn_has_self_parameter
-                && check_is_empty_sig(cx, cx.tcx.fn_sig(is_empty.def_id).skip_binder(), self_kind)) =>
+                && check_is_empty_sig(cx.tcx.fn_sig(is_empty.def_id).skip_binder(), self_kind, output)) =>
         {
             (
                 format!(
@@ -309,21 +366,13 @@ fn check_for_is_empty(
             db.span_note(span, "`is_empty` defined here");
         }
         if let Some(self_kind) = self_kind {
-            db.note(&format!(
-                "expected signature: `({}self) -> bool`",
-                match self_kind {
-                    ImplicitSelfKind::ImmRef => "&",
-                    ImplicitSelfKind::MutRef => "&mut ",
-                    _ => "",
-                }
-            ));
+            db.note(&output.expected_sig(self_kind));
         }
     });
 }
 
 fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
-    if let (&ExprKind::MethodCall(ref method_path, _, ref args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind)
-    {
+    if let (&ExprKind::MethodCall(method_path, _, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) {
         // check if we are in an is_empty() method
         if let Some(name) = get_item_name(cx, method) {
             if name.as_str() == "is_empty" {
@@ -401,7 +450,7 @@ fn is_empty_string(expr: &Expr<'_>) -> bool {
 }
 
 fn is_empty_array(expr: &Expr<'_>) -> bool {
-    if let ExprKind::Array(ref arr) = expr.kind {
+    if let ExprKind::Array(arr) = expr.kind {
         return arr.is_empty();
     }
     false
@@ -430,17 +479,17 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
             cx.tcx
                 .associated_items(*imp)
                 .in_definition_order()
-                .any(|item| is_is_empty(cx, &item))
+                .any(|item| is_is_empty(cx, item))
         })
     }
 
     let ty = &cx.typeck_results().expr_ty(expr).peel_refs();
     match ty.kind() {
-        ty::Dynamic(ref tt, ..) => tt.principal().map_or(false, |principal| {
+        ty::Dynamic(tt, ..) => tt.principal().map_or(false, |principal| {
             cx.tcx
                 .associated_items(principal.def_id())
                 .in_definition_order()
-                .any(|item| is_is_empty(cx, &item))
+                .any(|item| is_is_empty(cx, item))
         }),
         ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id),
         ty::Adt(id, _) => has_is_empty_impl(cx, id.did),
diff --git a/src/tools/clippy/clippy_lints/src/let_if_seq.rs b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
index 2d7d9c9befb..67eae4d87bb 100644
--- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs
+++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
@@ -61,13 +61,13 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
         while let Some(stmt) = it.next() {
             if_chain! {
                 if let Some(expr) = it.peek();
-                if let hir::StmtKind::Local(ref local) = stmt.kind;
+                if let hir::StmtKind::Local(local) = stmt.kind;
                 if let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind;
-                if let hir::StmtKind::Expr(ref if_) = expr.kind;
-                if let hir::ExprKind::If(ref cond, ref then, ref else_) = if_.kind;
+                if let hir::StmtKind::Expr(if_) = expr.kind;
+                if let hir::ExprKind::If(cond, then, ref else_) = if_.kind;
                 let mut used_visitor = LocalUsedVisitor::new(cx, canonical_id);
                 if !used_visitor.check_expr(cond);
-                if let hir::ExprKind::Block(ref then, _) = then.kind;
+                if let hir::ExprKind::Block(then, _) = then.kind;
                 if let Some(value) = check_assign(cx, canonical_id, &*then);
                 if !used_visitor.check_expr(value);
                 then {
@@ -79,20 +79,20 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
                     );
                     if has_interior_mutability { return; }
 
-                    let (default_multi_stmts, default) = if let Some(ref else_) = *else_ {
-                        if let hir::ExprKind::Block(ref else_, _) = else_.kind {
+                    let (default_multi_stmts, default) = if let Some(else_) = *else_ {
+                        if let hir::ExprKind::Block(else_, _) = else_.kind {
                             if let Some(default) = check_assign(cx, canonical_id, else_) {
                                 (else_.stmts.len() > 1, default)
-                            } else if let Some(ref default) = local.init {
-                                (true, &**default)
+                            } else if let Some(default) = local.init {
+                                (true, default)
                             } else {
                                 continue;
                             }
                         } else {
                             continue;
                         }
-                    } else if let Some(ref default) = local.init {
-                        (false, &**default)
+                    } else if let Some(default) = local.init {
+                        (false, default)
                     } else {
                         continue;
                     };
@@ -144,8 +144,8 @@ fn check_assign<'tcx>(
     if_chain! {
         if block.expr.is_none();
         if let Some(expr) = block.stmts.iter().last();
-        if let hir::StmtKind::Semi(ref expr) = expr.kind;
-        if let hir::ExprKind::Assign(ref var, ref value, _) = expr.kind;
+        if let hir::StmtKind::Semi(expr) = expr.kind;
+        if let hir::ExprKind::Assign(var, value, _) = expr.kind;
         if path_to_local_id(var, decl);
         then {
             let mut v = LocalUsedVisitor::new(cx, decl);
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index 7e3a76ded2c..17e23781db7 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -116,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
 
         if_chain! {
             if let PatKind::Wild = local.pat.kind;
-            if let Some(ref init) = local.init;
+            if let Some(init) = local.init;
             then {
                 let init_ty = cx.typeck_results().expr_ty(init);
                 let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index a99ed7656bf..11fef30945d 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -23,7 +23,6 @@
 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
 extern crate rustc_ast;
 extern crate rustc_ast_pretty;
-extern crate rustc_attr;
 extern crate rustc_data_structures;
 extern crate rustc_driver;
 extern crate rustc_errors;
@@ -166,6 +165,7 @@ mod consts;
 mod utils;
 
 // begin lints modules, do not remove this comment, it’s used in `update_lints`
+mod absurd_extreme_comparisons;
 mod approx_const;
 mod arithmetic;
 mod as_conversions;
@@ -233,6 +233,7 @@ mod if_let_mutex;
 mod if_let_some_result;
 mod if_not_else;
 mod if_then_some_else_none;
+mod implicit_hasher;
 mod implicit_return;
 mod implicit_saturating_sub;
 mod inconsistent_struct_constructor;
@@ -243,6 +244,7 @@ mod inherent_to_string;
 mod inline_fn_without_body;
 mod int_plus_one;
 mod integer_division;
+mod invalid_upcast_comparisons;
 mod items_after_statements;
 mod large_const_arrays;
 mod large_enum_variant;
@@ -290,6 +292,7 @@ mod needless_bool;
 mod needless_borrow;
 mod needless_borrowed_ref;
 mod needless_continue;
+mod needless_for_each;
 mod needless_pass_by_value;
 mod needless_question_mark;
 mod needless_update;
@@ -299,6 +302,7 @@ mod new_without_default;
 mod no_effect;
 mod non_copy_const;
 mod non_expressive_names;
+mod non_octal_unix_permissions;
 mod open_options;
 mod option_env_unwrap;
 mod option_if_let_else;
@@ -539,476 +543,482 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     // begin register lints, do not remove this comment, it’s used in `update_lints`
     store.register_lints(&[
         #[cfg(feature = "internal-lints")]
-        &utils::internal_lints::CLIPPY_LINTS_INTERNAL,
+        utils::internal_lints::CLIPPY_LINTS_INTERNAL,
         #[cfg(feature = "internal-lints")]
-        &utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS,
+        utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS,
         #[cfg(feature = "internal-lints")]
-        &utils::internal_lints::COMPILER_LINT_FUNCTIONS,
+        utils::internal_lints::COMPILER_LINT_FUNCTIONS,
         #[cfg(feature = "internal-lints")]
-        &utils::internal_lints::DEFAULT_LINT,
+        utils::internal_lints::DEFAULT_LINT,
         #[cfg(feature = "internal-lints")]
-        &utils::internal_lints::INTERNING_DEFINED_SYMBOL,
+        utils::internal_lints::IF_CHAIN_STYLE,
         #[cfg(feature = "internal-lints")]
-        &utils::internal_lints::INVALID_PATHS,
+        utils::internal_lints::INTERNING_DEFINED_SYMBOL,
         #[cfg(feature = "internal-lints")]
-        &utils::internal_lints::LINT_WITHOUT_LINT_PASS,
+        utils::internal_lints::INVALID_PATHS,
         #[cfg(feature = "internal-lints")]
-        &utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
+        utils::internal_lints::LINT_WITHOUT_LINT_PASS,
         #[cfg(feature = "internal-lints")]
-        &utils::internal_lints::OUTER_EXPN_EXPN_DATA,
+        utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
         #[cfg(feature = "internal-lints")]
-        &utils::internal_lints::PRODUCE_ICE,
+        utils::internal_lints::OUTER_EXPN_EXPN_DATA,
         #[cfg(feature = "internal-lints")]
-        &utils::internal_lints::UNNECESSARY_SYMBOL_STR,
-        &approx_const::APPROX_CONSTANT,
-        &arithmetic::FLOAT_ARITHMETIC,
-        &arithmetic::INTEGER_ARITHMETIC,
-        &as_conversions::AS_CONVERSIONS,
-        &asm_syntax::INLINE_ASM_X86_ATT_SYNTAX,
-        &asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX,
-        &assertions_on_constants::ASSERTIONS_ON_CONSTANTS,
-        &assign_ops::ASSIGN_OP_PATTERN,
-        &assign_ops::MISREFACTORED_ASSIGN_OP,
-        &async_yields_async::ASYNC_YIELDS_ASYNC,
-        &atomic_ordering::INVALID_ATOMIC_ORDERING,
-        &attrs::BLANKET_CLIPPY_RESTRICTION_LINTS,
-        &attrs::DEPRECATED_CFG_ATTR,
-        &attrs::DEPRECATED_SEMVER,
-        &attrs::EMPTY_LINE_AFTER_OUTER_ATTR,
-        &attrs::INLINE_ALWAYS,
-        &attrs::MISMATCHED_TARGET_OS,
-        &attrs::USELESS_ATTRIBUTE,
-        &await_holding_invalid::AWAIT_HOLDING_LOCK,
-        &await_holding_invalid::AWAIT_HOLDING_REFCELL_REF,
-        &bit_mask::BAD_BIT_MASK,
-        &bit_mask::INEFFECTIVE_BIT_MASK,
-        &bit_mask::VERBOSE_BIT_MASK,
-        &blacklisted_name::BLACKLISTED_NAME,
-        &blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS,
-        &booleans::LOGIC_BUG,
-        &booleans::NONMINIMAL_BOOL,
-        &bytecount::NAIVE_BYTECOUNT,
-        &cargo_common_metadata::CARGO_COMMON_METADATA,
-        &case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
-        &casts::CAST_LOSSLESS,
-        &casts::CAST_POSSIBLE_TRUNCATION,
-        &casts::CAST_POSSIBLE_WRAP,
-        &casts::CAST_PRECISION_LOSS,
-        &casts::CAST_PTR_ALIGNMENT,
-        &casts::CAST_REF_TO_MUT,
-        &casts::CAST_SIGN_LOSS,
-        &casts::CHAR_LIT_AS_U8,
-        &casts::FN_TO_NUMERIC_CAST,
-        &casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
-        &casts::PTR_AS_PTR,
-        &casts::UNNECESSARY_CAST,
-        &checked_conversions::CHECKED_CONVERSIONS,
-        &cognitive_complexity::COGNITIVE_COMPLEXITY,
-        &collapsible_if::COLLAPSIBLE_ELSE_IF,
-        &collapsible_if::COLLAPSIBLE_IF,
-        &collapsible_match::COLLAPSIBLE_MATCH,
-        &comparison_chain::COMPARISON_CHAIN,
-        &copies::IFS_SAME_COND,
-        &copies::IF_SAME_THEN_ELSE,
-        &copies::SAME_FUNCTIONS_IN_IF_CONDITION,
-        &copy_iterator::COPY_ITERATOR,
-        &create_dir::CREATE_DIR,
-        &dbg_macro::DBG_MACRO,
-        &default::DEFAULT_TRAIT_ACCESS,
-        &default::FIELD_REASSIGN_WITH_DEFAULT,
-        &default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK,
-        &dereference::EXPLICIT_DEREF_METHODS,
-        &derive::DERIVE_HASH_XOR_EQ,
-        &derive::DERIVE_ORD_XOR_PARTIAL_ORD,
-        &derive::EXPL_IMPL_CLONE_ON_COPY,
-        &derive::UNSAFE_DERIVE_DESERIALIZE,
-        &disallowed_method::DISALLOWED_METHOD,
-        &doc::DOC_MARKDOWN,
-        &doc::MISSING_ERRORS_DOC,
-        &doc::MISSING_PANICS_DOC,
-        &doc::MISSING_SAFETY_DOC,
-        &doc::NEEDLESS_DOCTEST_MAIN,
-        &double_comparison::DOUBLE_COMPARISONS,
-        &double_parens::DOUBLE_PARENS,
-        &drop_forget_ref::DROP_COPY,
-        &drop_forget_ref::DROP_REF,
-        &drop_forget_ref::FORGET_COPY,
-        &drop_forget_ref::FORGET_REF,
-        &duration_subsec::DURATION_SUBSEC,
-        &else_if_without_else::ELSE_IF_WITHOUT_ELSE,
-        &empty_enum::EMPTY_ENUM,
-        &entry::MAP_ENTRY,
-        &enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT,
-        &enum_variants::ENUM_VARIANT_NAMES,
-        &enum_variants::MODULE_INCEPTION,
-        &enum_variants::MODULE_NAME_REPETITIONS,
-        &enum_variants::PUB_ENUM_VARIANT_NAMES,
-        &eq_op::EQ_OP,
-        &eq_op::OP_REF,
-        &erasing_op::ERASING_OP,
-        &escape::BOXED_LOCAL,
-        &eta_reduction::REDUNDANT_CLOSURE,
-        &eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
-        &eval_order_dependence::DIVERGING_SUB_EXPRESSION,
-        &eval_order_dependence::EVAL_ORDER_DEPENDENCE,
-        &excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS,
-        &excessive_bools::STRUCT_EXCESSIVE_BOOLS,
-        &exhaustive_items::EXHAUSTIVE_ENUMS,
-        &exhaustive_items::EXHAUSTIVE_STRUCTS,
-        &exit::EXIT,
-        &explicit_write::EXPLICIT_WRITE,
-        &fallible_impl_from::FALLIBLE_IMPL_FROM,
-        &float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS,
-        &float_literal::EXCESSIVE_PRECISION,
-        &float_literal::LOSSY_FLOAT_LITERAL,
-        &floating_point_arithmetic::IMPRECISE_FLOPS,
-        &floating_point_arithmetic::SUBOPTIMAL_FLOPS,
-        &format::USELESS_FORMAT,
-        &formatting::POSSIBLE_MISSING_COMMA,
-        &formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
-        &formatting::SUSPICIOUS_ELSE_FORMATTING,
-        &formatting::SUSPICIOUS_UNARY_OP_FORMATTING,
-        &from_over_into::FROM_OVER_INTO,
-        &from_str_radix_10::FROM_STR_RADIX_10,
-        &functions::DOUBLE_MUST_USE,
-        &functions::MUST_USE_CANDIDATE,
-        &functions::MUST_USE_UNIT,
-        &functions::NOT_UNSAFE_PTR_ARG_DEREF,
-        &functions::RESULT_UNIT_ERR,
-        &functions::TOO_MANY_ARGUMENTS,
-        &functions::TOO_MANY_LINES,
-        &future_not_send::FUTURE_NOT_SEND,
-        &get_last_with_len::GET_LAST_WITH_LEN,
-        &identity_op::IDENTITY_OP,
-        &if_let_mutex::IF_LET_MUTEX,
-        &if_let_some_result::IF_LET_SOME_RESULT,
-        &if_not_else::IF_NOT_ELSE,
-        &if_then_some_else_none::IF_THEN_SOME_ELSE_NONE,
-        &implicit_return::IMPLICIT_RETURN,
-        &implicit_saturating_sub::IMPLICIT_SATURATING_SUB,
-        &inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR,
-        &indexing_slicing::INDEXING_SLICING,
-        &indexing_slicing::OUT_OF_BOUNDS_INDEXING,
-        &infinite_iter::INFINITE_ITER,
-        &infinite_iter::MAYBE_INFINITE_ITER,
-        &inherent_impl::MULTIPLE_INHERENT_IMPL,
-        &inherent_to_string::INHERENT_TO_STRING,
-        &inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY,
-        &inline_fn_without_body::INLINE_FN_WITHOUT_BODY,
-        &int_plus_one::INT_PLUS_ONE,
-        &integer_division::INTEGER_DIVISION,
-        &items_after_statements::ITEMS_AFTER_STATEMENTS,
-        &large_const_arrays::LARGE_CONST_ARRAYS,
-        &large_enum_variant::LARGE_ENUM_VARIANT,
-        &large_stack_arrays::LARGE_STACK_ARRAYS,
-        &len_zero::COMPARISON_TO_EMPTY,
-        &len_zero::LEN_WITHOUT_IS_EMPTY,
-        &len_zero::LEN_ZERO,
-        &let_if_seq::USELESS_LET_IF_SEQ,
-        &let_underscore::LET_UNDERSCORE_DROP,
-        &let_underscore::LET_UNDERSCORE_LOCK,
-        &let_underscore::LET_UNDERSCORE_MUST_USE,
-        &lifetimes::EXTRA_UNUSED_LIFETIMES,
-        &lifetimes::NEEDLESS_LIFETIMES,
-        &literal_representation::DECIMAL_LITERAL_REPRESENTATION,
-        &literal_representation::INCONSISTENT_DIGIT_GROUPING,
-        &literal_representation::LARGE_DIGIT_GROUPS,
-        &literal_representation::MISTYPED_LITERAL_SUFFIXES,
-        &literal_representation::UNREADABLE_LITERAL,
-        &literal_representation::UNUSUAL_BYTE_GROUPINGS,
-        &loops::EMPTY_LOOP,
-        &loops::EXPLICIT_COUNTER_LOOP,
-        &loops::EXPLICIT_INTO_ITER_LOOP,
-        &loops::EXPLICIT_ITER_LOOP,
-        &loops::FOR_KV_MAP,
-        &loops::FOR_LOOPS_OVER_FALLIBLES,
-        &loops::ITER_NEXT_LOOP,
-        &loops::MANUAL_FLATTEN,
-        &loops::MANUAL_MEMCPY,
-        &loops::MUT_RANGE_BOUND,
-        &loops::NEEDLESS_COLLECT,
-        &loops::NEEDLESS_RANGE_LOOP,
-        &loops::NEVER_LOOP,
-        &loops::SAME_ITEM_PUSH,
-        &loops::SINGLE_ELEMENT_LOOP,
-        &loops::WHILE_IMMUTABLE_CONDITION,
-        &loops::WHILE_LET_LOOP,
-        &loops::WHILE_LET_ON_ITERATOR,
-        &macro_use::MACRO_USE_IMPORTS,
-        &main_recursion::MAIN_RECURSION,
-        &manual_async_fn::MANUAL_ASYNC_FN,
-        &manual_map::MANUAL_MAP,
-        &manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
-        &manual_ok_or::MANUAL_OK_OR,
-        &manual_strip::MANUAL_STRIP,
-        &manual_unwrap_or::MANUAL_UNWRAP_OR,
-        &map_clone::MAP_CLONE,
-        &map_err_ignore::MAP_ERR_IGNORE,
-        &map_identity::MAP_IDENTITY,
-        &map_unit_fn::OPTION_MAP_UNIT_FN,
-        &map_unit_fn::RESULT_MAP_UNIT_FN,
-        &match_on_vec_items::MATCH_ON_VEC_ITEMS,
-        &matches::INFALLIBLE_DESTRUCTURING_MATCH,
-        &matches::MATCH_AS_REF,
-        &matches::MATCH_BOOL,
-        &matches::MATCH_LIKE_MATCHES_MACRO,
-        &matches::MATCH_OVERLAPPING_ARM,
-        &matches::MATCH_REF_PATS,
-        &matches::MATCH_SAME_ARMS,
-        &matches::MATCH_SINGLE_BINDING,
-        &matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
-        &matches::MATCH_WILD_ERR_ARM,
-        &matches::REDUNDANT_PATTERN_MATCHING,
-        &matches::REST_PAT_IN_FULLY_BOUND_STRUCTS,
-        &matches::SINGLE_MATCH,
-        &matches::SINGLE_MATCH_ELSE,
-        &matches::WILDCARD_ENUM_MATCH_ARM,
-        &matches::WILDCARD_IN_OR_PATTERNS,
-        &mem_discriminant::MEM_DISCRIMINANT_NON_ENUM,
-        &mem_forget::MEM_FORGET,
-        &mem_replace::MEM_REPLACE_OPTION_WITH_NONE,
-        &mem_replace::MEM_REPLACE_WITH_DEFAULT,
-        &mem_replace::MEM_REPLACE_WITH_UNINIT,
-        &methods::BIND_INSTEAD_OF_MAP,
-        &methods::BYTES_NTH,
-        &methods::CHARS_LAST_CMP,
-        &methods::CHARS_NEXT_CMP,
-        &methods::CLONE_DOUBLE_REF,
-        &methods::CLONE_ON_COPY,
-        &methods::CLONE_ON_REF_PTR,
-        &methods::EXPECT_FUN_CALL,
-        &methods::EXPECT_USED,
-        &methods::FILETYPE_IS_FILE,
-        &methods::FILTER_MAP,
-        &methods::FILTER_MAP_IDENTITY,
-        &methods::FILTER_MAP_NEXT,
-        &methods::FILTER_NEXT,
-        &methods::FLAT_MAP_IDENTITY,
-        &methods::FROM_ITER_INSTEAD_OF_COLLECT,
-        &methods::GET_UNWRAP,
-        &methods::IMPLICIT_CLONE,
-        &methods::INEFFICIENT_TO_STRING,
-        &methods::INSPECT_FOR_EACH,
-        &methods::INTO_ITER_ON_REF,
-        &methods::ITERATOR_STEP_BY_ZERO,
-        &methods::ITER_CLONED_COLLECT,
-        &methods::ITER_COUNT,
-        &methods::ITER_NEXT_SLICE,
-        &methods::ITER_NTH,
-        &methods::ITER_NTH_ZERO,
-        &methods::ITER_SKIP_NEXT,
-        &methods::MANUAL_FILTER_MAP,
-        &methods::MANUAL_FIND_MAP,
-        &methods::MANUAL_SATURATING_ARITHMETIC,
-        &methods::MAP_COLLECT_RESULT_UNIT,
-        &methods::MAP_FLATTEN,
-        &methods::MAP_UNWRAP_OR,
-        &methods::NEW_RET_NO_SELF,
-        &methods::OK_EXPECT,
-        &methods::OPTION_AS_REF_DEREF,
-        &methods::OPTION_MAP_OR_NONE,
-        &methods::OR_FUN_CALL,
-        &methods::RESULT_MAP_OR_INTO_OPTION,
-        &methods::SEARCH_IS_SOME,
-        &methods::SHOULD_IMPLEMENT_TRAIT,
-        &methods::SINGLE_CHAR_ADD_STR,
-        &methods::SINGLE_CHAR_PATTERN,
-        &methods::SKIP_WHILE_NEXT,
-        &methods::STRING_EXTEND_CHARS,
-        &methods::SUSPICIOUS_MAP,
-        &methods::UNINIT_ASSUMED_INIT,
-        &methods::UNNECESSARY_FILTER_MAP,
-        &methods::UNNECESSARY_FOLD,
-        &methods::UNNECESSARY_LAZY_EVALUATIONS,
-        &methods::UNWRAP_USED,
-        &methods::USELESS_ASREF,
-        &methods::WRONG_PUB_SELF_CONVENTION,
-        &methods::WRONG_SELF_CONVENTION,
-        &methods::ZST_OFFSET,
-        &minmax::MIN_MAX,
-        &misc::CMP_NAN,
-        &misc::CMP_OWNED,
-        &misc::FLOAT_CMP,
-        &misc::FLOAT_CMP_CONST,
-        &misc::MODULO_ONE,
-        &misc::SHORT_CIRCUIT_STATEMENT,
-        &misc::TOPLEVEL_REF_ARG,
-        &misc::USED_UNDERSCORE_BINDING,
-        &misc::ZERO_PTR,
-        &misc_early::BUILTIN_TYPE_SHADOW,
-        &misc_early::DOUBLE_NEG,
-        &misc_early::DUPLICATE_UNDERSCORE_ARGUMENT,
-        &misc_early::MIXED_CASE_HEX_LITERALS,
-        &misc_early::REDUNDANT_PATTERN,
-        &misc_early::UNNEEDED_FIELD_PATTERN,
-        &misc_early::UNNEEDED_WILDCARD_PATTERN,
-        &misc_early::UNSEPARATED_LITERAL_SUFFIX,
-        &misc_early::ZERO_PREFIXED_LITERAL,
-        &missing_const_for_fn::MISSING_CONST_FOR_FN,
-        &missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS,
-        &missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS,
-        &modulo_arithmetic::MODULO_ARITHMETIC,
-        &multiple_crate_versions::MULTIPLE_CRATE_VERSIONS,
-        &mut_key::MUTABLE_KEY_TYPE,
-        &mut_mut::MUT_MUT,
-        &mut_mutex_lock::MUT_MUTEX_LOCK,
-        &mut_reference::UNNECESSARY_MUT_PASSED,
-        &mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL,
-        &mutex_atomic::MUTEX_ATOMIC,
-        &mutex_atomic::MUTEX_INTEGER,
-        &needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE,
-        &needless_bool::BOOL_COMPARISON,
-        &needless_bool::NEEDLESS_BOOL,
-        &needless_borrow::NEEDLESS_BORROW,
-        &needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
-        &needless_continue::NEEDLESS_CONTINUE,
-        &needless_pass_by_value::NEEDLESS_PASS_BY_VALUE,
-        &needless_question_mark::NEEDLESS_QUESTION_MARK,
-        &needless_update::NEEDLESS_UPDATE,
-        &neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD,
-        &neg_multiply::NEG_MULTIPLY,
-        &new_without_default::NEW_WITHOUT_DEFAULT,
-        &no_effect::NO_EFFECT,
-        &no_effect::UNNECESSARY_OPERATION,
-        &non_copy_const::BORROW_INTERIOR_MUTABLE_CONST,
-        &non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST,
-        &non_expressive_names::JUST_UNDERSCORES_AND_DIGITS,
-        &non_expressive_names::MANY_SINGLE_CHAR_NAMES,
-        &non_expressive_names::SIMILAR_NAMES,
-        &open_options::NONSENSICAL_OPEN_OPTIONS,
-        &option_env_unwrap::OPTION_ENV_UNWRAP,
-        &option_if_let_else::OPTION_IF_LET_ELSE,
-        &overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
-        &panic_in_result_fn::PANIC_IN_RESULT_FN,
-        &panic_unimplemented::PANIC,
-        &panic_unimplemented::TODO,
-        &panic_unimplemented::UNIMPLEMENTED,
-        &panic_unimplemented::UNREACHABLE,
-        &partialeq_ne_impl::PARTIALEQ_NE_IMPL,
-        &pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE,
-        &pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF,
-        &path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE,
-        &pattern_type_mismatch::PATTERN_TYPE_MISMATCH,
-        &precedence::PRECEDENCE,
-        &ptr::CMP_NULL,
-        &ptr::MUT_FROM_REF,
-        &ptr::PTR_ARG,
-        &ptr_eq::PTR_EQ,
-        &ptr_offset_with_cast::PTR_OFFSET_WITH_CAST,
-        &question_mark::QUESTION_MARK,
-        &ranges::MANUAL_RANGE_CONTAINS,
-        &ranges::RANGE_MINUS_ONE,
-        &ranges::RANGE_PLUS_ONE,
-        &ranges::RANGE_ZIP_WITH_LEN,
-        &ranges::REVERSED_EMPTY_RANGES,
-        &redundant_clone::REDUNDANT_CLONE,
-        &redundant_closure_call::REDUNDANT_CLOSURE_CALL,
-        &redundant_else::REDUNDANT_ELSE,
-        &redundant_field_names::REDUNDANT_FIELD_NAMES,
-        &redundant_pub_crate::REDUNDANT_PUB_CRATE,
-        &redundant_slicing::REDUNDANT_SLICING,
-        &redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES,
-        &ref_option_ref::REF_OPTION_REF,
-        &reference::DEREF_ADDROF,
-        &reference::REF_IN_DEREF,
-        &regex::INVALID_REGEX,
-        &regex::TRIVIAL_REGEX,
-        &repeat_once::REPEAT_ONCE,
-        &returns::LET_AND_RETURN,
-        &returns::NEEDLESS_RETURN,
-        &self_assignment::SELF_ASSIGNMENT,
-        &semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED,
-        &serde_api::SERDE_API_MISUSE,
-        &shadow::SHADOW_REUSE,
-        &shadow::SHADOW_SAME,
-        &shadow::SHADOW_UNRELATED,
-        &single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
-        &size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT,
-        &slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
-        &stable_sort_primitive::STABLE_SORT_PRIMITIVE,
-        &strings::STRING_ADD,
-        &strings::STRING_ADD_ASSIGN,
-        &strings::STRING_FROM_UTF8_AS_BYTES,
-        &strings::STRING_LIT_AS_BYTES,
-        &strings::STRING_TO_STRING,
-        &strings::STR_TO_STRING,
-        &suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS,
-        &suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL,
-        &suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL,
-        &swap::ALMOST_SWAPPED,
-        &swap::MANUAL_SWAP,
-        &tabs_in_doc_comments::TABS_IN_DOC_COMMENTS,
-        &temporary_assignment::TEMPORARY_ASSIGNMENT,
-        &to_digit_is_some::TO_DIGIT_IS_SOME,
-        &to_string_in_display::TO_STRING_IN_DISPLAY,
-        &trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS,
-        &trait_bounds::TYPE_REPETITION_IN_BOUNDS,
-        &transmute::CROSSPOINTER_TRANSMUTE,
-        &transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
-        &transmute::TRANSMUTE_BYTES_TO_STR,
-        &transmute::TRANSMUTE_FLOAT_TO_INT,
-        &transmute::TRANSMUTE_INT_TO_BOOL,
-        &transmute::TRANSMUTE_INT_TO_CHAR,
-        &transmute::TRANSMUTE_INT_TO_FLOAT,
-        &transmute::TRANSMUTE_PTR_TO_PTR,
-        &transmute::TRANSMUTE_PTR_TO_REF,
-        &transmute::UNSOUND_COLLECTION_TRANSMUTE,
-        &transmute::USELESS_TRANSMUTE,
-        &transmute::WRONG_TRANSMUTE,
-        &transmuting_null::TRANSMUTING_NULL,
-        &try_err::TRY_ERR,
-        &types::ABSURD_EXTREME_COMPARISONS,
-        &types::BORROWED_BOX,
-        &types::BOX_VEC,
-        &types::IMPLICIT_HASHER,
-        &types::INVALID_UPCAST_COMPARISONS,
-        &types::LINKEDLIST,
-        &types::OPTION_OPTION,
-        &types::RC_BUFFER,
-        &types::REDUNDANT_ALLOCATION,
-        &types::TYPE_COMPLEXITY,
-        &types::VEC_BOX,
-        &undropped_manually_drops::UNDROPPED_MANUALLY_DROPS,
-        &unicode::INVISIBLE_CHARACTERS,
-        &unicode::NON_ASCII_LITERAL,
-        &unicode::UNICODE_NOT_NFC,
-        &unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
-        &unit_types::LET_UNIT_VALUE,
-        &unit_types::UNIT_ARG,
-        &unit_types::UNIT_CMP,
-        &unnamed_address::FN_ADDRESS_COMPARISONS,
-        &unnamed_address::VTABLE_ADDRESS_COMPARISONS,
-        &unnecessary_sort_by::UNNECESSARY_SORT_BY,
-        &unnecessary_wraps::UNNECESSARY_WRAPS,
-        &unnested_or_patterns::UNNESTED_OR_PATTERNS,
-        &unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
-        &unused_io_amount::UNUSED_IO_AMOUNT,
-        &unused_self::UNUSED_SELF,
-        &unused_unit::UNUSED_UNIT,
-        &unwrap::PANICKING_UNWRAP,
-        &unwrap::UNNECESSARY_UNWRAP,
-        &unwrap_in_result::UNWRAP_IN_RESULT,
-        &upper_case_acronyms::UPPER_CASE_ACRONYMS,
-        &use_self::USE_SELF,
-        &useless_conversion::USELESS_CONVERSION,
-        &vec::USELESS_VEC,
-        &vec_init_then_push::VEC_INIT_THEN_PUSH,
-        &vec_resize_to_zero::VEC_RESIZE_TO_ZERO,
-        &verbose_file_reads::VERBOSE_FILE_READS,
-        &wildcard_dependencies::WILDCARD_DEPENDENCIES,
-        &wildcard_imports::ENUM_GLOB_USE,
-        &wildcard_imports::WILDCARD_IMPORTS,
-        &write::PRINTLN_EMPTY_STRING,
-        &write::PRINT_LITERAL,
-        &write::PRINT_STDERR,
-        &write::PRINT_STDOUT,
-        &write::PRINT_WITH_NEWLINE,
-        &write::USE_DEBUG,
-        &write::WRITELN_EMPTY_STRING,
-        &write::WRITE_LITERAL,
-        &write::WRITE_WITH_NEWLINE,
-        &zero_div_zero::ZERO_DIVIDED_BY_ZERO,
-        &zero_sized_map_values::ZERO_SIZED_MAP_VALUES,
+        utils::internal_lints::PRODUCE_ICE,
+        #[cfg(feature = "internal-lints")]
+        utils::internal_lints::UNNECESSARY_SYMBOL_STR,
+        absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS,
+        approx_const::APPROX_CONSTANT,
+        arithmetic::FLOAT_ARITHMETIC,
+        arithmetic::INTEGER_ARITHMETIC,
+        as_conversions::AS_CONVERSIONS,
+        asm_syntax::INLINE_ASM_X86_ATT_SYNTAX,
+        asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX,
+        assertions_on_constants::ASSERTIONS_ON_CONSTANTS,
+        assign_ops::ASSIGN_OP_PATTERN,
+        assign_ops::MISREFACTORED_ASSIGN_OP,
+        async_yields_async::ASYNC_YIELDS_ASYNC,
+        atomic_ordering::INVALID_ATOMIC_ORDERING,
+        attrs::BLANKET_CLIPPY_RESTRICTION_LINTS,
+        attrs::DEPRECATED_CFG_ATTR,
+        attrs::DEPRECATED_SEMVER,
+        attrs::EMPTY_LINE_AFTER_OUTER_ATTR,
+        attrs::INLINE_ALWAYS,
+        attrs::MISMATCHED_TARGET_OS,
+        attrs::USELESS_ATTRIBUTE,
+        await_holding_invalid::AWAIT_HOLDING_LOCK,
+        await_holding_invalid::AWAIT_HOLDING_REFCELL_REF,
+        bit_mask::BAD_BIT_MASK,
+        bit_mask::INEFFECTIVE_BIT_MASK,
+        bit_mask::VERBOSE_BIT_MASK,
+        blacklisted_name::BLACKLISTED_NAME,
+        blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS,
+        booleans::LOGIC_BUG,
+        booleans::NONMINIMAL_BOOL,
+        bytecount::NAIVE_BYTECOUNT,
+        cargo_common_metadata::CARGO_COMMON_METADATA,
+        case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
+        casts::CAST_LOSSLESS,
+        casts::CAST_POSSIBLE_TRUNCATION,
+        casts::CAST_POSSIBLE_WRAP,
+        casts::CAST_PRECISION_LOSS,
+        casts::CAST_PTR_ALIGNMENT,
+        casts::CAST_REF_TO_MUT,
+        casts::CAST_SIGN_LOSS,
+        casts::CHAR_LIT_AS_U8,
+        casts::FN_TO_NUMERIC_CAST,
+        casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
+        casts::PTR_AS_PTR,
+        casts::UNNECESSARY_CAST,
+        checked_conversions::CHECKED_CONVERSIONS,
+        cognitive_complexity::COGNITIVE_COMPLEXITY,
+        collapsible_if::COLLAPSIBLE_ELSE_IF,
+        collapsible_if::COLLAPSIBLE_IF,
+        collapsible_match::COLLAPSIBLE_MATCH,
+        comparison_chain::COMPARISON_CHAIN,
+        copies::BRANCHES_SHARING_CODE,
+        copies::IFS_SAME_COND,
+        copies::IF_SAME_THEN_ELSE,
+        copies::SAME_FUNCTIONS_IN_IF_CONDITION,
+        copy_iterator::COPY_ITERATOR,
+        create_dir::CREATE_DIR,
+        dbg_macro::DBG_MACRO,
+        default::DEFAULT_TRAIT_ACCESS,
+        default::FIELD_REASSIGN_WITH_DEFAULT,
+        default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK,
+        dereference::EXPLICIT_DEREF_METHODS,
+        derive::DERIVE_HASH_XOR_EQ,
+        derive::DERIVE_ORD_XOR_PARTIAL_ORD,
+        derive::EXPL_IMPL_CLONE_ON_COPY,
+        derive::UNSAFE_DERIVE_DESERIALIZE,
+        disallowed_method::DISALLOWED_METHOD,
+        doc::DOC_MARKDOWN,
+        doc::MISSING_ERRORS_DOC,
+        doc::MISSING_PANICS_DOC,
+        doc::MISSING_SAFETY_DOC,
+        doc::NEEDLESS_DOCTEST_MAIN,
+        double_comparison::DOUBLE_COMPARISONS,
+        double_parens::DOUBLE_PARENS,
+        drop_forget_ref::DROP_COPY,
+        drop_forget_ref::DROP_REF,
+        drop_forget_ref::FORGET_COPY,
+        drop_forget_ref::FORGET_REF,
+        duration_subsec::DURATION_SUBSEC,
+        else_if_without_else::ELSE_IF_WITHOUT_ELSE,
+        empty_enum::EMPTY_ENUM,
+        entry::MAP_ENTRY,
+        enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT,
+        enum_variants::ENUM_VARIANT_NAMES,
+        enum_variants::MODULE_INCEPTION,
+        enum_variants::MODULE_NAME_REPETITIONS,
+        enum_variants::PUB_ENUM_VARIANT_NAMES,
+        eq_op::EQ_OP,
+        eq_op::OP_REF,
+        erasing_op::ERASING_OP,
+        escape::BOXED_LOCAL,
+        eta_reduction::REDUNDANT_CLOSURE,
+        eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
+        eval_order_dependence::DIVERGING_SUB_EXPRESSION,
+        eval_order_dependence::EVAL_ORDER_DEPENDENCE,
+        excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS,
+        excessive_bools::STRUCT_EXCESSIVE_BOOLS,
+        exhaustive_items::EXHAUSTIVE_ENUMS,
+        exhaustive_items::EXHAUSTIVE_STRUCTS,
+        exit::EXIT,
+        explicit_write::EXPLICIT_WRITE,
+        fallible_impl_from::FALLIBLE_IMPL_FROM,
+        float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS,
+        float_literal::EXCESSIVE_PRECISION,
+        float_literal::LOSSY_FLOAT_LITERAL,
+        floating_point_arithmetic::IMPRECISE_FLOPS,
+        floating_point_arithmetic::SUBOPTIMAL_FLOPS,
+        format::USELESS_FORMAT,
+        formatting::POSSIBLE_MISSING_COMMA,
+        formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
+        formatting::SUSPICIOUS_ELSE_FORMATTING,
+        formatting::SUSPICIOUS_UNARY_OP_FORMATTING,
+        from_over_into::FROM_OVER_INTO,
+        from_str_radix_10::FROM_STR_RADIX_10,
+        functions::DOUBLE_MUST_USE,
+        functions::MUST_USE_CANDIDATE,
+        functions::MUST_USE_UNIT,
+        functions::NOT_UNSAFE_PTR_ARG_DEREF,
+        functions::RESULT_UNIT_ERR,
+        functions::TOO_MANY_ARGUMENTS,
+        functions::TOO_MANY_LINES,
+        future_not_send::FUTURE_NOT_SEND,
+        get_last_with_len::GET_LAST_WITH_LEN,
+        identity_op::IDENTITY_OP,
+        if_let_mutex::IF_LET_MUTEX,
+        if_let_some_result::IF_LET_SOME_RESULT,
+        if_not_else::IF_NOT_ELSE,
+        if_then_some_else_none::IF_THEN_SOME_ELSE_NONE,
+        implicit_hasher::IMPLICIT_HASHER,
+        implicit_return::IMPLICIT_RETURN,
+        implicit_saturating_sub::IMPLICIT_SATURATING_SUB,
+        inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR,
+        indexing_slicing::INDEXING_SLICING,
+        indexing_slicing::OUT_OF_BOUNDS_INDEXING,
+        infinite_iter::INFINITE_ITER,
+        infinite_iter::MAYBE_INFINITE_ITER,
+        inherent_impl::MULTIPLE_INHERENT_IMPL,
+        inherent_to_string::INHERENT_TO_STRING,
+        inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY,
+        inline_fn_without_body::INLINE_FN_WITHOUT_BODY,
+        int_plus_one::INT_PLUS_ONE,
+        integer_division::INTEGER_DIVISION,
+        invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS,
+        items_after_statements::ITEMS_AFTER_STATEMENTS,
+        large_const_arrays::LARGE_CONST_ARRAYS,
+        large_enum_variant::LARGE_ENUM_VARIANT,
+        large_stack_arrays::LARGE_STACK_ARRAYS,
+        len_zero::COMPARISON_TO_EMPTY,
+        len_zero::LEN_WITHOUT_IS_EMPTY,
+        len_zero::LEN_ZERO,
+        let_if_seq::USELESS_LET_IF_SEQ,
+        let_underscore::LET_UNDERSCORE_DROP,
+        let_underscore::LET_UNDERSCORE_LOCK,
+        let_underscore::LET_UNDERSCORE_MUST_USE,
+        lifetimes::EXTRA_UNUSED_LIFETIMES,
+        lifetimes::NEEDLESS_LIFETIMES,
+        literal_representation::DECIMAL_LITERAL_REPRESENTATION,
+        literal_representation::INCONSISTENT_DIGIT_GROUPING,
+        literal_representation::LARGE_DIGIT_GROUPS,
+        literal_representation::MISTYPED_LITERAL_SUFFIXES,
+        literal_representation::UNREADABLE_LITERAL,
+        literal_representation::UNUSUAL_BYTE_GROUPINGS,
+        loops::EMPTY_LOOP,
+        loops::EXPLICIT_COUNTER_LOOP,
+        loops::EXPLICIT_INTO_ITER_LOOP,
+        loops::EXPLICIT_ITER_LOOP,
+        loops::FOR_KV_MAP,
+        loops::FOR_LOOPS_OVER_FALLIBLES,
+        loops::ITER_NEXT_LOOP,
+        loops::MANUAL_FLATTEN,
+        loops::MANUAL_MEMCPY,
+        loops::MUT_RANGE_BOUND,
+        loops::NEEDLESS_COLLECT,
+        loops::NEEDLESS_RANGE_LOOP,
+        loops::NEVER_LOOP,
+        loops::SAME_ITEM_PUSH,
+        loops::SINGLE_ELEMENT_LOOP,
+        loops::WHILE_IMMUTABLE_CONDITION,
+        loops::WHILE_LET_LOOP,
+        loops::WHILE_LET_ON_ITERATOR,
+        macro_use::MACRO_USE_IMPORTS,
+        main_recursion::MAIN_RECURSION,
+        manual_async_fn::MANUAL_ASYNC_FN,
+        manual_map::MANUAL_MAP,
+        manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
+        manual_ok_or::MANUAL_OK_OR,
+        manual_strip::MANUAL_STRIP,
+        manual_unwrap_or::MANUAL_UNWRAP_OR,
+        map_clone::MAP_CLONE,
+        map_err_ignore::MAP_ERR_IGNORE,
+        map_identity::MAP_IDENTITY,
+        map_unit_fn::OPTION_MAP_UNIT_FN,
+        map_unit_fn::RESULT_MAP_UNIT_FN,
+        match_on_vec_items::MATCH_ON_VEC_ITEMS,
+        matches::INFALLIBLE_DESTRUCTURING_MATCH,
+        matches::MATCH_AS_REF,
+        matches::MATCH_BOOL,
+        matches::MATCH_LIKE_MATCHES_MACRO,
+        matches::MATCH_OVERLAPPING_ARM,
+        matches::MATCH_REF_PATS,
+        matches::MATCH_SAME_ARMS,
+        matches::MATCH_SINGLE_BINDING,
+        matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
+        matches::MATCH_WILD_ERR_ARM,
+        matches::REDUNDANT_PATTERN_MATCHING,
+        matches::REST_PAT_IN_FULLY_BOUND_STRUCTS,
+        matches::SINGLE_MATCH,
+        matches::SINGLE_MATCH_ELSE,
+        matches::WILDCARD_ENUM_MATCH_ARM,
+        matches::WILDCARD_IN_OR_PATTERNS,
+        mem_discriminant::MEM_DISCRIMINANT_NON_ENUM,
+        mem_forget::MEM_FORGET,
+        mem_replace::MEM_REPLACE_OPTION_WITH_NONE,
+        mem_replace::MEM_REPLACE_WITH_DEFAULT,
+        mem_replace::MEM_REPLACE_WITH_UNINIT,
+        methods::BIND_INSTEAD_OF_MAP,
+        methods::BYTES_NTH,
+        methods::CHARS_LAST_CMP,
+        methods::CHARS_NEXT_CMP,
+        methods::CLONE_DOUBLE_REF,
+        methods::CLONE_ON_COPY,
+        methods::CLONE_ON_REF_PTR,
+        methods::EXPECT_FUN_CALL,
+        methods::EXPECT_USED,
+        methods::FILETYPE_IS_FILE,
+        methods::FILTER_MAP,
+        methods::FILTER_MAP_IDENTITY,
+        methods::FILTER_MAP_NEXT,
+        methods::FILTER_NEXT,
+        methods::FLAT_MAP_IDENTITY,
+        methods::FROM_ITER_INSTEAD_OF_COLLECT,
+        methods::GET_UNWRAP,
+        methods::IMPLICIT_CLONE,
+        methods::INEFFICIENT_TO_STRING,
+        methods::INSPECT_FOR_EACH,
+        methods::INTO_ITER_ON_REF,
+        methods::ITERATOR_STEP_BY_ZERO,
+        methods::ITER_CLONED_COLLECT,
+        methods::ITER_COUNT,
+        methods::ITER_NEXT_SLICE,
+        methods::ITER_NTH,
+        methods::ITER_NTH_ZERO,
+        methods::ITER_SKIP_NEXT,
+        methods::MANUAL_FILTER_MAP,
+        methods::MANUAL_FIND_MAP,
+        methods::MANUAL_SATURATING_ARITHMETIC,
+        methods::MAP_COLLECT_RESULT_UNIT,
+        methods::MAP_FLATTEN,
+        methods::MAP_UNWRAP_OR,
+        methods::NEW_RET_NO_SELF,
+        methods::OK_EXPECT,
+        methods::OPTION_AS_REF_DEREF,
+        methods::OPTION_FILTER_MAP,
+        methods::OPTION_MAP_OR_NONE,
+        methods::OR_FUN_CALL,
+        methods::RESULT_MAP_OR_INTO_OPTION,
+        methods::SEARCH_IS_SOME,
+        methods::SHOULD_IMPLEMENT_TRAIT,
+        methods::SINGLE_CHAR_ADD_STR,
+        methods::SINGLE_CHAR_PATTERN,
+        methods::SKIP_WHILE_NEXT,
+        methods::STRING_EXTEND_CHARS,
+        methods::SUSPICIOUS_MAP,
+        methods::UNINIT_ASSUMED_INIT,
+        methods::UNNECESSARY_FILTER_MAP,
+        methods::UNNECESSARY_FOLD,
+        methods::UNNECESSARY_LAZY_EVALUATIONS,
+        methods::UNWRAP_USED,
+        methods::USELESS_ASREF,
+        methods::WRONG_PUB_SELF_CONVENTION,
+        methods::WRONG_SELF_CONVENTION,
+        methods::ZST_OFFSET,
+        minmax::MIN_MAX,
+        misc::CMP_NAN,
+        misc::CMP_OWNED,
+        misc::FLOAT_CMP,
+        misc::FLOAT_CMP_CONST,
+        misc::MODULO_ONE,
+        misc::SHORT_CIRCUIT_STATEMENT,
+        misc::TOPLEVEL_REF_ARG,
+        misc::USED_UNDERSCORE_BINDING,
+        misc::ZERO_PTR,
+        misc_early::BUILTIN_TYPE_SHADOW,
+        misc_early::DOUBLE_NEG,
+        misc_early::DUPLICATE_UNDERSCORE_ARGUMENT,
+        misc_early::MIXED_CASE_HEX_LITERALS,
+        misc_early::REDUNDANT_PATTERN,
+        misc_early::UNNEEDED_FIELD_PATTERN,
+        misc_early::UNNEEDED_WILDCARD_PATTERN,
+        misc_early::UNSEPARATED_LITERAL_SUFFIX,
+        misc_early::ZERO_PREFIXED_LITERAL,
+        missing_const_for_fn::MISSING_CONST_FOR_FN,
+        missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS,
+        missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS,
+        modulo_arithmetic::MODULO_ARITHMETIC,
+        multiple_crate_versions::MULTIPLE_CRATE_VERSIONS,
+        mut_key::MUTABLE_KEY_TYPE,
+        mut_mut::MUT_MUT,
+        mut_mutex_lock::MUT_MUTEX_LOCK,
+        mut_reference::UNNECESSARY_MUT_PASSED,
+        mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL,
+        mutex_atomic::MUTEX_ATOMIC,
+        mutex_atomic::MUTEX_INTEGER,
+        needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE,
+        needless_bool::BOOL_COMPARISON,
+        needless_bool::NEEDLESS_BOOL,
+        needless_borrow::NEEDLESS_BORROW,
+        needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
+        needless_continue::NEEDLESS_CONTINUE,
+        needless_for_each::NEEDLESS_FOR_EACH,
+        needless_pass_by_value::NEEDLESS_PASS_BY_VALUE,
+        needless_question_mark::NEEDLESS_QUESTION_MARK,
+        needless_update::NEEDLESS_UPDATE,
+        neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD,
+        neg_multiply::NEG_MULTIPLY,
+        new_without_default::NEW_WITHOUT_DEFAULT,
+        no_effect::NO_EFFECT,
+        no_effect::UNNECESSARY_OPERATION,
+        non_copy_const::BORROW_INTERIOR_MUTABLE_CONST,
+        non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST,
+        non_expressive_names::JUST_UNDERSCORES_AND_DIGITS,
+        non_expressive_names::MANY_SINGLE_CHAR_NAMES,
+        non_expressive_names::SIMILAR_NAMES,
+        non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS,
+        open_options::NONSENSICAL_OPEN_OPTIONS,
+        option_env_unwrap::OPTION_ENV_UNWRAP,
+        option_if_let_else::OPTION_IF_LET_ELSE,
+        overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
+        panic_in_result_fn::PANIC_IN_RESULT_FN,
+        panic_unimplemented::PANIC,
+        panic_unimplemented::TODO,
+        panic_unimplemented::UNIMPLEMENTED,
+        panic_unimplemented::UNREACHABLE,
+        partialeq_ne_impl::PARTIALEQ_NE_IMPL,
+        pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE,
+        pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF,
+        path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE,
+        pattern_type_mismatch::PATTERN_TYPE_MISMATCH,
+        precedence::PRECEDENCE,
+        ptr::CMP_NULL,
+        ptr::MUT_FROM_REF,
+        ptr::PTR_ARG,
+        ptr_eq::PTR_EQ,
+        ptr_offset_with_cast::PTR_OFFSET_WITH_CAST,
+        question_mark::QUESTION_MARK,
+        ranges::MANUAL_RANGE_CONTAINS,
+        ranges::RANGE_MINUS_ONE,
+        ranges::RANGE_PLUS_ONE,
+        ranges::RANGE_ZIP_WITH_LEN,
+        ranges::REVERSED_EMPTY_RANGES,
+        redundant_clone::REDUNDANT_CLONE,
+        redundant_closure_call::REDUNDANT_CLOSURE_CALL,
+        redundant_else::REDUNDANT_ELSE,
+        redundant_field_names::REDUNDANT_FIELD_NAMES,
+        redundant_pub_crate::REDUNDANT_PUB_CRATE,
+        redundant_slicing::REDUNDANT_SLICING,
+        redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES,
+        ref_option_ref::REF_OPTION_REF,
+        reference::DEREF_ADDROF,
+        reference::REF_IN_DEREF,
+        regex::INVALID_REGEX,
+        regex::TRIVIAL_REGEX,
+        repeat_once::REPEAT_ONCE,
+        returns::LET_AND_RETURN,
+        returns::NEEDLESS_RETURN,
+        self_assignment::SELF_ASSIGNMENT,
+        semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED,
+        serde_api::SERDE_API_MISUSE,
+        shadow::SHADOW_REUSE,
+        shadow::SHADOW_SAME,
+        shadow::SHADOW_UNRELATED,
+        single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
+        size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT,
+        slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
+        stable_sort_primitive::STABLE_SORT_PRIMITIVE,
+        strings::STRING_ADD,
+        strings::STRING_ADD_ASSIGN,
+        strings::STRING_FROM_UTF8_AS_BYTES,
+        strings::STRING_LIT_AS_BYTES,
+        strings::STRING_TO_STRING,
+        strings::STR_TO_STRING,
+        suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS,
+        suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL,
+        suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL,
+        swap::ALMOST_SWAPPED,
+        swap::MANUAL_SWAP,
+        tabs_in_doc_comments::TABS_IN_DOC_COMMENTS,
+        temporary_assignment::TEMPORARY_ASSIGNMENT,
+        to_digit_is_some::TO_DIGIT_IS_SOME,
+        to_string_in_display::TO_STRING_IN_DISPLAY,
+        trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS,
+        trait_bounds::TYPE_REPETITION_IN_BOUNDS,
+        transmute::CROSSPOINTER_TRANSMUTE,
+        transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
+        transmute::TRANSMUTE_BYTES_TO_STR,
+        transmute::TRANSMUTE_FLOAT_TO_INT,
+        transmute::TRANSMUTE_INT_TO_BOOL,
+        transmute::TRANSMUTE_INT_TO_CHAR,
+        transmute::TRANSMUTE_INT_TO_FLOAT,
+        transmute::TRANSMUTE_PTR_TO_PTR,
+        transmute::TRANSMUTE_PTR_TO_REF,
+        transmute::UNSOUND_COLLECTION_TRANSMUTE,
+        transmute::USELESS_TRANSMUTE,
+        transmute::WRONG_TRANSMUTE,
+        transmuting_null::TRANSMUTING_NULL,
+        try_err::TRY_ERR,
+        types::BORROWED_BOX,
+        types::BOX_VEC,
+        types::LINKEDLIST,
+        types::OPTION_OPTION,
+        types::RC_BUFFER,
+        types::REDUNDANT_ALLOCATION,
+        types::TYPE_COMPLEXITY,
+        types::VEC_BOX,
+        undropped_manually_drops::UNDROPPED_MANUALLY_DROPS,
+        unicode::INVISIBLE_CHARACTERS,
+        unicode::NON_ASCII_LITERAL,
+        unicode::UNICODE_NOT_NFC,
+        unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
+        unit_types::LET_UNIT_VALUE,
+        unit_types::UNIT_ARG,
+        unit_types::UNIT_CMP,
+        unnamed_address::FN_ADDRESS_COMPARISONS,
+        unnamed_address::VTABLE_ADDRESS_COMPARISONS,
+        unnecessary_sort_by::UNNECESSARY_SORT_BY,
+        unnecessary_wraps::UNNECESSARY_WRAPS,
+        unnested_or_patterns::UNNESTED_OR_PATTERNS,
+        unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
+        unused_io_amount::UNUSED_IO_AMOUNT,
+        unused_self::UNUSED_SELF,
+        unused_unit::UNUSED_UNIT,
+        unwrap::PANICKING_UNWRAP,
+        unwrap::UNNECESSARY_UNWRAP,
+        unwrap_in_result::UNWRAP_IN_RESULT,
+        upper_case_acronyms::UPPER_CASE_ACRONYMS,
+        use_self::USE_SELF,
+        useless_conversion::USELESS_CONVERSION,
+        vec::USELESS_VEC,
+        vec_init_then_push::VEC_INIT_THEN_PUSH,
+        vec_resize_to_zero::VEC_RESIZE_TO_ZERO,
+        verbose_file_reads::VERBOSE_FILE_READS,
+        wildcard_dependencies::WILDCARD_DEPENDENCIES,
+        wildcard_imports::ENUM_GLOB_USE,
+        wildcard_imports::WILDCARD_IMPORTS,
+        write::PRINTLN_EMPTY_STRING,
+        write::PRINT_LITERAL,
+        write::PRINT_STDERR,
+        write::PRINT_STDOUT,
+        write::PRINT_WITH_NEWLINE,
+        write::USE_DEBUG,
+        write::WRITELN_EMPTY_STRING,
+        write::WRITE_LITERAL,
+        write::WRITE_WITH_NEWLINE,
+        zero_div_zero::ZERO_DIVIDED_BY_ZERO,
+        zero_sized_map_values::ZERO_SIZED_MAP_VALUES,
     ]);
     // end register lints, do not remove this comment, it’s used in `update_lints`
 
@@ -1020,6 +1030,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         store.register_late_pass(|| box utils::inspector::DeepCodeInspector);
         store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls);
         store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new());
+        store.register_late_pass(|| box utils::internal_lints::IfChainStyle);
         store.register_late_pass(|| box utils::internal_lints::InvalidPaths);
         store.register_late_pass(|| box utils::internal_lints::InterningDefinedSymbol::default());
         store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default());
@@ -1030,7 +1041,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box await_holding_invalid::AwaitHolding);
     store.register_late_pass(|| box serde_api::SerdeApi);
     let vec_box_size_threshold = conf.vec_box_size_threshold;
-    store.register_late_pass(move || box types::Types::new(vec_box_size_threshold));
+    let type_complexity_threshold = conf.type_complexity_threshold;
+    store.register_late_pass(move || box types::Types::new(vec_box_size_threshold, type_complexity_threshold));
     store.register_late_pass(|| box booleans::NonminimalBool);
     store.register_late_pass(|| box eq_op::EqOp);
     store.register_late_pass(|| box enum_clike::UnportableVariant);
@@ -1041,6 +1053,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box ptr_eq::PtrEq);
     store.register_late_pass(|| box needless_bool::NeedlessBool);
     store.register_late_pass(|| box needless_bool::BoolComparison);
+    store.register_late_pass(|| box needless_for_each::NeedlessForEach);
     store.register_late_pass(|| box approx_const::ApproxConstant);
     store.register_late_pass(|| box misc::MiscLints);
     store.register_late_pass(|| box eta_reduction::EtaReduction);
@@ -1059,6 +1072,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub);
     store.register_late_pass(|| box default_numeric_fallback::DefaultNumericFallback);
     store.register_late_pass(|| box inconsistent_struct_constructor::InconsistentStructConstructor);
+    store.register_late_pass(|| box non_octal_unix_permissions::NonOctalUnixPermissions);
 
     let msrv = conf.msrv.as_ref().and_then(|s| {
         parse_msrv(s, None, None).or_else(|| {
@@ -1081,6 +1095,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move || box missing_const_for_fn::MissingConstForFn::new(msrv));
     store.register_late_pass(move || box needless_question_mark::NeedlessQuestionMark::new(msrv));
     store.register_late_pass(move || box casts::Casts::new(msrv));
+    store.register_early_pass(move || box unnested_or_patterns::UnnestedOrPatterns::new(msrv));
 
     store.register_late_pass(|| box size_of_in_element_count::SizeOfInElementCount);
     store.register_late_pass(|| box map_clone::MapClone);
@@ -1091,8 +1106,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box main_recursion::MainRecursion::default());
     store.register_late_pass(|| box lifetimes::Lifetimes);
     store.register_late_pass(|| box entry::HashMapPass);
-    let type_complexity_threshold = conf.type_complexity_threshold;
-    store.register_late_pass(move || box types::TypeComplexity::new(type_complexity_threshold));
     store.register_late_pass(|| box minmax::MinMaxPass);
     store.register_late_pass(|| box open_options::OpenOptions);
     store.register_late_pass(|| box zero_div_zero::ZeroDiv);
@@ -1114,8 +1127,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box get_last_with_len::GetLastWithLen);
     store.register_late_pass(|| box drop_forget_ref::DropForgetRef);
     store.register_late_pass(|| box empty_enum::EmptyEnum);
-    store.register_late_pass(|| box types::AbsurdExtremeComparisons);
-    store.register_late_pass(|| box types::InvalidUpcastComparisons);
+    store.register_late_pass(|| box absurd_extreme_comparisons::AbsurdExtremeComparisons);
+    store.register_late_pass(|| box invalid_upcast_comparisons::InvalidUpcastComparisons);
     store.register_late_pass(|| box regex::Regex::default());
     store.register_late_pass(|| box copies::CopyAndPaste);
     store.register_late_pass(|| box copy_iterator::CopyIterator);
@@ -1125,9 +1138,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box new_without_default::NewWithoutDefault::default());
     let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>();
     store.register_late_pass(move || box blacklisted_name::BlacklistedName::new(blacklisted_names.clone()));
-    let too_many_arguments_threshold1 = conf.too_many_arguments_threshold;
-    let too_many_lines_threshold2 = conf.too_many_lines_threshold;
-    store.register_late_pass(move || box functions::Functions::new(too_many_arguments_threshold1, too_many_lines_threshold2));
+    let too_many_arguments_threshold = conf.too_many_arguments_threshold;
+    let too_many_lines_threshold = conf.too_many_lines_threshold;
+    store.register_late_pass(move || box functions::Functions::new(too_many_arguments_threshold, too_many_lines_threshold));
     let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
     store.register_late_pass(move || box doc::DocMarkdown::new(doc_valid_idents.clone()));
     store.register_late_pass(|| box neg_multiply::NegMultiply);
@@ -1159,7 +1172,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box infinite_iter::InfiniteIter);
     store.register_late_pass(|| box inline_fn_without_body::InlineFnWithoutBody);
     store.register_late_pass(|| box useless_conversion::UselessConversion::default());
-    store.register_late_pass(|| box types::ImplicitHasher);
+    store.register_late_pass(|| box implicit_hasher::ImplicitHasher);
     store.register_late_pass(|| box fallible_impl_from::FallibleImplFrom);
     store.register_late_pass(|| box double_comparison::DoubleComparisons);
     store.register_late_pass(|| box question_mark::QuestionMark);
@@ -1256,7 +1269,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_early_pass(move || box non_expressive_names::NonExpressiveNames {
         single_char_binding_names_threshold,
     });
-    store.register_early_pass(|| box unnested_or_patterns::UnnestedOrPatterns);
     store.register_late_pass(|| box macro_use::MacroUseImports::default());
     store.register_late_pass(|| box map_identity::MapIdentity);
     store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch);
@@ -1285,784 +1297,792 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move || box if_then_some_else_none::IfThenSomeElseNone::new(msrv));
 
     store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
-        LintId::of(&arithmetic::FLOAT_ARITHMETIC),
-        LintId::of(&arithmetic::INTEGER_ARITHMETIC),
-        LintId::of(&as_conversions::AS_CONVERSIONS),
-        LintId::of(&asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
-        LintId::of(&asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
-        LintId::of(&create_dir::CREATE_DIR),
-        LintId::of(&dbg_macro::DBG_MACRO),
-        LintId::of(&default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK),
-        LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE),
-        LintId::of(&exhaustive_items::EXHAUSTIVE_ENUMS),
-        LintId::of(&exhaustive_items::EXHAUSTIVE_STRUCTS),
-        LintId::of(&exit::EXIT),
-        LintId::of(&float_literal::LOSSY_FLOAT_LITERAL),
-        LintId::of(&if_then_some_else_none::IF_THEN_SOME_ELSE_NONE),
-        LintId::of(&implicit_return::IMPLICIT_RETURN),
-        LintId::of(&indexing_slicing::INDEXING_SLICING),
-        LintId::of(&inherent_impl::MULTIPLE_INHERENT_IMPL),
-        LintId::of(&integer_division::INTEGER_DIVISION),
-        LintId::of(&let_underscore::LET_UNDERSCORE_MUST_USE),
-        LintId::of(&literal_representation::DECIMAL_LITERAL_REPRESENTATION),
-        LintId::of(&map_err_ignore::MAP_ERR_IGNORE),
-        LintId::of(&matches::REST_PAT_IN_FULLY_BOUND_STRUCTS),
-        LintId::of(&matches::WILDCARD_ENUM_MATCH_ARM),
-        LintId::of(&mem_forget::MEM_FORGET),
-        LintId::of(&methods::CLONE_ON_REF_PTR),
-        LintId::of(&methods::EXPECT_USED),
-        LintId::of(&methods::FILETYPE_IS_FILE),
-        LintId::of(&methods::GET_UNWRAP),
-        LintId::of(&methods::UNWRAP_USED),
-        LintId::of(&methods::WRONG_PUB_SELF_CONVENTION),
-        LintId::of(&misc::FLOAT_CMP_CONST),
-        LintId::of(&misc_early::UNNEEDED_FIELD_PATTERN),
-        LintId::of(&missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
-        LintId::of(&missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
-        LintId::of(&modulo_arithmetic::MODULO_ARITHMETIC),
-        LintId::of(&panic_in_result_fn::PANIC_IN_RESULT_FN),
-        LintId::of(&panic_unimplemented::PANIC),
-        LintId::of(&panic_unimplemented::TODO),
-        LintId::of(&panic_unimplemented::UNIMPLEMENTED),
-        LintId::of(&panic_unimplemented::UNREACHABLE),
-        LintId::of(&pattern_type_mismatch::PATTERN_TYPE_MISMATCH),
-        LintId::of(&semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
-        LintId::of(&shadow::SHADOW_REUSE),
-        LintId::of(&shadow::SHADOW_SAME),
-        LintId::of(&strings::STRING_ADD),
-        LintId::of(&strings::STRING_TO_STRING),
-        LintId::of(&strings::STR_TO_STRING),
-        LintId::of(&types::RC_BUFFER),
-        LintId::of(&unwrap_in_result::UNWRAP_IN_RESULT),
-        LintId::of(&verbose_file_reads::VERBOSE_FILE_READS),
-        LintId::of(&write::PRINT_STDERR),
-        LintId::of(&write::PRINT_STDOUT),
-        LintId::of(&write::USE_DEBUG),
+        LintId::of(arithmetic::FLOAT_ARITHMETIC),
+        LintId::of(arithmetic::INTEGER_ARITHMETIC),
+        LintId::of(as_conversions::AS_CONVERSIONS),
+        LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
+        LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
+        LintId::of(create_dir::CREATE_DIR),
+        LintId::of(dbg_macro::DBG_MACRO),
+        LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK),
+        LintId::of(else_if_without_else::ELSE_IF_WITHOUT_ELSE),
+        LintId::of(exhaustive_items::EXHAUSTIVE_ENUMS),
+        LintId::of(exhaustive_items::EXHAUSTIVE_STRUCTS),
+        LintId::of(exit::EXIT),
+        LintId::of(float_literal::LOSSY_FLOAT_LITERAL),
+        LintId::of(if_then_some_else_none::IF_THEN_SOME_ELSE_NONE),
+        LintId::of(implicit_return::IMPLICIT_RETURN),
+        LintId::of(indexing_slicing::INDEXING_SLICING),
+        LintId::of(inherent_impl::MULTIPLE_INHERENT_IMPL),
+        LintId::of(integer_division::INTEGER_DIVISION),
+        LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE),
+        LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION),
+        LintId::of(map_err_ignore::MAP_ERR_IGNORE),
+        LintId::of(matches::REST_PAT_IN_FULLY_BOUND_STRUCTS),
+        LintId::of(matches::WILDCARD_ENUM_MATCH_ARM),
+        LintId::of(mem_forget::MEM_FORGET),
+        LintId::of(methods::CLONE_ON_REF_PTR),
+        LintId::of(methods::EXPECT_USED),
+        LintId::of(methods::FILETYPE_IS_FILE),
+        LintId::of(methods::GET_UNWRAP),
+        LintId::of(methods::UNWRAP_USED),
+        LintId::of(methods::WRONG_PUB_SELF_CONVENTION),
+        LintId::of(misc::FLOAT_CMP_CONST),
+        LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
+        LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
+        LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
+        LintId::of(modulo_arithmetic::MODULO_ARITHMETIC),
+        LintId::of(panic_in_result_fn::PANIC_IN_RESULT_FN),
+        LintId::of(panic_unimplemented::PANIC),
+        LintId::of(panic_unimplemented::TODO),
+        LintId::of(panic_unimplemented::UNIMPLEMENTED),
+        LintId::of(panic_unimplemented::UNREACHABLE),
+        LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH),
+        LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
+        LintId::of(shadow::SHADOW_REUSE),
+        LintId::of(shadow::SHADOW_SAME),
+        LintId::of(strings::STRING_ADD),
+        LintId::of(strings::STRING_TO_STRING),
+        LintId::of(strings::STR_TO_STRING),
+        LintId::of(types::RC_BUFFER),
+        LintId::of(unwrap_in_result::UNWRAP_IN_RESULT),
+        LintId::of(verbose_file_reads::VERBOSE_FILE_READS),
+        LintId::of(write::PRINT_STDERR),
+        LintId::of(write::PRINT_STDOUT),
+        LintId::of(write::USE_DEBUG),
     ]);
 
     store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
-        LintId::of(&attrs::INLINE_ALWAYS),
-        LintId::of(&await_holding_invalid::AWAIT_HOLDING_LOCK),
-        LintId::of(&await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
-        LintId::of(&bit_mask::VERBOSE_BIT_MASK),
-        LintId::of(&bytecount::NAIVE_BYTECOUNT),
-        LintId::of(&case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
-        LintId::of(&casts::CAST_LOSSLESS),
-        LintId::of(&casts::CAST_POSSIBLE_TRUNCATION),
-        LintId::of(&casts::CAST_POSSIBLE_WRAP),
-        LintId::of(&casts::CAST_PRECISION_LOSS),
-        LintId::of(&casts::CAST_PTR_ALIGNMENT),
-        LintId::of(&casts::CAST_SIGN_LOSS),
-        LintId::of(&casts::PTR_AS_PTR),
-        LintId::of(&checked_conversions::CHECKED_CONVERSIONS),
-        LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION),
-        LintId::of(&copy_iterator::COPY_ITERATOR),
-        LintId::of(&default::DEFAULT_TRAIT_ACCESS),
-        LintId::of(&dereference::EXPLICIT_DEREF_METHODS),
-        LintId::of(&derive::EXPL_IMPL_CLONE_ON_COPY),
-        LintId::of(&derive::UNSAFE_DERIVE_DESERIALIZE),
-        LintId::of(&doc::DOC_MARKDOWN),
-        LintId::of(&doc::MISSING_ERRORS_DOC),
-        LintId::of(&doc::MISSING_PANICS_DOC),
-        LintId::of(&empty_enum::EMPTY_ENUM),
-        LintId::of(&enum_variants::MODULE_NAME_REPETITIONS),
-        LintId::of(&enum_variants::PUB_ENUM_VARIANT_NAMES),
-        LintId::of(&eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS),
-        LintId::of(&excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS),
-        LintId::of(&excessive_bools::STRUCT_EXCESSIVE_BOOLS),
-        LintId::of(&functions::MUST_USE_CANDIDATE),
-        LintId::of(&functions::TOO_MANY_LINES),
-        LintId::of(&if_not_else::IF_NOT_ELSE),
-        LintId::of(&implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
-        LintId::of(&infinite_iter::MAYBE_INFINITE_ITER),
-        LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS),
-        LintId::of(&large_stack_arrays::LARGE_STACK_ARRAYS),
-        LintId::of(&let_underscore::LET_UNDERSCORE_DROP),
-        LintId::of(&literal_representation::LARGE_DIGIT_GROUPS),
-        LintId::of(&literal_representation::UNREADABLE_LITERAL),
-        LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP),
-        LintId::of(&loops::EXPLICIT_ITER_LOOP),
-        LintId::of(&macro_use::MACRO_USE_IMPORTS),
-        LintId::of(&manual_ok_or::MANUAL_OK_OR),
-        LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS),
-        LintId::of(&matches::MATCH_BOOL),
-        LintId::of(&matches::MATCH_SAME_ARMS),
-        LintId::of(&matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS),
-        LintId::of(&matches::MATCH_WILD_ERR_ARM),
-        LintId::of(&matches::SINGLE_MATCH_ELSE),
-        LintId::of(&methods::FILTER_MAP),
-        LintId::of(&methods::FILTER_MAP_NEXT),
-        LintId::of(&methods::IMPLICIT_CLONE),
-        LintId::of(&methods::INEFFICIENT_TO_STRING),
-        LintId::of(&methods::MAP_FLATTEN),
-        LintId::of(&methods::MAP_UNWRAP_OR),
-        LintId::of(&misc::USED_UNDERSCORE_BINDING),
-        LintId::of(&misc_early::UNSEPARATED_LITERAL_SUFFIX),
-        LintId::of(&mut_mut::MUT_MUT),
-        LintId::of(&needless_continue::NEEDLESS_CONTINUE),
-        LintId::of(&needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
-        LintId::of(&non_expressive_names::SIMILAR_NAMES),
-        LintId::of(&option_if_let_else::OPTION_IF_LET_ELSE),
-        LintId::of(&pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE),
-        LintId::of(&pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF),
-        LintId::of(&ranges::RANGE_MINUS_ONE),
-        LintId::of(&ranges::RANGE_PLUS_ONE),
-        LintId::of(&redundant_else::REDUNDANT_ELSE),
-        LintId::of(&ref_option_ref::REF_OPTION_REF),
-        LintId::of(&shadow::SHADOW_UNRELATED),
-        LintId::of(&strings::STRING_ADD_ASSIGN),
-        LintId::of(&trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
-        LintId::of(&trait_bounds::TYPE_REPETITION_IN_BOUNDS),
-        LintId::of(&types::IMPLICIT_HASHER),
-        LintId::of(&types::INVALID_UPCAST_COMPARISONS),
-        LintId::of(&types::LINKEDLIST),
-        LintId::of(&types::OPTION_OPTION),
-        LintId::of(&unicode::NON_ASCII_LITERAL),
-        LintId::of(&unicode::UNICODE_NOT_NFC),
-        LintId::of(&unit_types::LET_UNIT_VALUE),
-        LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS),
-        LintId::of(&unnested_or_patterns::UNNESTED_OR_PATTERNS),
-        LintId::of(&unused_self::UNUSED_SELF),
-        LintId::of(&wildcard_imports::ENUM_GLOB_USE),
-        LintId::of(&wildcard_imports::WILDCARD_IMPORTS),
-        LintId::of(&zero_sized_map_values::ZERO_SIZED_MAP_VALUES),
+        LintId::of(attrs::INLINE_ALWAYS),
+        LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
+        LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
+        LintId::of(bit_mask::VERBOSE_BIT_MASK),
+        LintId::of(bytecount::NAIVE_BYTECOUNT),
+        LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
+        LintId::of(casts::CAST_LOSSLESS),
+        LintId::of(casts::CAST_POSSIBLE_TRUNCATION),
+        LintId::of(casts::CAST_POSSIBLE_WRAP),
+        LintId::of(casts::CAST_PRECISION_LOSS),
+        LintId::of(casts::CAST_PTR_ALIGNMENT),
+        LintId::of(casts::CAST_SIGN_LOSS),
+        LintId::of(casts::PTR_AS_PTR),
+        LintId::of(checked_conversions::CHECKED_CONVERSIONS),
+        LintId::of(copies::SAME_FUNCTIONS_IN_IF_CONDITION),
+        LintId::of(copy_iterator::COPY_ITERATOR),
+        LintId::of(default::DEFAULT_TRAIT_ACCESS),
+        LintId::of(dereference::EXPLICIT_DEREF_METHODS),
+        LintId::of(derive::EXPL_IMPL_CLONE_ON_COPY),
+        LintId::of(derive::UNSAFE_DERIVE_DESERIALIZE),
+        LintId::of(doc::DOC_MARKDOWN),
+        LintId::of(doc::MISSING_ERRORS_DOC),
+        LintId::of(doc::MISSING_PANICS_DOC),
+        LintId::of(empty_enum::EMPTY_ENUM),
+        LintId::of(enum_variants::MODULE_NAME_REPETITIONS),
+        LintId::of(enum_variants::PUB_ENUM_VARIANT_NAMES),
+        LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS),
+        LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS),
+        LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS),
+        LintId::of(functions::MUST_USE_CANDIDATE),
+        LintId::of(functions::TOO_MANY_LINES),
+        LintId::of(if_not_else::IF_NOT_ELSE),
+        LintId::of(implicit_hasher::IMPLICIT_HASHER),
+        LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
+        LintId::of(infinite_iter::MAYBE_INFINITE_ITER),
+        LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS),
+        LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS),
+        LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS),
+        LintId::of(let_underscore::LET_UNDERSCORE_DROP),
+        LintId::of(literal_representation::LARGE_DIGIT_GROUPS),
+        LintId::of(literal_representation::UNREADABLE_LITERAL),
+        LintId::of(loops::EXPLICIT_INTO_ITER_LOOP),
+        LintId::of(loops::EXPLICIT_ITER_LOOP),
+        LintId::of(macro_use::MACRO_USE_IMPORTS),
+        LintId::of(manual_ok_or::MANUAL_OK_OR),
+        LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS),
+        LintId::of(matches::MATCH_BOOL),
+        LintId::of(matches::MATCH_SAME_ARMS),
+        LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS),
+        LintId::of(matches::MATCH_WILD_ERR_ARM),
+        LintId::of(matches::SINGLE_MATCH_ELSE),
+        LintId::of(methods::FILTER_MAP),
+        LintId::of(methods::FILTER_MAP_NEXT),
+        LintId::of(methods::IMPLICIT_CLONE),
+        LintId::of(methods::INEFFICIENT_TO_STRING),
+        LintId::of(methods::MAP_FLATTEN),
+        LintId::of(methods::MAP_UNWRAP_OR),
+        LintId::of(misc::USED_UNDERSCORE_BINDING),
+        LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
+        LintId::of(mut_mut::MUT_MUT),
+        LintId::of(needless_continue::NEEDLESS_CONTINUE),
+        LintId::of(needless_for_each::NEEDLESS_FOR_EACH),
+        LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
+        LintId::of(non_expressive_names::SIMILAR_NAMES),
+        LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
+        LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE),
+        LintId::of(pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF),
+        LintId::of(ranges::RANGE_MINUS_ONE),
+        LintId::of(ranges::RANGE_PLUS_ONE),
+        LintId::of(redundant_else::REDUNDANT_ELSE),
+        LintId::of(ref_option_ref::REF_OPTION_REF),
+        LintId::of(shadow::SHADOW_UNRELATED),
+        LintId::of(strings::STRING_ADD_ASSIGN),
+        LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
+        LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
+        LintId::of(types::LINKEDLIST),
+        LintId::of(types::OPTION_OPTION),
+        LintId::of(unicode::NON_ASCII_LITERAL),
+        LintId::of(unicode::UNICODE_NOT_NFC),
+        LintId::of(unit_types::LET_UNIT_VALUE),
+        LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS),
+        LintId::of(unnested_or_patterns::UNNESTED_OR_PATTERNS),
+        LintId::of(unused_self::UNUSED_SELF),
+        LintId::of(wildcard_imports::ENUM_GLOB_USE),
+        LintId::of(wildcard_imports::WILDCARD_IMPORTS),
+        LintId::of(zero_sized_map_values::ZERO_SIZED_MAP_VALUES),
     ]);
 
     #[cfg(feature = "internal-lints")]
     store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![
-        LintId::of(&utils::internal_lints::CLIPPY_LINTS_INTERNAL),
-        LintId::of(&utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS),
-        LintId::of(&utils::internal_lints::COMPILER_LINT_FUNCTIONS),
-        LintId::of(&utils::internal_lints::DEFAULT_LINT),
-        LintId::of(&utils::internal_lints::INTERNING_DEFINED_SYMBOL),
-        LintId::of(&utils::internal_lints::INVALID_PATHS),
-        LintId::of(&utils::internal_lints::LINT_WITHOUT_LINT_PASS),
-        LintId::of(&utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM),
-        LintId::of(&utils::internal_lints::OUTER_EXPN_EXPN_DATA),
-        LintId::of(&utils::internal_lints::PRODUCE_ICE),
-        LintId::of(&utils::internal_lints::UNNECESSARY_SYMBOL_STR),
+        LintId::of(utils::internal_lints::CLIPPY_LINTS_INTERNAL),
+        LintId::of(utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS),
+        LintId::of(utils::internal_lints::COMPILER_LINT_FUNCTIONS),
+        LintId::of(utils::internal_lints::DEFAULT_LINT),
+        LintId::of(utils::internal_lints::IF_CHAIN_STYLE),
+        LintId::of(utils::internal_lints::INTERNING_DEFINED_SYMBOL),
+        LintId::of(utils::internal_lints::INVALID_PATHS),
+        LintId::of(utils::internal_lints::LINT_WITHOUT_LINT_PASS),
+        LintId::of(utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM),
+        LintId::of(utils::internal_lints::OUTER_EXPN_EXPN_DATA),
+        LintId::of(utils::internal_lints::PRODUCE_ICE),
+        LintId::of(utils::internal_lints::UNNECESSARY_SYMBOL_STR),
     ]);
 
     store.register_group(true, "clippy::all", Some("clippy"), vec![
-        LintId::of(&approx_const::APPROX_CONSTANT),
-        LintId::of(&assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
-        LintId::of(&assign_ops::ASSIGN_OP_PATTERN),
-        LintId::of(&assign_ops::MISREFACTORED_ASSIGN_OP),
-        LintId::of(&async_yields_async::ASYNC_YIELDS_ASYNC),
-        LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING),
-        LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
-        LintId::of(&attrs::DEPRECATED_CFG_ATTR),
-        LintId::of(&attrs::DEPRECATED_SEMVER),
-        LintId::of(&attrs::MISMATCHED_TARGET_OS),
-        LintId::of(&attrs::USELESS_ATTRIBUTE),
-        LintId::of(&bit_mask::BAD_BIT_MASK),
-        LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK),
-        LintId::of(&blacklisted_name::BLACKLISTED_NAME),
-        LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
-        LintId::of(&booleans::LOGIC_BUG),
-        LintId::of(&booleans::NONMINIMAL_BOOL),
-        LintId::of(&casts::CAST_REF_TO_MUT),
-        LintId::of(&casts::CHAR_LIT_AS_U8),
-        LintId::of(&casts::FN_TO_NUMERIC_CAST),
-        LintId::of(&casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
-        LintId::of(&casts::UNNECESSARY_CAST),
-        LintId::of(&collapsible_if::COLLAPSIBLE_ELSE_IF),
-        LintId::of(&collapsible_if::COLLAPSIBLE_IF),
-        LintId::of(&collapsible_match::COLLAPSIBLE_MATCH),
-        LintId::of(&comparison_chain::COMPARISON_CHAIN),
-        LintId::of(&copies::IFS_SAME_COND),
-        LintId::of(&copies::IF_SAME_THEN_ELSE),
-        LintId::of(&default::FIELD_REASSIGN_WITH_DEFAULT),
-        LintId::of(&derive::DERIVE_HASH_XOR_EQ),
-        LintId::of(&derive::DERIVE_ORD_XOR_PARTIAL_ORD),
-        LintId::of(&doc::MISSING_SAFETY_DOC),
-        LintId::of(&doc::NEEDLESS_DOCTEST_MAIN),
-        LintId::of(&double_comparison::DOUBLE_COMPARISONS),
-        LintId::of(&double_parens::DOUBLE_PARENS),
-        LintId::of(&drop_forget_ref::DROP_COPY),
-        LintId::of(&drop_forget_ref::DROP_REF),
-        LintId::of(&drop_forget_ref::FORGET_COPY),
-        LintId::of(&drop_forget_ref::FORGET_REF),
-        LintId::of(&duration_subsec::DURATION_SUBSEC),
-        LintId::of(&entry::MAP_ENTRY),
-        LintId::of(&enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
-        LintId::of(&enum_variants::ENUM_VARIANT_NAMES),
-        LintId::of(&enum_variants::MODULE_INCEPTION),
-        LintId::of(&eq_op::EQ_OP),
-        LintId::of(&eq_op::OP_REF),
-        LintId::of(&erasing_op::ERASING_OP),
-        LintId::of(&escape::BOXED_LOCAL),
-        LintId::of(&eta_reduction::REDUNDANT_CLOSURE),
-        LintId::of(&eval_order_dependence::DIVERGING_SUB_EXPRESSION),
-        LintId::of(&eval_order_dependence::EVAL_ORDER_DEPENDENCE),
-        LintId::of(&explicit_write::EXPLICIT_WRITE),
-        LintId::of(&float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
-        LintId::of(&float_literal::EXCESSIVE_PRECISION),
-        LintId::of(&format::USELESS_FORMAT),
-        LintId::of(&formatting::POSSIBLE_MISSING_COMMA),
-        LintId::of(&formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
-        LintId::of(&formatting::SUSPICIOUS_ELSE_FORMATTING),
-        LintId::of(&formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
-        LintId::of(&from_over_into::FROM_OVER_INTO),
-        LintId::of(&from_str_radix_10::FROM_STR_RADIX_10),
-        LintId::of(&functions::DOUBLE_MUST_USE),
-        LintId::of(&functions::MUST_USE_UNIT),
-        LintId::of(&functions::NOT_UNSAFE_PTR_ARG_DEREF),
-        LintId::of(&functions::RESULT_UNIT_ERR),
-        LintId::of(&functions::TOO_MANY_ARGUMENTS),
-        LintId::of(&get_last_with_len::GET_LAST_WITH_LEN),
-        LintId::of(&identity_op::IDENTITY_OP),
-        LintId::of(&if_let_mutex::IF_LET_MUTEX),
-        LintId::of(&if_let_some_result::IF_LET_SOME_RESULT),
-        LintId::of(&inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
-        LintId::of(&indexing_slicing::OUT_OF_BOUNDS_INDEXING),
-        LintId::of(&infinite_iter::INFINITE_ITER),
-        LintId::of(&inherent_to_string::INHERENT_TO_STRING),
-        LintId::of(&inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY),
-        LintId::of(&inline_fn_without_body::INLINE_FN_WITHOUT_BODY),
-        LintId::of(&int_plus_one::INT_PLUS_ONE),
-        LintId::of(&large_const_arrays::LARGE_CONST_ARRAYS),
-        LintId::of(&large_enum_variant::LARGE_ENUM_VARIANT),
-        LintId::of(&len_zero::COMPARISON_TO_EMPTY),
-        LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY),
-        LintId::of(&len_zero::LEN_ZERO),
-        LintId::of(&let_underscore::LET_UNDERSCORE_LOCK),
-        LintId::of(&lifetimes::EXTRA_UNUSED_LIFETIMES),
-        LintId::of(&lifetimes::NEEDLESS_LIFETIMES),
-        LintId::of(&literal_representation::INCONSISTENT_DIGIT_GROUPING),
-        LintId::of(&literal_representation::MISTYPED_LITERAL_SUFFIXES),
-        LintId::of(&literal_representation::UNUSUAL_BYTE_GROUPINGS),
-        LintId::of(&loops::EMPTY_LOOP),
-        LintId::of(&loops::EXPLICIT_COUNTER_LOOP),
-        LintId::of(&loops::FOR_KV_MAP),
-        LintId::of(&loops::FOR_LOOPS_OVER_FALLIBLES),
-        LintId::of(&loops::ITER_NEXT_LOOP),
-        LintId::of(&loops::MANUAL_FLATTEN),
-        LintId::of(&loops::MANUAL_MEMCPY),
-        LintId::of(&loops::MUT_RANGE_BOUND),
-        LintId::of(&loops::NEEDLESS_COLLECT),
-        LintId::of(&loops::NEEDLESS_RANGE_LOOP),
-        LintId::of(&loops::NEVER_LOOP),
-        LintId::of(&loops::SAME_ITEM_PUSH),
-        LintId::of(&loops::SINGLE_ELEMENT_LOOP),
-        LintId::of(&loops::WHILE_IMMUTABLE_CONDITION),
-        LintId::of(&loops::WHILE_LET_LOOP),
-        LintId::of(&loops::WHILE_LET_ON_ITERATOR),
-        LintId::of(&main_recursion::MAIN_RECURSION),
-        LintId::of(&manual_async_fn::MANUAL_ASYNC_FN),
-        LintId::of(&manual_map::MANUAL_MAP),
-        LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
-        LintId::of(&manual_strip::MANUAL_STRIP),
-        LintId::of(&manual_unwrap_or::MANUAL_UNWRAP_OR),
-        LintId::of(&map_clone::MAP_CLONE),
-        LintId::of(&map_identity::MAP_IDENTITY),
-        LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
-        LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),
-        LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH),
-        LintId::of(&matches::MATCH_AS_REF),
-        LintId::of(&matches::MATCH_LIKE_MATCHES_MACRO),
-        LintId::of(&matches::MATCH_OVERLAPPING_ARM),
-        LintId::of(&matches::MATCH_REF_PATS),
-        LintId::of(&matches::MATCH_SINGLE_BINDING),
-        LintId::of(&matches::REDUNDANT_PATTERN_MATCHING),
-        LintId::of(&matches::SINGLE_MATCH),
-        LintId::of(&matches::WILDCARD_IN_OR_PATTERNS),
-        LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM),
-        LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
-        LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT),
-        LintId::of(&mem_replace::MEM_REPLACE_WITH_UNINIT),
-        LintId::of(&methods::BIND_INSTEAD_OF_MAP),
-        LintId::of(&methods::BYTES_NTH),
-        LintId::of(&methods::CHARS_LAST_CMP),
-        LintId::of(&methods::CHARS_NEXT_CMP),
-        LintId::of(&methods::CLONE_DOUBLE_REF),
-        LintId::of(&methods::CLONE_ON_COPY),
-        LintId::of(&methods::EXPECT_FUN_CALL),
-        LintId::of(&methods::FILTER_MAP_IDENTITY),
-        LintId::of(&methods::FILTER_NEXT),
-        LintId::of(&methods::FLAT_MAP_IDENTITY),
-        LintId::of(&methods::FROM_ITER_INSTEAD_OF_COLLECT),
-        LintId::of(&methods::INSPECT_FOR_EACH),
-        LintId::of(&methods::INTO_ITER_ON_REF),
-        LintId::of(&methods::ITERATOR_STEP_BY_ZERO),
-        LintId::of(&methods::ITER_CLONED_COLLECT),
-        LintId::of(&methods::ITER_COUNT),
-        LintId::of(&methods::ITER_NEXT_SLICE),
-        LintId::of(&methods::ITER_NTH),
-        LintId::of(&methods::ITER_NTH_ZERO),
-        LintId::of(&methods::ITER_SKIP_NEXT),
-        LintId::of(&methods::MANUAL_FILTER_MAP),
-        LintId::of(&methods::MANUAL_FIND_MAP),
-        LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC),
-        LintId::of(&methods::MAP_COLLECT_RESULT_UNIT),
-        LintId::of(&methods::NEW_RET_NO_SELF),
-        LintId::of(&methods::OK_EXPECT),
-        LintId::of(&methods::OPTION_AS_REF_DEREF),
-        LintId::of(&methods::OPTION_MAP_OR_NONE),
-        LintId::of(&methods::OR_FUN_CALL),
-        LintId::of(&methods::RESULT_MAP_OR_INTO_OPTION),
-        LintId::of(&methods::SEARCH_IS_SOME),
-        LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT),
-        LintId::of(&methods::SINGLE_CHAR_ADD_STR),
-        LintId::of(&methods::SINGLE_CHAR_PATTERN),
-        LintId::of(&methods::SKIP_WHILE_NEXT),
-        LintId::of(&methods::STRING_EXTEND_CHARS),
-        LintId::of(&methods::SUSPICIOUS_MAP),
-        LintId::of(&methods::UNINIT_ASSUMED_INIT),
-        LintId::of(&methods::UNNECESSARY_FILTER_MAP),
-        LintId::of(&methods::UNNECESSARY_FOLD),
-        LintId::of(&methods::UNNECESSARY_LAZY_EVALUATIONS),
-        LintId::of(&methods::USELESS_ASREF),
-        LintId::of(&methods::WRONG_SELF_CONVENTION),
-        LintId::of(&methods::ZST_OFFSET),
-        LintId::of(&minmax::MIN_MAX),
-        LintId::of(&misc::CMP_NAN),
-        LintId::of(&misc::CMP_OWNED),
-        LintId::of(&misc::FLOAT_CMP),
-        LintId::of(&misc::MODULO_ONE),
-        LintId::of(&misc::SHORT_CIRCUIT_STATEMENT),
-        LintId::of(&misc::TOPLEVEL_REF_ARG),
-        LintId::of(&misc::ZERO_PTR),
-        LintId::of(&misc_early::BUILTIN_TYPE_SHADOW),
-        LintId::of(&misc_early::DOUBLE_NEG),
-        LintId::of(&misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
-        LintId::of(&misc_early::MIXED_CASE_HEX_LITERALS),
-        LintId::of(&misc_early::REDUNDANT_PATTERN),
-        LintId::of(&misc_early::UNNEEDED_WILDCARD_PATTERN),
-        LintId::of(&misc_early::ZERO_PREFIXED_LITERAL),
-        LintId::of(&mut_key::MUTABLE_KEY_TYPE),
-        LintId::of(&mut_mutex_lock::MUT_MUTEX_LOCK),
-        LintId::of(&mut_reference::UNNECESSARY_MUT_PASSED),
-        LintId::of(&mutex_atomic::MUTEX_ATOMIC),
-        LintId::of(&needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
-        LintId::of(&needless_bool::BOOL_COMPARISON),
-        LintId::of(&needless_bool::NEEDLESS_BOOL),
-        LintId::of(&needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
-        LintId::of(&needless_question_mark::NEEDLESS_QUESTION_MARK),
-        LintId::of(&needless_update::NEEDLESS_UPDATE),
-        LintId::of(&neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
-        LintId::of(&neg_multiply::NEG_MULTIPLY),
-        LintId::of(&new_without_default::NEW_WITHOUT_DEFAULT),
-        LintId::of(&no_effect::NO_EFFECT),
-        LintId::of(&no_effect::UNNECESSARY_OPERATION),
-        LintId::of(&non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
-        LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
-        LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
-        LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES),
-        LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS),
-        LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP),
-        LintId::of(&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
-        LintId::of(&partialeq_ne_impl::PARTIALEQ_NE_IMPL),
-        LintId::of(&precedence::PRECEDENCE),
-        LintId::of(&ptr::CMP_NULL),
-        LintId::of(&ptr::MUT_FROM_REF),
-        LintId::of(&ptr::PTR_ARG),
-        LintId::of(&ptr_eq::PTR_EQ),
-        LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
-        LintId::of(&question_mark::QUESTION_MARK),
-        LintId::of(&ranges::MANUAL_RANGE_CONTAINS),
-        LintId::of(&ranges::RANGE_ZIP_WITH_LEN),
-        LintId::of(&ranges::REVERSED_EMPTY_RANGES),
-        LintId::of(&redundant_clone::REDUNDANT_CLONE),
-        LintId::of(&redundant_closure_call::REDUNDANT_CLOSURE_CALL),
-        LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES),
-        LintId::of(&redundant_slicing::REDUNDANT_SLICING),
-        LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
-        LintId::of(&reference::DEREF_ADDROF),
-        LintId::of(&reference::REF_IN_DEREF),
-        LintId::of(&regex::INVALID_REGEX),
-        LintId::of(&repeat_once::REPEAT_ONCE),
-        LintId::of(&returns::LET_AND_RETURN),
-        LintId::of(&returns::NEEDLESS_RETURN),
-        LintId::of(&self_assignment::SELF_ASSIGNMENT),
-        LintId::of(&serde_api::SERDE_API_MISUSE),
-        LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
-        LintId::of(&size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
-        LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
-        LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE),
-        LintId::of(&strings::STRING_FROM_UTF8_AS_BYTES),
-        LintId::of(&suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
-        LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
-        LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
-        LintId::of(&swap::ALMOST_SWAPPED),
-        LintId::of(&swap::MANUAL_SWAP),
-        LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
-        LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT),
-        LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME),
-        LintId::of(&to_string_in_display::TO_STRING_IN_DISPLAY),
-        LintId::of(&transmute::CROSSPOINTER_TRANSMUTE),
-        LintId::of(&transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS),
-        LintId::of(&transmute::TRANSMUTE_BYTES_TO_STR),
-        LintId::of(&transmute::TRANSMUTE_FLOAT_TO_INT),
-        LintId::of(&transmute::TRANSMUTE_INT_TO_BOOL),
-        LintId::of(&transmute::TRANSMUTE_INT_TO_CHAR),
-        LintId::of(&transmute::TRANSMUTE_INT_TO_FLOAT),
-        LintId::of(&transmute::TRANSMUTE_PTR_TO_PTR),
-        LintId::of(&transmute::TRANSMUTE_PTR_TO_REF),
-        LintId::of(&transmute::UNSOUND_COLLECTION_TRANSMUTE),
-        LintId::of(&transmute::WRONG_TRANSMUTE),
-        LintId::of(&transmuting_null::TRANSMUTING_NULL),
-        LintId::of(&try_err::TRY_ERR),
-        LintId::of(&types::ABSURD_EXTREME_COMPARISONS),
-        LintId::of(&types::BORROWED_BOX),
-        LintId::of(&types::BOX_VEC),
-        LintId::of(&types::REDUNDANT_ALLOCATION),
-        LintId::of(&types::TYPE_COMPLEXITY),
-        LintId::of(&types::VEC_BOX),
-        LintId::of(&undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
-        LintId::of(&unicode::INVISIBLE_CHARACTERS),
-        LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
-        LintId::of(&unit_types::UNIT_ARG),
-        LintId::of(&unit_types::UNIT_CMP),
-        LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
-        LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
-        LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY),
-        LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
-        LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT),
-        LintId::of(&unused_unit::UNUSED_UNIT),
-        LintId::of(&unwrap::PANICKING_UNWRAP),
-        LintId::of(&unwrap::UNNECESSARY_UNWRAP),
-        LintId::of(&upper_case_acronyms::UPPER_CASE_ACRONYMS),
-        LintId::of(&useless_conversion::USELESS_CONVERSION),
-        LintId::of(&vec::USELESS_VEC),
-        LintId::of(&vec_init_then_push::VEC_INIT_THEN_PUSH),
-        LintId::of(&vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
-        LintId::of(&write::PRINTLN_EMPTY_STRING),
-        LintId::of(&write::PRINT_LITERAL),
-        LintId::of(&write::PRINT_WITH_NEWLINE),
-        LintId::of(&write::WRITELN_EMPTY_STRING),
-        LintId::of(&write::WRITE_LITERAL),
-        LintId::of(&write::WRITE_WITH_NEWLINE),
-        LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO),
+        LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS),
+        LintId::of(approx_const::APPROX_CONSTANT),
+        LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
+        LintId::of(assign_ops::ASSIGN_OP_PATTERN),
+        LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP),
+        LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC),
+        LintId::of(atomic_ordering::INVALID_ATOMIC_ORDERING),
+        LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
+        LintId::of(attrs::DEPRECATED_CFG_ATTR),
+        LintId::of(attrs::DEPRECATED_SEMVER),
+        LintId::of(attrs::MISMATCHED_TARGET_OS),
+        LintId::of(attrs::USELESS_ATTRIBUTE),
+        LintId::of(bit_mask::BAD_BIT_MASK),
+        LintId::of(bit_mask::INEFFECTIVE_BIT_MASK),
+        LintId::of(blacklisted_name::BLACKLISTED_NAME),
+        LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
+        LintId::of(booleans::LOGIC_BUG),
+        LintId::of(booleans::NONMINIMAL_BOOL),
+        LintId::of(casts::CAST_REF_TO_MUT),
+        LintId::of(casts::CHAR_LIT_AS_U8),
+        LintId::of(casts::FN_TO_NUMERIC_CAST),
+        LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
+        LintId::of(casts::UNNECESSARY_CAST),
+        LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
+        LintId::of(collapsible_if::COLLAPSIBLE_IF),
+        LintId::of(collapsible_match::COLLAPSIBLE_MATCH),
+        LintId::of(comparison_chain::COMPARISON_CHAIN),
+        LintId::of(copies::BRANCHES_SHARING_CODE),
+        LintId::of(copies::IFS_SAME_COND),
+        LintId::of(copies::IF_SAME_THEN_ELSE),
+        LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
+        LintId::of(derive::DERIVE_HASH_XOR_EQ),
+        LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
+        LintId::of(doc::MISSING_SAFETY_DOC),
+        LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
+        LintId::of(double_comparison::DOUBLE_COMPARISONS),
+        LintId::of(double_parens::DOUBLE_PARENS),
+        LintId::of(drop_forget_ref::DROP_COPY),
+        LintId::of(drop_forget_ref::DROP_REF),
+        LintId::of(drop_forget_ref::FORGET_COPY),
+        LintId::of(drop_forget_ref::FORGET_REF),
+        LintId::of(duration_subsec::DURATION_SUBSEC),
+        LintId::of(entry::MAP_ENTRY),
+        LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
+        LintId::of(enum_variants::ENUM_VARIANT_NAMES),
+        LintId::of(enum_variants::MODULE_INCEPTION),
+        LintId::of(eq_op::EQ_OP),
+        LintId::of(eq_op::OP_REF),
+        LintId::of(erasing_op::ERASING_OP),
+        LintId::of(escape::BOXED_LOCAL),
+        LintId::of(eta_reduction::REDUNDANT_CLOSURE),
+        LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION),
+        LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE),
+        LintId::of(explicit_write::EXPLICIT_WRITE),
+        LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
+        LintId::of(float_literal::EXCESSIVE_PRECISION),
+        LintId::of(format::USELESS_FORMAT),
+        LintId::of(formatting::POSSIBLE_MISSING_COMMA),
+        LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
+        LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
+        LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
+        LintId::of(from_over_into::FROM_OVER_INTO),
+        LintId::of(from_str_radix_10::FROM_STR_RADIX_10),
+        LintId::of(functions::DOUBLE_MUST_USE),
+        LintId::of(functions::MUST_USE_UNIT),
+        LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF),
+        LintId::of(functions::RESULT_UNIT_ERR),
+        LintId::of(functions::TOO_MANY_ARGUMENTS),
+        LintId::of(get_last_with_len::GET_LAST_WITH_LEN),
+        LintId::of(identity_op::IDENTITY_OP),
+        LintId::of(if_let_mutex::IF_LET_MUTEX),
+        LintId::of(if_let_some_result::IF_LET_SOME_RESULT),
+        LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
+        LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
+        LintId::of(infinite_iter::INFINITE_ITER),
+        LintId::of(inherent_to_string::INHERENT_TO_STRING),
+        LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY),
+        LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY),
+        LintId::of(int_plus_one::INT_PLUS_ONE),
+        LintId::of(large_const_arrays::LARGE_CONST_ARRAYS),
+        LintId::of(large_enum_variant::LARGE_ENUM_VARIANT),
+        LintId::of(len_zero::COMPARISON_TO_EMPTY),
+        LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
+        LintId::of(len_zero::LEN_ZERO),
+        LintId::of(let_underscore::LET_UNDERSCORE_LOCK),
+        LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES),
+        LintId::of(lifetimes::NEEDLESS_LIFETIMES),
+        LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING),
+        LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES),
+        LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS),
+        LintId::of(loops::EMPTY_LOOP),
+        LintId::of(loops::EXPLICIT_COUNTER_LOOP),
+        LintId::of(loops::FOR_KV_MAP),
+        LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES),
+        LintId::of(loops::ITER_NEXT_LOOP),
+        LintId::of(loops::MANUAL_FLATTEN),
+        LintId::of(loops::MANUAL_MEMCPY),
+        LintId::of(loops::MUT_RANGE_BOUND),
+        LintId::of(loops::NEEDLESS_COLLECT),
+        LintId::of(loops::NEEDLESS_RANGE_LOOP),
+        LintId::of(loops::NEVER_LOOP),
+        LintId::of(loops::SAME_ITEM_PUSH),
+        LintId::of(loops::SINGLE_ELEMENT_LOOP),
+        LintId::of(loops::WHILE_IMMUTABLE_CONDITION),
+        LintId::of(loops::WHILE_LET_LOOP),
+        LintId::of(loops::WHILE_LET_ON_ITERATOR),
+        LintId::of(main_recursion::MAIN_RECURSION),
+        LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
+        LintId::of(manual_map::MANUAL_MAP),
+        LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
+        LintId::of(manual_strip::MANUAL_STRIP),
+        LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR),
+        LintId::of(map_clone::MAP_CLONE),
+        LintId::of(map_identity::MAP_IDENTITY),
+        LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
+        LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
+        LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
+        LintId::of(matches::MATCH_AS_REF),
+        LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
+        LintId::of(matches::MATCH_OVERLAPPING_ARM),
+        LintId::of(matches::MATCH_REF_PATS),
+        LintId::of(matches::MATCH_SINGLE_BINDING),
+        LintId::of(matches::REDUNDANT_PATTERN_MATCHING),
+        LintId::of(matches::SINGLE_MATCH),
+        LintId::of(matches::WILDCARD_IN_OR_PATTERNS),
+        LintId::of(mem_discriminant::MEM_DISCRIMINANT_NON_ENUM),
+        LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
+        LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT),
+        LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
+        LintId::of(methods::BIND_INSTEAD_OF_MAP),
+        LintId::of(methods::BYTES_NTH),
+        LintId::of(methods::CHARS_LAST_CMP),
+        LintId::of(methods::CHARS_NEXT_CMP),
+        LintId::of(methods::CLONE_DOUBLE_REF),
+        LintId::of(methods::CLONE_ON_COPY),
+        LintId::of(methods::EXPECT_FUN_CALL),
+        LintId::of(methods::FILTER_MAP_IDENTITY),
+        LintId::of(methods::FILTER_NEXT),
+        LintId::of(methods::FLAT_MAP_IDENTITY),
+        LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT),
+        LintId::of(methods::INSPECT_FOR_EACH),
+        LintId::of(methods::INTO_ITER_ON_REF),
+        LintId::of(methods::ITERATOR_STEP_BY_ZERO),
+        LintId::of(methods::ITER_CLONED_COLLECT),
+        LintId::of(methods::ITER_COUNT),
+        LintId::of(methods::ITER_NEXT_SLICE),
+        LintId::of(methods::ITER_NTH),
+        LintId::of(methods::ITER_NTH_ZERO),
+        LintId::of(methods::ITER_SKIP_NEXT),
+        LintId::of(methods::MANUAL_FILTER_MAP),
+        LintId::of(methods::MANUAL_FIND_MAP),
+        LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
+        LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
+        LintId::of(methods::NEW_RET_NO_SELF),
+        LintId::of(methods::OK_EXPECT),
+        LintId::of(methods::OPTION_AS_REF_DEREF),
+        LintId::of(methods::OPTION_FILTER_MAP),
+        LintId::of(methods::OPTION_MAP_OR_NONE),
+        LintId::of(methods::OR_FUN_CALL),
+        LintId::of(methods::RESULT_MAP_OR_INTO_OPTION),
+        LintId::of(methods::SEARCH_IS_SOME),
+        LintId::of(methods::SHOULD_IMPLEMENT_TRAIT),
+        LintId::of(methods::SINGLE_CHAR_ADD_STR),
+        LintId::of(methods::SINGLE_CHAR_PATTERN),
+        LintId::of(methods::SKIP_WHILE_NEXT),
+        LintId::of(methods::STRING_EXTEND_CHARS),
+        LintId::of(methods::SUSPICIOUS_MAP),
+        LintId::of(methods::UNINIT_ASSUMED_INIT),
+        LintId::of(methods::UNNECESSARY_FILTER_MAP),
+        LintId::of(methods::UNNECESSARY_FOLD),
+        LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
+        LintId::of(methods::USELESS_ASREF),
+        LintId::of(methods::WRONG_SELF_CONVENTION),
+        LintId::of(methods::ZST_OFFSET),
+        LintId::of(minmax::MIN_MAX),
+        LintId::of(misc::CMP_NAN),
+        LintId::of(misc::CMP_OWNED),
+        LintId::of(misc::FLOAT_CMP),
+        LintId::of(misc::MODULO_ONE),
+        LintId::of(misc::SHORT_CIRCUIT_STATEMENT),
+        LintId::of(misc::TOPLEVEL_REF_ARG),
+        LintId::of(misc::ZERO_PTR),
+        LintId::of(misc_early::BUILTIN_TYPE_SHADOW),
+        LintId::of(misc_early::DOUBLE_NEG),
+        LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
+        LintId::of(misc_early::MIXED_CASE_HEX_LITERALS),
+        LintId::of(misc_early::REDUNDANT_PATTERN),
+        LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
+        LintId::of(misc_early::ZERO_PREFIXED_LITERAL),
+        LintId::of(mut_key::MUTABLE_KEY_TYPE),
+        LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
+        LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
+        LintId::of(mutex_atomic::MUTEX_ATOMIC),
+        LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
+        LintId::of(needless_bool::BOOL_COMPARISON),
+        LintId::of(needless_bool::NEEDLESS_BOOL),
+        LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
+        LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
+        LintId::of(needless_update::NEEDLESS_UPDATE),
+        LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
+        LintId::of(neg_multiply::NEG_MULTIPLY),
+        LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
+        LintId::of(no_effect::NO_EFFECT),
+        LintId::of(no_effect::UNNECESSARY_OPERATION),
+        LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
+        LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
+        LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
+        LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES),
+        LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
+        LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
+        LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
+        LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
+        LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
+        LintId::of(precedence::PRECEDENCE),
+        LintId::of(ptr::CMP_NULL),
+        LintId::of(ptr::MUT_FROM_REF),
+        LintId::of(ptr::PTR_ARG),
+        LintId::of(ptr_eq::PTR_EQ),
+        LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
+        LintId::of(question_mark::QUESTION_MARK),
+        LintId::of(ranges::MANUAL_RANGE_CONTAINS),
+        LintId::of(ranges::RANGE_ZIP_WITH_LEN),
+        LintId::of(ranges::REVERSED_EMPTY_RANGES),
+        LintId::of(redundant_clone::REDUNDANT_CLONE),
+        LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL),
+        LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES),
+        LintId::of(redundant_slicing::REDUNDANT_SLICING),
+        LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
+        LintId::of(reference::DEREF_ADDROF),
+        LintId::of(reference::REF_IN_DEREF),
+        LintId::of(regex::INVALID_REGEX),
+        LintId::of(repeat_once::REPEAT_ONCE),
+        LintId::of(returns::LET_AND_RETURN),
+        LintId::of(returns::NEEDLESS_RETURN),
+        LintId::of(self_assignment::SELF_ASSIGNMENT),
+        LintId::of(serde_api::SERDE_API_MISUSE),
+        LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
+        LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
+        LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
+        LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
+        LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
+        LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
+        LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
+        LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
+        LintId::of(swap::ALMOST_SWAPPED),
+        LintId::of(swap::MANUAL_SWAP),
+        LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
+        LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT),
+        LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
+        LintId::of(to_string_in_display::TO_STRING_IN_DISPLAY),
+        LintId::of(transmute::CROSSPOINTER_TRANSMUTE),
+        LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS),
+        LintId::of(transmute::TRANSMUTE_BYTES_TO_STR),
+        LintId::of(transmute::TRANSMUTE_FLOAT_TO_INT),
+        LintId::of(transmute::TRANSMUTE_INT_TO_BOOL),
+        LintId::of(transmute::TRANSMUTE_INT_TO_CHAR),
+        LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
+        LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
+        LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
+        LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
+        LintId::of(transmute::WRONG_TRANSMUTE),
+        LintId::of(transmuting_null::TRANSMUTING_NULL),
+        LintId::of(try_err::TRY_ERR),
+        LintId::of(types::BORROWED_BOX),
+        LintId::of(types::BOX_VEC),
+        LintId::of(types::REDUNDANT_ALLOCATION),
+        LintId::of(types::TYPE_COMPLEXITY),
+        LintId::of(types::VEC_BOX),
+        LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
+        LintId::of(unicode::INVISIBLE_CHARACTERS),
+        LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
+        LintId::of(unit_types::UNIT_ARG),
+        LintId::of(unit_types::UNIT_CMP),
+        LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
+        LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS),
+        LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY),
+        LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
+        LintId::of(unused_io_amount::UNUSED_IO_AMOUNT),
+        LintId::of(unused_unit::UNUSED_UNIT),
+        LintId::of(unwrap::PANICKING_UNWRAP),
+        LintId::of(unwrap::UNNECESSARY_UNWRAP),
+        LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS),
+        LintId::of(useless_conversion::USELESS_CONVERSION),
+        LintId::of(vec::USELESS_VEC),
+        LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH),
+        LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
+        LintId::of(write::PRINTLN_EMPTY_STRING),
+        LintId::of(write::PRINT_LITERAL),
+        LintId::of(write::PRINT_WITH_NEWLINE),
+        LintId::of(write::WRITELN_EMPTY_STRING),
+        LintId::of(write::WRITE_LITERAL),
+        LintId::of(write::WRITE_WITH_NEWLINE),
+        LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO),
     ]);
 
     store.register_group(true, "clippy::style", Some("clippy_style"), vec![
-        LintId::of(&assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
-        LintId::of(&assign_ops::ASSIGN_OP_PATTERN),
-        LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
-        LintId::of(&blacklisted_name::BLACKLISTED_NAME),
-        LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
-        LintId::of(&casts::FN_TO_NUMERIC_CAST),
-        LintId::of(&casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
-        LintId::of(&collapsible_if::COLLAPSIBLE_ELSE_IF),
-        LintId::of(&collapsible_if::COLLAPSIBLE_IF),
-        LintId::of(&collapsible_match::COLLAPSIBLE_MATCH),
-        LintId::of(&comparison_chain::COMPARISON_CHAIN),
-        LintId::of(&default::FIELD_REASSIGN_WITH_DEFAULT),
-        LintId::of(&doc::MISSING_SAFETY_DOC),
-        LintId::of(&doc::NEEDLESS_DOCTEST_MAIN),
-        LintId::of(&enum_variants::ENUM_VARIANT_NAMES),
-        LintId::of(&enum_variants::MODULE_INCEPTION),
-        LintId::of(&eq_op::OP_REF),
-        LintId::of(&eta_reduction::REDUNDANT_CLOSURE),
-        LintId::of(&float_literal::EXCESSIVE_PRECISION),
-        LintId::of(&formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
-        LintId::of(&formatting::SUSPICIOUS_ELSE_FORMATTING),
-        LintId::of(&formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
-        LintId::of(&from_over_into::FROM_OVER_INTO),
-        LintId::of(&from_str_radix_10::FROM_STR_RADIX_10),
-        LintId::of(&functions::DOUBLE_MUST_USE),
-        LintId::of(&functions::MUST_USE_UNIT),
-        LintId::of(&functions::RESULT_UNIT_ERR),
-        LintId::of(&if_let_some_result::IF_LET_SOME_RESULT),
-        LintId::of(&inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
-        LintId::of(&inherent_to_string::INHERENT_TO_STRING),
-        LintId::of(&len_zero::COMPARISON_TO_EMPTY),
-        LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY),
-        LintId::of(&len_zero::LEN_ZERO),
-        LintId::of(&literal_representation::INCONSISTENT_DIGIT_GROUPING),
-        LintId::of(&literal_representation::UNUSUAL_BYTE_GROUPINGS),
-        LintId::of(&loops::EMPTY_LOOP),
-        LintId::of(&loops::FOR_KV_MAP),
-        LintId::of(&loops::NEEDLESS_RANGE_LOOP),
-        LintId::of(&loops::SAME_ITEM_PUSH),
-        LintId::of(&loops::WHILE_LET_ON_ITERATOR),
-        LintId::of(&main_recursion::MAIN_RECURSION),
-        LintId::of(&manual_async_fn::MANUAL_ASYNC_FN),
-        LintId::of(&manual_map::MANUAL_MAP),
-        LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
-        LintId::of(&map_clone::MAP_CLONE),
-        LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH),
-        LintId::of(&matches::MATCH_LIKE_MATCHES_MACRO),
-        LintId::of(&matches::MATCH_OVERLAPPING_ARM),
-        LintId::of(&matches::MATCH_REF_PATS),
-        LintId::of(&matches::REDUNDANT_PATTERN_MATCHING),
-        LintId::of(&matches::SINGLE_MATCH),
-        LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
-        LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT),
-        LintId::of(&methods::BYTES_NTH),
-        LintId::of(&methods::CHARS_LAST_CMP),
-        LintId::of(&methods::CHARS_NEXT_CMP),
-        LintId::of(&methods::FROM_ITER_INSTEAD_OF_COLLECT),
-        LintId::of(&methods::INTO_ITER_ON_REF),
-        LintId::of(&methods::ITER_CLONED_COLLECT),
-        LintId::of(&methods::ITER_NEXT_SLICE),
-        LintId::of(&methods::ITER_NTH_ZERO),
-        LintId::of(&methods::ITER_SKIP_NEXT),
-        LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC),
-        LintId::of(&methods::MAP_COLLECT_RESULT_UNIT),
-        LintId::of(&methods::NEW_RET_NO_SELF),
-        LintId::of(&methods::OK_EXPECT),
-        LintId::of(&methods::OPTION_MAP_OR_NONE),
-        LintId::of(&methods::RESULT_MAP_OR_INTO_OPTION),
-        LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT),
-        LintId::of(&methods::SINGLE_CHAR_ADD_STR),
-        LintId::of(&methods::STRING_EXTEND_CHARS),
-        LintId::of(&methods::UNNECESSARY_FOLD),
-        LintId::of(&methods::UNNECESSARY_LAZY_EVALUATIONS),
-        LintId::of(&methods::WRONG_SELF_CONVENTION),
-        LintId::of(&misc::TOPLEVEL_REF_ARG),
-        LintId::of(&misc::ZERO_PTR),
-        LintId::of(&misc_early::BUILTIN_TYPE_SHADOW),
-        LintId::of(&misc_early::DOUBLE_NEG),
-        LintId::of(&misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
-        LintId::of(&misc_early::MIXED_CASE_HEX_LITERALS),
-        LintId::of(&misc_early::REDUNDANT_PATTERN),
-        LintId::of(&mut_mutex_lock::MUT_MUTEX_LOCK),
-        LintId::of(&mut_reference::UNNECESSARY_MUT_PASSED),
-        LintId::of(&neg_multiply::NEG_MULTIPLY),
-        LintId::of(&new_without_default::NEW_WITHOUT_DEFAULT),
-        LintId::of(&non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
-        LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
-        LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
-        LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES),
-        LintId::of(&ptr::CMP_NULL),
-        LintId::of(&ptr::PTR_ARG),
-        LintId::of(&ptr_eq::PTR_EQ),
-        LintId::of(&question_mark::QUESTION_MARK),
-        LintId::of(&ranges::MANUAL_RANGE_CONTAINS),
-        LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES),
-        LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
-        LintId::of(&returns::LET_AND_RETURN),
-        LintId::of(&returns::NEEDLESS_RETURN),
-        LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
-        LintId::of(&suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
-        LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
-        LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME),
-        LintId::of(&try_err::TRY_ERR),
-        LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
-        LintId::of(&unused_unit::UNUSED_UNIT),
-        LintId::of(&upper_case_acronyms::UPPER_CASE_ACRONYMS),
-        LintId::of(&write::PRINTLN_EMPTY_STRING),
-        LintId::of(&write::PRINT_LITERAL),
-        LintId::of(&write::PRINT_WITH_NEWLINE),
-        LintId::of(&write::WRITELN_EMPTY_STRING),
-        LintId::of(&write::WRITE_LITERAL),
-        LintId::of(&write::WRITE_WITH_NEWLINE),
+        LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
+        LintId::of(assign_ops::ASSIGN_OP_PATTERN),
+        LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
+        LintId::of(blacklisted_name::BLACKLISTED_NAME),
+        LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
+        LintId::of(casts::FN_TO_NUMERIC_CAST),
+        LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
+        LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
+        LintId::of(collapsible_if::COLLAPSIBLE_IF),
+        LintId::of(collapsible_match::COLLAPSIBLE_MATCH),
+        LintId::of(comparison_chain::COMPARISON_CHAIN),
+        LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
+        LintId::of(doc::MISSING_SAFETY_DOC),
+        LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
+        LintId::of(enum_variants::ENUM_VARIANT_NAMES),
+        LintId::of(enum_variants::MODULE_INCEPTION),
+        LintId::of(eq_op::OP_REF),
+        LintId::of(eta_reduction::REDUNDANT_CLOSURE),
+        LintId::of(float_literal::EXCESSIVE_PRECISION),
+        LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
+        LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
+        LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
+        LintId::of(from_over_into::FROM_OVER_INTO),
+        LintId::of(from_str_radix_10::FROM_STR_RADIX_10),
+        LintId::of(functions::DOUBLE_MUST_USE),
+        LintId::of(functions::MUST_USE_UNIT),
+        LintId::of(functions::RESULT_UNIT_ERR),
+        LintId::of(if_let_some_result::IF_LET_SOME_RESULT),
+        LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
+        LintId::of(inherent_to_string::INHERENT_TO_STRING),
+        LintId::of(len_zero::COMPARISON_TO_EMPTY),
+        LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
+        LintId::of(len_zero::LEN_ZERO),
+        LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING),
+        LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS),
+        LintId::of(loops::EMPTY_LOOP),
+        LintId::of(loops::FOR_KV_MAP),
+        LintId::of(loops::NEEDLESS_RANGE_LOOP),
+        LintId::of(loops::SAME_ITEM_PUSH),
+        LintId::of(loops::WHILE_LET_ON_ITERATOR),
+        LintId::of(main_recursion::MAIN_RECURSION),
+        LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
+        LintId::of(manual_map::MANUAL_MAP),
+        LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
+        LintId::of(map_clone::MAP_CLONE),
+        LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
+        LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
+        LintId::of(matches::MATCH_OVERLAPPING_ARM),
+        LintId::of(matches::MATCH_REF_PATS),
+        LintId::of(matches::REDUNDANT_PATTERN_MATCHING),
+        LintId::of(matches::SINGLE_MATCH),
+        LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
+        LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT),
+        LintId::of(methods::BYTES_NTH),
+        LintId::of(methods::CHARS_LAST_CMP),
+        LintId::of(methods::CHARS_NEXT_CMP),
+        LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT),
+        LintId::of(methods::INTO_ITER_ON_REF),
+        LintId::of(methods::ITER_CLONED_COLLECT),
+        LintId::of(methods::ITER_NEXT_SLICE),
+        LintId::of(methods::ITER_NTH_ZERO),
+        LintId::of(methods::ITER_SKIP_NEXT),
+        LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
+        LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
+        LintId::of(methods::NEW_RET_NO_SELF),
+        LintId::of(methods::OK_EXPECT),
+        LintId::of(methods::OPTION_MAP_OR_NONE),
+        LintId::of(methods::RESULT_MAP_OR_INTO_OPTION),
+        LintId::of(methods::SHOULD_IMPLEMENT_TRAIT),
+        LintId::of(methods::SINGLE_CHAR_ADD_STR),
+        LintId::of(methods::STRING_EXTEND_CHARS),
+        LintId::of(methods::UNNECESSARY_FOLD),
+        LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
+        LintId::of(methods::WRONG_SELF_CONVENTION),
+        LintId::of(misc::TOPLEVEL_REF_ARG),
+        LintId::of(misc::ZERO_PTR),
+        LintId::of(misc_early::BUILTIN_TYPE_SHADOW),
+        LintId::of(misc_early::DOUBLE_NEG),
+        LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
+        LintId::of(misc_early::MIXED_CASE_HEX_LITERALS),
+        LintId::of(misc_early::REDUNDANT_PATTERN),
+        LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
+        LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
+        LintId::of(neg_multiply::NEG_MULTIPLY),
+        LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
+        LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
+        LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
+        LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
+        LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES),
+        LintId::of(ptr::CMP_NULL),
+        LintId::of(ptr::PTR_ARG),
+        LintId::of(ptr_eq::PTR_EQ),
+        LintId::of(question_mark::QUESTION_MARK),
+        LintId::of(ranges::MANUAL_RANGE_CONTAINS),
+        LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES),
+        LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
+        LintId::of(returns::LET_AND_RETURN),
+        LintId::of(returns::NEEDLESS_RETURN),
+        LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
+        LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
+        LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
+        LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
+        LintId::of(try_err::TRY_ERR),
+        LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
+        LintId::of(unused_unit::UNUSED_UNIT),
+        LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS),
+        LintId::of(write::PRINTLN_EMPTY_STRING),
+        LintId::of(write::PRINT_LITERAL),
+        LintId::of(write::PRINT_WITH_NEWLINE),
+        LintId::of(write::WRITELN_EMPTY_STRING),
+        LintId::of(write::WRITE_LITERAL),
+        LintId::of(write::WRITE_WITH_NEWLINE),
     ]);
 
     store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec![
-        LintId::of(&assign_ops::MISREFACTORED_ASSIGN_OP),
-        LintId::of(&attrs::DEPRECATED_CFG_ATTR),
-        LintId::of(&booleans::NONMINIMAL_BOOL),
-        LintId::of(&casts::CHAR_LIT_AS_U8),
-        LintId::of(&casts::UNNECESSARY_CAST),
-        LintId::of(&double_comparison::DOUBLE_COMPARISONS),
-        LintId::of(&double_parens::DOUBLE_PARENS),
-        LintId::of(&duration_subsec::DURATION_SUBSEC),
-        LintId::of(&eval_order_dependence::DIVERGING_SUB_EXPRESSION),
-        LintId::of(&eval_order_dependence::EVAL_ORDER_DEPENDENCE),
-        LintId::of(&explicit_write::EXPLICIT_WRITE),
-        LintId::of(&format::USELESS_FORMAT),
-        LintId::of(&functions::TOO_MANY_ARGUMENTS),
-        LintId::of(&get_last_with_len::GET_LAST_WITH_LEN),
-        LintId::of(&identity_op::IDENTITY_OP),
-        LintId::of(&int_plus_one::INT_PLUS_ONE),
-        LintId::of(&lifetimes::EXTRA_UNUSED_LIFETIMES),
-        LintId::of(&lifetimes::NEEDLESS_LIFETIMES),
-        LintId::of(&loops::EXPLICIT_COUNTER_LOOP),
-        LintId::of(&loops::MANUAL_FLATTEN),
-        LintId::of(&loops::MUT_RANGE_BOUND),
-        LintId::of(&loops::SINGLE_ELEMENT_LOOP),
-        LintId::of(&loops::WHILE_LET_LOOP),
-        LintId::of(&manual_strip::MANUAL_STRIP),
-        LintId::of(&manual_unwrap_or::MANUAL_UNWRAP_OR),
-        LintId::of(&map_identity::MAP_IDENTITY),
-        LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
-        LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),
-        LintId::of(&matches::MATCH_AS_REF),
-        LintId::of(&matches::MATCH_SINGLE_BINDING),
-        LintId::of(&matches::WILDCARD_IN_OR_PATTERNS),
-        LintId::of(&methods::BIND_INSTEAD_OF_MAP),
-        LintId::of(&methods::CLONE_ON_COPY),
-        LintId::of(&methods::FILTER_MAP_IDENTITY),
-        LintId::of(&methods::FILTER_NEXT),
-        LintId::of(&methods::FLAT_MAP_IDENTITY),
-        LintId::of(&methods::INSPECT_FOR_EACH),
-        LintId::of(&methods::ITER_COUNT),
-        LintId::of(&methods::MANUAL_FILTER_MAP),
-        LintId::of(&methods::MANUAL_FIND_MAP),
-        LintId::of(&methods::OPTION_AS_REF_DEREF),
-        LintId::of(&methods::SEARCH_IS_SOME),
-        LintId::of(&methods::SKIP_WHILE_NEXT),
-        LintId::of(&methods::SUSPICIOUS_MAP),
-        LintId::of(&methods::UNNECESSARY_FILTER_MAP),
-        LintId::of(&methods::USELESS_ASREF),
-        LintId::of(&misc::SHORT_CIRCUIT_STATEMENT),
-        LintId::of(&misc_early::UNNEEDED_WILDCARD_PATTERN),
-        LintId::of(&misc_early::ZERO_PREFIXED_LITERAL),
-        LintId::of(&needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
-        LintId::of(&needless_bool::BOOL_COMPARISON),
-        LintId::of(&needless_bool::NEEDLESS_BOOL),
-        LintId::of(&needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
-        LintId::of(&needless_question_mark::NEEDLESS_QUESTION_MARK),
-        LintId::of(&needless_update::NEEDLESS_UPDATE),
-        LintId::of(&neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
-        LintId::of(&no_effect::NO_EFFECT),
-        LintId::of(&no_effect::UNNECESSARY_OPERATION),
-        LintId::of(&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
-        LintId::of(&partialeq_ne_impl::PARTIALEQ_NE_IMPL),
-        LintId::of(&precedence::PRECEDENCE),
-        LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
-        LintId::of(&ranges::RANGE_ZIP_WITH_LEN),
-        LintId::of(&redundant_closure_call::REDUNDANT_CLOSURE_CALL),
-        LintId::of(&redundant_slicing::REDUNDANT_SLICING),
-        LintId::of(&reference::DEREF_ADDROF),
-        LintId::of(&reference::REF_IN_DEREF),
-        LintId::of(&repeat_once::REPEAT_ONCE),
-        LintId::of(&strings::STRING_FROM_UTF8_AS_BYTES),
-        LintId::of(&swap::MANUAL_SWAP),
-        LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT),
-        LintId::of(&transmute::CROSSPOINTER_TRANSMUTE),
-        LintId::of(&transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS),
-        LintId::of(&transmute::TRANSMUTE_BYTES_TO_STR),
-        LintId::of(&transmute::TRANSMUTE_FLOAT_TO_INT),
-        LintId::of(&transmute::TRANSMUTE_INT_TO_BOOL),
-        LintId::of(&transmute::TRANSMUTE_INT_TO_CHAR),
-        LintId::of(&transmute::TRANSMUTE_INT_TO_FLOAT),
-        LintId::of(&transmute::TRANSMUTE_PTR_TO_PTR),
-        LintId::of(&transmute::TRANSMUTE_PTR_TO_REF),
-        LintId::of(&types::BORROWED_BOX),
-        LintId::of(&types::TYPE_COMPLEXITY),
-        LintId::of(&types::VEC_BOX),
-        LintId::of(&unit_types::UNIT_ARG),
-        LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY),
-        LintId::of(&unwrap::UNNECESSARY_UNWRAP),
-        LintId::of(&useless_conversion::USELESS_CONVERSION),
-        LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO),
+        LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP),
+        LintId::of(attrs::DEPRECATED_CFG_ATTR),
+        LintId::of(booleans::NONMINIMAL_BOOL),
+        LintId::of(casts::CHAR_LIT_AS_U8),
+        LintId::of(casts::UNNECESSARY_CAST),
+        LintId::of(copies::BRANCHES_SHARING_CODE),
+        LintId::of(double_comparison::DOUBLE_COMPARISONS),
+        LintId::of(double_parens::DOUBLE_PARENS),
+        LintId::of(duration_subsec::DURATION_SUBSEC),
+        LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION),
+        LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE),
+        LintId::of(explicit_write::EXPLICIT_WRITE),
+        LintId::of(format::USELESS_FORMAT),
+        LintId::of(functions::TOO_MANY_ARGUMENTS),
+        LintId::of(get_last_with_len::GET_LAST_WITH_LEN),
+        LintId::of(identity_op::IDENTITY_OP),
+        LintId::of(int_plus_one::INT_PLUS_ONE),
+        LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES),
+        LintId::of(lifetimes::NEEDLESS_LIFETIMES),
+        LintId::of(loops::EXPLICIT_COUNTER_LOOP),
+        LintId::of(loops::MANUAL_FLATTEN),
+        LintId::of(loops::MUT_RANGE_BOUND),
+        LintId::of(loops::SINGLE_ELEMENT_LOOP),
+        LintId::of(loops::WHILE_LET_LOOP),
+        LintId::of(manual_strip::MANUAL_STRIP),
+        LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR),
+        LintId::of(map_identity::MAP_IDENTITY),
+        LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
+        LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
+        LintId::of(matches::MATCH_AS_REF),
+        LintId::of(matches::MATCH_SINGLE_BINDING),
+        LintId::of(matches::WILDCARD_IN_OR_PATTERNS),
+        LintId::of(methods::BIND_INSTEAD_OF_MAP),
+        LintId::of(methods::CLONE_ON_COPY),
+        LintId::of(methods::FILTER_MAP_IDENTITY),
+        LintId::of(methods::FILTER_NEXT),
+        LintId::of(methods::FLAT_MAP_IDENTITY),
+        LintId::of(methods::INSPECT_FOR_EACH),
+        LintId::of(methods::ITER_COUNT),
+        LintId::of(methods::MANUAL_FILTER_MAP),
+        LintId::of(methods::MANUAL_FIND_MAP),
+        LintId::of(methods::OPTION_AS_REF_DEREF),
+        LintId::of(methods::OPTION_FILTER_MAP),
+        LintId::of(methods::SEARCH_IS_SOME),
+        LintId::of(methods::SKIP_WHILE_NEXT),
+        LintId::of(methods::SUSPICIOUS_MAP),
+        LintId::of(methods::UNNECESSARY_FILTER_MAP),
+        LintId::of(methods::USELESS_ASREF),
+        LintId::of(misc::SHORT_CIRCUIT_STATEMENT),
+        LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
+        LintId::of(misc_early::ZERO_PREFIXED_LITERAL),
+        LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
+        LintId::of(needless_bool::BOOL_COMPARISON),
+        LintId::of(needless_bool::NEEDLESS_BOOL),
+        LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
+        LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
+        LintId::of(needless_update::NEEDLESS_UPDATE),
+        LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
+        LintId::of(no_effect::NO_EFFECT),
+        LintId::of(no_effect::UNNECESSARY_OPERATION),
+        LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
+        LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
+        LintId::of(precedence::PRECEDENCE),
+        LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
+        LintId::of(ranges::RANGE_ZIP_WITH_LEN),
+        LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL),
+        LintId::of(redundant_slicing::REDUNDANT_SLICING),
+        LintId::of(reference::DEREF_ADDROF),
+        LintId::of(reference::REF_IN_DEREF),
+        LintId::of(repeat_once::REPEAT_ONCE),
+        LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
+        LintId::of(swap::MANUAL_SWAP),
+        LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT),
+        LintId::of(transmute::CROSSPOINTER_TRANSMUTE),
+        LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS),
+        LintId::of(transmute::TRANSMUTE_BYTES_TO_STR),
+        LintId::of(transmute::TRANSMUTE_FLOAT_TO_INT),
+        LintId::of(transmute::TRANSMUTE_INT_TO_BOOL),
+        LintId::of(transmute::TRANSMUTE_INT_TO_CHAR),
+        LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
+        LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
+        LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
+        LintId::of(types::BORROWED_BOX),
+        LintId::of(types::TYPE_COMPLEXITY),
+        LintId::of(types::VEC_BOX),
+        LintId::of(unit_types::UNIT_ARG),
+        LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY),
+        LintId::of(unwrap::UNNECESSARY_UNWRAP),
+        LintId::of(useless_conversion::USELESS_CONVERSION),
+        LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO),
     ]);
 
     store.register_group(true, "clippy::correctness", Some("clippy_correctness"), vec![
-        LintId::of(&approx_const::APPROX_CONSTANT),
-        LintId::of(&async_yields_async::ASYNC_YIELDS_ASYNC),
-        LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING),
-        LintId::of(&attrs::DEPRECATED_SEMVER),
-        LintId::of(&attrs::MISMATCHED_TARGET_OS),
-        LintId::of(&attrs::USELESS_ATTRIBUTE),
-        LintId::of(&bit_mask::BAD_BIT_MASK),
-        LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK),
-        LintId::of(&booleans::LOGIC_BUG),
-        LintId::of(&casts::CAST_REF_TO_MUT),
-        LintId::of(&copies::IFS_SAME_COND),
-        LintId::of(&copies::IF_SAME_THEN_ELSE),
-        LintId::of(&derive::DERIVE_HASH_XOR_EQ),
-        LintId::of(&derive::DERIVE_ORD_XOR_PARTIAL_ORD),
-        LintId::of(&drop_forget_ref::DROP_COPY),
-        LintId::of(&drop_forget_ref::DROP_REF),
-        LintId::of(&drop_forget_ref::FORGET_COPY),
-        LintId::of(&drop_forget_ref::FORGET_REF),
-        LintId::of(&enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
-        LintId::of(&eq_op::EQ_OP),
-        LintId::of(&erasing_op::ERASING_OP),
-        LintId::of(&float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
-        LintId::of(&formatting::POSSIBLE_MISSING_COMMA),
-        LintId::of(&functions::NOT_UNSAFE_PTR_ARG_DEREF),
-        LintId::of(&if_let_mutex::IF_LET_MUTEX),
-        LintId::of(&indexing_slicing::OUT_OF_BOUNDS_INDEXING),
-        LintId::of(&infinite_iter::INFINITE_ITER),
-        LintId::of(&inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY),
-        LintId::of(&inline_fn_without_body::INLINE_FN_WITHOUT_BODY),
-        LintId::of(&let_underscore::LET_UNDERSCORE_LOCK),
-        LintId::of(&literal_representation::MISTYPED_LITERAL_SUFFIXES),
-        LintId::of(&loops::FOR_LOOPS_OVER_FALLIBLES),
-        LintId::of(&loops::ITER_NEXT_LOOP),
-        LintId::of(&loops::NEVER_LOOP),
-        LintId::of(&loops::WHILE_IMMUTABLE_CONDITION),
-        LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM),
-        LintId::of(&mem_replace::MEM_REPLACE_WITH_UNINIT),
-        LintId::of(&methods::CLONE_DOUBLE_REF),
-        LintId::of(&methods::ITERATOR_STEP_BY_ZERO),
-        LintId::of(&methods::UNINIT_ASSUMED_INIT),
-        LintId::of(&methods::ZST_OFFSET),
-        LintId::of(&minmax::MIN_MAX),
-        LintId::of(&misc::CMP_NAN),
-        LintId::of(&misc::FLOAT_CMP),
-        LintId::of(&misc::MODULO_ONE),
-        LintId::of(&mut_key::MUTABLE_KEY_TYPE),
-        LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS),
-        LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP),
-        LintId::of(&ptr::MUT_FROM_REF),
-        LintId::of(&ranges::REVERSED_EMPTY_RANGES),
-        LintId::of(&regex::INVALID_REGEX),
-        LintId::of(&self_assignment::SELF_ASSIGNMENT),
-        LintId::of(&serde_api::SERDE_API_MISUSE),
-        LintId::of(&size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
-        LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
-        LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
-        LintId::of(&swap::ALMOST_SWAPPED),
-        LintId::of(&to_string_in_display::TO_STRING_IN_DISPLAY),
-        LintId::of(&transmute::UNSOUND_COLLECTION_TRANSMUTE),
-        LintId::of(&transmute::WRONG_TRANSMUTE),
-        LintId::of(&transmuting_null::TRANSMUTING_NULL),
-        LintId::of(&types::ABSURD_EXTREME_COMPARISONS),
-        LintId::of(&undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
-        LintId::of(&unicode::INVISIBLE_CHARACTERS),
-        LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
-        LintId::of(&unit_types::UNIT_CMP),
-        LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
-        LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
-        LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT),
-        LintId::of(&unwrap::PANICKING_UNWRAP),
-        LintId::of(&vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
+        LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS),
+        LintId::of(approx_const::APPROX_CONSTANT),
+        LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC),
+        LintId::of(atomic_ordering::INVALID_ATOMIC_ORDERING),
+        LintId::of(attrs::DEPRECATED_SEMVER),
+        LintId::of(attrs::MISMATCHED_TARGET_OS),
+        LintId::of(attrs::USELESS_ATTRIBUTE),
+        LintId::of(bit_mask::BAD_BIT_MASK),
+        LintId::of(bit_mask::INEFFECTIVE_BIT_MASK),
+        LintId::of(booleans::LOGIC_BUG),
+        LintId::of(casts::CAST_REF_TO_MUT),
+        LintId::of(copies::IFS_SAME_COND),
+        LintId::of(copies::IF_SAME_THEN_ELSE),
+        LintId::of(derive::DERIVE_HASH_XOR_EQ),
+        LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
+        LintId::of(drop_forget_ref::DROP_COPY),
+        LintId::of(drop_forget_ref::DROP_REF),
+        LintId::of(drop_forget_ref::FORGET_COPY),
+        LintId::of(drop_forget_ref::FORGET_REF),
+        LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
+        LintId::of(eq_op::EQ_OP),
+        LintId::of(erasing_op::ERASING_OP),
+        LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
+        LintId::of(formatting::POSSIBLE_MISSING_COMMA),
+        LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF),
+        LintId::of(if_let_mutex::IF_LET_MUTEX),
+        LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
+        LintId::of(infinite_iter::INFINITE_ITER),
+        LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY),
+        LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY),
+        LintId::of(let_underscore::LET_UNDERSCORE_LOCK),
+        LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES),
+        LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES),
+        LintId::of(loops::ITER_NEXT_LOOP),
+        LintId::of(loops::NEVER_LOOP),
+        LintId::of(loops::WHILE_IMMUTABLE_CONDITION),
+        LintId::of(mem_discriminant::MEM_DISCRIMINANT_NON_ENUM),
+        LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
+        LintId::of(methods::CLONE_DOUBLE_REF),
+        LintId::of(methods::ITERATOR_STEP_BY_ZERO),
+        LintId::of(methods::UNINIT_ASSUMED_INIT),
+        LintId::of(methods::ZST_OFFSET),
+        LintId::of(minmax::MIN_MAX),
+        LintId::of(misc::CMP_NAN),
+        LintId::of(misc::FLOAT_CMP),
+        LintId::of(misc::MODULO_ONE),
+        LintId::of(mut_key::MUTABLE_KEY_TYPE),
+        LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
+        LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
+        LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
+        LintId::of(ptr::MUT_FROM_REF),
+        LintId::of(ranges::REVERSED_EMPTY_RANGES),
+        LintId::of(regex::INVALID_REGEX),
+        LintId::of(self_assignment::SELF_ASSIGNMENT),
+        LintId::of(serde_api::SERDE_API_MISUSE),
+        LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
+        LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
+        LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
+        LintId::of(swap::ALMOST_SWAPPED),
+        LintId::of(to_string_in_display::TO_STRING_IN_DISPLAY),
+        LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
+        LintId::of(transmute::WRONG_TRANSMUTE),
+        LintId::of(transmuting_null::TRANSMUTING_NULL),
+        LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
+        LintId::of(unicode::INVISIBLE_CHARACTERS),
+        LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
+        LintId::of(unit_types::UNIT_CMP),
+        LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
+        LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS),
+        LintId::of(unused_io_amount::UNUSED_IO_AMOUNT),
+        LintId::of(unwrap::PANICKING_UNWRAP),
+        LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
     ]);
 
     store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
-        LintId::of(&entry::MAP_ENTRY),
-        LintId::of(&escape::BOXED_LOCAL),
-        LintId::of(&large_const_arrays::LARGE_CONST_ARRAYS),
-        LintId::of(&large_enum_variant::LARGE_ENUM_VARIANT),
-        LintId::of(&loops::MANUAL_MEMCPY),
-        LintId::of(&loops::NEEDLESS_COLLECT),
-        LintId::of(&methods::EXPECT_FUN_CALL),
-        LintId::of(&methods::ITER_NTH),
-        LintId::of(&methods::OR_FUN_CALL),
-        LintId::of(&methods::SINGLE_CHAR_PATTERN),
-        LintId::of(&misc::CMP_OWNED),
-        LintId::of(&mutex_atomic::MUTEX_ATOMIC),
-        LintId::of(&redundant_clone::REDUNDANT_CLONE),
-        LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
-        LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE),
-        LintId::of(&types::BOX_VEC),
-        LintId::of(&types::REDUNDANT_ALLOCATION),
-        LintId::of(&vec::USELESS_VEC),
-        LintId::of(&vec_init_then_push::VEC_INIT_THEN_PUSH),
+        LintId::of(entry::MAP_ENTRY),
+        LintId::of(escape::BOXED_LOCAL),
+        LintId::of(large_const_arrays::LARGE_CONST_ARRAYS),
+        LintId::of(large_enum_variant::LARGE_ENUM_VARIANT),
+        LintId::of(loops::MANUAL_MEMCPY),
+        LintId::of(loops::NEEDLESS_COLLECT),
+        LintId::of(methods::EXPECT_FUN_CALL),
+        LintId::of(methods::ITER_NTH),
+        LintId::of(methods::OR_FUN_CALL),
+        LintId::of(methods::SINGLE_CHAR_PATTERN),
+        LintId::of(misc::CMP_OWNED),
+        LintId::of(mutex_atomic::MUTEX_ATOMIC),
+        LintId::of(redundant_clone::REDUNDANT_CLONE),
+        LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
+        LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
+        LintId::of(types::BOX_VEC),
+        LintId::of(types::REDUNDANT_ALLOCATION),
+        LintId::of(vec::USELESS_VEC),
+        LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH),
     ]);
 
     store.register_group(true, "clippy::cargo", Some("clippy_cargo"), vec![
-        LintId::of(&cargo_common_metadata::CARGO_COMMON_METADATA),
-        LintId::of(&multiple_crate_versions::MULTIPLE_CRATE_VERSIONS),
-        LintId::of(&wildcard_dependencies::WILDCARD_DEPENDENCIES),
+        LintId::of(cargo_common_metadata::CARGO_COMMON_METADATA),
+        LintId::of(multiple_crate_versions::MULTIPLE_CRATE_VERSIONS),
+        LintId::of(wildcard_dependencies::WILDCARD_DEPENDENCIES),
     ]);
 
     store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
-        LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
-        LintId::of(&cognitive_complexity::COGNITIVE_COMPLEXITY),
-        LintId::of(&disallowed_method::DISALLOWED_METHOD),
-        LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM),
-        LintId::of(&floating_point_arithmetic::IMPRECISE_FLOPS),
-        LintId::of(&floating_point_arithmetic::SUBOPTIMAL_FLOPS),
-        LintId::of(&future_not_send::FUTURE_NOT_SEND),
-        LintId::of(&let_if_seq::USELESS_LET_IF_SEQ),
-        LintId::of(&missing_const_for_fn::MISSING_CONST_FOR_FN),
-        LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
-        LintId::of(&mutex_atomic::MUTEX_INTEGER),
-        LintId::of(&needless_borrow::NEEDLESS_BORROW),
-        LintId::of(&path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
-        LintId::of(&redundant_pub_crate::REDUNDANT_PUB_CRATE),
-        LintId::of(&regex::TRIVIAL_REGEX),
-        LintId::of(&strings::STRING_LIT_AS_BYTES),
-        LintId::of(&transmute::USELESS_TRANSMUTE),
-        LintId::of(&use_self::USE_SELF),
+        LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
+        LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY),
+        LintId::of(disallowed_method::DISALLOWED_METHOD),
+        LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM),
+        LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS),
+        LintId::of(floating_point_arithmetic::SUBOPTIMAL_FLOPS),
+        LintId::of(future_not_send::FUTURE_NOT_SEND),
+        LintId::of(let_if_seq::USELESS_LET_IF_SEQ),
+        LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
+        LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
+        LintId::of(mutex_atomic::MUTEX_INTEGER),
+        LintId::of(needless_borrow::NEEDLESS_BORROW),
+        LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
+        LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE),
+        LintId::of(regex::TRIVIAL_REGEX),
+        LintId::of(strings::STRING_LIT_AS_BYTES),
+        LintId::of(transmute::USELESS_TRANSMUTE),
+        LintId::of(use_self::USE_SELF),
     ]);
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index e3b3fa21cab..116ad072837 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -81,7 +81,7 @@ declare_lint_pass!(Lifetimes => [NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES]);
 impl<'tcx> LateLintPass<'tcx> for Lifetimes {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         if let ItemKind::Fn(ref sig, ref generics, id) = item.kind {
-            check_fn_inner(cx, &sig.decl, Some(id), generics, item.span, true);
+            check_fn_inner(cx, sig.decl, Some(id), generics, item.span, true);
         }
     }
 
@@ -90,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
             let report_extra_lifetimes = trait_ref_of_method(cx, item.hir_id()).is_none();
             check_fn_inner(
                 cx,
-                &sig.decl,
+                sig.decl,
                 Some(id),
                 &item.generics,
                 item.span,
@@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
                 TraitFn::Required(_) => None,
                 TraitFn::Provided(id) => Some(id),
             };
-            check_fn_inner(cx, &sig.decl, body, &item.generics, item.span, true);
+            check_fn_inner(cx, sig.decl, body, &item.generics, item.span, true);
         }
     }
 }
@@ -149,7 +149,7 @@ fn check_fn_inner<'tcx>(
                     .last()
                     .expect("a path must have at least one segment")
                     .args;
-                if let Some(ref params) = *params {
+                if let Some(params) = *params {
                     let lifetimes = params.args.iter().filter_map(|arg| match arg {
                         GenericArg::Lifetime(lt) => Some(lt),
                         _ => None,
@@ -163,7 +163,7 @@ fn check_fn_inner<'tcx>(
             }
         }
     }
-    if could_use_elision(cx, decl, body, &generics.params) {
+    if could_use_elision(cx, decl, body, generics.params) {
         span_lint(
             cx,
             NEEDLESS_LIFETIMES,
@@ -201,7 +201,7 @@ fn could_use_elision<'tcx>(
         input_visitor.visit_ty(arg);
     }
     // extract lifetimes in output type
-    if let Return(ref ty) = func.output {
+    if let Return(ty) = func.output {
         output_visitor.visit_ty(ty);
     }
     for lt in named_generics {
@@ -416,12 +416,12 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, where_clause: &'tcx WhereCl
                 // a predicate like F: Trait or F: for<'a> Trait<'a>
                 let mut visitor = RefVisitor::new(cx);
                 // walk the type F, it may not contain LT refs
-                walk_ty(&mut visitor, &pred.bounded_ty);
+                walk_ty(&mut visitor, pred.bounded_ty);
                 if !visitor.all_lts().is_empty() {
                     return true;
                 }
                 // if the bounds define new lifetimes, they are fine to occur
-                let allowed_lts = allowed_lts_from(&pred.bound_generic_params);
+                let allowed_lts = allowed_lts_from(pred.bound_generic_params);
                 // now walk the bounds
                 for bound in pred.bounds.iter() {
                     walk_param_bound(&mut visitor, bound);
@@ -433,8 +433,8 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, where_clause: &'tcx WhereCl
             },
             WherePredicate::EqPredicate(ref pred) => {
                 let mut visitor = RefVisitor::new(cx);
-                walk_ty(&mut visitor, &pred.lhs_ty);
-                walk_ty(&mut visitor, &pred.rhs_ty);
+                walk_ty(&mut visitor, pred.lhs_ty);
+                walk_ty(&mut visitor, pred.rhs_ty);
                 if !visitor.lts.is_empty() {
                     return true;
                 }
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index 54470519260..e93b2e36b86 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -249,7 +249,7 @@ impl LiteralDigitGrouping {
     fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) {
         if_chain! {
             if let Some(src) = snippet_opt(cx, lit.span);
-            if let Some(mut num_lit) = NumericLiteral::from_lit(&src, &lit);
+            if let Some(mut num_lit) = NumericLiteral::from_lit(&src, lit);
             then {
                 if !Self::check_for_mistyped_suffix(cx, lit.span, &mut num_lit) {
                     return;
@@ -439,7 +439,7 @@ impl DecimalLiteralRepresentation {
         if_chain! {
             if let LitKind::Int(val, _) = lit.kind;
             if let Some(src) = snippet_opt(cx, lit.span);
-            if let Some(num_lit) = NumericLiteral::from_lit(&src, &lit);
+            if let Some(num_lit) = NumericLiteral::from_lit(&src, lit);
             if num_lit.radix == Radix::Decimal;
             if val >= u128::from(self.threshold);
             then {
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
index f14dbb1d642..98e60f7ed85 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
@@ -26,7 +26,7 @@ pub(super) fn check<'tcx>(
 
     // For each candidate, check the parent block to see if
     // it's initialized to zero at the start of the loop.
-    if let Some(block) = get_enclosing_block(&cx, expr.hir_id) {
+    if let Some(block) = get_enclosing_block(cx, expr.hir_id) {
         for id in increment_visitor.into_results() {
             let mut initialize_visitor = InitializeVisitor::new(cx, expr, id);
             walk_block(&mut initialize_visitor, block);
diff --git a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
index 8f18f54119b..666b8c58728 100644
--- a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
@@ -19,7 +19,7 @@ pub(super) fn check<'tcx>(
 ) {
     let pat_span = pat.span;
 
-    if let PatKind::Tuple(ref pat, _) = pat.kind {
+    if let PatKind::Tuple(pat, _) = pat.kind {
         if pat.len() == 2 {
             let arg_span = arg.span;
             let (new_pat_span, kind, ty, mutbl) = match *cx.typeck_results().expr_ty(arg).kind() {
@@ -35,7 +35,7 @@ pub(super) fn check<'tcx>(
                 Mutability::Mut => "_mut",
             };
             let arg = match arg.kind {
-                ExprKind::AddrOf(BorrowKind::Ref, _, ref expr) => &**expr,
+                ExprKind::AddrOf(BorrowKind::Ref, _, expr) => expr,
                 _ => arg,
             };
 
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
index 8d2b9cccba4..94743cfcf46 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
@@ -18,7 +18,7 @@ pub(super) fn check<'tcx>(
     body: &'tcx Expr<'_>,
     span: Span,
 ) {
-    if let ExprKind::Block(ref block, _) = body.kind {
+    if let ExprKind::Block(block, _) = body.kind {
         // Ensure the `if let` statement is the only expression or statement in the for-loop
         let inner_expr = if block.stmts.len() == 1 && block.expr.is_none() {
             let match_stmt = &block.stmts[0];
@@ -36,7 +36,7 @@ pub(super) fn check<'tcx>(
         if_chain! {
             if let Some(inner_expr) = inner_expr;
             if let ExprKind::Match(
-                ref match_expr, ref match_arms, MatchSource::IfLetDesugar{ contains_else_clause: false }
+                match_expr, match_arms, MatchSource::IfLetDesugar{ contains_else_clause: false }
             ) = inner_expr.kind;
             // Ensure match_expr in `if let` statement is the same as the pat from the for-loop
             if let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind;
@@ -46,9 +46,8 @@ pub(super) fn check<'tcx>(
             let some_ctor = is_some_ctor(cx, path.res);
             let ok_ctor = is_ok_ctor(cx, path.res);
             if some_ctor || ok_ctor;
-            let if_let_type = if some_ctor { "Some" } else { "Ok" };
-
             then {
+                let if_let_type = if some_ctor { "Some" } else { "Ok" };
                 // Prepare the error message
                 let msg = format!("unnecessary `if let` since only the `{}` variant of the iterator element is used", if_let_type);
 
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
index f5758b68f60..c91fe88757e 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
@@ -61,10 +61,10 @@ pub(super) fn check<'tcx>(
                         if_chain! {
                             if let ExprKind::Index(base_left, idx_left) = lhs.kind;
                             if let ExprKind::Index(base_right, idx_right) = rhs.kind;
-                            if is_slice_like(cx, cx.typeck_results().expr_ty(base_left))
-                                && is_slice_like(cx, cx.typeck_results().expr_ty(base_right));
-                            if let Some((start_left, offset_left)) = get_details_from_idx(cx, &idx_left, &starts);
-                            if let Some((start_right, offset_right)) = get_details_from_idx(cx, &idx_right, &starts);
+                            if is_slice_like(cx, cx.typeck_results().expr_ty(base_left));
+                            if is_slice_like(cx, cx.typeck_results().expr_ty(base_right));
+                            if let Some((start_left, offset_left)) = get_details_from_idx(cx, idx_left, &starts);
+                            if let Some((start_right, offset_right)) = get_details_from_idx(cx, idx_right, &starts);
 
                             // Source and destination must be different
                             if path_to_local(base_left) != path_to_local(base_right);
@@ -168,8 +168,8 @@ fn build_manual_memcpy_suggestion<'tcx>(
         },
     };
 
-    let (dst_offset, dst_limit) = print_offset_and_limit(&dst);
-    let (src_offset, src_limit) = print_offset_and_limit(&src);
+    let (dst_offset, dst_limit) = print_offset_and_limit(dst);
+    let (src_offset, src_limit) = print_offset_and_limit(src);
 
     let dst_base_str = snippet(cx, dst.base.span, "???");
     let src_base_str = snippet(cx, src.base.span, "???");
@@ -438,7 +438,7 @@ fn get_loop_counters<'a, 'tcx>(
 
     // For each candidate, check the parent block to see if
     // it's initialized to zero at the start of the loop.
-    get_enclosing_block(&cx, expr.hir_id).and_then(|block| {
+    get_enclosing_block(cx, expr.hir_id).and_then(|block| {
         increment_visitor
             .into_results()
             .filter_map(move |var_id| {
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index 20291491998..28acefd51fe 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -562,7 +562,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
         // check for `loop { if let {} else break }` that could be `while let`
         // (also matches an explicit "match" instead of "if let")
         // (even if the "match" or "if let" is used for declaration)
-        if let ExprKind::Loop(ref block, _, LoopSource::Loop, _) = expr.kind {
+        if let ExprKind::Loop(block, _, LoopSource::Loop, _) = expr.kind {
             // also check for empty `loop {}` statements, skipping those in #[panic_handler]
             empty_loop::check(cx, expr, block);
             while_let_loop::check(cx, expr, block);
@@ -570,7 +570,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
 
         while_let_on_iterator::check(cx, expr);
 
-        if let Some((cond, body)) = higher::while_loop(&expr) {
+        if let Some((cond, body)) = higher::while_loop(expr) {
             while_immutable_condition::check(cx, cond, body);
         }
 
@@ -602,7 +602,7 @@ fn check_for_loop<'tcx>(
 fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>, expr: &Expr<'_>) {
     let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used
 
-    if let ExprKind::MethodCall(ref method, _, ref args, _) = arg.kind {
+    if let ExprKind::MethodCall(method, _, args, _) = arg.kind {
         // just the receiver, no arguments
         if args.len() == 1 {
             let method_name = &*method.ident.as_str();
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
index 5594fc7b046..4d73aef76e8 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
@@ -10,8 +10,8 @@ use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor};
 use rustc_hir::{Block, Expr, ExprKind, GenericArg, HirId, Local, Pat, PatKind, QPath, StmtKind};
 use rustc_lint::LateContext;
 use rustc_middle::hir::map::Map;
-use rustc_span::source_map::Span;
 use rustc_span::symbol::{sym, Ident};
+use rustc_span::{MultiSpan, Span};
 
 const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed";
 
@@ -21,88 +21,60 @@ pub(super) fn check<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
 }
 fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
     if_chain! {
-        if let ExprKind::MethodCall(ref method, _, ref args, _) = expr.kind;
-        if let ExprKind::MethodCall(ref chain_method, _, _, _) = args[0].kind;
+        if let ExprKind::MethodCall(method, _, args, _) = expr.kind;
+        if let ExprKind::MethodCall(chain_method, method0_span, _, _) = args[0].kind;
         if chain_method.ident.name == sym!(collect) && is_trait_method(cx, &args[0], sym::Iterator);
-        if let Some(ref generic_args) = chain_method.args;
+        if let Some(generic_args) = chain_method.args;
         if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0);
-        then {
-            let ty = cx.typeck_results().node_type(ty.hir_id);
-            if is_type_diagnostic_item(cx, ty, sym::vec_type) ||
-                is_type_diagnostic_item(cx, ty, sym::vecdeque_type) ||
-                match_type(cx, ty, &paths::BTREEMAP) ||
-                is_type_diagnostic_item(cx, ty, sym::hashmap_type) {
-                if method.ident.name == sym!(len) {
-                    let span = shorten_needless_collect_span(expr);
-                    span_lint_and_sugg(
-                        cx,
-                        NEEDLESS_COLLECT,
-                        span,
-                        NEEDLESS_COLLECT_MSG,
-                        "replace with",
-                        "count()".to_string(),
-                        Applicability::MachineApplicable,
-                    );
-                }
-                if method.ident.name == sym!(is_empty) {
-                    let span = shorten_needless_collect_span(expr);
-                    span_lint_and_sugg(
-                        cx,
-                        NEEDLESS_COLLECT,
-                        span,
-                        NEEDLESS_COLLECT_MSG,
-                        "replace with",
-                        "next().is_none()".to_string(),
-                        Applicability::MachineApplicable,
-                    );
-                }
-                if method.ident.name == sym!(contains) {
-                    let contains_arg = snippet(cx, args[1].span, "??");
-                    let span = shorten_needless_collect_span(expr);
-                    span_lint_and_then(
-                        cx,
-                        NEEDLESS_COLLECT,
-                        span,
-                        NEEDLESS_COLLECT_MSG,
-                        |diag| {
-                            let (arg, pred) = contains_arg
-                                    .strip_prefix('&')
-                                    .map_or(("&x", &*contains_arg), |s| ("x", s));
-                            diag.span_suggestion(
-                                span,
-                                "replace with",
-                                format!(
-                                    "any(|{}| x == {})",
-                                    arg, pred
-                                ),
-                                Applicability::MachineApplicable,
-                            );
-                        }
-                    );
-                }
+        let ty = cx.typeck_results().node_type(ty.hir_id);
+        if is_type_diagnostic_item(cx, ty, sym::vec_type)
+            || is_type_diagnostic_item(cx, ty, sym::vecdeque_type)
+            || match_type(cx, ty, &paths::BTREEMAP)
+            || is_type_diagnostic_item(cx, ty, sym::hashmap_type);
+        if let Some(sugg) = match &*method.ident.name.as_str() {
+            "len" => Some("count()".to_string()),
+            "is_empty" => Some("next().is_none()".to_string()),
+            "contains" => {
+                let contains_arg = snippet(cx, args[1].span, "??");
+                let (arg, pred) = contains_arg
+                    .strip_prefix('&')
+                    .map_or(("&x", &*contains_arg), |s| ("x", s));
+                Some(format!("any(|{}| x == {})", arg, pred))
             }
+            _ => None,
+        };
+        then {
+            span_lint_and_sugg(
+                cx,
+                NEEDLESS_COLLECT,
+                method0_span.with_hi(expr.span.hi()),
+                NEEDLESS_COLLECT_MSG,
+                "replace with",
+                sugg,
+                Applicability::MachineApplicable,
+            );
         }
     }
 }
 
 fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
-    if let ExprKind::Block(ref block, _) = expr.kind {
-        for ref stmt in block.stmts {
+    if let ExprKind::Block(block, _) = expr.kind {
+        for stmt in block.stmts {
             if_chain! {
                 if let StmtKind::Local(
                     Local { pat: Pat { hir_id: pat_id, kind: PatKind::Binding(_, _, ident, .. ), .. },
-                    init: Some(ref init_expr), .. }
+                    init: Some(init_expr), .. }
                 ) = stmt.kind;
-                if let ExprKind::MethodCall(ref method_name, _, &[ref iter_source], ..) = init_expr.kind;
-                if method_name.ident.name == sym!(collect) && is_trait_method(cx, &init_expr, sym::Iterator);
-                if let Some(ref generic_args) = method_name.args;
+                if let ExprKind::MethodCall(method_name, collect_span, &[ref iter_source], ..) = init_expr.kind;
+                if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator);
+                if let Some(generic_args) = method_name.args;
                 if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0);
                 if let ty = cx.typeck_results().node_type(ty.hir_id);
                 if is_type_diagnostic_item(cx, ty, sym::vec_type) ||
                     is_type_diagnostic_item(cx, ty, sym::vecdeque_type) ||
                     match_type(cx, ty, &paths::LINKED_LIST);
                 if let Some(iter_calls) = detect_iter_and_into_iters(block, *ident);
-                if iter_calls.len() == 1;
+                if let [iter_call] = &*iter_calls;
                 then {
                     let mut used_count_visitor = UsedCountVisitor {
                         cx,
@@ -115,11 +87,12 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
                     }
 
                     // Suggest replacing iter_call with iter_replacement, and removing stmt
-                    let iter_call = &iter_calls[0];
+                    let mut span = MultiSpan::from_span(collect_span);
+                    span.push_span_label(iter_call.span, "the iterator could be used here instead".into());
                     span_lint_and_then(
                         cx,
                         super::NEEDLESS_COLLECT,
-                        stmt.span.until(iter_call.span),
+                        span,
                         NEEDLESS_COLLECT_MSG,
                         |diag| {
                             let iter_replacement = format!("{}{}", Sugg::hir(cx, iter_source, ".."), iter_call.get_iter_method(cx));
@@ -130,7 +103,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
                                     (iter_call.span, iter_replacement)
                                 ],
                                 Applicability::MachineApplicable,// MaybeIncorrect,
-                            ).emit();
+                            );
                         },
                     );
                 }
@@ -192,8 +165,8 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor {
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         // Check function calls on our collection
         if_chain! {
-            if let ExprKind::MethodCall(method_name, _, ref args, _) = &expr.kind;
-            if let Some(Expr { kind: ExprKind::Path(QPath::Resolved(_, ref path)), .. }) = args.get(0);
+            if let ExprKind::MethodCall(method_name, _, args, _) = &expr.kind;
+            if let Some(Expr { kind: ExprKind::Path(QPath::Resolved(_, path)), .. }) = args.get(0);
             if let &[name] = &path.segments;
             if name.ident == self.target;
             then {
@@ -220,7 +193,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor {
         }
         // Check if the collection is used for anything else
         if_chain! {
-            if let Expr { kind: ExprKind::Path(QPath::Resolved(_, ref path)), .. } = expr;
+            if let Expr { kind: ExprKind::Path(QPath::Resolved(_, path)), .. } = expr;
             if let &[name] = &path.segments;
             if name.ident == self.target;
             then {
@@ -270,14 +243,3 @@ fn detect_iter_and_into_iters<'tcx>(block: &'tcx Block<'tcx>, identifier: Ident)
     visitor.visit_block(block);
     if visitor.seen_other { None } else { Some(visitor.uses) }
 }
-
-fn shorten_needless_collect_span(expr: &Expr<'_>) -> Span {
-    if_chain! {
-        if let ExprKind::MethodCall(.., args, _) = &expr.kind;
-        if let ExprKind::MethodCall(_, span, ..) = &args[0].kind;
-        then {
-            return expr.span.with_lo(span.lo());
-        }
-    }
-    unreachable!();
-}
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
index 64ab3b6bfec..3065bcc3e6c 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
@@ -96,7 +96,7 @@ pub(super) fn check<'tcx>(
                 let take = if let Some(end) = *end {
                     let mut take_expr = end;
 
-                    if let ExprKind::Binary(ref op, ref left, ref right) = end.kind {
+                    if let ExprKind::Binary(ref op, left, right) = end.kind {
                         if let BinOpKind::Add = op.node {
                             let start_equal_left = SpanlessEq::new(cx).eq_expr(start, left);
                             let start_equal_right = SpanlessEq::new(cx).eq_expr(start, right);
@@ -190,10 +190,10 @@ pub(super) fn check<'tcx>(
 
 fn is_len_call(expr: &Expr<'_>, var: Symbol) -> bool {
     if_chain! {
-        if let ExprKind::MethodCall(ref method, _, ref len_args, _) = expr.kind;
+        if let ExprKind::MethodCall(method, _, len_args, _) = expr.kind;
         if len_args.len() == 1;
         if method.ident.name == sym!(len);
-        if let ExprKind::Path(QPath::Resolved(_, ref path)) = len_args[0].kind;
+        if let ExprKind::Path(QPath::Resolved(_, path)) = len_args[0].kind;
         if path.segments.len() == 1;
         if path.segments[0].ident.name == var;
         then {
@@ -254,51 +254,49 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
         if_chain! {
             // the indexed container is referenced by a name
             if let ExprKind::Path(ref seqpath) = seqexpr.kind;
-            if let QPath::Resolved(None, ref seqvar) = *seqpath;
+            if let QPath::Resolved(None, seqvar) = *seqpath;
             if seqvar.segments.len() == 1;
+            let index_used_directly = path_to_local_id(idx, self.var);
+            let indexed_indirectly = {
+                let mut used_visitor = LocalUsedVisitor::new(self.cx, self.var);
+                walk_expr(&mut used_visitor, idx);
+                used_visitor.used
+            };
+            if indexed_indirectly || index_used_directly;
             then {
-                let index_used_directly = path_to_local_id(idx, self.var);
-                let indexed_indirectly = {
-                    let mut used_visitor = LocalUsedVisitor::new(self.cx, self.var);
-                    walk_expr(&mut used_visitor, idx);
-                    used_visitor.used
-                };
-
-                if indexed_indirectly || index_used_directly {
-                    if self.prefer_mutable {
-                        self.indexed_mut.insert(seqvar.segments[0].ident.name);
+                if self.prefer_mutable {
+                    self.indexed_mut.insert(seqvar.segments[0].ident.name);
+                }
+                let res = self.cx.qpath_res(seqpath, seqexpr.hir_id);
+                match res {
+                    Res::Local(hir_id) => {
+                        let parent_id = self.cx.tcx.hir().get_parent_item(expr.hir_id);
+                        let parent_def_id = self.cx.tcx.hir().local_def_id(parent_id);
+                        let extent = self.cx.tcx.region_scope_tree(parent_def_id).var_scope(hir_id.local_id);
+                        if indexed_indirectly {
+                            self.indexed_indirectly.insert(seqvar.segments[0].ident.name, Some(extent));
+                        }
+                        if index_used_directly {
+                            self.indexed_directly.insert(
+                                seqvar.segments[0].ident.name,
+                                (Some(extent), self.cx.typeck_results().node_type(seqexpr.hir_id)),
+                            );
+                        }
+                        return false;  // no need to walk further *on the variable*
                     }
-                    let res = self.cx.qpath_res(seqpath, seqexpr.hir_id);
-                    match res {
-                        Res::Local(hir_id) => {
-                            let parent_id = self.cx.tcx.hir().get_parent_item(expr.hir_id);
-                            let parent_def_id = self.cx.tcx.hir().local_def_id(parent_id);
-                            let extent = self.cx.tcx.region_scope_tree(parent_def_id).var_scope(hir_id.local_id);
-                            if indexed_indirectly {
-                                self.indexed_indirectly.insert(seqvar.segments[0].ident.name, Some(extent));
-                            }
-                            if index_used_directly {
-                                self.indexed_directly.insert(
-                                    seqvar.segments[0].ident.name,
-                                    (Some(extent), self.cx.typeck_results().node_type(seqexpr.hir_id)),
-                                );
-                            }
-                            return false;  // no need to walk further *on the variable*
+                    Res::Def(DefKind::Static | DefKind::Const, ..) => {
+                        if indexed_indirectly {
+                            self.indexed_indirectly.insert(seqvar.segments[0].ident.name, None);
                         }
-                        Res::Def(DefKind::Static | DefKind::Const, ..) => {
-                            if indexed_indirectly {
-                                self.indexed_indirectly.insert(seqvar.segments[0].ident.name, None);
-                            }
-                            if index_used_directly {
-                                self.indexed_directly.insert(
-                                    seqvar.segments[0].ident.name,
-                                    (None, self.cx.typeck_results().node_type(seqexpr.hir_id)),
-                                );
-                            }
-                            return false;  // no need to walk further *on the variable*
+                        if index_used_directly {
+                            self.indexed_directly.insert(
+                                seqvar.segments[0].ident.name,
+                                (None, self.cx.typeck_results().node_type(seqexpr.hir_id)),
+                            );
                         }
-                        _ => (),
+                        return false;  // no need to walk further *on the variable*
                     }
+                    _ => (),
                 }
             }
         }
@@ -312,7 +310,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         if_chain! {
             // a range index op
-            if let ExprKind::MethodCall(ref meth, _, ref args, _) = expr.kind;
+            if let ExprKind::MethodCall(meth, _, args, _) = expr.kind;
             if (meth.ident.name == sym::index && match_trait_method(self.cx, expr, &paths::INDEX))
                 || (meth.ident.name == sym::index_mut && match_trait_method(self.cx, expr, &paths::INDEX_MUT));
             if !self.check(&args[1], &args[0], expr);
@@ -321,7 +319,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
 
         if_chain! {
             // an index op
-            if let ExprKind::Index(ref seqexpr, ref idx) = expr.kind;
+            if let ExprKind::Index(seqexpr, idx) = expr.kind;
             if !self.check(idx, seqexpr, expr);
             then { return }
         }
@@ -342,19 +340,19 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
 
         let old = self.prefer_mutable;
         match expr.kind {
-            ExprKind::AssignOp(_, ref lhs, ref rhs) | ExprKind::Assign(ref lhs, ref rhs, _) => {
+            ExprKind::AssignOp(_, lhs, rhs) | ExprKind::Assign(lhs, rhs, _) => {
                 self.prefer_mutable = true;
                 self.visit_expr(lhs);
                 self.prefer_mutable = false;
                 self.visit_expr(rhs);
             },
-            ExprKind::AddrOf(BorrowKind::Ref, mutbl, ref expr) => {
+            ExprKind::AddrOf(BorrowKind::Ref, mutbl, expr) => {
                 if mutbl == Mutability::Mut {
                     self.prefer_mutable = true;
                 }
                 self.visit_expr(expr);
             },
-            ExprKind::Call(ref f, args) => {
+            ExprKind::Call(f, args) => {
                 self.visit_expr(f);
                 for expr in args {
                     let ty = self.cx.typeck_results().expr_ty_adjusted(expr);
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index 01a7627fc7f..96720764e16 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -5,7 +5,7 @@ use rustc_lint::LateContext;
 use std::iter::{once, Iterator};
 
 pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-    if let ExprKind::Loop(ref block, _, _, _) = expr.kind {
+    if let ExprKind::Loop(block, _, _, _) = expr.kind {
         match never_loop_block(block, expr.hir_id) {
             NeverLoopResult::AlwaysBreak => span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops"),
             NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (),
@@ -76,36 +76,36 @@ fn never_loop_expr_seq<'a, T: Iterator<Item = &'a Expr<'a>>>(es: &mut T, main_lo
 
 fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<&'tcx Expr<'tcx>> {
     match stmt.kind {
-        StmtKind::Semi(ref e, ..) | StmtKind::Expr(ref e, ..) => Some(e),
-        StmtKind::Local(ref local) => local.init.as_deref(),
+        StmtKind::Semi(e, ..) | StmtKind::Expr(e, ..) => Some(e),
+        StmtKind::Local(local) => local.init.as_deref(),
         StmtKind::Item(..) => None,
     }
 }
 
 fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
     match expr.kind {
-        ExprKind::Box(ref e)
-        | ExprKind::Unary(_, ref e)
-        | ExprKind::Cast(ref e, _)
-        | ExprKind::Type(ref e, _)
-        | ExprKind::Field(ref e, _)
-        | ExprKind::AddrOf(_, _, ref e)
-        | ExprKind::Struct(_, _, Some(ref e))
-        | ExprKind::Repeat(ref e, _)
-        | ExprKind::DropTemps(ref e) => never_loop_expr(e, main_loop_id),
-        ExprKind::Array(ref es) | ExprKind::MethodCall(_, _, ref es, _) | ExprKind::Tup(ref es) => {
+        ExprKind::Box(e)
+        | ExprKind::Unary(_, e)
+        | ExprKind::Cast(e, _)
+        | ExprKind::Type(e, _)
+        | ExprKind::Field(e, _)
+        | ExprKind::AddrOf(_, _, e)
+        | ExprKind::Struct(_, _, Some(e))
+        | ExprKind::Repeat(e, _)
+        | ExprKind::DropTemps(e) => never_loop_expr(e, main_loop_id),
+        ExprKind::Array(es) | ExprKind::MethodCall(_, _, es, _) | ExprKind::Tup(es) => {
             never_loop_expr_all(&mut es.iter(), main_loop_id)
         },
-        ExprKind::Call(ref e, ref es) => never_loop_expr_all(&mut once(&**e).chain(es.iter()), main_loop_id),
-        ExprKind::Binary(_, ref e1, ref e2)
-        | ExprKind::Assign(ref e1, ref e2, _)
-        | ExprKind::AssignOp(_, ref e1, ref e2)
-        | ExprKind::Index(ref e1, ref e2) => never_loop_expr_all(&mut [&**e1, &**e2].iter().cloned(), main_loop_id),
-        ExprKind::Loop(ref b, _, _, _) => {
+        ExprKind::Call(e, es) => never_loop_expr_all(&mut once(e).chain(es.iter()), main_loop_id),
+        ExprKind::Binary(_, e1, e2)
+        | ExprKind::Assign(e1, e2, _)
+        | ExprKind::AssignOp(_, e1, e2)
+        | ExprKind::Index(e1, e2) => never_loop_expr_all(&mut [e1, e2].iter().cloned(), main_loop_id),
+        ExprKind::Loop(b, _, _, _) => {
             // Break can come from the inner loop so remove them.
             absorb_break(&never_loop_block(b, main_loop_id))
         },
-        ExprKind::If(ref e, ref e2, ref e3) => {
+        ExprKind::If(e, e2, ref e3) => {
             let e1 = never_loop_expr(e, main_loop_id);
             let e2 = never_loop_expr(e2, main_loop_id);
             let e3 = e3
@@ -113,7 +113,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
                 .map_or(NeverLoopResult::Otherwise, |e| never_loop_expr(e, main_loop_id));
             combine_seq(e1, combine_branches(e2, e3))
         },
-        ExprKind::Match(ref e, ref arms, _) => {
+        ExprKind::Match(e, arms, _) => {
             let e = never_loop_expr(e, main_loop_id);
             if arms.is_empty() {
                 e
@@ -122,7 +122,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
                 combine_seq(e, arms)
             }
         },
-        ExprKind::Block(ref b, _) => never_loop_block(b, main_loop_id),
+        ExprKind::Block(b, _) => never_loop_block(b, main_loop_id),
         ExprKind::Continue(d) => {
             let id = d
                 .target_id
@@ -136,7 +136,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
         ExprKind::Break(_, ref e) | ExprKind::Ret(ref e) => e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| {
             combine_seq(never_loop_expr(e, main_loop_id), NeverLoopResult::AlwaysBreak)
         }),
-        ExprKind::InlineAsm(ref asm) => asm
+        ExprKind::InlineAsm(asm) => asm
             .operands
             .iter()
             .map(|(o, _)| match o {
diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
index 849d7ec718c..cb2c83e9029 100644
--- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
@@ -1,11 +1,13 @@
 use super::SAME_ITEM_PUSH;
 use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::path_to_local;
 use clippy_utils::source::snippet_with_macro_callsite;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use if_chain::if_chain;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
-use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, Node, Pat, PatKind, Stmt, StmtKind};
+use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind};
 use rustc_lint::LateContext;
 use rustc_middle::hir::map::Map;
 use rustc_span::symbol::sym;
@@ -41,59 +43,55 @@ pub(super) fn check<'tcx>(
     }
 
     // Determine whether it is safe to lint the body
-    let mut same_item_push_visitor = SameItemPushVisitor {
-        should_lint: true,
-        vec_push: None,
-        cx,
-    };
+    let mut same_item_push_visitor = SameItemPushVisitor::new(cx);
     walk_expr(&mut same_item_push_visitor, body);
-    if same_item_push_visitor.should_lint {
-        if let Some((vec, pushed_item)) = same_item_push_visitor.vec_push {
-            let vec_ty = cx.typeck_results().expr_ty(vec);
-            let ty = vec_ty.walk().nth(1).unwrap().expect_ty();
-            if cx
-                .tcx
-                .lang_items()
-                .clone_trait()
-                .map_or(false, |id| implements_trait(cx, ty, id, &[]))
-            {
-                // Make sure that the push does not involve possibly mutating values
-                match pushed_item.kind {
-                    ExprKind::Path(ref qpath) => {
-                        match cx.qpath_res(qpath, pushed_item.hir_id) {
-                            // immutable bindings that are initialized with literal or constant
-                            Res::Local(hir_id) => {
-                                if_chain! {
-                                    let node = cx.tcx.hir().get(hir_id);
-                                    if let Node::Binding(pat) = node;
-                                    if let PatKind::Binding(bind_ann, ..) = pat.kind;
-                                    if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable);
-                                    let parent_node = cx.tcx.hir().get_parent_node(hir_id);
-                                    if let Some(Node::Local(parent_let_expr)) = cx.tcx.hir().find(parent_node);
-                                    if let Some(init) = parent_let_expr.init;
-                                    then {
-                                        match init.kind {
-                                            // immutable bindings that are initialized with literal
-                                            ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item),
-                                            // immutable bindings that are initialized with constant
-                                            ExprKind::Path(ref path) => {
-                                                if let Res::Def(DefKind::Const, ..) = cx.qpath_res(path, init.hir_id) {
-                                                    emit_lint(cx, vec, pushed_item);
-                                                }
+    if_chain! {
+        if same_item_push_visitor.should_lint();
+        if let Some((vec, pushed_item)) = same_item_push_visitor.vec_push;
+        let vec_ty = cx.typeck_results().expr_ty(vec);
+        let ty = vec_ty.walk().nth(1).unwrap().expect_ty();
+        if cx
+            .tcx
+            .lang_items()
+            .clone_trait()
+            .map_or(false, |id| implements_trait(cx, ty, id, &[]));
+        then {
+            // Make sure that the push does not involve possibly mutating values
+            match pushed_item.kind {
+                ExprKind::Path(ref qpath) => {
+                    match cx.qpath_res(qpath, pushed_item.hir_id) {
+                        // immutable bindings that are initialized with literal or constant
+                        Res::Local(hir_id) => {
+                            let node = cx.tcx.hir().get(hir_id);
+                            if_chain! {
+                                if let Node::Binding(pat) = node;
+                                if let PatKind::Binding(bind_ann, ..) = pat.kind;
+                                if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable);
+                                let parent_node = cx.tcx.hir().get_parent_node(hir_id);
+                                if let Some(Node::Local(parent_let_expr)) = cx.tcx.hir().find(parent_node);
+                                if let Some(init) = parent_let_expr.init;
+                                then {
+                                    match init.kind {
+                                        // immutable bindings that are initialized with literal
+                                        ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item),
+                                        // immutable bindings that are initialized with constant
+                                        ExprKind::Path(ref path) => {
+                                            if let Res::Def(DefKind::Const, ..) = cx.qpath_res(path, init.hir_id) {
+                                                emit_lint(cx, vec, pushed_item);
                                             }
-                                            _ => {},
                                         }
+                                        _ => {},
                                     }
                                 }
-                            },
-                            // constant
-                            Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item),
-                            _ => {},
-                        }
-                    },
-                    ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item),
-                    _ => {},
-                }
+                            }
+                        },
+                        // constant
+                        Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item),
+                        _ => {},
+                    }
+                },
+                ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item),
+                _ => {},
             }
         }
     }
@@ -101,10 +99,38 @@ pub(super) fn check<'tcx>(
 
 // Scans the body of the for loop and determines whether lint should be given
 struct SameItemPushVisitor<'a, 'tcx> {
-    should_lint: bool,
+    non_deterministic_expr: bool,
+    multiple_pushes: bool,
     // this field holds the last vec push operation visited, which should be the only push seen
     vec_push: Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)>,
     cx: &'a LateContext<'tcx>,
+    used_locals: FxHashSet<HirId>,
+}
+
+impl<'a, 'tcx> SameItemPushVisitor<'a, 'tcx> {
+    fn new(cx: &'a LateContext<'tcx>) -> Self {
+        Self {
+            non_deterministic_expr: false,
+            multiple_pushes: false,
+            vec_push: None,
+            cx,
+            used_locals: FxHashSet::default(),
+        }
+    }
+
+    fn should_lint(&self) -> bool {
+        if_chain! {
+            if !self.non_deterministic_expr;
+            if !self.multiple_pushes;
+            if let Some((vec, _)) = self.vec_push;
+            if let Some(hir_id) = path_to_local(vec);
+            then {
+                !self.used_locals.contains(&hir_id)
+            } else {
+                false
+            }
+        }
+    }
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> {
@@ -113,9 +139,14 @@ impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         match &expr.kind {
             // Non-determinism may occur ... don't give a lint
-            ExprKind::Loop(..) | ExprKind::Match(..) => self.should_lint = false,
+            ExprKind::Loop(..) | ExprKind::Match(..) | ExprKind::If(..) => self.non_deterministic_expr = true,
             ExprKind::Block(block, _) => self.visit_block(block),
-            _ => {},
+            _ => {
+                if let Some(hir_id) = path_to_local(expr) {
+                    self.used_locals.insert(hir_id);
+                }
+                walk_expr(self, expr);
+            },
         }
     }
 
@@ -130,7 +161,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> {
         if vec_push_option.is_none() {
             // Current statement is not a push so visit inside
             match &s.kind {
-                StmtKind::Expr(expr) | StmtKind::Semi(expr) => self.visit_expr(&expr),
+                StmtKind::Expr(expr) | StmtKind::Semi(expr) => self.visit_expr(expr),
                 _ => {},
             }
         } else {
@@ -140,7 +171,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> {
                 self.vec_push = vec_push_option;
             } else {
                 // There are multiple pushes ... don't lint
-                self.should_lint = false;
+                self.multiple_pushes = true;
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
index 8451c1c6130..fc067e81bca 100644
--- a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
@@ -15,12 +15,12 @@ pub(super) fn check<'tcx>(
     expr: &'tcx Expr<'_>,
 ) {
     if_chain! {
-        if let ExprKind::AddrOf(BorrowKind::Ref, _, ref arg_expr) = arg.kind;
+        if let ExprKind::AddrOf(BorrowKind::Ref, _, arg_expr) = arg.kind;
         if let PatKind::Binding(.., target, _) = pat.kind;
         if let ExprKind::Array([arg_expression]) = arg_expr.kind;
         if let ExprKind::Path(ref list_item) = arg_expression.kind;
         if let Some(list_item_name) = single_segment_path(list_item).map(|ps| ps.ident.name);
-        if let ExprKind::Block(ref block, _) = body.kind;
+        if let ExprKind::Block(block, _) = body.kind;
         if !block.stmts.is_empty();
 
         then {
diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs
index bb409c48532..4db6644b9d7 100644
--- a/src/tools/clippy/clippy_lints/src/loops/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs
@@ -1,9 +1,9 @@
 use clippy_utils::ty::{has_iter_method, implements_trait};
 use clippy_utils::{get_parent_expr, is_integer_const, path_to_local, path_to_local_id, sugg};
 use if_chain::if_chain;
-use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_expr, walk_pat, walk_stmt, NestedVisitorMap, Visitor};
+use rustc_hir::HirIdMap;
 use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Stmt, StmtKind};
 use rustc_lint::LateContext;
 use rustc_middle::hir::map::Map;
@@ -20,9 +20,9 @@ enum IncrementVisitorVarState {
 
 /// Scan a for loop for variables that are incremented exactly once and not used after that.
 pub(super) struct IncrementVisitor<'a, 'tcx> {
-    cx: &'a LateContext<'tcx>,                          // context reference
-    states: FxHashMap<HirId, IncrementVisitorVarState>, // incremented variables
-    depth: u32,                                         // depth of conditional expressions
+    cx: &'a LateContext<'tcx>,                  // context reference
+    states: HirIdMap<IncrementVisitorVarState>, // incremented variables
+    depth: u32,                                 // depth of conditional expressions
     done: bool,
 }
 
@@ -30,7 +30,7 @@ impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> {
     pub(super) fn new(cx: &'a LateContext<'tcx>) -> Self {
         Self {
             cx,
-            states: FxHashMap::default(),
+            states: HirIdMap::default(),
             depth: 0,
             done: false,
         }
@@ -65,7 +65,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
                 }
 
                 match parent.kind {
-                    ExprKind::AssignOp(op, ref lhs, ref rhs) => {
+                    ExprKind::AssignOp(op, lhs, rhs) => {
                         if lhs.hir_id == expr.hir_id {
                             *state = if op.node == BinOpKind::Add
                                 && is_integer_const(self.cx, rhs, 1)
@@ -79,7 +79,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
                             };
                         }
                     },
-                    ExprKind::Assign(ref lhs, _, _) if lhs.hir_id == expr.hir_id => {
+                    ExprKind::Assign(lhs, _, _) if lhs.hir_id == expr.hir_id => {
                         *state = IncrementVisitorVarState::DontWarn
                     },
                     ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
@@ -153,7 +153,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
     fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
         // Look for declarations of the variable
         if_chain! {
-            if let StmtKind::Local(ref local) = stmt.kind;
+            if let StmtKind::Local(local) = stmt.kind;
             if local.pat.hir_id == self.var_id;
             if let PatKind::Binding(.., ident, _) = local.pat.kind;
             then {
@@ -191,10 +191,10 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
 
             if let Some(parent) = get_parent_expr(self.cx, expr) {
                 match parent.kind {
-                    ExprKind::AssignOp(_, ref lhs, _) if lhs.hir_id == expr.hir_id => {
+                    ExprKind::AssignOp(_, lhs, _) if lhs.hir_id == expr.hir_id => {
                         self.state = InitializeVisitorState::DontWarn;
                     },
-                    ExprKind::Assign(ref lhs, ref rhs, _) if lhs.hir_id == expr.hir_id => {
+                    ExprKind::Assign(lhs, rhs, _) if lhs.hir_id == expr.hir_id => {
                         self.state = if_chain! {
                             if self.depth == 0;
                             if let InitializeVisitorState::Declared(name)
@@ -273,7 +273,7 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor {
             return;
         }
         match expr.kind {
-            ExprKind::Assign(ref path, _, _) | ExprKind::AssignOp(_, ref path, _) => {
+            ExprKind::Assign(path, _, _) | ExprKind::AssignOp(_, path, _) => {
                 if path_to_local_id(path, self.iterator) {
                     self.nesting = RuledOut;
                 }
@@ -327,7 +327,7 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic
         // (&mut x).into_iter() ==> x.iter_mut()
         match &arg.kind {
             ExprKind::AddrOf(BorrowKind::Ref, mutability, arg_inner)
-                if has_iter_method(cx, cx.typeck_results().expr_ty(&arg_inner)).is_some() =>
+                if has_iter_method(cx, cx.typeck_results().expr_ty(arg_inner)).is_some() =>
             {
                 let meth_name = match mutability {
                     Mutability::Mut => "iter_mut",
@@ -335,7 +335,7 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic
                 };
                 format!(
                     "{}.{}()",
-                    sugg::Sugg::hir_with_applicability(cx, &arg_inner, "_", applic_ref).maybe_par(),
+                    sugg::Sugg::hir_with_applicability(cx, arg_inner, "_", applic_ref).maybe_par(),
                     meth_name,
                 )
             }
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
index cad9ff8489a..de267cc77d2 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
@@ -3,13 +3,13 @@ use crate::consts::constant;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::usage::mutated_variables;
 use if_chain::if_chain;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::DefIdMap;
 use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
-use rustc_hir::{def_id, Expr, ExprKind, HirId, QPath};
+use rustc_hir::HirIdSet;
+use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::LateContext;
 use rustc_middle::hir::map::Map;
-use std::iter::Iterator;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) {
     if constant(cx, cx.typeck_results(), cond).is_some() {
@@ -19,8 +19,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'
 
     let mut var_visitor = VarCollectorVisitor {
         cx,
-        ids: FxHashSet::default(),
-        def_ids: FxHashMap::default(),
+        ids: HirIdSet::default(),
+        def_ids: DefIdMap::default(),
         skip: false,
     };
     var_visitor.visit_expr(cond);
@@ -93,8 +93,8 @@ impl<'tcx> Visitor<'tcx> for HasBreakOrReturnVisitor {
 /// All variables definition IDs are collected
 struct VarCollectorVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
-    ids: FxHashSet<HirId>,
-    def_ids: FxHashMap<def_id::DefId, bool>,
+    ids: HirIdSet,
+    def_ids: DefIdMap<bool>,
     skip: bool,
 }
 
@@ -103,9 +103,8 @@ impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> {
         if_chain! {
             if let ExprKind::Path(ref qpath) = ex.kind;
             if let QPath::Resolved(None, _) = *qpath;
-            let res = self.cx.qpath_res(qpath, ex.hir_id);
             then {
-                match res {
+                match self.cx.qpath_res(qpath, ex.hir_id) {
                     Res::Local(hir_id) => {
                         self.ids.insert(hir_id);
                     },
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
index ffe8c0c5494..9c172079852 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
@@ -11,14 +11,14 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'
     let inner_stmt_expr = extract_expr_from_first_stmt(loop_block);
     // or extract the first expression (if any) from the block
     if let Some(inner) = inner_stmt_expr.or_else(|| extract_first_expr(loop_block)) {
-        if let ExprKind::Match(ref matchexpr, ref arms, ref source) = inner.kind {
+        if let ExprKind::Match(matchexpr, arms, ref source) = inner.kind {
             // ensure "if let" compatible match structure
             match *source {
                 MatchSource::Normal | MatchSource::IfLetDesugar { .. } => {
                     if arms.len() == 2
                         && arms[0].guard.is_none()
                         && arms[1].guard.is_none()
-                        && is_simple_break_expr(&arms[1].body)
+                        && is_simple_break_expr(arms[1].body)
                     {
                         if in_external_macro(cx.sess(), expr.span) {
                             return;
@@ -57,7 +57,7 @@ fn extract_expr_from_first_stmt<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<
     if block.stmts.is_empty() {
         return None;
     }
-    if let StmtKind::Local(ref local) = block.stmts[0].kind {
+    if let StmtKind::Local(local) = block.stmts[0].kind {
         local.init //.map(|expr| expr)
     } else {
         None
@@ -67,9 +67,9 @@ fn extract_expr_from_first_stmt<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<
 /// If a block begins with an expression (with or without semicolon), return it.
 fn extract_first_expr<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> {
     match block.expr {
-        Some(ref expr) if block.stmts.is_empty() => Some(expr),
+        Some(expr) if block.stmts.is_empty() => Some(expr),
         None if !block.stmts.is_empty() => match block.stmts[0].kind {
-            StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => Some(expr),
+            StmtKind::Expr(expr) | StmtKind::Semi(expr) => Some(expr),
             StmtKind::Local(..) | StmtKind::Item(..) => None,
         },
         _ => None,
@@ -82,7 +82,7 @@ fn extract_first_expr<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> {
 fn is_simple_break_expr(expr: &Expr<'_>) -> bool {
     match expr.kind {
         ExprKind::Break(dest, ref passed_expr) if dest.label.is_none() && passed_expr.is_none() => true,
-        ExprKind::Block(ref b, _) => extract_first_expr(b).map_or(false, |subexpr| is_simple_break_expr(subexpr)),
+        ExprKind::Block(b, _) => extract_first_expr(b).map_or(false, |subexpr| is_simple_break_expr(subexpr)),
         _ => false,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
index 57fc6250a9a..82715d9bafa 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
@@ -16,12 +16,10 @@ use rustc_middle::hir::map::Map;
 use rustc_span::symbol::sym;
 
 pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-    if let ExprKind::Match(ref match_expr, ref arms, MatchSource::WhileLetDesugar) = expr.kind {
+    if let ExprKind::Match(match_expr, arms, MatchSource::WhileLetDesugar) = expr.kind {
         let pat = &arms[0].pat.kind;
-        if let (
-            &PatKind::TupleStruct(ref qpath, ref pat_args, _),
-            &ExprKind::MethodCall(ref method_path, _, ref method_args, _),
-        ) = (pat, &match_expr.kind)
+        if let (&PatKind::TupleStruct(ref qpath, pat_args, _), &ExprKind::MethodCall(method_path, _, method_args, _)) =
+            (pat, &match_expr.kind)
         {
             let iter_expr = &method_args[0];
 
@@ -40,8 +38,8 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 && is_trait_method(cx, match_expr, sym::Iterator)
                 && lhs_constructor.ident.name == sym::Some
                 && (pat_args.is_empty()
-                    || !is_refutable(cx, &pat_args[0])
-                        && !is_used_inside(cx, iter_expr, &arms[0].body)
+                    || !is_refutable(cx, pat_args[0])
+                        && !is_used_inside(cx, iter_expr, arms[0].body)
                         && !is_iterator_used_after_while_let(cx, iter_expr)
                         && !is_nested(cx, expr, &method_args[0]))
             {
diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs
index d573c297838..c506d52e746 100644
--- a/src/tools/clippy/clippy_lints/src/macro_use.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_use.rs
@@ -9,7 +9,7 @@ use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{edition::Edition, Span};
+use rustc_span::{edition::Edition, sym, Span};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for `#[macro_use] use...`.
@@ -110,9 +110,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
             if cx.sess().opts.edition >= Edition::Edition2018;
             if let hir::ItemKind::Use(path, _kind) = &item.kind;
             let attrs = cx.tcx.hir().attrs(item.hir_id());
-            if let Some(mac_attr) = attrs
-                .iter()
-                .find(|attr| attr.ident().map(|s| s.to_string()) == Some("macro_use".to_string()));
+            if let Some(mac_attr) = attrs.iter().find(|attr| attr.has_name(sym::macro_use));
             if let Res::Def(DefKind::Mod, id) = path.res;
             then {
                 for kid in cx.tcx.item_children(id).iter() {
diff --git a/src/tools/clippy/clippy_lints/src/manual_map.rs b/src/tools/clippy/clippy_lints/src/manual_map.rs
index ed157783b72..8c9e3af62f4 100644
--- a/src/tools/clippy/clippy_lints/src/manual_map.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_map.rs
@@ -2,7 +2,7 @@ use crate::{map_unit_fn::OPTION_MAP_UNIT_FN, matches::MATCH_AS_REF};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::ty::{can_partially_move_ty, is_type_diagnostic_item, peel_mid_ty_refs_is_mutable};
-use clippy_utils::{is_allowed, is_else_clause_of_if_let_else, match_def_path, match_var, paths, peel_hir_expr_refs};
+use clippy_utils::{in_constant, is_allowed, is_else_clause, match_def_path, match_var, paths, peel_hir_expr_refs};
 use rustc_ast::util::parser::PREC_POSTFIX;
 use rustc_errors::Applicability;
 use rustc_hir::{
@@ -47,16 +47,16 @@ declare_lint_pass!(ManualMap => [MANUAL_MAP]);
 impl LateLintPass<'_> for ManualMap {
     #[allow(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if in_external_macro(cx.sess(), expr.span) {
-            return;
-        }
-
         if let ExprKind::Match(
             scrutinee,
             [arm1 @ Arm { guard: None, .. }, arm2 @ Arm { guard: None, .. }],
             match_kind,
         ) = expr.kind
         {
+            if in_external_macro(cx.sess(), expr.span) || in_constant(cx, expr.hir_id) {
+                return;
+            }
+
             let (scrutinee_ty, ty_ref_count, ty_mutability) =
                 peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(scrutinee));
             if !(is_type_diagnostic_item(cx, scrutinee_ty, sym::option_type)
@@ -181,8 +181,7 @@ impl LateLintPass<'_> for ManualMap {
                 expr.span,
                 "manual implementation of `Option::map`",
                 "try this",
-                if matches!(match_kind, MatchSource::IfLetDesugar { .. }) && is_else_clause_of_if_let_else(cx.tcx, expr)
-                {
+                if matches!(match_kind, MatchSource::IfLetDesugar { .. }) && is_else_clause(cx.tcx, expr) {
                     format!("{{ {}{}.map({}) }}", scrutinee_str, as_ref_str, body_str)
                 } else {
                     format!("{}{}.map({})", scrutinee_str, as_ref_str, body_str)
diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
index 95261580b8e..dc19805b50a 100644
--- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
@@ -1,9 +1,9 @@
+use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::meets_msrv;
 use clippy_utils::source::snippet_opt;
 use if_chain::if_chain;
-use rustc_ast::ast::{Attribute, FieldDef, Item, ItemKind, Variant, VariantData, VisibilityKind};
-use rustc_attr as attr;
+use rustc_ast::ast::{FieldDef, Item, ItemKind, Variant, VariantData, VisibilityKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_semver::RustcVersion;
@@ -102,19 +102,11 @@ fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants
     fn is_non_exhaustive_marker(variant: &Variant) -> bool {
         matches!(variant.data, VariantData::Unit(_))
             && variant.ident.as_str().starts_with('_')
-            && variant.attrs.iter().any(|a| is_doc_hidden(a))
-    }
-
-    fn is_doc_hidden(attr: &Attribute) -> bool {
-        attr.has_name(sym::doc)
-            && match attr.meta_item_list() {
-                Some(l) => attr::list_contains_name(&l, sym::hidden),
-                None => false,
-            }
+            && is_doc_hidden(&variant.attrs)
     }
 
+    let mut markers = variants.iter().filter(|v| is_non_exhaustive_marker(v));
     if_chain! {
-        let mut markers = variants.iter().filter(|v| is_non_exhaustive_marker(v));
         if let Some(marker) = markers.next();
         if markers.count() == 0 && variants.len() > 1;
         then {
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index 9da37efddac..dfa464ddb81 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -91,7 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
                 } else {
                     return;
                 };
-                let target_res = cx.qpath_res(&target_path, target_arg.hir_id);
+                let target_res = cx.qpath_res(target_path, target_arg.hir_id);
                 if target_res == Res::Err {
                     return;
                 };
@@ -174,7 +174,7 @@ fn eq_pattern_length<'tcx>(cx: &LateContext<'tcx>, pattern: &Expr<'_>, expr: &'t
 
 // Tests if `expr` is a `&str`.
 fn is_ref_str(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    match cx.typeck_results().expr_ty_adjusted(&expr).kind() {
+    match cx.typeck_results().expr_ty_adjusted(expr).kind() {
         ty::Ref(_, ty, _) => ty.is_str(),
         _ => false,
     }
diff --git a/src/tools/clippy/clippy_lints/src/map_clone.rs b/src/tools/clippy/clippy_lints/src/map_clone.rs
index cfcc705eabc..99c35ae3bbf 100644
--- a/src/tools/clippy/clippy_lints/src/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/map_clone.rs
@@ -52,17 +52,17 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
         }
 
         if_chain! {
-            if let hir::ExprKind::MethodCall(ref method, _, ref args, _) = e.kind;
+            if let hir::ExprKind::MethodCall(method, _, args, _) = e.kind;
             if args.len() == 2;
             if method.ident.name == sym::map;
             let ty = cx.typeck_results().expr_ty(&args[0]);
             if is_type_diagnostic_item(cx, ty, sym::option_type) || is_trait_method(cx, e, sym::Iterator);
             if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].kind;
-            let closure_body = cx.tcx.hir().body(body_id);
-            let closure_expr = remove_blocks(&closure_body.value);
             then {
+                let closure_body = cx.tcx.hir().body(body_id);
+                let closure_expr = remove_blocks(&closure_body.value);
                 match closure_body.params[0].pat.kind {
-                    hir::PatKind::Ref(ref inner, hir::Mutability::Not) => if let hir::PatKind::Binding(
+                    hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding(
                         hir::BindingAnnotation::Unannotated, .., name, None
                     ) = inner.kind {
                         if ident_eq(name, closure_expr) {
@@ -71,14 +71,14 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
                     },
                     hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => {
                         match closure_expr.kind {
-                            hir::ExprKind::Unary(hir::UnOp::Deref, ref inner) => {
+                            hir::ExprKind::Unary(hir::UnOp::Deref, inner) => {
                                 if ident_eq(name, inner) {
                                     if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() {
                                         lint(cx, e.span, args[0].span, true);
                                     }
                                 }
                             },
-                            hir::ExprKind::MethodCall(ref method, _, [obj], _) => if_chain! {
+                            hir::ExprKind::MethodCall(method, _, [obj], _) => if_chain! {
                                 if ident_eq(name, obj) && method.ident.name == sym::clone;
                                 if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id);
                                 if let Some(trait_id) = cx.tcx.trait_of_item(fn_id);
@@ -109,7 +109,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
 }
 
 fn ident_eq(name: Ident, path: &hir::Expr<'_>) -> bool {
-    if let hir::ExprKind::Path(hir::QPath::Resolved(None, ref path)) = path.kind {
+    if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = path.kind {
         path.segments.len() == 1 && path.segments[0].ident == name
     } else {
         false
diff --git a/src/tools/clippy/clippy_lints/src/map_err_ignore.rs b/src/tools/clippy/clippy_lints/src/map_err_ignore.rs
index a6a63961be5..425a9734e5f 100644
--- a/src/tools/clippy/clippy_lints/src/map_err_ignore.rs
+++ b/src/tools/clippy/clippy_lints/src/map_err_ignore.rs
@@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for MapErrIgnore {
         }
 
         // check if this is a method call (e.g. x.foo())
-        if let ExprKind::MethodCall(ref method, _t_span, ref args, _) = e.kind {
+        if let ExprKind::MethodCall(method, _t_span, args, _) = e.kind {
             // only work if the method name is `map_err` and there are only 2 arguments (e.g. x.map_err(|_|[1]
             // Enum::Variant[2]))
             if method.ident.as_str() == "map_err" && args.len() == 2 {
diff --git a/src/tools/clippy/clippy_lints/src/map_identity.rs b/src/tools/clippy/clippy_lints/src/map_identity.rs
index 75191e1f9ee..e7719e7663d 100644
--- a/src/tools/clippy/clippy_lints/src/map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/map_identity.rs
@@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for MapIdentity {
 /// map(). Otherwise, returns None.
 fn get_map_argument<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a [Expr<'a>]> {
     if_chain! {
-        if let ExprKind::MethodCall(ref method, _, ref args, _) = expr.kind;
+        if let ExprKind::MethodCall(method, _, args, _) = expr.kind;
         if args.len() == 2 && method.ident.name == sym::map;
         let caller_ty = cx.typeck_results().expr_ty(&args[0]);
         if is_trait_method(cx, expr, sym::Iterator)
@@ -80,7 +80,7 @@ fn get_map_argument<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a
 fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     match expr.kind {
         ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)),
-        ExprKind::Path(QPath::Resolved(_, ref path)) => match_path(path, &paths::STD_CONVERT_IDENTITY),
+        ExprKind::Path(QPath::Resolved(_, path)) => match_path(path, &paths::STD_CONVERT_IDENTITY),
         _ => false,
     }
 }
@@ -99,12 +99,12 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
 
     match body.kind {
         ExprKind::Path(QPath::Resolved(None, _)) => match_expr_param(cx, body, params[0].pat),
-        ExprKind::Ret(Some(ref ret_val)) => match_expr_param(cx, ret_val, params[0].pat),
-        ExprKind::Block(ref block, _) => {
+        ExprKind::Ret(Some(ret_val)) => match_expr_param(cx, ret_val, params[0].pat),
+        ExprKind::Block(block, _) => {
             if_chain! {
                 if block.stmts.len() == 1;
-                if let StmtKind::Semi(ref expr) | StmtKind::Expr(ref expr) = block.stmts[0].kind;
-                if let ExprKind::Ret(Some(ref ret_val)) = expr.kind;
+                if let StmtKind::Semi(expr) | StmtKind::Expr(expr) = block.stmts[0].kind;
+                if let ExprKind::Ret(Some(ret_val)) = expr.kind;
                 then {
                     match_expr_param(cx, ret_val, params[0].pat)
                 } else {
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index d4764b5ccff..57cd907e77e 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -133,7 +133,7 @@ fn reduce_unit_expression<'a>(cx: &LateContext<'_>, expr: &'a hir::Expr<'_>) ->
             // Calls can't be reduced any more
             Some(expr.span)
         },
-        hir::ExprKind::Block(ref block, _) => {
+        hir::ExprKind::Block(block, _) => {
             match (block.stmts, block.expr.as_ref()) {
                 (&[], Some(inner_expr)) => {
                     // If block only contains an expression,
@@ -144,8 +144,8 @@ fn reduce_unit_expression<'a>(cx: &LateContext<'_>, expr: &'a hir::Expr<'_>) ->
                     // If block only contains statements,
                     // reduce `{ X; }` to `X` or `X;`
                     match inner_stmt.kind {
-                        hir::StmtKind::Local(ref local) => Some(local.span),
-                        hir::StmtKind::Expr(ref e) => Some(e.span),
+                        hir::StmtKind::Local(local) => Some(local.span),
+                        hir::StmtKind::Expr(e) => Some(e.span),
                         hir::StmtKind::Semi(..) => Some(inner_stmt.span),
                         hir::StmtKind::Item(..) => None,
                     }
@@ -168,17 +168,15 @@ fn unit_closure<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &hir::Expr<'_>,
 ) -> Option<(&'tcx hir::Param<'tcx>, &'tcx hir::Expr<'tcx>)> {
-    if let hir::ExprKind::Closure(_, ref decl, inner_expr_id, _, _) = expr.kind {
+    if_chain! {
+        if let hir::ExprKind::Closure(_, decl, inner_expr_id, _, _) = expr.kind;
         let body = cx.tcx.hir().body(inner_expr_id);
         let body_expr = &body.value;
-
-        if_chain! {
-            if decl.inputs.len() == 1;
-            if is_unit_expression(cx, body_expr);
-            if let Some(binding) = iter_input_pats(&decl, body).next();
-            then {
-                return Some((binding, body_expr));
-            }
+        if decl.inputs.len() == 1;
+        if is_unit_expression(cx, body_expr);
+        if let Some(binding) = iter_input_pats(decl, body).next();
+        then {
+            return Some((binding, body_expr));
         }
     }
     None
@@ -269,7 +267,7 @@ impl<'tcx> LateLintPass<'tcx> for MapUnit {
             return;
         }
 
-        if let hir::StmtKind::Semi(ref expr) = stmt.kind {
+        if let hir::StmtKind::Semi(expr) = stmt.kind {
             if let Some(arglists) = method_chain_args(expr, &["map"]) {
                 lint_map_unit_fn(cx, stmt, expr, arglists[0]);
             }
diff --git a/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs b/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs
index ccaa5e98c83..ca6fb0831fe 100644
--- a/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs
+++ b/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs
@@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchOnVecItems {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if_chain! {
             if !in_external_macro(cx.sess(), expr.span);
-            if let ExprKind::Match(ref match_expr, _, MatchSource::Normal) = expr.kind;
+            if let ExprKind::Match(match_expr, _, MatchSource::Normal) = expr.kind;
             if let Some(idx_expr) = is_vec_indexing(cx, match_expr);
             if let ExprKind::Index(vec, idx) = idx_expr.kind;
 
@@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchOnVecItems {
 
 fn is_vec_indexing<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
     if_chain! {
-        if let ExprKind::Index(ref array, ref index) = expr.kind;
+        if let ExprKind::Index(array, index) = expr.kind;
         if is_vector(cx, array);
         if !is_full_range(cx, index);
 
diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs
index 2f2dc4cfc6b..c8ee0abd3df 100644
--- a/src/tools/clippy/clippy_lints/src/matches.rs
+++ b/src/tools/clippy/clippy_lints/src/matches.rs
@@ -13,13 +13,13 @@ use clippy_utils::{
 use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash};
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::Applicability;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::{
     self as hir, Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Guard, HirId, Local, MatchSource,
     Mutability, Node, Pat, PatKind, PathSegment, QPath, RangeEnd, TyKind,
 };
+use rustc_hir::{HirIdMap, HirIdSet};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty, TyS, VariantDef};
@@ -590,7 +590,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
             lint_match_arms(cx, expr);
         }
 
-        if let ExprKind::Match(ref ex, ref arms, MatchSource::Normal) = expr.kind {
+        if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind {
             check_single_match(cx, ex, arms, expr);
             check_match_bool(cx, ex, arms, expr);
             check_overlapping_arms(cx, ex, arms);
@@ -605,7 +605,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                 check_match_single_binding(cx, ex, arms, expr);
             }
         }
-        if let ExprKind::Match(ref ex, ref arms, _) = expr.kind {
+        if let ExprKind::Match(ex, arms, _) = expr.kind {
             check_match_ref_pats(cx, ex, arms, expr);
         }
     }
@@ -614,14 +614,14 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
         if_chain! {
             if !in_external_macro(cx.sess(), local.span);
             if !in_macro(local.span);
-            if let Some(ref expr) = local.init;
-            if let ExprKind::Match(ref target, ref arms, MatchSource::Normal) = expr.kind;
+            if let Some(expr) = local.init;
+            if let ExprKind::Match(target, arms, MatchSource::Normal) = expr.kind;
             if arms.len() == 1 && arms[0].guard.is_none();
             if let PatKind::TupleStruct(
-                QPath::Resolved(None, ref variant_name), ref args, _) = arms[0].pat.kind;
+                QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind;
             if args.len() == 1;
-            if let PatKind::Binding(_, arg, ..) = strip_pat_refs(&args[0]).kind;
-            let body = remove_blocks(&arms[0].body);
+            if let PatKind::Binding(_, arg, ..) = strip_pat_refs(args[0]).kind;
+            let body = remove_blocks(arms[0].body);
             if path_to_local_id(body, arg);
 
             then {
@@ -650,7 +650,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
         if_chain! {
             if !in_external_macro(cx.sess(), pat.span);
             if !in_macro(pat.span);
-            if let PatKind::Struct(QPath::Resolved(_, ref path), fields, true) = pat.kind;
+            if let PatKind::Struct(QPath::Resolved(_, path), fields, true) = pat.kind;
             if let Some(def_id) = path.res.opt_def_id();
             let ty = cx.tcx.type_of(def_id);
             if let ty::Adt(def, _) = ty.kind();
@@ -733,8 +733,8 @@ fn report_single_match_single_pattern(
         format!(" else {}", expr_block(cx, els, None, "..", Some(expr.span)))
     });
 
+    let (pat, pat_ref_count) = peel_hir_pat_refs(arms[0].pat);
     let (msg, sugg) = if_chain! {
-        let (pat, pat_ref_count) = peel_hir_pat_refs(arms[0].pat);
         if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind;
         let (ty, ty_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(ex));
         if let Some(trait_id) = cx.tcx.lang_items().structural_peq_trait();
@@ -762,7 +762,7 @@ fn report_single_match_single_pattern(
                 // PartialEq for different reference counts may not exist.
                 "&".repeat(ref_count_diff),
                 snippet(cx, arms[0].pat.span, ".."),
-                expr_block(cx, &arms[0].body, None, "..", Some(expr.span)),
+                expr_block(cx, arms[0].body, None, "..", Some(expr.span)),
                 els_str,
             );
             (msg, sugg)
@@ -772,7 +772,7 @@ fn report_single_match_single_pattern(
                 "if let {} = {} {}{}",
                 snippet(cx, arms[0].pat.span, ".."),
                 snippet(cx, ex.span, ".."),
-                expr_block(cx, &arms[0].body, None, "..", Some(expr.span)),
+                expr_block(cx, arms[0].body, None, "..", Some(expr.span)),
                 els_str,
             );
             (msg, sugg)
@@ -810,7 +810,7 @@ fn check_single_match_opt_like(
     ];
 
     let path = match arms[1].pat.kind {
-        PatKind::TupleStruct(ref path, ref inner, _) => {
+        PatKind::TupleStruct(ref path, inner, _) => {
             // Contains any non wildcard patterns (e.g., `Err(err)`)?
             if !inner.iter().all(is_wild) {
                 return;
@@ -842,7 +842,7 @@ fn check_match_bool(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
             move |diag| {
                 if arms.len() == 2 {
                     // no guards
-                    let exprs = if let PatKind::Lit(ref arm_bool) = arms[0].pat.kind {
+                    let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind {
                         if let ExprKind::Lit(ref lit) = arm_bool.kind {
                             match lit.node {
                                 LitKind::Bool(true) => Some((&*arms[0].body, &*arms[1].body)),
@@ -918,14 +918,14 @@ fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm
     let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs();
     if is_type_diagnostic_item(cx, ex_ty, sym::result_type) {
         for arm in arms {
-            if let PatKind::TupleStruct(ref path, ref inner, _) = arm.pat.kind {
+            if let PatKind::TupleStruct(ref path, inner, _) = arm.pat.kind {
                 let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false));
                 if path_str == "Err" {
                     let mut matching_wild = inner.iter().any(is_wild);
                     let mut ident_bind_name = String::from("_");
                     if !matching_wild {
                         // Looking for unused bindings (i.e.: `_e`)
-                        inner.iter().for_each(|pat| {
+                        for pat in inner.iter() {
                             if let PatKind::Binding(_, id, ident, None) = pat.kind {
                                 if ident.as_str().starts_with('_')
                                     && !LocalUsedVisitor::new(cx, id).check_expr(arm.body)
@@ -934,11 +934,11 @@ fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm
                                     matching_wild = true;
                                 }
                             }
-                        });
+                        }
                     }
                     if_chain! {
                         if matching_wild;
-                        if let ExprKind::Block(ref block, _) = arm.body.kind;
+                        if let ExprKind::Block(block, _) = arm.body.kind;
                         if is_panic_block(block);
                         then {
                             // `Err(_)` or `Err(_e)` arm with `panic!` found
@@ -984,6 +984,11 @@ impl CommonPrefixSearcher<'a> {
     }
 }
 
+fn is_doc_hidden(cx: &LateContext<'_>, variant_def: &VariantDef) -> bool {
+    let attrs = cx.tcx.get_attrs(variant_def.def_id);
+    clippy_utils::attrs::is_doc_hidden(attrs)
+}
+
 #[allow(clippy::too_many_lines)]
 fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
     let ty = cx.typeck_results().expr_ty(ex).peel_refs();
@@ -1042,16 +1047,18 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>])
                     path
                 },
                 PatKind::TupleStruct(path, patterns, ..) => {
-                    if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p)) {
-                        let id = cx.qpath_res(path, pat.hir_id).def_id();
-                        missing_variants.retain(|e| e.ctor_def_id != Some(id));
+                    if let Some(id) = cx.qpath_res(path, pat.hir_id).opt_def_id() {
+                        if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p)) {
+                            missing_variants.retain(|e| e.ctor_def_id != Some(id));
+                        }
                     }
                     path
                 },
                 PatKind::Struct(path, patterns, ..) => {
-                    if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p.pat)) {
-                        let id = cx.qpath_res(path, pat.hir_id).def_id();
-                        missing_variants.retain(|e| e.def_id != id);
+                    if let Some(id) = cx.qpath_res(path, pat.hir_id).opt_def_id() {
+                        if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p.pat)) {
+                            missing_variants.retain(|e| e.def_id != id);
+                        }
                     }
                     path
                 },
@@ -1103,7 +1110,7 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>])
 
     match missing_variants.as_slice() {
         [] => (),
-        [x] if !adt_def.is_variant_list_non_exhaustive() => span_lint_and_sugg(
+        [x] if !adt_def.is_variant_list_non_exhaustive() && !is_doc_hidden(cx, x) => span_lint_and_sugg(
             cx,
             MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
             wildcard_span,
@@ -1137,9 +1144,7 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>])
 // If the block contains only a `panic!` macro (as expression or statement)
 fn is_panic_block(block: &Block<'_>) -> bool {
     match (&block.expr, block.stmts.len(), block.stmts.first()) {
-        (&Some(ref exp), 0, _) => {
-            is_expn_of(exp.span, "panic").is_some() && is_expn_of(exp.span, "unreachable").is_none()
-        },
+        (&Some(exp), 0, _) => is_expn_of(exp.span, "panic").is_some() && is_expn_of(exp.span, "unreachable").is_none(),
         (&None, 1, Some(stmt)) => {
             is_expn_of(stmt.span, "panic").is_some() && is_expn_of(stmt.span, "unreachable").is_none()
         },
@@ -1150,7 +1155,7 @@ fn is_panic_block(block: &Block<'_>) -> bool {
 fn check_match_ref_pats(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
     if has_only_ref_pats(arms) {
         let mut suggs = Vec::with_capacity(arms.len() + 1);
-        let (title, msg) = if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, ref inner) = ex.kind {
+        let (title, msg) = if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = ex.kind {
             let span = ex.span.source_callsite();
             suggs.push((span, Sugg::hir_with_macro_callsite(cx, inner, "..").to_string()));
             (
@@ -1167,7 +1172,7 @@ fn check_match_ref_pats(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], e
         };
 
         suggs.extend(arms.iter().filter_map(|a| {
-            if let PatKind::Ref(ref refp, _) = a.pat.kind {
+            if let PatKind::Ref(refp, _) = a.pat.kind {
                 Some((a.pat.span, snippet(cx, refp.span, "..").to_string()))
             } else {
                 None
@@ -1236,7 +1241,7 @@ fn check_match_as_ref(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp
 
 fn check_wild_in_or_pats(cx: &LateContext<'_>, arms: &[Arm<'_>]) {
     for arm in arms {
-        if let PatKind::Or(ref fields) = arm.pat.kind {
+        if let PatKind::Or(fields) = arm.pat.kind {
             // look for multiple fields in this arm that contains at least one Wild pattern
             if fields.len() > 1 && fields.iter().any(is_wild) {
                 span_lint_and_help(
@@ -1302,7 +1307,7 @@ fn find_matches_sugg(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr
             // strip potential borrows (#6503), but only if the type is a reference
             let mut ex_new = ex;
             if let ExprKind::AddrOf(BorrowKind::Ref, .., ex_inner) = ex.kind {
-                if let ty::Ref(..) = cx.typeck_results().expr_ty(&ex_inner).kind() {
+                if let ty::Ref(..) = cx.typeck_results().expr_ty(ex_inner).kind() {
                     ex_new = ex_inner;
                 }
             };
@@ -1379,7 +1384,7 @@ fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[A
 
     let matched_vars = ex.span;
     let bind_names = arms[0].pat.span;
-    let match_body = remove_blocks(&arms[0].body);
+    let match_body = remove_blocks(arms[0].body);
     let mut snippet_body = if match_body.span.from_expansion() {
         Sugg::hir_with_macro_callsite(cx, match_body, "..").to_string()
     } else {
@@ -1390,13 +1395,13 @@ fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[A
     match match_body.kind {
         ExprKind::Block(block, _) => {
             // macro + expr_ty(body) == ()
-            if block.span.from_expansion() && cx.typeck_results().expr_ty(&match_body).is_unit() {
+            if block.span.from_expansion() && cx.typeck_results().expr_ty(match_body).is_unit() {
                 snippet_body.push(';');
             }
         },
         _ => {
             // expr_ty(body) == ()
-            if cx.typeck_results().expr_ty(&match_body).is_unit() {
+            if cx.typeck_results().expr_ty(match_body).is_unit() {
                 snippet_body.push(';');
             }
         },
@@ -1481,8 +1486,8 @@ fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[A
 
 /// Returns true if the `ex` match expression is in a local (`let`) statement
 fn opt_parent_let<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<&'a Local<'a>> {
+    let map = &cx.tcx.hir();
     if_chain! {
-        let map = &cx.tcx.hir();
         if let Some(Node::Expr(parent_arm_expr)) = map.find(map.get_parent_node(ex.hir_id));
         if let Some(Node::Local(parent_let_expr)) = map.find(map.get_parent_node(parent_arm_expr.hir_id));
         then {
@@ -1496,10 +1501,7 @@ fn opt_parent_let<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<&'a Local<'
 fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<Constant>> {
     arms.iter()
         .flat_map(|arm| {
-            if let Arm {
-                ref pat, guard: None, ..
-            } = *arm
-            {
+            if let Arm { pat, guard: None, .. } = *arm {
                 if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
                     let lhs = match lhs {
                         Some(lhs) => constant(cx, cx.typeck_results(), lhs)?.0,
@@ -1519,7 +1521,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
                     });
                 }
 
-                if let PatKind::Lit(ref value) = pat.kind {
+                if let PatKind::Lit(value) = pat.kind {
                     let value = constant(cx, cx.typeck_results(), value)?.0;
                     return Some(SpannedRange {
                         span: pat.span,
@@ -1566,8 +1568,8 @@ fn type_ranges(ranges: &[SpannedRange<Constant>]) -> TypedRanges {
 
 fn is_unit_expr(expr: &Expr<'_>) -> bool {
     match expr.kind {
-        ExprKind::Tup(ref v) if v.is_empty() => true,
-        ExprKind::Block(ref b, _) if b.stmts.is_empty() && b.expr.is_none() => true,
+        ExprKind::Tup(v) if v.is_empty() => true,
+        ExprKind::Block(b, _) if b.stmts.is_empty() && b.expr.is_none() => true,
         _ => false,
     }
 }
@@ -1580,14 +1582,14 @@ fn is_none_arm(arm: &Arm<'_>) -> bool {
 // Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`)
 fn is_ref_some_arm(arm: &Arm<'_>) -> Option<BindingAnnotation> {
     if_chain! {
-        if let PatKind::TupleStruct(ref path, ref pats, _) = arm.pat.kind;
+        if let PatKind::TupleStruct(ref path, pats, _) = arm.pat.kind;
         if pats.len() == 1 && match_qpath(path, &paths::OPTION_SOME);
         if let PatKind::Binding(rb, .., ident, _) = pats[0].kind;
         if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut;
-        if let ExprKind::Call(ref e, ref args) = remove_blocks(&arm.body).kind;
+        if let ExprKind::Call(e, args) = remove_blocks(arm.body).kind;
         if let ExprKind::Path(ref some_path) = e.kind;
         if match_qpath(some_path, &paths::OPTION_SOME) && args.len() == 1;
-        if let ExprKind::Path(QPath::Resolved(_, ref path2)) = args[0].kind;
+        if let ExprKind::Path(QPath::Resolved(_, path2)) = args[0].kind;
         if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name;
         then {
             return Some(rb)
@@ -1669,7 +1671,7 @@ where
 
     values.sort();
 
-    for (a, b) in iter::zip(&values, &values[1..]) {
+    for (a, b) in iter::zip(&values, values.iter().skip(1)) {
         match (a, b) {
             (&Kind::Start(_, ra), &Kind::End(_, rb)) => {
                 if ra.node != rb.node {
@@ -1679,7 +1681,7 @@ where
             (&Kind::End(a, _), &Kind::Start(b, _)) if a != Bound::Included(b) => (),
             _ => {
                 // skip if the range `a` is completely included into the range `b`
-                if let Ordering::Equal | Ordering::Less = a.cmp(&b) {
+                if let Ordering::Equal | Ordering::Less = a.cmp(b) {
                     let kind_a = Kind::End(a.range().node.1, a.range());
                     let kind_b = Kind::End(b.range().node.1, b.range());
                     if let Ordering::Equal | Ordering::Greater = kind_a.cmp(&kind_b) {
@@ -1724,8 +1726,14 @@ mod redundant_pattern_match {
         arms: &[Arm<'_>],
         keyword: &'static str,
     ) {
-        let good_method = match arms[0].pat.kind {
-            PatKind::TupleStruct(ref path, ref patterns, _) if patterns.len() == 1 => {
+        // also look inside refs
+        let mut kind = &arms[0].pat.kind;
+        // if we have &None for example, peel it so we can detect "if let None = x"
+        if let PatKind::Ref(inner, _mutability) = kind {
+            kind = &inner.kind;
+        }
+        let good_method = match kind {
+            PatKind::TupleStruct(ref path, patterns, _) if patterns.len() == 1 => {
                 if let PatKind::Wild = patterns[0].kind {
                     if match_qpath(path, &paths::RESULT_OK) {
                         "is_ok()"
@@ -1806,8 +1814,8 @@ mod redundant_pattern_match {
 
             let found_good_method = match node_pair {
                 (
-                    PatKind::TupleStruct(ref path_left, ref patterns_left, _),
-                    PatKind::TupleStruct(ref path_right, ref patterns_right, _),
+                    PatKind::TupleStruct(ref path_left, patterns_left, _),
+                    PatKind::TupleStruct(ref path_right, patterns_right, _),
                 ) if patterns_left.len() == 1 && patterns_right.len() == 1 => {
                     if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) {
                         find_good_method_for_match(
@@ -1834,8 +1842,8 @@ mod redundant_pattern_match {
                         None
                     }
                 },
-                (PatKind::TupleStruct(ref path_left, ref patterns, _), PatKind::Path(ref path_right))
-                | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, ref patterns, _))
+                (PatKind::TupleStruct(ref path_left, patterns, _), PatKind::Path(ref path_right))
+                | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, patterns, _))
                     if patterns.len() == 1 =>
                 {
                     if let PatKind::Wild = patterns[0].kind {
@@ -1957,10 +1965,10 @@ fn test_overlapping() {
 
 /// Implementation of `MATCH_SAME_ARMS`.
 fn lint_match_arms<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) {
-    if let ExprKind::Match(_, ref arms, MatchSource::Normal) = expr.kind {
+    if let ExprKind::Match(_, arms, MatchSource::Normal) = expr.kind {
         let hash = |&(_, arm): &(usize, &Arm<'_>)| -> u64 {
             let mut h = SpanlessHash::new(cx);
-            h.hash_expr(&arm.body);
+            h.hash_expr(arm.body);
             h.finish()
         };
 
@@ -1968,7 +1976,7 @@ fn lint_match_arms<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) {
             let min_index = usize::min(lindex, rindex);
             let max_index = usize::max(lindex, rindex);
 
-            let mut local_map: FxHashMap<HirId, HirId> = FxHashMap::default();
+            let mut local_map: HirIdMap<HirId> = HirIdMap::default();
             let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
                 if_chain! {
                     if let Some(a_id) = path_to_local(a);
@@ -1996,7 +2004,7 @@ fn lint_match_arms<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) {
             (min_index..=max_index).all(|index| arms[index].guard.is_none())
                 && SpanlessEq::new(cx)
                     .expr_fallback(eq_fallback)
-                    .eq_expr(&lhs.body, &rhs.body)
+                    .eq_expr(lhs.body, rhs.body)
                 // these checks could be removed to allow unused bindings
                 && bindings_eq(lhs.pat, local_map.keys().copied().collect())
                 && bindings_eq(rhs.pat, local_map.values().copied().collect())
@@ -2052,7 +2060,7 @@ fn pat_contains_local(pat: &Pat<'_>, id: HirId) -> bool {
 }
 
 /// Returns true if all the bindings in the `Pat` are in `ids` and vice versa
-fn bindings_eq(pat: &Pat<'_>, mut ids: FxHashSet<HirId>) -> bool {
+fn bindings_eq(pat: &Pat<'_>, mut ids: HirIdSet) -> bool {
     let mut result = true;
     pat.each_binding_or_first(&mut |_, id, _, _| result &= ids.remove(&id));
     result && ids.is_empty()
diff --git a/src/tools/clippy/clippy_lints/src/mem_discriminant.rs b/src/tools/clippy/clippy_lints/src/mem_discriminant.rs
index 7895ba9f1e0..a735c616f6e 100644
--- a/src/tools/clippy/clippy_lints/src/mem_discriminant.rs
+++ b/src/tools/clippy/clippy_lints/src/mem_discriminant.rs
@@ -34,7 +34,7 @@ declare_lint_pass!(MemDiscriminant => [MEM_DISCRIMINANT_NON_ENUM]);
 impl<'tcx> LateLintPass<'tcx> for MemDiscriminant {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
-            if let ExprKind::Call(ref func, ref func_args) = expr.kind;
+            if let ExprKind::Call(func, func_args) = expr.kind;
             // is `mem::discriminant`
             if let ExprKind::Path(ref func_qpath) = func.kind;
             if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
@@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for MemDiscriminant {
                             let mut derefs_needed = ptr_depth;
                             let mut cur_expr = param;
                             while derefs_needed > 0  {
-                                if let ExprKind::AddrOf(BorrowKind::Ref, _, ref inner_expr) = cur_expr.kind {
+                                if let ExprKind::AddrOf(BorrowKind::Ref, _, inner_expr) = cur_expr.kind {
                                     derefs_needed -= 1;
                                     cur_expr = inner_expr;
                                 } else {
diff --git a/src/tools/clippy/clippy_lints/src/mem_forget.rs b/src/tools/clippy/clippy_lints/src/mem_forget.rs
index c13802e3953..a28cb5f32fe 100644
--- a/src/tools/clippy/clippy_lints/src/mem_forget.rs
+++ b/src/tools/clippy/clippy_lints/src/mem_forget.rs
@@ -28,7 +28,7 @@ declare_lint_pass!(MemForget => [MEM_FORGET]);
 
 impl<'tcx> LateLintPass<'tcx> for MemForget {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        if let ExprKind::Call(ref path_expr, ref args) = e.kind {
+        if let ExprKind::Call(path_expr, args) = e.kind {
             if let ExprKind::Path(ref qpath) = path_expr.kind {
                 if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id() {
                     if match_def_path(cx, def_id, &paths::MEM_FORGET) {
diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs
index 426c108d89f..e1d351aee45 100644
--- a/src/tools/clippy/clippy_lints/src/mem_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs
@@ -109,14 +109,14 @@ fn check_replace_option_with_none(cx: &LateContext<'_>, src: &Expr<'_>, dest: &E
             // argument's type. All that's left is to get
             // replacee's path.
             let replaced_path = match dest.kind {
-                ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, ref replaced) => {
-                    if let ExprKind::Path(QPath::Resolved(None, ref replaced_path)) = replaced.kind {
+                ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, replaced) => {
+                    if let ExprKind::Path(QPath::Resolved(None, replaced_path)) = replaced.kind {
                         replaced_path
                     } else {
                         return;
                     }
                 },
-                ExprKind::Path(QPath::Resolved(None, ref replaced_path)) => replaced_path,
+                ExprKind::Path(QPath::Resolved(None, replaced_path)) => replaced_path,
                 _ => return,
             };
 
@@ -161,7 +161,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'
     }
 
     if_chain! {
-        if let ExprKind::Call(ref repl_func, ref repl_args) = src.kind;
+        if let ExprKind::Call(repl_func, repl_args) = src.kind;
         if repl_args.is_empty();
         if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
         if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
@@ -214,7 +214,7 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<
         .iter()
         .any(|symbol| is_diagnostic_assoc_item(cx, def_id, *symbol))
     {
-        if let QPath::TypeRelative(_, ref method) = path {
+        if let QPath::TypeRelative(_, method) = path {
             if method.ident.name == sym::new {
                 return true;
             }
@@ -225,34 +225,33 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<
 }
 
 fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) {
-    if let ExprKind::Call(ref repl_func, _) = src.kind {
-        if_chain! {
-            if !in_external_macro(cx.tcx.sess, expr_span);
-            if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
-            if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
-            if is_diagnostic_assoc_item(cx, repl_def_id, sym::Default)
-                || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath);
+    if_chain! {
+        if let ExprKind::Call(repl_func, _) = src.kind;
+        if !in_external_macro(cx.tcx.sess, expr_span);
+        if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
+        if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
+        if is_diagnostic_assoc_item(cx, repl_def_id, sym::Default)
+            || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath);
 
-            then {
-                span_lint_and_then(
-                    cx,
-                    MEM_REPLACE_WITH_DEFAULT,
-                    expr_span,
-                    "replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`",
-                    |diag| {
-                        if !in_macro(expr_span) {
-                            let suggestion = format!("std::mem::take({})", snippet(cx, dest.span, ""));
+        then {
+            span_lint_and_then(
+                cx,
+                MEM_REPLACE_WITH_DEFAULT,
+                expr_span,
+                "replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`",
+                |diag| {
+                    if !in_macro(expr_span) {
+                        let suggestion = format!("std::mem::take({})", snippet(cx, dest.span, ""));
 
-                            diag.span_suggestion(
-                                expr_span,
-                                "consider using",
-                                suggestion,
-                                Applicability::MachineApplicable
-                            );
-                        }
+                        diag.span_suggestion(
+                            expr_span,
+                            "consider using",
+                            suggestion,
+                            Applicability::MachineApplicable
+                        );
                     }
-                );
-            }
+                }
+            );
         }
     }
 }
@@ -274,11 +273,11 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
             // Check that `expr` is a call to `mem::replace()`
-            if let ExprKind::Call(ref func, ref func_args) = expr.kind;
+            if let ExprKind::Call(func, func_args) = expr.kind;
             if let ExprKind::Path(ref func_qpath) = func.kind;
             if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
             if match_def_path(cx, def_id, &paths::MEM_REPLACE);
-            if let [dest, src] = &**func_args;
+            if let [dest, src] = func_args;
             then {
                 check_replace_option_with_none(cx, src, dest, expr.span);
                 check_replace_with_uninit(cx, src, dest, expr.span);
diff --git a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
index 0ba8a98a018..287bff886bf 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
@@ -1,101 +1,82 @@
 use super::{contains_return, BIND_INSTEAD_OF_MAP};
 use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{snippet, snippet_with_macro_callsite};
-use clippy_utils::ty::match_type;
-use clippy_utils::{in_macro, match_qpath, method_calls, paths, remove_blocks, visitors::find_all_ret_expressions};
+use clippy_utils::{in_macro, remove_blocks, visitors::find_all_ret_expressions};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
+use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
+use rustc_hir::{LangItem, QPath};
 use rustc_lint::LateContext;
+use rustc_middle::ty::DefIdTree;
 use rustc_span::Span;
 
 pub(crate) struct OptionAndThenSome;
 
 impl BindInsteadOfMap for OptionAndThenSome {
-    const TYPE_NAME: &'static str = "Option";
-    const TYPE_QPATH: &'static [&'static str] = &paths::OPTION;
-
+    const VARIANT_LANG_ITEM: LangItem = LangItem::OptionSome;
     const BAD_METHOD_NAME: &'static str = "and_then";
-    const BAD_VARIANT_NAME: &'static str = "Some";
-    const BAD_VARIANT_QPATH: &'static [&'static str] = &paths::OPTION_SOME;
-
     const GOOD_METHOD_NAME: &'static str = "map";
 }
 
 pub(crate) struct ResultAndThenOk;
 
 impl BindInsteadOfMap for ResultAndThenOk {
-    const TYPE_NAME: &'static str = "Result";
-    const TYPE_QPATH: &'static [&'static str] = &paths::RESULT;
-
+    const VARIANT_LANG_ITEM: LangItem = LangItem::ResultOk;
     const BAD_METHOD_NAME: &'static str = "and_then";
-    const BAD_VARIANT_NAME: &'static str = "Ok";
-    const BAD_VARIANT_QPATH: &'static [&'static str] = &paths::RESULT_OK;
-
     const GOOD_METHOD_NAME: &'static str = "map";
 }
 
 pub(crate) struct ResultOrElseErrInfo;
 
 impl BindInsteadOfMap for ResultOrElseErrInfo {
-    const TYPE_NAME: &'static str = "Result";
-    const TYPE_QPATH: &'static [&'static str] = &paths::RESULT;
-
+    const VARIANT_LANG_ITEM: LangItem = LangItem::ResultErr;
     const BAD_METHOD_NAME: &'static str = "or_else";
-    const BAD_VARIANT_NAME: &'static str = "Err";
-    const BAD_VARIANT_QPATH: &'static [&'static str] = &paths::RESULT_ERR;
-
     const GOOD_METHOD_NAME: &'static str = "map_err";
 }
 
 pub(crate) trait BindInsteadOfMap {
-    const TYPE_NAME: &'static str;
-    const TYPE_QPATH: &'static [&'static str];
-
+    const VARIANT_LANG_ITEM: LangItem;
     const BAD_METHOD_NAME: &'static str;
-    const BAD_VARIANT_NAME: &'static str;
-    const BAD_VARIANT_QPATH: &'static [&'static str];
-
     const GOOD_METHOD_NAME: &'static str;
 
-    fn no_op_msg() -> String {
-        format!(
+    fn no_op_msg(cx: &LateContext<'_>) -> Option<String> {
+        let variant_id = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM).ok()?;
+        let item_id = cx.tcx.parent(variant_id)?;
+        Some(format!(
             "using `{}.{}({})`, which is a no-op",
-            Self::TYPE_NAME,
+            cx.tcx.item_name(item_id),
             Self::BAD_METHOD_NAME,
-            Self::BAD_VARIANT_NAME
-        )
+            cx.tcx.item_name(variant_id),
+        ))
     }
 
-    fn lint_msg() -> String {
-        format!(
+    fn lint_msg(cx: &LateContext<'_>) -> Option<String> {
+        let variant_id = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM).ok()?;
+        let item_id = cx.tcx.parent(variant_id)?;
+        Some(format!(
             "using `{}.{}(|x| {}(y))`, which is more succinctly expressed as `{}(|x| y)`",
-            Self::TYPE_NAME,
+            cx.tcx.item_name(item_id),
             Self::BAD_METHOD_NAME,
-            Self::BAD_VARIANT_NAME,
+            cx.tcx.item_name(variant_id),
             Self::GOOD_METHOD_NAME
-        )
+        ))
     }
 
     fn lint_closure_autofixable(
         cx: &LateContext<'_>,
         expr: &hir::Expr<'_>,
-        args: &[hir::Expr<'_>],
+        recv: &hir::Expr<'_>,
         closure_expr: &hir::Expr<'_>,
         closure_args_span: Span,
     ) -> bool {
         if_chain! {
-            if let hir::ExprKind::Call(ref some_expr, ref some_args) = closure_expr.kind;
-            if let hir::ExprKind::Path(ref qpath) = some_expr.kind;
-            if match_qpath(qpath, Self::BAD_VARIANT_QPATH);
-            if some_args.len() == 1;
+            if let hir::ExprKind::Call(some_expr, [inner_expr]) = closure_expr.kind;
+            if let hir::ExprKind::Path(QPath::Resolved(_, path)) = some_expr.kind;
+            if Self::is_variant(cx, path.res);
+            if !contains_return(inner_expr);
+            if let Some(msg) = Self::lint_msg(cx);
             then {
-                let inner_expr = &some_args[0];
-
-                if contains_return(inner_expr) {
-                    return false;
-                }
-
                 let some_inner_snip = if inner_expr.span.from_expansion() {
                     snippet_with_macro_callsite(cx, inner_expr.span, "_")
                 } else {
@@ -103,13 +84,13 @@ pub(crate) trait BindInsteadOfMap {
                 };
 
                 let closure_args_snip = snippet(cx, closure_args_span, "..");
-                let option_snip = snippet(cx, args[0].span, "..");
+                let option_snip = snippet(cx, recv.span, "..");
                 let note = format!("{}.{}({} {})", option_snip, Self::GOOD_METHOD_NAME, closure_args_snip, some_inner_snip);
                 span_lint_and_sugg(
                     cx,
                     BIND_INSTEAD_OF_MAP,
                     expr.span,
-                    Self::lint_msg().as_ref(),
+                    &msg,
                     "try this",
                     note,
                     Applicability::MachineApplicable,
@@ -126,68 +107,84 @@ pub(crate) trait BindInsteadOfMap {
         let can_sugg: bool = find_all_ret_expressions(cx, closure_expr, |ret_expr| {
             if_chain! {
                 if !in_macro(ret_expr.span);
-                if let hir::ExprKind::Call(ref func_path, ref args) = ret_expr.kind;
-                if let hir::ExprKind::Path(ref qpath) = func_path.kind;
-                if match_qpath(qpath, Self::BAD_VARIANT_QPATH);
-                if args.len() == 1;
-                if !contains_return(&args[0]);
+                if let hir::ExprKind::Call(func_path, [arg]) = ret_expr.kind;
+                if let hir::ExprKind::Path(QPath::Resolved(_, path)) = func_path.kind;
+                if Self::is_variant(cx, path.res);
+                if !contains_return(arg);
                 then {
-                    suggs.push((ret_expr.span, args[0].span.source_callsite()));
+                    suggs.push((ret_expr.span, arg.span.source_callsite()));
                     true
                 } else {
                     false
                 }
             }
         });
-
-        if can_sugg {
-            span_lint_and_then(cx, BIND_INSTEAD_OF_MAP, expr.span, Self::lint_msg().as_ref(), |diag| {
-                multispan_sugg_with_applicability(
-                    diag,
-                    "try this",
-                    Applicability::MachineApplicable,
-                    std::iter::once((*method_calls(expr, 1).2.get(0).unwrap(), Self::GOOD_METHOD_NAME.into())).chain(
-                        suggs
-                            .into_iter()
-                            .map(|(span1, span2)| (span1, snippet(cx, span2, "_").into())),
-                    ),
-                )
-            });
-        }
-        can_sugg
+        let (span, msg) = if_chain! {
+            if can_sugg;
+            if let hir::ExprKind::MethodCall(_, span, ..) = expr.kind;
+            if let Some(msg) = Self::lint_msg(cx);
+            then { (span, msg) } else { return false; }
+        };
+        span_lint_and_then(cx, BIND_INSTEAD_OF_MAP, expr.span, &msg, |diag| {
+            multispan_sugg_with_applicability(
+                diag,
+                "try this",
+                Applicability::MachineApplicable,
+                std::iter::once((span, Self::GOOD_METHOD_NAME.into())).chain(
+                    suggs
+                        .into_iter()
+                        .map(|(span1, span2)| (span1, snippet(cx, span2, "_").into())),
+                ),
+            )
+        });
+        true
     }
 
     /// Lint use of `_.and_then(|x| Some(y))` for `Option`s
-    fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) -> bool {
-        if !match_type(cx, cx.typeck_results().expr_ty(&args[0]), Self::TYPE_QPATH) {
-            return false;
+    fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) -> bool {
+        if_chain! {
+            if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def();
+            if let Ok(vid) = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM);
+            if Some(adt.did) == cx.tcx.parent(vid);
+            then {} else { return false; }
         }
 
-        match args[1].kind {
+        match arg.kind {
             hir::ExprKind::Closure(_, _, body_id, closure_args_span, _) => {
                 let closure_body = cx.tcx.hir().body(body_id);
                 let closure_expr = remove_blocks(&closure_body.value);
 
-                if Self::lint_closure_autofixable(cx, expr, args, closure_expr, closure_args_span) {
+                if Self::lint_closure_autofixable(cx, expr, recv, closure_expr, closure_args_span) {
                     true
                 } else {
                     Self::lint_closure(cx, expr, closure_expr)
                 }
             },
             // `_.and_then(Some)` case, which is no-op.
-            hir::ExprKind::Path(ref qpath) if match_qpath(qpath, Self::BAD_VARIANT_QPATH) => {
-                span_lint_and_sugg(
-                    cx,
-                    BIND_INSTEAD_OF_MAP,
-                    expr.span,
-                    Self::no_op_msg().as_ref(),
-                    "use the expression directly",
-                    snippet(cx, args[0].span, "..").into(),
-                    Applicability::MachineApplicable,
-                );
+            hir::ExprKind::Path(QPath::Resolved(_, path)) if Self::is_variant(cx, path.res) => {
+                if let Some(msg) = Self::no_op_msg(cx) {
+                    span_lint_and_sugg(
+                        cx,
+                        BIND_INSTEAD_OF_MAP,
+                        expr.span,
+                        &msg,
+                        "use the expression directly",
+                        snippet(cx, recv.span, "..").into(),
+                        Applicability::MachineApplicable,
+                    );
+                }
                 true
             },
             _ => false,
         }
     }
+
+    fn is_variant(cx: &LateContext<'_>, res: Res) -> bool {
+        if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res {
+            if let Ok(variant_id) = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM) {
+                return cx.tcx.parent(id) == Some(variant_id);
+            }
+        }
+        false
+    }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
index 4f88f80a304..2ad3e673c57 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
@@ -1,41 +1,34 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_diagnostic_item;
-use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
+use rustc_hir::Expr;
 use rustc_lint::LateContext;
 use rustc_span::sym;
 
 use super::BYTES_NTH;
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'tcx [Expr<'tcx>]) {
-    if_chain! {
-        if let ExprKind::MethodCall(_, _, ref args, _) = expr.kind;
-        let ty = cx.typeck_results().expr_ty(&iter_args[0]).peel_refs();
-        let caller_type = if is_type_diagnostic_item(cx, ty, sym::string_type) {
-            Some("String")
-        } else if ty.is_str() {
-            Some("str")
-        } else {
-            None
-        };
-        if let Some(caller_type) = caller_type;
-        then {
-            let mut applicability = Applicability::MachineApplicable;
-            span_lint_and_sugg(
-                cx,
-                BYTES_NTH,
-                expr.span,
-                &format!("called `.byte().nth()` on a `{}`", caller_type),
-                "try",
-                format!(
-                    "{}.as_bytes().get({})",
-                    snippet_with_applicability(cx, iter_args[0].span, "..", &mut applicability),
-                    snippet_with_applicability(cx, args[1].span, "..", &mut applicability)
-                ),
-                applicability,
-            );
-        }
-    }
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, n_arg: &'tcx Expr<'tcx>) {
+    let ty = cx.typeck_results().expr_ty(recv).peel_refs();
+    let caller_type = if ty.is_str() {
+        "str"
+    } else if is_type_diagnostic_item(cx, ty, sym::string_type) {
+        "String"
+    } else {
+        return;
+    };
+    let mut applicability = Applicability::MachineApplicable;
+    span_lint_and_sugg(
+        cx,
+        BYTES_NTH,
+        expr.span,
+        &format!("called `.byte().nth()` on a `{}`", caller_type),
+        "try",
+        format!(
+            "{}.as_bytes().get({})",
+            snippet_with_applicability(cx, recv.span, "..", &mut applicability),
+            snippet_with_applicability(cx, n_arg.span, "..", &mut applicability)
+        ),
+        applicability,
+    );
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
index c668fe52781..514c4118765 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
@@ -19,7 +19,7 @@ pub(super) fn check(
 ) -> bool {
     if_chain! {
         if let Some(args) = method_chain_args(info.chain, chain_methods);
-        if let hir::ExprKind::Call(ref fun, ref arg_char) = info.other.kind;
+        if let hir::ExprKind::Call(fun, arg_char) = info.other.kind;
         if arg_char.len() == 1;
         if let hir::ExprKind::Path(ref qpath) = fun.kind;
         if let Some(segment) = single_segment_path(qpath);
diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
index edb6649b87b..ce2e8fa8b10 100644
--- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
@@ -1,10 +1,12 @@
-use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::get_parent_node;
+use clippy_utils::source::snippet_with_context;
 use clippy_utils::sugg;
 use clippy_utils::ty::is_copy;
 use rustc_errors::Applicability;
-use rustc_hir as hir;
+use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind};
 use rustc_lint::LateContext;
-use rustc_middle::ty;
+use rustc_middle::ty::{self, adjustment::Adjust};
 use rustc_span::symbol::{sym, Symbol};
 use std::iter;
 
@@ -12,12 +14,26 @@ use super::CLONE_DOUBLE_REF;
 use super::CLONE_ON_COPY;
 
 /// Checks for the `CLONE_ON_COPY` lint.
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) {
-    if !(args.len() == 1 && method_name == sym::clone) {
+#[allow(clippy::too_many_lines)]
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, args: &[Expr<'_>]) {
+    let arg = match args {
+        [arg] if method_name == sym::clone => arg,
+        _ => return,
+    };
+    if cx
+        .typeck_results()
+        .type_dependent_def_id(expr.hir_id)
+        .and_then(|id| cx.tcx.trait_of_item(id))
+        .zip(cx.tcx.lang_items().clone_trait())
+        .map_or(true, |(x, y)| x != y)
+    {
         return;
     }
-    let arg = &args[0];
-    let arg_ty = cx.typeck_results().expr_ty_adjusted(&args[0]);
+    let arg_adjustments = cx.typeck_results().expr_adjustments(arg);
+    let arg_ty = arg_adjustments
+        .last()
+        .map_or_else(|| cx.typeck_results().expr_ty(arg), |a| a.target);
+
     let ty = cx.typeck_results().expr_ty(expr);
     if let ty::Ref(_, inner, _) = arg_ty.kind() {
         if let ty::Ref(_, innermost, _) = inner.kind() {
@@ -61,57 +77,57 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Sym
     }
 
     if is_copy(cx, ty) {
-        let snip;
-        if let Some(snippet) = sugg::Sugg::hir_opt(cx, arg) {
-            let parent = cx.tcx.hir().get_parent_node(expr.hir_id);
-            match &cx.tcx.hir().get(parent) {
-                hir::Node::Expr(parent) => match parent.kind {
-                    // &*x is a nop, &x.clone() is not
-                    hir::ExprKind::AddrOf(..) => return,
-                    // (*x).func() is useless, x.clone().func() can work in case func borrows mutably
-                    hir::ExprKind::MethodCall(_, _, parent_args, _) if expr.hir_id == parent_args[0].hir_id => {
-                        return;
-                    },
-
-                    _ => {},
-                },
-                hir::Node::Stmt(stmt) => {
-                    if let hir::StmtKind::Local(ref loc) = stmt.kind {
-                        if let hir::PatKind::Ref(..) = loc.pat.kind {
-                            // let ref y = *x borrows x, let ref y = x.clone() does not
-                            return;
-                        }
-                    }
-                },
-                _ => {},
+        let parent_is_suffix_expr = match get_parent_node(cx.tcx, expr.hir_id) {
+            Some(Node::Expr(parent)) => match parent.kind {
+                // &*x is a nop, &x.clone() is not
+                ExprKind::AddrOf(..) => return,
+                // (*x).func() is useless, x.clone().func() can work in case func borrows self
+                ExprKind::MethodCall(_, _, [self_arg, ..], _)
+                    if expr.hir_id == self_arg.hir_id && ty != cx.typeck_results().expr_ty_adjusted(expr) =>
+                {
+                    return;
+                }
+                ExprKind::MethodCall(_, _, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true,
+                ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
+                | ExprKind::Field(..)
+                | ExprKind::Index(..) => true,
+                _ => false,
+            },
+            // local binding capturing a reference
+            Some(Node::Local(l))
+                if matches!(
+                    l.pat.kind,
+                    PatKind::Binding(BindingAnnotation::Ref | BindingAnnotation::RefMut, ..)
+                ) =>
+            {
+                return;
             }
+            _ => false,
+        };
 
-            // x.clone() might have dereferenced x, possibly through Deref impls
-            if cx.typeck_results().expr_ty(arg) == ty {
-                snip = Some(("try removing the `clone` call", format!("{}", snippet)));
-            } else {
-                let deref_count = cx
-                    .typeck_results()
-                    .expr_adjustments(arg)
-                    .iter()
-                    .filter(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(_)))
-                    .count();
-                let derefs: String = iter::repeat('*').take(deref_count).collect();
-                snip = Some(("try dereferencing it", format!("{}{}", derefs, snippet)));
-            }
+        let mut app = Applicability::MachineApplicable;
+        let snip = snippet_with_context(cx, arg.span, expr.span.ctxt(), "_", &mut app).0;
+
+        let deref_count = arg_adjustments
+            .iter()
+            .take_while(|adj| matches!(adj.kind, Adjust::Deref(_)))
+            .count();
+        let (help, sugg) = if deref_count == 0 {
+            ("try removing the `clone` call", snip.into())
+        } else if parent_is_suffix_expr {
+            ("try dereferencing it", format!("({}{})", "*".repeat(deref_count), snip))
         } else {
-            snip = None;
-        }
-        span_lint_and_then(
+            ("try dereferencing it", format!("{}{}", "*".repeat(deref_count), snip))
+        };
+
+        span_lint_and_sugg(
             cx,
             CLONE_ON_COPY,
             expr.span,
             &format!("using `clone` on type `{}` which implements the `Copy` trait", ty),
-            |diag| {
-                if let Some((text, snip)) = snip {
-                    diag.span_suggestion(expr.span, text, snip, Applicability::MachineApplicable);
-                }
-            },
+            help,
+            sugg,
+            app,
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
index e7bffa66b3f..03cb41697d5 100644
--- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
@@ -100,9 +100,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_span: Spa
         applicability: &mut Applicability,
     ) -> Vec<String> {
         if_chain! {
-            if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref format_arg) = a.kind;
-            if let hir::ExprKind::Match(ref format_arg_expr, _, _) = format_arg.kind;
-            if let hir::ExprKind::Tup(ref format_arg_expr_tup) = format_arg_expr.kind;
+            if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, format_arg) = a.kind;
+            if let hir::ExprKind::Match(format_arg_expr, _, _) = format_arg.kind;
+            if let hir::ExprKind::Tup(format_arg_expr_tup) = format_arg_expr.kind;
 
             then {
                 format_arg_expr_tup
@@ -155,7 +155,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_span: Spa
         if block.stmts.len() == 1;
         if let hir::StmtKind::Local(local) = &block.stmts[0].kind;
         if let Some(arg_root) = &local.init;
-        if let hir::ExprKind::Call(ref inner_fun, ref inner_args) = arg_root.kind;
+        if let hir::ExprKind::Call(inner_fun, inner_args) = arg_root.kind;
         if is_expn_of(inner_fun.span, "format").is_some() && inner_args.len() == 1;
         if let hir::ExprKind::Call(_, format_args) = &inner_args[0].kind;
         then {
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_used.rs b/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
index 64531b29ade..63a834fdce0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
@@ -7,8 +7,8 @@ use rustc_span::sym;
 use super::EXPECT_USED;
 
 /// lint use of `expect()` for `Option`s and `Result`s
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expect_args: &[hir::Expr<'_>]) {
-    let obj_ty = cx.typeck_results().expr_ty(&expect_args[0]).peel_refs();
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
+    let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
 
     let mess = if is_type_diagnostic_item(cx, obj_ty, sym::option_type) {
         Some((EXPECT_USED, "an Option", "None"))
diff --git a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
index 39d2f15dbc8..7b2967feb0f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
@@ -8,8 +8,8 @@ use rustc_span::source_map::Span;
 
 use super::FILETYPE_IS_FILE;
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
-    let ty = cx.typeck_results().expr_ty(&args[0]);
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
+    let ty = cx.typeck_results().expr_ty(recv);
 
     if !match_type(cx, ty, &paths::FILE_TYPE) {
         return;
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
index 2cb476acb2b..35fae450eeb 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -1,87 +1,174 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet;
-use clippy_utils::{is_trait_method, path_to_local_id, SpanlessEq};
+use clippy_utils::source::{indent_of, reindent_multiline, snippet};
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{is_trait_method, path_to_local_id, remove_blocks, SpanlessEq};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
-use rustc_hir::{Expr, ExprKind, PatKind, UnOp};
+use rustc_hir::def::Res;
+use rustc_hir::{Expr, ExprKind, PatKind, QPath, UnOp};
 use rustc_lint::LateContext;
 use rustc_middle::ty::TyS;
-use rustc_span::symbol::sym;
+use rustc_span::source_map::Span;
+use rustc_span::symbol::{sym, Symbol};
+use std::borrow::Cow;
 
 use super::MANUAL_FILTER_MAP;
 use super::MANUAL_FIND_MAP;
+use super::OPTION_FILTER_MAP;
+
+fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool {
+    match &expr.kind {
+        hir::ExprKind::Path(QPath::TypeRelative(_, mname)) => mname.ident.name == method_name,
+        hir::ExprKind::Path(QPath::Resolved(_, segments)) => {
+            segments.segments.last().unwrap().ident.name == method_name
+        },
+        hir::ExprKind::Closure(_, _, c, _, _) => {
+            let body = cx.tcx.hir().body(*c);
+            let closure_expr = remove_blocks(&body.value);
+            let arg_id = body.params[0].pat.hir_id;
+            match closure_expr.kind {
+                hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, _, args, _) => {
+                    if_chain! {
+                    if ident.name == method_name;
+                    if let hir::ExprKind::Path(path) = &args[0].kind;
+                    if let Res::Local(ref local) = cx.qpath_res(path, args[0].hir_id);
+                    then {
+                        return arg_id == *local
+                    }
+                    }
+                    false
+                },
+                _ => false,
+            }
+        },
+        _ => false,
+    }
+}
+
+fn is_option_filter_map<'tcx>(cx: &LateContext<'tcx>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool {
+    is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some))
+}
+
+/// lint use of `filter().map()` for `Iterators`
+fn lint_filter_some_map_unwrap(
+    cx: &LateContext<'_>,
+    expr: &hir::Expr<'_>,
+    filter_recv: &hir::Expr<'_>,
+    filter_arg: &hir::Expr<'_>,
+    map_arg: &hir::Expr<'_>,
+    target_span: Span,
+    methods_span: Span,
+) {
+    let iterator = is_trait_method(cx, expr, sym::Iterator);
+    let option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(filter_recv), sym::option_type);
+    if (iterator || option) && is_option_filter_map(cx, filter_arg, map_arg) {
+        let msg = "`filter` for `Some` followed by `unwrap`";
+        let help = "consider using `flatten` instead";
+        let sugg = format!(
+            "{}",
+            reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, target_span),)
+        );
+        span_lint_and_sugg(
+            cx,
+            OPTION_FILTER_MAP,
+            methods_span,
+            msg,
+            help,
+            sugg,
+            Applicability::MachineApplicable,
+        );
+    }
+}
 
 /// lint use of `filter().map()` or `find().map()` for `Iterators`
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, is_find: bool) {
+#[allow(clippy::too_many_arguments)]
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &hir::Expr<'_>,
+    filter_recv: &hir::Expr<'_>,
+    filter_arg: &hir::Expr<'_>,
+    filter_span: Span,
+    map_recv: &hir::Expr<'_>,
+    map_arg: &hir::Expr<'_>,
+    map_span: Span,
+    is_find: bool,
+) {
+    lint_filter_some_map_unwrap(
+        cx,
+        expr,
+        filter_recv,
+        filter_arg,
+        map_arg,
+        map_span,
+        filter_span.with_hi(expr.span.hi()),
+    );
     if_chain! {
-        if let ExprKind::MethodCall(_, _, [map_recv, map_arg], map_span) = expr.kind;
-        if let ExprKind::MethodCall(_, _, [_, filter_arg], filter_span) = map_recv.kind;
-        if is_trait_method(cx, map_recv, sym::Iterator);
+            if is_trait_method(cx, map_recv, sym::Iterator);
 
-        // filter(|x| ...is_some())...
-        if let ExprKind::Closure(_, _, filter_body_id, ..) = filter_arg.kind;
-        let filter_body = cx.tcx.hir().body(filter_body_id);
-        if let [filter_param] = filter_body.params;
-        // optional ref pattern: `filter(|&x| ..)`
-        let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind {
-            (ref_pat, true)
-        } else {
-            (filter_param.pat, false)
-        };
-        // closure ends with is_some() or is_ok()
-        if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
-        if let ExprKind::MethodCall(path, _, [filter_arg], _) = filter_body.value.kind;
-        if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).ty_adt_def();
-        if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::option_type, opt_ty.did) {
-            Some(false)
-        } else if cx.tcx.is_diagnostic_item(sym::result_type, opt_ty.did) {
-            Some(true)
-        } else {
-            None
-        };
-        if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" };
+            // filter(|x| ...is_some())...
+            if let ExprKind::Closure(_, _, filter_body_id, ..) = filter_arg.kind;
+            let filter_body = cx.tcx.hir().body(filter_body_id);
+            if let [filter_param] = filter_body.params;
+            // optional ref pattern: `filter(|&x| ..)`
+            let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind {
+                (ref_pat, true)
+            } else {
+                (filter_param.pat, false)
+            };
+            // closure ends with is_some() or is_ok()
+            if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
+            if let ExprKind::MethodCall(path, _, [filter_arg], _) = filter_body.value.kind;
+            if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).ty_adt_def();
+            if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::option_type, opt_ty.did) {
+                Some(false)
+            } else if cx.tcx.is_diagnostic_item(sym::result_type, opt_ty.did) {
+                Some(true)
+            } else {
+                None
+            };
+            if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" };
 
-        // ...map(|x| ...unwrap())
-        if let ExprKind::Closure(_, _, map_body_id, ..) = map_arg.kind;
-        let map_body = cx.tcx.hir().body(map_body_id);
-        if let [map_param] = map_body.params;
-        if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind;
-        // closure ends with expect() or unwrap()
-        if let ExprKind::MethodCall(seg, _, [map_arg, ..], _) = map_body.value.kind;
-        if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or);
+            // ...map(|x| ...unwrap())
+            if let ExprKind::Closure(_, _, map_body_id, ..) = map_arg.kind;
+            let map_body = cx.tcx.hir().body(map_body_id);
+            if let [map_param] = map_body.params;
+            if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind;
+            // closure ends with expect() or unwrap()
+            if let ExprKind::MethodCall(seg, _, [map_arg, ..], _) = map_body.value.kind;
+            if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or);
 
-        let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
-            // in `filter(|x| ..)`, replace `*x` with `x`
-            let a_path = if_chain! {
-                if !is_filter_param_ref;
-                if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind;
-                then { expr_path } else { a }
-            };
-            // let the filter closure arg and the map closure arg be equal
-            if_chain! {
-                if path_to_local_id(a_path, filter_param_id);
-                if path_to_local_id(b, map_param_id);
-                if TyS::same_type(cx.typeck_results().expr_ty_adjusted(a), cx.typeck_results().expr_ty_adjusted(b));
-                then {
-                    return true;
+            let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
+                // in `filter(|x| ..)`, replace `*x` with `x`
+                let a_path = if_chain! {
+                    if !is_filter_param_ref;
+                    if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind;
+                    then { expr_path } else { a }
+                };
+                // let the filter closure arg and the map closure arg be equal
+                if_chain! {
+                    if path_to_local_id(a_path, filter_param_id);
+                    if path_to_local_id(b, map_param_id);
+                    if TyS::same_type(cx.typeck_results().expr_ty_adjusted(a), cx.typeck_results().expr_ty_adjusted(b));
+                    then {
+                        return true;
+                    }
                 }
-            }
-            false
-        };
-        if SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg);
-        then {
-            let span = filter_span.to(map_span);
-            let (filter_name, lint) = if is_find {
-                ("find", MANUAL_FIND_MAP)
-            } else {
-                ("filter", MANUAL_FILTER_MAP)
+                false
             };
-            let msg = format!("`{}(..).map(..)` can be simplified as `{0}_map(..)`", filter_name);
-            let to_opt = if is_result { ".ok()" } else { "" };
-            let sugg = format!("{}_map(|{}| {}{})", filter_name, map_param_ident,
-                snippet(cx, map_arg.span, ".."), to_opt);
-            span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable);
-        }
+            if SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg);
+            then {
+                let span = filter_span.with_hi(expr.span.hi());
+                let (filter_name, lint) = if is_find {
+                    ("find", MANUAL_FIND_MAP)
+                } else {
+                    ("filter", MANUAL_FILTER_MAP)
+                };
+                let msg = format!("`{}(..).map(..)` can be simplified as `{0}_map(..)`", filter_name);
+                let to_opt = if is_result { ".ok()" } else { "" };
+                let sugg = format!("{}_map(|{}| {}{})", filter_name, map_param_ident,
+                    snippet(cx, map_arg.span, ".."), to_opt);
+                span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable);
+            }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs
index 80598d88508..3a61f4ccad7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs
@@ -8,15 +8,8 @@ use rustc_span::{source_map::Span, sym};
 
 use super::FILTER_MAP_IDENTITY;
 
-pub(super) fn check(
-    cx: &LateContext<'_>,
-    expr: &hir::Expr<'_>,
-    filter_map_args: &[hir::Expr<'_>],
-    filter_map_span: Span,
-) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg: &hir::Expr<'_>, filter_map_span: Span) {
     if is_trait_method(cx, expr, sym::Iterator) {
-        let arg_node = &filter_map_args[1].kind;
-
         let apply_lint = |message: &str| {
             span_lint_and_sugg(
                 cx,
@@ -30,8 +23,8 @@ pub(super) fn check(
         };
 
         if_chain! {
-            if let hir::ExprKind::Closure(_, _, body_id, _, _) = arg_node;
-            let body = cx.tcx.hir().body(*body_id);
+            if let hir::ExprKind::Closure(_, _, body_id, _, _) = filter_map_arg.kind;
+            let body = cx.tcx.hir().body(body_id);
 
             if let hir::PatKind::Binding(_, binding_id, ..) = body.params[0].pat.kind;
             if path_to_local_id(&body.value, binding_id);
@@ -41,7 +34,7 @@ pub(super) fn check(
         }
 
         if_chain! {
-            if let hir::ExprKind::Path(ref qpath) = arg_node;
+            if let hir::ExprKind::Path(ref qpath) = filter_map_arg.kind;
 
             if match_qpath(qpath, &paths::STD_CONVERT_IDENTITY);
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs
index ba57abd16c9..2b19e4ee8c0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs
@@ -14,7 +14,8 @@ const FILTER_MAP_NEXT_MSRV: RustcVersion = RustcVersion::new(1, 30, 0);
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx hir::Expr<'_>,
-    filter_args: &'tcx [hir::Expr<'_>],
+    recv: &'tcx hir::Expr<'_>,
+    arg: &'tcx hir::Expr<'_>,
     msrv: Option<&RustcVersion>,
 ) {
     if is_trait_method(cx, expr, sym::Iterator) {
@@ -24,9 +25,9 @@ pub(super) fn check<'tcx>(
 
         let msg = "called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling \
                    `.find_map(..)` instead";
-        let filter_snippet = snippet(cx, filter_args[1].span, "..");
+        let filter_snippet = snippet(cx, arg.span, "..");
         if filter_snippet.lines().count() <= 1 {
-            let iter_snippet = snippet(cx, filter_args[0].span, "..");
+            let iter_snippet = snippet(cx, recv.span, "..");
             span_lint_and_sugg(
                 cx,
                 FILTER_MAP_NEXT,
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs
index 6cd24334414..172714f6b01 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs
@@ -9,14 +9,19 @@ use rustc_span::sym;
 use super::FILTER_NEXT;
 
 /// lint use of `filter().next()` for `Iterators`
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, filter_args: &'tcx [hir::Expr<'_>]) {
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx hir::Expr<'_>,
+    recv: &'tcx hir::Expr<'_>,
+    filter_arg: &'tcx hir::Expr<'_>,
+) {
     // lint if caller of `.filter().next()` is an Iterator
     if is_trait_method(cx, expr, sym::Iterator) {
         let msg = "called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling \
                    `.find(..)` instead";
-        let filter_snippet = snippet(cx, filter_args[1].span, "..");
+        let filter_snippet = snippet(cx, filter_arg.span, "..");
         if filter_snippet.lines().count() <= 1 {
-            let iter_snippet = snippet(cx, filter_args[0].span, "..");
+            let iter_snippet = snippet(cx, recv.span, "..");
             // add note if not multi-line
             span_lint_and_sugg(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs
index 034ea6c6562..dd613d0cd63 100644
--- a/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs
@@ -12,11 +12,11 @@ use super::FLAT_MAP_IDENTITY;
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx hir::Expr<'_>,
-    flat_map_args: &'tcx [hir::Expr<'_>],
+    flat_map_arg: &'tcx hir::Expr<'_>,
     flat_map_span: Span,
 ) {
     if is_trait_method(cx, expr, sym::Iterator) {
-        let arg_node = &flat_map_args[1].kind;
+        let arg_node = &flat_map_arg.kind;
 
         let apply_lint = |message: &str| {
             span_lint_and_sugg(
@@ -35,7 +35,7 @@ pub(super) fn check<'tcx>(
             let body = cx.tcx.hir().body(*body_id);
 
             if let hir::PatKind::Binding(_, _, binding_ident, _) = body.params[0].pat.kind;
-            if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = body.value.kind;
+            if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = body.value.kind;
 
             if path.segments.len() == 1;
             if path.segments[0].ident.name == binding_ident.name;
diff --git a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
index 15cf5674313..707c54f7a3c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
@@ -40,8 +40,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Exp
 }
 
 fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -> String {
+    let call_site = expr.span.source_callsite();
     if_chain! {
-        let call_site = expr.span.source_callsite();
         if let Ok(snippet) = cx.sess().source_map().span_to_snippet(call_site);
         let snippet_split = snippet.split("::").collect::<Vec<_>>();
         if let Some((_, elements)) = snippet_split.split_last();
diff --git a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
index b3a9743c614..54f28064384 100644
--- a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
@@ -11,18 +11,20 @@ use rustc_span::sym;
 
 use super::GET_UNWRAP;
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args: &'tcx [hir::Expr<'_>], is_mut: bool) {
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &hir::Expr<'_>,
+    recv: &'tcx hir::Expr<'tcx>,
+    get_arg: &'tcx hir::Expr<'_>,
+    is_mut: bool,
+) {
     // Note: we don't want to lint `get_mut().unwrap` for `HashMap` or `BTreeMap`,
     // because they do not implement `IndexMut`
     let mut applicability = Applicability::MachineApplicable;
-    let expr_ty = cx.typeck_results().expr_ty(&get_args[0]);
-    let get_args_str = if get_args.len() > 1 {
-        snippet_with_applicability(cx, get_args[1].span, "..", &mut applicability)
-    } else {
-        return; // not linting on a .get().unwrap() chain or variant
-    };
+    let expr_ty = cx.typeck_results().expr_ty(recv);
+    let get_args_str = snippet_with_applicability(cx, get_arg.span, "..", &mut applicability);
     let mut needs_ref;
-    let caller_type = if derefs_to_slice(cx, &get_args[0], expr_ty).is_some() {
+    let caller_type = if derefs_to_slice(cx, recv, expr_ty).is_some() {
         needs_ref = get_args_str.parse::<usize>().is_ok();
         "slice"
     } else if is_type_diagnostic_item(cx, expr_ty, sym::vec_type) {
@@ -77,7 +79,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args
         format!(
             "{}{}[{}]",
             borrow_str,
-            snippet_with_applicability(cx, get_args[0].span, "..", &mut applicability),
+            snippet_with_applicability(cx, recv.span, "..", &mut applicability),
             get_args_str
         ),
         applicability,
diff --git a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
index 04461ad5c3a..1211e2f2bf7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
@@ -13,7 +13,7 @@ use clippy_utils::is_diagnostic_assoc_item;
 pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, trait_diagnostic: Symbol) {
     if_chain! {
         if let ExprKind::MethodCall(method_path, _, [arg], _) = &expr.kind;
-        let return_type = cx.typeck_results().expr_ty(&expr);
+        let return_type = cx.typeck_results().expr_ty(expr);
         let input_type = cx.typeck_results().expr_ty(arg).peel_refs();
         if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did));
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs b/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
index 848f47e39f6..739f313716e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
@@ -9,10 +9,10 @@ use rustc_span::sym;
 
 use super::ITER_CLONED_COLLECT;
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, recv: &'tcx hir::Expr<'_>) {
     if_chain! {
         if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::vec_type);
-        if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0]));
+        if let Some(slice) = derefs_to_slice(cx, recv, cx.typeck_results().expr_ty(recv));
         if let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite());
 
         then {
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_count.rs b/src/tools/clippy/clippy_lints/src/methods/iter_count.rs
index e394a8fe819..c6b7c7cd179 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_count.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_count.rs
@@ -10,9 +10,9 @@ use rustc_span::sym;
 
 use super::ITER_COUNT;
 
-pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'tcx [Expr<'tcx>], iter_method: &str) {
-    let ty = cx.typeck_results().expr_ty(&iter_args[0]);
-    let caller_type = if derefs_to_slice(cx, &iter_args[0], ty).is_some() {
+pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, iter_method: &str) {
+    let ty = cx.typeck_results().expr_ty(recv);
+    let caller_type = if derefs_to_slice(cx, recv, ty).is_some() {
         "slice"
     } else if is_type_diagnostic_item(cx, ty, sym::vec_type) {
         "Vec"
@@ -42,7 +42,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'
         "try",
         format!(
             "{}.len()",
-            snippet_with_applicability(cx, iter_args[0].span, "..", &mut applicability),
+            snippet_with_applicability(cx, recv.span, "..", &mut applicability),
         ),
         applicability,
     );
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
index e9b37b6f2bd..a49851de38e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
@@ -13,9 +13,7 @@ use rustc_span::symbol::sym;
 
 use super::ITER_NEXT_SLICE;
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) {
-    let caller_expr = &iter_args[0];
-
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, caller_expr: &'tcx hir::Expr<'_>) {
     // Skip lint if the `iter().next()` expression is a for loop argument,
     // since it is already covered by `&loops::ITER_NEXT_LOOP`
     let mut parent_expr_opt = get_parent_expr(cx, expr);
@@ -29,7 +27,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, ite
     if derefs_to_slice(cx, caller_expr, cx.typeck_results().expr_ty(caller_expr)).is_some() {
         // caller is a Slice
         if_chain! {
-            if let hir::ExprKind::Index(ref caller_var, ref index_expr) = &caller_expr.kind;
+            if let hir::ExprKind::Index(caller_var, index_expr) = &caller_expr.kind;
             if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen })
                 = higher::range(index_expr);
             if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind;
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs b/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs
index c46af427b3c..c2232239fe4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs
@@ -11,20 +11,20 @@ use super::ITER_NTH;
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &hir::Expr<'_>,
-    nth_and_iter_args: &[&'tcx [hir::Expr<'tcx>]],
+    iter_recv: &'tcx hir::Expr<'tcx>,
+    nth_recv: &hir::Expr<'_>,
+    nth_arg: &hir::Expr<'_>,
     is_mut: bool,
 ) {
-    let iter_args = nth_and_iter_args[1];
     let mut_str = if is_mut { "_mut" } else { "" };
-    let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0])).is_some() {
+    let caller_type = if derefs_to_slice(cx, iter_recv, cx.typeck_results().expr_ty(iter_recv)).is_some() {
         "slice"
-    } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym::vec_type) {
+    } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(iter_recv), sym::vec_type) {
         "Vec"
-    } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym::vecdeque_type) {
+    } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(iter_recv), sym::vecdeque_type) {
         "VecDeque"
     } else {
-        let nth_args = nth_and_iter_args[0];
-        iter_nth_zero::check(cx, expr, &nth_args);
+        iter_nth_zero::check(cx, expr, nth_recv, nth_arg);
         return; // caller is not a type that we want to lint
     };
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs
index a12f672739c..52d7c15332e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs
@@ -10,10 +10,10 @@ use rustc_span::sym;
 
 use super::ITER_NTH_ZERO;
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, nth_args: &'tcx [hir::Expr<'_>]) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
     if_chain! {
         if is_trait_method(cx, expr, sym::Iterator);
-        if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &nth_args[1]);
+        if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), arg);
         then {
             let mut applicability = Applicability::MachineApplicable;
             span_lint_and_sugg(
@@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, nth_args
                 expr.span,
                 "called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent",
                 "try calling `.next()` instead of `.nth(0)`",
-                format!("{}.next()", snippet_with_applicability(cx, nth_args[0].span, "..", &mut applicability)),
+                format!("{}.next()", snippet_with_applicability(cx, recv.span, "..", &mut applicability)),
                 applicability,
             );
         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs b/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs
index b1d398876d3..e32594757d0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs
@@ -8,19 +8,17 @@ use rustc_span::sym;
 
 use super::ITER_SKIP_NEXT;
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[hir::Expr<'_>]) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
     // lint if caller of skip is an Iterator
     if is_trait_method(cx, expr, sym::Iterator) {
-        if let [caller, n] = skip_args {
-            span_lint_and_sugg(
-                cx,
-                ITER_SKIP_NEXT,
-                expr.span.trim_start(caller.span).unwrap(),
-                "called `skip(..).next()` on an iterator",
-                "use `nth` instead",
-                format!(".nth({})", snippet(cx, n.span, "..")),
-                Applicability::MachineApplicable,
-            );
-        }
+        span_lint_and_sugg(
+            cx,
+            ITER_SKIP_NEXT,
+            expr.span.trim_start(recv.span).unwrap(),
+            "called `skip(..).next()` on an iterator",
+            "use `nth` instead",
+            format!(".nth({})", snippet(cx, arg.span, "..")),
+            Applicability::MachineApplicable,
+        );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs
index 3baa580314f..06b12998b1a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs
@@ -7,9 +7,9 @@ use rustc_span::sym;
 
 use super::ITERATOR_STEP_BY_ZERO;
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, args: &'tcx [hir::Expr<'_>]) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) {
     if is_trait_method(cx, expr, sym::Iterator) {
-        if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &args[1]) {
+        if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), arg) {
             span_lint(
                 cx,
                 ITERATOR_STEP_BY_ZERO,
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
index f16699322d1..ecb8b72ef46 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
@@ -8,11 +8,14 @@ use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_target::abi::LayoutOf;
 
-pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[&[hir::Expr<'_>]], arith: &str) {
-    let unwrap_arg = &args[0][1];
-    let arith_lhs = &args[1][0];
-    let arith_rhs = &args[1][1];
-
+pub fn check(
+    cx: &LateContext<'_>,
+    expr: &hir::Expr<'_>,
+    arith_lhs: &hir::Expr<'_>,
+    arith_rhs: &hir::Expr<'_>,
+    unwrap_arg: &hir::Expr<'_>,
+    arith: &str,
+) {
     let ty = cx.typeck_results().expr_ty(arith_lhs);
     if !ty.is_integral() {
         return;
@@ -41,44 +44,28 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[&[hir::Expr<'_>
             // "mul" is omitted because lhs can be negative.
             _ => return,
         }
-
-        let mut applicability = Applicability::MachineApplicable;
-        span_lint_and_sugg(
-            cx,
-            super::MANUAL_SATURATING_ARITHMETIC,
-            expr.span,
-            "manual saturating arithmetic",
-            &format!("try using `saturating_{}`", arith),
-            format!(
-                "{}.saturating_{}({})",
-                snippet_with_applicability(cx, arith_lhs.span, "..", &mut applicability),
-                arith,
-                snippet_with_applicability(cx, arith_rhs.span, "..", &mut applicability),
-            ),
-            applicability,
-        );
     } else {
         match (mm, arith) {
             (MinMax::Max, "add" | "mul") | (MinMax::Min, "sub") => (),
             _ => return,
         }
-
-        let mut applicability = Applicability::MachineApplicable;
-        span_lint_and_sugg(
-            cx,
-            super::MANUAL_SATURATING_ARITHMETIC,
-            expr.span,
-            "manual saturating arithmetic",
-            &format!("try using `saturating_{}`", arith),
-            format!(
-                "{}.saturating_{}({})",
-                snippet_with_applicability(cx, arith_lhs.span, "..", &mut applicability),
-                arith,
-                snippet_with_applicability(cx, arith_rhs.span, "..", &mut applicability),
-            ),
-            applicability,
-        );
     }
+
+    let mut applicability = Applicability::MachineApplicable;
+    span_lint_and_sugg(
+        cx,
+        super::MANUAL_SATURATING_ARITHMETIC,
+        expr.span,
+        "manual saturating arithmetic",
+        &format!("try using `saturating_{}`", arith),
+        format!(
+            "{}.saturating_{}({})",
+            snippet_with_applicability(cx, arith_lhs.span, "..", &mut applicability),
+            arith,
+            snippet_with_applicability(cx, arith_rhs.span, "..", &mut applicability),
+        ),
+        applicability,
+    );
 }
 
 #[derive(PartialEq, Eq)]
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs b/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs
index e4402b2da21..82063ad70b5 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs
@@ -14,13 +14,13 @@ use super::MAP_COLLECT_RESULT_UNIT;
 pub(super) fn check(
     cx: &LateContext<'_>,
     expr: &hir::Expr<'_>,
-    map_args: &[hir::Expr<'_>],
-    collect_args: &[hir::Expr<'_>],
+    iter: &hir::Expr<'_>,
+    map_fn: &hir::Expr<'_>,
+    collect_recv: &hir::Expr<'_>,
 ) {
     if_chain! {
         // called on Iterator
-        if let [map_expr] = collect_args;
-        if is_trait_method(cx, map_expr, sym::Iterator);
+        if is_trait_method(cx, collect_recv, sym::Iterator);
         // return of collect `Result<(),_>`
         let collect_ret_ty = cx.typeck_results().expr_ty(expr);
         if is_type_diagnostic_item(cx, collect_ret_ty, sym::result_type);
@@ -28,7 +28,6 @@ pub(super) fn check(
         if let Some(result_t) = substs.types().next();
         if result_t.is_unit();
         // get parts for snippet
-        if let [iter, map_fn] = map_args;
         then {
             span_lint_and_sugg(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
index 4bc52b036a8..e8ad16bc0de 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
@@ -11,10 +11,15 @@ use rustc_span::symbol::sym;
 use super::MAP_FLATTEN;
 
 /// lint use of `map().flatten()` for `Iterators` and 'Options'
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_args: &'tcx [hir::Expr<'_>]) {
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx hir::Expr<'_>,
+    recv: &'tcx hir::Expr<'_>,
+    map_arg: &'tcx hir::Expr<'_>,
+) {
     // lint if caller of `.map().flatten()` is an Iterator
     if is_trait_method(cx, expr, sym::Iterator) {
-        let map_closure_ty = cx.typeck_results().expr_ty(&map_args[1]);
+        let map_closure_ty = cx.typeck_results().expr_ty(map_arg);
         let is_map_to_option = match map_closure_ty.kind() {
             ty::Closure(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) => {
                 let map_closure_sig = match map_closure_ty.kind() {
@@ -34,12 +39,12 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map
             // `(...).map(...)` has type `impl Iterator<Item=impl Iterator<...>>
             "flat_map"
         };
-        let func_snippet = snippet(cx, map_args[1].span, "..");
+        let func_snippet = snippet(cx, map_arg.span, "..");
         let hint = format!(".{0}({1})", method_to_use, func_snippet);
         span_lint_and_sugg(
             cx,
             MAP_FLATTEN,
-            expr.span.with_lo(map_args[0].span.hi()),
+            expr.span.with_lo(recv.span.hi()),
             "called `map(..).flatten()` on an `Iterator`",
             &format!("try using `{}` instead", method_to_use),
             hint,
@@ -48,13 +53,13 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map
     }
 
     // lint if caller of `.map().flatten()` is an Option
-    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type) {
-        let func_snippet = snippet(cx, map_args[1].span, "..");
+    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type) {
+        let func_snippet = snippet(cx, map_arg.span, "..");
         let hint = format!(".and_then({})", func_snippet);
         span_lint_and_sugg(
             cx,
             MAP_FLATTEN,
-            expr.span.with_lo(map_args[0].span.hi()),
+            expr.span.with_lo(recv.span.hi()),
             "called `map(..).flatten()` on an `Option`",
             "try using `and_then` instead",
             hint,
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
index deb4b4492b5..4330fea727b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
@@ -18,22 +18,23 @@ const MAP_UNWRAP_OR_MSRV: RustcVersion = RustcVersion::new(1, 41, 0);
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx hir::Expr<'_>,
-    map_args: &'tcx [hir::Expr<'_>],
-    unwrap_args: &'tcx [hir::Expr<'_>],
+    recv: &'tcx hir::Expr<'_>,
+    map_arg: &'tcx hir::Expr<'_>,
+    unwrap_arg: &'tcx hir::Expr<'_>,
     msrv: Option<&RustcVersion>,
 ) -> bool {
     if !meets_msrv(msrv, &MAP_UNWRAP_OR_MSRV) {
         return false;
     }
     // lint if the caller of `map()` is an `Option`
-    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type);
-    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::result_type);
+    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type);
+    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::result_type);
 
     if is_option || is_result {
         // Don't make a suggestion that may fail to compile due to mutably borrowing
         // the same variable twice.
-        let map_mutated_vars = mutated_variables(&map_args[0], cx);
-        let unwrap_mutated_vars = mutated_variables(&unwrap_args[1], cx);
+        let map_mutated_vars = mutated_variables(recv, cx);
+        let unwrap_mutated_vars = mutated_variables(unwrap_arg, cx);
         if let (Some(map_mutated_vars), Some(unwrap_mutated_vars)) = (map_mutated_vars, unwrap_mutated_vars) {
             if map_mutated_vars.intersection(&unwrap_mutated_vars).next().is_some() {
                 return false;
@@ -51,14 +52,14 @@ pub(super) fn check<'tcx>(
             `.map_or_else(<g>, <f>)` instead"
         };
         // get snippets for args to map() and unwrap_or_else()
-        let map_snippet = snippet(cx, map_args[1].span, "..");
-        let unwrap_snippet = snippet(cx, unwrap_args[1].span, "..");
+        let map_snippet = snippet(cx, map_arg.span, "..");
+        let unwrap_snippet = snippet(cx, unwrap_arg.span, "..");
         // lint, with note if neither arg is > 1 line and both map() and
         // unwrap_or_else() have the same span
         let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1;
-        let same_span = map_args[1].span.ctxt() == unwrap_args[1].span.ctxt();
+        let same_span = map_arg.span.ctxt() == unwrap_arg.span.ctxt();
         if same_span && !multiline {
-            let var_snippet = snippet(cx, map_args[0].span, "..");
+            let var_snippet = snippet(cx, recv.span, "..");
             span_lint_and_sugg(
                 cx,
                 MAP_UNWRAP_OR,
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index fccdee07877..b1ade5addd6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -62,17 +62,18 @@ mod zst_offset;
 use bind_instead_of_map::BindInsteadOfMap;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item};
-use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, method_calls, paths, return_ty};
+use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, paths, return_ty};
 use if_chain::if_chain;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
-use rustc_hir::{PrimTy, QPath, TraitItem, TraitItemKind};
+use rustc_hir::{Expr, ExprKind, PrimTy, QPath, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, TraitRef, Ty, TyS};
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::symbol::{sym, SymbolStr};
+use rustc_span::symbol::SymbolStr;
+use rustc_span::{sym, Span};
 use rustc_typeck::hir_ty_to_ty;
 
 declare_clippy_lint! {
@@ -205,6 +206,13 @@ declare_clippy_lint! {
     /// |`to_`  | not `_mut` |`self`                 | `Copy`       |
     /// |`to_`  | not `_mut` |`&self`                | not `Copy`   |
     ///
+    /// Note: Clippy doesn't trigger methods with `to_` prefix in:
+    /// - Traits definition.
+    /// Clippy can not tell if a type that implements a trait is `Copy` or not.
+    /// - Traits implementation, when `&self` is taken.
+    /// The method signature is controlled by the trait and often `&self` is required for all types that implement the trait
+    /// (see e.g. the `std::string::ToString` trait).
+    ///
     /// Please find more info here:
     /// https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv
     ///
@@ -897,6 +905,28 @@ declare_clippy_lint! {
 }
 
 declare_clippy_lint! {
+    /// **What it does:** Checks for indirect collection of populated `Option`
+    ///
+    /// **Why is this bad?** `Option` is like a collection of 0-1 things, so `flatten`
+    /// automatically does this without suspicious-looking `unwrap` calls.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let _ = std::iter::empty::<Option<i32>>().filter(Option::is_some).map(Option::unwrap);
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let _ = std::iter::empty::<Option<i32>>().flatten();
+    /// ```
+    pub OPTION_FILTER_MAP,
+    complexity,
+    "filtering `Option` for `Some` then force-unwrapping, which can be one type-safe operation"
+}
+
+declare_clippy_lint! {
     /// **What it does:** Checks for the use of `iter.nth(0)`.
     ///
     /// **Why is this bad?** `iter.next()` is equivalent to
@@ -1651,6 +1681,7 @@ impl_lint_pass!(Methods => [
     FILTER_MAP_IDENTITY,
     MANUAL_FILTER_MAP,
     MANUAL_FIND_MAP,
+    OPTION_FILTER_MAP,
     FILTER_MAP_NEXT,
     FLAT_MAP_IDENTITY,
     MAP_FLATTEN,
@@ -1681,140 +1712,38 @@ impl_lint_pass!(Methods => [
     IMPLICIT_CLONE
 ]);
 
+/// Extracts a method call name, args, and `Span` of the method name.
+fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(SymbolStr, &'tcx [hir::Expr<'tcx>], Span)> {
+    if let ExprKind::MethodCall(path, span, args, _) = recv.kind {
+        if !args.iter().any(|e| e.span.from_expansion()) {
+            return Some((path.ident.name.as_str(), args, span));
+        }
+    }
+    None
+}
+
+/// Same as `method_call` but the `SymbolStr` is dereferenced into a temporary `&str`
+macro_rules! method_call {
+    ($expr:expr) => {
+        method_call($expr)
+            .as_ref()
+            .map(|&(ref name, args, span)| (&**name, args, span))
+    };
+}
+
 impl<'tcx> LateLintPass<'tcx> for Methods {
-    #[allow(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if in_macro(expr.span) {
             return;
         }
 
-        let (method_names, arg_lists, method_spans) = method_calls(expr, 2);
-        let method_names: Vec<SymbolStr> = method_names.iter().map(|s| s.as_str()).collect();
-        let method_names: Vec<&str> = method_names.iter().map(|s| &**s).collect();
-
-        match method_names.as_slice() {
-            ["unwrap", "get"] => get_unwrap::check(cx, expr, arg_lists[1], false),
-            ["unwrap", "get_mut"] => get_unwrap::check(cx, expr, arg_lists[1], true),
-            ["unwrap", ..] => unwrap_used::check(cx, expr, arg_lists[0]),
-            ["expect", "ok"] => ok_expect::check(cx, expr, arg_lists[1]),
-            ["expect", ..] => expect_used::check(cx, expr, arg_lists[0]),
-            ["unwrap_or", "map"] => option_map_unwrap_or::check(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]),
-            ["unwrap_or_else", "map"] => {
-                if !map_unwrap_or::check(cx, expr, arg_lists[1], arg_lists[0], self.msrv.as_ref()) {
-                    unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "unwrap_or");
-                }
-            },
-            ["map_or", ..] => option_map_or_none::check(cx, expr, arg_lists[0]),
-            ["and_then", ..] => {
-                let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, arg_lists[0]);
-                let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, arg_lists[0]);
-                if !biom_option_linted && !biom_result_linted {
-                    unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "and");
-                }
-            },
-            ["or_else", ..] => {
-                if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, arg_lists[0]) {
-                    unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "or");
-                }
-            },
-            ["next", "filter"] => filter_next::check(cx, expr, arg_lists[1]),
-            ["next", "skip_while"] => skip_while_next::check(cx, expr, arg_lists[1]),
-            ["next", "iter"] => iter_next_slice::check(cx, expr, arg_lists[1]),
-            ["map", "filter"] => filter_map::check(cx, expr, false),
-            ["map", "filter_map"] => filter_map_map::check(cx, expr),
-            ["next", "filter_map"] => filter_map_next::check(cx, expr, arg_lists[1], self.msrv.as_ref()),
-            ["map", "find"] => filter_map::check(cx, expr, true),
-            ["flat_map", "filter"] => filter_flat_map::check(cx, expr),
-            ["flat_map", "filter_map"] => filter_map_flat_map::check(cx, expr),
-            ["flat_map", ..] => flat_map_identity::check(cx, expr, arg_lists[0], method_spans[0]),
-            ["flatten", "map"] => map_flatten::check(cx, expr, arg_lists[1]),
-            [option_check_method, "find"] if "is_some" == *option_check_method || "is_none" == *option_check_method => {
-                search_is_some::check(
-                    cx,
-                    expr,
-                    "find",
-                    option_check_method,
-                    arg_lists[1],
-                    arg_lists[0],
-                    method_spans[1],
-                )
-            },
-            [option_check_method, "position"]
-                if "is_some" == *option_check_method || "is_none" == *option_check_method =>
-            {
-                search_is_some::check(
-                    cx,
-                    expr,
-                    "position",
-                    option_check_method,
-                    arg_lists[1],
-                    arg_lists[0],
-                    method_spans[1],
-                )
-            },
-            [option_check_method, "rposition"]
-                if "is_some" == *option_check_method || "is_none" == *option_check_method =>
-            {
-                search_is_some::check(
-                    cx,
-                    expr,
-                    "rposition",
-                    option_check_method,
-                    arg_lists[1],
-                    arg_lists[0],
-                    method_spans[1],
-                )
-            },
-            ["extend", ..] => string_extend_chars::check(cx, expr, arg_lists[0]),
-            ["count", "into_iter"] => iter_count::check(cx, expr, &arg_lists[1], "into_iter"),
-            ["count", "iter"] => iter_count::check(cx, expr, &arg_lists[1], "iter"),
-            ["count", "iter_mut"] => iter_count::check(cx, expr, &arg_lists[1], "iter_mut"),
-            ["nth", "iter"] => iter_nth::check(cx, expr, &arg_lists, false),
-            ["nth", "iter_mut"] => iter_nth::check(cx, expr, &arg_lists, true),
-            ["nth", "bytes"] => bytes_nth::check(cx, expr, &arg_lists[1]),
-            ["nth", ..] => iter_nth_zero::check(cx, expr, arg_lists[0]),
-            ["step_by", ..] => iterator_step_by_zero::check(cx, expr, arg_lists[0]),
-            ["next", "skip"] => iter_skip_next::check(cx, expr, arg_lists[1]),
-            ["collect", "cloned"] => iter_cloned_collect::check(cx, expr, arg_lists[1]),
-            ["as_ref"] => useless_asref::check(cx, expr, "as_ref", arg_lists[0]),
-            ["as_mut"] => useless_asref::check(cx, expr, "as_mut", arg_lists[0]),
-            ["fold", ..] => unnecessary_fold::check(cx, expr, arg_lists[0], method_spans[0]),
-            ["filter_map", ..] => {
-                unnecessary_filter_map::check(cx, expr, arg_lists[0]);
-                filter_map_identity::check(cx, expr, arg_lists[0], method_spans[0]);
-            },
-            ["count", "map"] => suspicious_map::check(cx, expr, arg_lists[1], arg_lists[0]),
-            ["assume_init"] => uninit_assumed_init::check(cx, &arg_lists[0][0], expr),
-            ["unwrap_or", arith @ ("checked_add" | "checked_sub" | "checked_mul")] => {
-                manual_saturating_arithmetic::check(cx, expr, &arg_lists, &arith["checked_".len()..])
-            },
-            ["add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub"] => {
-                zst_offset::check(cx, expr, arg_lists[0])
-            },
-            ["is_file", ..] => filetype_is_file::check(cx, expr, arg_lists[0]),
-            ["map", "as_ref"] => {
-                option_as_ref_deref::check(cx, expr, arg_lists[1], arg_lists[0], false, self.msrv.as_ref())
-            },
-            ["map", "as_mut"] => {
-                option_as_ref_deref::check(cx, expr, arg_lists[1], arg_lists[0], true, self.msrv.as_ref())
-            },
-            ["unwrap_or_else", ..] => unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "unwrap_or"),
-            ["get_or_insert_with", ..] => unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "get_or_insert"),
-            ["ok_or_else", ..] => unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "ok_or"),
-            ["collect", "map"] => map_collect_result_unit::check(cx, expr, arg_lists[1], arg_lists[0]),
-            ["for_each", "inspect"] => inspect_for_each::check(cx, expr, method_spans[1]),
-            ["to_owned", ..] => implicit_clone::check(cx, expr, sym::ToOwned),
-            ["to_os_string", ..] => implicit_clone::check(cx, expr, sym::OsStr),
-            ["to_path_buf", ..] => implicit_clone::check(cx, expr, sym::Path),
-            ["to_vec", ..] => implicit_clone::check(cx, expr, sym::slice),
-            _ => {},
-        }
+        check_methods(cx, expr, self.msrv.as_ref());
 
         match expr.kind {
-            hir::ExprKind::Call(ref func, ref args) => {
+            hir::ExprKind::Call(func, args) => {
                 from_iter_instead_of_collect::check(cx, expr, args, &func.kind);
             },
-            hir::ExprKind::MethodCall(ref method_call, ref method_span, ref args, _) => {
+            hir::ExprKind::MethodCall(method_call, ref method_span, args, _) => {
                 or_fun_call::check(cx, expr, *method_span, &method_call.ident.as_str(), args);
                 expect_fun_call::check(cx, expr, *method_span, &method_call.ident.as_str(), args);
                 clone_on_copy::check(cx, expr, method_call.ident.name, args);
@@ -1824,9 +1753,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                 into_iter_on_ref::check(cx, expr, *method_span, method_call.ident.name, args);
                 single_char_pattern::check(cx, expr, method_call.ident.name, args);
             },
-            hir::ExprKind::Binary(op, ref lhs, ref rhs)
-                if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne =>
-            {
+            hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
                 let mut info = BinaryExprInfo {
                     expr,
                     chain: lhs,
@@ -1834,7 +1761,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                     eq: op.node == hir::BinOpKind::Eq,
                 };
                 lint_binary_expr_with_method_call(cx, &mut info);
-            }
+            },
             _ => (),
         }
     }
@@ -1850,10 +1777,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
         let self_ty = cx.tcx.type_of(item.def_id);
 
         let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }));
-
         if_chain! {
             if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind;
-            if let Some(first_arg) = iter_input_pats(&sig.decl, cx.tcx.hir().body(id)).next();
+            if let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next();
 
             let method_sig = cx.tcx.fn_sig(impl_item.def_id);
             let method_sig = cx.tcx.erase_late_bound_regions(method_sig);
@@ -1873,7 +1799,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                             method_config.output_type.matches(&sig.decl.output) &&
                             method_config.self_kind.matches(cx, self_ty, first_arg_ty) &&
                             fn_header_equals(method_config.fn_header, sig.header) &&
-                            method_config.lifetime_param_cond(&impl_item)
+                            method_config.lifetime_param_cond(impl_item)
                         {
                             span_lint_and_help(
                                 cx,
@@ -1902,6 +1828,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                     self_ty,
                     first_arg_ty,
                     first_arg.pat.span,
+                    implements_trait,
                     false
                 );
             }
@@ -1960,11 +1887,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
         if_chain! {
             if let TraitItemKind::Fn(ref sig, _) = item.kind;
             if let Some(first_arg_ty) = sig.decl.inputs.iter().next();
-            let first_arg_span = first_arg_ty.span;
-            let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty);
-            let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty();
-
             then {
+                let first_arg_span = first_arg_ty.span;
+                let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty);
+                let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty();
                 wrong_self_convention::check(
                     cx,
                     &item.ident.name.as_str(),
@@ -1972,6 +1898,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                     self_ty,
                     first_arg_ty,
                     first_arg_span,
+                    false,
                     true
                 );
             }
@@ -1997,6 +1924,140 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
 
     extract_msrv_attr!(LateContext);
 }
+
+#[allow(clippy::too_many_lines)]
+fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Option<&RustcVersion>) {
+    if let Some((name, [recv, args @ ..], span)) = method_call!(expr) {
+        match (name, args) {
+            ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [recv, _]) => {
+                zst_offset::check(cx, expr, recv)
+            },
+            ("and_then", [arg]) => {
+                let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg);
+                let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg);
+                if !biom_option_linted && !biom_result_linted {
+                    unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
+                }
+            },
+            ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
+            ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
+            ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
+            ("collect", []) => match method_call!(recv) {
+                Some(("cloned", [recv2], _)) => iter_cloned_collect::check(cx, expr, recv2),
+                Some(("map", [m_recv, m_arg], _)) => {
+                    map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
+                },
+                _ => {},
+            },
+            ("count", []) => match method_call!(recv) {
+                Some((name @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
+                    iter_count::check(cx, expr, recv2, name);
+                },
+                Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
+                _ => {},
+            },
+            ("expect", [_]) => match method_call!(recv) {
+                Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
+                _ => expect_used::check(cx, expr, recv),
+            },
+            ("extend", [arg]) => string_extend_chars::check(cx, expr, recv, arg),
+            ("filter_map", [arg]) => {
+                unnecessary_filter_map::check(cx, expr, arg);
+                filter_map_identity::check(cx, expr, arg, span);
+            },
+            ("flat_map", [flm_arg]) => match method_call!(recv) {
+                Some(("filter", [_, _], _)) => filter_flat_map::check(cx, expr),
+                Some(("filter_map", [_, _], _)) => filter_map_flat_map::check(cx, expr),
+                _ => flat_map_identity::check(cx, expr, flm_arg, span),
+            },
+            ("flatten", []) => {
+                if let Some(("map", [recv, map_arg], _)) = method_call!(recv) {
+                    map_flatten::check(cx, expr, recv, map_arg);
+                }
+            },
+            ("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
+            ("for_each", [_]) => {
+                if let Some(("inspect", [_, _], span2)) = method_call!(recv) {
+                    inspect_for_each::check(cx, expr, span2);
+                }
+            },
+            ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"),
+            ("is_file", []) => filetype_is_file::check(cx, expr, recv),
+            ("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
+            ("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
+            ("map", [m_arg]) => {
+                if let Some((name, [recv2, args @ ..], span2)) = method_call!(recv) {
+                    match (name, args) {
+                        ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, msrv),
+                        ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, msrv),
+                        ("filter", [f_arg]) => {
+                            filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false)
+                        },
+                        ("filter_map", [_]) => filter_map_map::check(cx, expr),
+                        ("find", [f_arg]) => filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true),
+                        _ => {},
+                    }
+                }
+            },
+            ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map),
+            ("next", []) => {
+                if let Some((name, [recv, args @ ..], _)) = method_call!(recv) {
+                    match (name, args) {
+                        ("filter", [arg]) => filter_next::check(cx, expr, recv, arg),
+                        ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv, arg, msrv),
+                        ("iter", []) => iter_next_slice::check(cx, expr, recv),
+                        ("skip", [arg]) => iter_skip_next::check(cx, expr, recv, arg),
+                        ("skip_while", [_]) => skip_while_next::check(cx, expr),
+                        _ => {},
+                    }
+                }
+            },
+            ("nth", [n_arg]) => match method_call!(recv) {
+                Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
+                Some(("iter", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
+                Some(("iter_mut", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
+                _ => iter_nth_zero::check(cx, expr, recv, n_arg),
+            },
+            ("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
+            ("or_else", [arg]) => {
+                if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) {
+                    unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
+                }
+            },
+            ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
+            ("to_os_string", []) => implicit_clone::check(cx, expr, sym::OsStr),
+            ("to_owned", []) => implicit_clone::check(cx, expr, sym::ToOwned),
+            ("to_path_buf", []) => implicit_clone::check(cx, expr, sym::Path),
+            ("to_vec", []) => implicit_clone::check(cx, expr, sym::slice),
+            ("unwrap", []) => match method_call!(recv) {
+                Some(("get", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, false),
+                Some(("get_mut", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, true),
+                _ => unwrap_used::check(cx, expr, recv),
+            },
+            ("unwrap_or", [u_arg]) => match method_call!(recv) {
+                Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
+                    manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
+                },
+                Some(("map", [m_recv, m_arg], span)) => {
+                    option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span)
+                },
+                _ => {},
+            },
+            ("unwrap_or_else", [u_arg]) => match method_call!(recv) {
+                Some(("map", [recv, map_arg], _)) if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, msrv) => {},
+                _ => unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"),
+            },
+            _ => {},
+        }
+    }
+}
+
+fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
+    if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span)) = method_call!(recv) {
+        search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span)
+    }
+}
+
 /// Used for `lint_binary_expr_with_method_call`.
 #[derive(Copy, Clone)]
 struct BinaryExprInfo<'a> {
@@ -2209,10 +2270,10 @@ impl OutType {
         let is_unit = |ty: &hir::Ty<'_>| matches!(ty.kind, hir::TyKind::Tup(&[]));
         match (self, ty) {
             (Self::Unit, &hir::FnRetTy::DefaultReturn(_)) => true,
-            (Self::Unit, &hir::FnRetTy::Return(ref ty)) if is_unit(ty) => true,
-            (Self::Bool, &hir::FnRetTy::Return(ref ty)) if is_bool(ty) => true,
-            (Self::Any, &hir::FnRetTy::Return(ref ty)) if !is_unit(ty) => true,
-            (Self::Ref, &hir::FnRetTy::Return(ref ty)) => matches!(ty.kind, hir::TyKind::Rptr(_, _)),
+            (Self::Unit, &hir::FnRetTy::Return(ty)) if is_unit(ty) => true,
+            (Self::Bool, &hir::FnRetTy::Return(ty)) if is_bool(ty) => true,
+            (Self::Any, &hir::FnRetTy::Return(ty)) if !is_unit(ty) => true,
+            (Self::Ref, &hir::FnRetTy::Return(ty)) => matches!(ty.kind, hir::TyKind::Rptr(_, _)),
             _ => false,
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs b/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs
index e6ce9cac397..d0b1b4b84be 100644
--- a/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs
@@ -9,11 +9,11 @@ use rustc_span::sym;
 use super::OK_EXPECT;
 
 /// lint use of `ok().expect()` for `Result`s
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ok_args: &[hir::Expr<'_>]) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
     if_chain! {
         // lint if the caller of `ok()` is a `Result`
-        if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&ok_args[0]), sym::result_type);
-        let result_type = cx.typeck_results().expr_ty(&ok_args[0]);
+        if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::result_type);
+        let result_type = cx.typeck_results().expr_ty(recv);
         if let Some(error_type) = get_error_type(cx, result_type);
         if has_debug_impl(error_type, cx);
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
index d11ede080dc..7e9c8fa829d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
@@ -18,8 +18,8 @@ const OPTION_AS_REF_DEREF_MSRV: RustcVersion = RustcVersion::new(1, 40, 0);
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &hir::Expr<'_>,
-    as_ref_args: &[hir::Expr<'_>],
-    map_args: &[hir::Expr<'_>],
+    as_ref_recv: &hir::Expr<'_>,
+    map_arg: &hir::Expr<'_>,
     is_mut: bool,
     msrv: Option<&RustcVersion>,
 ) {
@@ -29,7 +29,7 @@ pub(super) fn check<'tcx>(
 
     let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not);
 
-    let option_ty = cx.typeck_results().expr_ty(&as_ref_args[0]);
+    let option_ty = cx.typeck_results().expr_ty(as_ref_recv);
     if !is_type_diagnostic_item(cx, option_ty, sym::option_type) {
         return;
     }
@@ -46,9 +46,9 @@ pub(super) fn check<'tcx>(
         &paths::VEC_AS_MUT_SLICE,
     ];
 
-    let is_deref = match map_args[1].kind {
+    let is_deref = match map_arg.kind {
         hir::ExprKind::Path(ref expr_qpath) => cx
-            .qpath_res(expr_qpath, map_args[1].hir_id)
+            .qpath_res(expr_qpath, map_arg.hir_id)
             .opt_def_id()
             .map_or(false, |fun_def_id| {
                 deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path))
@@ -77,10 +77,10 @@ pub(super) fn check<'tcx>(
                         }
                     }
                 },
-                hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref inner) if same_mutability(m) => {
+                hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, inner) if same_mutability(m) => {
                     if_chain! {
-                        if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner1) = inner.kind;
-                        if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner2) = inner1.kind;
+                        if let hir::ExprKind::Unary(hir::UnOp::Deref, inner1) = inner.kind;
+                        if let hir::ExprKind::Unary(hir::UnOp::Deref, inner2) = inner1.kind;
                         then {
                             path_to_local_id(inner2, closure_body.params[0].pat.hir_id)
                         } else {
@@ -96,12 +96,12 @@ pub(super) fn check<'tcx>(
 
     if is_deref {
         let current_method = if is_mut {
-            format!(".as_mut().map({})", snippet(cx, map_args[1].span, ".."))
+            format!(".as_mut().map({})", snippet(cx, map_arg.span, ".."))
         } else {
-            format!(".as_ref().map({})", snippet(cx, map_args[1].span, ".."))
+            format!(".as_ref().map({})", snippet(cx, map_arg.span, ".."))
         };
         let method_hint = if is_mut { "as_deref_mut" } else { "as_deref" };
-        let hint = format!("{}.{}()", snippet(cx, as_ref_args[0].span, ".."), method_hint);
+        let hint = format!("{}.{}()", snippet(cx, as_ref_recv.span, ".."), method_hint);
         let suggestion = format!("try using {} instead", method_hint);
 
         let msg = format!(
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
index d93db2c22e4..013a6f90ac9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
@@ -11,9 +11,15 @@ use super::OPTION_MAP_OR_NONE;
 use super::RESULT_MAP_OR_INTO_OPTION;
 
 /// lint use of `_.map_or(None, _)` for `Option`s and `Result`s
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_or_args: &'tcx [hir::Expr<'_>]) {
-    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym::option_type);
-    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym::result_type);
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx hir::Expr<'_>,
+    recv: &'tcx hir::Expr<'_>,
+    def_arg: &'tcx hir::Expr<'_>,
+    map_arg: &'tcx hir::Expr<'_>,
+) {
+    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type);
+    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::result_type);
 
     // There are two variants of this `map_or` lint:
     // (1) using `map_or` as an adapter from `Result<T,E>` to `Option<T>`
@@ -25,7 +31,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map
     }
 
     let (lint_name, msg, instead, hint) = {
-        let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = map_or_args[1].kind {
+        let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = def_arg.kind {
             match_qpath(qpath, &paths::OPTION_NONE)
         } else {
             return;
@@ -36,15 +42,15 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map
             return;
         }
 
-        let f_arg_is_some = if let hir::ExprKind::Path(ref qpath) = map_or_args[2].kind {
+        let f_arg_is_some = if let hir::ExprKind::Path(ref qpath) = map_arg.kind {
             match_qpath(qpath, &paths::OPTION_SOME)
         } else {
             false
         };
 
         if is_option {
-            let self_snippet = snippet(cx, map_or_args[0].span, "..");
-            let func_snippet = snippet(cx, map_or_args[2].span, "..");
+            let self_snippet = snippet(cx, recv.span, "..");
+            let func_snippet = snippet(cx, map_arg.span, "..");
             let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \
                        `and_then(..)` instead";
             (
@@ -56,7 +62,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map
         } else if f_arg_is_some {
             let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \
                        `ok()` instead";
-            let self_snippet = snippet(cx, map_or_args[0].span, "..");
+            let self_snippet = snippet(cx, recv.span, "..");
             (
                 RESULT_MAP_OR_INTO_OPTION,
                 msg,
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
index e252abc177a..5bca49dec24 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
@@ -18,13 +18,15 @@ use super::MAP_UNWRAP_OR;
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &rustc_hir::Expr<'_>,
-    map_args: &'tcx [rustc_hir::Expr<'_>],
-    unwrap_args: &'tcx [rustc_hir::Expr<'_>],
+    recv: &rustc_hir::Expr<'_>,
+    map_arg: &'tcx rustc_hir::Expr<'_>,
+    unwrap_recv: &rustc_hir::Expr<'_>,
+    unwrap_arg: &'tcx rustc_hir::Expr<'_>,
     map_span: Span,
 ) {
     // lint if the caller of `map()` is an `Option`
-    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type) {
-        if !is_copy(cx, cx.typeck_results().expr_ty(&unwrap_args[1])) {
+    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type) {
+        if !is_copy(cx, cx.typeck_results().expr_ty(unwrap_arg)) {
             // Do not lint if the `map` argument uses identifiers in the `map`
             // argument that are also used in the `unwrap_or` argument
 
@@ -32,27 +34,27 @@ pub(super) fn check<'tcx>(
                 cx,
                 identifiers: FxHashSet::default(),
             };
-            unwrap_visitor.visit_expr(&unwrap_args[1]);
+            unwrap_visitor.visit_expr(unwrap_arg);
 
             let mut map_expr_visitor = MapExprVisitor {
                 cx,
                 identifiers: unwrap_visitor.identifiers,
                 found_identifier: false,
             };
-            map_expr_visitor.visit_expr(&map_args[1]);
+            map_expr_visitor.visit_expr(map_arg);
 
             if map_expr_visitor.found_identifier {
                 return;
             }
         }
 
-        if differing_macro_contexts(unwrap_args[1].span, map_span) {
+        if differing_macro_contexts(unwrap_arg.span, map_span) {
             return;
         }
 
         let mut applicability = Applicability::MachineApplicable;
         // get snippet for unwrap_or()
-        let unwrap_snippet = snippet_with_applicability(cx, unwrap_args[1].span, "..", &mut applicability);
+        let unwrap_snippet = snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability);
         // lint message
         // comparing the snippet from source to raw text ("None") below is safe
         // because we already have checked the type.
@@ -70,14 +72,14 @@ pub(super) fn check<'tcx>(
         );
 
         span_lint_and_then(cx, MAP_UNWRAP_OR, expr.span, msg, |diag| {
-            let map_arg_span = map_args[1].span;
+            let map_arg_span = map_arg.span;
 
             let mut suggestion = vec![
                 (
                     map_span,
                     String::from(if unwrap_snippet_none { "and_then" } else { "map_or" }),
                 ),
-                (expr.span.with_lo(unwrap_args[0].span.hi()), String::from("")),
+                (expr.span.with_lo(unwrap_recv.span.hi()), String::from("")),
             ];
 
             if !unwrap_snippet_none {
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index 89dedc5f0d8..800172f4cf3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -10,7 +10,7 @@ use rustc_hir::{BlockCheckMode, UnsafeSource};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 use rustc_span::source_map::Span;
-use rustc_span::symbol::sym;
+use rustc_span::symbol::{kw, sym};
 use std::borrow::Cow;
 
 use super::OR_FUN_CALL;
@@ -38,8 +38,8 @@ pub(super) fn check<'tcx>(
             if !or_has_args;
             if name == "unwrap_or";
             if let hir::ExprKind::Path(ref qpath) = fun.kind;
-            let path = &*last_path_segment(qpath).ident.as_str();
-            if ["default", "new"].contains(&path);
+            let path = last_path_segment(qpath).ident.name;
+            if matches!(path, kw::Default | sym::new);
             let arg_ty = cx.typeck_results().expr_ty(arg);
             if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
             if implements_trait(cx, arg_ty, default_trait_id, &[]);
@@ -86,7 +86,7 @@ pub(super) fn check<'tcx>(
             (&paths::RESULT, true, &["or", "unwrap_or"], "else"),
         ];
 
-        if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind {
+        if let hir::ExprKind::MethodCall(path, _, args, _) = &arg.kind {
             if path.ident.as_str() == "len" {
                 let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs();
 
@@ -105,7 +105,7 @@ pub(super) fn check<'tcx>(
             if KNOW_TYPES.iter().any(|k| k.2.contains(&name));
 
             if is_lazyness_candidate(cx, arg);
-            if !contains_return(&arg);
+            if !contains_return(arg);
 
             let self_ty = cx.typeck_results().expr_ty(self_expr);
 
@@ -158,7 +158,7 @@ pub(super) fn check<'tcx>(
 
     if args.len() == 2 {
         match args[1].kind {
-            hir::ExprKind::Call(ref fun, ref or_args) => {
+            hir::ExprKind::Call(fun, or_args) => {
                 let or_has_args = !or_args.is_empty();
                 if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) {
                     let fun_span = if or_has_args { None } else { Some(fun.span) };
diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
index de7d168295f..ecec6fc3bb7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
@@ -15,35 +15,37 @@ use super::SEARCH_IS_SOME;
 
 /// lint searching an Iterator followed by `is_some()`
 /// or calling `find()` on a string followed by `is_some()` or `is_none()`
-#[allow(clippy::too_many_lines)]
+#[allow(clippy::too_many_arguments, clippy::too_many_lines)]
 pub(super) fn check<'tcx>(
-    cx: &LateContext<'tcx>,
+    cx: &LateContext<'_>,
     expr: &'tcx hir::Expr<'_>,
     search_method: &str,
-    option_check_method: &str,
-    search_args: &'tcx [hir::Expr<'_>],
-    is_some_args: &'tcx [hir::Expr<'_>],
+    is_some: bool,
+    search_recv: &hir::Expr<'_>,
+    search_arg: &'tcx hir::Expr<'_>,
+    is_some_recv: &hir::Expr<'_>,
     method_span: Span,
 ) {
+    let option_check_method = if is_some { "is_some" } else { "is_none" };
     // lint if caller of search is an Iterator
-    if is_trait_method(cx, &is_some_args[0], sym::Iterator) {
+    if is_trait_method(cx, is_some_recv, sym::Iterator) {
         let msg = format!(
             "called `{}()` after searching an `Iterator` with `{}`",
             option_check_method, search_method
         );
-        let search_snippet = snippet(cx, search_args[1].span, "..");
+        let search_snippet = snippet(cx, search_arg.span, "..");
         if search_snippet.lines().count() <= 1 {
             // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()`
             // suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()`
             let any_search_snippet = if_chain! {
                 if search_method == "find";
-                if let hir::ExprKind::Closure(_, _, body_id, ..) = search_args[1].kind;
+                if let hir::ExprKind::Closure(_, _, body_id, ..) = search_arg.kind;
                 let closure_body = cx.tcx.hir().body(body_id);
                 if let Some(closure_arg) = closure_body.params.get(0);
                 then {
                     if let hir::PatKind::Ref(..) = closure_arg.pat.kind {
                         Some(search_snippet.replacen('&', "", 1))
-                    } else if let PatKind::Binding(_, _, ident, _) = strip_pat_refs(&closure_arg.pat).kind {
+                    } else if let PatKind::Binding(_, _, ident, _) = strip_pat_refs(closure_arg.pat).kind {
                         let name = &*ident.name.as_str();
                         Some(search_snippet.replace(&format!("*{}", name), name))
                     } else {
@@ -54,38 +56,34 @@ pub(super) fn check<'tcx>(
                 }
             };
             // add note if not multi-line
-            match option_check_method {
-                "is_some" => {
-                    span_lint_and_sugg(
-                        cx,
-                        SEARCH_IS_SOME,
-                        method_span.with_hi(expr.span.hi()),
-                        &msg,
-                        "use `any()` instead",
-                        format!(
-                            "any({})",
-                            any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
-                        ),
-                        Applicability::MachineApplicable,
-                    );
-                },
-                "is_none" => {
-                    let iter = snippet(cx, search_args[0].span, "..");
-                    span_lint_and_sugg(
-                        cx,
-                        SEARCH_IS_SOME,
-                        expr.span,
-                        &msg,
-                        "use `!_.any()` instead",
-                        format!(
-                            "!{}.any({})",
-                            iter,
-                            any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
-                        ),
-                        Applicability::MachineApplicable,
-                    );
-                },
-                _ => (),
+            if is_some {
+                span_lint_and_sugg(
+                    cx,
+                    SEARCH_IS_SOME,
+                    method_span.with_hi(expr.span.hi()),
+                    &msg,
+                    "use `any()` instead",
+                    format!(
+                        "any({})",
+                        any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
+                    ),
+                    Applicability::MachineApplicable,
+                );
+            } else {
+                let iter = snippet(cx, search_recv.span, "..");
+                span_lint_and_sugg(
+                    cx,
+                    SEARCH_IS_SOME,
+                    expr.span,
+                    &msg,
+                    "use `!_.any()` instead",
+                    format!(
+                        "!{}.any({})",
+                        iter,
+                        any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
+                    ),
+                    Applicability::MachineApplicable,
+                );
             }
         } else {
             let hint = format!(
@@ -110,14 +108,14 @@ pub(super) fn check<'tcx>(
             }
         };
         if_chain! {
-            if is_string_or_str_slice(&search_args[0]);
-            if is_string_or_str_slice(&search_args[1]);
+            if is_string_or_str_slice(search_recv);
+            if is_string_or_str_slice(search_arg);
             then {
                 let msg = format!("called `{}()` after calling `find()` on a string", option_check_method);
                 match option_check_method {
                     "is_some" => {
                         let mut applicability = Applicability::MachineApplicable;
-                        let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability);
+                        let find_arg = snippet_with_applicability(cx, search_arg.span, "..", &mut applicability);
                         span_lint_and_sugg(
                             cx,
                             SEARCH_IS_SOME,
@@ -129,9 +127,9 @@ pub(super) fn check<'tcx>(
                         );
                     },
                     "is_none" => {
-                        let string = snippet(cx, search_args[0].span, "..");
+                        let string = snippet(cx, search_recv.span, "..");
                         let mut applicability = Applicability::MachineApplicable;
-                        let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability);
+                        let find_arg = snippet_with_applicability(cx, search_arg.span, "..", &mut applicability);
                         span_lint_and_sugg(
                             cx,
                             SEARCH_IS_SOME,
diff --git a/src/tools/clippy/clippy_lints/src/methods/skip_while_next.rs b/src/tools/clippy/clippy_lints/src/methods/skip_while_next.rs
index 3db83785b59..9f0b6c34ea2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/skip_while_next.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/skip_while_next.rs
@@ -7,7 +7,7 @@ use rustc_span::sym;
 use super::SKIP_WHILE_NEXT;
 
 /// lint use of `skip_while().next()` for `Iterators`
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, _skip_while_args: &'tcx [hir::Expr<'_>]) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
     // lint if caller of `.skip_while().next()` is an Iterator
     if is_trait_method(cx, expr, sym::Iterator) {
         span_lint_and_help(
diff --git a/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs b/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
index 5c688ac5621..6e7890a3080 100644
--- a/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
@@ -10,12 +10,11 @@ use rustc_span::symbol::sym;
 
 use super::STRING_EXTEND_CHARS;
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
-    let obj_ty = cx.typeck_results().expr_ty(&args[0]).peel_refs();
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
+    let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
     if !is_type_diagnostic_item(cx, obj_ty, sym::string_type) {
         return;
     }
-    let arg = &args[1];
     if let Some(arglists) = method_chain_args(arg, &["chars"]) {
         let target = &arglists[0][0];
         let self_ty = cx.typeck_results().expr_ty(target).peel_refs();
@@ -36,7 +35,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Exp
             "try this",
             format!(
                 "{}.push_str({}{})",
-                snippet_with_applicability(cx, args[0].span, "..", &mut applicability),
+                snippet_with_applicability(cx, recv.span, "..", &mut applicability),
                 ref_str,
                 snippet_with_applicability(cx, target.span, "..", &mut applicability)
             ),
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
index 7015bd54c35..0fd0668c734 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
@@ -8,15 +8,8 @@ use rustc_span::sym;
 
 use super::SUSPICIOUS_MAP;
 
-pub fn check<'tcx>(
-    cx: &LateContext<'tcx>,
-    expr: &hir::Expr<'_>,
-    map_args: &[hir::Expr<'_>],
-    count_args: &[hir::Expr<'_>],
-) {
+pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, count_recv: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) {
     if_chain! {
-        if let [count_recv] = count_args;
-        if let [_, map_arg] = map_args;
         if is_trait_method(cx, count_recv, sym::Iterator);
         let closure = expr_or_init(cx, map_arg);
         if let Some(body_id) = cx.tcx.hir().maybe_body_owned_by(closure.hir_id);
diff --git a/src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs b/src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs
index f2f6ef4be6c..0ae65c0c01d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs
@@ -8,18 +8,18 @@ use rustc_middle::ty::{self, Ty};
 use super::UNINIT_ASSUMED_INIT;
 
 /// lint for `MaybeUninit::uninit().assume_init()` (we already have the latter)
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, outer: &hir::Expr<'_>) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
     if_chain! {
-        if let hir::ExprKind::Call(ref callee, ref args) = expr.kind;
+        if let hir::ExprKind::Call(callee, args) = recv.kind;
         if args.is_empty();
         if let hir::ExprKind::Path(ref path) = callee.kind;
         if match_qpath(path, &paths::MEM_MAYBEUNINIT_UNINIT);
-        if !is_maybe_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(outer));
+        if !is_maybe_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(expr));
         then {
             span_lint(
                 cx,
                 UNINIT_ASSUMED_INIT,
-                outer.span,
+                expr.span,
                 "this call for this type may be undefined behavior"
             );
         }
@@ -28,9 +28,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, outer: &hir::Exp
 
 fn is_maybe_uninit_ty_valid(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
     match ty.kind() {
-        ty::Array(ref component, _) => is_maybe_uninit_ty_valid(cx, component),
-        ty::Tuple(ref types) => types.types().all(|ty| is_maybe_uninit_ty_valid(cx, ty)),
-        ty::Adt(ref adt, _) => match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT),
+        ty::Array(component, _) => is_maybe_uninit_ty_valid(cx, component),
+        ty::Tuple(types) => types.types().all(|ty| is_maybe_uninit_ty_valid(cx, ty)),
+        ty::Adt(adt, _) => match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT),
         _ => false,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
index 48d905ab833..0f28bfdf09e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::usage::mutated_variables;
 use clippy_utils::{is_trait_method, match_qpath, path_to_local_id, paths};
-use if_chain::if_chain;
 use rustc_hir as hir;
 use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
 use rustc_lint::LateContext;
@@ -10,20 +9,20 @@ use rustc_span::sym;
 
 use super::UNNECESSARY_FILTER_MAP;
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
     if !is_trait_method(cx, expr, sym::Iterator) {
         return;
     }
 
-    if let hir::ExprKind::Closure(_, _, body_id, ..) = args[1].kind {
+    if let hir::ExprKind::Closure(_, _, body_id, ..) = arg.kind {
         let body = cx.tcx.hir().body(body_id);
         let arg_id = body.params[0].pat.hir_id;
         let mutates_arg =
             mutated_variables(&body.value, cx).map_or(true, |used_mutably| used_mutably.contains(&arg_id));
 
-        let (mut found_mapping, mut found_filtering) = check_expression(&cx, arg_id, &body.value);
+        let (mut found_mapping, mut found_filtering) = check_expression(cx, arg_id, &body.value);
 
-        let mut return_visitor = ReturnVisitor::new(&cx, arg_id);
+        let mut return_visitor = ReturnVisitor::new(cx, arg_id);
         return_visitor.visit_expr(&body.value);
         found_mapping |= return_visitor.found_mapping;
         found_filtering |= return_visitor.found_filtering;
@@ -53,38 +52,35 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Exp
 // returns (found_mapping, found_filtering)
 fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tcx hir::Expr<'_>) -> (bool, bool) {
     match &expr.kind {
-        hir::ExprKind::Call(ref func, ref args) => {
-            if_chain! {
-                if let hir::ExprKind::Path(ref path) = func.kind;
-                then {
-                    if match_qpath(path, &paths::OPTION_SOME) {
-                        if path_to_local_id(&args[0], arg_id) {
-                            return (false, false)
-                        }
-                        return (true, false);
+        hir::ExprKind::Call(func, args) => {
+            if let hir::ExprKind::Path(ref path) = func.kind {
+                if match_qpath(path, &paths::OPTION_SOME) {
+                    if path_to_local_id(&args[0], arg_id) {
+                        return (false, false);
                     }
-                    // We don't know. It might do anything.
-                    return (true, true);
+                    return (true, false);
                 }
+                // We don't know. It might do anything.
+                return (true, true);
             }
             (true, true)
         },
-        hir::ExprKind::Block(ref block, _) => block
+        hir::ExprKind::Block(block, _) => block
             .expr
             .as_ref()
-            .map_or((false, false), |expr| check_expression(cx, arg_id, &expr)),
+            .map_or((false, false), |expr| check_expression(cx, arg_id, expr)),
         hir::ExprKind::Match(_, arms, _) => {
             let mut found_mapping = false;
             let mut found_filtering = false;
             for arm in *arms {
-                let (m, f) = check_expression(cx, arg_id, &arm.body);
+                let (m, f) = check_expression(cx, arg_id, arm.body);
                 found_mapping |= m;
                 found_filtering |= f;
             }
             (found_mapping, found_filtering)
         },
         // There must be an else_arm or there will be a type error
-        hir::ExprKind::If(_, ref if_arm, Some(ref else_arm)) => {
+        hir::ExprKind::If(_, if_arm, Some(else_arm)) => {
             let if_check = check_expression(cx, arg_id, if_arm);
             let else_check = check_expression(cx, arg_id, else_arm);
             (if_check.0 | else_check.0, if_check.1 | else_check.1)
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
index 1268fd4bda9..75517c48a21 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
@@ -11,11 +11,17 @@ use rustc_span::{source_map::Span, sym};
 
 use super::UNNECESSARY_FOLD;
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: &[hir::Expr<'_>], fold_span: Span) {
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &hir::Expr<'_>,
+    init: &hir::Expr<'_>,
+    acc: &hir::Expr<'_>,
+    fold_span: Span,
+) {
     fn check_fold_with_op(
         cx: &LateContext<'_>,
         expr: &hir::Expr<'_>,
-        fold_args: &[hir::Expr<'_>],
+        acc: &hir::Expr<'_>,
         fold_span: Span,
         op: hir::BinOpKind,
         replacement_method_name: &str,
@@ -23,18 +29,18 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: &[hir
     ) {
         if_chain! {
             // Extract the body of the closure passed to fold
-            if let hir::ExprKind::Closure(_, _, body_id, _, _) = fold_args[2].kind;
+            if let hir::ExprKind::Closure(_, _, body_id, _, _) = acc.kind;
             let closure_body = cx.tcx.hir().body(body_id);
             let closure_expr = remove_blocks(&closure_body.value);
 
             // Check if the closure body is of the form `acc <op> some_expr(x)`
-            if let hir::ExprKind::Binary(ref bin_op, ref left_expr, ref right_expr) = closure_expr.kind;
+            if let hir::ExprKind::Binary(ref bin_op, left_expr, right_expr) = closure_expr.kind;
             if bin_op.node == op;
 
             // Extract the names of the two arguments to the closure
             if let [param_a, param_b] = closure_body.params;
-            if let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(&param_a.pat).kind;
-            if let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(&param_b.pat).kind;
+            if let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(param_a.pat).kind;
+            if let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(param_b.pat).kind;
 
             if path_to_local_id(left_expr, first_arg_id);
             if replacement_has_args || path_to_local_id(right_expr, second_arg_id);
@@ -74,25 +80,14 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: &[hir
         return;
     }
 
-    assert!(
-        fold_args.len() == 3,
-        "Expected fold_args to have three entries - the receiver, the initial value and the closure"
-    );
-
     // Check if the first argument to .fold is a suitable literal
-    if let hir::ExprKind::Lit(ref lit) = fold_args[1].kind {
+    if let hir::ExprKind::Lit(ref lit) = init.kind {
         match lit.node {
-            ast::LitKind::Bool(false) => {
-                check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Or, "any", true)
-            },
-            ast::LitKind::Bool(true) => {
-                check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::And, "all", true)
-            },
-            ast::LitKind::Int(0, _) => {
-                check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Add, "sum", false)
-            },
+            ast::LitKind::Bool(false) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, "any", true),
+            ast::LitKind::Bool(true) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, "all", true),
+            ast::LitKind::Int(0, _) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, "sum", false),
             ast::LitKind::Int(1, _) => {
-                check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Mul, "product", false)
+                check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, "product", false)
             },
             _ => (),
         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
index a86185bf0a6..b7380883a5e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
@@ -14,14 +14,15 @@ use super::UNNECESSARY_LAZY_EVALUATIONS;
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx hir::Expr<'_>,
-    args: &'tcx [hir::Expr<'_>],
+    recv: &'tcx hir::Expr<'_>,
+    arg: &'tcx hir::Expr<'_>,
     simplify_using: &str,
 ) {
-    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym::option_type);
-    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym::result_type);
+    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type);
+    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::result_type);
 
     if is_option || is_result {
-        if let hir::ExprKind::Closure(_, _, eid, _, _) = args[1].kind {
+        if let hir::ExprKind::Closure(_, _, eid, _, _) = arg.kind {
             let body = cx.tcx.hir().body(eid);
             let body_expr = &body.value;
 
@@ -55,7 +56,7 @@ pub(super) fn check<'tcx>(
                     &format!("use `{}` instead", simplify_using),
                     format!(
                         "{0}.{1}({2})",
-                        snippet(cx, args[0].span, ".."),
+                        snippet(cx, recv.span, ".."),
                         simplify_using,
                         snippet(cx, body_expr.span, ".."),
                     ),
diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
index 2f5806115bd..7fd1948594d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
@@ -7,8 +7,8 @@ use rustc_span::sym;
 use super::UNWRAP_USED;
 
 /// lint use of `unwrap()` for `Option`s and `Result`s
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::Expr<'_>]) {
-    let obj_ty = cx.typeck_results().expr_ty(&unwrap_args[0]).peel_refs();
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
+    let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
 
     let mess = if is_type_diagnostic_item(cx, obj_ty, sym::option_type) {
         Some((UNWRAP_USED, "an Option", "None"))
diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
index b5505af0f7e..e0b1de68b37 100644
--- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
@@ -10,12 +10,11 @@ use rustc_lint::LateContext;
 use super::USELESS_ASREF;
 
 /// Checks for the `USELESS_ASREF` lint.
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_ref_args: &[hir::Expr<'_>]) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, recvr: &hir::Expr<'_>) {
     // when we get here, we've already checked that the call name is "as_ref" or "as_mut"
     // check if the call is to the actual `AsRef` or `AsMut` trait
     if match_trait_method(cx, expr, &paths::ASREF_TRAIT) || match_trait_method(cx, expr, &paths::ASMUT_TRAIT) {
         // check if the type after `as_ref` or `as_mut` is the same as before
-        let recvr = &as_ref_args[0];
         let rcv_ty = cx.typeck_results().expr_ty(recvr);
         let res_ty = cx.typeck_results().expr_ty(expr);
         let (base_res_ty, res_depth) = walk_ptrs_ty_depth(res_ty);
diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs
index ac6b55396da..f6bf37e08b9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs
@@ -26,7 +26,7 @@ pub(super) fn derefs_to_slice<'tcx>(
         }
     }
 
-    if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind {
+    if let hir::ExprKind::MethodCall(path, _, args, _) = expr.kind {
         if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) {
             Some(&args[0])
         } else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
index 59e683aa9a7..1e0de249a91 100644
--- a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
@@ -21,8 +21,10 @@ const CONVENTIONS: [(&[Convention], &[SelfKind]); 9] = [
 
     // Conversion using `to_` can use borrowed (non-Copy types) or owned (Copy types).
     // Source: https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv
-    (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false), Convention::ImplementsTrait(false)], &[SelfKind::Ref]),
-    (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true), Convention::ImplementsTrait(false)], &[SelfKind::Value]),
+    (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false), 
+    Convention::IsTraitItem(false)], &[SelfKind::Ref]),
+    (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true), 
+    Convention::IsTraitItem(false), Convention::ImplementsTrait(false)], &[SelfKind::Value]),
 ];
 
 enum Convention {
@@ -32,18 +34,27 @@ enum Convention {
     NotEndsWith(&'static str),
     IsSelfTypeCopy(bool),
     ImplementsTrait(bool),
+    IsTraitItem(bool),
 }
 
 impl Convention {
     #[must_use]
-    fn check<'tcx>(&self, cx: &LateContext<'tcx>, self_ty: &'tcx TyS<'tcx>, other: &str, is_trait_def: bool) -> bool {
+    fn check<'tcx>(
+        &self,
+        cx: &LateContext<'tcx>,
+        self_ty: &'tcx TyS<'tcx>,
+        other: &str,
+        implements_trait: bool,
+        is_trait_item: bool,
+    ) -> bool {
         match *self {
             Self::Eq(this) => this == other,
             Self::StartsWith(this) => other.starts_with(this) && this != other,
             Self::EndsWith(this) => other.ends_with(this) && this != other,
-            Self::NotEndsWith(this) => !Self::EndsWith(this).check(cx, self_ty, other, is_trait_def),
+            Self::NotEndsWith(this) => !Self::EndsWith(this).check(cx, self_ty, other, implements_trait, is_trait_item),
             Self::IsSelfTypeCopy(is_true) => is_true == is_copy(cx, self_ty),
-            Self::ImplementsTrait(is_true) => is_true == is_trait_def,
+            Self::ImplementsTrait(is_true) => is_true == implements_trait,
+            Self::IsTraitItem(is_true) => is_true == is_trait_item,
         }
     }
 }
@@ -60,12 +71,17 @@ impl fmt::Display for Convention {
             },
             Self::ImplementsTrait(is_true) => {
                 let (negation, s_suffix) = if is_true { ("", "s") } else { (" does not", "") };
-                format!("Method{} implement{} a trait", negation, s_suffix).fmt(f)
+                format!("method{} implement{} a trait", negation, s_suffix).fmt(f)
+            },
+            Self::IsTraitItem(is_true) => {
+                let suffix = if is_true { " is" } else { " is not" };
+                format!("method{} a trait item", suffix).fmt(f)
             },
         }
     }
 }
 
+#[allow(clippy::too_many_arguments)]
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     item_name: &str,
@@ -73,6 +89,7 @@ pub(super) fn check<'tcx>(
     self_ty: &'tcx TyS<'tcx>,
     first_arg_ty: &'tcx TyS<'tcx>,
     first_arg_span: Span,
+    implements_trait: bool,
     is_trait_item: bool,
 ) {
     let lint = if is_pub {
@@ -83,7 +100,7 @@ pub(super) fn check<'tcx>(
     if let Some((conventions, self_kinds)) = &CONVENTIONS.iter().find(|(convs, _)| {
         convs
             .iter()
-            .all(|conv| conv.check(cx, self_ty, item_name, is_trait_item))
+            .all(|conv| conv.check(cx, self_ty, item_name, implements_trait, is_trait_item))
     }) {
         if !self_kinds.iter().any(|k| k.matches(cx, self_ty, first_arg_ty)) {
             let suggestion = {
@@ -99,6 +116,7 @@ pub(super) fn check<'tcx>(
                         .filter_map(|conv| {
                             if (cut_ends_with_conv && matches!(conv, Convention::NotEndsWith(_)))
                                 || matches!(conv, Convention::ImplementsTrait(_))
+                                || matches!(conv, Convention::IsTraitItem(_))
                             {
                                 None
                             } else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs b/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs
index 9f6a7c4db17..866cf616679 100644
--- a/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs
@@ -6,10 +6,9 @@ use rustc_middle::ty;
 
 use super::ZST_OFFSET;
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
     if_chain! {
-        if args.len() == 2;
-        if let ty::RawPtr(ty::TypeAndMut { ref ty, .. }) = cx.typeck_results().expr_ty(&args[0]).kind();
+        if let ty::RawPtr(ty::TypeAndMut { ty, .. }) = cx.typeck_results().expr_ty(recv).kind();
         if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty));
         if layout.is_zst();
         then {
diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs
index 776f4c7b741..45948f4d926 100644
--- a/src/tools/clippy/clippy_lints/src/minmax.rs
+++ b/src/tools/clippy/clippy_lints/src/minmax.rs
@@ -67,7 +67,7 @@ enum MinMax {
 
 fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Constant, &'a Expr<'a>)> {
     match expr.kind {
-        ExprKind::Call(ref path, ref args) => {
+        ExprKind::Call(path, args) => {
             if let ExprKind::Path(ref qpath) = path.kind {
                 cx.typeck_results()
                     .qpath_res(qpath, path.hir_id)
@@ -85,7 +85,7 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons
                 None
             }
         },
-        ExprKind::MethodCall(ref path, _, ref args, _) => {
+        ExprKind::MethodCall(path, _, args, _) => {
             if_chain! {
                 if let [obj, _] = args;
                 if cx.typeck_results().expr_ty(obj).is_floating_point() || match_trait_method(cx, expr, &paths::ORD);
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index 026ea50936a..afced5a5ce5 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -304,55 +304,54 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         if_chain! {
             if !in_external_macro(cx.tcx.sess, stmt.span);
-            if let StmtKind::Local(ref local) = stmt.kind;
+            if let StmtKind::Local(local) = stmt.kind;
             if let PatKind::Binding(an, .., name, None) = local.pat.kind;
-            if let Some(ref init) = local.init;
+            if let Some(init) = local.init;
             if !higher::is_from_for_desugar(local);
+            if an == BindingAnnotation::Ref || an == BindingAnnotation::RefMut;
             then {
-                if an == BindingAnnotation::Ref || an == BindingAnnotation::RefMut {
-                    // use the macro callsite when the init span (but not the whole local span)
-                    // comes from an expansion like `vec![1, 2, 3]` in `let ref _ = vec![1, 2, 3];`
-                    let sugg_init = if init.span.from_expansion() && !local.span.from_expansion() {
-                        Sugg::hir_with_macro_callsite(cx, init, "..")
-                    } else {
-                        Sugg::hir(cx, init, "..")
-                    };
-                    let (mutopt, initref) = if an == BindingAnnotation::RefMut {
-                        ("mut ", sugg_init.mut_addr())
-                    } else {
-                        ("", sugg_init.addr())
-                    };
-                    let tyopt = if let Some(ref ty) = local.ty {
-                        format!(": &{mutopt}{ty}", mutopt=mutopt, ty=snippet(cx, ty.span, ".."))
-                    } else {
-                        String::new()
-                    };
-                    span_lint_hir_and_then(
-                        cx,
-                        TOPLEVEL_REF_ARG,
-                        init.hir_id,
-                        local.pat.span,
-                        "`ref` on an entire `let` pattern is discouraged, take a reference with `&` instead",
-                        |diag| {
-                            diag.span_suggestion(
-                                stmt.span,
-                                "try",
-                                format!(
-                                    "let {name}{tyopt} = {initref};",
-                                    name=snippet(cx, name.span, ".."),
-                                    tyopt=tyopt,
-                                    initref=initref,
-                                ),
-                                Applicability::MachineApplicable,
-                            );
-                        }
-                    );
-                }
+                // use the macro callsite when the init span (but not the whole local span)
+                // comes from an expansion like `vec![1, 2, 3]` in `let ref _ = vec![1, 2, 3];`
+                let sugg_init = if init.span.from_expansion() && !local.span.from_expansion() {
+                    Sugg::hir_with_macro_callsite(cx, init, "..")
+                } else {
+                    Sugg::hir(cx, init, "..")
+                };
+                let (mutopt, initref) = if an == BindingAnnotation::RefMut {
+                    ("mut ", sugg_init.mut_addr())
+                } else {
+                    ("", sugg_init.addr())
+                };
+                let tyopt = if let Some(ty) = local.ty {
+                    format!(": &{mutopt}{ty}", mutopt=mutopt, ty=snippet(cx, ty.span, ".."))
+                } else {
+                    String::new()
+                };
+                span_lint_hir_and_then(
+                    cx,
+                    TOPLEVEL_REF_ARG,
+                    init.hir_id,
+                    local.pat.span,
+                    "`ref` on an entire `let` pattern is discouraged, take a reference with `&` instead",
+                    |diag| {
+                        diag.span_suggestion(
+                            stmt.span,
+                            "try",
+                            format!(
+                                "let {name}{tyopt} = {initref};",
+                                name=snippet(cx, name.span, ".."),
+                                tyopt=tyopt,
+                                initref=initref,
+                            ),
+                            Applicability::MachineApplicable,
+                        );
+                    }
+                );
             }
         };
         if_chain! {
-            if let StmtKind::Semi(ref expr) = stmt.kind;
-            if let ExprKind::Binary(ref binop, ref a, ref b) = expr.kind;
+            if let StmtKind::Semi(expr) = stmt.kind;
+            if let ExprKind::Binary(ref binop, a, b) = expr.kind;
             if binop.node == BinOpKind::And || binop.node == BinOpKind::Or;
             if let Some(sugg) = Sugg::hir_opt(cx, a);
             then {
@@ -379,11 +378,11 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         match expr.kind {
-            ExprKind::Cast(ref e, ref ty) => {
+            ExprKind::Cast(e, ty) => {
                 check_cast(cx, expr.span, e, ty);
                 return;
             },
-            ExprKind::Binary(ref cmp, ref left, ref right) => {
+            ExprKind::Binary(ref cmp, left, right) => {
                 check_binary(cx, expr, cmp, left, right);
                 return;
             },
@@ -462,21 +461,18 @@ fn check_nan(cx: &LateContext<'_>, expr: &Expr<'_>, cmp_expr: &Expr<'_>) {
     if_chain! {
         if !in_constant(cx, cmp_expr.hir_id);
         if let Some((value, _)) = constant(cx, cx.typeck_results(), expr);
+        if match value {
+            Constant::F32(num) => num.is_nan(),
+            Constant::F64(num) => num.is_nan(),
+            _ => false,
+        };
         then {
-            let needs_lint = match value {
-                Constant::F32(num) => num.is_nan(),
-                Constant::F64(num) => num.is_nan(),
-                _ => false,
-            };
-
-            if needs_lint {
-                span_lint(
-                    cx,
-                    CMP_NAN,
-                    cmp_expr.span,
-                    "doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead",
-                );
-            }
+            span_lint(
+                cx,
+                CMP_NAN,
+                cmp_expr.span,
+                "doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead",
+            );
         }
     }
 }
@@ -505,12 +501,12 @@ fn is_allowed<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
 // Return true if `expr` is the result of `signum()` invoked on a float value.
 fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     // The negation of a signum is still a signum
-    if let ExprKind::Unary(UnOp::Neg, ref child_expr) = expr.kind {
-        return is_signum(cx, &child_expr);
+    if let ExprKind::Unary(UnOp::Neg, child_expr) = expr.kind {
+        return is_signum(cx, child_expr);
     }
 
     if_chain! {
-        if let ExprKind::MethodCall(ref method_name, _, ref expressions, _) = expr.kind;
+        if let ExprKind::MethodCall(method_name, _, expressions, _) = expr.kind;
         if sym!(signum) == method_name.ident.name;
         // Check that the receiver of the signum() is a float (expressions[0] is the receiver of
         // the method call)
@@ -556,7 +552,7 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left:
     }
 
     let (arg_ty, snip) = match expr.kind {
-        ExprKind::MethodCall(.., ref args, _) if args.len() == 1 => {
+        ExprKind::MethodCall(.., args, _) if args.len() == 1 => {
             if_chain!(
                 if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
                 if is_diagnostic_assoc_item(cx, expr_def_id, sym::ToString)
@@ -568,7 +564,7 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left:
                 }
             )
         },
-        ExprKind::Call(ref path, ref v) if v.len() == 1 => {
+        ExprKind::Call(path, v) if v.len() == 1 => {
             if let ExprKind::Path(ref path) = path.kind {
                 if match_qpath(path, &["String", "from_str"]) || match_qpath(path, &["String", "from"]) {
                     (cx.typeck_results().expr_ty(&v[0]), snippet(cx, v[0].span, ".."))
@@ -653,7 +649,7 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left:
 /// of what it means for an expression to be "used".
 fn is_used(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     get_parent_expr(cx, expr).map_or(true, |parent| match parent.kind {
-        ExprKind::Assign(_, ref rhs, _) | ExprKind::AssignOp(_, _, ref rhs) => SpanlessEq::new(cx).eq_expr(rhs, expr),
+        ExprKind::Assign(_, rhs, _) | ExprKind::AssignOp(_, _, rhs) => SpanlessEq::new(cx).eq_expr(rhs, expr),
         _ => is_used(cx, parent),
     })
 }
diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
index 23554669d97..0dc02431ad5 100644
--- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
@@ -138,7 +138,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
 
         let mir = cx.tcx.optimized_mir(def_id);
 
-        if let Err((span, err)) = is_min_const_fn(cx.tcx, &mir) {
+        if let Err((span, err)) = is_min_const_fn(cx.tcx, mir) {
             if rustc_mir::const_eval::is_min_const_fn(cx.tcx, def_id.to_def_id()) {
                 cx.tcx.sess.span_err(span, &err);
             }
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 21b4983a1af..dfab3e8a931 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -5,10 +5,10 @@
 // [`missing_doc`]: https://github.com/rust-lang/rust/blob/cf9cf7c923eb01146971429044f216a3ca905e06/compiler/rustc_lint/src/builtin.rs#L415
 //
 
+use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::span_lint;
 use if_chain::if_chain;
 use rustc_ast::ast::{self, MetaItem, MetaItemKind};
-use rustc_ast::attr;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty;
@@ -93,9 +93,9 @@ impl MissingDoc {
             return;
         }
 
-        let has_doc = attrs
-            .iter()
-            .any(|a| a.is_doc_comment() || a.doc_str().is_some() || a.value_str().is_some() || Self::has_include(a.meta()));
+        let has_doc = attrs.iter().any(|a| {
+            a.is_doc_comment() || a.doc_str().is_some() || a.value_str().is_some() || Self::has_include(a.meta())
+        });
         if !has_doc {
             span_lint(
                 cx,
@@ -111,14 +111,7 @@ impl_lint_pass!(MissingDoc => [MISSING_DOCS_IN_PRIVATE_ITEMS]);
 
 impl<'tcx> LateLintPass<'tcx> for MissingDoc {
     fn enter_lint_attrs(&mut self, _: &LateContext<'tcx>, attrs: &'tcx [ast::Attribute]) {
-        let doc_hidden = self.doc_hidden()
-            || attrs.iter().any(|attr| {
-                attr.has_name(sym::doc)
-                    && match attr.meta_item_list() {
-                        None => false,
-                        Some(l) => attr::list_contains_name(&l[..], sym::hidden),
-                    }
-            });
+        let doc_hidden = self.doc_hidden() || is_doc_hidden(attrs);
         self.doc_hidden_stack.push(doc_hidden);
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index dd4488f3f02..041fe64a1a9 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
                 let attrs = cx.tcx.hir().attrs(it.hir_id());
                 check_missing_inline_attrs(cx, attrs, it.span, desc);
             },
-            hir::ItemKind::Trait(ref _is_auto, ref _unsafe, ref _generics, ref _bounds, trait_items) => {
+            hir::ItemKind::Trait(ref _is_auto, ref _unsafe, ref _generics, _bounds, trait_items) => {
                 // note: we need to check if the trait is exported so we can't use
                 // `LateLintPass::check_trait_item` here.
                 for tit in trait_items {
diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs
index 4d3dff36a20..1786d5805d7 100644
--- a/src/tools/clippy/clippy_lints/src/mut_key.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_key.rs
@@ -59,21 +59,21 @@ declare_lint_pass!(MutableKeyType => [ MUTABLE_KEY_TYPE ]);
 impl<'tcx> LateLintPass<'tcx> for MutableKeyType {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
         if let hir::ItemKind::Fn(ref sig, ..) = item.kind {
-            check_sig(cx, item.hir_id(), &sig.decl);
+            check_sig(cx, item.hir_id(), sig.decl);
         }
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'tcx>) {
         if let hir::ImplItemKind::Fn(ref sig, ..) = item.kind {
             if trait_ref_of_method(cx, item.hir_id()).is_none() {
-                check_sig(cx, item.hir_id(), &sig.decl);
+                check_sig(cx, item.hir_id(), sig.decl);
             }
         }
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'tcx>) {
         if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind {
-            check_sig(cx, item.hir_id(), &sig.decl);
+            check_sig(cx, item.hir_id(), sig.decl);
         }
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/mut_mut.rs b/src/tools/clippy/clippy_lints/src/mut_mut.rs
index ef33e41a5fa..4b9c51d0c16 100644
--- a/src/tools/clippy/clippy_lints/src/mut_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_mut.rs
@@ -62,7 +62,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> {
             // Let's ignore the generated code.
             intravisit::walk_expr(self, arg);
             intravisit::walk_expr(self, body);
-        } else if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, ref e) = expr.kind {
+        } else if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, e) = expr.kind {
             if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, _) = e.kind {
                 span_lint(
                     self.cx,
@@ -85,7 +85,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> {
         if let hir::TyKind::Rptr(
             _,
             hir::MutTy {
-                ty: ref pty,
+                ty: pty,
                 mutbl: hir::Mutability::Mut,
             },
         ) = ty.kind
diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs
index 05457e80d52..cea6fce1195 100644
--- a/src/tools/clippy/clippy_lints/src/mut_reference.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs
@@ -33,7 +33,7 @@ declare_lint_pass!(UnnecessaryMutPassed => [UNNECESSARY_MUT_PASSED]);
 impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         match e.kind {
-            ExprKind::Call(ref fn_expr, ref arguments) => {
+            ExprKind::Call(fn_expr, arguments) => {
                 if let ExprKind::Path(ref path) = fn_expr.kind {
                     check_arguments(
                         cx,
@@ -44,7 +44,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
                     );
                 }
             },
-            ExprKind::MethodCall(ref path, _, ref arguments, _) => {
+            ExprKind::MethodCall(path, _, arguments, _) => {
                 let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap();
                 let substs = cx.typeck_results().node_substs(e.hir_id);
                 let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs
index db7b3423ad9..96a58d1410f 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs
@@ -71,7 +71,7 @@ declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL]);
 impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         use self::Expression::{Bool, RetBool};
-        if let ExprKind::If(ref pred, ref then_block, Some(ref else_expr)) = e.kind {
+        if let ExprKind::If(pred, then_block, Some(else_expr)) = e.kind {
             let reduce = |ret, not| {
                 let mut applicability = Applicability::MachineApplicable;
                 let snip = Sugg::hir_with_applicability(cx, pred, "<predicate>", &mut applicability);
@@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
                     snip = snip.make_return();
                 }
 
-                if parent_node_is_if_expr(&e, &cx) {
+                if parent_node_is_if_expr(e, cx) {
                     snip = snip.blockify()
                 }
 
@@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
                     applicability,
                 );
             };
-            if let ExprKind::Block(ref then_block, _) = then_block.kind {
+            if let ExprKind::Block(then_block, _) = then_block.kind {
                 match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) {
                     (RetBool(true), RetBool(true)) | (Bool(true), Bool(true)) => {
                         span_lint(
@@ -225,7 +225,7 @@ fn check_comparison<'a, 'tcx>(
 ) {
     use self::Expression::{Bool, Other};
 
-    if let ExprKind::Binary(op, ref left_side, ref right_side) = e.kind {
+    if let ExprKind::Binary(op, left_side, right_side) = e.kind {
         let (l_ty, r_ty) = (
             cx.typeck_results().expr_ty(left_side),
             cx.typeck_results().expr_ty(right_side),
@@ -237,7 +237,7 @@ fn check_comparison<'a, 'tcx>(
             let mut applicability = Applicability::MachineApplicable;
 
             if let BinOpKind::Eq = op.node {
-                let expression_info = one_side_is_unary_not(&left_side, &right_side);
+                let expression_info = one_side_is_unary_not(left_side, right_side);
                 if expression_info.one_side_is_unary_not {
                     span_lint_and_sugg(
                         cx,
@@ -324,9 +324,9 @@ fn fetch_bool_block(block: &Block<'_>) -> Expression {
     match (&*block.stmts, block.expr.as_ref()) {
         (&[], Some(e)) => fetch_bool_expr(&**e),
         (&[ref e], None) => {
-            if let StmtKind::Semi(ref e) = e.kind {
+            if let StmtKind::Semi(e) = e.kind {
                 if let ExprKind::Ret(_) = e.kind {
-                    fetch_bool_expr(&**e)
+                    fetch_bool_expr(e)
                 } else {
                     Expression::Other
                 }
@@ -340,7 +340,7 @@ fn fetch_bool_block(block: &Block<'_>) -> Expression {
 
 fn fetch_bool_expr(expr: &Expr<'_>) -> Expression {
     match expr.kind {
-        ExprKind::Block(ref block, _) => fetch_bool_block(block),
+        ExprKind::Block(block, _) => fetch_bool_block(block),
         ExprKind::Lit(ref lit_ptr) => {
             if let LitKind::Bool(value) = lit_ptr.node {
                 Expression::Bool(value)
@@ -348,7 +348,7 @@ fn fetch_bool_expr(expr: &Expr<'_>) -> Expression {
                 Expression::Other
             }
         },
-        ExprKind::Ret(Some(ref expr)) => match fetch_bool_expr(expr) {
+        ExprKind::Ret(Some(expr)) => match fetch_bool_expr(expr) {
             Expression::Bool(value) => Expression::RetBool(value),
             _ => Expression::Other,
         },
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrow.rs b/src/tools/clippy/clippy_lints/src/needless_borrow.rs
index 79d84da2dfc..eef3c16730b 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrow.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrow.rs
@@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
         if e.span.from_expansion() || self.derived_item.is_some() {
             return;
         }
-        if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, ref inner) = e.kind {
+        if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = e.kind {
             if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(inner).kind() {
                 for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) {
                     if let [Adjustment {
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
index 7fbffe04a3f..0e976b130eb 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
@@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef {
 
         if_chain! {
             // Only lint immutable refs, because `&mut ref T` may be useful.
-            if let PatKind::Ref(ref sub_pat, Mutability::Not) = pat.kind;
+            if let PatKind::Ref(sub_pat, Mutability::Not) = pat.kind;
 
             // Check sub_pat got a `ref` keyword (excluding `ref mut`).
             if let PatKind::Binding(BindingAnnotation::Ref, .., spanned_name, _) = sub_pat.kind;
diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
new file mode 100644
index 00000000000..079b6642d58
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
@@ -0,0 +1,167 @@
+use rustc_errors::Applicability;
+use rustc_hir::{
+    intravisit::{walk_expr, NestedVisitorMap, Visitor},
+    Expr, ExprKind, Stmt, StmtKind,
+};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::map::Map;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{source_map::Span, sym, Symbol};
+
+use if_chain::if_chain;
+
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_trait_method;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::ty::has_iter_method;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `for_each` that would be more simply written as a
+    /// `for` loop.
+    ///
+    /// **Why is this bad?** `for_each` may be used after applying iterator transformers like
+    /// `filter` for better readability and performance. It may also be used to fit a simple
+    /// operation on one line.
+    /// But when none of these apply, a simple `for` loop is more idiomatic.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let v = vec![0, 1, 2];
+    /// v.iter().for_each(|elem| {
+    ///     println!("{}", elem);
+    /// })
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let v = vec![0, 1, 2];
+    /// for elem in v.iter() {
+    ///     println!("{}", elem);
+    /// }
+    /// ```
+    pub NEEDLESS_FOR_EACH,
+    pedantic,
+    "using `for_each` where a `for` loop would be simpler"
+}
+
+declare_lint_pass!(NeedlessForEach => [NEEDLESS_FOR_EACH]);
+
+impl LateLintPass<'_> for NeedlessForEach {
+    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+        let expr = match stmt.kind {
+            StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr,
+            _ => return,
+        };
+
+        if_chain! {
+            // Check the method name is `for_each`.
+            if let ExprKind::MethodCall(method_name, _, [for_each_recv, for_each_arg], _) = expr.kind;
+            if method_name.ident.name == Symbol::intern("for_each");
+            // Check `for_each` is an associated function of `Iterator`.
+            if is_trait_method(cx, expr, sym::Iterator);
+            // Checks the receiver of `for_each` is also a method call.
+            if let ExprKind::MethodCall(_, _, [iter_recv], _) = for_each_recv.kind;
+            // Skip the lint if the call chain is too long. e.g. `v.field.iter().for_each()` or
+            // `v.foo().iter().for_each()` must be skipped.
+            if matches!(
+                iter_recv.kind,
+                ExprKind::Array(..) | ExprKind::Call(..) | ExprKind::Path(..)
+            );
+            // Checks the type of the `iter` method receiver is NOT a user defined type.
+            if has_iter_method(cx, cx.typeck_results().expr_ty(iter_recv)).is_some();
+            // Skip the lint if the body is not block because this is simpler than `for` loop.
+            // e.g. `v.iter().for_each(f)` is simpler and clearer than using `for` loop.
+            if let ExprKind::Closure(_, _, body_id, ..) = for_each_arg.kind;
+            let body = cx.tcx.hir().body(body_id);
+            if let ExprKind::Block(..) = body.value.kind;
+            then {
+                let mut ret_collector = RetCollector::default();
+                ret_collector.visit_expr(&body.value);
+
+                // Skip the lint if `return` is used in `Loop` in order not to suggest using `'label`.
+                if ret_collector.ret_in_loop {
+                    return;
+                }
+
+                let (mut applicability, ret_suggs) = if ret_collector.spans.is_empty() {
+                    (Applicability::MachineApplicable, None)
+                } else {
+                    (
+                        Applicability::MaybeIncorrect,
+                        Some(
+                            ret_collector
+                                .spans
+                                .into_iter()
+                                .map(|span| (span, "continue".to_string()))
+                                .collect(),
+                        ),
+                    )
+                };
+
+                let sugg = format!(
+                    "for {} in {} {}",
+                    snippet_with_applicability(cx, body.params[0].pat.span, "..", &mut applicability),
+                    snippet_with_applicability(cx, for_each_recv.span, "..", &mut applicability),
+                    snippet_with_applicability(cx, body.value.span, "..", &mut applicability),
+                );
+
+                span_lint_and_then(cx, NEEDLESS_FOR_EACH, stmt.span, "needless use of `for_each`", |diag| {
+                    diag.span_suggestion(stmt.span, "try", sugg, applicability);
+                    if let Some(ret_suggs) = ret_suggs {
+                        diag.multipart_suggestion("...and replace `return` with `continue`", ret_suggs, applicability);
+                    }
+                })
+            }
+        }
+    }
+}
+
+/// This type plays two roles.
+/// 1. Collect spans of `return` in the closure body.
+/// 2. Detect use of `return` in `Loop` in the closure body.
+///
+/// NOTE: The functionality of this type is similar to
+/// [`crate::utilts::visitors::find_all_ret_expressions`], but we can't use
+/// `find_all_ret_expressions` instead of this type. The reasons are:
+/// 1. `find_all_ret_expressions` passes the argument of `ExprKind::Ret` to a callback, but what we
+///    need here is `ExprKind::Ret` itself.
+/// 2. We can't trace current loop depth with `find_all_ret_expressions`.
+#[derive(Default)]
+struct RetCollector {
+    spans: Vec<Span>,
+    ret_in_loop: bool,
+    loop_depth: u16,
+}
+
+impl<'tcx> Visitor<'tcx> for RetCollector {
+    type Map = Map<'tcx>;
+
+    fn visit_expr(&mut self, expr: &Expr<'_>) {
+        match expr.kind {
+            ExprKind::Ret(..) => {
+                if self.loop_depth > 0 && !self.ret_in_loop {
+                    self.ret_in_loop = true
+                }
+
+                self.spans.push(expr.span)
+            },
+
+            ExprKind::Loop(..) => {
+                self.loop_depth += 1;
+                walk_expr(self, expr);
+                self.loop_depth -= 1;
+                return;
+            },
+
+            _ => {},
+        }
+
+        walk_expr(self, expr);
+    }
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::None
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index e70c248e87b..780e2241293 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -5,10 +5,11 @@ use clippy_utils::ty::{implements_trait, is_copy, is_type_diagnostic_item};
 use clippy_utils::{get_trait_def_id, is_self, paths};
 use if_chain::if_chain;
 use rustc_ast::ast::Attribute;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Node, PatKind, QPath, TyKind};
+use rustc_hir::{HirIdMap, HirIdSet};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::FakeReadCause;
@@ -207,7 +208,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                             if is_type_diagnostic_item(cx, ty, sym::vec_type);
                             if let Some(clone_spans) =
                                 get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")]);
-                            if let TyKind::Path(QPath::Resolved(_, ref path)) = input.kind;
+                            if let TyKind::Path(QPath::Resolved(_, path)) = input.kind;
                             if let Some(elem_ty) = path.segments.iter()
                                 .find(|seg| seg.ident.name == sym::Vec)
                                 .and_then(|ps| ps.args.as_ref())
@@ -310,10 +311,10 @@ fn requires_exact_signature(attrs: &[Attribute]) -> bool {
 
 #[derive(Default)]
 struct MovedVariablesCtxt {
-    moved_vars: FxHashSet<HirId>,
+    moved_vars: HirIdSet,
     /// Spans which need to be prefixed with `*` for dereferencing the
     /// suggested additional reference.
-    spans_need_deref: FxHashMap<HirId, FxHashSet<Span>>,
+    spans_need_deref: HirIdMap<FxHashSet<Span>>,
 }
 
 impl MovedVariablesCtxt {
diff --git a/src/tools/clippy/clippy_lints/src/needless_update.rs b/src/tools/clippy/clippy_lints/src/needless_update.rs
index e93de8a252a..8f325404deb 100644
--- a/src/tools/clippy/clippy_lints/src/needless_update.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_update.rs
@@ -49,7 +49,7 @@ declare_lint_pass!(NeedlessUpdate => [NEEDLESS_UPDATE]);
 
 impl<'tcx> LateLintPass<'tcx> for NeedlessUpdate {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let ExprKind::Struct(_, ref fields, Some(ref base)) = expr.kind {
+        if let ExprKind::Struct(_, fields, Some(base)) = expr.kind {
             let ty = cx.typeck_results().expr_ty(expr);
             if let ty::Adt(def, _) = ty.kind() {
                 if fields.len() == def.non_enum_variant().fields.len()
diff --git a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
index 4b935c7b906..0704173a011 100644
--- a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
@@ -51,8 +51,8 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd {
         if_chain! {
 
             if !in_external_macro(cx.sess(), expr.span);
-            if let ExprKind::Unary(UnOp::Not, ref inner) = expr.kind;
-            if let ExprKind::Binary(ref op, ref left, _) = inner.kind;
+            if let ExprKind::Unary(UnOp::Not, inner) = expr.kind;
+            if let ExprKind::Binary(ref op, left, _) = inner.kind;
             if let BinOpKind::Le | BinOpKind::Ge | BinOpKind::Lt | BinOpKind::Gt = op.node;
 
             then {
diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
index 7b00879251f..34fd012572f 100644
--- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
@@ -28,12 +28,12 @@ declare_lint_pass!(NegMultiply => [NEG_MULTIPLY]);
 #[allow(clippy::match_same_arms)]
 impl<'tcx> LateLintPass<'tcx> for NegMultiply {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        if let ExprKind::Binary(ref op, ref left, ref right) = e.kind {
+        if let ExprKind::Binary(ref op, left, right) = e.kind {
             if BinOpKind::Mul == op.node {
                 match (&left.kind, &right.kind) {
                     (&ExprKind::Unary(..), &ExprKind::Unary(..)) => {},
-                    (&ExprKind::Unary(UnOp::Neg, ref lit), _) => check_mul(cx, e.span, lit, right),
-                    (_, &ExprKind::Unary(UnOp::Neg, ref lit)) => check_mul(cx, e.span, lit, left),
+                    (&ExprKind::Unary(UnOp::Neg, lit), _) => check_mul(cx, e.span, lit, right),
+                    (_, &ExprKind::Unary(UnOp::Neg, lit)) => check_mul(cx, e.span, lit, left),
                     _ => {},
                 }
             }
diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs
index 3789572ad43..a5f91eb035f 100644
--- a/src/tools/clippy/clippy_lints/src/new_without_default.rs
+++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs
@@ -97,60 +97,60 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
                             // impl of `Default`
                             return;
                         }
-                        if sig.decl.inputs.is_empty() && name == sym::new && cx.access_levels.is_reachable(id) {
+                        if_chain! {
+                            if sig.decl.inputs.is_empty();
+                            if name == sym::new;
+                            if cx.access_levels.is_reachable(id);
                             let self_def_id = cx.tcx.hir().local_def_id(cx.tcx.hir().get_parent_item(id));
                             let self_ty = cx.tcx.type_of(self_def_id);
-                            if_chain! {
-                                if TyS::same_type(self_ty, return_ty(cx, id));
-                                if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
-                                then {
-                                    if self.impling_types.is_none() {
-                                        let mut impls = HirIdSet::default();
-                                        cx.tcx.for_each_impl(default_trait_id, |d| {
-                                            if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() {
-                                                if let Some(local_def_id) = ty_def.did.as_local() {
-                                                    impls.insert(cx.tcx.hir().local_def_id_to_hir_id(local_def_id));
-                                                }
-                                            }
-                                        });
-                                        self.impling_types = Some(impls);
-                                    }
-
-                                    // Check if a Default implementation exists for the Self type, regardless of
-                                    // generics
-                                    if_chain! {
-                                        if let Some(ref impling_types) = self.impling_types;
-                                        if let Some(self_def) = cx.tcx.type_of(self_def_id).ty_adt_def();
-                                        if let Some(self_local_did) = self_def.did.as_local();
-                                        then {
-                                            let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did);
-                                            if impling_types.contains(&self_id) {
-                                                return;
+                            if TyS::same_type(self_ty, return_ty(cx, id));
+                            if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
+                            then {
+                                if self.impling_types.is_none() {
+                                    let mut impls = HirIdSet::default();
+                                    cx.tcx.for_each_impl(default_trait_id, |d| {
+                                        if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() {
+                                            if let Some(local_def_id) = ty_def.did.as_local() {
+                                                impls.insert(cx.tcx.hir().local_def_id_to_hir_id(local_def_id));
                                             }
                                         }
-                                    }
+                                    });
+                                    self.impling_types = Some(impls);
+                                }
 
-                                    let generics_sugg = snippet(cx, generics.span, "");
-                                    span_lint_hir_and_then(
-                                        cx,
-                                        NEW_WITHOUT_DEFAULT,
-                                        id,
-                                        impl_item.span,
-                                        &format!(
-                                            "you should consider adding a `Default` implementation for `{}`",
-                                            self_ty
-                                        ),
-                                        |diag| {
-                                            diag.suggest_prepend_item(
-                                                cx,
-                                                item.span,
-                                                "try this",
-                                                &create_new_without_default_suggest_msg(self_ty, &generics_sugg),
-                                                Applicability::MaybeIncorrect,
-                                            );
-                                        },
-                                    );
+                                // Check if a Default implementation exists for the Self type, regardless of
+                                // generics
+                                if_chain! {
+                                    if let Some(ref impling_types) = self.impling_types;
+                                    if let Some(self_def) = cx.tcx.type_of(self_def_id).ty_adt_def();
+                                    if let Some(self_local_did) = self_def.did.as_local();
+                                    let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did);
+                                    if impling_types.contains(&self_id);
+                                    then {
+                                        return;
+                                    }
                                 }
+
+                                let generics_sugg = snippet(cx, generics.span, "");
+                                span_lint_hir_and_then(
+                                    cx,
+                                    NEW_WITHOUT_DEFAULT,
+                                    id,
+                                    impl_item.span,
+                                    &format!(
+                                        "you should consider adding a `Default` implementation for `{}`",
+                                        self_ty
+                                    ),
+                                    |diag| {
+                                        diag.suggest_prepend_item(
+                                            cx,
+                                            item.span,
+                                            "try this",
+                                            &create_new_without_default_suggest_msg(self_ty, &generics_sugg),
+                                            Applicability::MaybeIncorrect,
+                                        );
+                                    },
+                                );
                             }
                         }
                     }
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 83953a16bc8..cfcaf509471 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -51,23 +51,21 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     match expr.kind {
         ExprKind::Lit(..) | ExprKind::Closure(..) => true,
         ExprKind::Path(..) => !has_drop(cx, cx.typeck_results().expr_ty(expr)),
-        ExprKind::Index(ref a, ref b) | ExprKind::Binary(_, ref a, ref b) => {
-            has_no_effect(cx, a) && has_no_effect(cx, b)
-        },
-        ExprKind::Array(ref v) | ExprKind::Tup(ref v) => v.iter().all(|val| has_no_effect(cx, val)),
-        ExprKind::Repeat(ref inner, _)
-        | ExprKind::Cast(ref inner, _)
-        | ExprKind::Type(ref inner, _)
-        | ExprKind::Unary(_, ref inner)
-        | ExprKind::Field(ref inner, _)
-        | ExprKind::AddrOf(_, _, ref inner)
-        | ExprKind::Box(ref inner) => has_no_effect(cx, inner),
-        ExprKind::Struct(_, ref fields, ref base) => {
+        ExprKind::Index(a, b) | ExprKind::Binary(_, a, b) => has_no_effect(cx, a) && has_no_effect(cx, b),
+        ExprKind::Array(v) | ExprKind::Tup(v) => v.iter().all(|val| has_no_effect(cx, val)),
+        ExprKind::Repeat(inner, _)
+        | ExprKind::Cast(inner, _)
+        | ExprKind::Type(inner, _)
+        | ExprKind::Unary(_, inner)
+        | ExprKind::Field(inner, _)
+        | ExprKind::AddrOf(_, _, inner)
+        | ExprKind::Box(inner) => has_no_effect(cx, inner),
+        ExprKind::Struct(_, fields, ref base) => {
             !has_drop(cx, cx.typeck_results().expr_ty(expr))
-                && fields.iter().all(|field| has_no_effect(cx, &field.expr))
+                && fields.iter().all(|field| has_no_effect(cx, field.expr))
                 && base.as_ref().map_or(true, |base| has_no_effect(cx, base))
         },
-        ExprKind::Call(ref callee, ref args) => {
+        ExprKind::Call(callee, args) => {
             if let ExprKind::Path(ref qpath) = callee.kind {
                 let res = cx.qpath_res(qpath, callee.hir_id);
                 match res {
@@ -81,7 +79,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
                 false
             }
         },
-        ExprKind::Block(ref block, _) => {
+        ExprKind::Block(block, _) => {
             block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| has_no_effect(cx, expr))
         },
         _ => false,
@@ -92,7 +90,7 @@ declare_lint_pass!(NoEffect => [NO_EFFECT, UNNECESSARY_OPERATION]);
 
 impl<'tcx> LateLintPass<'tcx> for NoEffect {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
-        if let StmtKind::Semi(ref expr) = stmt.kind {
+        if let StmtKind::Semi(expr) = stmt.kind {
             if has_no_effect(cx, expr) {
                 span_lint(cx, NO_EFFECT, stmt.span, "statement with no effect");
             } else if let Some(reduced) = reduce_expression(cx, expr) {
@@ -127,26 +125,26 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Vec
         return None;
     }
     match expr.kind {
-        ExprKind::Index(ref a, ref b) => Some(vec![&**a, &**b]),
-        ExprKind::Binary(ref binop, ref a, ref b) if binop.node != BinOpKind::And && binop.node != BinOpKind::Or => {
-            Some(vec![&**a, &**b])
+        ExprKind::Index(a, b) => Some(vec![a, b]),
+        ExprKind::Binary(ref binop, a, b) if binop.node != BinOpKind::And && binop.node != BinOpKind::Or => {
+            Some(vec![a, b])
         },
-        ExprKind::Array(ref v) | ExprKind::Tup(ref v) => Some(v.iter().collect()),
-        ExprKind::Repeat(ref inner, _)
-        | ExprKind::Cast(ref inner, _)
-        | ExprKind::Type(ref inner, _)
-        | ExprKind::Unary(_, ref inner)
-        | ExprKind::Field(ref inner, _)
-        | ExprKind::AddrOf(_, _, ref inner)
-        | ExprKind::Box(ref inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])),
-        ExprKind::Struct(_, ref fields, ref base) => {
+        ExprKind::Array(v) | ExprKind::Tup(v) => Some(v.iter().collect()),
+        ExprKind::Repeat(inner, _)
+        | ExprKind::Cast(inner, _)
+        | ExprKind::Type(inner, _)
+        | ExprKind::Unary(_, inner)
+        | ExprKind::Field(inner, _)
+        | ExprKind::AddrOf(_, _, inner)
+        | ExprKind::Box(inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])),
+        ExprKind::Struct(_, fields, ref base) => {
             if has_drop(cx, cx.typeck_results().expr_ty(expr)) {
                 None
             } else {
                 Some(fields.iter().map(|f| &f.expr).chain(base).map(Deref::deref).collect())
             }
         },
-        ExprKind::Call(ref callee, ref args) => {
+        ExprKind::Call(callee, args) => {
             if let ExprKind::Path(ref qpath) = callee.kind {
                 let res = cx.qpath_res(qpath, callee.hir_id);
                 match res {
@@ -161,7 +159,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Vec
                 None
             }
         },
-        ExprKind::Block(ref block, _) => {
+        ExprKind::Block(block, _) => {
             if block.stmts.is_empty() {
                 block.expr.as_ref().and_then(|e| {
                     match block.rules {
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index aa1d8fbe300..d775cd7c7f7 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -307,19 +307,17 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
                             // we should use here as a frozen variant is a potential to be frozen
                             // similar to unknown layouts.
                             // e.g. `layout_of(...).is_err() || has_frozen_variant(...);`
+                        let ty = hir_ty_to_ty(cx.tcx, hir_ty);
+                        let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
+                        if is_unfrozen(cx, normalized);
+                        if is_value_unfrozen_poly(cx, *body_id, normalized);
                         then {
-                            let ty = hir_ty_to_ty(cx.tcx, hir_ty);
-                            let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
-                            if is_unfrozen(cx, normalized)
-                                && is_value_unfrozen_poly(cx, *body_id, normalized)
-                            {
-                                lint(
-                                   cx,
-                                   Source::Assoc {
-                                       item: impl_item.span,
-                                    },
-                                );
-                            }
+                            lint(
+                               cx,
+                               Source::Assoc {
+                                   item: impl_item.span,
+                                },
+                            );
                         }
                     }
                 },
diff --git a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
new file mode 100644
index 00000000000..a83daea97bf
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
@@ -0,0 +1,106 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::{snippet_opt, snippet_with_applicability};
+use clippy_utils::ty::match_type;
+use clippy_utils::{match_def_path, paths};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for non-octal values used to set Unix file permissions.
+    ///
+    /// **Why is this bad?** They will be converted into octal, creating potentially
+    /// unintended file permissions.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust,ignore
+    /// use std::fs::OpenOptions;
+    /// use std::os::unix::fs::OpenOptionsExt;
+    ///
+    /// let mut options = OpenOptions::new();
+    /// options.mode(644);
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// use std::fs::OpenOptions;
+    /// use std::os::unix::fs::OpenOptionsExt;
+    ///
+    /// let mut options = OpenOptions::new();
+    /// options.mode(0o644);
+    /// ```
+    pub NON_OCTAL_UNIX_PERMISSIONS,
+    correctness,
+    "use of non-octal value to set unix file permissions, which will be translated into octal"
+}
+
+declare_lint_pass!(NonOctalUnixPermissions => [NON_OCTAL_UNIX_PERMISSIONS]);
+
+impl LateLintPass<'_> for NonOctalUnixPermissions {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+        match &expr.kind {
+            ExprKind::MethodCall(path, _, [func, param], _) => {
+                let obj_ty = cx.typeck_results().expr_ty(func).peel_refs();
+
+                if_chain! {
+                    if (path.ident.name == sym!(mode)
+                        && (match_type(cx, obj_ty, &paths::OPEN_OPTIONS)
+                            || match_type(cx, obj_ty, &paths::DIR_BUILDER)))
+                        || (path.ident.name == sym!(set_mode) && match_type(cx, obj_ty, &paths::PERMISSIONS));
+                    if let ExprKind::Lit(_) = param.kind;
+
+                    then {
+                        let snip = match snippet_opt(cx, param.span) {
+                            Some(s) => s,
+                            _ => return,
+                        };
+
+                        if !snip.starts_with("0o") {
+                            show_error(cx, param);
+                        }
+                    }
+                }
+            },
+            ExprKind::Call(func, [param]) => {
+                if_chain! {
+                    if let ExprKind::Path(ref path) = func.kind;
+                    if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id();
+                    if match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE);
+                    if let ExprKind::Lit(_) = param.kind;
+
+                    then {
+                        let snip = match snippet_opt(cx, param.span) {
+                            Some(s) => s,
+                            _ => return,
+                        };
+
+                        if !snip.starts_with("0o") {
+                            show_error(cx, param);
+                        }
+                    }
+                }
+            },
+            _ => {},
+        };
+    }
+}
+
+fn show_error(cx: &LateContext<'_>, param: &Expr<'_>) {
+    let mut applicability = Applicability::MachineApplicable;
+    span_lint_and_sugg(
+        cx,
+        NON_OCTAL_UNIX_PERMISSIONS,
+        param.span,
+        "using a non-octal value to set unix file permissions",
+        "consider using an octal literal instead",
+        format!(
+            "0o{}",
+            snippet_with_applicability(cx, param.span, "0o..", &mut applicability,),
+        ),
+        applicability,
+    );
+}
diff --git a/src/tools/clippy/clippy_lints/src/open_options.rs b/src/tools/clippy/clippy_lints/src/open_options.rs
index c61dff4b8e0..9efe45336bf 100644
--- a/src/tools/clippy/clippy_lints/src/open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/open_options.rs
@@ -31,7 +31,7 @@ declare_lint_pass!(OpenOptions => [NONSENSICAL_OPEN_OPTIONS]);
 
 impl<'tcx> LateLintPass<'tcx> for OpenOptions {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        if let ExprKind::MethodCall(ref path, _, ref arguments, _) = e.kind {
+        if let ExprKind::MethodCall(path, _, arguments, _) = e.kind {
             let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs();
             if path.ident.name == sym!(open) && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) {
                 let mut options = Vec::new();
@@ -59,7 +59,7 @@ enum OpenOption {
 }
 
 fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) {
-    if let ExprKind::MethodCall(ref path, _, ref arguments, _) = argument.kind {
+    if let ExprKind::MethodCall(path, _, arguments, _) = argument.kind {
         let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs();
 
         // Only proceed if this is a call on some object of type std::fs::OpenOptions
diff --git a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
index a0bc324e026..b6f518661bd 100644
--- a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
@@ -4,6 +4,7 @@ use if_chain::if_chain;
 use rustc_ast::ast::{Expr, ExprKind};
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of `option_env!(...).unwrap()` and
@@ -37,8 +38,7 @@ impl EarlyLintPass for OptionEnvUnwrap {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         if_chain! {
             if let ExprKind::MethodCall(path_segment, args, _) = &expr.kind;
-            let method_name = path_segment.ident.as_str();
-            if method_name == "expect" || method_name == "unwrap";
+            if matches!(path_segment.ident.name, sym::expect | sym::unwrap);
             if let ExprKind::Call(caller, _) = &args[0].kind;
             if is_direct_expn_of(caller.span, "option_env").is_some();
             then {
diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
index a76a4a33f1f..1b9120ae45f 100644
--- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
@@ -66,9 +66,9 @@ declare_lint_pass!(OptionIfLetElse => [OPTION_IF_LET_ELSE]);
 
 /// Returns true iff the given expression is the result of calling `Result::ok`
 fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
-    if let ExprKind::MethodCall(ref path, _, &[ref receiver], _) = &expr.kind {
+    if let ExprKind::MethodCall(path, _, &[ref receiver], _) = &expr.kind {
         path.ident.name.as_str() == "ok"
-            && is_type_diagnostic_item(cx, &cx.typeck_results().expr_ty(&receiver), sym::result_type)
+            && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::result_type)
     } else {
         false
     }
@@ -97,9 +97,9 @@ fn extract_body_from_arm<'a>(arm: &'a Arm<'a>) -> Option<&'a Expr<'a>> {
     ) = &arm.body.kind
     {
         if let [] = statements {
-            Some(&expr)
+            Some(expr)
         } else {
-            Some(&arm.body)
+            Some(arm.body)
         }
     } else {
         None
diff --git a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs b/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs
index cf667c6e805..e222782c2cc 100644
--- a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs
+++ b/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs
@@ -31,11 +31,11 @@ impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         let eq = |l, r| SpanlessEq::new(cx).eq_path_segment(l, r);
         if_chain! {
-            if let ExprKind::Binary(ref op, ref first, ref second) = expr.kind;
-            if let ExprKind::Binary(ref op2, ref ident1, ref ident2) = first.kind;
-            if let ExprKind::Path(QPath::Resolved(_, ref path1)) = ident1.kind;
-            if let ExprKind::Path(QPath::Resolved(_, ref path2)) = ident2.kind;
-            if let ExprKind::Path(QPath::Resolved(_, ref path3)) = second.kind;
+            if let ExprKind::Binary(ref op, first, second) = expr.kind;
+            if let ExprKind::Binary(ref op2, ident1, ident2) = first.kind;
+            if let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind;
+            if let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind;
+            if let ExprKind::Path(QPath::Resolved(_, path3)) = second.kind;
             if eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]);
             if cx.typeck_results().expr_ty(ident1).is_integral();
             if cx.typeck_results().expr_ty(ident2).is_integral();
@@ -56,11 +56,11 @@ impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional {
         }
 
         if_chain! {
-            if let ExprKind::Binary(ref op, ref first, ref second) = expr.kind;
-            if let ExprKind::Binary(ref op2, ref ident1, ref ident2) = second.kind;
-            if let ExprKind::Path(QPath::Resolved(_, ref path1)) = ident1.kind;
-            if let ExprKind::Path(QPath::Resolved(_, ref path2)) = ident2.kind;
-            if let ExprKind::Path(QPath::Resolved(_, ref path3)) = first.kind;
+            if let ExprKind::Binary(ref op, first, second) = expr.kind;
+            if let ExprKind::Binary(ref op2, ident1, ident2) = second.kind;
+            if let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind;
+            if let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind;
+            if let ExprKind::Path(QPath::Resolved(_, path3)) = first.kind;
             if eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]);
             if cx.typeck_results().expr_ty(ident1).is_integral();
             if cx.typeck_results().expr_ty(ident2).is_integral();
diff --git a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
index d06e7f8fe1e..1e946858947 100644
--- a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
+++ b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
@@ -97,11 +97,10 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented {
 fn get_outer_span(expr: &Expr<'_>) -> Span {
     if_chain! {
         if expr.span.from_expansion();
-        let first = expr.span.ctxt().outer_expn_data();
-        if first.call_site.from_expansion();
-        let second = first.call_site.ctxt().outer_expn_data();
+        let first = expr.span.ctxt().outer_expn_data().call_site;
+        if first.from_expansion();
         then {
-            second.call_site
+            first.ctxt().outer_expn_data().call_site
         } else {
             expr.span
         }
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index e151f85a391..6f80e447c7d 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -142,11 +142,11 @@ impl<'tcx> PassByRefOrValue {
                     };
 
                     if_chain! {
-                        if !output_lts.contains(&input_lt);
+                        if !output_lts.contains(input_lt);
                         if is_copy(cx, ty);
                         if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
                         if size <= self.ref_min_size;
-                        if let hir::TyKind::Rptr(_, MutTy { ty: ref decl_ty, .. }) = input.kind;
+                        if let hir::TyKind::Rptr(_, MutTy { ty: decl_ty, .. }) = input.kind;
                         then {
                             let value_type = if is_self_ty(decl_ty) {
                                 "self".into()
diff --git a/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs b/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs
index 95ffae28d8c..00245926381 100644
--- a/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs
+++ b/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs
@@ -45,7 +45,7 @@ declare_lint_pass!(PathBufPushOverwrite => [PATH_BUF_PUSH_OVERWRITE]);
 impl<'tcx> LateLintPass<'tcx> for PathBufPushOverwrite {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
-            if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind;
+            if let ExprKind::MethodCall(path, _, args, _) = expr.kind;
             if path.ident.name == sym!(push);
             if args.len() == 2;
             if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), sym::PathBuf);
diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
index c0c2ab67e38..9bab783998a 100644
--- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
@@ -87,7 +87,7 @@ declare_lint_pass!(PatternTypeMismatch => [PATTERN_TYPE_MISMATCH]);
 
 impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
-        if let StmtKind::Local(ref local) = stmt.kind {
+        if let StmtKind::Local(local) = stmt.kind {
             if let Some(init) = &local.init {
                 if let Some(init_ty) = cx.typeck_results().node_type_opt(init.hir_id) {
                     let pat = &local.pat;
@@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch {
     }
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let ExprKind::Match(ref expr, arms, source) = expr.kind {
+        if let ExprKind::Match(expr, arms, source) = expr.kind {
             match source {
                 MatchSource::Normal | MatchSource::IfLetDesugar { .. } | MatchSource::WhileLetDesugar => {
                     if let Some(expr_ty) = cx.typeck_results().node_type_opt(expr.hir_id) {
@@ -136,7 +136,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch {
     ) {
         if let Some(fn_sig) = cx.typeck_results().liberated_fn_sigs().get(hir_id) {
             for (param, ty) in iter::zip(body.params, fn_sig.inputs()) {
-                apply_lint(cx, &param.pat, ty, DerefPossible::Impossible);
+                apply_lint(cx, param.pat, ty, DerefPossible::Impossible);
             }
         }
     }
@@ -188,7 +188,7 @@ fn find_first_mismatch<'tcx>(
     ty: Ty<'tcx>,
     level: Level,
 ) -> Option<(Span, Mutability, Level)> {
-    if let PatKind::Ref(ref sub_pat, _) = pat.kind {
+    if let PatKind::Ref(sub_pat, _) = pat.kind {
         if let TyKind::Ref(_, sub_ty, _) = ty.kind() {
             return find_first_mismatch(cx, sub_pat, sub_ty, Level::Lower);
         }
@@ -200,8 +200,8 @@ fn find_first_mismatch<'tcx>(
         }
     }
 
-    if let PatKind::Struct(ref qpath, ref field_pats, _) = pat.kind {
-        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind() {
+    if let PatKind::Struct(ref qpath, field_pats, _) = pat.kind {
+        if let TyKind::Adt(adt_def, substs_ref) = ty.kind() {
             if let Some(variant) = get_variant(adt_def, qpath) {
                 let field_defs = &variant.fields;
                 return find_first_mismatch_in_struct(cx, field_pats, field_defs, substs_ref);
@@ -209,8 +209,8 @@ fn find_first_mismatch<'tcx>(
         }
     }
 
-    if let PatKind::TupleStruct(ref qpath, ref pats, _) = pat.kind {
-        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind() {
+    if let PatKind::TupleStruct(ref qpath, pats, _) = pat.kind {
+        if let TyKind::Adt(adt_def, substs_ref) = ty.kind() {
             if let Some(variant) = get_variant(adt_def, qpath) {
                 let field_defs = &variant.fields;
                 let ty_iter = field_defs.iter().map(|field_def| field_def.ty(cx.tcx, substs_ref));
@@ -219,7 +219,7 @@ fn find_first_mismatch<'tcx>(
         }
     }
 
-    if let PatKind::Tuple(ref pats, _) = pat.kind {
+    if let PatKind::Tuple(pats, _) = pat.kind {
         if let TyKind::Tuple(..) = ty.kind() {
             return find_first_mismatch_in_tuple(cx, pats, ty.tuple_fields());
         }
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index be686b1b0cd..09fcdb5faf8 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -124,7 +124,7 @@ declare_lint_pass!(Ptr => [PTR_ARG, CMP_NULL, MUT_FROM_REF]);
 impl<'tcx> LateLintPass<'tcx> for Ptr {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         if let ItemKind::Fn(ref sig, _, body_id) = item.kind {
-            check_fn(cx, &sig.decl, item.hir_id(), Some(body_id));
+            check_fn(cx, sig.decl, item.hir_id(), Some(body_id));
         }
     }
 
@@ -136,7 +136,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
                     return; // ignore trait impls
                 }
             }
-            check_fn(cx, &sig.decl, item.hir_id(), Some(body_id));
+            check_fn(cx, sig.decl, item.hir_id(), Some(body_id));
         }
     }
 
@@ -147,12 +147,12 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
             } else {
                 None
             };
-            check_fn(cx, &sig.decl, item.hir_id(), body_id);
+            check_fn(cx, sig.decl, item.hir_id(), body_id);
         }
     }
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let ExprKind::Binary(ref op, ref l, ref r) = expr.kind {
+        if let ExprKind::Binary(ref op, l, r) = expr.kind {
             if (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne) && (is_null_path(l) || is_null_path(r)) {
                 span_lint(
                     cx,
@@ -262,35 +262,34 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
                 }
             } else if match_type(cx, ty, &paths::COW) {
                 if_chain! {
-                    if let TyKind::Rptr(_, MutTy { ref ty, ..} ) = arg.kind;
-                    if let TyKind::Path(QPath::Resolved(None, ref pp)) = ty.kind;
+                    if let TyKind::Rptr(_, MutTy { ty, ..} ) = arg.kind;
+                    if let TyKind::Path(QPath::Resolved(None, pp)) = ty.kind;
                     if let [ref bx] = *pp.segments;
-                    if let Some(ref params) = bx.args;
+                    if let Some(params) = bx.args;
                     if !params.parenthesized;
                     if let Some(inner) = params.args.iter().find_map(|arg| match arg {
                         GenericArg::Type(ty) => Some(ty),
                         _ => None,
                     });
+                    let replacement = snippet_opt(cx, inner.span);
+                    if let Some(r) = replacement;
                     then {
-                        let replacement = snippet_opt(cx, inner.span);
-                        if let Some(r) = replacement {
-                            span_lint_and_sugg(
-                                cx,
-                                PTR_ARG,
-                                arg.span,
-                                "using a reference to `Cow` is not recommended",
-                                "change this to",
-                                "&".to_owned() + &r,
-                                Applicability::Unspecified,
-                            );
-                        }
+                        span_lint_and_sugg(
+                            cx,
+                            PTR_ARG,
+                            arg.span,
+                            "using a reference to `Cow` is not recommended",
+                            "change this to",
+                            "&".to_owned() + &r,
+                            Applicability::Unspecified,
+                        );
                     }
                 }
             }
         }
     }
 
-    if let FnRetTy::Return(ref ty) = decl.output {
+    if let FnRetTy::Return(ty) = decl.output {
         if let Some((out, Mutability::Mut, _)) = get_rptr_lm(ty) {
             let mut immutables = vec![];
             for (_, ref mutbl, ref argspan) in decl
@@ -323,8 +322,8 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
 
 fn get_only_generic_arg_snippet(cx: &LateContext<'_>, arg: &Ty<'_>) -> Option<String> {
     if_chain! {
-        if let TyKind::Path(QPath::Resolved(_, ref path)) = walk_ptrs_hir_ty(arg).kind;
-        if let Some(&PathSegment{args: Some(ref parameters), ..}) = path.segments.last();
+        if let TyKind::Path(QPath::Resolved(_, path)) = walk_ptrs_hir_ty(arg).kind;
+        if let Some(&PathSegment{args: Some(parameters), ..}) = path.segments.last();
         let types: Vec<_> = parameters.args.iter().filter_map(|arg| match arg {
             GenericArg::Type(ty) => Some(ty),
             _ => None,
@@ -347,7 +346,7 @@ fn get_rptr_lm<'tcx>(ty: &'tcx Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability,
 }
 
 fn is_null_path(expr: &Expr<'_>) -> bool {
-    if let ExprKind::Call(ref pathexp, ref args) = expr.kind {
+    if let ExprKind::Call(pathexp, args) = expr.kind {
         if args.is_empty() {
             if let ExprKind::Path(ref path) = pathexp.kind {
                 return match_qpath(path, &paths::PTR_NULL) || match_qpath(path, &paths::PTR_NULL_MUT);
diff --git a/src/tools/clippy/clippy_lints/src/ptr_eq.rs b/src/tools/clippy/clippy_lints/src/ptr_eq.rs
index 5796c59c8b3..77cfa3f6b17 100644
--- a/src/tools/clippy/clippy_lints/src/ptr_eq.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr_eq.rs
@@ -46,11 +46,11 @@ impl LateLintPass<'_> for PtrEq {
             return;
         }
 
-        if let ExprKind::Binary(ref op, ref left, ref right) = expr.kind {
+        if let ExprKind::Binary(ref op, left, right) = expr.kind {
             if BinOpKind::Eq == op.node {
                 let (left, right) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) {
                     (Some(lhs), Some(rhs)) => (lhs, rhs),
-                    _ => (&**left, &**right),
+                    _ => (left, right),
                 };
 
                 if_chain! {
@@ -79,7 +79,7 @@ impl LateLintPass<'_> for PtrEq {
 // E.g., `foo as *const _ as usize` returns `foo as *const _`.
 fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
     if cx.typeck_results().expr_ty(cast_expr) == cx.tcx.types.usize {
-        if let ExprKind::Cast(ref expr, _) = cast_expr.kind {
+        if let ExprKind::Cast(expr, _) = cast_expr.kind {
             return Some(expr);
         }
     }
@@ -90,7 +90,7 @@ fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>
 // E.g., `foo as *const _` returns `foo`.
 fn expr_as_cast_to_raw_pointer<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
     if cx.typeck_results().expr_ty(cast_expr).is_unsafe_ptr() {
-        if let ExprKind::Cast(ref expr, _) = cast_expr.kind {
+        if let ExprKind::Cast(expr, _) = cast_expr.kind {
             return Some(expr);
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
index c04b4255256..afb198f4955 100644
--- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
@@ -78,8 +78,8 @@ impl<'tcx> LateLintPass<'tcx> for PtrOffsetWithCast {
 
 // If the given expression is a cast from a usize, return the lhs of the cast
 fn expr_as_cast_from_usize<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
-    if let ExprKind::Cast(ref cast_lhs_expr, _) = expr.kind {
-        if is_expr_ty_usize(cx, &cast_lhs_expr) {
+    if let ExprKind::Cast(cast_lhs_expr, _) = expr.kind {
+        if is_expr_ty_usize(cx, cast_lhs_expr) {
             return Some(cast_lhs_expr);
         }
     }
@@ -92,7 +92,7 @@ fn expr_as_ptr_offset_call<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'_>,
 ) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Method)> {
-    if let ExprKind::MethodCall(ref path_segment, _, ref args, _) = expr.kind {
+    if let ExprKind::MethodCall(path_segment, _, args, _) = expr.kind {
         if is_expr_ty_raw_ptr(cx, &args[0]) {
             if path_segment.ident.name == sym::offset {
                 return Some((&args[0], &args[1], Method::Offset));
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index 2054255a7c9..6d720f43851 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -148,14 +148,14 @@ impl QuestionMark {
 
     fn expression_returns_none(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
         match expression.kind {
-            ExprKind::Block(ref block, _) => {
+            ExprKind::Block(block, _) => {
                 if let Some(return_expression) = Self::return_expression(block) {
-                    return Self::expression_returns_none(cx, &return_expression);
+                    return Self::expression_returns_none(cx, return_expression);
                 }
 
                 false
             },
-            ExprKind::Ret(Some(ref expr)) => Self::expression_returns_none(cx, expr),
+            ExprKind::Ret(Some(expr)) => Self::expression_returns_none(cx, expr),
             ExprKind::Path(ref qp) => {
                 if let Res::Def(DefKind::Ctor(def::CtorOf::Variant, def::CtorKind::Const), def_id) =
                     cx.qpath_res(qp, expression.hir_id)
@@ -174,7 +174,7 @@ impl QuestionMark {
         if_chain! {
             if block.stmts.len() == 1;
             if let Some(expr) = block.stmts.iter().last();
-            if let StmtKind::Semi(ref expr) = expr.kind;
+            if let StmtKind::Semi(expr) = expr.kind;
             if let ExprKind::Ret(Some(ret_expr)) = expr.kind;
 
             then {
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index 95b21489eb5..1c3c125e579 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -183,10 +183,10 @@ impl_lint_pass!(Ranges => [
 impl<'tcx> LateLintPass<'tcx> for Ranges {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         match expr.kind {
-            ExprKind::MethodCall(ref path, _, ref args, _) => {
+            ExprKind::MethodCall(path, _, args, _) => {
                 check_range_zip_with_len(cx, path, args, expr.span);
             },
-            ExprKind::Binary(ref op, ref l, ref r) => {
+            ExprKind::Binary(ref op, l, r) => {
                 if meets_msrv(self.msrv.as_ref(), &MANUAL_RANGE_CONTAINS_MSRV) {
                     check_possible_range_contains(cx, op.node, l, r, expr);
                 }
@@ -287,7 +287,7 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'
 }
 
 fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant, Ident, Span, Span, Ordering, bool)> {
-    if let ExprKind::Binary(ref op, ref l, ref r) = ex.kind {
+    if let ExprKind::Binary(ref op, l, r) = ex.kind {
         let (inclusive, ordering) = match op.node {
             BinOpKind::Gt => (false, Ordering::Greater),
             BinOpKind::Ge => (true, Ordering::Greater),
@@ -320,32 +320,29 @@ fn match_ident(e: &Expr<'_>) -> Option<Ident> {
 }
 
 fn check_range_zip_with_len(cx: &LateContext<'_>, path: &PathSegment<'_>, args: &[Expr<'_>], span: Span) {
-    let name = path.ident.as_str();
-    if name == "zip" && args.len() == 2 {
-        let iter = &args[0].kind;
-        let zip_arg = &args[1];
-        if_chain! {
-            // `.iter()` call
-            if let ExprKind::MethodCall(ref iter_path, _, ref iter_args, _) = *iter;
-            if iter_path.ident.name == sym::iter;
-            // range expression in `.zip()` call: `0..x.len()`
-            if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(zip_arg);
-            if is_integer_const(cx, start, 0);
-            // `.len()` call
-            if let ExprKind::MethodCall(ref len_path, _, ref len_args, _) = end.kind;
-            if len_path.ident.name == sym!(len) && len_args.len() == 1;
-            // `.iter()` and `.len()` called on same `Path`
-            if let ExprKind::Path(QPath::Resolved(_, ref iter_path)) = iter_args[0].kind;
-            if let ExprKind::Path(QPath::Resolved(_, ref len_path)) = len_args[0].kind;
-            if SpanlessEq::new(cx).eq_path_segments(&iter_path.segments, &len_path.segments);
-            then {
-                span_lint(cx,
-                    RANGE_ZIP_WITH_LEN,
-                    span,
-                    &format!("it is more idiomatic to use `{}.iter().enumerate()`",
-                        snippet(cx, iter_args[0].span, "_"))
-                );
-            }
+    if_chain! {
+        if path.ident.as_str() == "zip";
+        if let [iter, zip_arg] = args;
+        // `.iter()` call
+        if let ExprKind::MethodCall(iter_path, _, iter_args, _) = iter.kind;
+        if iter_path.ident.name == sym::iter;
+        // range expression in `.zip()` call: `0..x.len()`
+        if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(zip_arg);
+        if is_integer_const(cx, start, 0);
+        // `.len()` call
+        if let ExprKind::MethodCall(len_path, _, len_args, _) = end.kind;
+        if len_path.ident.name == sym!(len) && len_args.len() == 1;
+        // `.iter()` and `.len()` called on same `Path`
+        if let ExprKind::Path(QPath::Resolved(_, iter_path)) = iter_args[0].kind;
+        if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_args[0].kind;
+        if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments);
+        then {
+            span_lint(cx,
+                RANGE_ZIP_WITH_LEN,
+                span,
+                &format!("it is more idiomatic to use `{}.iter().enumerate()`",
+                    snippet(cx, iter_args[0].span, "_"))
+            );
         }
     }
 }
@@ -511,8 +508,8 @@ fn y_plus_one<'t>(cx: &LateContext<'_>, expr: &'t Expr<'_>) -> Option<&'t Expr<'
             Spanned {
                 node: BinOpKind::Add, ..
             },
-            ref lhs,
-            ref rhs,
+            lhs,
+            rhs,
         ) => {
             if is_integer_const(cx, lhs, 1) {
                 Some(rhs)
@@ -532,8 +529,8 @@ fn y_minus_one<'t>(cx: &LateContext<'_>, expr: &'t Expr<'_>) -> Option<&'t Expr<
             Spanned {
                 node: BinOpKind::Sub, ..
             },
-            ref lhs,
-            ref rhs,
+            lhs,
+            rhs,
         ) if is_integer_const(cx, rhs, 1) => Some(lhs),
         _ => None,
     }
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index 3abe619207e..7dafce60d5e 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -94,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
             .into_results_cursor(mir);
         let mut possible_borrower = {
             let mut vis = PossibleBorrowerVisitor::new(cx, mir);
-            vis.visit_body(&mir);
+            vis.visit_body(mir);
             vis.into_map(cx, maybe_storage_live_result)
         };
 
@@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
                 continue;
             }
 
-            if let ty::Adt(ref def, _) = arg_ty.kind() {
+            if let ty::Adt(def, _) = arg_ty.kind() {
                 if match_def_path(cx, def.did, &paths::MEM_MANUALLY_DROP) {
                     continue;
                 }
@@ -199,79 +199,72 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
                 (local, deref_clone_ret)
             };
 
-            let is_temp = mir.local_kind(ret_local) == mir::LocalKind::Temp;
-
-            // 1. `local` can be moved out if it is not used later.
-            // 2. If `ret_local` is a temporary and is neither consumed nor mutated, we can remove this `clone`
-            // call anyway.
-            let (used, consumed_or_mutated) = traversal::ReversePostorder::new(&mir, bb).skip(1).fold(
-                (false, !is_temp),
-                |(used, consumed), (tbb, tdata)| {
-                    // Short-circuit
-                    if (used && consumed) ||
-                        // Give up on loops
-                        tdata.terminator().successors().any(|s| *s == bb)
-                    {
-                        return (true, true);
+            let clone_usage = if local == ret_local {
+                CloneUsage {
+                    cloned_used: false,
+                    cloned_consume_or_mutate_loc: None,
+                    clone_consumed_or_mutated: true,
+                }
+            } else {
+                let clone_usage = visit_clone_usage(local, ret_local, mir, bb);
+                if clone_usage.cloned_used && clone_usage.clone_consumed_or_mutated {
+                    // cloned value is used, and the clone is modified or moved
+                    continue;
+                } else if let Some(loc) = clone_usage.cloned_consume_or_mutate_loc {
+                    // cloned value is mutated, and the clone is alive.
+                    if possible_borrower.is_alive_at(ret_local, loc) {
+                        continue;
                     }
+                }
+                clone_usage
+            };
 
-                    let mut vis = LocalUseVisitor {
-                        used: (local, false),
-                        consumed_or_mutated: (ret_local, false),
-                    };
-                    vis.visit_basic_block_data(tbb, tdata);
-                    (used || vis.used.1, consumed || vis.consumed_or_mutated.1)
-                },
-            );
-
-            if !used || !consumed_or_mutated {
-                let span = terminator.source_info.span;
-                let scope = terminator.source_info.scope;
-                let node = mir.source_scopes[scope]
-                    .local_data
-                    .as_ref()
-                    .assert_crate_local()
-                    .lint_root;
-
-                if_chain! {
-                    if let Some(snip) = snippet_opt(cx, span);
-                    if let Some(dot) = snip.rfind('.');
-                    then {
-                        let sugg_span = span.with_lo(
-                            span.lo() + BytePos(u32::try_from(dot).unwrap())
-                        );
-                        let mut app = Applicability::MaybeIncorrect;
-
-                        let call_snip = &snip[dot + 1..];
-                        // Machine applicable when `call_snip` looks like `foobar()`
-                        if let Some(call_snip) = call_snip.strip_suffix("()").map(str::trim) {
-                            if call_snip.as_bytes().iter().all(|b| b.is_ascii_alphabetic() || *b == b'_') {
-                                app = Applicability::MachineApplicable;
-                            }
+            let span = terminator.source_info.span;
+            let scope = terminator.source_info.scope;
+            let node = mir.source_scopes[scope]
+                .local_data
+                .as_ref()
+                .assert_crate_local()
+                .lint_root;
+
+            if_chain! {
+                if let Some(snip) = snippet_opt(cx, span);
+                if let Some(dot) = snip.rfind('.');
+                then {
+                    let sugg_span = span.with_lo(
+                        span.lo() + BytePos(u32::try_from(dot).unwrap())
+                    );
+                    let mut app = Applicability::MaybeIncorrect;
+
+                    let call_snip = &snip[dot + 1..];
+                    // Machine applicable when `call_snip` looks like `foobar()`
+                    if let Some(call_snip) = call_snip.strip_suffix("()").map(str::trim) {
+                        if call_snip.as_bytes().iter().all(|b| b.is_ascii_alphabetic() || *b == b'_') {
+                            app = Applicability::MachineApplicable;
                         }
+                    }
 
-                        span_lint_hir_and_then(cx, REDUNDANT_CLONE, node, sugg_span, "redundant clone", |diag| {
-                            diag.span_suggestion(
-                                sugg_span,
-                                "remove this",
-                                String::new(),
-                                app,
+                    span_lint_hir_and_then(cx, REDUNDANT_CLONE, node, sugg_span, "redundant clone", |diag| {
+                        diag.span_suggestion(
+                            sugg_span,
+                            "remove this",
+                            String::new(),
+                            app,
+                        );
+                        if clone_usage.cloned_used {
+                            diag.span_note(
+                                span,
+                                "cloned value is neither consumed nor mutated",
                             );
-                            if used {
-                                diag.span_note(
-                                    span,
-                                    "cloned value is neither consumed nor mutated",
-                                );
-                            } else {
-                                diag.span_note(
-                                    span.with_hi(span.lo() + BytePos(u32::try_from(dot).unwrap())),
-                                    "this value is dropped without further use",
-                                );
-                            }
-                        });
-                    } else {
-                        span_lint_hir(cx, REDUNDANT_CLONE, node, span, "redundant clone");
-                    }
+                        } else {
+                            diag.span_note(
+                                span.with_hi(span.lo() + BytePos(u32::try_from(dot).unwrap())),
+                                "this value is dropped without further use",
+                            );
+                        }
+                    });
+                } else {
+                    span_lint_hir(cx, REDUNDANT_CLONE, node, span, "redundant clone");
                 }
             }
         }
@@ -365,49 +358,97 @@ fn base_local_and_movability<'tcx>(
     (local, deref || field || slice)
 }
 
-struct LocalUseVisitor {
-    used: (mir::Local, bool),
-    consumed_or_mutated: (mir::Local, bool),
+#[derive(Default)]
+struct CloneUsage {
+    /// Whether the cloned value is used after the clone.
+    cloned_used: bool,
+    /// The first location where the cloned value is consumed or mutated, if any.
+    cloned_consume_or_mutate_loc: Option<mir::Location>,
+    /// Whether the clone value is mutated.
+    clone_consumed_or_mutated: bool,
 }
-
-impl<'tcx> mir::visit::Visitor<'tcx> for LocalUseVisitor {
-    fn visit_basic_block_data(&mut self, block: mir::BasicBlock, data: &mir::BasicBlockData<'tcx>) {
-        let statements = &data.statements;
-        for (statement_index, statement) in statements.iter().enumerate() {
-            self.visit_statement(statement, mir::Location { block, statement_index });
-        }
-
-        self.visit_terminator(
-            data.terminator(),
-            mir::Location {
-                block,
-                statement_index: statements.len(),
-            },
-        );
+fn visit_clone_usage(cloned: mir::Local, clone: mir::Local, mir: &mir::Body<'_>, bb: mir::BasicBlock) -> CloneUsage {
+    struct V {
+        cloned: mir::Local,
+        clone: mir::Local,
+        result: CloneUsage,
     }
+    impl<'tcx> mir::visit::Visitor<'tcx> for V {
+        fn visit_basic_block_data(&mut self, block: mir::BasicBlock, data: &mir::BasicBlockData<'tcx>) {
+            let statements = &data.statements;
+            for (statement_index, statement) in statements.iter().enumerate() {
+                self.visit_statement(statement, mir::Location { block, statement_index });
+            }
 
-    fn visit_place(&mut self, place: &mir::Place<'tcx>, ctx: PlaceContext, _: mir::Location) {
-        let local = place.local;
-
-        if local == self.used.0
-            && !matches!(
-                ctx,
-                PlaceContext::MutatingUse(MutatingUseContext::Drop) | PlaceContext::NonUse(_)
-            )
-        {
-            self.used.1 = true;
+            self.visit_terminator(
+                data.terminator(),
+                mir::Location {
+                    block,
+                    statement_index: statements.len(),
+                },
+            );
         }
 
-        if local == self.consumed_or_mutated.0 {
-            match ctx {
-                PlaceContext::NonMutatingUse(NonMutatingUseContext::Move)
-                | PlaceContext::MutatingUse(MutatingUseContext::Borrow) => {
-                    self.consumed_or_mutated.1 = true;
-                },
-                _ => {},
+        fn visit_place(&mut self, place: &mir::Place<'tcx>, ctx: PlaceContext, loc: mir::Location) {
+            let local = place.local;
+
+            if local == self.cloned
+                && !matches!(
+                    ctx,
+                    PlaceContext::MutatingUse(MutatingUseContext::Drop) | PlaceContext::NonUse(_)
+                )
+            {
+                self.result.cloned_used = true;
+                self.result.cloned_consume_or_mutate_loc = self.result.cloned_consume_or_mutate_loc.or_else(|| {
+                    matches!(
+                        ctx,
+                        PlaceContext::NonMutatingUse(NonMutatingUseContext::Move)
+                            | PlaceContext::MutatingUse(MutatingUseContext::Borrow)
+                    )
+                    .then(|| loc)
+                });
+            } else if local == self.clone {
+                match ctx {
+                    PlaceContext::NonMutatingUse(NonMutatingUseContext::Move)
+                    | PlaceContext::MutatingUse(MutatingUseContext::Borrow) => {
+                        self.result.clone_consumed_or_mutated = true;
+                    },
+                    _ => {},
+                }
             }
         }
     }
+
+    let init = CloneUsage {
+        cloned_used: false,
+        cloned_consume_or_mutate_loc: None,
+        // Consider non-temporary clones consumed.
+        // TODO: Actually check for mutation of non-temporaries.
+        clone_consumed_or_mutated: mir.local_kind(clone) != mir::LocalKind::Temp,
+    };
+    traversal::ReversePostorder::new(mir, bb)
+        .skip(1)
+        .fold(init, |usage, (tbb, tdata)| {
+            // Short-circuit
+            if (usage.cloned_used && usage.clone_consumed_or_mutated) ||
+                // Give up on loops
+                tdata.terminator().successors().any(|s| *s == bb)
+            {
+                return CloneUsage {
+                    cloned_used: true,
+                    clone_consumed_or_mutated: true,
+                    ..usage
+                };
+            }
+
+            let mut v = V {
+                cloned,
+                clone,
+                result: usage,
+            };
+            v.visit_basic_block_data(tbb, tdata);
+            v.result
+        })
 }
 
 /// Determines liveness of each local purely based on `StorageLive`/`Dead`.
@@ -547,7 +588,7 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> {
             // If the call returns something with lifetimes,
             // let's conservatively assume the returned value contains lifetime of all the arguments.
             // For example, given `let y: Foo<'a> = foo(x)`, `y` is considered to be a possible borrower of `x`.
-            if ContainsRegion.visit_ty(&self.body.local_decls[*dest].ty).is_continue() {
+            if ContainsRegion.visit_ty(self.body.local_decls[*dest].ty).is_continue() {
                 return;
             }
 
@@ -623,4 +664,9 @@ impl PossibleBorrowerMap<'_, '_> {
 
         self.bitset.0 == self.bitset.1
     }
+
+    fn is_alive_at(&mut self, local: mir::Local, at: mir::Location) -> bool {
+        self.maybe_live.seek_after_primary_effect(at);
+        self.maybe_live.contains(local)
+    }
 }
diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
index 2977a108d14..92921bedf4d 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -111,10 +111,10 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
 
                 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
                     if_chain! {
-                        if let hir::ExprKind::Call(ref closure, _) = expr.kind;
-                        if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = closure.kind;
-                        if self.path.segments[0].ident == path.segments[0].ident
-                            && self.path.res == path.res;
+                        if let hir::ExprKind::Call(closure, _) = expr.kind;
+                        if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind;
+                        if self.path.segments[0].ident == path.segments[0].ident;
+                        if self.path.res == path.res;
                         then {
                             self.count += 1;
                         }
@@ -133,14 +133,14 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
 
         for w in block.stmts.windows(2) {
             if_chain! {
-                if let hir::StmtKind::Local(ref local) = w[0].kind;
-                if let Option::Some(ref t) = local.init;
+                if let hir::StmtKind::Local(local) = w[0].kind;
+                if let Option::Some(t) = local.init;
                 if let hir::ExprKind::Closure(..) = t.kind;
                 if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind;
-                if let hir::StmtKind::Semi(ref second) = w[1].kind;
-                if let hir::ExprKind::Assign(_, ref call, _) = second.kind;
-                if let hir::ExprKind::Call(ref closure, _) = call.kind;
-                if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = closure.kind;
+                if let hir::StmtKind::Semi(second) = w[1].kind;
+                if let hir::ExprKind::Assign(_, call, _) = second.kind;
+                if let hir::ExprKind::Call(closure, _) = call.kind;
+                if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind;
                 if ident == path.segments[0].ident;
                 if count_closure_usage(cx, block, path) == 1;
                 then {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
index 6da7b5fbcc8..9c6cd7b4fa6 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
@@ -1,11 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::is_type_lang_item;
+use clippy_utils::{get_parent_expr, in_macro};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, LangItem};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::{lint::in_external_macro, ty::TyS};
+use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::TyS;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_clippy_lint! {
@@ -40,26 +41,44 @@ declare_lint_pass!(RedundantSlicing => [REDUNDANT_SLICING]);
 
 impl LateLintPass<'_> for RedundantSlicing {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if in_external_macro(cx.sess(), expr.span) {
+        if in_macro(expr.span) {
             return;
         }
 
+        let ctxt = expr.span.ctxt();
         if_chain! {
-            if let ExprKind::AddrOf(_, _, addressee) = expr.kind;
+            if let ExprKind::AddrOf(BorrowKind::Ref, mutability, addressee) = expr.kind;
+            if addressee.span.ctxt() == ctxt;
             if let ExprKind::Index(indexed, range) = addressee.kind;
             if is_type_lang_item(cx, cx.typeck_results().expr_ty_adjusted(range), LangItem::RangeFull);
             if TyS::same_type(cx.typeck_results().expr_ty(expr), cx.typeck_results().expr_ty(indexed));
             then {
                 let mut app = Applicability::MachineApplicable;
-                let hint = snippet_with_applicability(cx, indexed.span, "..", &mut app).into_owned();
+                let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
+
+                let (reborrow_str, help_str) = if mutability == Mutability::Mut {
+                    // The slice was used to reborrow the mutable reference.
+                    ("&mut *", "reborrow the original value instead")
+                } else if matches!(
+                    get_parent_expr(cx, expr),
+                    Some(Expr {
+                        kind: ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _),
+                        ..
+                    })
+                ) {
+                    // The slice was used to make a temporary reference.
+                    ("&*", "reborrow the original value instead")
+                } else {
+                    ("", "use the original value instead")
+                };
 
                 span_lint_and_sugg(
                     cx,
                     REDUNDANT_SLICING,
                     expr.span,
                     "redundant slicing of the whole range",
-                    "use the original slice instead",
-                    hint,
+                    help_str,
+                    format!("{}{}", reborrow_str, snip),
                     app,
                 );
             }
diff --git a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
index 0922cfa494e..0cf4e0ce7fe 100644
--- a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
@@ -44,7 +44,7 @@ impl<'tcx> LateLintPass<'tcx> for RefOptionRef {
             if let Some(def_id) = res.opt_def_id();
 
             if cx.tcx.is_diagnostic_item(sym::option_type, def_id);
-            if let Some(ref params) = last_path_segment(qpath).args ;
+            if let Some(params) = last_path_segment(qpath).args ;
             if !params.parenthesized;
             if let Some(inner_ty) = params.args.iter().find_map(|arg| match arg {
                 GenericArg::Type(inner_ty) => Some(inner_ty),
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index 1cc332de894..4b5306de58e 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -60,7 +60,7 @@ impl_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]);
 impl<'tcx> LateLintPass<'tcx> for Regex {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
-            if let ExprKind::Call(ref fun, ref args) = expr.kind;
+            if let ExprKind::Call(fun, args) = expr.kind;
             if let ExprKind::Path(ref qpath) = fun.kind;
             if args.len() == 1;
             if let Some(def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
@@ -134,7 +134,7 @@ fn is_trivial_regex(s: &regex_syntax::hir::Hir) -> Option<&'static str> {
 
 fn check_set<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
     if_chain! {
-        if let ExprKind::AddrOf(BorrowKind::Ref, _, ref expr) = expr.kind;
+        if let ExprKind::AddrOf(BorrowKind::Ref, _, expr) = expr.kind;
         if let ExprKind::Array(exprs) = expr.kind;
         then {
             for expr in exprs {
diff --git a/src/tools/clippy/clippy_lints/src/repeat_once.rs b/src/tools/clippy/clippy_lints/src/repeat_once.rs
index 63e5ec69e66..560a5e7c920 100644
--- a/src/tools/clippy/clippy_lints/src/repeat_once.rs
+++ b/src/tools/clippy/clippy_lints/src/repeat_once.rs
@@ -45,10 +45,10 @@ impl<'tcx> LateLintPass<'tcx> for RepeatOnce {
         if_chain! {
             if let ExprKind::MethodCall(path, _, [receiver, count], _) = &expr.kind;
             if path.ident.name == sym!(repeat);
-            if let Some(Constant::Int(1)) = constant_context(cx, cx.typeck_results()).expr(&count);
+            if let Some(Constant::Int(1)) = constant_context(cx, cx.typeck_results()).expr(count);
             if !in_macro(receiver.span);
             then {
-                let ty = cx.typeck_results().expr_ty(&receiver).peel_refs();
+                let ty = cx.typeck_results().expr_ty(receiver).peel_refs();
                 if ty.is_str() {
                     span_lint_and_sugg(
                         cx,
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index 8995ae431ad..af772cf4a14 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for Return {
                         err.span_label(local.span, "unnecessary `let` binding");
 
                         if let Some(mut snippet) = snippet_opt(cx, initexpr.span) {
-                            if !cx.typeck_results().expr_adjustments(&retexpr).is_empty() {
+                            if !cx.typeck_results().expr_adjustments(retexpr).is_empty() {
                                 snippet.push_str(" as _");
                             }
                             err.multipart_suggestion(
@@ -143,7 +143,7 @@ impl<'tcx> LateLintPass<'tcx> for Return {
                 check_final_expr(cx, &body.value, Some(body.value.span), replacement)
             },
             FnKind::ItemFn(..) | FnKind::Method(..) => {
-                if let ExprKind::Block(ref block, _) = body.value.kind {
+                if let ExprKind::Block(block, _) = body.value.kind {
                     check_block_return(cx, block);
                 }
             },
@@ -160,7 +160,7 @@ fn check_block_return<'tcx>(cx: &LateContext<'tcx>, block: &Block<'tcx>) {
         check_final_expr(cx, expr, Some(expr.span), RetReplacement::Empty);
     } else if let Some(stmt) = block.stmts.iter().last() {
         match stmt.kind {
-            StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => {
+            StmtKind::Expr(expr) | StmtKind::Semi(expr) => {
                 check_final_expr(cx, expr, Some(stmt.span), RetReplacement::Empty);
             },
             _ => (),
@@ -192,11 +192,11 @@ fn check_final_expr<'tcx>(
             }
         },
         // a whole block? check it!
-        ExprKind::Block(ref block, _) => {
+        ExprKind::Block(block, _) => {
             check_block_return(cx, block);
         },
         ExprKind::If(_, then, else_clause_opt) => {
-            if let ExprKind::Block(ref ifblock, _) = then.kind {
+            if let ExprKind::Block(ifblock, _) = then.kind {
                 check_block_return(cx, ifblock);
             }
             if let Some(else_clause) = else_clause_opt {
@@ -207,16 +207,16 @@ fn check_final_expr<'tcx>(
         // an if/if let expr, check both exprs
         // note, if without else is going to be a type checking error anyways
         // (except for unit type functions) so we don't match it
-        ExprKind::Match(_, ref arms, source) => match source {
+        ExprKind::Match(_, arms, source) => match source {
             MatchSource::Normal => {
                 for arm in arms.iter() {
-                    check_final_expr(cx, &arm.body, Some(arm.body.span), RetReplacement::Block);
+                    check_final_expr(cx, arm.body, Some(arm.body.span), RetReplacement::Block);
                 }
             },
             MatchSource::IfLetDesugar {
                 contains_else_clause: true,
             } => {
-                if let ExprKind::Block(ref ifblock, _) = arms[0].body.kind {
+                if let ExprKind::Block(ifblock, _) = arms[0].body.kind {
                     check_block_return(cx, ifblock);
                 }
                 check_final_expr(cx, arms[1].body, None, RetReplacement::Empty);
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
index f61af15fbed..553987a426b 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
@@ -51,7 +51,7 @@ impl LateLintPass<'_> for SemicolonIfNothingReturned {
                     return;
                 }
 
-                let sugg = sugg::Sugg::hir_with_macro_callsite(cx, &expr, "..");
+                let sugg = sugg::Sugg::hir_with_macro_callsite(cx, expr, "..");
                 let suggestion = format!("{0};", sugg);
                 span_lint_and_sugg(
                     cx,
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index 612d2fd84cb..d6101bd5e36 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -130,12 +130,12 @@ fn check_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'_>, bindings: &
     let len = bindings.len();
     for stmt in block.stmts {
         match stmt.kind {
-            StmtKind::Local(ref local) => check_local(cx, local, bindings),
-            StmtKind::Expr(ref e) | StmtKind::Semi(ref e) => check_expr(cx, e, bindings),
+            StmtKind::Local(local) => check_local(cx, local, bindings),
+            StmtKind::Expr(e) | StmtKind::Semi(e) => check_expr(cx, e, bindings),
             StmtKind::Item(..) => {},
         }
     }
-    if let Some(ref o) = block.expr {
+    if let Some(o) = block.expr {
         check_expr(cx, o, bindings);
     }
     bindings.truncate(len);
@@ -149,16 +149,16 @@ fn check_local<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>, bindings: &
         return;
     }
     let Local {
-        ref pat,
+        pat,
         ref ty,
         ref init,
         span,
         ..
     } = *local;
-    if let Some(ref t) = *ty {
+    if let Some(t) = *ty {
         check_ty(cx, t, bindings)
     }
-    if let Some(ref o) = *init {
+    if let Some(o) = *init {
         check_expr(cx, o, bindings);
         check_pat(cx, pat, Some(o), span, bindings);
     } else {
@@ -196,34 +196,34 @@ fn check_pat<'tcx>(
                     bindings.push((name, ident.span));
                 }
             }
-            if let Some(ref p) = *inner {
+            if let Some(p) = *inner {
                 check_pat(cx, p, init, span, bindings);
             }
         },
         PatKind::Struct(_, pfields, _) => {
             if let Some(init_struct) = init {
-                if let ExprKind::Struct(_, ref efields, _) = init_struct.kind {
+                if let ExprKind::Struct(_, efields, _) = init_struct.kind {
                     for field in pfields {
                         let name = field.ident.name;
                         let efield = efields
                             .iter()
                             .find_map(|f| if f.ident.name == name { Some(&*f.expr) } else { None });
-                        check_pat(cx, &field.pat, efield, span, bindings);
+                        check_pat(cx, field.pat, efield, span, bindings);
                     }
                 } else {
                     for field in pfields {
-                        check_pat(cx, &field.pat, init, span, bindings);
+                        check_pat(cx, field.pat, init, span, bindings);
                     }
                 }
             } else {
                 for field in pfields {
-                    check_pat(cx, &field.pat, None, span, bindings);
+                    check_pat(cx, field.pat, None, span, bindings);
                 }
             }
         },
         PatKind::Tuple(inner, _) => {
             if let Some(init_tup) = init {
-                if let ExprKind::Tup(ref tup) = init_tup.kind {
+                if let ExprKind::Tup(tup) = init_tup.kind {
                     for (i, p) in inner.iter().enumerate() {
                         check_pat(cx, p, Some(&tup[i]), p.span, bindings);
                     }
@@ -238,10 +238,10 @@ fn check_pat<'tcx>(
                 }
             }
         },
-        PatKind::Box(ref inner) => {
+        PatKind::Box(inner) => {
             if let Some(initp) = init {
-                if let ExprKind::Box(ref inner_init) = initp.kind {
-                    check_pat(cx, inner, Some(&**inner_init), span, bindings);
+                if let ExprKind::Box(inner_init) = initp.kind {
+                    check_pat(cx, inner, Some(inner_init), span, bindings);
                 } else {
                     check_pat(cx, inner, init, span, bindings);
                 }
@@ -249,7 +249,7 @@ fn check_pat<'tcx>(
                 check_pat(cx, inner, init, span, bindings);
             }
         },
-        PatKind::Ref(ref inner, _) => check_pat(cx, inner, init, span, bindings),
+        PatKind::Ref(inner, _) => check_pat(cx, inner, init, span, bindings),
         // PatVec(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
         _ => (),
     }
@@ -323,11 +323,10 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut
         return;
     }
     match expr.kind {
-        ExprKind::Unary(_, ref e)
-        | ExprKind::Field(ref e, _)
-        | ExprKind::AddrOf(_, _, ref e)
-        | ExprKind::Box(ref e) => check_expr(cx, e, bindings),
-        ExprKind::Block(ref block, _) | ExprKind::Loop(ref block, ..) => check_block(cx, block, bindings),
+        ExprKind::Unary(_, e) | ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) | ExprKind::Box(e) => {
+            check_expr(cx, e, bindings)
+        },
+        ExprKind::Block(block, _) | ExprKind::Loop(block, ..) => check_block(cx, block, bindings),
         // ExprKind::Call
         // ExprKind::MethodCall
         ExprKind::Array(v) | ExprKind::Tup(v) => {
@@ -335,18 +334,18 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut
                 check_expr(cx, e, bindings)
             }
         },
-        ExprKind::If(ref cond, ref then, ref otherwise) => {
+        ExprKind::If(cond, then, ref otherwise) => {
             check_expr(cx, cond, bindings);
-            check_expr(cx, &**then, bindings);
-            if let Some(ref o) = *otherwise {
+            check_expr(cx, then, bindings);
+            if let Some(o) = *otherwise {
                 check_expr(cx, o, bindings);
             }
         },
-        ExprKind::Match(ref init, arms, _) => {
+        ExprKind::Match(init, arms, _) => {
             check_expr(cx, init, bindings);
             let len = bindings.len();
             for arm in arms {
-                check_pat(cx, &arm.pat, Some(&**init), arm.pat.span, bindings);
+                check_pat(cx, arm.pat, Some(init), arm.pat.span, bindings);
                 // This is ugly, but needed to get the right type
                 if let Some(ref guard) = arm.guard {
                     match guard {
@@ -357,7 +356,7 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut
                         },
                     }
                 }
-                check_expr(cx, &arm.body, bindings);
+                check_expr(cx, arm.body, bindings);
                 bindings.truncate(len);
             }
         },
@@ -367,14 +366,12 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut
 
 fn check_ty<'tcx>(cx: &LateContext<'tcx>, ty: &'tcx Ty<'_>, bindings: &mut Vec<(Symbol, Span)>) {
     match ty.kind {
-        TyKind::Slice(ref sty) => check_ty(cx, sty, bindings),
-        TyKind::Array(ref fty, ref anon_const) => {
+        TyKind::Slice(sty) => check_ty(cx, sty, bindings),
+        TyKind::Array(fty, ref anon_const) => {
             check_ty(cx, fty, bindings);
             check_expr(cx, &cx.tcx.hir().body(anon_const.body).value, bindings);
         },
-        TyKind::Ptr(MutTy { ty: ref mty, .. }) | TyKind::Rptr(_, MutTy { ty: ref mty, .. }) => {
-            check_ty(cx, mty, bindings)
-        },
+        TyKind::Ptr(MutTy { ty: mty, .. }) | TyKind::Rptr(_, MutTy { ty: mty, .. }) => check_ty(cx, mty, bindings),
         TyKind::Tup(tup) => {
             for t in tup {
                 check_ty(cx, t, bindings)
@@ -387,12 +384,12 @@ fn check_ty<'tcx>(cx: &LateContext<'tcx>, ty: &'tcx Ty<'_>, bindings: &mut Vec<(
 
 fn is_self_shadow(name: Symbol, expr: &Expr<'_>) -> bool {
     match expr.kind {
-        ExprKind::Box(ref inner) | ExprKind::AddrOf(_, _, ref inner) => is_self_shadow(name, inner),
-        ExprKind::Block(ref block, _) => {
+        ExprKind::Box(inner) | ExprKind::AddrOf(_, _, inner) => is_self_shadow(name, inner),
+        ExprKind::Block(block, _) => {
             block.stmts.is_empty() && block.expr.as_ref().map_or(false, |e| is_self_shadow(name, e))
         },
-        ExprKind::Unary(op, ref inner) => (UnOp::Deref == op) && is_self_shadow(name, inner),
-        ExprKind::Path(QPath::Resolved(_, ref path)) => path_eq_name(name, path),
+        ExprKind::Unary(op, inner) => (UnOp::Deref == op) && is_self_shadow(name, inner),
+        ExprKind::Path(QPath::Resolved(_, path)) => path_eq_name(name, path),
         _ => false,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index d55a83f1613..8cf89ae456e 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -70,14 +70,14 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         // Matches initialization on reassignements. For example: `vec = Vec::with_capacity(100)`
         if_chain! {
-            if let ExprKind::Assign(ref left, ref right, _) = expr.kind;
+            if let ExprKind::Assign(left, right, _) = expr.kind;
 
             // Extract variable name
-            if let ExprKind::Path(QPath::Resolved(_, ref path)) = left.kind;
+            if let ExprKind::Path(QPath::Resolved(_, path)) = left.kind;
             if let Some(variable_name) = path.segments.get(0);
 
             // Extract len argument
-            if let Some(ref len_arg) = Self::is_vec_with_capacity(right);
+            if let Some(len_arg) = Self::is_vec_with_capacity(right);
 
             then {
                 let vi = VecAllocation {
@@ -94,10 +94,10 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         // Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)`
         if_chain! {
-            if let StmtKind::Local(ref local) = stmt.kind;
+            if let StmtKind::Local(local) = stmt.kind;
             if let PatKind::Binding(BindingAnnotation::Mutable, .., variable_name, None) = local.pat.kind;
-            if let Some(ref init) = local.init;
-            if let Some(ref len_arg) = Self::is_vec_with_capacity(init);
+            if let Some(init) = local.init;
+            if let Some(len_arg) = Self::is_vec_with_capacity(init);
 
             then {
                 let vi = VecAllocation {
@@ -117,7 +117,7 @@ impl SlowVectorInit {
     /// of the first argument of `with_capacity` call if it matches or `None` if it does not.
     fn is_vec_with_capacity<'tcx>(expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
         if_chain! {
-            if let ExprKind::Call(ref func, ref args) = expr.kind;
+            if let ExprKind::Call(func, args) = expr.kind;
             if let ExprKind::Path(ref path) = func.kind;
             if match_qpath(path, &["Vec", "with_capacity"]);
             if args.len() == 1;
@@ -208,11 +208,11 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
     fn search_slow_extend_filling(&mut self, expr: &'tcx Expr<'_>) {
         if_chain! {
             if self.initialization_found;
-            if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind;
+            if let ExprKind::MethodCall(path, _, args, _) = expr.kind;
             if let ExprKind::Path(ref qpath_subj) = args[0].kind;
-            if match_qpath(&qpath_subj, &[&*self.vec_alloc.variable_name.as_str()]);
+            if match_qpath(qpath_subj, &[&*self.vec_alloc.variable_name.as_str()]);
             if path.ident.name == sym!(extend);
-            if let Some(ref extend_arg) = args.get(1);
+            if let Some(extend_arg) = args.get(1);
             if self.is_repeat_take(extend_arg);
 
             then {
@@ -225,11 +225,11 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
     fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'_>) {
         if_chain! {
             if self.initialization_found;
-            if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind;
+            if let ExprKind::MethodCall(path, _, args, _) = expr.kind;
             if let ExprKind::Path(ref qpath_subj) = args[0].kind;
-            if match_qpath(&qpath_subj, &[&*self.vec_alloc.variable_name.as_str()]);
+            if match_qpath(qpath_subj, &[&*self.vec_alloc.variable_name.as_str()]);
             if path.ident.name == sym!(resize);
-            if let (Some(ref len_arg), Some(fill_arg)) = (args.get(1), args.get(2));
+            if let (Some(len_arg), Some(fill_arg)) = (args.get(1), args.get(2));
 
             // Check that is filled with 0
             if let ExprKind::Lit(ref lit) = fill_arg.kind;
@@ -247,15 +247,15 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
     /// Returns `true` if give expression is `repeat(0).take(...)`
     fn is_repeat_take(&self, expr: &Expr<'_>) -> bool {
         if_chain! {
-            if let ExprKind::MethodCall(ref take_path, _, ref take_args, _) = expr.kind;
+            if let ExprKind::MethodCall(take_path, _, take_args, _) = expr.kind;
             if take_path.ident.name == sym!(take);
 
             // Check that take is applied to `repeat(0)`
-            if let Some(ref repeat_expr) = take_args.get(0);
+            if let Some(repeat_expr) = take_args.get(0);
             if Self::is_repeat_zero(repeat_expr);
 
             // Check that len expression is equals to `with_capacity` expression
-            if let Some(ref len_arg) = take_args.get(1);
+            if let Some(len_arg) = take_args.get(1);
             if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr);
 
             then {
@@ -269,10 +269,10 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
     /// Returns `true` if given expression is `repeat(0)`
     fn is_repeat_zero(expr: &Expr<'_>) -> bool {
         if_chain! {
-            if let ExprKind::Call(ref fn_expr, ref repeat_args) = expr.kind;
+            if let ExprKind::Call(fn_expr, repeat_args) = expr.kind;
             if let ExprKind::Path(ref qpath_repeat) = fn_expr.kind;
-            if match_qpath(&qpath_repeat, &["repeat"]);
-            if let Some(ref repeat_arg) = repeat_args.get(0);
+            if match_qpath(qpath_repeat, &["repeat"]);
+            if let Some(repeat_arg) = repeat_args.get(0);
             if let ExprKind::Lit(ref lit) = repeat_arg.kind;
             if let LitKind::Int(0, _) = lit.node;
 
@@ -291,7 +291,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> {
     fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
         if self.initialization_found {
             match stmt.kind {
-                StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => {
+                StmtKind::Expr(expr) | StmtKind::Semi(expr) => {
                     self.search_slow_extend_filling(expr);
                     self.search_slow_resize_filling(expr);
                 },
@@ -306,7 +306,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> {
 
     fn visit_block(&mut self, block: &'tcx Block<'_>) {
         if self.initialization_found {
-            if let Some(ref s) = block.stmts.get(0) {
+            if let Some(s) = block.stmts.get(0) {
                 self.visit_stmt(s)
             }
 
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 99ca7ef77a5..9d91b53e1bb 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -119,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd {
             Spanned {
                 node: BinOpKind::Add, ..
             },
-            ref left,
+            left,
             _,
         ) = e.kind
         {
@@ -127,7 +127,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd {
                 if !is_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) {
                     let parent = get_parent_expr(cx, e);
                     if let Some(p) = parent {
-                        if let ExprKind::Assign(ref target, _, _) = p.kind {
+                        if let ExprKind::Assign(target, _, _) = p.kind {
                             // avoid duplicate matches
                             if SpanlessEq::new(cx).eq_expr(target, left) {
                                 return;
@@ -142,7 +142,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd {
                     "you added something to a string. Consider using `String::push_str()` instead",
                 );
             }
-        } else if let ExprKind::Assign(ref target, ref src, _) = e.kind {
+        } else if let ExprKind::Assign(target, src, _) = e.kind {
             if is_string(cx, target) && is_add(cx, src, target) {
                 span_lint(
                     cx,
@@ -166,10 +166,10 @@ fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {
             Spanned {
                 node: BinOpKind::Add, ..
             },
-            ref left,
+            left,
             _,
         ) => SpanlessEq::new(cx).eq_expr(target, left),
-        ExprKind::Block(ref block, _) => {
+        ExprKind::Block(block, _) => {
             block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target))
         },
         _ => false,
@@ -210,8 +210,8 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
             if let Some(args) = match_function_call(cx, e, &paths::STR_FROM_UTF8);
 
             // Find string::as_bytes
-            if let ExprKind::AddrOf(BorrowKind::Ref, _, ref args) = args[0].kind;
-            if let ExprKind::Index(ref left, ref right) = args.kind;
+            if let ExprKind::AddrOf(BorrowKind::Ref, _, args) = args[0].kind;
+            if let ExprKind::Index(left, right) = args.kind;
             let (method_names, expressions, _) = method_calls(left, 1);
             if method_names.len() == 1;
             if expressions.len() == 1;
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
index 46f423204a2..cb2237e5312 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
@@ -225,7 +225,7 @@ fn attempt_to_emit_no_difference_lint(
                     emit_suggestion(
                         cx,
                         binop.span,
-                        replace_left_sugg(cx, &binop, &sugg, &mut applicability),
+                        replace_left_sugg(cx, binop, &sugg, &mut applicability),
                         applicability,
                     );
                     return;
@@ -247,7 +247,7 @@ fn attempt_to_emit_no_difference_lint(
                     emit_suggestion(
                         cx,
                         binop.span,
-                        replace_right_sugg(cx, &binop, &sugg, &mut applicability),
+                        replace_right_sugg(cx, binop, &sugg, &mut applicability),
                         applicability,
                     );
                     return;
@@ -276,8 +276,8 @@ fn ident_swap_sugg(
     location: IdentLocation,
     applicability: &mut Applicability,
 ) -> Option<String> {
-    let left_ident = get_ident(&binop.left, location)?;
-    let right_ident = get_ident(&binop.right, location)?;
+    let left_ident = get_ident(binop.left, location)?;
+    let right_ident = get_ident(binop.right, location)?;
 
     let sugg = match (
         paired_identifiers.contains(&left_ident),
@@ -293,8 +293,7 @@ fn ident_swap_sugg(
             // ends up duplicating a clause, the `logic_bug` lint
             // should catch it.
 
-            let right_suggestion =
-                suggestion_with_swapped_ident(cx, &binop.right, location, left_ident, applicability)?;
+            let right_suggestion = suggestion_with_swapped_ident(cx, binop.right, location, left_ident, applicability)?;
 
             replace_right_sugg(cx, binop, &right_suggestion, applicability)
         },
@@ -302,15 +301,14 @@ fn ident_swap_sugg(
             // We haven't seen a pair involving the left one, so
             // it's probably what is wanted.
 
-            let right_suggestion =
-                suggestion_with_swapped_ident(cx, &binop.right, location, left_ident, applicability)?;
+            let right_suggestion = suggestion_with_swapped_ident(cx, binop.right, location, left_ident, applicability)?;
 
             replace_right_sugg(cx, binop, &right_suggestion, applicability)
         },
         (true, false) => {
             // We haven't seen a pair involving the right one, so
             // it's probably what is wanted.
-            let left_suggestion = suggestion_with_swapped_ident(cx, &binop.left, location, right_ident, applicability)?;
+            let left_suggestion = suggestion_with_swapped_ident(cx, binop.left, location, right_ident, applicability)?;
 
             replace_left_sugg(cx, binop, &left_suggestion, applicability)
         },
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
index 99e3d818b79..512abde11a6 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
@@ -68,14 +68,13 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl {
 
             // Check for more than one binary operation in the implemented function
             // Linting when multiple operations are involved can result in false positives
+            let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id);
             if_chain! {
-                let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id);
                 if let hir::Node::ImplItem(impl_item) = cx.tcx.hir().get(parent_fn);
                 if let hir::ImplItemKind::Fn(_, body_id) = impl_item.kind;
-                let body = cx.tcx.hir().body(body_id);
-                let mut visitor = BinaryExprVisitor { nb_binops: 0 };
-
                 then {
+                    let body = cx.tcx.hir().body(body_id);
+                    let mut visitor = BinaryExprVisitor { nb_binops: 0 };
                     walk_expr(&mut visitor, &body.value);
                     if visitor.nb_binops > 1 {
                         return;
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index 14519eaa962..19967e2c970 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -78,26 +78,26 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) {
     for w in block.stmts.windows(3) {
         if_chain! {
             // let t = foo();
-            if let StmtKind::Local(ref tmp) = w[0].kind;
-            if let Some(ref tmp_init) = tmp.init;
+            if let StmtKind::Local(tmp) = w[0].kind;
+            if let Some(tmp_init) = tmp.init;
             if let PatKind::Binding(.., ident, None) = tmp.pat.kind;
 
             // foo() = bar();
-            if let StmtKind::Semi(ref first) = w[1].kind;
-            if let ExprKind::Assign(ref lhs1, ref rhs1, _) = first.kind;
+            if let StmtKind::Semi(first) = w[1].kind;
+            if let ExprKind::Assign(lhs1, rhs1, _) = first.kind;
 
             // bar() = t;
-            if let StmtKind::Semi(ref second) = w[2].kind;
-            if let ExprKind::Assign(ref lhs2, ref rhs2, _) = second.kind;
-            if let ExprKind::Path(QPath::Resolved(None, ref rhs2)) = rhs2.kind;
+            if let StmtKind::Semi(second) = w[2].kind;
+            if let ExprKind::Assign(lhs2, rhs2, _) = second.kind;
+            if let ExprKind::Path(QPath::Resolved(None, rhs2)) = rhs2.kind;
             if rhs2.segments.len() == 1;
 
             if ident.name == rhs2.segments[0].ident.name;
             if eq_expr_value(cx, tmp_init, lhs1);
             if eq_expr_value(cx, rhs1, lhs2);
             then {
-                if let ExprKind::Field(ref lhs1, _) = lhs1.kind {
-                    if let ExprKind::Field(ref lhs2, _) = lhs2.kind {
+                if let ExprKind::Field(lhs1, _) = lhs1.kind {
+                    if let ExprKind::Field(lhs2, _) = lhs2.kind {
                         if lhs1.hir_id.owner == lhs2.hir_id.owner {
                             return;
                         }
@@ -192,8 +192,8 @@ enum Slice<'a> {
 
 /// Checks if both expressions are index operations into "slice-like" types.
 fn check_for_slice<'a>(cx: &LateContext<'_>, lhs1: &'a Expr<'_>, lhs2: &'a Expr<'_>) -> Slice<'a> {
-    if let ExprKind::Index(ref lhs1, ref idx1) = lhs1.kind {
-        if let ExprKind::Index(ref lhs2, ref idx2) = lhs2.kind {
+    if let ExprKind::Index(lhs1, idx1) = lhs1.kind {
+        if let ExprKind::Index(lhs2, idx2) = lhs2.kind {
             if eq_expr_value(cx, lhs1, lhs2) {
                 let ty = cx.typeck_results().expr_ty(lhs1).peel_refs();
 
@@ -217,11 +217,11 @@ fn check_for_slice<'a>(cx: &LateContext<'_>, lhs1: &'a Expr<'_>, lhs2: &'a Expr<
 fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
     for w in block.stmts.windows(2) {
         if_chain! {
-            if let StmtKind::Semi(ref first) = w[0].kind;
-            if let StmtKind::Semi(ref second) = w[1].kind;
+            if let StmtKind::Semi(first) = w[0].kind;
+            if let StmtKind::Semi(second) = w[1].kind;
             if !differing_macro_contexts(first.span, second.span);
-            if let ExprKind::Assign(ref lhs0, ref rhs0, _) = first.kind;
-            if let ExprKind::Assign(ref lhs1, ref rhs1, _) = second.kind;
+            if let ExprKind::Assign(lhs0, rhs0, _) = first.kind;
+            if let ExprKind::Assign(lhs1, rhs1, _) = second.kind;
             if eq_expr_value(cx, lhs0, rhs1);
             if eq_expr_value(cx, lhs1, rhs0);
             then {
diff --git a/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs b/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs
index 88bd2feaadd..a0492a88f91 100644
--- a/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs
+++ b/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs
@@ -86,7 +86,7 @@ impl TabsInDocComments {
 
 impl EarlyLintPass for TabsInDocComments {
     fn check_attribute(&mut self, cx: &EarlyContext<'_>, attribute: &ast::Attribute) {
-        Self::warn_if_tabs_in_doc(cx, &attribute);
+        Self::warn_if_tabs_in_doc(cx, attribute);
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/to_string_in_display.rs b/src/tools/clippy/clippy_lints/src/to_string_in_display.rs
index 42ec14c31b5..ae05a8da37b 100644
--- a/src/tools/clippy/clippy_lints/src/to_string_in_display.rs
+++ b/src/tools/clippy/clippy_lints/src/to_string_in_display.rs
@@ -92,7 +92,7 @@ impl LateLintPass<'_> for ToStringInDisplay {
         if_chain! {
             if self.in_display_impl;
             if let Some(self_hir_id) = self.self_hir_id;
-            if let ExprKind::MethodCall(ref path, _, args, _) = expr.kind;
+            if let ExprKind::MethodCall(path, _, args, _) = expr.kind;
             if path.ident.name == sym!(to_string);
             if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
             if is_diagnostic_assoc_item(cx, expr_def_id, sym::ToString);
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index 3ff27c3bcf4..b0589b0512e 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -107,7 +107,7 @@ impl TraitBounds {
                 if let WherePredicate::BoundPredicate(ref p) = bound;
                 if p.bounds.len() as u64 <= self.max_trait_bounds;
                 if !in_macro(p.span);
-                let h = hash(&p.bounded_ty);
+                let h = hash(p.bounded_ty);
                 if let Some(ref v) = map.insert(h, p.bounds.iter().collect::<Vec<_>>());
 
                 then {
@@ -170,7 +170,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
         if_chain! {
             if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
             if !in_macro(bound_predicate.span);
-            if let TyKind::Path(QPath::Resolved(_, Path { ref segments, .. })) = bound_predicate.bounded_ty.kind;
+            if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
             if let Some(segment) = segments.first();
             if let Some(trait_resolutions_direct) = map.get(&segment.ident);
             then {
diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
index 47d58bd30db..86ac916df6c 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
@@ -325,7 +325,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
     #[allow(clippy::similar_names, clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         if_chain! {
-            if let ExprKind::Call(ref path_expr, ref args) = e.kind;
+            if let ExprKind::Call(path_expr, args) = e.kind;
             if let ExprKind::Path(ref qpath) = path_expr.kind;
             if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id();
             if match_def_path(cx, def_id, &paths::TRANSMUTE);
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs
index 72489f27cd3..3aa3c393ba5 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs
@@ -30,16 +30,16 @@ pub(super) fn check<'tcx>(
                     let mut arg = sugg::Sugg::hir(cx, expr, "..");
 
                     if let ExprKind::Unary(UnOp::Neg, inner_expr) = &expr.kind {
-                        expr = &inner_expr;
+                        expr = inner_expr;
                     }
 
                     if_chain! {
                         // if the expression is a float literal and it is unsuffixed then
                         // add a suffix so the suggestion is valid and unambiguous
-                        let op = format!("{}{}", arg, float_ty.name_str()).into();
                         if let ExprKind::Lit(lit) = &expr.kind;
                         if let ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) = lit.node;
                         then {
+                            let op = format!("{}{}", arg, float_ty.name_str()).into();
                             match arg {
                                 sugg::Sugg::MaybeParen(_) => arg = sugg::Sugg::MaybeParen(op),
                                 _ => arg = sugg::Sugg::NonParen(op)
diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs
index c6d0d63b0b5..f359b606e45 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs
@@ -16,7 +16,7 @@ use rustc_typeck::check::{cast::CastCheck, FnCtxt, Inherited};
 pub(super) fn get_type_snippet(cx: &LateContext<'_>, path: &QPath<'_>, to_ref_ty: Ty<'_>) -> String {
     let seg = last_path_segment(path);
     if_chain! {
-        if let Some(ref params) = seg.args;
+        if let Some(params) = seg.args;
         if !params.parenthesized;
         if let Some(to_ty) = params.args.iter().filter_map(|arg| match arg {
             GenericArg::Type(ty) => Some(ty),
diff --git a/src/tools/clippy/clippy_lints/src/transmuting_null.rs b/src/tools/clippy/clippy_lints/src/transmuting_null.rs
index d42cdde110e..0be05d3e0cf 100644
--- a/src/tools/clippy/clippy_lints/src/transmuting_null.rs
+++ b/src/tools/clippy/clippy_lints/src/transmuting_null.rs
@@ -37,7 +37,7 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull {
         }
 
         if_chain! {
-            if let ExprKind::Call(ref func, ref args) = expr.kind;
+            if let ExprKind::Call(func, args) = expr.kind;
             if let ExprKind::Path(ref path) = func.kind;
             if match_qpath(path, &paths::STD_MEM_TRANSMUTE);
             if args.len() == 1;
@@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull {
                 // Catching:
                 // `std::mem::transmute(0 as *const i32)`
                 if_chain! {
-                    if let ExprKind::Cast(ref inner_expr, ref _cast_ty) = args[0].kind;
+                    if let ExprKind::Cast(inner_expr, _cast_ty) = args[0].kind;
                     if let ExprKind::Lit(ref lit) = inner_expr.kind;
                     if let LitKind::Int(0, _) = lit.node;
                     then {
@@ -69,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull {
                 // Catching:
                 // `std::mem::transmute(std::ptr::null::<i32>())`
                 if_chain! {
-                    if let ExprKind::Call(ref func1, ref args1) = args[0].kind;
+                    if let ExprKind::Call(func1, args1) = args[0].kind;
                     if let ExprKind::Path(ref path1) = func1.kind;
                     if match_qpath(path1, &paths::STD_PTR_NULL);
                     if args1.is_empty();
diff --git a/src/tools/clippy/clippy_lints/src/try_err.rs b/src/tools/clippy/clippy_lints/src/try_err.rs
index e61058c2749..23a1953ffac 100644
--- a/src/tools/clippy/clippy_lints/src/try_err.rs
+++ b/src/tools/clippy/clippy_lints/src/try_err.rs
@@ -60,13 +60,13 @@ impl<'tcx> LateLintPass<'tcx> for TryErr {
         // };
         if_chain! {
             if !in_external_macro(cx.tcx.sess, expr.span);
-            if let ExprKind::Match(ref match_arg, _, MatchSource::TryDesugar) = expr.kind;
-            if let ExprKind::Call(ref match_fun, ref try_args) = match_arg.kind;
+            if let ExprKind::Match(match_arg, _, MatchSource::TryDesugar) = expr.kind;
+            if let ExprKind::Call(match_fun, try_args) = match_arg.kind;
             if let ExprKind::Path(ref match_fun_path) = match_fun.kind;
             if matches!(match_fun_path, QPath::LangItem(LangItem::TryIntoResult, _));
-            if let Some(ref try_arg) = try_args.get(0);
-            if let ExprKind::Call(ref err_fun, ref err_args) = try_arg.kind;
-            if let Some(ref err_arg) = err_args.get(0);
+            if let Some(try_arg) = try_args.get(0);
+            if let ExprKind::Call(err_fun, err_args) = try_arg.kind;
+            if let Some(err_arg) = err_args.get(0);
             if let ExprKind::Path(ref err_fun_path) = err_fun.kind;
             if match_qpath(err_fun_path, &paths::RESULT_ERR);
             if let Some(return_ty) = find_return_type(cx, &expr.kind);
@@ -123,9 +123,9 @@ impl<'tcx> LateLintPass<'tcx> for TryErr {
 
 /// Finds function return type by examining return expressions in match arms.
 fn find_return_type<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx ExprKind<'_>) -> Option<Ty<'tcx>> {
-    if let ExprKind::Match(_, ref arms, MatchSource::TryDesugar) = expr {
+    if let ExprKind::Match(_, arms, MatchSource::TryDesugar) = expr {
         for arm in arms.iter() {
-            if let ExprKind::Ret(Some(ref ret)) = arm.body.kind {
+            if let ExprKind::Ret(Some(ret)) = arm.body.kind {
                 return Some(cx.typeck_results().expr_ty(ret));
             }
         }
@@ -138,9 +138,8 @@ fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t
     if_chain! {
         if let ty::Adt(_, subst) = ty.kind();
         if is_type_diagnostic_item(cx, ty, sym::result_type);
-        let err_ty = subst.type_at(1);
         then {
-            Some(err_ty)
+            Some(subst.type_at(1))
         } else {
             None
         }
@@ -156,10 +155,8 @@ fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<
 
         if let ty::Adt(ready_def, ready_subst) = ready_ty.kind();
         if cx.tcx.is_diagnostic_item(sym::result_type, ready_def.did);
-        let err_ty = ready_subst.type_at(1);
-
         then {
-            Some(err_ty)
+            Some(ready_subst.type_at(1))
         } else {
             None
         }
@@ -179,10 +176,8 @@ fn poll_option_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) ->
 
         if let ty::Adt(some_def, some_subst) = some_ty.kind();
         if cx.tcx.is_diagnostic_item(sym::result_type, some_def.did);
-        let err_ty = some_subst.type_at(1);
-
         then {
-            Some(err_ty)
+            Some(some_subst.type_at(1))
         } else {
             None
         }
diff --git a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
index d68c6db4e23..1425d8f3f37 100644
--- a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
@@ -19,9 +19,9 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
             if_chain! {
                 if let Some(def_id) = def.opt_def_id();
                 if Some(def_id) == cx.tcx.lang_items().owned_box();
-                if let QPath::Resolved(None, ref path) = *qpath;
+                if let QPath::Resolved(None, path) = *qpath;
                 if let [ref bx] = *path.segments;
-                if let Some(ref params) = bx.args;
+                if let Some(params) = bx.args;
                 if !params.parenthesized;
                 if let Some(inner) = params.args.iter().find_map(|arg| match arg {
                     GenericArg::Type(ty) => Some(ty),
@@ -86,11 +86,11 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
 // Returns true if given type is `Any` trait.
 fn is_any_trait(t: &hir::Ty<'_>) -> bool {
     if_chain! {
-        if let TyKind::TraitObject(ref traits, ..) = t.kind;
+        if let TyKind::TraitObject(traits, ..) = t.kind;
         if !traits.is_empty();
         // Only Send/Sync can be used as additional traits, so it is enough to
         // check only the first trait.
-        if match_path(&traits[0].trait_ref.path, &paths::ANY_TRAIT);
+        if match_path(traits[0].trait_ref.path, &paths::ANY_TRAIT);
         then {
             return true;
         }
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index c73c1c9d92d..d9b47a699dc 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -1,43 +1,22 @@
-#![allow(rustc::default_hash_types)]
-
 mod borrowed_box;
 mod box_vec;
 mod linked_list;
 mod option_option;
 mod rc_buffer;
 mod redundant_allocation;
+mod type_complexity;
 mod utils;
 mod vec_box;
 
-use std::borrow::Cow;
-use std::cmp::Ordering;
-use std::collections::BTreeMap;
-
-use clippy_utils::diagnostics::{multispan_sugg, span_lint, span_lint_and_help, span_lint_and_then};
-use clippy_utils::source::{snippet, snippet_opt};
-use clippy_utils::ty::{is_isize_or_usize, is_type_diagnostic_item};
-use if_chain::if_chain;
-use rustc_errors::DiagnosticBuilder;
 use rustc_hir as hir;
-use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
-    BinOpKind, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericParamKind, HirId, ImplItem,
-    ImplItemKind, Item, ItemKind, Local, MutTy, QPath, TraitFn, TraitItem, TraitItemKind, TyKind,
+    Body, FnDecl, FnRetTy, GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind, Local, MutTy, QPath, TraitItem,
+    TraitItemKind, TyKind,
 };
-use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::hir::map::Map;
-use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{self, IntTy, Ty, TyS, TypeckResults, UintTy};
-use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
-use rustc_span::symbol::sym;
-use rustc_target::abi::LayoutOf;
-use rustc_target::spec::abi::Abi;
-use rustc_typeck::hir_ty_to_ty;
-
-use crate::consts::{constant, Constant};
-use clippy_utils::paths;
-use clippy_utils::{clip, comparisons, differing_macro_contexts, int_bits, match_path, sext, unsext};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for use of `Box<Vec<_>>` anywhere in the code.
@@ -250,55 +229,119 @@ declare_clippy_lint! {
     "shared ownership of a buffer type"
 }
 
+declare_clippy_lint! {
+    /// **What it does:** Checks for types used in structs, parameters and `let`
+    /// declarations above a certain complexity threshold.
+    ///
+    /// **Why is this bad?** Too complex types make the code less readable. Consider
+    /// using a `type` definition to simplify them.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # use std::rc::Rc;
+    /// struct Foo {
+    ///     inner: Rc<Vec<Vec<Box<(u32, u32, u32, u32)>>>>,
+    /// }
+    /// ```
+    pub TYPE_COMPLEXITY,
+    complexity,
+    "usage of very complex types that might be better factored into `type` definitions"
+}
+
 pub struct Types {
     vec_box_size_threshold: u64,
+    type_complexity_threshold: u64,
 }
 
-impl_lint_pass!(Types => [BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION, RC_BUFFER]);
+impl_lint_pass!(Types => [BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION, RC_BUFFER, TYPE_COMPLEXITY]);
 
 impl<'tcx> LateLintPass<'tcx> for Types {
     fn check_fn(&mut self, cx: &LateContext<'_>, _: FnKind<'_>, decl: &FnDecl<'_>, _: &Body<'_>, _: Span, id: HirId) {
-        // Skip trait implementations; see issue #605.
-        if let Some(hir::Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_item(id)) {
-            if let ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = item.kind {
-                return;
-            }
+        let is_in_trait_impl = if let Some(hir::Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_item(id))
+        {
+            matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
+        } else {
+            false
+        };
+
+        self.check_fn_decl(
+            cx,
+            decl,
+            CheckTyContext {
+                is_in_trait_impl,
+                ..CheckTyContext::default()
+            },
+        );
+    }
+
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
+        match item.kind {
+            ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _) => self.check_ty(cx, ty, CheckTyContext::default()),
+            // functions, enums, structs, impls and traits are covered
+            _ => (),
         }
+    }
 
-        self.check_fn_decl(cx, decl);
+    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
+        match item.kind {
+            ImplItemKind::Const(ty, _) | ImplItemKind::TyAlias(ty) => self.check_ty(
+                cx,
+                ty,
+                CheckTyContext {
+                    is_in_trait_impl: true,
+                    ..CheckTyContext::default()
+                },
+            ),
+            // methods are covered by check_fn
+            ImplItemKind::Fn(..) => (),
+        }
     }
 
     fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
-        self.check_ty(cx, &field.ty, false);
+        self.check_ty(cx, field.ty, CheckTyContext::default());
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) {
         match item.kind {
-            TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => self.check_ty(cx, ty, false),
-            TraitItemKind::Fn(ref sig, _) => self.check_fn_decl(cx, &sig.decl),
+            TraitItemKind::Const(ty, _) | TraitItemKind::Type(_, Some(ty)) => {
+                self.check_ty(cx, ty, CheckTyContext::default())
+            },
+            TraitItemKind::Fn(ref sig, _) => self.check_fn_decl(cx, sig.decl, CheckTyContext::default()),
             TraitItemKind::Type(..) => (),
         }
     }
 
     fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
-        if let Some(ref ty) = local.ty {
-            self.check_ty(cx, ty, true);
+        if let Some(ty) = local.ty {
+            self.check_ty(
+                cx,
+                ty,
+                CheckTyContext {
+                    is_local: true,
+                    ..CheckTyContext::default()
+                },
+            );
         }
     }
 }
 
 impl Types {
-    pub fn new(vec_box_size_threshold: u64) -> Self {
-        Self { vec_box_size_threshold }
+    pub fn new(vec_box_size_threshold: u64, type_complexity_threshold: u64) -> Self {
+        Self {
+            vec_box_size_threshold,
+            type_complexity_threshold,
+        }
     }
 
-    fn check_fn_decl(&mut self, cx: &LateContext<'_>, decl: &FnDecl<'_>) {
+    fn check_fn_decl(&mut self, cx: &LateContext<'_>, decl: &FnDecl<'_>, context: CheckTyContext) {
         for input in decl.inputs {
-            self.check_ty(cx, input, false);
+            self.check_ty(cx, input, context);
         }
 
-        if let FnRetTy::Return(ref ty) = decl.output {
-            self.check_ty(cx, ty, false);
+        if let FnRetTy::Return(ty) = decl.output {
+            self.check_ty(cx, ty, context);
         }
     }
 
@@ -306,12 +349,22 @@ impl Types {
     /// lint found.
     ///
     /// The parameter `is_local` distinguishes the context of the type.
-    fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, is_local: bool) {
+    fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, mut context: CheckTyContext) {
         if hir_ty.span.from_expansion() {
             return;
         }
+
+        if !context.is_nested_call && type_complexity::check(cx, hir_ty, self.type_complexity_threshold) {
+            return;
+        }
+
+        // Skip trait implementations; see issue #605.
+        if context.is_in_trait_impl {
+            return;
+        }
+
         match hir_ty.kind {
-            TyKind::Path(ref qpath) if !is_local => {
+            TyKind::Path(ref qpath) if !context.is_local => {
                 let hir_id = hir_ty.hir_id;
                 let res = cx.qpath_res(qpath, hir_id);
                 if let Some(def_id) = res.opt_def_id() {
@@ -328,8 +381,9 @@ impl Types {
                     }
                 }
                 match *qpath {
-                    QPath::Resolved(Some(ref ty), ref p) => {
-                        self.check_ty(cx, ty, is_local);
+                    QPath::Resolved(Some(ty), p) => {
+                        context.is_nested_call = true;
+                        self.check_ty(cx, ty, context);
                         for ty in p.segments.iter().flat_map(|seg| {
                             seg.args
                                 .as_ref()
@@ -339,10 +393,11 @@ impl Types {
                                     _ => None,
                                 })
                         }) {
-                            self.check_ty(cx, ty, is_local);
+                            self.check_ty(cx, ty, context);
                         }
                     },
-                    QPath::Resolved(None, ref p) => {
+                    QPath::Resolved(None, p) => {
+                        context.is_nested_call = true;
                         for ty in p.segments.iter().flat_map(|seg| {
                             seg.args
                                 .as_ref()
@@ -352,17 +407,18 @@ impl Types {
                                     _ => None,
                                 })
                         }) {
-                            self.check_ty(cx, ty, is_local);
+                            self.check_ty(cx, ty, context);
                         }
                     },
-                    QPath::TypeRelative(ref ty, ref seg) => {
-                        self.check_ty(cx, ty, is_local);
-                        if let Some(ref params) = seg.args {
+                    QPath::TypeRelative(ty, seg) => {
+                        context.is_nested_call = true;
+                        self.check_ty(cx, ty, context);
+                        if let Some(params) = seg.args {
                             for ty in params.args.iter().filter_map(|arg| match arg {
                                 GenericArg::Type(ty) => Some(ty),
                                 _ => None,
                             }) {
-                                self.check_ty(cx, ty, is_local);
+                                self.check_ty(cx, ty, context);
                             }
                         }
                     },
@@ -370,16 +426,19 @@ impl Types {
                 }
             },
             TyKind::Rptr(ref lt, ref mut_ty) => {
+                context.is_nested_call = true;
                 if !borrowed_box::check(cx, hir_ty, lt, mut_ty) {
-                    self.check_ty(cx, &mut_ty.ty, is_local);
+                    self.check_ty(cx, mut_ty.ty, context);
                 }
             },
-            TyKind::Slice(ref ty) | TyKind::Array(ref ty, _) | TyKind::Ptr(MutTy { ref ty, .. }) => {
-                self.check_ty(cx, ty, is_local)
+            TyKind::Slice(ty) | TyKind::Array(ty, _) | TyKind::Ptr(MutTy { ty, .. }) => {
+                context.is_nested_call = true;
+                self.check_ty(cx, ty, context)
             },
             TyKind::Tup(tys) => {
+                context.is_nested_call = true;
                 for ty in tys {
-                    self.check_ty(cx, ty, is_local);
+                    self.check_ty(cx, ty, context);
                 }
             },
             _ => {},
@@ -387,895 +446,9 @@ impl Types {
     }
 }
 
-declare_clippy_lint! {
-    /// **What it does:** Checks for types used in structs, parameters and `let`
-    /// declarations above a certain complexity threshold.
-    ///
-    /// **Why is this bad?** Too complex types make the code less readable. Consider
-    /// using a `type` definition to simplify them.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    /// ```rust
-    /// # use std::rc::Rc;
-    /// struct Foo {
-    ///     inner: Rc<Vec<Vec<Box<(u32, u32, u32, u32)>>>>,
-    /// }
-    /// ```
-    pub TYPE_COMPLEXITY,
-    complexity,
-    "usage of very complex types that might be better factored into `type` definitions"
-}
-
-pub struct TypeComplexity {
-    threshold: u64,
-}
-
-impl TypeComplexity {
-    #[must_use]
-    pub fn new(threshold: u64) -> Self {
-        Self { threshold }
-    }
-}
-
-impl_lint_pass!(TypeComplexity => [TYPE_COMPLEXITY]);
-
-impl<'tcx> LateLintPass<'tcx> for TypeComplexity {
-    fn check_fn(
-        &mut self,
-        cx: &LateContext<'tcx>,
-        _: FnKind<'tcx>,
-        decl: &'tcx FnDecl<'_>,
-        _: &'tcx Body<'_>,
-        _: Span,
-        _: HirId,
-    ) {
-        self.check_fndecl(cx, decl);
-    }
-
-    fn check_field_def(&mut self, cx: &LateContext<'tcx>, field: &'tcx hir::FieldDef<'_>) {
-        // enum variants are also struct fields now
-        self.check_type(cx, &field.ty);
-    }
-
-    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        match item.kind {
-            ItemKind::Static(ref ty, _, _) | ItemKind::Const(ref ty, _) => self.check_type(cx, ty),
-            // functions, enums, structs, impls and traits are covered
-            _ => (),
-        }
-    }
-
-    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
-        match item.kind {
-            TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => self.check_type(cx, ty),
-            TraitItemKind::Fn(FnSig { ref decl, .. }, TraitFn::Required(_)) => self.check_fndecl(cx, decl),
-            // methods with default impl are covered by check_fn
-            TraitItemKind::Type(..) | TraitItemKind::Fn(_, TraitFn::Provided(_)) => (),
-        }
-    }
-
-    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
-        match item.kind {
-            ImplItemKind::Const(ref ty, _) | ImplItemKind::TyAlias(ref ty) => self.check_type(cx, ty),
-            // methods are covered by check_fn
-            ImplItemKind::Fn(..) => (),
-        }
-    }
-
-    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
-        if let Some(ref ty) = local.ty {
-            self.check_type(cx, ty);
-        }
-    }
-}
-
-impl<'tcx> TypeComplexity {
-    fn check_fndecl(&self, cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'_>) {
-        for arg in decl.inputs {
-            self.check_type(cx, arg);
-        }
-        if let FnRetTy::Return(ref ty) = decl.output {
-            self.check_type(cx, ty);
-        }
-    }
-
-    fn check_type(&self, cx: &LateContext<'_>, ty: &hir::Ty<'_>) {
-        if ty.span.from_expansion() {
-            return;
-        }
-        let score = {
-            let mut visitor = TypeComplexityVisitor { score: 0, nest: 1 };
-            visitor.visit_ty(ty);
-            visitor.score
-        };
-
-        if score > self.threshold {
-            span_lint(
-                cx,
-                TYPE_COMPLEXITY,
-                ty.span,
-                "very complex type used. Consider factoring parts into `type` definitions",
-            );
-        }
-    }
-}
-
-/// Walks a type and assigns a complexity score to it.
-struct TypeComplexityVisitor {
-    /// total complexity score of the type
-    score: u64,
-    /// current nesting level
-    nest: u64,
-}
-
-impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor {
-    type Map = Map<'tcx>;
-
-    fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) {
-        let (add_score, sub_nest) = match ty.kind {
-            // _, &x and *x have only small overhead; don't mess with nesting level
-            TyKind::Infer | TyKind::Ptr(..) | TyKind::Rptr(..) => (1, 0),
-
-            // the "normal" components of a type: named types, arrays/tuples
-            TyKind::Path(..) | TyKind::Slice(..) | TyKind::Tup(..) | TyKind::Array(..) => (10 * self.nest, 1),
-
-            // function types bring a lot of overhead
-            TyKind::BareFn(ref bare) if bare.abi == Abi::Rust => (50 * self.nest, 1),
-
-            TyKind::TraitObject(ref param_bounds, _, _) => {
-                let has_lifetime_parameters = param_bounds.iter().any(|bound| {
-                    bound
-                        .bound_generic_params
-                        .iter()
-                        .any(|gen| matches!(gen.kind, GenericParamKind::Lifetime { .. }))
-                });
-                if has_lifetime_parameters {
-                    // complex trait bounds like A<'a, 'b>
-                    (50 * self.nest, 1)
-                } else {
-                    // simple trait bounds like A + B
-                    (20 * self.nest, 0)
-                }
-            },
-
-            _ => (0, 0),
-        };
-        self.score += add_score;
-        self.nest += sub_nest;
-        walk_ty(self, ty);
-        self.nest -= sub_nest;
-    }
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-}
-
-declare_clippy_lint! {
-    /// **What it does:** Checks for comparisons where one side of the relation is
-    /// either the minimum or maximum value for its type and warns if it involves a
-    /// case that is always true or always false. Only integer and boolean types are
-    /// checked.
-    ///
-    /// **Why is this bad?** An expression like `min <= x` may misleadingly imply
-    /// that it is possible for `x` to be less than the minimum. Expressions like
-    /// `max < x` are probably mistakes.
-    ///
-    /// **Known problems:** For `usize` the size of the current compile target will
-    /// be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such
-    /// a comparison to detect target pointer width will trigger this lint. One can
-    /// use `mem::sizeof` and compare its value or conditional compilation
-    /// attributes
-    /// like `#[cfg(target_pointer_width = "64")] ..` instead.
-    ///
-    /// **Example:**
-    ///
-    /// ```rust
-    /// let vec: Vec<isize> = Vec::new();
-    /// if vec.len() <= 0 {}
-    /// if 100 > i32::MAX {}
-    /// ```
-    pub ABSURD_EXTREME_COMPARISONS,
-    correctness,
-    "a comparison with a maximum or minimum value that is always true or false"
-}
-
-declare_lint_pass!(AbsurdExtremeComparisons => [ABSURD_EXTREME_COMPARISONS]);
-
-enum ExtremeType {
-    Minimum,
-    Maximum,
-}
-
-struct ExtremeExpr<'a> {
-    which: ExtremeType,
-    expr: &'a Expr<'a>,
-}
-
-enum AbsurdComparisonResult {
-    AlwaysFalse,
-    AlwaysTrue,
-    InequalityImpossible,
-}
-
-fn is_cast_between_fixed_and_target<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
-    if let ExprKind::Cast(ref cast_exp, _) = expr.kind {
-        let precast_ty = cx.typeck_results().expr_ty(cast_exp);
-        let cast_ty = cx.typeck_results().expr_ty(expr);
-
-        return is_isize_or_usize(precast_ty) != is_isize_or_usize(cast_ty);
-    }
-
-    false
-}
-
-fn detect_absurd_comparison<'tcx>(
-    cx: &LateContext<'tcx>,
-    op: BinOpKind,
-    lhs: &'tcx Expr<'_>,
-    rhs: &'tcx Expr<'_>,
-) -> Option<(ExtremeExpr<'tcx>, AbsurdComparisonResult)> {
-    use crate::types::AbsurdComparisonResult::{AlwaysFalse, AlwaysTrue, InequalityImpossible};
-    use crate::types::ExtremeType::{Maximum, Minimum};
-    use clippy_utils::comparisons::{normalize_comparison, Rel};
-
-    // absurd comparison only makes sense on primitive types
-    // primitive types don't implement comparison operators with each other
-    if cx.typeck_results().expr_ty(lhs) != cx.typeck_results().expr_ty(rhs) {
-        return None;
-    }
-
-    // comparisons between fix sized types and target sized types are considered unanalyzable
-    if is_cast_between_fixed_and_target(cx, lhs) || is_cast_between_fixed_and_target(cx, rhs) {
-        return None;
-    }
-
-    let (rel, normalized_lhs, normalized_rhs) = normalize_comparison(op, lhs, rhs)?;
-
-    let lx = detect_extreme_expr(cx, normalized_lhs);
-    let rx = detect_extreme_expr(cx, normalized_rhs);
-
-    Some(match rel {
-        Rel::Lt => {
-            match (lx, rx) {
-                (Some(l @ ExtremeExpr { which: Maximum, .. }), _) => (l, AlwaysFalse), // max < x
-                (_, Some(r @ ExtremeExpr { which: Minimum, .. })) => (r, AlwaysFalse), // x < min
-                _ => return None,
-            }
-        },
-        Rel::Le => {
-            match (lx, rx) {
-                (Some(l @ ExtremeExpr { which: Minimum, .. }), _) => (l, AlwaysTrue), // min <= x
-                (Some(l @ ExtremeExpr { which: Maximum, .. }), _) => (l, InequalityImpossible), // max <= x
-                (_, Some(r @ ExtremeExpr { which: Minimum, .. })) => (r, InequalityImpossible), // x <= min
-                (_, Some(r @ ExtremeExpr { which: Maximum, .. })) => (r, AlwaysTrue), // x <= max
-                _ => return None,
-            }
-        },
-        Rel::Ne | Rel::Eq => return None,
-    })
-}
-
-fn detect_extreme_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<ExtremeExpr<'tcx>> {
-    use crate::types::ExtremeType::{Maximum, Minimum};
-
-    let ty = cx.typeck_results().expr_ty(expr);
-
-    let cv = constant(cx, cx.typeck_results(), expr)?.0;
-
-    let which = match (ty.kind(), cv) {
-        (&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => Minimum,
-        (&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MIN >> (128 - int_bits(cx.tcx, ity)), ity) => {
-            Minimum
-        },
-
-        (&ty::Bool, Constant::Bool(true)) => Maximum,
-        (&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MAX >> (128 - int_bits(cx.tcx, ity)), ity) => {
-            Maximum
-        },
-        (&ty::Uint(uty), Constant::Int(i)) if clip(cx.tcx, u128::MAX, uty) == i => Maximum,
-
-        _ => return None,
-    };
-    Some(ExtremeExpr { which, expr })
-}
-
-impl<'tcx> LateLintPass<'tcx> for AbsurdExtremeComparisons {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        use crate::types::AbsurdComparisonResult::{AlwaysFalse, AlwaysTrue, InequalityImpossible};
-        use crate::types::ExtremeType::{Maximum, Minimum};
-
-        if let ExprKind::Binary(ref cmp, ref lhs, ref rhs) = expr.kind {
-            if let Some((culprit, result)) = detect_absurd_comparison(cx, cmp.node, lhs, rhs) {
-                if !expr.span.from_expansion() {
-                    let msg = "this comparison involving the minimum or maximum element for this \
-                               type contains a case that is always true or always false";
-
-                    let conclusion = match result {
-                        AlwaysFalse => "this comparison is always false".to_owned(),
-                        AlwaysTrue => "this comparison is always true".to_owned(),
-                        InequalityImpossible => format!(
-                            "the case where the two sides are not equal never occurs, consider using `{} == {}` \
-                             instead",
-                            snippet(cx, lhs.span, "lhs"),
-                            snippet(cx, rhs.span, "rhs")
-                        ),
-                    };
-
-                    let help = format!(
-                        "because `{}` is the {} value for this type, {}",
-                        snippet(cx, culprit.expr.span, "x"),
-                        match culprit.which {
-                            Minimum => "minimum",
-                            Maximum => "maximum",
-                        },
-                        conclusion
-                    );
-
-                    span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, &help);
-                }
-            }
-        }
-    }
-}
-
-declare_clippy_lint! {
-    /// **What it does:** Checks for comparisons where the relation is always either
-    /// true or false, but where one side has been upcast so that the comparison is
-    /// necessary. Only integer types are checked.
-    ///
-    /// **Why is this bad?** An expression like `let x : u8 = ...; (x as u32) > 300`
-    /// will mistakenly imply that it is possible for `x` to be outside the range of
-    /// `u8`.
-    ///
-    /// **Known problems:**
-    /// https://github.com/rust-lang/rust-clippy/issues/886
-    ///
-    /// **Example:**
-    /// ```rust
-    /// let x: u8 = 1;
-    /// (x as u32) > 300;
-    /// ```
-    pub INVALID_UPCAST_COMPARISONS,
-    pedantic,
-    "a comparison involving an upcast which is always true or false"
-}
-
-declare_lint_pass!(InvalidUpcastComparisons => [INVALID_UPCAST_COMPARISONS]);
-
-#[derive(Copy, Clone, Debug, Eq)]
-enum FullInt {
-    S(i128),
-    U(u128),
-}
-
-impl FullInt {
-    #[allow(clippy::cast_sign_loss)]
-    #[must_use]
-    fn cmp_s_u(s: i128, u: u128) -> Ordering {
-        if s < 0 {
-            Ordering::Less
-        } else if u > (i128::MAX as u128) {
-            Ordering::Greater
-        } else {
-            (s as u128).cmp(&u)
-        }
-    }
-}
-
-impl PartialEq for FullInt {
-    #[must_use]
-    fn eq(&self, other: &Self) -> bool {
-        self.partial_cmp(other).expect("`partial_cmp` only returns `Some(_)`") == Ordering::Equal
-    }
-}
-
-impl PartialOrd for FullInt {
-    #[must_use]
-    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        Some(match (self, other) {
-            (&Self::S(s), &Self::S(o)) => s.cmp(&o),
-            (&Self::U(s), &Self::U(o)) => s.cmp(&o),
-            (&Self::S(s), &Self::U(o)) => Self::cmp_s_u(s, o),
-            (&Self::U(s), &Self::S(o)) => Self::cmp_s_u(o, s).reverse(),
-        })
-    }
-}
-
-impl Ord for FullInt {
-    #[must_use]
-    fn cmp(&self, other: &Self) -> Ordering {
-        self.partial_cmp(other)
-            .expect("`partial_cmp` for FullInt can never return `None`")
-    }
-}
-
-fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> {
-    if let ExprKind::Cast(ref cast_exp, _) = expr.kind {
-        let pre_cast_ty = cx.typeck_results().expr_ty(cast_exp);
-        let cast_ty = cx.typeck_results().expr_ty(expr);
-        // if it's a cast from i32 to u32 wrapping will invalidate all these checks
-        if cx.layout_of(pre_cast_ty).ok().map(|l| l.size) == cx.layout_of(cast_ty).ok().map(|l| l.size) {
-            return None;
-        }
-        match pre_cast_ty.kind() {
-            ty::Int(int_ty) => Some(match int_ty {
-                IntTy::I8 => (FullInt::S(i128::from(i8::MIN)), FullInt::S(i128::from(i8::MAX))),
-                IntTy::I16 => (FullInt::S(i128::from(i16::MIN)), FullInt::S(i128::from(i16::MAX))),
-                IntTy::I32 => (FullInt::S(i128::from(i32::MIN)), FullInt::S(i128::from(i32::MAX))),
-                IntTy::I64 => (FullInt::S(i128::from(i64::MIN)), FullInt::S(i128::from(i64::MAX))),
-                IntTy::I128 => (FullInt::S(i128::MIN), FullInt::S(i128::MAX)),
-                IntTy::Isize => (FullInt::S(isize::MIN as i128), FullInt::S(isize::MAX as i128)),
-            }),
-            ty::Uint(uint_ty) => Some(match uint_ty {
-                UintTy::U8 => (FullInt::U(u128::from(u8::MIN)), FullInt::U(u128::from(u8::MAX))),
-                UintTy::U16 => (FullInt::U(u128::from(u16::MIN)), FullInt::U(u128::from(u16::MAX))),
-                UintTy::U32 => (FullInt::U(u128::from(u32::MIN)), FullInt::U(u128::from(u32::MAX))),
-                UintTy::U64 => (FullInt::U(u128::from(u64::MIN)), FullInt::U(u128::from(u64::MAX))),
-                UintTy::U128 => (FullInt::U(u128::MIN), FullInt::U(u128::MAX)),
-                UintTy::Usize => (FullInt::U(usize::MIN as u128), FullInt::U(usize::MAX as u128)),
-            }),
-            _ => None,
-        }
-    } else {
-        None
-    }
-}
-
-fn node_as_const_fullint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<FullInt> {
-    let val = constant(cx, cx.typeck_results(), expr)?.0;
-    if let Constant::Int(const_int) = val {
-        match *cx.typeck_results().expr_ty(expr).kind() {
-            ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
-            ty::Uint(_) => Some(FullInt::U(const_int)),
-            _ => None,
-        }
-    } else {
-        None
-    }
-}
-
-fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, always: bool) {
-    if let ExprKind::Cast(ref cast_val, _) = expr.kind {
-        span_lint(
-            cx,
-            INVALID_UPCAST_COMPARISONS,
-            span,
-            &format!(
-                "because of the numeric bounds on `{}` prior to casting, this expression is always {}",
-                snippet(cx, cast_val.span, "the expression"),
-                if always { "true" } else { "false" },
-            ),
-        );
-    }
-}
-
-fn upcast_comparison_bounds_err<'tcx>(
-    cx: &LateContext<'tcx>,
-    span: Span,
-    rel: comparisons::Rel,
-    lhs_bounds: Option<(FullInt, FullInt)>,
-    lhs: &'tcx Expr<'_>,
-    rhs: &'tcx Expr<'_>,
-    invert: bool,
-) {
-    use clippy_utils::comparisons::Rel;
-
-    if let Some((lb, ub)) = lhs_bounds {
-        if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) {
-            if rel == Rel::Eq || rel == Rel::Ne {
-                if norm_rhs_val < lb || norm_rhs_val > ub {
-                    err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);
-                }
-            } else if match rel {
-                Rel::Lt => {
-                    if invert {
-                        norm_rhs_val < lb
-                    } else {
-                        ub < norm_rhs_val
-                    }
-                },
-                Rel::Le => {
-                    if invert {
-                        norm_rhs_val <= lb
-                    } else {
-                        ub <= norm_rhs_val
-                    }
-                },
-                Rel::Eq | Rel::Ne => unreachable!(),
-            } {
-                err_upcast_comparison(cx, span, lhs, true)
-            } else if match rel {
-                Rel::Lt => {
-                    if invert {
-                        norm_rhs_val >= ub
-                    } else {
-                        lb >= norm_rhs_val
-                    }
-                },
-                Rel::Le => {
-                    if invert {
-                        norm_rhs_val > ub
-                    } else {
-                        lb > norm_rhs_val
-                    }
-                },
-                Rel::Eq | Rel::Ne => unreachable!(),
-            } {
-                err_upcast_comparison(cx, span, lhs, false)
-            }
-        }
-    }
-}
-
-impl<'tcx> LateLintPass<'tcx> for InvalidUpcastComparisons {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let ExprKind::Binary(ref cmp, ref lhs, ref rhs) = expr.kind {
-            let normalized = comparisons::normalize_comparison(cmp.node, lhs, rhs);
-            let (rel, normalized_lhs, normalized_rhs) = if let Some(val) = normalized {
-                val
-            } else {
-                return;
-            };
-
-            let lhs_bounds = numeric_cast_precast_bounds(cx, normalized_lhs);
-            let rhs_bounds = numeric_cast_precast_bounds(cx, normalized_rhs);
-
-            upcast_comparison_bounds_err(cx, expr.span, rel, lhs_bounds, normalized_lhs, normalized_rhs, false);
-            upcast_comparison_bounds_err(cx, expr.span, rel, rhs_bounds, normalized_rhs, normalized_lhs, true);
-        }
-    }
-}
-
-declare_clippy_lint! {
-    /// **What it does:** Checks for public `impl` or `fn` missing generalization
-    /// over different hashers and implicitly defaulting to the default hashing
-    /// algorithm (`SipHash`).
-    ///
-    /// **Why is this bad?** `HashMap` or `HashSet` with custom hashers cannot be
-    /// used with them.
-    ///
-    /// **Known problems:** Suggestions for replacing constructors can contain
-    /// false-positives. Also applying suggestions can require modification of other
-    /// pieces of code, possibly including external crates.
-    ///
-    /// **Example:**
-    /// ```rust
-    /// # use std::collections::HashMap;
-    /// # use std::hash::{Hash, BuildHasher};
-    /// # trait Serialize {};
-    /// impl<K: Hash + Eq, V> Serialize for HashMap<K, V> { }
-    ///
-    /// pub fn foo(map: &mut HashMap<i32, i32>) { }
-    /// ```
-    /// could be rewritten as
-    /// ```rust
-    /// # use std::collections::HashMap;
-    /// # use std::hash::{Hash, BuildHasher};
-    /// # trait Serialize {};
-    /// impl<K: Hash + Eq, V, S: BuildHasher> Serialize for HashMap<K, V, S> { }
-    ///
-    /// pub fn foo<S: BuildHasher>(map: &mut HashMap<i32, i32, S>) { }
-    /// ```
-    pub IMPLICIT_HASHER,
-    pedantic,
-    "missing generalization over different hashers"
-}
-
-declare_lint_pass!(ImplicitHasher => [IMPLICIT_HASHER]);
-
-impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
-    #[allow(clippy::cast_possible_truncation, clippy::too_many_lines)]
-    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        use rustc_span::BytePos;
-
-        fn suggestion<'tcx>(
-            cx: &LateContext<'tcx>,
-            diag: &mut DiagnosticBuilder<'_>,
-            generics_span: Span,
-            generics_suggestion_span: Span,
-            target: &ImplicitHasherType<'_>,
-            vis: ImplicitHasherConstructorVisitor<'_, '_, '_>,
-        ) {
-            let generics_snip = snippet(cx, generics_span, "");
-            // trim `<` `>`
-            let generics_snip = if generics_snip.is_empty() {
-                ""
-            } else {
-                &generics_snip[1..generics_snip.len() - 1]
-            };
-
-            multispan_sugg(
-                diag,
-                "consider adding a type parameter",
-                vec![
-                    (
-                        generics_suggestion_span,
-                        format!(
-                            "<{}{}S: ::std::hash::BuildHasher{}>",
-                            generics_snip,
-                            if generics_snip.is_empty() { "" } else { ", " },
-                            if vis.suggestions.is_empty() {
-                                ""
-                            } else {
-                                // request users to add `Default` bound so that generic constructors can be used
-                                " + Default"
-                            },
-                        ),
-                    ),
-                    (
-                        target.span(),
-                        format!("{}<{}, S>", target.type_name(), target.type_arguments(),),
-                    ),
-                ],
-            );
-
-            if !vis.suggestions.is_empty() {
-                multispan_sugg(diag, "...and use generic constructor", vis.suggestions);
-            }
-        }
-
-        if !cx.access_levels.is_exported(item.hir_id()) {
-            return;
-        }
-
-        match item.kind {
-            ItemKind::Impl(ref impl_) => {
-                let mut vis = ImplicitHasherTypeVisitor::new(cx);
-                vis.visit_ty(impl_.self_ty);
-
-                for target in &vis.found {
-                    if differing_macro_contexts(item.span, target.span()) {
-                        return;
-                    }
-
-                    let generics_suggestion_span = impl_.generics.span.substitute_dummy({
-                        let pos = snippet_opt(cx, item.span.until(target.span()))
-                            .and_then(|snip| Some(item.span.lo() + BytePos(snip.find("impl")? as u32 + 4)));
-                        if let Some(pos) = pos {
-                            Span::new(pos, pos, item.span.data().ctxt)
-                        } else {
-                            return;
-                        }
-                    });
-
-                    let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
-                    for item in impl_.items.iter().map(|item| cx.tcx.hir().impl_item(item.id)) {
-                        ctr_vis.visit_impl_item(item);
-                    }
-
-                    span_lint_and_then(
-                        cx,
-                        IMPLICIT_HASHER,
-                        target.span(),
-                        &format!(
-                            "impl for `{}` should be generalized over different hashers",
-                            target.type_name()
-                        ),
-                        move |diag| {
-                            suggestion(cx, diag, impl_.generics.span, generics_suggestion_span, target, ctr_vis);
-                        },
-                    );
-                }
-            },
-            ItemKind::Fn(ref sig, ref generics, body_id) => {
-                let body = cx.tcx.hir().body(body_id);
-
-                for ty in sig.decl.inputs {
-                    let mut vis = ImplicitHasherTypeVisitor::new(cx);
-                    vis.visit_ty(ty);
-
-                    for target in &vis.found {
-                        if in_external_macro(cx.sess(), generics.span) {
-                            continue;
-                        }
-                        let generics_suggestion_span = generics.span.substitute_dummy({
-                            let pos = snippet_opt(cx, item.span.until(body.params[0].pat.span))
-                                .and_then(|snip| {
-                                    let i = snip.find("fn")?;
-                                    Some(item.span.lo() + BytePos((i + (&snip[i..]).find('(')?) as u32))
-                                })
-                                .expect("failed to create span for type parameters");
-                            Span::new(pos, pos, item.span.data().ctxt)
-                        });
-
-                        let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
-                        ctr_vis.visit_body(body);
-
-                        span_lint_and_then(
-                            cx,
-                            IMPLICIT_HASHER,
-                            target.span(),
-                            &format!(
-                                "parameter of type `{}` should be generalized over different hashers",
-                                target.type_name()
-                            ),
-                            move |diag| {
-                                suggestion(cx, diag, generics.span, generics_suggestion_span, target, ctr_vis);
-                            },
-                        );
-                    }
-                }
-            },
-            _ => {},
-        }
-    }
-}
-
-enum ImplicitHasherType<'tcx> {
-    HashMap(Span, Ty<'tcx>, Cow<'static, str>, Cow<'static, str>),
-    HashSet(Span, Ty<'tcx>, Cow<'static, str>),
-}
-
-impl<'tcx> ImplicitHasherType<'tcx> {
-    /// Checks that `ty` is a target type without a `BuildHasher`.
-    fn new(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'_>) -> Option<Self> {
-        if let TyKind::Path(QPath::Resolved(None, ref path)) = hir_ty.kind {
-            let params: Vec<_> = path
-                .segments
-                .last()
-                .as_ref()?
-                .args
-                .as_ref()?
-                .args
-                .iter()
-                .filter_map(|arg| match arg {
-                    GenericArg::Type(ty) => Some(ty),
-                    _ => None,
-                })
-                .collect();
-            let params_len = params.len();
-
-            let ty = hir_ty_to_ty(cx.tcx, hir_ty);
-
-            if is_type_diagnostic_item(cx, ty, sym::hashmap_type) && params_len == 2 {
-                Some(ImplicitHasherType::HashMap(
-                    hir_ty.span,
-                    ty,
-                    snippet(cx, params[0].span, "K"),
-                    snippet(cx, params[1].span, "V"),
-                ))
-            } else if is_type_diagnostic_item(cx, ty, sym::hashset_type) && params_len == 1 {
-                Some(ImplicitHasherType::HashSet(
-                    hir_ty.span,
-                    ty,
-                    snippet(cx, params[0].span, "T"),
-                ))
-            } else {
-                None
-            }
-        } else {
-            None
-        }
-    }
-
-    fn type_name(&self) -> &'static str {
-        match *self {
-            ImplicitHasherType::HashMap(..) => "HashMap",
-            ImplicitHasherType::HashSet(..) => "HashSet",
-        }
-    }
-
-    fn type_arguments(&self) -> String {
-        match *self {
-            ImplicitHasherType::HashMap(.., ref k, ref v) => format!("{}, {}", k, v),
-            ImplicitHasherType::HashSet(.., ref t) => format!("{}", t),
-        }
-    }
-
-    fn ty(&self) -> Ty<'tcx> {
-        match *self {
-            ImplicitHasherType::HashMap(_, ty, ..) | ImplicitHasherType::HashSet(_, ty, ..) => ty,
-        }
-    }
-
-    fn span(&self) -> Span {
-        match *self {
-            ImplicitHasherType::HashMap(span, ..) | ImplicitHasherType::HashSet(span, ..) => span,
-        }
-    }
-}
-
-struct ImplicitHasherTypeVisitor<'a, 'tcx> {
-    cx: &'a LateContext<'tcx>,
-    found: Vec<ImplicitHasherType<'tcx>>,
-}
-
-impl<'a, 'tcx> ImplicitHasherTypeVisitor<'a, 'tcx> {
-    fn new(cx: &'a LateContext<'tcx>) -> Self {
-        Self { cx, found: vec![] }
-    }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
-    fn visit_ty(&mut self, t: &'tcx hir::Ty<'_>) {
-        if let Some(target) = ImplicitHasherType::new(self.cx, t) {
-            self.found.push(target);
-        }
-
-        walk_ty(self, t);
-    }
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-}
-
-/// Looks for default-hasher-dependent constructors like `HashMap::new`.
-struct ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
-    cx: &'a LateContext<'tcx>,
-    maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
-    target: &'b ImplicitHasherType<'tcx>,
-    suggestions: BTreeMap<Span, String>,
-}
-
-impl<'a, 'b, 'tcx> ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
-    fn new(cx: &'a LateContext<'tcx>, target: &'b ImplicitHasherType<'tcx>) -> Self {
-        Self {
-            cx,
-            maybe_typeck_results: cx.maybe_typeck_results(),
-            target,
-            suggestions: BTreeMap::new(),
-        }
-    }
-}
-
-impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
-    type Map = Map<'tcx>;
-
-    fn visit_body(&mut self, body: &'tcx Body<'_>) {
-        let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body.id()));
-        walk_body(self, body);
-        self.maybe_typeck_results = old_maybe_typeck_results;
-    }
-
-    fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
-        if_chain! {
-            if let ExprKind::Call(ref fun, ref args) = e.kind;
-            if let ExprKind::Path(QPath::TypeRelative(ref ty, ref method)) = fun.kind;
-            if let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind;
-            then {
-                if !TyS::same_type(self.target.ty(), self.maybe_typeck_results.unwrap().expr_ty(e)) {
-                    return;
-                }
-
-                if match_path(ty_path, &paths::HASHMAP) {
-                    if method.ident.name == sym::new {
-                        self.suggestions
-                            .insert(e.span, "HashMap::default()".to_string());
-                    } else if method.ident.name == sym!(with_capacity) {
-                        self.suggestions.insert(
-                            e.span,
-                            format!(
-                                "HashMap::with_capacity_and_hasher({}, Default::default())",
-                                snippet(self.cx, args[0].span, "capacity"),
-                            ),
-                        );
-                    }
-                } else if match_path(ty_path, &paths::HASHSET) {
-                    if method.ident.name == sym::new {
-                        self.suggestions
-                            .insert(e.span, "HashSet::default()".to_string());
-                    } else if method.ident.name == sym!(with_capacity) {
-                        self.suggestions.insert(
-                            e.span,
-                            format!(
-                                "HashSet::with_capacity_and_hasher({}, Default::default())",
-                                snippet(self.cx, args[0].span, "capacity"),
-                            ),
-                        );
-                    }
-                }
-            }
-        }
-
-        walk_expr(self, e);
-    }
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
-    }
+#[derive(Clone, Copy, Default)]
+struct CheckTyContext {
+    is_in_trait_impl: bool,
+    is_local: bool,
+    is_nested_call: bool,
 }
diff --git a/src/tools/clippy/clippy_lints/src/types/type_complexity.rs b/src/tools/clippy/clippy_lints/src/types/type_complexity.rs
new file mode 100644
index 00000000000..d8c4b67520d
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/types/type_complexity.rs
@@ -0,0 +1,79 @@
+use clippy_utils::diagnostics::span_lint;
+use rustc_hir as hir;
+use rustc_hir::intravisit::{walk_ty, NestedVisitorMap, Visitor};
+use rustc_hir::{GenericParamKind, TyKind};
+use rustc_lint::LateContext;
+use rustc_middle::hir::map::Map;
+use rustc_target::spec::abi::Abi;
+
+use super::TYPE_COMPLEXITY;
+
+pub(super) fn check(cx: &LateContext<'_>, ty: &hir::Ty<'_>, type_complexity_threshold: u64) -> bool {
+    let score = {
+        let mut visitor = TypeComplexityVisitor { score: 0, nest: 1 };
+        visitor.visit_ty(ty);
+        visitor.score
+    };
+
+    if score > type_complexity_threshold {
+        span_lint(
+            cx,
+            TYPE_COMPLEXITY,
+            ty.span,
+            "very complex type used. Consider factoring parts into `type` definitions",
+        );
+        true
+    } else {
+        false
+    }
+}
+
+/// Walks a type and assigns a complexity score to it.
+struct TypeComplexityVisitor {
+    /// total complexity score of the type
+    score: u64,
+    /// current nesting level
+    nest: u64,
+}
+
+impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor {
+    type Map = Map<'tcx>;
+
+    fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) {
+        let (add_score, sub_nest) = match ty.kind {
+            // _, &x and *x have only small overhead; don't mess with nesting level
+            TyKind::Infer | TyKind::Ptr(..) | TyKind::Rptr(..) => (1, 0),
+
+            // the "normal" components of a type: named types, arrays/tuples
+            TyKind::Path(..) | TyKind::Slice(..) | TyKind::Tup(..) | TyKind::Array(..) => (10 * self.nest, 1),
+
+            // function types bring a lot of overhead
+            TyKind::BareFn(bare) if bare.abi == Abi::Rust => (50 * self.nest, 1),
+
+            TyKind::TraitObject(param_bounds, _, _) => {
+                let has_lifetime_parameters = param_bounds.iter().any(|bound| {
+                    bound
+                        .bound_generic_params
+                        .iter()
+                        .any(|gen| matches!(gen.kind, GenericParamKind::Lifetime { .. }))
+                });
+                if has_lifetime_parameters {
+                    // complex trait bounds like A<'a, 'b>
+                    (50 * self.nest, 1)
+                } else {
+                    // simple trait bounds like A + B
+                    (20 * self.nest, 0)
+                }
+            },
+
+            _ => (0, 0),
+        };
+        self.score += add_score;
+        self.nest += sub_nest;
+        walk_ty(self, ty);
+        self.nest -= sub_nest;
+    }
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::None
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/types/utils.rs b/src/tools/clippy/clippy_lints/src/types/utils.rs
index 45f891ed718..0fa75f8f0a9 100644
--- a/src/tools/clippy/clippy_lints/src/types/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/types/utils.rs
@@ -7,7 +7,7 @@ use rustc_span::source_map::Span;
 pub(super) fn match_borrows_parameter(_cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<Span> {
     let last = last_path_segment(qpath);
     if_chain! {
-        if let Some(ref params) = last.args;
+        if let Some(params) = last.args;
         if !params.parenthesized;
         if let Some(ty) = params.args.iter().find_map(|arg| match arg {
             GenericArg::Type(ty) => Some(ty),
diff --git a/src/tools/clippy/clippy_lints/src/types/vec_box.rs b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
index d2c373db261..7a444174626 100644
--- a/src/tools/clippy/clippy_lints/src/types/vec_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
@@ -22,7 +22,7 @@ pub(super) fn check(
     if cx.tcx.is_diagnostic_item(sym::vec_type, def_id) {
         if_chain! {
             // Get the _ part of Vec<_>
-            if let Some(ref last) = last_path_segment(qpath).args;
+            if let Some(last) = last_path_segment(qpath).args;
             if let Some(ty) = last.args.iter().find_map(|arg| match arg {
                 GenericArg::Type(ty) => Some(ty),
                 _ => None,
@@ -33,7 +33,7 @@ pub(super) fn check(
             if let Some(def_id) = res.opt_def_id();
             if Some(def_id) == cx.tcx.lang_items().owned_box();
             // At this point, we know ty is Box<T>, now get T
-            if let Some(ref last) = last_path_segment(ty_qpath).args;
+            if let Some(last) = last_path_segment(ty_qpath).args;
             if let Some(boxed_ty) = last.args.iter().find_map(|arg| match arg {
                 GenericArg::Type(ty) => Some(ty),
                 _ => None,
diff --git a/src/tools/clippy/clippy_lints/src/undropped_manually_drops.rs b/src/tools/clippy/clippy_lints/src/undropped_manually_drops.rs
index b6749069176..f4f5e1233e3 100644
--- a/src/tools/clippy/clippy_lints/src/undropped_manually_drops.rs
+++ b/src/tools/clippy/clippy_lints/src/undropped_manually_drops.rs
@@ -35,7 +35,7 @@ declare_lint_pass!(UndroppedManuallyDrops => [UNDROPPED_MANUALLY_DROPS]);
 
 impl LateLintPass<'tcx> for UndroppedManuallyDrops {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let Some(ref args) = match_function_call(cx, expr, &paths::DROP) {
+        if let Some(args) = match_function_call(cx, expr, &paths::DROP) {
             let ty = cx.typeck_results().expr_ty(&args[0]);
             if is_type_lang_item(cx, ty, lang_items::LangItem::ManuallyDrop) {
                 span_lint_and_help(
diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
index 4c13941f665..1c420a50427 100644
--- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
@@ -116,8 +116,8 @@ fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Spa
         let ty = cx.tcx.erase_late_bound_regions(ret_ty);
         if ty.is_unit();
         then {
+            let body = cx.tcx.hir().body(body_id);
             if_chain! {
-                let body = cx.tcx.hir().body(body_id);
                 if let ExprKind::Block(block, _) = body.value.kind;
                 if block.expr.is_none();
                 if let Some(stmt) = block.stmts.last();
@@ -138,7 +138,7 @@ fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Spa
 
 impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if let ExprKind::MethodCall(_, _, ref args, _) = expr.kind {
+        if let ExprKind::MethodCall(_, _, args, _) = expr.kind {
             let arg_indices = get_args_to_check(cx, expr);
             for (i, trait_name) in arg_indices {
                 if i < args.len() {
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
index 8698a718bbd..fad647dfb26 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
@@ -9,8 +9,8 @@ use rustc_middle::lint::in_external_macro;
 use super::LET_UNIT_VALUE;
 
 pub(super) fn check(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
-    if let StmtKind::Local(ref local) = stmt.kind {
-        if cx.typeck_results().pat_ty(&local.pat).is_unit() {
+    if let StmtKind::Local(local) = stmt.kind {
+        if cx.typeck_results().pat_ty(local.pat).is_unit() {
             if in_external_macro(cx.sess(), stmt.span) || local.pat.span.from_expansion() {
                 return;
             }
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
index 925ab577099..57be2d2f674 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
@@ -19,9 +19,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if is_questionmark_desugar_marked_call(expr) {
         return;
     }
+    let map = &cx.tcx.hir();
+    let opt_parent_node = map.find(map.get_parent_node(expr.hir_id));
     if_chain! {
-        let map = &cx.tcx.hir();
-        let opt_parent_node = map.find(map.get_parent_node(expr.hir_id));
         if let Some(hir::Node::Expr(parent_expr)) = opt_parent_node;
         if is_questionmark_desugar_marked_call(parent_expr);
         then {
@@ -54,7 +54,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
 
 fn is_questionmark_desugar_marked_call(expr: &Expr<'_>) -> bool {
     use rustc_span::hygiene::DesugaringKind;
-    if let ExprKind::Call(ref callee, _) = expr.kind {
+    if let ExprKind::Call(callee, _) = expr.kind {
         callee.span.is_desugaring(DesugaringKind::QuestionMark)
     } else {
         false
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
index b3077dec5d8..85257f3113c 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
@@ -9,7 +9,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if expr.span.from_expansion() {
         if let Some(callee) = expr.span.source_callee() {
             if let ExpnKind::Macro(MacroKind::Bang, symbol) = callee.kind {
-                if let ExprKind::Binary(ref cmp, ref left, _) = expr.kind {
+                if let ExprKind::Binary(ref cmp, left, _) = expr.kind {
                     let op = cmp.node;
                     if op.is_comparison() && cx.typeck_results().expr_ty(left).is_unit() {
                         let result = match &*symbol.as_str() {
@@ -34,7 +34,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
         return;
     }
 
-    if let ExprKind::Binary(ref cmp, ref left, _) = expr.kind {
+    if let ExprKind::Binary(ref cmp, left, _) = expr.kind {
         let op = cmp.node;
         if op.is_comparison() && cx.typeck_results().expr_ty(left).is_unit() {
             let result = match op {
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/utils.rs b/src/tools/clippy/clippy_lints/src/unit_types/utils.rs
index 4e194a05e8d..9a3750b2356 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/utils.rs
@@ -1,5 +1,5 @@
 use rustc_hir::{Expr, ExprKind};
 
 pub(super) fn is_unit_literal(expr: &Expr<'_>) -> bool {
-    matches!(expr.kind, ExprKind::Tup(ref slice) if slice.is_empty())
+    matches!(expr.kind, ExprKind::Tup(slice) if slice.is_empty())
 }
diff --git a/src/tools/clippy/clippy_lints/src/unnamed_address.rs b/src/tools/clippy/clippy_lints/src/unnamed_address.rs
index d5bc3de6698..9cca05b1f1a 100644
--- a/src/tools/clippy/clippy_lints/src/unnamed_address.rs
+++ b/src/tools/clippy/clippy_lints/src/unnamed_address.rs
@@ -77,7 +77,7 @@ impl LateLintPass<'_> for UnnamedAddress {
         }
 
         if_chain! {
-            if let ExprKind::Binary(binop, ref left, ref right) = expr.kind;
+            if let ExprKind::Binary(binop, left, right) = expr.kind;
             if is_comparison(binop.node);
             if is_trait_ptr(cx, left) && is_trait_ptr(cx, right);
             then {
@@ -93,7 +93,7 @@ impl LateLintPass<'_> for UnnamedAddress {
         }
 
         if_chain! {
-            if let ExprKind::Call(ref func, [ref _left, ref _right]) = expr.kind;
+            if let ExprKind::Call(func, [ref _left, ref _right]) = expr.kind;
             if let ExprKind::Path(ref func_qpath) = func.kind;
             if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
             if match_def_path(cx, def_id, &paths::PTR_EQ) ||
@@ -114,10 +114,10 @@ impl LateLintPass<'_> for UnnamedAddress {
         }
 
         if_chain! {
-            if let ExprKind::Binary(binop, ref left, ref right) = expr.kind;
+            if let ExprKind::Binary(binop, left, right) = expr.kind;
             if is_comparison(binop.node);
-            if cx.typeck_results().expr_ty_adjusted(left).is_fn_ptr() &&
-                cx.typeck_results().expr_ty_adjusted(right).is_fn_ptr();
+            if cx.typeck_results().expr_ty_adjusted(left).is_fn_ptr();
+            if cx.typeck_results().expr_ty_adjusted(right).is_fn_ptr();
             if is_fn_def(cx, left) || is_fn_def(cx, right);
             then {
                 span_lint(
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
index 6becff9662a..347d858b640 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
@@ -81,9 +81,8 @@ fn mirrored_exprs(
         },
         // Two arrays with mirrored contents
         (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) => {
-            iter::zip(*left_exprs, *right_exprs)
-                .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident))
-        }
+            iter::zip(*left_exprs, *right_exprs).all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident))
+        },
         // The two exprs are function calls.
         // Check to see that the function itself and its arguments are mirrored
         (ExprKind::Call(left_expr, left_args), ExprKind::Call(right_expr, right_args)) => {
@@ -101,12 +100,11 @@ fn mirrored_exprs(
             left_segment.ident == right_segment.ident
                 && iter::zip(*left_args, *right_args)
                     .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident))
-        }
+        },
         // Two tuples with mirrored contents
         (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => {
-            iter::zip(*left_exprs, *right_exprs)
-                .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident))
-        }
+            iter::zip(*left_exprs, *right_exprs).all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident))
+        },
         // Two binary ops, which are the same operation and which have mirrored arguments
         (ExprKind::Binary(left_op, left_left, left_right), ExprKind::Binary(right_op, right_left, right_right)) => {
             left_op.node == right_op.node
@@ -143,8 +141,7 @@ fn mirrored_exprs(
                 },
             )),
         ) => {
-            (iter::zip(*left_segments, *right_segments)
-                .all(|(left, right)| left.ident == right.ident)
+            (iter::zip(*left_segments, *right_segments).all(|(left, right)| left.ident == right.ident)
                 && left_segments
                     .iter()
                     .all(|seg| &seg.ident != a_ident && &seg.ident != b_ident))
@@ -182,15 +179,15 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
         if method_path.ident.name == sym::cmp;
         then {
             let (closure_body, closure_arg, reverse) = if mirrored_exprs(
-                &cx,
-                &left_expr,
-                &left_ident,
-                &right_expr,
-                &right_ident
+                cx,
+                left_expr,
+                left_ident,
+                right_expr,
+                right_ident
             ) {
-                (Sugg::hir(cx, &left_expr, "..").to_string(), left_ident.name.to_string(), false)
-            } else if mirrored_exprs(&cx, &left_expr, &right_ident, &right_expr, &left_ident) {
-                (Sugg::hir(cx, &left_expr, "..").to_string(), right_ident.name.to_string(), true)
+                (Sugg::hir(cx, left_expr, "..").to_string(), left_ident.name.to_string(), false)
+            } else if mirrored_exprs(cx, left_expr, right_ident, right_expr, left_ident) {
+                (Sugg::hir(cx, left_expr, "..").to_string(), right_ident.name.to_string(), true)
             } else {
                 return None;
             };
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
index c2be457e9dc..5bb417cb1be 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
@@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
             if_chain! {
                 if !in_macro(ret_expr.span);
                 // Check if a function call.
-                if let ExprKind::Call(ref func, ref args) = ret_expr.kind;
+                if let ExprKind::Call(func, args) = ret_expr.kind;
                 // Get the Path of the function call.
                 if let ExprKind::Path(ref qpath) = func.kind;
                 // Check if OPTION_SOME or RESULT_OK, depending on return type.
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index 2b9479365c6..9376a2cf66a 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -1,15 +1,19 @@
 #![allow(clippy::wildcard_imports, clippy::enum_glob_use)]
 
-use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::over;
+use clippy_utils::{
+    ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path},
+    meets_msrv,
+};
 use rustc_ast::mut_visit::*;
 use rustc_ast::ptr::P;
 use rustc_ast::{self as ast, Pat, PatKind, PatKind::*, DUMMY_NODE_ID};
 use rustc_ast_pretty::pprust;
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_semver::RustcVersion;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::DUMMY_SP;
 
 use std::cell::Cell;
@@ -50,26 +54,50 @@ declare_clippy_lint! {
     "unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`"
 }
 
-declare_lint_pass!(UnnestedOrPatterns => [UNNESTED_OR_PATTERNS]);
+const UNNESTED_OR_PATTERNS_MSRV: RustcVersion = RustcVersion::new(1, 53, 0);
+
+#[derive(Clone, Copy)]
+pub struct UnnestedOrPatterns {
+    msrv: Option<RustcVersion>,
+}
+
+impl UnnestedOrPatterns {
+    #[must_use]
+    pub fn new(msrv: Option<RustcVersion>) -> Self {
+        Self { msrv }
+    }
+}
+
+impl_lint_pass!(UnnestedOrPatterns => [UNNESTED_OR_PATTERNS]);
 
 impl EarlyLintPass for UnnestedOrPatterns {
     fn check_arm(&mut self, cx: &EarlyContext<'_>, a: &ast::Arm) {
-        lint_unnested_or_patterns(cx, &a.pat);
+        if meets_msrv(self.msrv.as_ref(), &UNNESTED_OR_PATTERNS_MSRV) {
+            lint_unnested_or_patterns(cx, &a.pat);
+        }
     }
 
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
-        if let ast::ExprKind::Let(pat, _) = &e.kind {
-            lint_unnested_or_patterns(cx, pat);
+        if meets_msrv(self.msrv.as_ref(), &UNNESTED_OR_PATTERNS_MSRV) {
+            if let ast::ExprKind::Let(pat, _) = &e.kind {
+                lint_unnested_or_patterns(cx, pat);
+            }
         }
     }
 
     fn check_param(&mut self, cx: &EarlyContext<'_>, p: &ast::Param) {
-        lint_unnested_or_patterns(cx, &p.pat);
+        if meets_msrv(self.msrv.as_ref(), &UNNESTED_OR_PATTERNS_MSRV) {
+            lint_unnested_or_patterns(cx, &p.pat);
+        }
     }
 
     fn check_local(&mut self, cx: &EarlyContext<'_>, l: &ast::Local) {
-        lint_unnested_or_patterns(cx, &l.pat);
+        if meets_msrv(self.msrv.as_ref(), &UNNESTED_OR_PATTERNS_MSRV) {
+            lint_unnested_or_patterns(cx, &l.pat);
+        }
     }
+
+    extract_msrv_attr!(EarlyContext);
 }
 
 fn lint_unnested_or_patterns(cx: &EarlyContext<'_>, pat: &Pat) {
diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
index 9990052e114..024ab03fd41 100644
--- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -36,13 +36,13 @@ declare_lint_pass!(UnusedIoAmount => [UNUSED_IO_AMOUNT]);
 impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
     fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
         let expr = match s.kind {
-            hir::StmtKind::Semi(ref expr) | hir::StmtKind::Expr(ref expr) => &**expr,
+            hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr,
             _ => return,
         };
 
         match expr.kind {
-            hir::ExprKind::Match(ref res, _, _) if is_try(expr).is_some() => {
-                if let hir::ExprKind::Call(ref func, ref args) = res.kind {
+            hir::ExprKind::Match(res, _, _) if is_try(expr).is_some() => {
+                if let hir::ExprKind::Call(func, args) = res.kind {
                     if matches!(
                         func.kind,
                         hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryIntoResult, _))
@@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
                 }
             },
 
-            hir::ExprKind::MethodCall(ref path, _, ref args, _) => match &*path.ident.as_str() {
+            hir::ExprKind::MethodCall(path, _, args, _) => match &*path.ident.as_str() {
                 "expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" => {
                     check_method_call(cx, &args[0], expr);
                 },
@@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
 }
 
 fn check_method_call(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) {
-    if let hir::ExprKind::MethodCall(ref path, _, _, _) = call.kind {
+    if let hir::ExprKind::MethodCall(path, _, _, _) = call.kind {
         let symbol = &*path.ident.as_str();
         let read_trait = match_trait_method(cx, call, &paths::IO_READ);
         let write_trait = match_trait_method(cx, call, &paths::IO_WRITE);
diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs
index aef4ce75915..15343cf90f2 100644
--- a/src/tools/clippy/clippy_lints/src/unused_self.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_self.rs
@@ -49,21 +49,18 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf {
             if assoc_item.fn_has_self_parameter;
             if let ImplItemKind::Fn(.., body_id) = &impl_item.kind;
             let body = cx.tcx.hir().body(*body_id);
-            if !body.params.is_empty();
+            if let [self_param, ..] = body.params;
+            let self_hir_id = self_param.pat.hir_id;
+            if !LocalUsedVisitor::new(cx, self_hir_id).check_body(body);
             then {
-                let self_param = &body.params[0];
-                let self_hir_id = self_param.pat.hir_id;
-                if !LocalUsedVisitor::new(cx, self_hir_id).check_body(body) {
-                    span_lint_and_help(
-                        cx,
-                        UNUSED_SELF,
-                        self_param.span,
-                        "unused `self` argument",
-                        None,
-                        "consider refactoring to a associated function",
-                    );
-                    return;
-                }
+                span_lint_and_help(
+                    cx,
+                    UNUSED_SELF,
+                    self_param.span,
+                    "unused `self` argument",
+                    None,
+                    "consider refactoring to a associated function",
+                );
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs
index 329ea49024b..ce2d0b3ab2f 100644
--- a/src/tools/clippy/clippy_lints/src/unused_unit.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs
@@ -45,7 +45,7 @@ impl EarlyLintPass for UnusedUnit {
 
     fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
         if_chain! {
-            if let Some(ref stmt) = block.stmts.last();
+            if let Some(stmt) = block.stmts.last();
             if let ast::StmtKind::Expr(ref expr) = stmt.kind;
             if is_unit_expr(expr) && !stmt.span.from_expansion();
             then {
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index fb29acca18a..d4efee56eff 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -166,8 +166,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
         } else {
             // find `unwrap[_err]()` calls:
             if_chain! {
-                if let ExprKind::MethodCall(ref method_name, _, ref args, _) = expr.kind;
-                if let ExprKind::Path(QPath::Resolved(None, ref path)) = args[0].kind;
+                if let ExprKind::MethodCall(method_name, _, args, _) = expr.kind;
+                if let ExprKind::Path(QPath::Resolved(None, path)) = args[0].kind;
                 if [sym::unwrap, sym!(unwrap_err)].contains(&method_name.ident.name);
                 let call_to_unwrap = method_name.ident.name == sym::unwrap;
                 if let Some(unwrappable) = self.unwrappables.iter()
diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
index 0d745813beb..d17aa6d8424 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
@@ -110,31 +110,27 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> {
 }
 
 fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tcx hir::ImplItem<'_>) {
-    if_chain! {
+    if let ImplItemKind::Fn(_, body_id) = impl_item.kind {
+        let body = cx.tcx.hir().body(body_id);
+        let mut fpu = FindExpectUnwrap {
+            lcx: cx,
+            typeck_results: cx.tcx.typeck(impl_item.def_id),
+            result: Vec::new(),
+        };
+        fpu.visit_expr(&body.value);
 
-        if let ImplItemKind::Fn(_, body_id) = impl_item.kind;
-        then {
-            let body = cx.tcx.hir().body(body_id);
-            let mut fpu = FindExpectUnwrap {
-                lcx: cx,
-                typeck_results: cx.tcx.typeck(impl_item.def_id),
-                result: Vec::new(),
-            };
-            fpu.visit_expr(&body.value);
-
-            // if we've found one, lint
-            if  !fpu.result.is_empty()  {
-                span_lint_and_then(
-                    cx,
-                    UNWRAP_IN_RESULT,
-                    impl_span,
-                    "used unwrap or expect in a function that returns result or option",
-                    move |diag| {
-                        diag.help(
-                            "unwrap and expect should not be used in a function that returns result or option" );
-                        diag.span_note(fpu.result, "potential non-recoverable error(s)");
-                    });
-            }
+        // if we've found one, lint
+        if !fpu.result.is_empty() {
+            span_lint_and_then(
+                cx,
+                UNWRAP_IN_RESULT,
+                impl_span,
+                "used unwrap or expect in a function that returns result or option",
+                move |diag| {
+                    diag.help("unwrap and expect should not be used in a function that returns result or option");
+                    diag.span_note(fpu.result, "potential non-recoverable error(s)");
+                },
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
index a6d29d36862..4ac2ec55b98 100644
--- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
+++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use if_chain::if_chain;
 use itertools::Itertools;
-use rustc_ast::ast::{Item, ItemKind, Variant, VisibilityKind};
+use rustc_ast::ast::{Item, ItemKind, VisibilityKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
@@ -99,21 +98,21 @@ fn check_ident(cx: &EarlyContext<'_>, ident: &Ident, be_aggressive: bool) {
 
 impl EarlyLintPass for UpperCaseAcronyms {
     fn check_item(&mut self, cx: &EarlyContext<'_>, it: &Item) {
-        if_chain! {
-            if !in_external_macro(cx.sess(), it.span);
+        // do not lint public items or in macros
+        if !in_external_macro(cx.sess(), it.span) && !matches!(it.vis.kind, VisibilityKind::Public) {
             if matches!(
                 it.kind,
-                ItemKind::TyAlias(..) | ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Trait(..)
-            );
-            // do not lint public items
-            if !matches!(it.vis.kind, VisibilityKind::Public);
-            then {
+                ItemKind::TyAlias(..) | ItemKind::Struct(..) | ItemKind::Trait(..)
+            ) {
                 check_ident(cx, &it.ident, self.upper_case_acronyms_aggressive);
+            } else if let ItemKind::Enum(ref enumdef, _) = it.kind {
+                // check enum variants seperately because again we only want to lint on private enums and
+                // the fn check_variant does not know about the vis of the enum of its variants
+                enumdef
+                    .variants
+                    .iter()
+                    .for_each(|variant| check_ident(cx, &variant.ident, self.upper_case_acronyms_aggressive));
             }
         }
     }
-
-    fn check_variant(&mut self, cx: &EarlyContext<'_>, v: &Variant) {
-        check_ident(cx, &v.ident, self.upper_case_acronyms_aggressive);
-    }
 }
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index 116cb8b1e1c..c6a3c58a9a2 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -104,7 +104,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
                 of_trait,
                 ..
             }) => {
-                let should_check = if let TyKind::Path(QPath::Resolved(_, ref item_path)) = hir_self_ty.kind {
+                let should_check = if let TyKind::Path(QPath::Resolved(_, item_path)) = hir_self_ty.kind {
                     let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args;
                     parameters.as_ref().map_or(true, |params| {
                         !params.parenthesized && !params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)))
@@ -197,7 +197,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
                 for (impl_hir_ty, trait_sem_ty) in impl_inputs_outputs.zip(trait_method_sig.inputs_and_output) {
                     if trait_sem_ty.walk().any(|inner| inner == self_ty.into()) {
                         let mut visitor = SkipTyCollector::default();
-                        visitor.visit_ty(&impl_hir_ty);
+                        visitor.visit_ty(impl_hir_ty);
                         types_to_skip.extend(visitor.types_to_skip);
                     }
                 }
@@ -333,7 +333,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
                 // unit enum variants (`Enum::A`)
                 ExprKind::Path(qpath) => {
                     if expr_ty_matches(cx, expr, self_ty) {
-                        span_lint_on_qpath_resolved(cx, &qpath, true);
+                        span_lint_on_qpath_resolved(cx, qpath, true);
                     }
                 },
                 _ => (),
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index 3e1b69e676b..7edb280be73 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -53,17 +53,17 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
         }
 
         match e.kind {
-            ExprKind::Match(_, ref arms, MatchSource::TryDesugar) => {
+            ExprKind::Match(_, arms, MatchSource::TryDesugar) => {
                 let e = match arms[0].body.kind {
-                    ExprKind::Ret(Some(ref e)) | ExprKind::Break(_, Some(ref e)) => e,
+                    ExprKind::Ret(Some(e)) | ExprKind::Break(_, Some(e)) => e,
                     _ => return,
                 };
-                if let ExprKind::Call(_, ref args) = e.kind {
+                if let ExprKind::Call(_, args) = e.kind {
                     self.try_desugar_arm.push(args[0].hir_id);
                 }
             },
 
-            ExprKind::MethodCall(ref name, .., ref args, _) => {
+            ExprKind::MethodCall(name, .., args, _) => {
                 if match_trait_method(cx, e, &paths::INTO) && &*name.ident.as_str() == "into" {
                     let a = cx.typeck_results().expr_ty(e);
                     let b = cx.typeck_results().expr_ty(&args[0]);
@@ -82,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                 }
                 if match_trait_method(cx, e, &paths::INTO_ITERATOR) && name.ident.name == sym::into_iter {
                     if let Some(parent_expr) = get_parent_expr(cx, e) {
-                        if let ExprKind::MethodCall(ref parent_name, ..) = parent_expr.kind {
+                        if let ExprKind::MethodCall(parent_name, ..) = parent_expr.kind {
                             if parent_name.ident.name != sym::into_iter {
                                 return;
                             }
@@ -103,38 +103,35 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                         );
                     }
                 }
-                if match_trait_method(cx, e, &paths::TRY_INTO_TRAIT) && &*name.ident.as_str() == "try_into" {
-                    if_chain! {
-                        let a = cx.typeck_results().expr_ty(e);
-                        let b = cx.typeck_results().expr_ty(&args[0]);
-                        if is_type_diagnostic_item(cx, a, sym::result_type);
-                        if let ty::Adt(_, substs) = a.kind();
-                        if let Some(a_type) = substs.types().next();
-                        if TyS::same_type(a_type, b);
-
-                        then {
-                            span_lint_and_help(
-                                cx,
-                                USELESS_CONVERSION,
-                                e.span,
-                                &format!("useless conversion to the same type: `{}`", b),
-                                None,
-                                "consider removing `.try_into()`",
-                            );
-                        }
+                if_chain! {
+                    if match_trait_method(cx, e, &paths::TRY_INTO_TRAIT) && &*name.ident.as_str() == "try_into";
+                    let a = cx.typeck_results().expr_ty(e);
+                    let b = cx.typeck_results().expr_ty(&args[0]);
+                    if is_type_diagnostic_item(cx, a, sym::result_type);
+                    if let ty::Adt(_, substs) = a.kind();
+                    if let Some(a_type) = substs.types().next();
+                    if TyS::same_type(a_type, b);
+                    then {
+                        span_lint_and_help(
+                            cx,
+                            USELESS_CONVERSION,
+                            e.span,
+                            &format!("useless conversion to the same type: `{}`", b),
+                            None,
+                            "consider removing `.try_into()`",
+                        );
                     }
                 }
             },
 
-            ExprKind::Call(ref path, ref args) => {
+            ExprKind::Call(path, args) => {
                 if_chain! {
                     if args.len() == 1;
                     if let ExprKind::Path(ref qpath) = path.kind;
                     if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
-                    let a = cx.typeck_results().expr_ty(e);
-                    let b = cx.typeck_results().expr_ty(&args[0]);
-
                     then {
+                        let a = cx.typeck_results().expr_ty(e);
+                        let b = cx.typeck_results().expr_ty(&args[0]);
                         if_chain! {
                             if match_def_path(cx, def_id, &paths::TRY_FROM);
                             if is_type_diagnostic_item(cx, a, sym::result_type);
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index a92c987014f..e70f8a09ebe 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -203,13 +203,13 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
         print!("    if let ExprKind::");
         let current = format!("{}.kind", self.current);
         match expr.kind {
-            ExprKind::Box(ref inner) => {
+            ExprKind::Box(inner) => {
                 let inner_pat = self.next("inner");
                 println!("Box(ref {}) = {};", inner_pat, current);
                 self.current = inner_pat;
                 self.visit_expr(inner);
             },
-            ExprKind::Array(ref elements) => {
+            ExprKind::Array(elements) => {
                 let elements_pat = self.next("elements");
                 println!("Array(ref {}) = {};", elements_pat, current);
                 println!("    if {}.len() == {};", elements_pat, elements.len());
@@ -218,7 +218,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                     self.visit_expr(element);
                 }
             },
-            ExprKind::Call(ref func, ref args) => {
+            ExprKind::Call(func, args) => {
                 let func_pat = self.next("func");
                 let args_pat = self.next("args");
                 println!("Call(ref {}, ref {}) = {};", func_pat, args_pat, current);
@@ -230,14 +230,14 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                     self.visit_expr(arg);
                 }
             },
-            ExprKind::MethodCall(ref _method_name, ref _generics, ref _args, ref _fn_span) => {
+            ExprKind::MethodCall(_method_name, ref _generics, _args, ref _fn_span) => {
                 println!(
                     "MethodCall(ref method_name, ref generics, ref args, ref fn_span) = {};",
                     current
                 );
                 println!("    // unimplemented: `ExprKind::MethodCall` is not further destructured at the moment");
             },
-            ExprKind::Tup(ref elements) => {
+            ExprKind::Tup(elements) => {
                 let elements_pat = self.next("elements");
                 println!("Tup(ref {}) = {};", elements_pat, current);
                 println!("    if {}.len() == {};", elements_pat, elements.len());
@@ -246,7 +246,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                     self.visit_expr(element);
                 }
             },
-            ExprKind::Binary(ref op, ref left, ref right) => {
+            ExprKind::Binary(ref op, left, right) => {
                 let op_pat = self.next("op");
                 let left_pat = self.next("left");
                 let right_pat = self.next("right");
@@ -260,7 +260,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                 self.current = right_pat;
                 self.visit_expr(right);
             },
-            ExprKind::Unary(ref op, ref inner) => {
+            ExprKind::Unary(ref op, inner) => {
                 let inner_pat = self.next("inner");
                 println!("Unary(UnOp::{:?}, ref {}) = {};", op, inner_pat, current);
                 self.current = inner_pat;
@@ -296,7 +296,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                     },
                 }
             },
-            ExprKind::Cast(ref expr, ref ty) => {
+            ExprKind::Cast(expr, ty) => {
                 let cast_pat = self.next("expr");
                 let cast_ty = self.next("cast_ty");
                 let qp_label = self.next("qp");
@@ -310,13 +310,13 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                 self.current = cast_pat;
                 self.visit_expr(expr);
             },
-            ExprKind::Type(ref expr, ref _ty) => {
+            ExprKind::Type(expr, _ty) => {
                 let cast_pat = self.next("expr");
                 println!("Type(ref {}, _) = {};", cast_pat, current);
                 self.current = cast_pat;
                 self.visit_expr(expr);
             },
-            ExprKind::Loop(ref body, _, desugaring, _) => {
+            ExprKind::Loop(body, _, desugaring, _) => {
                 let body_pat = self.next("body");
                 let des = loop_desugaring_name(desugaring);
                 let label_pat = self.next("label");
@@ -324,10 +324,10 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                 self.current = body_pat;
                 self.visit_block(body);
             },
-            ExprKind::If(ref cond, ref then, ref opt_else) => {
+            ExprKind::If(cond, then, ref opt_else) => {
                 let cond_pat = self.next("cond");
                 let then_pat = self.next("then");
-                if let Some(ref else_) = *opt_else {
+                if let Some(else_) = *opt_else {
                     let else_pat = self.next("else_");
                     println!(
                         "If(ref {}, ref {}, Some(ref {})) = {};",
@@ -343,7 +343,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                 self.current = then_pat;
                 self.visit_expr(then);
             },
-            ExprKind::Match(ref expr, ref arms, desugaring) => {
+            ExprKind::Match(expr, arms, desugaring) => {
                 let des = desugaring_name(desugaring);
                 let expr_pat = self.next("expr");
                 let arms_pat = self.next("arms");
@@ -353,18 +353,18 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                 println!("    if {}.len() == {};", arms_pat, arms.len());
                 for (i, arm) in arms.iter().enumerate() {
                     self.current = format!("{}[{}].body", arms_pat, i);
-                    self.visit_expr(&arm.body);
+                    self.visit_expr(arm.body);
                     if let Some(ref guard) = arm.guard {
                         let guard_pat = self.next("guard");
                         println!("    if let Some(ref {}) = {}[{}].guard;", guard_pat, arms_pat, i);
                         match guard {
-                            hir::Guard::If(ref if_expr) => {
+                            hir::Guard::If(if_expr) => {
                                 let if_expr_pat = self.next("expr");
                                 println!("    if let Guard::If(ref {}) = {};", if_expr_pat, guard_pat);
                                 self.current = if_expr_pat;
                                 self.visit_expr(if_expr);
                             },
-                            hir::Guard::IfLet(ref if_let_pat, ref if_let_expr) => {
+                            hir::Guard::IfLet(if_let_pat, if_let_expr) => {
                                 let if_let_pat_pat = self.next("pat");
                                 let if_let_expr_pat = self.next("expr");
                                 println!(
@@ -379,26 +379,26 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                         }
                     }
                     self.current = format!("{}[{}].pat", arms_pat, i);
-                    self.visit_pat(&arm.pat);
+                    self.visit_pat(arm.pat);
                 }
             },
-            ExprKind::Closure(ref _capture_clause, ref _func, _, _, _) => {
+            ExprKind::Closure(ref _capture_clause, _func, _, _, _) => {
                 println!("Closure(ref capture_clause, ref func, _, _, _) = {};", current);
                 println!("    // unimplemented: `ExprKind::Closure` is not further destructured at the moment");
             },
-            ExprKind::Yield(ref sub, _) => {
+            ExprKind::Yield(sub, _) => {
                 let sub_pat = self.next("sub");
                 println!("Yield(ref sub) = {};", current);
                 self.current = sub_pat;
                 self.visit_expr(sub);
             },
-            ExprKind::Block(ref block, _) => {
+            ExprKind::Block(block, _) => {
                 let block_pat = self.next("block");
                 println!("Block(ref {}) = {};", block_pat, current);
                 self.current = block_pat;
                 self.visit_block(block);
             },
-            ExprKind::Assign(ref target, ref value, _) => {
+            ExprKind::Assign(target, value, _) => {
                 let target_pat = self.next("target");
                 let value_pat = self.next("value");
                 println!(
@@ -410,7 +410,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                 self.current = value_pat;
                 self.visit_expr(value);
             },
-            ExprKind::AssignOp(ref op, ref target, ref value) => {
+            ExprKind::AssignOp(ref op, target, value) => {
                 let op_pat = self.next("op");
                 let target_pat = self.next("target");
                 let value_pat = self.next("value");
@@ -424,7 +424,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                 self.current = value_pat;
                 self.visit_expr(value);
             },
-            ExprKind::Field(ref object, ref field_ident) => {
+            ExprKind::Field(object, ref field_ident) => {
                 let obj_pat = self.next("object");
                 let field_name_pat = self.next("field_name");
                 println!("Field(ref {}, ref {}) = {};", obj_pat, field_name_pat, current);
@@ -432,7 +432,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                 self.current = obj_pat;
                 self.visit_expr(object);
             },
-            ExprKind::Index(ref object, ref index) => {
+            ExprKind::Index(object, index) => {
                 let object_pat = self.next("object");
                 let index_pat = self.next("index");
                 println!("Index(ref {}, ref {}) = {};", object_pat, index_pat, current);
@@ -447,7 +447,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                 self.current = path_pat;
                 self.print_qpath(path);
             },
-            ExprKind::AddrOf(kind, mutability, ref inner) => {
+            ExprKind::AddrOf(kind, mutability, inner) => {
                 let inner_pat = self.next("inner");
                 println!(
                     "AddrOf(BorrowKind::{:?}, Mutability::{:?}, ref {}) = {};",
@@ -458,7 +458,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
             },
             ExprKind::Break(ref _destination, ref opt_value) => {
                 let destination_pat = self.next("destination");
-                if let Some(ref value) = *opt_value {
+                if let Some(value) = *opt_value {
                     let value_pat = self.next("value");
                     println!("Break(ref {}, Some(ref {})) = {};", destination_pat, value_pat, current);
                     self.current = value_pat;
@@ -474,7 +474,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                 // FIXME: implement label printing
             },
             ExprKind::Ret(ref opt_value) => {
-                if let Some(ref value) = *opt_value {
+                if let Some(value) = *opt_value {
                     let value_pat = self.next("value");
                     println!("Ret(Some(ref {})) = {};", value_pat, current);
                     self.current = value_pat;
@@ -491,10 +491,10 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                 println!("LlvmInlineAsm(_) = {};", current);
                 println!("    // unimplemented: `ExprKind::LlvmInlineAsm` is not further destructured at the moment");
             },
-            ExprKind::Struct(ref path, ref fields, ref opt_base) => {
+            ExprKind::Struct(path, fields, ref opt_base) => {
                 let path_pat = self.next("path");
                 let fields_pat = self.next("fields");
-                if let Some(ref base) = *opt_base {
+                if let Some(base) = *opt_base {
                     let base_pat = self.next("base");
                     println!(
                         "Struct(ref {}, ref {}, Some(ref {})) = {};",
@@ -516,7 +516,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                 self.current = value_pat;
             },
             // FIXME: compute length (needs type info)
-            ExprKind::Repeat(ref value, _) => {
+            ExprKind::Repeat(value, _) => {
                 let value_pat = self.next("value");
                 println!("Repeat(ref {}, _) = {};", value_pat, current);
                 println!("// unimplemented: repeat count check");
@@ -526,7 +526,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
             ExprKind::Err => {
                 println!("Err = {}", current);
             },
-            ExprKind::DropTemps(ref expr) => {
+            ExprKind::DropTemps(expr) => {
                 let expr_pat = self.next("expr");
                 println!("DropTemps(ref {}) = {};", expr_pat, current);
                 self.current = expr_pat;
@@ -560,7 +560,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                     BindingAnnotation::RefMut => "BindingAnnotation::RefMut",
                 };
                 let name_pat = self.next("name");
-                if let Some(ref sub) = *sub {
+                if let Some(sub) = *sub {
                     let sub_pat = self.next("sub");
                     println!(
                         "Binding({}, _, {}, Some(ref {})) = {};",
@@ -573,7 +573,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                 }
                 println!("    if {}.as_str() == \"{}\";", name_pat, ident.as_str());
             },
-            PatKind::Struct(ref path, ref fields, ignore) => {
+            PatKind::Struct(ref path, fields, ignore) => {
                 let path_pat = self.next("path");
                 let fields_pat = self.next("fields");
                 println!(
@@ -585,13 +585,13 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                 println!("    if {}.len() == {};", fields_pat, fields.len());
                 println!("    // unimplemented: field checks");
             },
-            PatKind::Or(ref fields) => {
+            PatKind::Or(fields) => {
                 let fields_pat = self.next("fields");
                 println!("Or(ref {}) = {};", fields_pat, current);
                 println!("    if {}.len() == {};", fields_pat, fields.len());
                 println!("    // unimplemented: field checks");
             },
-            PatKind::TupleStruct(ref path, ref fields, skip_pos) => {
+            PatKind::TupleStruct(ref path, fields, skip_pos) => {
                 let path_pat = self.next("path");
                 let fields_pat = self.next("fields");
                 println!(
@@ -609,25 +609,25 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                 self.current = path_pat;
                 self.print_qpath(path);
             },
-            PatKind::Tuple(ref fields, skip_pos) => {
+            PatKind::Tuple(fields, skip_pos) => {
                 let fields_pat = self.next("fields");
                 println!("Tuple(ref {}, {:?}) = {};", fields_pat, skip_pos, current);
                 println!("    if {}.len() == {};", fields_pat, fields.len());
                 println!("    // unimplemented: field checks");
             },
-            PatKind::Box(ref pat) => {
+            PatKind::Box(pat) => {
                 let pat_pat = self.next("pat");
                 println!("Box(ref {}) = {};", pat_pat, current);
                 self.current = pat_pat;
                 self.visit_pat(pat);
             },
-            PatKind::Ref(ref pat, muta) => {
+            PatKind::Ref(pat, muta) => {
                 let pat_pat = self.next("pat");
                 println!("Ref(ref {}, Mutability::{:?}) = {};", pat_pat, muta, current);
                 self.current = pat_pat;
                 self.visit_pat(pat);
             },
-            PatKind::Lit(ref lit_expr) => {
+            PatKind::Lit(lit_expr) => {
                 let lit_expr_pat = self.next("lit_expr");
                 println!("Lit(ref {}) = {}", lit_expr_pat, current);
                 self.current = lit_expr_pat;
@@ -645,10 +645,10 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                 self.current = end_pat;
                 walk_list!(self, visit_expr, end);
             },
-            PatKind::Slice(ref start, ref middle, ref end) => {
+            PatKind::Slice(start, ref middle, end) => {
                 let start_pat = self.next("start");
                 let end_pat = self.next("end");
-                if let Some(ref middle) = middle {
+                if let Some(middle) = middle {
                     let middle_pat = self.next("middle");
                     println!(
                         "Slice(ref {}, Some(ref {}), ref {}) = {};",
@@ -678,17 +678,17 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
         let current = format!("{}.kind", self.current);
         match s.kind {
             // A local (let) binding:
-            StmtKind::Local(ref local) => {
+            StmtKind::Local(local) => {
                 let local_pat = self.next("local");
                 println!("Local(ref {}) = {};", local_pat, current);
-                if let Some(ref init) = local.init {
+                if let Some(init) = local.init {
                     let init_pat = self.next("init");
                     println!("    if let Some(ref {}) = {}.init;", init_pat, local_pat);
                     self.current = init_pat;
                     self.visit_expr(init);
                 }
                 self.current = format!("{}.pat", local_pat);
-                self.visit_pat(&local.pat);
+                self.visit_pat(local.pat);
             },
             // An item binding:
             StmtKind::Item(_) => {
@@ -696,7 +696,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
             },
 
             // Expr without trailing semi-colon (must have unit type):
-            StmtKind::Expr(ref e) => {
+            StmtKind::Expr(e) => {
                 let e_pat = self.next("e");
                 println!("Expr(ref {}, _) = {}", e_pat, current);
                 self.current = e_pat;
@@ -704,7 +704,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
             },
 
             // Expr with trailing semi-colon (may have any type):
-            StmtKind::Semi(ref e) => {
+            StmtKind::Semi(e) => {
                 let e_pat = self.next("e");
                 println!("Semi(ref {}, _) = {}", e_pat, current);
                 self.current = e_pat;
@@ -752,7 +752,7 @@ fn loop_desugaring_name(des: hir::LoopSource) -> &'static str {
 
 fn print_path(path: &QPath<'_>, first: &mut bool) {
     match *path {
-        QPath::Resolved(_, ref path) => {
+        QPath::Resolved(_, path) => {
             for segment in path.segments {
                 if *first {
                     *first = false;
@@ -762,7 +762,7 @@ fn print_path(path: &QPath<'_>, first: &mut bool) {
                 print!("{:?}", segment.ident.as_str());
             }
         },
-        QPath::TypeRelative(ref ty, ref segment) => match ty.kind {
+        QPath::TypeRelative(ty, segment) => match ty.kind {
             hir::TyKind::Path(ref inner_path) => {
                 print_path(inner_path, first);
                 if *first {
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index 9139a0966c5..147f823491d 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -106,7 +106,7 @@ macro_rules! define_Conf {
 
 pub use self::helpers::Conf;
 define_Conf! {
-    /// Lint: REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN. The minimum rust version that the project supports
+    /// Lint: REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, NEEDLESS_QUESTION_MARK, PTR_AS_PTR. The minimum rust version that the project supports
     (msrv, "msrv": Option<String>, None),
     /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses
     (blacklisted_names, "blacklisted_names": Vec<String>, ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()),
diff --git a/src/tools/clippy/clippy_lints/src/utils/inspector.rs b/src/tools/clippy/clippy_lints/src/utils/inspector.rs
index b3fe66ed428..4665eeeff7b 100644
--- a/src/tools/clippy/clippy_lints/src/utils/inspector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/inspector.rs
@@ -47,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for DeepCodeInspector {
         match item.vis.node {
             hir::VisibilityKind::Public => println!("public"),
             hir::VisibilityKind::Crate(_) => println!("visible crate wide"),
-            hir::VisibilityKind::Restricted { ref path, .. } => println!(
+            hir::VisibilityKind::Restricted { path, .. } => println!(
                 "visible in module `{}`",
                 rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(path, false))
             ),
@@ -99,13 +99,13 @@ impl<'tcx> LateLintPass<'tcx> for DeepCodeInspector {
         if !has_attr(cx.sess(), cx.tcx.hir().attrs(arm.hir_id)) {
             return;
         }
-        print_pat(cx, &arm.pat, 1);
+        print_pat(cx, arm.pat, 1);
         if let Some(ref guard) = arm.guard {
             println!("guard:");
             print_guard(cx, guard, 1);
         }
         println!("body:");
-        print_expr(cx, &arm.body, 1);
+        print_expr(cx, arm.body, 1);
     }
 
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx hir::Stmt<'_>) {
@@ -113,17 +113,17 @@ impl<'tcx> LateLintPass<'tcx> for DeepCodeInspector {
             return;
         }
         match stmt.kind {
-            hir::StmtKind::Local(ref local) => {
+            hir::StmtKind::Local(local) => {
                 println!("local variable of type {}", cx.typeck_results().node_type(local.hir_id));
                 println!("pattern:");
-                print_pat(cx, &local.pat, 0);
-                if let Some(ref e) = local.init {
+                print_pat(cx, local.pat, 0);
+                if let Some(e) = local.init {
                     println!("init expression:");
                     print_expr(cx, e, 0);
                 }
             },
             hir::StmtKind::Item(_) => println!("item decl"),
-            hir::StmtKind::Expr(ref e) | hir::StmtKind::Semi(ref e) => print_expr(cx, e, 0),
+            hir::StmtKind::Expr(e) | hir::StmtKind::Semi(e) => print_expr(cx, e, 0),
         }
     }
     // fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx
@@ -151,7 +151,7 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
         cx.typeck_results().adjustments().get(expr.hir_id)
     );
     match expr.kind {
-        hir::ExprKind::Box(ref e) => {
+        hir::ExprKind::Box(e) => {
             println!("{}Box", ind);
             print_expr(cx, e, indent + 1);
         },
@@ -161,7 +161,7 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
                 print_expr(cx, e, indent + 1);
             }
         },
-        hir::ExprKind::Call(ref func, args) => {
+        hir::ExprKind::Call(func, args) => {
             println!("{}Call", ind);
             println!("{}function:", ind);
             print_expr(cx, func, indent + 1);
@@ -170,7 +170,7 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
                 print_expr(cx, arg, indent + 1);
             }
         },
-        hir::ExprKind::MethodCall(ref path, _, args, _) => {
+        hir::ExprKind::MethodCall(path, _, args, _) => {
             println!("{}MethodCall", ind);
             println!("{}method name: {}", ind, path.ident.name);
             for arg in args {
@@ -183,7 +183,7 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
                 print_expr(cx, e, indent + 1);
             }
         },
-        hir::ExprKind::Binary(op, ref lhs, ref rhs) => {
+        hir::ExprKind::Binary(op, lhs, rhs) => {
             println!("{}Binary", ind);
             println!("{}op: {:?}", ind, op.node);
             println!("{}lhs:", ind);
@@ -191,7 +191,7 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
             println!("{}rhs:", ind);
             print_expr(cx, rhs, indent + 1);
         },
-        hir::ExprKind::Unary(op, ref inner) => {
+        hir::ExprKind::Unary(op, inner) => {
             println!("{}Unary", ind);
             println!("{}op: {:?}", ind, op);
             print_expr(cx, inner, indent + 1);
@@ -200,12 +200,12 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
             println!("{}Lit", ind);
             println!("{}{:?}", ind, lit);
         },
-        hir::ExprKind::Cast(ref e, ref target) => {
+        hir::ExprKind::Cast(e, target) => {
             println!("{}Cast", ind);
             print_expr(cx, e, indent + 1);
             println!("{}target type: {:?}", ind, target);
         },
-        hir::ExprKind::Type(ref e, ref target) => {
+        hir::ExprKind::Type(e, target) => {
             println!("{}Type", ind);
             print_expr(cx, e, indent + 1);
             println!("{}target type: {:?}", ind, target);
@@ -213,16 +213,16 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
         hir::ExprKind::Loop(..) => {
             println!("{}Loop", ind);
         },
-        hir::ExprKind::If(ref cond, _, ref else_opt) => {
+        hir::ExprKind::If(cond, _, ref else_opt) => {
             println!("{}If", ind);
             println!("{}condition:", ind);
             print_expr(cx, cond, indent + 1);
-            if let Some(ref els) = *else_opt {
+            if let Some(els) = *else_opt {
                 println!("{}else:", ind);
                 print_expr(cx, els, indent + 1);
             }
         },
-        hir::ExprKind::Match(ref cond, _, ref source) => {
+        hir::ExprKind::Match(cond, _, ref source) => {
             println!("{}Match", ind);
             println!("{}condition:", ind);
             print_expr(cx, cond, indent + 1);
@@ -232,21 +232,21 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
             println!("{}Closure", ind);
             println!("{}clause: {:?}", ind, clause);
         },
-        hir::ExprKind::Yield(ref sub, _) => {
+        hir::ExprKind::Yield(sub, _) => {
             println!("{}Yield", ind);
             print_expr(cx, sub, indent + 1);
         },
         hir::ExprKind::Block(_, _) => {
             println!("{}Block", ind);
         },
-        hir::ExprKind::Assign(ref lhs, ref rhs, _) => {
+        hir::ExprKind::Assign(lhs, rhs, _) => {
             println!("{}Assign", ind);
             println!("{}lhs:", ind);
             print_expr(cx, lhs, indent + 1);
             println!("{}rhs:", ind);
             print_expr(cx, rhs, indent + 1);
         },
-        hir::ExprKind::AssignOp(ref binop, ref lhs, ref rhs) => {
+        hir::ExprKind::AssignOp(ref binop, lhs, rhs) => {
             println!("{}AssignOp", ind);
             println!("{}op: {:?}", ind, binop.node);
             println!("{}lhs:", ind);
@@ -254,31 +254,31 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
             println!("{}rhs:", ind);
             print_expr(cx, rhs, indent + 1);
         },
-        hir::ExprKind::Field(ref e, ident) => {
+        hir::ExprKind::Field(e, ident) => {
             println!("{}Field", ind);
             println!("{}field name: {}", ind, ident.name);
             println!("{}struct expr:", ind);
             print_expr(cx, e, indent + 1);
         },
-        hir::ExprKind::Index(ref arr, ref idx) => {
+        hir::ExprKind::Index(arr, idx) => {
             println!("{}Index", ind);
             println!("{}array expr:", ind);
             print_expr(cx, arr, indent + 1);
             println!("{}index expr:", ind);
             print_expr(cx, idx, indent + 1);
         },
-        hir::ExprKind::Path(hir::QPath::Resolved(ref ty, ref path)) => {
+        hir::ExprKind::Path(hir::QPath::Resolved(ref ty, path)) => {
             println!("{}Resolved Path, {:?}", ind, ty);
             println!("{}path: {:?}", ind, path);
         },
-        hir::ExprKind::Path(hir::QPath::TypeRelative(ref ty, ref seg)) => {
+        hir::ExprKind::Path(hir::QPath::TypeRelative(ty, seg)) => {
             println!("{}Relative Path, {:?}", ind, ty);
             println!("{}seg: {:?}", ind, seg);
         },
         hir::ExprKind::Path(hir::QPath::LangItem(lang_item, ..)) => {
             println!("{}Lang Item Path, {:?}", ind, lang_item.name());
         },
-        hir::ExprKind::AddrOf(kind, ref muta, ref e) => {
+        hir::ExprKind::AddrOf(kind, ref muta, e) => {
             println!("{}AddrOf", ind);
             println!("kind: {:?}", kind);
             println!("mutability: {:?}", muta);
@@ -286,18 +286,18 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
         },
         hir::ExprKind::Break(_, ref e) => {
             println!("{}Break", ind);
-            if let Some(ref e) = *e {
+            if let Some(e) = *e {
                 print_expr(cx, e, indent + 1);
             }
         },
         hir::ExprKind::Continue(_) => println!("{}Again", ind),
         hir::ExprKind::Ret(ref e) => {
             println!("{}Ret", ind);
-            if let Some(ref e) = *e {
+            if let Some(e) = *e {
                 print_expr(cx, e, indent + 1);
             }
         },
-        hir::ExprKind::InlineAsm(ref asm) => {
+        hir::ExprKind::InlineAsm(asm) => {
             println!("{}InlineAsm", ind);
             println!("{}template: {}", ind, InlineAsmTemplatePiece::to_string(asm.template));
             println!("{}options: {:?}", ind, asm.options);
@@ -321,11 +321,11 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
                     hir::InlineAsmOperand::Const { anon_const } => {
                         println!("{}anon_const:", ind);
                         print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
-                    }
+                    },
                 }
             }
         },
-        hir::ExprKind::LlvmInlineAsm(ref asm) => {
+        hir::ExprKind::LlvmInlineAsm(asm) => {
             let inputs = &asm.inputs_exprs;
             let outputs = &asm.outputs_exprs;
             println!("{}LlvmInlineAsm", ind);
@@ -338,14 +338,14 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
                 print_expr(cx, e, indent + 1);
             }
         },
-        hir::ExprKind::Struct(ref path, fields, ref base) => {
+        hir::ExprKind::Struct(path, fields, ref base) => {
             println!("{}Struct", ind);
             println!("{}path: {:?}", ind, path);
             for field in fields {
                 println!("{}field \"{}\":", ind, field.ident.name);
-                print_expr(cx, &field.expr, indent + 1);
+                print_expr(cx, field.expr, indent + 1);
             }
-            if let Some(ref base) = *base {
+            if let Some(base) = *base {
                 println!("{}base:", ind);
                 print_expr(cx, base, indent + 1);
             }
@@ -355,7 +355,7 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
             println!("{}anon_const:", ind);
             print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
         },
-        hir::ExprKind::Repeat(ref val, ref anon_const) => {
+        hir::ExprKind::Repeat(val, ref anon_const) => {
             println!("{}Repeat", ind);
             println!("{}value:", ind);
             print_expr(cx, val, indent + 1);
@@ -365,7 +365,7 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
         hir::ExprKind::Err => {
             println!("{}Err", ind);
         },
-        hir::ExprKind::DropTemps(ref e) => {
+        hir::ExprKind::DropTemps(e) => {
             println!("{}DropTemps", ind);
             print_expr(cx, e, indent + 1);
         },
@@ -378,7 +378,7 @@ fn print_item(cx: &LateContext<'_>, item: &hir::Item<'_>) {
     match item.vis.node {
         hir::VisibilityKind::Public => println!("public"),
         hir::VisibilityKind::Crate(_) => println!("visible crate wide"),
-        hir::VisibilityKind::Restricted { ref path, .. } => println!(
+        hir::VisibilityKind::Restricted { path, .. } => println!(
             "visible in module `{}`",
             rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(path, false))
         ),
@@ -398,7 +398,7 @@ fn print_item(cx: &LateContext<'_>, item: &hir::Item<'_>) {
                 println!("weird extern crate without a crate id");
             }
         },
-        hir::ItemKind::Use(ref path, ref kind) => println!("{:?}, {:?}", path, kind),
+        hir::ItemKind::Use(path, ref kind) => println!("{:?}, {:?}", path, kind),
         hir::ItemKind::Static(..) => println!("static item of type {:#?}", cx.tcx.type_of(did)),
         hir::ItemKind::Const(..) => println!("const item of type {:#?}", cx.tcx.type_of(did)),
         hir::ItemKind::Fn(..) => {
@@ -407,7 +407,7 @@ fn print_item(cx: &LateContext<'_>, item: &hir::Item<'_>) {
         },
         hir::ItemKind::Mod(..) => println!("module"),
         hir::ItemKind::ForeignMod { abi, .. } => println!("foreign module with abi: {}", abi),
-        hir::ItemKind::GlobalAsm(ref asm) => println!("global asm: {:?}", asm),
+        hir::ItemKind::GlobalAsm(asm) => println!("global asm: {:?}", asm),
         hir::ItemKind::TyAlias(..) => {
             println!("type alias for {:?}", cx.tcx.type_of(did));
         },
@@ -457,7 +457,7 @@ fn print_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, indent: usize) {
             println!("{}Binding", ind);
             println!("{}mode: {:?}", ind, mode);
             println!("{}name: {}", ind, ident.name);
-            if let Some(ref inner) = *inner {
+            if let Some(inner) = *inner {
                 println!("{}inner:", ind);
                 print_pat(cx, inner, indent + 1);
             }
@@ -482,7 +482,7 @@ fn print_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, indent: usize) {
                 if field.is_shorthand {
                     println!("{}  in shorthand notation", ind);
                 }
-                print_pat(cx, &field.pat, indent + 1);
+                print_pat(cx, field.pat, indent + 1);
             }
         },
         hir::PatKind::TupleStruct(ref path, fields, opt_dots_position) => {
@@ -499,11 +499,11 @@ fn print_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, indent: usize) {
                 print_pat(cx, field, indent + 1);
             }
         },
-        hir::PatKind::Path(hir::QPath::Resolved(ref ty, ref path)) => {
+        hir::PatKind::Path(hir::QPath::Resolved(ref ty, path)) => {
             println!("{}Resolved Path, {:?}", ind, ty);
             println!("{}path: {:?}", ind, path);
         },
-        hir::PatKind::Path(hir::QPath::TypeRelative(ref ty, ref seg)) => {
+        hir::PatKind::Path(hir::QPath::TypeRelative(ty, seg)) => {
             println!("{}Relative Path, {:?}", ind, ty);
             println!("{}seg: {:?}", ind, seg);
         },
@@ -519,16 +519,16 @@ fn print_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, indent: usize) {
                 print_pat(cx, field, indent + 1);
             }
         },
-        hir::PatKind::Box(ref inner) => {
+        hir::PatKind::Box(inner) => {
             println!("{}Box", ind);
             print_pat(cx, inner, indent + 1);
         },
-        hir::PatKind::Ref(ref inner, ref muta) => {
+        hir::PatKind::Ref(inner, ref muta) => {
             println!("{}Ref", ind);
             println!("{}mutability: {:?}", ind, muta);
             print_pat(cx, inner, indent + 1);
         },
-        hir::PatKind::Lit(ref e) => {
+        hir::PatKind::Lit(e) => {
             println!("{}Lit", ind);
             print_expr(cx, e, indent + 1);
         },
@@ -552,7 +552,7 @@ fn print_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, indent: usize) {
                 print_pat(cx, pat, indent + 1);
             }
             println!("i:");
-            if let Some(ref pat) = *range {
+            if let Some(pat) = *range {
                 print_pat(cx, pat, indent + 1);
             }
             println!("[y, z]:");
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
index c496ff1fb24..cf8039d6059 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
@@ -1,8 +1,10 @@
 use crate::consts::{constant_simple, Constant};
-use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg};
+use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::snippet;
 use clippy_utils::ty::match_type;
-use clippy_utils::{is_expn_of, match_def_path, match_qpath, method_calls, path_to_res, paths, run_lints, SpanlessEq};
+use clippy_utils::{
+    is_else_clause, is_expn_of, match_def_path, match_qpath, method_calls, path_to_res, paths, run_lints, SpanlessEq,
+};
 use if_chain::if_chain;
 use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, ModKind, NodeId};
 use rustc_ast::visit::FnKind;
@@ -14,15 +16,17 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::hir_id::CRATE_HIR_ID;
 use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
 use rustc_hir::{
-    BinOpKind, Crate, Expr, ExprKind, HirId, Item, MutTy, Mutability, Node, Path, StmtKind, Ty, TyKind, UnOp,
+    BinOpKind, Block, Crate, Expr, ExprKind, HirId, Item, Local, MatchSource, MutTy, Mutability, Node, Path, Stmt,
+    StmtKind, Ty, TyKind, UnOp,
 };
-use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
+use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::map::Map;
 use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
-use rustc_span::source_map::{Span, Spanned};
+use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{Symbol, SymbolStr};
+use rustc_span::{BytePos, Span};
 use rustc_typeck::hir_ty_to_ty;
 
 use std::borrow::{Borrow, Cow};
@@ -297,6 +301,13 @@ declare_clippy_lint! {
     "unnecessary conversion between Symbol and string"
 }
 
+declare_clippy_lint! {
+    /// Finds unidiomatic usage of `if_chain!`
+    pub IF_CHAIN_STYLE,
+    internal,
+    "non-idiomatic `if_chain!` usage"
+}
+
 declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]);
 
 impl EarlyLintPass for ClippyLintsInternal {
@@ -342,12 +353,12 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
             return;
         }
 
-        if let hir::ItemKind::Static(ref ty, Mutability::Not, body_id) = item.kind {
+        if let hir::ItemKind::Static(ty, Mutability::Not, body_id) = item.kind {
             if is_lint_ref_type(cx, ty) {
                 let expr = &cx.tcx.hir().body(body_id).value;
                 if_chain! {
-                    if let ExprKind::AddrOf(_, _, ref inner_exp) = expr.kind;
-                    if let ExprKind::Struct(_, ref fields, _) = inner_exp.kind;
+                    if let ExprKind::AddrOf(_, _, inner_exp) = expr.kind;
+                    if let ExprKind::Struct(_, fields, _) = inner_exp.kind;
                     let field = fields
                         .iter()
                         .find(|f| f.ident.as_str() == "desc")
@@ -374,7 +385,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
         {
             if let hir::ItemKind::Impl(hir::Impl {
                 of_trait: None,
-                items: ref impl_item_refs,
+                items: impl_item_refs,
                 ..
             }) = item.kind
             {
@@ -426,7 +437,7 @@ fn is_lint_ref_type<'tcx>(cx: &LateContext<'tcx>, ty: &Ty<'_>) -> bool {
     if let TyKind::Rptr(
         _,
         MutTy {
-            ty: ref inner,
+            ty: inner,
             mutbl: Mutability::Not,
         },
     ) = ty.kind
@@ -487,7 +498,7 @@ impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions {
         }
 
         if_chain! {
-            if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind;
+            if let ExprKind::MethodCall(path, _, args, _) = expr.kind;
             let fn_name = path.ident;
             if let Some(sugg) = self.map.get(&*fn_name.as_str());
             let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs();
@@ -566,7 +577,7 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls {
         }
 
         if_chain! {
-            if let ExprKind::Call(ref func, ref and_then_args) = expr.kind;
+            if let ExprKind::Call(func, and_then_args) = expr.kind;
             if let ExprKind::Path(ref path) = func.kind;
             if match_qpath(path, &["span_lint_and_then"]);
             if and_then_args.len() == 5;
@@ -576,10 +587,10 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls {
             let stmts = &block.stmts;
             if stmts.len() == 1 && block.expr.is_none();
             if let StmtKind::Semi(only_expr) = &stmts[0].kind;
-            if let ExprKind::MethodCall(ref ps, _, ref span_call_args, _) = &only_expr.kind;
-            let and_then_snippets = get_and_then_snippets(cx, and_then_args);
-            let mut sle = SpanlessEq::new(cx).deny_side_effects();
+            if let ExprKind::MethodCall(ps, _, span_call_args, _) = &only_expr.kind;
             then {
+                let and_then_snippets = get_and_then_snippets(cx, and_then_args);
+                let mut sle = SpanlessEq::new(cx).deny_side_effects();
                 match &*ps.ident.as_str() {
                     "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
                         suggest_suggestion(cx, expr, &and_then_snippets, &span_suggestion_snippets(cx, span_call_args));
@@ -751,7 +762,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem {
             // Check if this is a call to utils::match_type()
             if let ExprKind::Call(fn_path, [context, ty, ty_path]) = expr.kind;
             if let ExprKind::Path(fn_qpath) = &fn_path.kind;
-            if match_qpath(&fn_qpath, &["utils", "match_type"]);
+            if match_qpath(fn_qpath, &["utils", "match_type"]);
             // Extract the path to the matched type
             if let Some(segments) = path_to_matched_type(cx, ty_path);
             let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect();
@@ -1063,3 +1074,159 @@ impl<'tcx> SymbolStrExpr<'tcx> {
         }
     }
 }
+
+declare_lint_pass!(IfChainStyle => [IF_CHAIN_STYLE]);
+
+impl<'tcx> LateLintPass<'tcx> for IfChainStyle {
+    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
+        let (local, after, if_chain_span) = if_chain! {
+            if let [Stmt { kind: StmtKind::Local(local), .. }, after @ ..] = block.stmts;
+            if let Some(if_chain_span) = is_expn_of(block.span, "if_chain");
+            then { (local, after, if_chain_span) } else { return }
+        };
+        if is_first_if_chain_expr(cx, block.hir_id, if_chain_span) {
+            span_lint(
+                cx,
+                IF_CHAIN_STYLE,
+                if_chain_local_span(cx, local, if_chain_span),
+                "`let` expression should be above the `if_chain!`",
+            );
+        } else if local.span.ctxt() == block.span.ctxt() && is_if_chain_then(after, block.expr, if_chain_span) {
+            span_lint(
+                cx,
+                IF_CHAIN_STYLE,
+                if_chain_local_span(cx, local, if_chain_span),
+                "`let` expression should be inside `then { .. }`",
+            )
+        }
+    }
+
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+        let (cond, then, els) = match expr.kind {
+            ExprKind::If(cond, then, els) => (Some(cond), then, els.is_some()),
+            ExprKind::Match(
+                _,
+                [arm, ..],
+                MatchSource::IfLetDesugar {
+                    contains_else_clause: els,
+                },
+            ) => (None, arm.body, els),
+            _ => return,
+        };
+        let then_block = match then.kind {
+            ExprKind::Block(block, _) => block,
+            _ => return,
+        };
+        let if_chain_span = is_expn_of(expr.span, "if_chain");
+        if !els {
+            check_nested_if_chains(cx, expr, then_block, if_chain_span);
+        }
+        let if_chain_span = match if_chain_span {
+            None => return,
+            Some(span) => span,
+        };
+        // check for `if a && b;`
+        if_chain! {
+            if let Some(cond) = cond;
+            if let ExprKind::Binary(op, _, _) = cond.kind;
+            if op.node == BinOpKind::And;
+            if cx.sess().source_map().is_multiline(cond.span);
+            then {
+                span_lint(cx, IF_CHAIN_STYLE, cond.span, "`if a && b;` should be `if a; if b;`");
+            }
+        }
+        if is_first_if_chain_expr(cx, expr.hir_id, if_chain_span)
+            && is_if_chain_then(then_block.stmts, then_block.expr, if_chain_span)
+        {
+            span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`")
+        }
+    }
+}
+
+fn check_nested_if_chains(
+    cx: &LateContext<'_>,
+    if_expr: &Expr<'_>,
+    then_block: &Block<'_>,
+    if_chain_span: Option<Span>,
+) {
+    #[rustfmt::skip]
+    let (head, tail) = match *then_block {
+        Block { stmts, expr: Some(tail), .. } => (stmts, tail),
+        Block {
+            stmts: &[
+                ref head @ ..,
+                Stmt { kind: StmtKind::Expr(tail) | StmtKind::Semi(tail), .. }
+            ],
+            ..
+        } => (head, tail),
+        _ => return,
+    };
+    if_chain! {
+        if matches!(tail.kind,
+            ExprKind::If(_, _, None)
+            | ExprKind::Match(.., MatchSource::IfLetDesugar { contains_else_clause: false }));
+        let sm = cx.sess().source_map();
+        if head
+            .iter()
+            .all(|stmt| matches!(stmt.kind, StmtKind::Local(..)) && !sm.is_multiline(stmt.span));
+        if if_chain_span.is_some() || !is_else_clause(cx.tcx, if_expr);
+        then {} else { return }
+    }
+    let (span, msg) = match (if_chain_span, is_expn_of(tail.span, "if_chain")) {
+        (None, Some(_)) => (if_expr.span, "this `if` can be part of the inner `if_chain!`"),
+        (Some(_), None) => (tail.span, "this `if` can be part of the outer `if_chain!`"),
+        (Some(a), Some(b)) if a != b => (b, "this `if_chain!` can be merged with the outer `if_chain!`"),
+        _ => return,
+    };
+    span_lint_and_then(cx, IF_CHAIN_STYLE, span, msg, |diag| {
+        let (span, msg) = match head {
+            [] => return,
+            [stmt] => (stmt.span, "this `let` statement can also be in the `if_chain!`"),
+            [a, .., b] => (
+                a.span.to(b.span),
+                "these `let` statements can also be in the `if_chain!`",
+            ),
+        };
+        diag.span_help(span, msg);
+    });
+}
+
+fn is_first_if_chain_expr(cx: &LateContext<'_>, hir_id: HirId, if_chain_span: Span) -> bool {
+    cx.tcx
+        .hir()
+        .parent_iter(hir_id)
+        .find(|(_, node)| {
+            #[rustfmt::skip]
+            !matches!(node, Node::Expr(Expr { kind: ExprKind::Block(..), .. }) | Node::Stmt(_))
+        })
+        .map_or(false, |(id, _)| {
+            is_expn_of(cx.tcx.hir().span(id), "if_chain") != Some(if_chain_span)
+        })
+}
+
+/// Checks a trailing slice of statements and expression of a `Block` to see if they are part
+/// of the `then {..}` portion of an `if_chain!`
+fn is_if_chain_then(stmts: &[Stmt<'_>], expr: Option<&Expr<'_>>, if_chain_span: Span) -> bool {
+    let span = if let [stmt, ..] = stmts {
+        stmt.span
+    } else if let Some(expr) = expr {
+        expr.span
+    } else {
+        // empty `then {}`
+        return true;
+    };
+    is_expn_of(span, "if_chain").map_or(true, |span| span != if_chain_span)
+}
+
+/// Creates a `Span` for `let x = ..;` in an `if_chain!` call.
+fn if_chain_local_span(cx: &LateContext<'_>, local: &Local<'_>, if_chain_span: Span) -> Span {
+    let mut span = local.pat.span;
+    if let Some(init) = local.init {
+        span = span.to(init.span);
+    }
+    span.adjust(if_chain_span.ctxt().outer_expn());
+    let sm = cx.sess().source_map();
+    let span = sm.span_extend_to_prev_str(span, "let", false);
+    let span = sm.span_extend_to_next_char(span, ';', false);
+    Span::new(span.lo() - BytePos(3), span.hi() + BytePos(1), span.ctxt())
+}
diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs
index 1af9583887f..febd4b6ff7b 100644
--- a/src/tools/clippy/clippy_lints/src/vec.rs
+++ b/src/tools/clippy/clippy_lints/src/vec.rs
@@ -6,7 +6,7 @@ use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_copy;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{BorrowKind, Expr, ExprKind};
+use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -49,10 +49,10 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
         if_chain! {
             if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(expr).kind();
             if let ty::Slice(..) = ty.kind();
-            if let ExprKind::AddrOf(BorrowKind::Ref, _, ref addressee) = expr.kind;
+            if let ExprKind::AddrOf(BorrowKind::Ref, mutability, addressee) = expr.kind;
             if let Some(vec_args) = higher::vec_macro(cx, addressee);
             then {
-                self.check_vec_macro(cx, &vec_args, expr.span);
+                self.check_vec_macro(cx, &vec_args, mutability, expr.span);
             }
         }
 
@@ -70,14 +70,20 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
                     .ctxt()
                     .outer_expn_data()
                     .call_site;
-                self.check_vec_macro(cx, &vec_args, span);
+                self.check_vec_macro(cx, &vec_args, Mutability::Not, span);
             }
         }
     }
 }
 
 impl UselessVec {
-    fn check_vec_macro<'tcx>(self, cx: &LateContext<'tcx>, vec_args: &higher::VecArgs<'tcx>, span: Span) {
+    fn check_vec_macro<'tcx>(
+        self,
+        cx: &LateContext<'tcx>,
+        vec_args: &higher::VecArgs<'tcx>,
+        mutability: Mutability,
+        span: Span,
+    ) {
         let mut applicability = Applicability::MachineApplicable;
         let snippet = match *vec_args {
             higher::VecArgs::Repeat(elem, len) => {
@@ -87,11 +93,22 @@ impl UselessVec {
                         return;
                     }
 
-                    format!(
-                        "&[{}; {}]",
-                        snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
-                        snippet_with_applicability(cx, len.span, "len", &mut applicability)
-                    )
+                    match mutability {
+                        Mutability::Mut => {
+                            format!(
+                                "&mut [{}; {}]",
+                                snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
+                                snippet_with_applicability(cx, len.span, "len", &mut applicability)
+                            )
+                        },
+                        Mutability::Not => {
+                            format!(
+                                "&[{}; {}]",
+                                snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
+                                snippet_with_applicability(cx, len.span, "len", &mut applicability)
+                            )
+                        },
+                    }
                 } else {
                     return;
                 }
@@ -104,9 +121,22 @@ impl UselessVec {
                     }
                     let span = args[0].span.to(last.span);
 
-                    format!("&[{}]", snippet_with_applicability(cx, span, "..", &mut applicability))
+                    match mutability {
+                        Mutability::Mut => {
+                            format!(
+                                "&mut [{}]",
+                                snippet_with_applicability(cx, span, "..", &mut applicability)
+                            )
+                        },
+                        Mutability::Not => {
+                            format!("&[{}]", snippet_with_applicability(cx, span, "..", &mut applicability))
+                        },
+                    }
                 } else {
-                    "&[]".into()
+                    match mutability {
+                        Mutability::Mut => "&mut []".into(),
+                        Mutability::Not => "&[]".into(),
+                    }
                 }
             },
         };
diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
index 8b696ed1c84..c7190e2f979 100644
--- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
@@ -108,22 +108,21 @@ impl LateLintPass<'_> for VecInitThenPush {
     }
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if self.searcher.is_none() {
-            if_chain! {
-                if !in_external_macro(cx.sess(), expr.span);
-                if let ExprKind::Assign(left, right, _) = expr.kind;
-                if let Some(id) = path_to_local(left);
-                if let Some(init_kind) = get_vec_init_kind(cx, right);
-                then {
-                    self.searcher = Some(VecPushSearcher {
-                        local_id: id,
-                        init: init_kind,
-                        lhs_is_local: false,
-                        lhs_span: left.span,
-                        err_span: expr.span,
-                        found: 0,
-                    });
-                }
+        if_chain! {
+            if self.searcher.is_none();
+            if !in_external_macro(cx.sess(), expr.span);
+            if let ExprKind::Assign(left, right, _) = expr.kind;
+            if let Some(id) = path_to_local(left);
+            if let Some(init_kind) = get_vec_init_kind(cx, right);
+            then {
+                self.searcher = Some(VecPushSearcher {
+                    local_id: id,
+                    init: init_kind,
+                    lhs_is_local: false,
+                    lhs_span: left.span,
+                    err_span: expr.span,
+                    found: 0,
+                });
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs b/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs
index e035d3c5cad..5540e87405f 100644
--- a/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs
@@ -30,7 +30,7 @@ declare_lint_pass!(VecResizeToZero => [VEC_RESIZE_TO_ZERO]);
 impl<'tcx> LateLintPass<'tcx> for VecResizeToZero {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
-            if let hir::ExprKind::MethodCall(path_segment, _, ref args, _) = expr.kind;
+            if let hir::ExprKind::MethodCall(path_segment, _, args, _) = expr.kind;
             if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
             if match_def_path(cx, method_def_id, &paths::VEC_RESIZE) && args.len() == 3;
             if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = args[1].kind;
diff --git a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
index 3b4890ad560..350b1cf25ff 100644
--- a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
@@ -31,7 +31,7 @@ impl<'tcx> LateLintPass<'tcx> for ZeroDiv {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         // check for instances of 0.0/0.0
         if_chain! {
-            if let ExprKind::Binary(ref op, ref left, ref right) = expr.kind;
+            if let ExprKind::Binary(ref op, left, right) = expr.kind;
             if let BinOpKind::Div = op.node;
             // TODO - constant_simple does not fold many operations involving floats.
             // That's probably fine for this lint - it's pretty unlikely that someone would
diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
index 2abd033e2a0..f93f0047f51 100644
--- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
@@ -50,7 +50,7 @@ impl LateLintPass<'_> for ZeroSizedMapValues {
             if !in_trait_impl(cx, hir_ty.hir_id);
             let ty = ty_from_hir_ty(cx, hir_ty);
             if is_type_diagnostic_item(cx, ty, sym::hashmap_type) || match_type(cx, ty, &paths::BTREEMAP);
-            if let Adt(_, ref substs) = ty.kind();
+            if let Adt(_, substs) = ty.kind();
             let ty = substs.type_at(1);
             // Do this to prevent `layout_of` crashing, being unable to fully normalize `ty`.
             if is_normalizable(cx, cx.param_env, ty);
diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs
index 8d28421d70d..7ec8452bf4c 100644
--- a/src/tools/clippy/clippy_utils/src/attrs.rs
+++ b/src/tools/clippy/clippy_utils/src/attrs.rs
@@ -1,4 +1,4 @@
-use rustc_ast::ast;
+use rustc_ast::{ast, attr};
 use rustc_errors::Applicability;
 use rustc_session::Session;
 use rustc_span::sym;
@@ -148,3 +148,13 @@ pub fn get_unique_inner_attr(sess: &Session, attrs: &[ast::Attribute], name: &'s
 pub fn is_proc_macro(sess: &Session, attrs: &[ast::Attribute]) -> bool {
     attrs.iter().any(|attr| sess.is_proc_macro_attr(attr))
 }
+
+/// Return true if the attributes contain `#[doc(hidden)]`
+pub fn is_doc_hidden(attrs: &[ast::Attribute]) -> bool {
+    #[allow(clippy::filter_map)]
+    attrs
+        .iter()
+        .filter(|attr| attr.has_name(sym::doc))
+        .flat_map(ast::Attribute::meta_item_list)
+        .any(|l| attr::list_contains_name(&l, sym::hidden))
+}
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 8af10ebe777..2a305d8bcbe 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -140,12 +140,10 @@ impl Constant {
             (&Self::F64(l), &Self::F64(r)) => l.partial_cmp(&r),
             (&Self::F32(l), &Self::F32(r)) => l.partial_cmp(&r),
             (&Self::Bool(ref l), &Self::Bool(ref r)) => Some(l.cmp(r)),
-            (&Self::Tuple(ref l), &Self::Tuple(ref r)) | (&Self::Vec(ref l), &Self::Vec(ref r)) => {
-                iter::zip(l, r)
-                    .map(|(li, ri)| Self::partial_cmp(tcx, cmp_type, li, ri))
-                    .find(|r| r.map_or(true, |o| o != Ordering::Equal))
-                    .unwrap_or_else(|| Some(l.len().cmp(&r.len())))
-            }
+            (&Self::Tuple(ref l), &Self::Tuple(ref r)) | (&Self::Vec(ref l), &Self::Vec(ref r)) => iter::zip(l, r)
+                .map(|(li, ri)| Self::partial_cmp(tcx, cmp_type, li, ri))
+                .find(|r| r.map_or(true, |o| o != Ordering::Equal))
+                .unwrap_or_else(|| Some(l.len().cmp(&r.len()))),
             (&Self::Repeat(ref lv, ref ls), &Self::Repeat(ref rv, ref rs)) => {
                 match Self::partial_cmp(tcx, cmp_type, lv, rv) {
                     Some(Equal) => Some(ls.cmp(rs)),
diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs
index e9c9cb12b9d..7f827f1759d 100644
--- a/src/tools/clippy/clippy_utils/src/diagnostics.rs
+++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs
@@ -133,9 +133,11 @@ pub fn span_lint_and_note<'a, T: LintContext>(
 ///
 /// If you need to customize your lint output a lot, use this function.
 /// If you change the signature, remember to update the internal lint `CollapsibleCalls`
-pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F)
+pub fn span_lint_and_then<C, S, F>(cx: &C, lint: &'static Lint, sp: S, msg: &str, f: F)
 where
-    F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>),
+    C: LintContext,
+    S: Into<MultiSpan>,
+    F: FnOnce(&mut DiagnosticBuilder<'_>),
 {
     cx.struct_span_lint(lint, sp, |diag| {
         let mut diag = diag.build(msg);
@@ -216,6 +218,11 @@ where
     multispan_sugg_with_applicability(diag, help_msg, Applicability::Unspecified, sugg)
 }
 
+/// Create a suggestion made from several `span → replacement`.
+///
+/// rustfix currently doesn't support the automatic application of suggestions with
+/// multiple spans. This is tracked in issue [rustfix#141](https://github.com/rust-lang/rustfix/issues/141).
+/// Suggestions with multiple spans will be silently ignored.
 pub fn multispan_sugg_with_applicability<I>(
     diag: &mut DiagnosticBuilder<'_>,
     help_msg: &str,
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index b30c0b79881..f695f1a61e7 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -2,9 +2,9 @@ use crate::consts::{constant_context, constant_simple};
 use crate::differing_macro_contexts;
 use crate::source::snippet_opt;
 use rustc_ast::ast::InlineAsmTemplatePiece;
-use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::def::Res;
+use rustc_hir::HirIdMap;
 use rustc_hir::{
     BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprField, ExprKind, FnRetTy, GenericArg,
     GenericArgs, Guard, HirId, InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path,
@@ -58,13 +58,14 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
 
     /// Use this method to wrap comparisons that may involve inter-expression context.
     /// See `self.locals`.
-    fn inter_expr(&mut self) -> HirEqInterExpr<'_, 'a, 'tcx> {
+    pub fn inter_expr(&mut self) -> HirEqInterExpr<'_, 'a, 'tcx> {
         HirEqInterExpr {
             inner: self,
-            locals: FxHashMap::default(),
+            locals: HirIdMap::default(),
         }
     }
 
+    #[allow(dead_code)]
     pub fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool {
         self.inter_expr().eq_block(left, right)
     }
@@ -82,22 +83,24 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
     }
 }
 
-struct HirEqInterExpr<'a, 'b, 'tcx> {
+pub struct HirEqInterExpr<'a, 'b, 'tcx> {
     inner: &'a mut SpanlessEq<'b, 'tcx>,
 
     // When binding are declared, the binding ID in the left expression is mapped to the one on the
     // right. For example, when comparing `{ let x = 1; x + 2 }` and `{ let y = 1; y + 2 }`,
     // these blocks are considered equal since `x` is mapped to `y`.
-    locals: FxHashMap<HirId, HirId>,
+    locals: HirIdMap<HirId>,
 }
 
 impl HirEqInterExpr<'_, '_, '_> {
-    fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool {
+    pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool {
         match (&left.kind, &right.kind) {
             (&StmtKind::Local(ref l), &StmtKind::Local(ref r)) => {
-                self.eq_pat(&l.pat, &r.pat)
+                // eq_pat adds the HirIds to the locals map. We therefor call it last to make sure that
+                // these only get added if the init and type is equal.
+                both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
                     && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r))
-                    && both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
+                    && self.eq_pat(&l.pat, &r.pat)
             },
             (&StmtKind::Expr(ref l), &StmtKind::Expr(ref r)) | (&StmtKind::Semi(ref l), &StmtKind::Semi(ref r)) => {
                 self.eq_expr(l, r)
@@ -159,7 +162,7 @@ impl HirEqInterExpr<'_, '_, '_> {
     }
 
     #[allow(clippy::similar_names)]
-    fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
+    pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
         if !self.inner.allow_side_effects && differing_macro_contexts(left.span, right.span) {
             return false;
         }
@@ -483,6 +486,15 @@ pub fn over<X>(left: &[X], right: &[X], mut eq_fn: impl FnMut(&X, &X) -> bool) -
     left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y))
 }
 
+/// Counts how many elements of the slices are equal as per `eq_fn`.
+pub fn count_eq<X: Sized>(
+    left: &mut dyn Iterator<Item = X>,
+    right: &mut dyn Iterator<Item = X>,
+    mut eq_fn: impl FnMut(&X, &X) -> bool,
+) -> usize {
+    left.zip(right).take_while(|(l, r)| eq_fn(l, r)).count()
+}
+
 /// Checks if two expressions evaluate to the same value, and don't contain any side effects.
 pub fn eq_expr_value(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>) -> bool {
     SpanlessEq::new(cx).deny_side_effects().eq_expr(left, right)
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 6b235875c20..c847712ec2e 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -48,7 +48,7 @@ pub mod usage;
 pub mod visitors;
 
 pub use self::attrs::*;
-pub use self::hir_utils::{both, eq_expr_value, over, SpanlessEq, SpanlessHash};
+pub use self::hir_utils::{both, count_eq, eq_expr_value, over, SpanlessEq, SpanlessHash};
 
 use std::collections::hash_map::Entry;
 use std::hash::BuildHasherDefault;
@@ -61,10 +61,9 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{
-    def, Arm, BindingAnnotation, Block, Body, Constness, Expr, ExprKind, FieldDef, FnDecl, ForeignItem, GenericArgs,
-    GenericParam, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, LangItem, Lifetime, Local, MacroDef,
-    MatchSource, Mod, Node, Param, Pat, PatKind, Path, PathSegment, QPath, Stmt, TraitItem, TraitItemKind, TraitRef,
-    TyKind, Variant, Visibility,
+    def, Arm, BindingAnnotation, Block, Body, Constness, Expr, ExprKind, FnDecl, GenericArgs, HirId, Impl, ImplItem,
+    ImplItemKind, Item, ItemKind, LangItem, MatchSource, Node, Param, Pat, PatKind, Path, PathSegment, QPath,
+    TraitItem, TraitItemKind, TraitRef, TyKind,
 };
 use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::exports::Export;
@@ -76,7 +75,7 @@ use rustc_session::Session;
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::original_sp;
 use rustc_span::sym;
-use rustc_span::symbol::{kw, Ident, Symbol};
+use rustc_span::symbol::{kw, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::Integer;
 
@@ -350,6 +349,10 @@ pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment
     }
 }
 
+/// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the
+/// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from
+/// `QPath::Resolved.1.res.opt_def_id()`.
+///
 /// Matches a `QPath` against a slice of segment string literals.
 ///
 /// There is also `match_path` if you are dealing with a `rustc_hir::Path` instead of a
@@ -377,6 +380,10 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
     }
 }
 
+/// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the
+/// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from
+/// `QPath::Resolved.1.res.opt_def_id()`.
+///
 /// Matches a `Path` against a slice of segment string literals.
 ///
 /// There is also `match_qpath` if you are dealing with a `rustc_hir::QPath` instead of a
@@ -610,9 +617,9 @@ pub fn get_pat_name(pat: &Pat<'_>) -> Option<Symbol> {
     }
 }
 
-struct ContainsName {
-    name: Symbol,
-    result: bool,
+pub struct ContainsName {
+    pub name: Symbol,
+    pub result: bool,
 }
 
 impl<'tcx> Visitor<'tcx> for ContainsName {
@@ -713,41 +720,6 @@ fn line_span<T: LintContext>(cx: &T, span: Span) -> Span {
     Span::new(line_start, span.hi(), span.ctxt())
 }
 
-/// Gets the span of the node, if there is one.
-pub fn get_node_span(node: Node<'_>) -> Option<Span> {
-    match node {
-        Node::Param(Param { span, .. })
-        | Node::Item(Item { span, .. })
-        | Node::ForeignItem(ForeignItem { span, .. })
-        | Node::TraitItem(TraitItem { span, .. })
-        | Node::ImplItem(ImplItem { span, .. })
-        | Node::Variant(Variant { span, .. })
-        | Node::Field(FieldDef { span, .. })
-        | Node::Expr(Expr { span, .. })
-        | Node::Stmt(Stmt { span, .. })
-        | Node::PathSegment(PathSegment {
-            ident: Ident { span, .. },
-            ..
-        })
-        | Node::Ty(hir::Ty { span, .. })
-        | Node::TraitRef(TraitRef {
-            path: Path { span, .. },
-            ..
-        })
-        | Node::Binding(Pat { span, .. })
-        | Node::Pat(Pat { span, .. })
-        | Node::Arm(Arm { span, .. })
-        | Node::Block(Block { span, .. })
-        | Node::Local(Local { span, .. })
-        | Node::MacroDef(MacroDef { span, .. })
-        | Node::Lifetime(Lifetime { span, .. })
-        | Node::GenericParam(GenericParam { span, .. })
-        | Node::Visibility(Visibility { span, .. })
-        | Node::Crate(Mod { inner: span, .. }) => Some(*span),
-        Node::Ctor(_) | Node::AnonConst(_) => None,
-    }
-}
-
 /// Gets the parent node, if any.
 pub fn get_parent_node(tcx: TyCtxt<'_>, id: HirId) -> Option<Node<'_>> {
     tcx.hir().parent_iter(id).next().map(|(_, node)| node)
@@ -798,22 +770,29 @@ pub fn get_parent_as_impl(tcx: TyCtxt<'_>, id: HirId) -> Option<&Impl<'_>> {
     }
 }
 
-/// Checks if the given expression is the else clause in the expression `if let .. {} else {}`
-pub fn is_else_clause_of_if_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
+/// Checks if the given expression is the else clause of either an `if` or `if let` expression.
+pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
     let map = tcx.hir();
     let mut iter = map.parent_iter(expr.hir_id);
-    let arm_id = match iter.next() {
-        Some((id, Node::Arm(..))) => id,
-        _ => return false,
-    };
     match iter.next() {
+        Some((arm_id, Node::Arm(..))) => matches!(
+            iter.next(),
+            Some((
+                _,
+                Node::Expr(Expr {
+                    kind: ExprKind::Match(_, [_, else_arm], MatchSource::IfLetDesugar { .. }),
+                    ..
+                })
+            ))
+            if else_arm.hir_id == arm_id
+        ),
         Some((
             _,
             Node::Expr(Expr {
-                kind: ExprKind::Match(_, [_, else_arm], kind),
+                kind: ExprKind::If(_, _, Some(else_expr)),
                 ..
             }),
-        )) => else_arm.hir_id == arm_id && matches!(kind, MatchSource::IfLetDesugar { .. }),
+        )) => else_expr.hir_id == expr.hir_id,
         _ => false,
     }
 }
@@ -1210,6 +1189,8 @@ pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>,
     (conds, blocks)
 }
 
+/// This function returns true if the given expression is the `else` or `if else` part of an if
+/// statement
 pub fn parent_node_is_if_expr(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool {
     let map = cx.tcx.hir();
     let parent_id = map.get_parent_node(expr.hir_id);
@@ -1223,16 +1204,9 @@ pub fn parent_node_is_if_expr(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool {
     )
 }
 
-// Finds the attribute with the given name, if any
-pub fn attr_by_name<'a>(attrs: &'a [Attribute], name: &'_ str) -> Option<&'a Attribute> {
-    attrs
-        .iter()
-        .find(|attr| attr.ident().map_or(false, |ident| ident.as_str() == name))
-}
-
 // Finds the `#[must_use]` attribute, if any
 pub fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> {
-    attr_by_name(attrs, "must_use")
+    attrs.iter().find(|a| a.has_name(sym::must_use))
 }
 
 // check if expr is calling method or function with #[must_use] attribute
@@ -1320,6 +1294,16 @@ pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<DefId> {
     }
 }
 
+/// This function checks if any of the lints in the slice is enabled for the provided `HirId`.
+/// A lint counts as enabled with any of the levels: `Level::Forbid` | `Level::Deny` | `Level::Warn`
+///
+/// ```ignore
+/// #[deny(clippy::YOUR_AWESOME_LINT)]
+/// println!("Hello, World!"); // <- Clippy code: run_lints(cx, &[YOUR_AWESOME_LINT], id) == true
+///
+/// #[allow(clippy::YOUR_AWESOME_LINT)]
+/// println!("See you soon!"); // <- Clippy code: run_lints(cx, &[YOUR_AWESOME_LINT], id) == false
+/// ```
 pub fn run_lints(cx: &LateContext<'_>, lints: &[&'static Lint], id: HirId) -> bool {
     lints.iter().any(|lint| {
         matches!(
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 11a446e42a4..3b4c4070c0e 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -26,6 +26,7 @@ pub const DEFAULT_TRAIT: [&str; 3] = ["core", "default", "Default"];
 pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"];
 pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"];
 pub const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
+pub const DIR_BUILDER: [&str; 3] = ["std", "fs", "DirBuilder"];
 pub const DISPLAY_FMT_METHOD: [&str; 4] = ["core", "fmt", "Display", "fmt"];
 pub const DISPLAY_TRAIT: [&str; 3] = ["core", "fmt", "Display"];
 pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"];
@@ -92,9 +93,10 @@ pub(super) const PANIC_ANY: [&str; 3] = ["std", "panic", "panic_any"];
 pub const PARKING_LOT_MUTEX_GUARD: [&str; 2] = ["parking_lot", "MutexGuard"];
 pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 2] = ["parking_lot", "RwLockReadGuard"];
 pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 2] = ["parking_lot", "RwLockWriteGuard"];
-pub const PATH_BUF: [&str; 3] = ["std", "path", "PathBuf"];
 pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
 pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
+pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"];
+pub const PERMISSIONS_FROM_MODE: [&str; 7] = ["std", "sys", "unix", "ext", "fs", "PermissionsExt", "from_mode"];
 pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
 pub const POLL_PENDING: [&str; 5] = ["core", "task", "poll", "Poll", "Pending"];
 pub const POLL_READY: [&str; 5] = ["core", "task", "poll", "Poll", "Ready"];
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index dac4d93499d..b52cbf31e35 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -210,7 +210,7 @@ fn check_statement(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, statemen
         StatementKind::Assign(box (place, rval)) => {
             check_place(tcx, *place, span, body)?;
             check_rvalue(tcx, body, def_id, rval, span)
-        }
+        },
 
         StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body),
         // just an assignment
@@ -218,13 +218,11 @@ fn check_statement(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, statemen
 
         StatementKind::LlvmInlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())),
 
-        StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping{
-          dst, src, count,
-        }) => {
-          check_operand(tcx, dst, span, body)?;
-          check_operand(tcx, src, span, body)?;
-          check_operand(tcx, count, span, body)
-        }
+        StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { dst, src, count }) => {
+            check_operand(tcx, dst, span, body)?;
+            check_operand(tcx, src, span, body)?;
+            check_operand(tcx, count, span, body)
+        },
         // These are all NOPs
         StatementKind::StorageLive(_)
         | StatementKind::StorageDead(_)
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index b2fe4317154..0633a19391f 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -267,17 +267,44 @@ impl<'a> Sugg<'a> {
             Sugg::NonParen(..) => self,
             // `(x)` and `(x).y()` both don't need additional parens.
             Sugg::MaybeParen(sugg) => {
-                if sugg.starts_with('(') && sugg.ends_with(')') {
+                if has_enclosing_paren(&sugg) {
                     Sugg::MaybeParen(sugg)
                 } else {
                     Sugg::NonParen(format!("({})", sugg).into())
                 }
             },
-            Sugg::BinOp(_, sugg) => Sugg::NonParen(format!("({})", sugg).into()),
+            Sugg::BinOp(_, sugg) => {
+                if has_enclosing_paren(&sugg) {
+                    Sugg::NonParen(sugg)
+                } else {
+                    Sugg::NonParen(format!("({})", sugg).into())
+                }
+            },
         }
     }
 }
 
+/// Return `true` if `sugg` is enclosed in parenthesis.
+fn has_enclosing_paren(sugg: impl AsRef<str>) -> bool {
+    let mut chars = sugg.as_ref().chars();
+    if let Some('(') = chars.next() {
+        let mut depth = 1;
+        while let Some(c) = chars.next() {
+            if c == '(' {
+                depth += 1;
+            } else if c == ')' {
+                depth -= 1;
+            }
+            if depth == 0 {
+                break;
+            }
+        }
+        chars.next().is_none()
+    } else {
+        false
+    }
+}
+
 // Copied from the rust standart library, and then edited
 macro_rules! forward_binop_impls_to_ref {
     (impl $imp:ident, $method:ident for $t:ty, type Output = $o:ty) => {
@@ -668,6 +695,8 @@ impl<T: LintContext> DiagnosticBuilderExt<T> for rustc_errors::DiagnosticBuilder
 #[cfg(test)]
 mod test {
     use super::Sugg;
+
+    use rustc_ast::util::parser::AssocOp;
     use std::borrow::Cow;
 
     const SUGGESTION: Sugg<'static> = Sugg::NonParen(Cow::Borrowed("function_call()"));
@@ -681,4 +710,13 @@ mod test {
     fn blockify_transforms_sugg_into_a_block() {
         assert_eq!("{ function_call() }", SUGGESTION.blockify().to_string());
     }
+
+    #[test]
+    fn binop_maybe_par() {
+        let sugg = Sugg::BinOp(AssocOp::Add, "(1 + 1)".into());
+        assert_eq!("(1 + 1)", sugg.maybe_par().to_string());
+
+        let sugg = Sugg::BinOp(AssocOp::Add, "(1 + 1) + (1 + 1)".into());
+        assert_eq!("((1 + 1) + (1 + 1))", sugg.maybe_par().to_string());
+    }
 }
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index 54f110988d7..650b70c63af 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -1,9 +1,9 @@
 use crate as utils;
-use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::intravisit;
 use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
+use rustc_hir::HirIdSet;
 use rustc_hir::{Expr, ExprKind, HirId, Path};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
@@ -13,9 +13,9 @@ use rustc_middle::ty;
 use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 
 /// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined.
-pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> Option<FxHashSet<HirId>> {
+pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> Option<HirIdSet> {
     let mut delegate = MutVarsDelegate {
-        used_mutably: FxHashSet::default(),
+        used_mutably: HirIdSet::default(),
         skip: false,
     };
     cx.tcx.infer_ctxt().enter(|infcx| {
@@ -44,7 +44,7 @@ pub fn is_potentially_mutated<'tcx>(variable: &'tcx Path<'_>, expr: &'tcx Expr<'
 }
 
 struct MutVarsDelegate {
-    used_mutably: FxHashSet<HirId>,
+    used_mutably: HirIdSet,
     skip: bool,
 }
 
diff --git a/src/tools/clippy/doc/adding_lints.md b/src/tools/clippy/doc/adding_lints.md
index 575853996c0..99b86953d51 100644
--- a/src/tools/clippy/doc/adding_lints.md
+++ b/src/tools/clippy/doc/adding_lints.md
@@ -18,7 +18,7 @@ because that's clearly a non-descriptive name.
   - [Lint passes](#lint-passes)
   - [Emitting a lint](#emitting-a-lint)
   - [Adding the lint logic](#adding-the-lint-logic)
-  - [Specifying the lint's minimum supported Rust version (msrv)](#specifying-the-lints-minimum-supported-rust-version-msrv)
+  - [Specifying the lint's minimum supported Rust version (MSRV)](#specifying-the-lints-minimum-supported-rust-version-msrv)
   - [Author lint](#author-lint)
   - [Documentation](#documentation)
   - [Running rustfmt](#running-rustfmt)
@@ -388,18 +388,19 @@ pass.
 [`FnKind::Fn`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/visit/enum.FnKind.html#variant.Fn
 [ident]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Ident.html
 
-## Specifying the lint's minimum supported Rust version (msrv)
+## Specifying the lint's minimum supported Rust version (MSRV)
 
-Projects supporting older versions of Rust would need to disable a lint if it targets features
-present in later versions. Support for this can be added by specifying an msrv in your lint like so,
+Projects supporting older versions of Rust would need to disable a lint if it
+targets features present in later versions. Support for this can be added by
+specifying an MSRV in your lint like so,
 
 ```rust
 const MANUAL_STRIP_MSRV: RustcVersion = RustcVersion::new(1, 45, 0);
 ```
 
-The project's msrv will also have to be an attribute in the lint so you'll have to add a struct
-and constructor for your lint. The project's msrv needs to be passed when the lint is registered
-in `lib.rs`
+The project's MSRV will also have to be an attribute in the lint so you'll have
+to add a struct and constructor for your lint. The project's MSRV needs to be
+passed when the lint is registered in `lib.rs`
 
 ```rust
 pub struct ManualStrip {
@@ -414,8 +415,8 @@ impl ManualStrip {
 }
 ```
 
-The project's msrv can then be matched against the lint's msrv in the LintPass using the `meets_msrv` utility
-function.
+The project's MSRV can then be matched against the lint's `msrv` in the LintPass
+using the `meets_msrv` utility function.
 
 ``` rust
 if !meets_msrv(self.msrv.as_ref(), &MANUAL_STRIP_MSRV) {
@@ -423,9 +424,10 @@ if !meets_msrv(self.msrv.as_ref(), &MANUAL_STRIP_MSRV) {
 }
 ```
 
-The project's msrv can also be specified as an inner attribute, which overrides the value from
-`clippy.toml`. This can be accounted for using the `extract_msrv_attr!(LintContext)` macro and passing
-LateContext/EarlyContext.
+The project's MSRV can also be specified as an inner attribute, which overrides
+the value from `clippy.toml`. This can be accounted for using the
+`extract_msrv_attr!(LintContext)` macro and passing
+`LateContext`/`EarlyContext`.
 
 ```rust
 impl<'tcx> LateLintPass<'tcx> for ManualStrip {
@@ -436,8 +438,20 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
 }
 ```
 
-Once the msrv is added to the lint, a relevant test case should be added to `tests/ui/min_rust_version_attr.rs`
-which verifies that the lint isn't emitted if the project's msrv is lower.
+Once the `msrv` is added to the lint, a relevant test case should be added to
+`tests/ui/min_rust_version_attr.rs` which verifies that the lint isn't emitted
+if the project's MSRV is lower.
+
+As a last step, the lint should be added to the lint documentation. This is done
+in `clippy_lints/src/utils/conf.rs`:
+
+```rust
+define_Conf! {
+    /// Lint: LIST, OF, LINTS, <THE_NEWLY_ADDED_LINT>. The minimum rust version that the project supports
+    (msrv, "msrv": Option<String>, None),
+    ...
+}
+```
 
 ## Author lint
 
@@ -533,9 +547,9 @@ Before submitting your PR make sure you followed all of the basic requirements:
 
 ## Adding configuration to a lint
 
-Clippy supports the configuration of lints values using a `clippy.toml` file in the workspace 
+Clippy supports the configuration of lints values using a `clippy.toml` file in the workspace
 directory. Adding a configuration to a lint can be useful for thresholds or to constrain some
-behavior that can be seen as a false positive for some users. Adding a configuration is done 
+behavior that can be seen as a false positive for some users. Adding a configuration is done
 in the following steps:
 
 1. Adding a new configuration entry to [clippy_utils::conf](/clippy_utils/src/conf.rs)
@@ -544,10 +558,10 @@ in the following steps:
     /// Lint: LINT_NAME. <The configuration field doc comment>
     (configuration_ident, "configuration_value": Type, DefaultValue),
     ```
-    The configuration value and identifier should usually be the same. The doc comment will be 
+    The configuration value and identifier should usually be the same. The doc comment will be
     automatically added to the lint documentation.
 2. Adding the configuration value to the lint impl struct:
-    1. This first requires the definition of a lint impl struct. Lint impl structs are usually 
+    1. This first requires the definition of a lint impl struct. Lint impl structs are usually
         generated with the `declare_lint_pass!` macro. This struct needs to be defined manually
         to add some kind of metadata to it:
         ```rust
@@ -564,7 +578,7 @@ in the following steps:
             LINT_NAME
         ]);
         ```
-    
+
     2. Next add the configuration value and a corresponding creation method like this:
         ```rust
         #[derive(Copy, Clone)]
@@ -584,7 +598,7 @@ in the following steps:
         ```
 3. Passing the configuration value to the lint impl struct:
 
-    First find the struct construction in the [clippy_lints lib file](/clippy_lints/src/lib.rs). 
+    First find the struct construction in the [clippy_lints lib file](/clippy_lints/src/lib.rs).
     The configuration value is now cloned or copied into a local value that is then passed to the
     impl struct like this:
     ```rust
@@ -601,9 +615,9 @@ in the following steps:
 
 4. Adding tests:
     1. The default configured value can be tested like any normal lint in [`tests/ui`](/tests/ui).
-    2. The configuration itself will be tested separately in [`tests/ui-toml`](/tests/ui-toml). 
-        Simply add a new subfolder with a fitting name. This folder contains a `clippy.toml` file 
-        with the configuration value and a rust file that should be linted by Clippy. The test can 
+    2. The configuration itself will be tested separately in [`tests/ui-toml`](/tests/ui-toml).
+        Simply add a new subfolder with a fitting name. This folder contains a `clippy.toml` file
+        with the configuration value and a rust file that should be linted by Clippy. The test can
         otherwise be written as usual.
 
 ## Cheatsheet
diff --git a/src/tools/clippy/lintcheck-logs/lintcheck_crates_logs.txt b/src/tools/clippy/lintcheck-logs/lintcheck_crates_logs.txt
index 3439b1e2c43..8f22bd65683 100644
--- a/src/tools/clippy/lintcheck-logs/lintcheck_crates_logs.txt
+++ b/src/tools/clippy/lintcheck-logs/lintcheck_crates_logs.txt
@@ -1,12 +1,12 @@
-clippy 0.1.52 (94d1c0a96 2021-03-11)
+clippy 0.1.53 (0b7671963 2021-03-31)
 
 target/lintcheck/sources/anyhow-1.0.38/build.rs:1:null clippy::cargo_common_metadata "package `anyhow` is missing `package.keywords` metadata"
 target/lintcheck/sources/anyhow-1.0.38/src/error.rs:350:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
 target/lintcheck/sources/anyhow-1.0.38/src/lib.rs:1:null clippy::cargo_common_metadata "package `anyhow` is missing `package.keywords` metadata"
-target/lintcheck/sources/async-trait-0.1.42/registry/src/github.com-1ecc6299db9ec823/syn-1.0.63/src/custom_keyword.rs:201:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
 target/lintcheck/sources/async-trait-0.1.42/src/expand.rs:130:1 clippy::too_many_lines "this function has too many lines (104/100)"
 target/lintcheck/sources/async-trait-0.1.42/src/expand.rs:156:26 clippy::default_trait_access "calling `syn::token::Where::default()` is more clear than this expression"
 target/lintcheck/sources/async-trait-0.1.42/src/expand.rs:259:1 clippy::too_many_lines "this function has too many lines (204/100)"
+target/lintcheck/sources/async-trait-0.1.42/src/expand.rs:387:17 clippy::match_wildcard_for_single_variants "wildcard matches only a single variant and will also match any future added variants"
 target/lintcheck/sources/async-trait-0.1.42/src/expand.rs:414:35 clippy::shadow_unrelated "`generics` is being shadowed"
 target/lintcheck/sources/async-trait-0.1.42/src/expand.rs:464:32 clippy::if_not_else "unnecessary `!=` operation"
 target/lintcheck/sources/async-trait-0.1.42/src/lib.rs:102:7 clippy::doc_markdown "you should put `async_trait` between ticks in the documentation"
@@ -88,7 +88,6 @@ target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/yank.rs:32:36 clipp
 target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/yank.rs:33:35 clippy::redundant_closure_for_method_calls "redundant closure"
 target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/yank.rs:34:36 clippy::redundant_closure_for_method_calls "redundant closure"
 target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/yank.rs:35:36 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/main.rs:100:17 clippy::match_wildcard_for_single_variants "wildcard match will miss any future added variants"
 target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/main.rs:118:41 clippy::redundant_closure_for_method_calls "redundant closure"
 target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/main.rs:137:43 clippy::redundant_closure_for_method_calls "redundant closure"
 target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/main.rs:148:19 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
@@ -101,7 +100,6 @@ target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/main.rs:1:null clippy::multi
 target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/main.rs:1:null clippy::multiple_crate_versions "multiple versions for dependency `humantime`: 1.3.0, 2.0.0"
 target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/main.rs:72:22 clippy::redundant_closure_for_method_calls "redundant closure"
 target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/main.rs:79:40 clippy::manual_map "manual implementation of `Option::map`"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/main.rs:94:13 clippy::match_wildcard_for_single_variants "wildcard match will miss any future added variants"
 target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/main.rs:98:60 clippy::redundant_closure_for_method_calls "redundant closure"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_config.rs:155:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_config.rs:170:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
@@ -125,7 +123,7 @@ target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/targ
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:469:58 clippy::redundant_closure_for_method_calls "redundant closure"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:603:19 clippy::redundant_closure_for_method_calls "redundant closure"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:665:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:697:12 clippy::inconsistent_struct_constructor "inconsistent struct constructor"
+target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:697:12 clippy::inconsistent_struct_constructor "struct constructor field order is inconsistent with struct definition field order"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:82:31 clippy::doc_markdown "you should put `FileType` between ticks in the documentation"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:83:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:84:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
@@ -255,6 +253,8 @@ target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/job_queue.rs:871:1
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/job_queue.rs:890:9 clippy::unused_self "unused `self` argument"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/job_queue.rs:93:24 clippy::doc_markdown "you should put `JobQueue` between ticks in the documentation"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/links.rs:8:1 clippy::module_name_repetitions "item name ends with its containing module's name"
+target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/lto.rs:130:13 clippy::unnested_or_patterns "unnested or-patterns"
+target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/lto.rs:135:13 clippy::unnested_or_patterns "unnested or-patterns"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:1016:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:1094:19 clippy::redundant_closure_for_method_calls "redundant closure"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:1131:1 clippy::unnecessary_wraps "this function's return value is unnecessary"
@@ -271,6 +271,7 @@ target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:392:45 clip
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:415:23 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:464:18 clippy::ptr_arg "writing `&PathBuf` instead of `&Path` involves a new object where a slice will do"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:488:61 clippy::ptr_arg "writing `&PathBuf` instead of `&Path` involves a new object where a slice will do"
+target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:498:21 clippy::unnested_or_patterns "unnested or-patterns"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:654:46 clippy::implicit_clone "implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenced type"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:667:15 clippy::similar_names "binding's name is too similar to existing binding"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:693:1 clippy::unnecessary_wraps "this function's return value is unnecessary"
@@ -279,7 +280,6 @@ target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:736:1 clipp
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:73:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:777:12 clippy::if_not_else "unnecessary boolean `not` operation"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:873:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/output_depinfo.rs:41:13 clippy::match_wildcard_for_single_variants "wildcard match will miss any future added variants"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/rustdoc.rs:16:1 clippy::module_name_repetitions "item name starts with its containing module's name"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/rustdoc.rs:57:1 clippy::module_name_repetitions "item name starts with its containing module's name"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/rustdoc.rs:72:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
@@ -554,7 +554,6 @@ target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/context.rs:42:1 cl
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/context.rs:74:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/encode.rs:156:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/encode.rs:156:5 clippy::too_many_lines "this function has too many lines (164/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/encode.rs:339:17 clippy::match_wildcard_for_single_variants "wildcard match will miss any future added variants"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/encode.rs:438:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/encode.rs:449:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/encode.rs:529:34 clippy::redundant_closure_for_method_calls "redundant closure"
@@ -636,6 +635,7 @@ target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:130:9 clippy::sing
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:148:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:153:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:163:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
+target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:166:13 clippy::match_wildcard_for_single_variants "wildcard matches only a single variant and will also match any future added variants"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:18:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:198:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:206:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
@@ -781,6 +781,7 @@ target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:267:5 clippy::
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:317:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:329:37 clippy::doc_markdown "you should put `VirtualManifest` between ticks in the documentation"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:410:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
+target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:420:17 clippy::match_wildcard_for_single_variants "wildcard matches only a single variant and will also match any future added variants"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:440:9 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:511:32 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:561:25 clippy::non_ascii_literal "literal non-ASCII character detected"
@@ -964,6 +965,7 @@ target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:510:1 clippy::mi
 target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:529:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:53:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:53:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
+target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:573:17 clippy::match_wildcard_for_single_variants "wildcard matches only a single variant and will also match any future added variants"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:573:22 clippy::match_same_arms "this `match` has identical arm bodies"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:608:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:621:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
@@ -990,7 +992,9 @@ target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/resolve.rs:58:1 clippy::modu
 target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/resolve.rs:602:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/resolve.rs:75:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/resolve.rs:75:1 clippy::module_name_repetitions "item name starts with its containing module's name"
+target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/format/mod.rs:103:21 clippy::match_wildcard_for_single_variants "wildcard matches only a single variant and will also match any future added variants"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/graph.rs:129:26 clippy::doc_markdown "you should put `PackageIds` between ticks in the documentation"
+target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/graph.rs:137:17 clippy::match_wildcard_for_single_variants "wildcard matches only a single variant and will also match any future added variants"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/graph.rs:152:15 clippy::match_on_vec_items "indexing into a vector may panic"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/graph.rs:173:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/graph.rs:234:46 clippy::filter_map "called `filter(..).flat_map(..)` on an `Iterator`"
@@ -1010,10 +1014,10 @@ target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/vendor.rs:14:1 clippy::modul
 target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/vendor.rs:215:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/vendor.rs:21:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/vendor.rs:21:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
+target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/vendor.rs:311:13 clippy::unnested_or_patterns "unnested or-patterns"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/vendor.rs:314:34 clippy::match_same_arms "this `match` has identical arm bodies"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/vendor.rs:320:29 clippy::case_sensitive_file_extension_comparisons "case-sensitive file extension comparison"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/vendor.rs:320:60 clippy::case_sensitive_file_extension_comparisons "case-sensitive file extension comparison"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/vendor.rs:324:13 clippy::match_wildcard_for_single_variants "wildcard match will miss any future added variants"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/vendor.rs:70:1 clippy::too_many_lines "this function has too many lines (175/100)"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/config.rs:102:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/config.rs:111:28 clippy::needless_question_mark "question mark operator is useless here"
@@ -1167,6 +1171,7 @@ target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1323:9 clippy
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1339:39 clippy::unused_self "unused `self` argument"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1344:1 clippy::module_name_repetitions "item name starts with its containing module's name"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1420:1 clippy::module_name_repetitions "item name starts with its containing module's name"
+target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1531:13 clippy::unnested_or_patterns "unnested or-patterns"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1553:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1560:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1567:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
@@ -1187,7 +1192,6 @@ target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1778:1 clippy
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1804:1 clippy::module_name_repetitions "item name ends with its containing module's name"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1896:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1901:5 clippy::doc_markdown "you should put `StringList` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:214:13 clippy::match_wildcard_for_single_variants "wildcard match will miss any future added variants"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:259:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:298:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:311:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
@@ -1242,6 +1246,8 @@ target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:150:5 clippy::mus
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:15:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:237:5 clippy::pub_enum_variant_names "variant name ends with the enum's name"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:245:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
+target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:289:21 clippy::match_wildcard_for_single_variants "wildcard matches only a single variant and will also match any future added variants"
+target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:293:13 clippy::match_wildcard_for_single_variants "wildcard matches only a single variant and will also match any future added variants"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:321:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:328:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:356:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
@@ -1348,7 +1354,7 @@ target/lintcheck/sources/cargo-0.49.0/src/cargo/util/process_builder.rs:185:5 cl
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/process_builder.rs:190:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/process_builder.rs:218:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/process_builder.rs:218:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/process_builder.rs:278:22 clippy::inconsistent_struct_constructor "inconsistent struct constructor"
+target/lintcheck/sources/cargo-0.49.0/src/cargo/util/process_builder.rs:278:22 clippy::inconsistent_struct_constructor "struct constructor field order is inconsistent with struct definition field order"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/process_builder.rs:307:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/process_builder.rs:343:39 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/progress.rs:122:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
@@ -1448,6 +1454,8 @@ target/lintcheck/sources/cargo-0.49.0/src/cargo/util/workspace.rs:56:1 clippy::m
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/workspace.rs:60:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
 target/lintcheck/sources/cargo-0.49.0/src/cargo/util/workspace.rs:64:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
 target/lintcheck/sources/cfg-expr-0.7.1/src/error.rs:107:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
+target/lintcheck/sources/cfg-expr-0.7.1/src/error.rs:55:13 clippy::unnested_or_patterns "unnested or-patterns"
+target/lintcheck/sources/cfg-expr-0.7.1/src/error.rs:58:13 clippy::unnested_or_patterns "unnested or-patterns"
 target/lintcheck/sources/cfg-expr-0.7.1/src/error.rs:5:1 clippy::module_name_repetitions "item name ends with its containing module's name"
 target/lintcheck/sources/cfg-expr-0.7.1/src/error.rs:74:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
 target/lintcheck/sources/cfg-expr-0.7.1/src/error.rs:91:24 clippy::if_not_else "unnecessary boolean `not` operation"
@@ -1458,6 +1466,7 @@ target/lintcheck/sources/cfg-expr-0.7.1/src/expr/lexer.rs:58:5 clippy::must_use_
 target/lintcheck/sources/cfg-expr-0.7.1/src/expr/lexer.rs:76:1 clippy::module_name_repetitions "item name starts with its containing module's name"
 target/lintcheck/sources/cfg-expr-0.7.1/src/expr/lexer.rs:97:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
 target/lintcheck/sources/cfg-expr-0.7.1/src/expr/mod.rs:351:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
+target/lintcheck/sources/cfg-expr-0.7.1/src/expr/mod.rs:408:13 clippy::match_wildcard_for_single_variants "wildcard matches only a single variant and will also match any future added variants"
 target/lintcheck/sources/cfg-expr-0.7.1/src/expr/mod.rs:464:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
 target/lintcheck/sources/cfg-expr-0.7.1/src/expr/mod.rs:57:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
 target/lintcheck/sources/cfg-expr-0.7.1/src/expr/mod.rs:586:33 clippy::match_same_arms "this `match` has identical arm bodies"
@@ -1467,12 +1476,25 @@ target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:116:31 clippy::simila
 target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:124:36 clippy::similar_names "binding's name is too similar to existing binding"
 target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:17:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
 target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:17:5 clippy::too_many_lines "this function has too many lines (345/100)"
+target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:211:21 clippy::unnested_or_patterns "unnested or-patterns"
+target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:211:21 clippy::unnested_or_patterns "unnested or-patterns"
+target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:211:21 clippy::unnested_or_patterns "unnested or-patterns"
+target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:211:21 clippy::unnested_or_patterns "unnested or-patterns"
+target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:211:21 clippy::unnested_or_patterns "unnested or-patterns"
+target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:211:21 clippy::unnested_or_patterns "unnested or-patterns"
+target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:211:21 clippy::unnested_or_patterns "unnested or-patterns"
 target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:22:13 clippy::shadow_unrelated "`original` is being shadowed"
+target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:238:21 clippy::unnested_or_patterns "unnested or-patterns"
 target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:243:36 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
 target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:254:34 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
+target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:259:21 clippy::unnested_or_patterns "unnested or-patterns"
 target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:25:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
+target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:284:21 clippy::unnested_or_patterns "unnested or-patterns"
+target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:292:21 clippy::unnested_or_patterns "unnested or-patterns"
+target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:347:21 clippy::unnested_or_patterns "unnested or-patterns"
 target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:390:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
 target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:392:17 clippy::if_not_else "unnecessary `!=` operation"
+target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:39:31 clippy::too_many_lines "this function has too many lines (136/100)"
 target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:67:13 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
 target/lintcheck/sources/cfg-expr-0.7.1/src/lib.rs:1:null clippy::cargo_common_metadata "package `cfg-expr` is missing `package.categories` metadata"
 target/lintcheck/sources/cfg-expr-0.7.1/src/targets/builtins.rs:11:5 clippy::wildcard_imports "usage of wildcard import"
@@ -2191,9 +2213,7 @@ target/lintcheck/sources/libc-0.2.81/src/unix/mod.rs:202:35 clippy::unnecessary_
 target/lintcheck/sources/libc-0.2.81/src/unix/mod.rs:282:40 clippy::unreadable_literal "long literal lacking separators"
 target/lintcheck/sources/libc-0.2.81/src/unix/mod.rs:284:41 clippy::unreadable_literal "long literal lacking separators"
 target/lintcheck/sources/libc-0.2.81/src/unix/mod.rs:285:36 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/mod.rs:34:10 clippy::upper_case_acronyms "name `DIR` contains a capitalized acronym"
 target/lintcheck/sources/libc-0.2.81/src/unix/mod.rs:36:1 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/unix/mod.rs:386:10 clippy::upper_case_acronyms "name `FILE` contains a capitalized acronym"
 target/lintcheck/sources/libc-0.2.81/src/unix/mod.rs:388:1 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
 target/lintcheck/sources/libc-0.2.81/src/unix/mod.rs:396:1 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
 target/lintcheck/sources/log-0.4.11/src/lib.rs:1047:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
@@ -2212,11 +2232,13 @@ target/lintcheck/sources/log-0.4.11/src/lib.rs:356:1 clippy::expl_impl_clone_on_
 target/lintcheck/sources/log-0.4.11/src/lib.rs:448:12 clippy::manual_range_contains "manual `RangeInclusive::contains` implementation"
 target/lintcheck/sources/log-0.4.11/src/lib.rs:500:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
 target/lintcheck/sources/log-0.4.11/src/lib.rs:506:28 clippy::trivially_copy_pass_by_ref "this argument (8 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
+target/lintcheck/sources/log-0.4.11/src/lib.rs:506:28 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
 target/lintcheck/sources/log-0.4.11/src/lib.rs:506:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
 target/lintcheck/sources/log-0.4.11/src/lib.rs:506:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
 target/lintcheck/sources/log-0.4.11/src/lib.rs:538:1 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
 target/lintcheck/sources/log-0.4.11/src/lib.rs:653:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
 target/lintcheck/sources/log-0.4.11/src/lib.rs:661:21 clippy::trivially_copy_pass_by_ref "this argument (8 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
+target/lintcheck/sources/log-0.4.11/src/lib.rs:661:21 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
 target/lintcheck/sources/log-0.4.11/src/lib.rs:661:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
 target/lintcheck/sources/log-0.4.11/src/lib.rs:677:44 clippy::match_same_arms "this `match` has identical arm bodies"
 target/lintcheck/sources/log-0.4.11/src/lib.rs:758:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
@@ -2233,13 +2255,14 @@ target/lintcheck/sources/log-0.4.11/src/lib.rs:908:5 clippy::must_use_candidate
 target/lintcheck/sources/log-0.4.11/src/lib.rs:908:5 clippy::new_without_default "you should consider adding a `Default` implementation for `RecordBuilder<'a>`"
 target/lintcheck/sources/log-0.4.11/src/lib.rs:995:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
 target/lintcheck/sources/proc-macro2-1.0.24/src/detection.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:108:17 clippy::match_wildcard_for_single_variants "wildcard match will miss any future added variants"
+target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:108:17 clippy::match_wildcard_for_single_variants "wildcard matches only a single variant and will also match any future added variants"
 target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:269:20 clippy::unused_self "unused `self` argument"
 target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:430:24 clippy::trivially_copy_pass_by_ref "this argument (0 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
 target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:437:23 clippy::trivially_copy_pass_by_ref "this argument (0 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
 target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:437:23 clippy::unused_self "unused `self` argument"
 target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:471:17 clippy::trivially_copy_pass_by_ref "this argument (0 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
 target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:471:17 clippy::unused_self "unused `self` argument"
+target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:50:9 clippy::mem_replace_with_default "replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`"
 target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:654:5 clippy::manual_range_contains "manual `RangeInclusive::contains` implementation"
 target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:655:12 clippy::manual_range_contains "manual `RangeInclusive::contains` implementation"
 target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:661:5 clippy::manual_range_contains "manual `RangeInclusive::contains` implementation"
@@ -2286,6 +2309,12 @@ target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:891:36 clippy::doc_markdo
 target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:894:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
 target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:911:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
 target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:996:9 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
+target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:353:17 clippy::unnested_or_patterns "unnested or-patterns"
+target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:360:17 clippy::unnested_or_patterns "unnested or-patterns"
+target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:411:17 clippy::unnested_or_patterns "unnested or-patterns"
+target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:413:17 clippy::unnested_or_patterns "unnested or-patterns"
+target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:476:13 clippy::unnested_or_patterns "unnested or-patterns"
+target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:500:13 clippy::unnested_or_patterns "unnested or-patterns"
 target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:552:5 clippy::while_let_on_iterator "this loop could be written as a `for` loop"
 target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:584:21 clippy::manual_range_contains "manual `RangeInclusive::contains` implementation"
 target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:602:20 clippy::map_unwrap_or "called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead"
@@ -2360,6 +2389,10 @@ target/lintcheck/sources/quote-1.0.7/src/runtime.rs:52:5 clippy::module_name_rep
 target/lintcheck/sources/quote-1.0.7/src/runtime.rs:63:5 clippy::module_name_repetitions "item name ends with its containing module's name"
 target/lintcheck/sources/quote-1.0.7/src/runtime.rs:66:33 clippy::doc_markdown "you should put `DoesNotHaveIter` between ticks in the documentation"
 target/lintcheck/sources/quote-1.0.7/src/runtime.rs:80:5 clippy::module_name_repetitions "item name ends with its containing module's name"
+target/lintcheck/sources/quote-1.0.7/src/to_tokens.rs:132:26 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
+target/lintcheck/sources/quote-1.0.7/src/to_tokens.rs:159:18 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
+target/lintcheck/sources/quote-1.0.7/src/to_tokens.rs:165:18 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
+target/lintcheck/sources/quote-1.0.7/src/to_tokens.rs:80:18 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
 target/lintcheck/sources/rand-0.7.3/src/distributions/bernoulli.rs:103:20 clippy::cast_possible_truncation "casting `f64` to `u64` may truncate the value"
 target/lintcheck/sources/rand-0.7.3/src/distributions/bernoulli.rs:103:20 clippy::cast_sign_loss "casting `f64` to `u64` may lose the sign of the value"
 target/lintcheck/sources/rand-0.7.3/src/distributions/bernoulli.rs:116:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
@@ -2467,9 +2500,9 @@ target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:943:54 clippy::
 target/lintcheck/sources/rand-0.7.3/src/distributions/unit_circle.rs:30:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
 target/lintcheck/sources/rand-0.7.3/src/distributions/unit_sphere.rs:24:1 clippy::module_name_repetitions "item name starts with its containing module's name"
 target/lintcheck/sources/rand-0.7.3/src/distributions/unit_sphere.rs:29:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:247:15 clippy::wrong_self_convention "methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name"
-target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:248:20 clippy::wrong_self_convention "methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name"
-target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:249:18 clippy::wrong_self_convention "methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name"
+target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:247:15 clippy::wrong_self_convention "methods called `is_*` usually take `self` by reference or no `self`"
+target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:248:20 clippy::wrong_self_convention "methods called `is_*` usually take `self` by reference or no `self`"
+target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:249:18 clippy::wrong_self_convention "methods called `is_*` usually take `self` by reference or no `self`"
 target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:254:5 clippy::inline_always "you have declared `#[inline(always)]` on `lanes`. This is usually a bad idea"
 target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:258:5 clippy::inline_always "you have declared `#[inline(always)]` on `splat`. This is usually a bad idea"
 target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:262:5 clippy::inline_always "you have declared `#[inline(always)]` on `extract`. This is usually a bad idea"
@@ -2504,7 +2537,69 @@ target/lintcheck/sources/rand-0.7.3/src/distributions/weighted/mod.rs:169:16 cli
 target/lintcheck/sources/rand-0.7.3/src/distributions/weighted/mod.rs:386:1 clippy::module_name_repetitions "item name starts with its containing module's name"
 target/lintcheck/sources/rand-0.7.3/src/distributions/weighted/mod.rs:85:1 clippy::module_name_repetitions "item name starts with its containing module's name"
 target/lintcheck/sources/rand-0.7.3/src/lib.rs:333:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:404:14 clippy::wrong_self_convention "methods called `to_*` usually take self by reference; consider choosing a less ambiguous name"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:412:14 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:435:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:435:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:435:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:435:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:435:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:435:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:435:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:435:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:435:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:435:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:435:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:459:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:459:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:459:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:459:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:459:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:459:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:459:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:459:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:459:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:459:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:459:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
+target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
 target/lintcheck/sources/rand-0.7.3/src/lib.rs:552:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
 target/lintcheck/sources/rand-0.7.3/src/rngs/adapter/read.rs:47:1 clippy::module_name_repetitions "item name starts with its containing module's name"
 target/lintcheck/sources/rand-0.7.3/src/rngs/adapter/read.rs:89:1 clippy::module_name_repetitions "item name starts with its containing module's name"
@@ -2605,6 +2700,7 @@ target/lintcheck/sources/rayon-1.5.0/src/collections/hash_set.rs:9:5 clippy::wil
 target/lintcheck/sources/rayon-1.5.0/src/collections/linked_list.rs:7:5 clippy::wildcard_imports "usage of wildcard import"
 target/lintcheck/sources/rayon-1.5.0/src/collections/linked_list.rs:8:5 clippy::wildcard_imports "usage of wildcard import"
 target/lintcheck/sources/rayon-1.5.0/src/collections/mod.rs:59:32 clippy::mem_replace_with_default "replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`"
+target/lintcheck/sources/rayon-1.5.0/src/collections/mod.rs:68:40 clippy::mem_replace_with_default "replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`"
 target/lintcheck/sources/rayon-1.5.0/src/collections/vec_deque.rs:8:5 clippy::wildcard_imports "usage of wildcard import"
 target/lintcheck/sources/rayon-1.5.0/src/collections/vec_deque.rs:9:5 clippy::wildcard_imports "usage of wildcard import"
 target/lintcheck/sources/rayon-1.5.0/src/compile_fail/cannot_collect_filtermap_data.rs:2:1 clippy::needless_doctest_main "needless `fn main` in doctest"
@@ -2626,7 +2722,7 @@ target/lintcheck/sources/rayon-1.5.0/src/iter/chain.rs:58:17 clippy::shadow_unre
 target/lintcheck/sources/rayon-1.5.0/src/iter/chain.rs:78:14 clippy::shadow_unrelated "`a` is being shadowed"
 target/lintcheck/sources/rayon-1.5.0/src/iter/chain.rs:78:17 clippy::shadow_unrelated "`b` is being shadowed"
 target/lintcheck/sources/rayon-1.5.0/src/iter/chain.rs:97:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/chunks.rs:29:9 clippy::inconsistent_struct_constructor "inconsistent struct constructor"
+target/lintcheck/sources/rayon-1.5.0/src/iter/chunks.rs:29:9 clippy::inconsistent_struct_constructor "struct constructor field order is inconsistent with struct definition field order"
 target/lintcheck/sources/rayon-1.5.0/src/iter/chunks.rs:3:5 clippy::wildcard_imports "usage of wildcard import"
 target/lintcheck/sources/rayon-1.5.0/src/iter/chunks.rs:4:5 clippy::wildcard_imports "usage of wildcard import"
 target/lintcheck/sources/rayon-1.5.0/src/iter/chunks.rs:77:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
@@ -2704,8 +2800,6 @@ target/lintcheck/sources/rayon-1.5.0/src/iter/interleave.rs:200:23 clippy::doc_m
 target/lintcheck/sources/rayon-1.5.0/src/iter/interleave.rs:249:41 clippy::doc_markdown "you should put `DoubleEndedIterator` between ticks in the documentation"
 target/lintcheck/sources/rayon-1.5.0/src/iter/interleave.rs:250:5 clippy::doc_markdown "you should put `ExactSizeIterator` between ticks in the documentation"
 target/lintcheck/sources/rayon-1.5.0/src/iter/interleave.rs:263:33 clippy::doc_markdown "you should put `InterleaveSeq` between ticks in the documentation"
-target/lintcheck/sources/rayon-1.5.0/src/iter/interleave.rs:280:17 clippy::match_wildcard_for_single_variants "wildcard match will miss any future added variants"
-target/lintcheck/sources/rayon-1.5.0/src/iter/interleave.rs:285:17 clippy::match_wildcard_for_single_variants "wildcard match will miss any future added variants"
 target/lintcheck/sources/rayon-1.5.0/src/iter/interleave.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
 target/lintcheck/sources/rayon-1.5.0/src/iter/interleave.rs:313:9 clippy::comparison_chain "`if` chain can be rewritten with `match`"
 target/lintcheck/sources/rayon-1.5.0/src/iter/interleave.rs:82:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
@@ -2761,6 +2855,7 @@ target/lintcheck/sources/rayon-1.5.0/src/iter/positions.rs:1:5 clippy::wildcard_
 target/lintcheck/sources/rayon-1.5.0/src/iter/positions.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
 target/lintcheck/sources/rayon-1.5.0/src/iter/product.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
 target/lintcheck/sources/rayon-1.5.0/src/iter/reduce.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
+target/lintcheck/sources/rayon-1.5.0/src/iter/reduce.rs:67:19 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
 target/lintcheck/sources/rayon-1.5.0/src/iter/repeat.rs:103:1 clippy::module_name_repetitions "item name starts with its containing module's name"
 target/lintcheck/sources/rayon-1.5.0/src/iter/repeat.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
 target/lintcheck/sources/rayon-1.5.0/src/iter/repeat.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
@@ -2787,7 +2882,9 @@ target/lintcheck/sources/rayon-1.5.0/src/iter/try_fold.rs:190:1 clippy::module_n
 target/lintcheck/sources/rayon-1.5.0/src/iter/try_fold.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
 target/lintcheck/sources/rayon-1.5.0/src/iter/try_fold.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
 target/lintcheck/sources/rayon-1.5.0/src/iter/try_reduce.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
+target/lintcheck/sources/rayon-1.5.0/src/iter/try_reduce.rs:74:19 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
 target/lintcheck/sources/rayon-1.5.0/src/iter/try_reduce_with.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
+target/lintcheck/sources/rayon-1.5.0/src/iter/try_reduce_with.rs:69:19 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
 target/lintcheck/sources/rayon-1.5.0/src/iter/unzip.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
 target/lintcheck/sources/rayon-1.5.0/src/iter/unzip.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
 target/lintcheck/sources/rayon-1.5.0/src/iter/update.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
@@ -2960,6 +3057,7 @@ target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1129:13 clippy::doc_markdown "yo
 target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1134:13 clippy::doc_markdown "you should put `is_match` between ticks in the documentation"
 target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1185:68 clippy::doc_markdown "you should put `is_match` between ticks in the documentation"
 target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1193:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
+target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1205:13 clippy::mem_replace_with_default "replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`"
 target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1244:50 clippy::doc_markdown "you should put `current_state` between ticks in the documentation"
 target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1338:58 clippy::doc_markdown "you should put `STATE_DEAD` between ticks in the documentation"
 target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1339:9 clippy::doc_markdown "you should put `STATE_UNKNOWN` between ticks in the documentation"
@@ -3365,7 +3463,7 @@ target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:369:5 clippy::upper_
 target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:410:14 clippy::trivially_copy_pass_by_ref "this argument (2 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
 target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:475:18 clippy::match_same_arms "this `match` has identical arm bodies"
 target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:512:19 clippy::doc_markdown "you should put `ArgMatches` between ticks in the documentation"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:549:16 clippy::wrong_self_convention "methods called `to_*` usually take self by reference; consider choosing a less ambiguous name"
+target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:549:16 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
 target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:76:18 clippy::trivially_copy_pass_by_ref "this argument (1 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
 target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:77:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
 target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:923:42 clippy::doc_markdown "you should put `BinaryDetection::quit` between ticks in the documentation"
@@ -3409,6 +3507,14 @@ target/lintcheck/sources/rpmalloc-0.2.0/src/lib.rs:71:73 clippy::doc_markdown "y
 target/lintcheck/sources/rpmalloc-0.2.0/src/lib.rs:72:50 clippy::doc_markdown "you should put bare URLs between `<`/`>` or make a proper Markdown link"
 target/lintcheck/sources/rpmalloc-0.2.0/src/lib.rs:92:9 clippy::ptr_as_ptr "`as` casting between raw pointers without changing its mutability"
 target/lintcheck/sources/rpmalloc-0.2.0/src/lib.rs:95:21 clippy::ptr_as_ptr "`as` casting between raw pointers without changing its mutability"
+target/lintcheck/sources/serde-1.0.118/src/de/from_primitive.rs:103:24 clippy::wrong_self_convention "methods called `from_*` usually take no `self`"
+target/lintcheck/sources/serde-1.0.118/src/de/from_primitive.rs:107:25 clippy::wrong_self_convention "methods called `from_*` usually take no `self`"
+target/lintcheck/sources/serde-1.0.118/src/de/from_primitive.rs:111:25 clippy::wrong_self_convention "methods called `from_*` usually take no `self`"
+target/lintcheck/sources/serde-1.0.118/src/de/from_primitive.rs:115:25 clippy::wrong_self_convention "methods called `from_*` usually take no `self`"
+target/lintcheck/sources/serde-1.0.118/src/de/from_primitive.rs:48:24 clippy::wrong_self_convention "methods called `from_*` usually take no `self`"
+target/lintcheck/sources/serde-1.0.118/src/de/from_primitive.rs:52:25 clippy::wrong_self_convention "methods called `from_*` usually take no `self`"
+target/lintcheck/sources/serde-1.0.118/src/de/from_primitive.rs:56:25 clippy::wrong_self_convention "methods called `from_*` usually take no `self`"
+target/lintcheck/sources/serde-1.0.118/src/de/from_primitive.rs:60:25 clippy::wrong_self_convention "methods called `from_*` usually take no `self`"
 target/lintcheck/sources/serde-1.0.118/src/de/mod.rs:1592:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
 target/lintcheck/sources/serde-1.0.118/src/de/mod.rs:1616:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
 target/lintcheck/sources/serde-1.0.118/src/de/mod.rs:1627:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
@@ -3418,10 +3524,18 @@ target/lintcheck/sources/serde-1.0.118/src/de/mod.rs:952:13 clippy::let_undersco
 target/lintcheck/sources/serde-1.0.118/src/de/mod.rs:986:13 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
 target/lintcheck/sources/serde_yaml-0.8.17/src/lib.rs:1:null clippy::cargo_common_metadata "package `serde_yaml` is missing `package.categories` metadata"
 target/lintcheck/sources/syn-1.0.54/build.rs:1:null clippy::cargo_common_metadata "package `syn` is missing `package.keywords` metadata"
+target/lintcheck/sources/syn-1.0.54/src/custom_keyword.rs:177:26 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
+target/lintcheck/sources/syn-1.0.54/src/gen/clone.rs:1900:13 clippy::match_wildcard_for_single_variants "wildcard matches only a single variant and will also match any future added variants"
+target/lintcheck/sources/syn-1.0.54/src/generics.rs:1227:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
 target/lintcheck/sources/syn-1.0.54/src/lib.rs:1:null clippy::cargo_common_metadata "package `syn` is missing `package.keywords` metadata"
 target/lintcheck/sources/syn-1.0.54/src/lit.rs:1397:40 clippy::redundant_else "redundant else block"
 target/lintcheck/sources/syn-1.0.54/src/lit.rs:1405:28 clippy::redundant_else "redundant else block"
 target/lintcheck/sources/syn-1.0.54/src/lit.rs:1485:32 clippy::redundant_else "redundant else block"
+target/lintcheck/sources/syn-1.0.54/src/op.rs:190:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
+target/lintcheck/sources/syn-1.0.54/src/op.rs:226:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
+target/lintcheck/sources/syn-1.0.54/src/token.rs:311:30 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
+target/lintcheck/sources/syn-1.0.54/src/token.rs:446:30 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
+target/lintcheck/sources/syn-1.0.54/src/token.rs:563:18 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
 target/lintcheck/sources/syn-1.0.54/src/token.rs:974:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
 target/lintcheck/sources/tame-oidc-0.1.0/src/errors.rs:9:5 clippy::upper_case_acronyms "name `HTTP` contains a capitalized acronym"
 target/lintcheck/sources/tame-oidc-0.1.0/src/lib.rs:1:null clippy::cargo_common_metadata "package `tame-oidc` is missing `package.categories` metadata"
@@ -3439,8 +3553,6 @@ target/lintcheck/sources/tame-oidc-0.1.0/src/provider.rs:26:5 clippy::missing_er
 target/lintcheck/sources/tame-oidc-0.1.0/src/provider.rs:38:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
 target/lintcheck/sources/tame-oidc-0.1.0/src/provider.rs:57:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
 target/lintcheck/sources/tame-oidc-0.1.0/src/provider.rs:71:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/tame-oidc-0.1.0/src/provider.rs:77:12 clippy::upper_case_acronyms "name `JWK` contains a capitalized acronym"
-target/lintcheck/sources/tame-oidc-0.1.0/src/provider.rs:90:12 clippy::upper_case_acronyms "name `JWKS` contains a capitalized acronym"
 target/lintcheck/sources/tame-oidc-0.1.0/src/provider.rs:95:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
 target/lintcheck/sources/thiserror-1.0.24/src/lib.rs:1:null clippy::cargo_common_metadata "package `thiserror` is missing `package.keywords` metadata"
 target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:1:null clippy::cargo_common_metadata "package `unicode-xid` is missing `package.categories` metadata"
@@ -3448,12 +3560,12 @@ target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:57:64 clippy::doc_markdown
 target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:60:10 clippy::doc_markdown "you should put `XID_Start` between ticks in the documentation"
 target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:62:27 clippy::doc_markdown "you should put `ID_Start` between ticks in the documentation"
 target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:62:67 clippy::doc_markdown "you should put `NFKx` between ticks in the documentation"
-target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:63:21 clippy::wrong_self_convention "methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name"
+target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:63:21 clippy::wrong_self_convention "methods called `is_*` usually take `self` by reference or no `self`"
 target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:65:61 clippy::doc_markdown "you should put `XID_Continue` between ticks in the documentation"
 target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:68:10 clippy::doc_markdown "you should put `XID_Continue` between ticks in the documentation"
 target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:70:28 clippy::doc_markdown "you should put `ID_Continue` between ticks in the documentation"
 target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:70:72 clippy::doc_markdown "you should put `NFKx` between ticks in the documentation"
-target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:71:24 clippy::wrong_self_convention "methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name"
+target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:71:24 clippy::wrong_self_convention "methods called `is_*` usually take `self` by reference or no `self`"
 target/lintcheck/sources/xsv-0.13.0/src/cmd/cat.rs:101:34 clippy::redundant_closure_for_method_calls "redundant closure"
 target/lintcheck/sources/xsv-0.13.0/src/cmd/cat.rs:42:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
 target/lintcheck/sources/xsv-0.13.0/src/cmd/cat.rs:53:9 clippy::similar_names "binding's name is too similar to existing binding"
@@ -3520,7 +3632,6 @@ target/lintcheck/sources/xsv-0.13.0/src/cmd/sample.rs:115:21 clippy::cast_possib
 target/lintcheck/sources/xsv-0.13.0/src/cmd/sample.rs:11:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
 target/lintcheck/sources/xsv-0.13.0/src/cmd/sample.rs:51:9 clippy::similar_names "binding's name is too similar to existing binding"
 target/lintcheck/sources/xsv-0.13.0/src/cmd/sample.rs:58:19 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/sample.rs:69:9 clippy::match_wildcard_for_single_variants "wildcard match will miss any future added variants"
 target/lintcheck/sources/xsv-0.13.0/src/cmd/sample.rs:75:16 clippy::explicit_into_iter_loop "it is more concise to loop over containers instead of using explicit iteration methods"
 target/lintcheck/sources/xsv-0.13.0/src/cmd/sample.rs:91:42 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers"
 target/lintcheck/sources/xsv-0.13.0/src/cmd/sample.rs:92:43 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers"
@@ -3567,7 +3678,7 @@ target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:293:25 clippy::match_same_a
 target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:297:25 clippy::option_map_unit_fn "called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`"
 target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:301:21 clippy::option_map_unit_fn "called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`"
 target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:302:21 clippy::option_map_unit_fn "called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:308:18 clippy::wrong_self_convention "methods called `to_*` usually take self by reference; consider choosing a less ambiguous name"
+target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:308:18 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
 target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:318:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
 target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:322:45 clippy::redundant_closure_for_method_calls "redundant closure"
 target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:322:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
@@ -3600,7 +3711,7 @@ target/lintcheck/sources/xsv-0.13.0/src/cmd/table.rs:50:9 clippy::similar_names
 target/lintcheck/sources/xsv-0.13.0/src/cmd/table.rs:54:9 clippy::similar_names "binding's name is too similar to existing binding"
 target/lintcheck/sources/xsv-0.13.0/src/config.rs:113:43 clippy::or_fun_call "use of `unwrap_or` followed by a function call"
 target/lintcheck/sources/xsv-0.13.0/src/config.rs:58:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
-target/lintcheck/sources/xsv-0.13.0/src/config.rs:77:28 clippy::explicit_deref_methods "explicit deref method call"
+target/lintcheck/sources/xsv-0.13.0/src/config.rs:77:28 clippy::explicit_deref_methods "explicit `deref` method call"
 target/lintcheck/sources/xsv-0.13.0/src/config.rs:90:13 clippy::redundant_field_names "redundant field names in struct initialization"
 target/lintcheck/sources/xsv-0.13.0/src/index.rs:31:13 clippy::redundant_field_names "redundant field names in struct initialization"
 target/lintcheck/sources/xsv-0.13.0/src/main.rs:164:49 clippy::redundant_clone "redundant clone"
@@ -3640,7 +3751,6 @@ clippy::from_iter_instead_of_collect 1
 clippy::int_plus_one 1
 clippy::manual_flatten 1
 clippy::manual_saturating_arithmetic 1
-clippy::mem_replace_with_default 1
 clippy::nonminimal_bool 1
 clippy::or_fun_call 1
 clippy::precedence 1
@@ -3677,7 +3787,9 @@ clippy::inconsistent_struct_constructor 3
 clippy::manual_map 3
 clippy::mut_mut 3
 clippy::ptr_arg 3
+clippy::upper_case_acronyms 3
 clippy::zero_ptr 3
+clippy::mem_replace_with_default 4
 clippy::too_many_arguments 4
 clippy::explicit_iter_loop 5
 clippy::field_reassign_with_default 5
@@ -3695,16 +3807,14 @@ clippy::implicit_clone 7
 clippy::map_clone 7
 clippy::option_map_unit_fn 7
 clippy::range_plus_one 7
-clippy::upper_case_acronyms 7
 clippy::invalid_upcast_comparisons 8
 clippy::needless_question_mark 8
-clippy::wrong_self_convention 8
 clippy::len_without_is_empty 9
 clippy::multiple_crate_versions 9
 clippy::manual_range_contains 10
-clippy::match_wildcard_for_single_variants 10
 clippy::missing_safety_doc 10
 clippy::needless_doctest_main 10
+clippy::match_wildcard_for_single_variants 11
 clippy::needless_lifetimes 12
 clippy::linkedlist 14
 clippy::single_char_add_str 14
@@ -3722,11 +3832,12 @@ clippy::cargo_common_metadata 21
 clippy::ptr_as_ptr 21
 clippy::redundant_static_lifetimes 21
 clippy::cast_lossless 23
+clippy::unnested_or_patterns 25
 clippy::default_trait_access 26
 clippy::let_underscore_drop 26
 clippy::trivially_copy_pass_by_ref 26
 clippy::redundant_else 29
-clippy::too_many_lines 35
+clippy::too_many_lines 36
 clippy::if_not_else 38
 clippy::unseparated_literal_suffix 41
 clippy::cast_precision_loss 44
@@ -3736,13 +3847,14 @@ clippy::inline_always 59
 clippy::missing_panics_doc 59
 clippy::match_same_arms 62
 clippy::similar_names 83
+clippy::wrong_self_convention 94
 clippy::cast_possible_truncation 95
 clippy::redundant_field_names 111
 clippy::redundant_closure_for_method_calls 131
 clippy::items_after_statements 143
 clippy::module_name_repetitions 146
+clippy::expl_impl_clone_on_copy 164
 clippy::wildcard_imports 164
-clippy::expl_impl_clone_on_copy 165
 clippy::doc_markdown 184
 clippy::missing_errors_doc 356
 clippy::unreadable_literal 365
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index 581b47647eb..2041aed2b97 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -294,6 +294,14 @@ impl Crate {
             });
         let stdout = String::from_utf8_lossy(&all_output.stdout);
         let stderr = String::from_utf8_lossy(&all_output.stderr);
+        let status = &all_output.status;
+
+        if !status.success() {
+            eprintln!(
+                "\nWARNING: bad exit status after checking {} {} \n",
+                self.name, self.version
+            );
+        }
 
         if fix {
             if let Some(stderr) = stderr
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index c2821f31fd7..7e4d12b8632 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2021-03-25"
+channel = "nightly-2021-04-08"
 components = ["llvm-tools-preview", "rustc-dev", "rust-src"]
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index b6aed862e89..fa0c5f01430 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -99,17 +99,17 @@ impl rustc_driver::Callbacks for ClippyCallbacks {
         config.parse_sess_created = Some(Box::new(move |parse_sess| {
             track_clippy_args(parse_sess, &clippy_args_var);
         }));
-        config.register_lints = Some(Box::new(move |sess, mut lint_store| {
+        config.register_lints = Some(Box::new(move |sess, lint_store| {
             // technically we're ~guaranteed that this is none but might as well call anything that
             // is there already. Certainly it can't hurt.
             if let Some(previous) = &previous {
                 (previous)(sess, lint_store);
             }
 
-            let conf = clippy_lints::read_conf(&[], &sess);
-            clippy_lints::register_plugins(&mut lint_store, &sess, &conf);
-            clippy_lints::register_pre_expansion_lints(&mut lint_store);
-            clippy_lints::register_renamed(&mut lint_store);
+            let conf = clippy_lints::read_conf(&[], sess);
+            clippy_lints::register_plugins(lint_store, sess, &conf);
+            clippy_lints::register_pre_expansion_lints(lint_store);
+            clippy_lints::register_renamed(lint_store);
         }));
 
         // FIXME: #4825; This is required, because Clippy lints that are based on MIR have to be
@@ -191,7 +191,7 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
     ];
 
     for note in &xs {
-        handler.note_without_error(&note);
+        handler.note_without_error(note);
     }
 
     // If backtraces are enabled, also print the query stack
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index 0594663786c..f4d354f0bf9 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -98,7 +98,7 @@ fn default_config() -> compiletest::Config {
 fn run_mode(cfg: &mut compiletest::Config) {
     cfg.mode = TestMode::Ui;
     cfg.src_base = Path::new("tests").join("ui");
-    compiletest::run_tests(&cfg);
+    compiletest::run_tests(cfg);
 }
 
 fn run_internal_tests(cfg: &mut compiletest::Config) {
@@ -108,7 +108,7 @@ fn run_internal_tests(cfg: &mut compiletest::Config) {
     }
     cfg.mode = TestMode::Ui;
     cfg.src_base = Path::new("tests").join("ui-internal");
-    compiletest::run_tests(&cfg);
+    compiletest::run_tests(cfg);
 }
 
 fn run_ui_toml(config: &mut compiletest::Config) {
@@ -136,7 +136,7 @@ fn run_ui_toml(config: &mut compiletest::Config) {
                     base: config.src_base.clone(),
                     relative_dir: dir_path.file_name().unwrap().into(),
                 };
-                let test_name = compiletest::make_test_name(&config, &paths);
+                let test_name = compiletest::make_test_name(config, &paths);
                 let index = tests
                     .iter()
                     .position(|test| test.desc.name == test_name)
@@ -150,10 +150,10 @@ fn run_ui_toml(config: &mut compiletest::Config) {
     config.mode = TestMode::Ui;
     config.src_base = Path::new("tests").join("ui-toml").canonicalize().unwrap();
 
-    let tests = compiletest::make_tests(&config);
+    let tests = compiletest::make_tests(config);
 
     let manifest_dir = var("CARGO_MANIFEST_DIR").unwrap_or_default();
-    let res = run_tests(&config, tests);
+    let res = run_tests(config, tests);
     set_var("CARGO_MANIFEST_DIR", &manifest_dir);
     match res {
         Ok(true) => {},
@@ -221,7 +221,7 @@ fn run_ui_cargo(config: &mut compiletest::Config) {
                         base: config.src_base.clone(),
                         relative_dir: src_path.strip_prefix(&config.src_base).unwrap().into(),
                     };
-                    let test_name = compiletest::make_test_name(&config, &paths);
+                    let test_name = compiletest::make_test_name(config, &paths);
                     let index = tests
                         .iter()
                         .position(|test| test.desc.name == test_name)
@@ -240,11 +240,11 @@ fn run_ui_cargo(config: &mut compiletest::Config) {
     config.mode = TestMode::Ui;
     config.src_base = Path::new("tests").join("ui-cargo").canonicalize().unwrap();
 
-    let tests = compiletest::make_tests(&config);
+    let tests = compiletest::make_tests(config);
 
     let current_dir = env::current_dir().unwrap();
     let conf_dir = var("CLIPPY_CONF_DIR").unwrap_or_default();
-    let res = run_tests(&config, &config.filters, tests);
+    let res = run_tests(config, &config.filters, tests);
     env::set_current_dir(current_dir).unwrap();
     set_var("CLIPPY_CONF_DIR", conf_dir);
 
diff --git a/src/tools/clippy/tests/lint_message_convention.rs b/src/tools/clippy/tests/lint_message_convention.rs
index 3f754c255b7..2f8989c8e11 100644
--- a/src/tools/clippy/tests/lint_message_convention.rs
+++ b/src/tools/clippy/tests/lint_message_convention.rs
@@ -89,14 +89,14 @@ fn lint_message_convention() {
         .filter(|message| !message.bad_lines.is_empty())
         .collect();
 
-    bad_tests.iter().for_each(|message| {
+    for message in &bad_tests {
         eprintln!(
             "error: the test '{}' contained the following nonconforming lines :",
             message.path.display()
         );
         message.bad_lines.iter().for_each(|line| eprintln!("{}", line));
         eprintln!("\n\n");
-    });
+    }
 
     eprintln!(
         "\n\n\nLint message should not start with a capital letter and should not have punctuation at the end of the message unless multiple sentences are needed."
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr
index c8ae6c820df..5e9aa8dc36a 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr
@@ -1,9 +1,7 @@
-error: package `cargo_common_metadata` is missing `package.authors` metadata
+error: package `cargo_common_metadata` is missing `package.description` metadata
    |
    = note: `-D clippy::cargo-common-metadata` implied by `-D warnings`
 
-error: package `cargo_common_metadata` is missing `package.description` metadata
-
 error: package `cargo_common_metadata` is missing `either package.license or package.license_file` metadata
 
 error: package `cargo_common_metadata` is missing `package.repository` metadata
@@ -14,5 +12,5 @@ error: package `cargo_common_metadata` is missing `package.keywords` metadata
 
 error: package `cargo_common_metadata` is missing `package.categories` metadata
 
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.stderr b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.stderr
index c8ae6c820df..5e9aa8dc36a 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.stderr
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.stderr
@@ -1,9 +1,7 @@
-error: package `cargo_common_metadata` is missing `package.authors` metadata
+error: package `cargo_common_metadata` is missing `package.description` metadata
    |
    = note: `-D clippy::cargo-common-metadata` implied by `-D warnings`
 
-error: package `cargo_common_metadata` is missing `package.description` metadata
-
 error: package `cargo_common_metadata` is missing `either package.license or package.license_file` metadata
 
 error: package `cargo_common_metadata` is missing `package.repository` metadata
@@ -14,5 +12,5 @@ error: package `cargo_common_metadata` is missing `package.keywords` metadata
 
 error: package `cargo_common_metadata` is missing `package.categories` metadata
 
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.stderr b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.stderr
index c8ae6c820df..5e9aa8dc36a 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.stderr
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.stderr
@@ -1,9 +1,7 @@
-error: package `cargo_common_metadata` is missing `package.authors` metadata
+error: package `cargo_common_metadata` is missing `package.description` metadata
    |
    = note: `-D clippy::cargo-common-metadata` implied by `-D warnings`
 
-error: package `cargo_common_metadata` is missing `package.description` metadata
-
 error: package `cargo_common_metadata` is missing `either package.license or package.license_file` metadata
 
 error: package `cargo_common_metadata` is missing `package.repository` metadata
@@ -14,5 +12,5 @@ error: package `cargo_common_metadata` is missing `package.keywords` metadata
 
 error: package `cargo_common_metadata` is missing `package.categories` metadata
 
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml
index 737e84e963c..cb4774d43a2 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml
@@ -2,7 +2,6 @@
 name = "cargo_common_metadata"
 version = "0.1.0"
 publish = false
-authors = ["Random person from the Internet <someone@someplace.org>"]
 description = "A test package for the cargo_common_metadata lint"
 repository = "https://github.com/someone/cargo_common_metadata"
 readme = "README.md"
diff --git a/src/tools/clippy/tests/ui-internal/if_chain_style.rs b/src/tools/clippy/tests/ui-internal/if_chain_style.rs
new file mode 100644
index 00000000000..8e871707aa8
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/if_chain_style.rs
@@ -0,0 +1,92 @@
+#![warn(clippy::if_chain_style)]
+#![allow(clippy::no_effect)]
+
+extern crate if_chain;
+
+use if_chain::if_chain;
+
+fn main() {
+    if true {
+        let x = "";
+        // `if_chain!` inside `if`
+        if_chain! {
+            if true;
+            if true;
+            then {}
+        }
+    }
+    if_chain! {
+        if true
+            // multi-line AND'ed conditions
+            && false;
+        if let Some(1) = Some(1);
+        // `let` before `then`
+        let x = "";
+        then {
+            ();
+        }
+    }
+    if_chain! {
+        // single `if` condition
+        if true;
+        then {
+            let x = "";
+            // nested if
+            if true {}
+        }
+    }
+    if_chain! {
+        // starts with `let ..`
+        let x = "";
+        if let Some(1) = Some(1);
+        then {
+            let x = "";
+            let x = "";
+            // nested if_chain!
+            if_chain! {
+                if true;
+                if true;
+                then {}
+            }
+        }
+    }
+}
+
+fn negative() {
+    if true {
+        ();
+        if_chain! {
+            if true;
+            if true;
+            then { (); }
+        }
+    }
+    if_chain! {
+        if true;
+        let x = "";
+        if true;
+        then { (); }
+    }
+    if_chain! {
+        if true;
+        if true;
+        then {
+            if true { 1 } else { 2 }
+        } else {
+            3
+        }
+    };
+    if true {
+        if_chain! {
+            if true;
+            if true;
+            then {}
+        }
+    } else if false {
+        if_chain! {
+            if true;
+            if false;
+            then {}
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui-internal/if_chain_style.stderr b/src/tools/clippy/tests/ui-internal/if_chain_style.stderr
new file mode 100644
index 00000000000..b53c3ea05da
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/if_chain_style.stderr
@@ -0,0 +1,85 @@
+error: this `if` can be part of the inner `if_chain!`
+  --> $DIR/if_chain_style.rs:9:5
+   |
+LL | /     if true {
+LL | |         let x = "";
+LL | |         // `if_chain!` inside `if`
+LL | |         if_chain! {
+...  |
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::if-chain-style` implied by `-D warnings`
+help: this `let` statement can also be in the `if_chain!`
+  --> $DIR/if_chain_style.rs:10:9
+   |
+LL |         let x = "";
+   |         ^^^^^^^^^^^
+
+error: `if a && b;` should be `if a; if b;`
+  --> $DIR/if_chain_style.rs:19:12
+   |
+LL |           if true
+   |  ____________^
+LL | |             // multi-line AND'ed conditions
+LL | |             && false;
+   | |____________________^
+
+error: `let` expression should be inside `then { .. }`
+  --> $DIR/if_chain_style.rs:24:9
+   |
+LL |         let x = "";
+   |         ^^^^^^^^^^^
+
+error: this `if` can be part of the outer `if_chain!`
+  --> $DIR/if_chain_style.rs:35:13
+   |
+LL |             if true {}
+   |             ^^^^^^^^^^
+   |
+help: this `let` statement can also be in the `if_chain!`
+  --> $DIR/if_chain_style.rs:33:13
+   |
+LL |             let x = "";
+   |             ^^^^^^^^^^^
+
+error: `if_chain!` only has one `if`
+  --> $DIR/if_chain_style.rs:29:5
+   |
+LL | /     if_chain! {
+LL | |         // single `if` condition
+LL | |         if true;
+LL | |         then {
+...  |
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `let` expression should be above the `if_chain!`
+  --> $DIR/if_chain_style.rs:40:9
+   |
+LL |         let x = "";
+   |         ^^^^^^^^^^^
+
+error: this `if_chain!` can be merged with the outer `if_chain!`
+  --> $DIR/if_chain_style.rs:46:13
+   |
+LL | /             if_chain! {
+LL | |                 if true;
+LL | |                 if true;
+LL | |                 then {}
+LL | |             }
+   | |_____________^
+   |
+help: these `let` statements can also be in the `if_chain!`
+  --> $DIR/if_chain_style.rs:43:13
+   |
+LL | /             let x = "";
+LL | |             let x = "";
+   | |_______________________^
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs b/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs
index c6659edacc3..1a5cf1b1947 100644
--- a/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs
+++ b/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs
@@ -25,4 +25,20 @@ pub struct MIXEDCapital;
 
 pub struct FULLCAPITAL;
 
+// enum variants should not be linted if the num is pub
+pub enum ParseError<T> {
+    FULLCAPITAL(u8),
+    MIXEDCapital(String),
+    Utf8(std::string::FromUtf8Error),
+    Parse(T, String),
+}
+
+// private, do lint here
+enum ParseErrorPrivate<T> {
+    WASD(u8),
+    WASDMixed(String),
+    Utf8(std::string::FromUtf8Error),
+    Parse(T, String),
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.stderr b/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.stderr
index 38e30683d57..02f29bbefe1 100644
--- a/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.stderr
+++ b/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.stderr
@@ -66,5 +66,17 @@ error: name `GCCLLVMSomething` contains a capitalized acronym
 LL | struct GCCLLVMSomething;
    |        ^^^^^^^^^^^^^^^^ help: consider making the acronym lowercase, except the initial letter: `GccllvmSomething`
 
-error: aborting due to 11 previous errors
+error: name `WASD` contains a capitalized acronym
+  --> $DIR/upper_case_acronyms.rs:38:5
+   |
+LL |     WASD(u8),
+   |     ^^^^ help: consider making the acronym lowercase, except the initial letter: `Wasd`
+
+error: name `WASDMixed` contains a capitalized acronym
+  --> $DIR/upper_case_acronyms.rs:39:5
+   |
+LL |     WASDMixed(String),
+   |     ^^^^^^^^^ help: consider making the acronym lowercase, except the initial letter: `WasdMixed`
+
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs
index ea25729d11d..4327f12c37c 100644
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs
@@ -1,5 +1,9 @@
 #![warn(clippy::borrow_interior_mutable_const)]
-#![allow(clippy::declare_interior_mutable_const, clippy::ref_in_deref)]
+#![allow(
+    clippy::declare_interior_mutable_const,
+    clippy::ref_in_deref,
+    clippy::needless_borrow
+)]
 #![allow(const_item_mutation)]
 
 use std::borrow::Cow;
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
index 9a908cf30e9..f146b97cf61 100644
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
@@ -1,5 +1,5 @@
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:54:5
+  --> $DIR/others.rs:58:5
    |
 LL |     ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
    |     ^^^^^^
@@ -8,7 +8,7 @@ LL |     ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:55:16
+  --> $DIR/others.rs:59:16
    |
 LL |     assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability
    |                ^^^^^^
@@ -16,7 +16,7 @@ LL |     assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutabi
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:58:22
+  --> $DIR/others.rs:62:22
    |
 LL |     let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
    |                      ^^^^^^^^^
@@ -24,7 +24,7 @@ LL |     let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:59:25
+  --> $DIR/others.rs:63:25
    |
 LL |     let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
    |                         ^^^^^^^^^
@@ -32,7 +32,7 @@ LL |     let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:60:27
+  --> $DIR/others.rs:64:27
    |
 LL |     let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
    |                           ^^^^^^^^^
@@ -40,7 +40,7 @@ LL |     let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:61:26
+  --> $DIR/others.rs:65:26
    |
 LL |     let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
    |                          ^^^^^^^^^
@@ -48,7 +48,7 @@ LL |     let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:72:14
+  --> $DIR/others.rs:76:14
    |
 LL |     let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
    |              ^^^^^^^^^^^^
@@ -56,7 +56,7 @@ LL |     let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:73:14
+  --> $DIR/others.rs:77:14
    |
 LL |     let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
    |              ^^^^^^^^^^^^
@@ -64,7 +64,7 @@ LL |     let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:74:19
+  --> $DIR/others.rs:78:19
    |
 LL |     let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
    |                   ^^^^^^^^^^^^
@@ -72,7 +72,7 @@ LL |     let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:75:14
+  --> $DIR/others.rs:79:14
    |
 LL |     let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
    |              ^^^^^^^^^^^^
@@ -80,7 +80,7 @@ LL |     let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:76:13
+  --> $DIR/others.rs:80:13
    |
 LL |     let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability
    |             ^^^^^^^^^^^^
@@ -88,7 +88,7 @@ LL |     let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mu
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:82:13
+  --> $DIR/others.rs:86:13
    |
 LL |     let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
    |             ^^^^^^^^^^^^
@@ -96,7 +96,7 @@ LL |     let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:87:5
+  --> $DIR/others.rs:91:5
    |
 LL |     CELL.set(2); //~ ERROR interior mutability
    |     ^^^^
@@ -104,7 +104,7 @@ LL |     CELL.set(2); //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:88:16
+  --> $DIR/others.rs:92:16
    |
 LL |     assert_eq!(CELL.get(), 6); //~ ERROR interior mutability
    |                ^^^^
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs
new file mode 100644
index 00000000000..c389c243d44
--- /dev/null
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs
@@ -0,0 +1,209 @@
+#![allow(dead_code)]
+#![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
+
+// This tests the branches_sharing_code lint at the end of blocks
+
+fn simple_examples() {
+    let x = 1;
+
+    let _ = if x == 7 {
+        println!("Branch I");
+        let start_value = 0;
+        println!("=^.^=");
+
+        // Same but not moveable due to `start_value`
+        let _ = start_value;
+
+        // The rest is self contained and moveable => Only lint the rest
+        let result = false;
+        println!("Block end!");
+        result
+    } else {
+        println!("Branch II");
+        let start_value = 8;
+        println!("xD");
+
+        // Same but not moveable due to `start_value`
+        let _ = start_value;
+
+        // The rest is self contained and moveable => Only lint the rest
+        let result = false;
+        println!("Block end!");
+        result
+    };
+
+    // Else if block
+    if x == 9 {
+        println!("The index is: 6");
+
+        println!("Same end of block");
+    } else if x == 8 {
+        println!("The index is: 4");
+
+        // We should only get a lint trigger for the last statement
+        println!("This is also eq with the else block");
+        println!("Same end of block");
+    } else {
+        println!("This is also eq with the else block");
+        println!("Same end of block");
+    }
+
+    // Use of outer scope value
+    let outer_scope_value = "I'm outside the if block";
+    if x < 99 {
+        let z = "How are you";
+        println!("I'm a local because I use the value `z`: `{}`", z);
+
+        println!(
+            "I'm moveable because I know: `outer_scope_value`: '{}'",
+            outer_scope_value
+        );
+    } else {
+        let z = 45678000;
+        println!("I'm a local because I use the value `z`: `{}`", z);
+
+        println!(
+            "I'm moveable because I know: `outer_scope_value`: '{}'",
+            outer_scope_value
+        );
+    }
+
+    if x == 9 {
+        if x == 8 {
+            // No parent!!
+            println!("---");
+            println!("Hello World");
+        } else {
+            println!("Hello World");
+        }
+    }
+}
+
+/// Simple examples where the move can cause some problems due to moved values
+fn simple_but_suggestion_is_invalid() {
+    let x = 16;
+
+    // Local value
+    let later_used_value = 17;
+    if x == 9 {
+        let _ = 9;
+        let later_used_value = "A string value";
+        println!("{}", later_used_value);
+    } else {
+        let later_used_value = "A string value";
+        println!("{}", later_used_value);
+        // I'm expecting a note about this
+    }
+    println!("{}", later_used_value);
+
+    // outer function
+    if x == 78 {
+        let simple_examples = "I now identify as a &str :)";
+        println!("This is the new simple_example: {}", simple_examples);
+    } else {
+        println!("Separator print statement");
+
+        let simple_examples = "I now identify as a &str :)";
+        println!("This is the new simple_example: {}", simple_examples);
+    }
+    simple_examples();
+}
+
+/// Tests where the blocks are not linted due to the used value scope
+fn not_moveable_due_to_value_scope() {
+    let x = 18;
+
+    // Using a local value in the moved code
+    if x == 9 {
+        let y = 18;
+        println!("y is: `{}`", y);
+    } else {
+        let y = "A string";
+        println!("y is: `{}`", y);
+    }
+
+    // Using a local value in the expression
+    let _ = if x == 0 {
+        let mut result = x + 1;
+
+        println!("1. Doing some calculations");
+        println!("2. Some more calculations");
+        println!("3. Setting result");
+
+        result
+    } else {
+        let mut result = x - 1;
+
+        println!("1. Doing some calculations");
+        println!("2. Some more calculations");
+        println!("3. Setting result");
+
+        result
+    };
+
+    let _ = if x == 7 {
+        let z1 = 100;
+        println!("z1: {}", z1);
+
+        let z2 = z1;
+        println!("z2: {}", z2);
+
+        z2
+    } else {
+        let z1 = 300;
+        println!("z1: {}", z1);
+
+        let z2 = z1;
+        println!("z2: {}", z2);
+
+        z2
+    };
+}
+
+/// This should add a note to the lint msg since the moved expression is not `()`
+fn added_note_for_expression_use() -> u32 {
+    let x = 9;
+
+    let _ = if x == 7 {
+        x << 2
+    } else {
+        let _ = 6;
+        x << 2
+    };
+
+    if x == 9 {
+        x * 4
+    } else {
+        let _ = 17;
+        x * 4
+    }
+}
+
+#[rustfmt::skip]
+fn test_suggestion_with_weird_formatting() {
+    let x = 9;
+    let mut a = 0;
+    let mut b = 0;
+
+    // The error message still looks weird tbh but this is the best I can do
+    // for weird formatting
+    if x == 17 { b = 1; a = 0x99; } else { a = 0x99; }
+}
+
+fn fp_test() {
+    let x = 17;
+
+    if x == 18 {
+        let y = 19;
+        if y < x {
+            println!("Trigger")
+        }
+    } else {
+        let z = 166;
+        if z < x {
+            println!("Trigger")
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr
new file mode 100644
index 00000000000..271fcd8b6c1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr
@@ -0,0 +1,143 @@
+error: all if blocks contain the same code at the end
+  --> $DIR/shared_at_bottom.rs:30:5
+   |
+LL | /         let result = false;
+LL | |         println!("Block end!");
+LL | |         result
+LL | |     };
+   | |_____^
+   |
+note: the lint level is defined here
+  --> $DIR/shared_at_bottom.rs:2:36
+   |
+LL | #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: The end suggestion probably needs some adjustments to use the expression result correctly
+help: consider moving the end statements out like this
+   |
+LL |     }
+LL |     let result = false;
+LL |     println!("Block end!");
+LL |     result;
+   |
+
+error: all if blocks contain the same code at the end
+  --> $DIR/shared_at_bottom.rs:48:5
+   |
+LL | /         println!("Same end of block");
+LL | |     }
+   | |_____^
+   |
+help: consider moving the end statements out like this
+   |
+LL |     }
+LL |     println!("Same end of block");
+   |
+
+error: all if blocks contain the same code at the end
+  --> $DIR/shared_at_bottom.rs:65:5
+   |
+LL | /         println!(
+LL | |             "I'm moveable because I know: `outer_scope_value`: '{}'",
+LL | |             outer_scope_value
+LL | |         );
+LL | |     }
+   | |_____^
+   |
+help: consider moving the end statements out like this
+   |
+LL |     }
+LL |     println!(
+LL |         "I'm moveable because I know: `outer_scope_value`: '{}'",
+LL |         outer_scope_value
+LL |     );
+   |
+
+error: all if blocks contain the same code at the end
+  --> $DIR/shared_at_bottom.rs:77:9
+   |
+LL | /             println!("Hello World");
+LL | |         }
+   | |_________^
+   |
+help: consider moving the end statements out like this
+   |
+LL |         }
+LL |         println!("Hello World");
+   |
+
+error: all if blocks contain the same code at the end
+  --> $DIR/shared_at_bottom.rs:93:5
+   |
+LL | /         let later_used_value = "A string value";
+LL | |         println!("{}", later_used_value);
+LL | |         // I'm expecting a note about this
+LL | |     }
+   | |_____^
+   |
+   = warning: Some moved values might need to be renamed to avoid wrong references
+help: consider moving the end statements out like this
+   |
+LL |     }
+LL |     let later_used_value = "A string value";
+LL |     println!("{}", later_used_value);
+   |
+
+error: all if blocks contain the same code at the end
+  --> $DIR/shared_at_bottom.rs:106:5
+   |
+LL | /         let simple_examples = "I now identify as a &str :)";
+LL | |         println!("This is the new simple_example: {}", simple_examples);
+LL | |     }
+   | |_____^
+   |
+   = warning: Some moved values might need to be renamed to avoid wrong references
+help: consider moving the end statements out like this
+   |
+LL |     }
+LL |     let simple_examples = "I now identify as a &str :)";
+LL |     println!("This is the new simple_example: {}", simple_examples);
+   |
+
+error: all if blocks contain the same code at the end
+  --> $DIR/shared_at_bottom.rs:171:5
+   |
+LL | /         x << 2
+LL | |     };
+   | |_____^
+   |
+   = note: The end suggestion probably needs some adjustments to use the expression result correctly
+help: consider moving the end statements out like this
+   |
+LL |     }
+LL |     x << 2;
+   |
+
+error: all if blocks contain the same code at the end
+  --> $DIR/shared_at_bottom.rs:178:5
+   |
+LL | /         x * 4
+LL | |     }
+   | |_____^
+   |
+   = note: The end suggestion probably needs some adjustments to use the expression result correctly
+help: consider moving the end statements out like this
+   |
+LL |     }
+LL |     x * 4
+   |
+
+error: all if blocks contain the same code at the end
+  --> $DIR/shared_at_bottom.rs:190:44
+   |
+LL |     if x == 17 { b = 1; a = 0x99; } else { a = 0x99; }
+   |                                            ^^^^^^^^^^^
+   |
+help: consider moving the end statements out like this
+   |
+LL |     if x == 17 { b = 1; a = 0x99; } else { }
+LL |     a = 0x99;
+   |
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs
new file mode 100644
index 00000000000..e65bcfd7873
--- /dev/null
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs
@@ -0,0 +1,103 @@
+#![allow(dead_code, clippy::eval_order_dependence)]
+#![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
+
+// This tests the branches_sharing_code lint at the start of blocks
+
+fn simple_examples() {
+    let x = 0;
+
+    // Simple
+    if true {
+        println!("Hello World!");
+        println!("I'm branch nr: 1");
+    } else {
+        println!("Hello World!");
+        println!("I'm branch nr: 2");
+    }
+
+    // Else if
+    if x == 0 {
+        let y = 9;
+        println!("The value y was set to: `{}`", y);
+        let _z = y;
+
+        println!("I'm the true start index of arrays");
+    } else if x == 1 {
+        let y = 9;
+        println!("The value y was set to: `{}`", y);
+        let _z = y;
+
+        println!("I start counting from 1 so my array starts from `1`");
+    } else {
+        let y = 9;
+        println!("The value y was set to: `{}`", y);
+        let _z = y;
+
+        println!("Ha, Pascal allows you to start the array where you want")
+    }
+
+    // Return a value
+    let _ = if x == 7 {
+        let y = 16;
+        println!("What can I say except: \"you're welcome?\"");
+        let _ = y;
+        x
+    } else {
+        let y = 16;
+        println!("Thank you");
+        y
+    };
+}
+
+/// Simple examples where the move can cause some problems due to moved values
+fn simple_but_suggestion_is_invalid() {
+    let x = 10;
+
+    // Can't be automatically moved because used_value_name is getting used again
+    let used_value_name = 19;
+    if x == 10 {
+        let used_value_name = "Different type";
+        println!("Str: {}", used_value_name);
+        let _ = 1;
+    } else {
+        let used_value_name = "Different type";
+        println!("Str: {}", used_value_name);
+        let _ = 2;
+    }
+    let _ = used_value_name;
+
+    // This can be automatically moved as `can_be_overridden` is not used again
+    let can_be_overridden = 8;
+    let _ = can_be_overridden;
+    if x == 11 {
+        let can_be_overridden = "Move me";
+        println!("I'm also moveable");
+        let _ = 111;
+    } else {
+        let can_be_overridden = "Move me";
+        println!("I'm also moveable");
+        let _ = 222;
+    }
+}
+
+/// This function tests that the `IS_SAME_THAN_ELSE` only covers the lint if it's enabled.
+fn check_if_same_than_else_mask() {
+    let x = 2021;
+
+    #[allow(clippy::if_same_then_else)]
+    if x == 2020 {
+        println!("This should trigger the `SHARED_CODE_IN_IF_BLOCKS` lint.");
+        println!("Because `IF_SAME_THEN_ELSE` is allowed here");
+    } else {
+        println!("This should trigger the `SHARED_CODE_IN_IF_BLOCKS` lint.");
+        println!("Because `IF_SAME_THEN_ELSE` is allowed here");
+    }
+
+    if x == 2019 {
+        println!("This should trigger `IS_SAME_THAN_ELSE` as usual");
+    } else {
+        println!("This should trigger `IS_SAME_THAN_ELSE` as usual");
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr
new file mode 100644
index 00000000000..15867e9ea02
--- /dev/null
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr
@@ -0,0 +1,121 @@
+error: all if blocks contain the same code at the start
+  --> $DIR/shared_at_top.rs:10:5
+   |
+LL | /     if true {
+LL | |         println!("Hello World!");
+   | |_________________________________^
+   |
+note: the lint level is defined here
+  --> $DIR/shared_at_top.rs:2:36
+   |
+LL | #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider moving the start statements out like this
+   |
+LL |     println!("Hello World!");
+LL |     if true {
+   |
+
+error: all if blocks contain the same code at the start
+  --> $DIR/shared_at_top.rs:19:5
+   |
+LL | /     if x == 0 {
+LL | |         let y = 9;
+LL | |         println!("The value y was set to: `{}`", y);
+LL | |         let _z = y;
+   | |___________________^
+   |
+   = warning: Some moved values might need to be renamed to avoid wrong references
+help: consider moving the start statements out like this
+   |
+LL |     let y = 9;
+LL |     println!("The value y was set to: `{}`", y);
+LL |     let _z = y;
+LL |     if x == 0 {
+   |
+
+error: all if blocks contain the same code at the start
+  --> $DIR/shared_at_top.rs:40:5
+   |
+LL | /     let _ = if x == 7 {
+LL | |         let y = 16;
+   | |___________________^
+   |
+help: consider moving the start statements out like this
+   |
+LL |     let y = 16;
+LL |     let _ = if x == 7 {
+   |
+
+error: all if blocks contain the same code at the start
+  --> $DIR/shared_at_top.rs:58:5
+   |
+LL | /     if x == 10 {
+LL | |         let used_value_name = "Different type";
+LL | |         println!("Str: {}", used_value_name);
+   | |_____________________________________________^
+   |
+   = warning: Some moved values might need to be renamed to avoid wrong references
+help: consider moving the start statements out like this
+   |
+LL |     let used_value_name = "Different type";
+LL |     println!("Str: {}", used_value_name);
+LL |     if x == 10 {
+   |
+
+error: all if blocks contain the same code at the start
+  --> $DIR/shared_at_top.rs:72:5
+   |
+LL | /     if x == 11 {
+LL | |         let can_be_overridden = "Move me";
+LL | |         println!("I'm also moveable");
+   | |______________________________________^
+   |
+   = warning: Some moved values might need to be renamed to avoid wrong references
+help: consider moving the start statements out like this
+   |
+LL |     let can_be_overridden = "Move me";
+LL |     println!("I'm also moveable");
+LL |     if x == 11 {
+   |
+
+error: all if blocks contain the same code at the start
+  --> $DIR/shared_at_top.rs:88:5
+   |
+LL | /     if x == 2020 {
+LL | |         println!("This should trigger the `SHARED_CODE_IN_IF_BLOCKS` lint.");
+LL | |         println!("Because `IF_SAME_THEN_ELSE` is allowed here");
+   | |________________________________________________________________^
+   |
+help: consider moving the start statements out like this
+   |
+LL |     println!("This should trigger the `SHARED_CODE_IN_IF_BLOCKS` lint.");
+LL |     println!("Because `IF_SAME_THEN_ELSE` is allowed here");
+LL |     if x == 2020 {
+   |
+
+error: this `if` has identical blocks
+  --> $DIR/shared_at_top.rs:96:18
+   |
+LL |       if x == 2019 {
+   |  __________________^
+LL | |         println!("This should trigger `IS_SAME_THAN_ELSE` as usual");
+LL | |     } else {
+   | |_____^
+   |
+note: the lint level is defined here
+  --> $DIR/shared_at_top.rs:2:9
+   |
+LL | #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: same as this
+  --> $DIR/shared_at_top.rs:98:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         println!("This should trigger `IS_SAME_THAN_ELSE` as usual");
+LL | |     }
+   | |_____^
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs
new file mode 100644
index 00000000000..deefdad32c9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs
@@ -0,0 +1,119 @@
+#![allow(dead_code)]
+#![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
+
+// branches_sharing_code at the top and bottom of the if blocks
+
+struct DataPack {
+    id: u32,
+    name: String,
+    some_data: Vec<u8>,
+}
+
+fn overlapping_eq_regions() {
+    let x = 9;
+
+    // Overlap with separator
+    if x == 7 {
+        let t = 7;
+        let _overlap_start = t * 2;
+        let _overlap_end = 2 * t;
+        let _u = 9;
+    } else {
+        let t = 7;
+        let _overlap_start = t * 2;
+        let _overlap_end = 2 * t;
+        println!("Overlap separator");
+        let _overlap_start = t * 2;
+        let _overlap_end = 2 * t;
+        let _u = 9;
+    }
+
+    // Overlap with separator
+    if x == 99 {
+        let r = 7;
+        let _overlap_start = r;
+        let _overlap_middle = r * r;
+        let _overlap_end = r * r * r;
+        let z = "end";
+    } else {
+        let r = 7;
+        let _overlap_start = r;
+        let _overlap_middle = r * r;
+        let _overlap_middle = r * r;
+        let _overlap_end = r * r * r;
+        let z = "end";
+    }
+}
+
+fn complexer_example() {
+    fn gen_id(x: u32, y: u32) -> u32 {
+        let x = x & 0x0000_ffff;
+        let y = (y & 0xffff_0000) << 16;
+        x | y
+    }
+
+    fn process_data(data: DataPack) {
+        let _ = data;
+    }
+
+    let x = 8;
+    let y = 9;
+    if (x > 7 && y < 13) || (x + y) % 2 == 1 {
+        let a = 0xcafe;
+        let b = 0xffff00ff;
+        let e_id = gen_id(a, b);
+
+        println!("From the a `{}` to the b `{}`", a, b);
+
+        let pack = DataPack {
+            id: e_id,
+            name: "Player 1".to_string(),
+            some_data: vec![0x12, 0x34, 0x56, 0x78, 0x90],
+        };
+        process_data(pack);
+    } else {
+        let a = 0xcafe;
+        let b = 0xffff00ff;
+        let e_id = gen_id(a, b);
+
+        println!("The new ID is '{}'", e_id);
+
+        let pack = DataPack {
+            id: e_id,
+            name: "Player 1".to_string(),
+            some_data: vec![0x12, 0x34, 0x56, 0x78, 0x90],
+        };
+        process_data(pack);
+    }
+}
+
+/// This should add a note to the lint msg since the moved expression is not `()`
+fn added_note_for_expression_use() -> u32 {
+    let x = 9;
+
+    let _ = if x == 7 {
+        let _ = 19;
+
+        let _splitter = 6;
+
+        x << 2
+    } else {
+        let _ = 19;
+
+        x << 2
+    };
+
+    if x == 9 {
+        let _ = 17;
+
+        let _splitter = 6;
+
+        x * 4
+    } else {
+        let _ = 17;
+
+        x * 4
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr
new file mode 100644
index 00000000000..212cfb2f1d1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr
@@ -0,0 +1,154 @@
+error: all if blocks contain the same code at the start and the end. Here at the start
+  --> $DIR/shared_at_top_and_bottom.rs:16:5
+   |
+LL | /     if x == 7 {
+LL | |         let t = 7;
+LL | |         let _overlap_start = t * 2;
+LL | |         let _overlap_end = 2 * t;
+   | |_________________________________^
+   |
+note: the lint level is defined here
+  --> $DIR/shared_at_top_and_bottom.rs:2:36
+   |
+LL | #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: and here at the end
+  --> $DIR/shared_at_top_and_bottom.rs:28:5
+   |
+LL | /         let _u = 9;
+LL | |     }
+   | |_____^
+help: consider moving the start statements out like this
+   |
+LL |     let t = 7;
+LL |     let _overlap_start = t * 2;
+LL |     let _overlap_end = 2 * t;
+LL |     if x == 7 {
+   |
+help: and consider moving the end statements out like this
+   |
+LL |     }
+LL |     let _u = 9;
+   |
+
+error: all if blocks contain the same code at the start and the end. Here at the start
+  --> $DIR/shared_at_top_and_bottom.rs:32:5
+   |
+LL | /     if x == 99 {
+LL | |         let r = 7;
+LL | |         let _overlap_start = r;
+LL | |         let _overlap_middle = r * r;
+   | |____________________________________^
+   |
+note: and here at the end
+  --> $DIR/shared_at_top_and_bottom.rs:43:5
+   |
+LL | /         let _overlap_end = r * r * r;
+LL | |         let z = "end";
+LL | |     }
+   | |_____^
+   = warning: Some moved values might need to be renamed to avoid wrong references
+help: consider moving the start statements out like this
+   |
+LL |     let r = 7;
+LL |     let _overlap_start = r;
+LL |     let _overlap_middle = r * r;
+LL |     if x == 99 {
+   |
+help: and consider moving the end statements out like this
+   |
+LL |     }
+LL |     let _overlap_end = r * r * r;
+LL |     let z = "end";
+   |
+
+error: all if blocks contain the same code at the start and the end. Here at the start
+  --> $DIR/shared_at_top_and_bottom.rs:61:5
+   |
+LL | /     if (x > 7 && y < 13) || (x + y) % 2 == 1 {
+LL | |         let a = 0xcafe;
+LL | |         let b = 0xffff00ff;
+LL | |         let e_id = gen_id(a, b);
+   | |________________________________^
+   |
+note: and here at the end
+  --> $DIR/shared_at_top_and_bottom.rs:81:5
+   |
+LL | /         let pack = DataPack {
+LL | |             id: e_id,
+LL | |             name: "Player 1".to_string(),
+LL | |             some_data: vec![0x12, 0x34, 0x56, 0x78, 0x90],
+LL | |         };
+LL | |         process_data(pack);
+LL | |     }
+   | |_____^
+   = warning: Some moved values might need to be renamed to avoid wrong references
+help: consider moving the start statements out like this
+   |
+LL |     let a = 0xcafe;
+LL |     let b = 0xffff00ff;
+LL |     let e_id = gen_id(a, b);
+LL |     if (x > 7 && y < 13) || (x + y) % 2 == 1 {
+   |
+help: and consider moving the end statements out like this
+   |
+LL |     }
+LL |     let pack = DataPack {
+LL |         id: e_id,
+LL |         name: "Player 1".to_string(),
+LL |         some_data: vec![0x12, 0x34, 0x56, 0x78, 0x90],
+LL |     };
+ ...
+
+error: all if blocks contain the same code at the start and the end. Here at the start
+  --> $DIR/shared_at_top_and_bottom.rs:94:5
+   |
+LL | /     let _ = if x == 7 {
+LL | |         let _ = 19;
+   | |___________________^
+   |
+note: and here at the end
+  --> $DIR/shared_at_top_and_bottom.rs:103:5
+   |
+LL | /         x << 2
+LL | |     };
+   | |_____^
+   = note: The end suggestion probably needs some adjustments to use the expression result correctly
+help: consider moving the start statements out like this
+   |
+LL |     let _ = 19;
+LL |     let _ = if x == 7 {
+   |
+help: and consider moving the end statements out like this
+   |
+LL |     }
+LL |     x << 2;
+   |
+
+error: all if blocks contain the same code at the start and the end. Here at the start
+  --> $DIR/shared_at_top_and_bottom.rs:106:5
+   |
+LL | /     if x == 9 {
+LL | |         let _ = 17;
+   | |___________________^
+   |
+note: and here at the end
+  --> $DIR/shared_at_top_and_bottom.rs:115:5
+   |
+LL | /         x * 4
+LL | |     }
+   | |_____^
+   = note: The end suggestion probably needs some adjustments to use the expression result correctly
+help: consider moving the start statements out like this
+   |
+LL |     let _ = 17;
+LL |     if x == 9 {
+   |
+help: and consider moving the end statements out like this
+   |
+LL |     }
+LL |     x * 4
+   |
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs b/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs
new file mode 100644
index 00000000000..0c70e3748ec
--- /dev/null
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs
@@ -0,0 +1,155 @@
+#![allow(dead_code, clippy::eval_order_dependence)]
+#![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
+
+// This tests valid if blocks that shouldn't trigger the lint
+
+// Tests with value references are includes in "shared_code_at_bottom.rs"
+
+fn valid_examples() {
+    let x = 2;
+
+    // The edge statements are different
+    if x == 9 {
+        let y = 1 << 5;
+
+        println!("This is the same: vvv");
+        let _z = y;
+        println!("The block expression is different");
+
+        println!("Different end 1");
+    } else {
+        let y = 1 << 7;
+
+        println!("This is the same: vvv");
+        let _z = y;
+        println!("The block expression is different");
+
+        println!("Different end 2");
+    }
+
+    // No else
+    if x == 2 {
+        println!("Hello world!");
+        println!("Hello back, how are you?");
+
+        // This is different vvvv
+        println!("Howdy stranger =^.^=");
+
+        println!("Bye Bye World");
+    } else if x == 9 {
+        println!("Hello world!");
+        println!("Hello back, how are you?");
+
+        // This is different vvvv
+        println!("Hello reviewer :D");
+
+        println!("Bye Bye World");
+    }
+
+    // Overlapping statements only in else if blocks -> Don't lint
+    if x == 0 {
+        println!("I'm important!")
+    } else if x == 17 {
+        println!("I share code in else if");
+
+        println!("x is 17");
+    } else {
+        println!("I share code in else if");
+
+        println!("x is nether x nor 17");
+    }
+
+    // Mutability is different
+    if x == 13 {
+        let mut y = 9;
+        println!("Value y is: {}", y);
+        y += 16;
+        let _z1 = y;
+    } else {
+        let y = 9;
+        println!("Value y is: {}", y);
+        let _z2 = y;
+    }
+
+    // Same blocks but at start and bottom so no `if_same_then_else` lint
+    if x == 418 {
+        let y = 9;
+        let z = 8;
+        let _ = (x, y, z);
+        // Don't tell the programmer, my code is also in the else block
+    } else if x == 419 {
+        println!("+-----------+");
+        println!("|           |");
+        println!("|  O     O  |");
+        println!("|     °     |");
+        println!("|  \\_____/  |");
+        println!("|           |");
+        println!("+-----------+");
+    } else {
+        let y = 9;
+        let z = 8;
+        let _ = (x, y, z);
+        // I'm so much better than the x == 418 block. Trust me
+    }
+
+    let x = 1;
+    if true {
+        println!("{}", x);
+    } else {
+        let x = 2;
+        println!("{}", x);
+    }
+
+    // Let's test empty blocks
+    if false {
+    } else {
+    }
+}
+
+/// This makes sure that the `if_same_then_else` masks the `shared_code_in_if_blocks` lint
+fn trigger_other_lint() {
+    let x = 0;
+    let y = 1;
+
+    // Same block
+    if x == 0 {
+        let u = 19;
+        println!("How are u today?");
+        let _ = "This is a string";
+    } else {
+        let u = 19;
+        println!("How are u today?");
+        let _ = "This is a string";
+    }
+
+    // Only same expression
+    let _ = if x == 6 { 7 } else { 7 };
+
+    // Same in else if block
+    let _ = if x == 67 {
+        println!("Well I'm the most important block");
+        "I'm a pretty string"
+    } else if x == 68 {
+        println!("I'm a doppelgänger");
+        // Don't listen to my clone below
+
+        if y == 90 { "=^.^=" } else { ":D" }
+    } else {
+        // Don't listen to my clone above
+        println!("I'm a doppelgänger");
+
+        if y == 90 { "=^.^=" } else { ":D" }
+    };
+
+    if x == 0 {
+        println!("I'm single");
+    } else if x == 68 {
+        println!("I'm a doppelgänger");
+        // Don't listen to my clone below
+    } else {
+        // Don't listen to my clone above
+        println!("I'm a doppelgänger");
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.stderr
new file mode 100644
index 00000000000..a815995e717
--- /dev/null
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.stderr
@@ -0,0 +1,101 @@
+error: this `if` has identical blocks
+  --> $DIR/valid_if_blocks.rs:104:14
+   |
+LL |       if false {
+   |  ______________^
+LL | |     } else {
+   | |_____^
+   |
+note: the lint level is defined here
+  --> $DIR/valid_if_blocks.rs:2:9
+   |
+LL | #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: same as this
+  --> $DIR/valid_if_blocks.rs:105:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |     }
+   | |_____^
+
+error: this `if` has identical blocks
+  --> $DIR/valid_if_blocks.rs:115:15
+   |
+LL |       if x == 0 {
+   |  _______________^
+LL | |         let u = 19;
+LL | |         println!("How are u today?");
+LL | |         let _ = "This is a string";
+LL | |     } else {
+   | |_____^
+   |
+note: same as this
+  --> $DIR/valid_if_blocks.rs:119:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         let u = 19;
+LL | |         println!("How are u today?");
+LL | |         let _ = "This is a string";
+LL | |     }
+   | |_____^
+
+error: this `if` has identical blocks
+  --> $DIR/valid_if_blocks.rs:126:23
+   |
+LL |     let _ = if x == 6 { 7 } else { 7 };
+   |                       ^^^^^
+   |
+note: same as this
+  --> $DIR/valid_if_blocks.rs:126:34
+   |
+LL |     let _ = if x == 6 { 7 } else { 7 };
+   |                                  ^^^^^
+
+error: this `if` has identical blocks
+  --> $DIR/valid_if_blocks.rs:132:23
+   |
+LL |       } else if x == 68 {
+   |  _______________________^
+LL | |         println!("I'm a doppelgänger");
+LL | |         // Don't listen to my clone below
+LL | |
+LL | |         if y == 90 { "=^.^=" } else { ":D" }
+LL | |     } else {
+   | |_____^
+   |
+note: same as this
+  --> $DIR/valid_if_blocks.rs:137:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         // Don't listen to my clone above
+LL | |         println!("I'm a doppelgänger");
+LL | |
+LL | |         if y == 90 { "=^.^=" } else { ":D" }
+LL | |     };
+   | |_____^
+
+error: this `if` has identical blocks
+  --> $DIR/valid_if_blocks.rs:146:23
+   |
+LL |       } else if x == 68 {
+   |  _______________________^
+LL | |         println!("I'm a doppelgänger");
+LL | |         // Don't listen to my clone below
+LL | |     } else {
+   | |_____^
+   |
+note: same as this
+  --> $DIR/valid_if_blocks.rs:149:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         // Don't listen to my clone above
+LL | |         println!("I'm a doppelgänger");
+LL | |     }
+   | |_____^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.rs b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.rs
index c986c992a07..ec082c73b44 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.rs
+++ b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.rs
@@ -1,5 +1,5 @@
 #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
-#![allow(clippy::if_same_then_else)]
+#![allow(clippy::if_same_then_else, clippy::branches_sharing_code)]
 
 fn test_complex_conditions() {
     let x: Result<(), ()> = Ok(());
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs
index 2307996a48f..043ea4148dc 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs
+++ b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs
@@ -1,5 +1,5 @@
 #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
-#![allow(clippy::if_same_then_else)]
+#![allow(clippy::if_same_then_else, clippy::branches_sharing_code)]
 
 fn test_nested() {
     fn nested() {
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
index 36967630834..8f23fb28827 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
+++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
@@ -1,5 +1,5 @@
 #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
-#![allow(clippy::if_same_then_else)]
+#![allow(clippy::if_same_then_else, clippy::branches_sharing_code)]
 
 macro_rules! m {
     ($a:expr) => {
diff --git a/src/tools/clippy/tests/ui/clone_on_copy.fixed b/src/tools/clippy/tests/ui/clone_on_copy.fixed
index d924625132e..8d43f64768d 100644
--- a/src/tools/clippy/tests/ui/clone_on_copy.fixed
+++ b/src/tools/clippy/tests/ui/clone_on_copy.fixed
@@ -6,7 +6,8 @@
     clippy::deref_addrof,
     clippy::no_effect,
     clippy::unnecessary_operation,
-    clippy::vec_init_then_push
+    clippy::vec_init_then_push,
+    clippy::toplevel_ref_arg
 )]
 
 use std::cell::RefCell;
@@ -29,6 +30,37 @@ fn clone_on_copy() {
     let rc = RefCell::new(0);
     *rc.borrow();
 
+    let x = 0u32;
+    x.rotate_left(1);
+
+    #[derive(Clone, Copy)]
+    struct Foo;
+    impl Foo {
+        fn clone(&self) -> u32 {
+            0
+        }
+    }
+    Foo.clone(); // ok, this is not the clone trait
+
+    macro_rules! m {
+        ($e:expr) => {{ $e }};
+    }
+    m!(42);
+
+    struct Wrap([u32; 2]);
+    impl core::ops::Deref for Wrap {
+        type Target = [u32; 2];
+        fn deref(&self) -> &[u32; 2] {
+            &self.0
+        }
+    }
+    let x = Wrap([0, 0]);
+    (*x)[0];
+
+    let x = 42;
+    let ref y = x.clone(); // ok, binds by reference
+    let ref mut y = x.clone(); // ok, binds by reference
+
     // Issue #4348
     let mut x = 43;
     let _ = &x.clone(); // ok, getting a ref
diff --git a/src/tools/clippy/tests/ui/clone_on_copy.rs b/src/tools/clippy/tests/ui/clone_on_copy.rs
index 97f49467244..f15501f7184 100644
--- a/src/tools/clippy/tests/ui/clone_on_copy.rs
+++ b/src/tools/clippy/tests/ui/clone_on_copy.rs
@@ -6,7 +6,8 @@
     clippy::deref_addrof,
     clippy::no_effect,
     clippy::unnecessary_operation,
-    clippy::vec_init_then_push
+    clippy::vec_init_then_push,
+    clippy::toplevel_ref_arg
 )]
 
 use std::cell::RefCell;
@@ -29,6 +30,37 @@ fn clone_on_copy() {
     let rc = RefCell::new(0);
     rc.borrow().clone();
 
+    let x = 0u32;
+    x.clone().rotate_left(1);
+
+    #[derive(Clone, Copy)]
+    struct Foo;
+    impl Foo {
+        fn clone(&self) -> u32 {
+            0
+        }
+    }
+    Foo.clone(); // ok, this is not the clone trait
+
+    macro_rules! m {
+        ($e:expr) => {{ $e }};
+    }
+    m!(42).clone();
+
+    struct Wrap([u32; 2]);
+    impl core::ops::Deref for Wrap {
+        type Target = [u32; 2];
+        fn deref(&self) -> &[u32; 2] {
+            &self.0
+        }
+    }
+    let x = Wrap([0, 0]);
+    x.clone()[0];
+
+    let x = 42;
+    let ref y = x.clone(); // ok, binds by reference
+    let ref mut y = x.clone(); // ok, binds by reference
+
     // Issue #4348
     let mut x = 43;
     let _ = &x.clone(); // ok, getting a ref
diff --git a/src/tools/clippy/tests/ui/clone_on_copy.stderr b/src/tools/clippy/tests/ui/clone_on_copy.stderr
index 7a706884fb0..e7d28b4320b 100644
--- a/src/tools/clippy/tests/ui/clone_on_copy.stderr
+++ b/src/tools/clippy/tests/ui/clone_on_copy.stderr
@@ -1,5 +1,5 @@
 error: using `clone` on type `i32` which implements the `Copy` trait
-  --> $DIR/clone_on_copy.rs:23:5
+  --> $DIR/clone_on_copy.rs:24:5
    |
 LL |     42.clone();
    |     ^^^^^^^^^^ help: try removing the `clone` call: `42`
@@ -7,28 +7,46 @@ LL |     42.clone();
    = note: `-D clippy::clone-on-copy` implied by `-D warnings`
 
 error: using `clone` on type `i32` which implements the `Copy` trait
-  --> $DIR/clone_on_copy.rs:27:5
+  --> $DIR/clone_on_copy.rs:28:5
    |
 LL |     (&42).clone();
    |     ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)`
 
 error: using `clone` on type `i32` which implements the `Copy` trait
-  --> $DIR/clone_on_copy.rs:30:5
+  --> $DIR/clone_on_copy.rs:31:5
    |
 LL |     rc.borrow().clone();
    |     ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()`
 
+error: using `clone` on type `u32` which implements the `Copy` trait
+  --> $DIR/clone_on_copy.rs:34:5
+   |
+LL |     x.clone().rotate_left(1);
+   |     ^^^^^^^^^ help: try removing the `clone` call: `x`
+
+error: using `clone` on type `i32` which implements the `Copy` trait
+  --> $DIR/clone_on_copy.rs:48:5
+   |
+LL |     m!(42).clone();
+   |     ^^^^^^^^^^^^^^ help: try removing the `clone` call: `m!(42)`
+
+error: using `clone` on type `[u32; 2]` which implements the `Copy` trait
+  --> $DIR/clone_on_copy.rs:58:5
+   |
+LL |     x.clone()[0];
+   |     ^^^^^^^^^ help: try dereferencing it: `(*x)`
+
 error: using `clone` on type `char` which implements the `Copy` trait
-  --> $DIR/clone_on_copy.rs:36:14
+  --> $DIR/clone_on_copy.rs:68:14
    |
 LL |     is_ascii('z'.clone());
    |              ^^^^^^^^^^^ help: try removing the `clone` call: `'z'`
 
 error: using `clone` on type `i32` which implements the `Copy` trait
-  --> $DIR/clone_on_copy.rs:40:14
+  --> $DIR/clone_on_copy.rs:72:14
    |
 LL |     vec.push(42.clone());
    |              ^^^^^^^^^^ help: try removing the `clone` call: `42`
 
-error: aborting due to 5 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/clone_on_copy_mut.rs b/src/tools/clippy/tests/ui/clone_on_copy_mut.rs
deleted file mode 100644
index 5bfa256623b..00000000000
--- a/src/tools/clippy/tests/ui/clone_on_copy_mut.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-pub fn dec_read_dec(i: &mut i32) -> i32 {
-    *i -= 1;
-    let ret = *i;
-    *i -= 1;
-    ret
-}
-
-pub fn minus_1(i: &i32) -> i32 {
-    dec_read_dec(&mut i.clone())
-}
-
-fn main() {
-    let mut i = 10;
-    assert_eq!(minus_1(&i), 9);
-    assert_eq!(i, 10);
-    assert_eq!(dec_read_dec(&mut i), 9);
-    assert_eq!(i, 8);
-}
diff --git a/src/tools/clippy/tests/ui/collapsible_match2.rs b/src/tools/clippy/tests/ui/collapsible_match2.rs
index 8372a212477..542e6948427 100644
--- a/src/tools/clippy/tests/ui/collapsible_match2.rs
+++ b/src/tools/clippy/tests/ui/collapsible_match2.rs
@@ -1,5 +1,10 @@
 #![warn(clippy::collapsible_match)]
-#![allow(clippy::needless_return, clippy::no_effect, clippy::single_match)]
+#![allow(
+    clippy::needless_return,
+    clippy::no_effect,
+    clippy::single_match,
+    clippy::needless_borrow
+)]
 
 fn lint_cases(opt_opt: Option<Option<u32>>, res_opt: Result<Option<u32>, String>) {
     // if guards on outer match
diff --git a/src/tools/clippy/tests/ui/collapsible_match2.stderr b/src/tools/clippy/tests/ui/collapsible_match2.stderr
index c8a445ef369..ffef32d1fde 100644
--- a/src/tools/clippy/tests/ui/collapsible_match2.stderr
+++ b/src/tools/clippy/tests/ui/collapsible_match2.stderr
@@ -1,5 +1,5 @@
 error: unnecessary nested match
-  --> $DIR/collapsible_match2.rs:8:34
+  --> $DIR/collapsible_match2.rs:13:34
    |
 LL |               Ok(val) if make() => match val {
    |  __________________________________^
@@ -10,7 +10,7 @@ LL | |             },
    |
    = note: `-D clippy::collapsible-match` implied by `-D warnings`
 help: the outer pattern can be modified to include the inner pattern
-  --> $DIR/collapsible_match2.rs:8:16
+  --> $DIR/collapsible_match2.rs:13:16
    |
 LL |             Ok(val) if make() => match val {
    |                ^^^ replace this binding
@@ -18,7 +18,7 @@ LL |                 Some(n) => foo(n),
    |                 ^^^^^^^ with this pattern
 
 error: unnecessary nested match
-  --> $DIR/collapsible_match2.rs:15:24
+  --> $DIR/collapsible_match2.rs:20:24
    |
 LL |               Ok(val) => match val {
    |  ________________________^
@@ -28,7 +28,7 @@ LL | |             },
    | |_____________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> $DIR/collapsible_match2.rs:15:16
+  --> $DIR/collapsible_match2.rs:20:16
    |
 LL |             Ok(val) => match val {
    |                ^^^ replace this binding
@@ -36,7 +36,7 @@ LL |                 Some(n) => foo(n),
    |                 ^^^^^^^ with this pattern
 
 error: unnecessary nested match
-  --> $DIR/collapsible_match2.rs:29:29
+  --> $DIR/collapsible_match2.rs:34:29
    |
 LL |                       $pat => match $e {
    |  _____________________________^
@@ -49,7 +49,7 @@ LL |           mac!(res_opt => Ok(val), val => Some(n), foo(n));
    |           ------------------------------------------------- in this macro invocation
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> $DIR/collapsible_match2.rs:41:28
+  --> $DIR/collapsible_match2.rs:46:28
    |
 LL |         mac!(res_opt => Ok(val), val => Some(n), foo(n));
    |                            ^^^          ^^^^^^^ with this pattern
@@ -58,7 +58,7 @@ LL |         mac!(res_opt => Ok(val), val => Some(n), foo(n));
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: unnecessary nested match
-  --> $DIR/collapsible_match2.rs:46:20
+  --> $DIR/collapsible_match2.rs:51:20
    |
 LL |           Some(s) => match *s {
    |  ____________________^
@@ -68,7 +68,7 @@ LL | |         },
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> $DIR/collapsible_match2.rs:46:14
+  --> $DIR/collapsible_match2.rs:51:14
    |
 LL |         Some(s) => match *s {
    |              ^ replace this binding
@@ -76,7 +76,7 @@ LL |             [n] => foo(n),
    |             ^^^ with this pattern
 
 error: unnecessary nested match
-  --> $DIR/collapsible_match2.rs:55:24
+  --> $DIR/collapsible_match2.rs:60:24
    |
 LL |           Some(ref s) => match &*s {
    |  ________________________^
@@ -86,7 +86,7 @@ LL | |         },
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> $DIR/collapsible_match2.rs:55:14
+  --> $DIR/collapsible_match2.rs:60:14
    |
 LL |         Some(ref s) => match &*s {
    |              ^^^^^ replace this binding
diff --git a/src/tools/clippy/tests/ui/crashes/ice-7012.rs b/src/tools/clippy/tests/ui/crashes/ice-7012.rs
new file mode 100644
index 00000000000..60bdbc4f124
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-7012.rs
@@ -0,0 +1,17 @@
+#![allow(clippy::all)]
+
+enum _MyOption {
+    None,
+    Some(()),
+}
+
+impl _MyOption {
+    fn _foo(&self) {
+        match self {
+            &Self::Some(_) => {},
+            _ => {},
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback.rs b/src/tools/clippy/tests/ui/default_numeric_fallback.rs
index 0b3758952ac..43468872db0 100644
--- a/src/tools/clippy/tests/ui/default_numeric_fallback.rs
+++ b/src/tools/clippy/tests/ui/default_numeric_fallback.rs
@@ -3,6 +3,7 @@
 #![allow(clippy::never_loop)]
 #![allow(clippy::no_effect)]
 #![allow(clippy::unnecessary_operation)]
+#![allow(clippy::branches_sharing_code)]
 
 mod basic_expr {
     fn test() {
diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback.stderr b/src/tools/clippy/tests/ui/default_numeric_fallback.stderr
index b31aa4ebcf8..d1c4c8203dd 100644
--- a/src/tools/clippy/tests/ui/default_numeric_fallback.stderr
+++ b/src/tools/clippy/tests/ui/default_numeric_fallback.stderr
@@ -1,5 +1,5 @@
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:10:17
+  --> $DIR/default_numeric_fallback.rs:11:17
    |
 LL |         let x = 22;
    |                 ^^ help: consider adding suffix: `22_i32`
@@ -7,139 +7,139 @@ LL |         let x = 22;
    = note: `-D clippy::default-numeric-fallback` implied by `-D warnings`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:11:18
+  --> $DIR/default_numeric_fallback.rs:12:18
    |
 LL |         let x = [1, 2, 3];
    |                  ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:11:21
+  --> $DIR/default_numeric_fallback.rs:12:21
    |
 LL |         let x = [1, 2, 3];
    |                     ^ help: consider adding suffix: `2_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:11:24
+  --> $DIR/default_numeric_fallback.rs:12:24
    |
 LL |         let x = [1, 2, 3];
    |                        ^ help: consider adding suffix: `3_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:12:28
+  --> $DIR/default_numeric_fallback.rs:13:28
    |
 LL |         let x = if true { (1, 2) } else { (3, 4) };
    |                            ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:12:31
+  --> $DIR/default_numeric_fallback.rs:13:31
    |
 LL |         let x = if true { (1, 2) } else { (3, 4) };
    |                               ^ help: consider adding suffix: `2_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:12:44
+  --> $DIR/default_numeric_fallback.rs:13:44
    |
 LL |         let x = if true { (1, 2) } else { (3, 4) };
    |                                            ^ help: consider adding suffix: `3_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:12:47
+  --> $DIR/default_numeric_fallback.rs:13:47
    |
 LL |         let x = if true { (1, 2) } else { (3, 4) };
    |                                               ^ help: consider adding suffix: `4_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:13:23
+  --> $DIR/default_numeric_fallback.rs:14:23
    |
 LL |         let x = match 1 {
    |                       ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:14:13
+  --> $DIR/default_numeric_fallback.rs:15:13
    |
 LL |             1 => 1,
    |             ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:14:18
+  --> $DIR/default_numeric_fallback.rs:15:18
    |
 LL |             1 => 1,
    |                  ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:15:18
+  --> $DIR/default_numeric_fallback.rs:16:18
    |
 LL |             _ => 2,
    |                  ^ help: consider adding suffix: `2_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:19:17
+  --> $DIR/default_numeric_fallback.rs:20:17
    |
 LL |         let x = 0.12;
    |                 ^^^^ help: consider adding suffix: `0.12_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:37:21
+  --> $DIR/default_numeric_fallback.rs:38:21
    |
 LL |             let y = 1;
    |                     ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:45:21
+  --> $DIR/default_numeric_fallback.rs:46:21
    |
 LL |             let y = 1;
    |                     ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:51:21
+  --> $DIR/default_numeric_fallback.rs:52:21
    |
 LL |             let y = 1;
    |                     ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:63:9
+  --> $DIR/default_numeric_fallback.rs:64:9
    |
 LL |         1
    |         ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:69:27
+  --> $DIR/default_numeric_fallback.rs:70:27
    |
 LL |         let f = || -> _ { 1 };
    |                           ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:73:29
+  --> $DIR/default_numeric_fallback.rs:74:29
    |
 LL |         let f = || -> i32 { 1 };
    |                             ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:87:21
+  --> $DIR/default_numeric_fallback.rs:88:21
    |
 LL |         generic_arg(1);
    |                     ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:90:32
+  --> $DIR/default_numeric_fallback.rs:91:32
    |
 LL |         let x: _ = generic_arg(1);
    |                                ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:108:28
+  --> $DIR/default_numeric_fallback.rs:109:28
    |
 LL |         GenericStruct { x: 1 };
    |                            ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:111:36
+  --> $DIR/default_numeric_fallback.rs:112:36
    |
 LL |         let _ = GenericStruct { x: 1 };
    |                                    ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:131:23
+  --> $DIR/default_numeric_fallback.rs:132:23
    |
 LL |         s.generic_arg(1);
    |                       ^ help: consider adding suffix: `1_i32`
diff --git a/src/tools/clippy/tests/ui/derive.rs b/src/tools/clippy/tests/ui/derive.rs
index 8fcb0e8b28d..4e46bf13991 100644
--- a/src/tools/clippy/tests/ui/derive.rs
+++ b/src/tools/clippy/tests/ui/derive.rs
@@ -35,7 +35,6 @@ impl<'a> Clone for Lt<'a> {
     }
 }
 
-// Ok, `Clone` cannot be derived because of the big array
 #[derive(Copy)]
 struct BigArray {
     a: [u8; 65],
@@ -47,7 +46,6 @@ impl Clone for BigArray {
     }
 }
 
-// Ok, function pointers are not always Clone
 #[derive(Copy)]
 struct FnPtr {
     a: fn() -> !,
@@ -59,7 +57,7 @@ impl Clone for FnPtr {
     }
 }
 
-// Ok, generics
+// Ok, Clone trait impl doesn't have constrained generics.
 #[derive(Copy)]
 struct Generic<T> {
     a: T,
@@ -71,4 +69,21 @@ impl<T> Clone for Generic<T> {
     }
 }
 
+#[derive(Copy)]
+struct Generic2<T>(T);
+impl<T: Clone> Clone for Generic2<T> {
+    fn clone(&self) -> Self {
+        Self(self.0.clone())
+    }
+}
+
+// Ok, Clone trait impl doesn't have constrained generics.
+#[derive(Copy)]
+struct GenericRef<'a, T, U>(T, &'a U);
+impl<T: Clone, U> Clone for GenericRef<'_, T, U> {
+    fn clone(&self) -> Self {
+        Self(self.0.clone(), self.1)
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/derive.stderr b/src/tools/clippy/tests/ui/derive.stderr
index 1328a9b3107..82a70ceecc3 100644
--- a/src/tools/clippy/tests/ui/derive.stderr
+++ b/src/tools/clippy/tests/ui/derive.stderr
@@ -40,7 +40,7 @@ LL | | }
    | |_^
 
 error: you are implementing `Clone` explicitly on a `Copy` type
-  --> $DIR/derive.rs:44:1
+  --> $DIR/derive.rs:43:1
    |
 LL | / impl Clone for BigArray {
 LL | |     fn clone(&self) -> Self {
@@ -50,7 +50,7 @@ LL | | }
    | |_^
    |
 note: consider deriving `Clone` or removing `Copy`
-  --> $DIR/derive.rs:44:1
+  --> $DIR/derive.rs:43:1
    |
 LL | / impl Clone for BigArray {
 LL | |     fn clone(&self) -> Self {
@@ -60,7 +60,7 @@ LL | | }
    | |_^
 
 error: you are implementing `Clone` explicitly on a `Copy` type
-  --> $DIR/derive.rs:56:1
+  --> $DIR/derive.rs:54:1
    |
 LL | / impl Clone for FnPtr {
 LL | |     fn clone(&self) -> Self {
@@ -70,7 +70,7 @@ LL | | }
    | |_^
    |
 note: consider deriving `Clone` or removing `Copy`
-  --> $DIR/derive.rs:56:1
+  --> $DIR/derive.rs:54:1
    |
 LL | / impl Clone for FnPtr {
 LL | |     fn clone(&self) -> Self {
@@ -79,5 +79,25 @@ LL | |     }
 LL | | }
    | |_^
 
-error: aborting due to 4 previous errors
+error: you are implementing `Clone` explicitly on a `Copy` type
+  --> $DIR/derive.rs:74:1
+   |
+LL | / impl<T: Clone> Clone for Generic2<T> {
+LL | |     fn clone(&self) -> Self {
+LL | |         Self(self.0.clone())
+LL | |     }
+LL | | }
+   | |_^
+   |
+note: consider deriving `Clone` or removing `Copy`
+  --> $DIR/derive.rs:74:1
+   |
+LL | / impl<T: Clone> Clone for Generic2<T> {
+LL | |     fn clone(&self) -> Self {
+LL | |         Self(self.0.clone())
+LL | |     }
+LL | | }
+   | |_^
+
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/doc.rs b/src/tools/clippy/tests/ui/doc.rs
index d2c666bd290..c946a047f1b 100644
--- a/src/tools/clippy/tests/ui/doc.rs
+++ b/src/tools/clippy/tests/ui/doc.rs
@@ -1,8 +1,8 @@
 //! This file tests for the `DOC_MARKDOWN` lint.
 
-#![allow(dead_code)]
+#![allow(dead_code, incomplete_features)]
 #![warn(clippy::doc_markdown)]
-#![feature(custom_inner_attributes)]
+#![feature(custom_inner_attributes, const_generics, const_evaluatable_checked, const_option)]
 #![rustfmt::skip]
 
 /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
@@ -202,3 +202,20 @@ fn issue_2343() {}
 /// This should not cause an ICE:
 /// __|_ _|__||_|
 fn pulldown_cmark_crash() {}
+
+// issue #7033 - const_evaluatable_checked ICE
+struct S<T, const N: usize>
+where [(); N.checked_next_power_of_two().unwrap()]: {
+    arr: [T; N.checked_next_power_of_two().unwrap()],
+    n: usize,
+}
+
+impl<T: Copy + Default, const N: usize> S<T, N>
+where [(); N.checked_next_power_of_two().unwrap()]: {
+    fn new() -> Self {
+        Self {
+            arr: [T::default(); N.checked_next_power_of_two().unwrap()],
+            n: 0,
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/escape_analysis.rs b/src/tools/clippy/tests/ui/escape_analysis.rs
index d26f48fc68f..13e2b6c7a2e 100644
--- a/src/tools/clippy/tests/ui/escape_analysis.rs
+++ b/src/tools/clippy/tests/ui/escape_analysis.rs
@@ -101,7 +101,7 @@ fn warn_match() {
     let x = box A;
     match &x {
         // not moved
-        ref y => (),
+        y => (),
     }
 }
 
@@ -111,7 +111,7 @@ fn nowarn_large_array() {
     let x = box [1; 10000];
     match &x {
         // not moved
-        ref y => (),
+        y => (),
     }
 }
 
diff --git a/src/tools/clippy/tests/ui/floating_point_log.fixed b/src/tools/clippy/tests/ui/floating_point_log.fixed
index 7dc7ee94aff..5b487bb8fcf 100644
--- a/src/tools/clippy/tests/ui/floating_point_log.fixed
+++ b/src/tools/clippy/tests/ui/floating_point_log.fixed
@@ -27,7 +27,7 @@ fn check_ln1p() {
     let _ = (x / 2.0).ln_1p();
     let _ = x.powi(3).ln_1p();
     let _ = (x.powi(3) / 2.0).ln_1p();
-    let _ = ((std::f32::consts::E - 1.0)).ln_1p();
+    let _ = (std::f32::consts::E - 1.0).ln_1p();
     let _ = x.ln_1p();
     let _ = x.powi(3).ln_1p();
     let _ = (x + 2.0).ln_1p();
diff --git a/src/tools/clippy/tests/ui/floating_point_log.stderr b/src/tools/clippy/tests/ui/floating_point_log.stderr
index 900dc2b7933..96e5a154441 100644
--- a/src/tools/clippy/tests/ui/floating_point_log.stderr
+++ b/src/tools/clippy/tests/ui/floating_point_log.stderr
@@ -90,7 +90,7 @@ error: ln(1 + x) can be computed more accurately
   --> $DIR/floating_point_log.rs:30:13
    |
 LL |     let _ = (1.0 + (std::f32::consts::E - 1.0)).ln();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `((std::f32::consts::E - 1.0)).ln_1p()`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(std::f32::consts::E - 1.0).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
   --> $DIR/floating_point_log.rs:31:13
diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.stderr b/src/tools/clippy/tests/ui/from_str_radix_10.stderr
index 471bf52a9a7..da5c16f8d01 100644
--- a/src/tools/clippy/tests/ui/from_str_radix_10.stderr
+++ b/src/tools/clippy/tests/ui/from_str_radix_10.stderr
@@ -28,7 +28,7 @@ error: this call to `from_str_radix` can be replaced with a call to `str::parse`
   --> $DIR/from_str_radix_10.rs:32:5
    |
 LL |     u16::from_str_radix(&("10".to_owned() + "5"), 10)?;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(("10".to_owned() + "5")).parse::<u16>()`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `("10".to_owned() + "5").parse::<u16>()`
 
 error: this call to `from_str_radix` can be replaced with a call to `str::parse`
   --> $DIR/from_str_radix_10.rs:33:5
diff --git a/src/tools/clippy/tests/ui/if_same_then_else.rs b/src/tools/clippy/tests/ui/if_same_then_else.rs
index 9c5fe02f751..ef956745500 100644
--- a/src/tools/clippy/tests/ui/if_same_then_else.rs
+++ b/src/tools/clippy/tests/ui/if_same_then_else.rs
@@ -5,7 +5,8 @@
     clippy::never_loop,
     clippy::no_effect,
     clippy::unused_unit,
-    clippy::zero_divided_by_zero
+    clippy::zero_divided_by_zero,
+    clippy::branches_sharing_code
 )]
 
 struct Foo {
diff --git a/src/tools/clippy/tests/ui/if_same_then_else.stderr b/src/tools/clippy/tests/ui/if_same_then_else.stderr
index d9fdf06fa8b..2f38052fc20 100644
--- a/src/tools/clippy/tests/ui/if_same_then_else.stderr
+++ b/src/tools/clippy/tests/ui/if_same_then_else.stderr
@@ -1,111 +1,111 @@
 error: this `if` has identical blocks
-  --> $DIR/if_same_then_else.rs:28:12
+  --> $DIR/if_same_then_else.rs:21:13
    |
-LL |       } else {
-   |  ____________^
-LL | |         //~ ERROR same body as `if` block
+LL |       if true {
+   |  _____________^
 LL | |         Foo { bar: 42 };
 LL | |         0..10;
+LL | |         ..;
 ...  |
 LL | |         foo();
-LL | |     }
+LL | |     } else {
    | |_____^
    |
    = note: `-D clippy::if-same-then-else` implied by `-D warnings`
 note: same as this
-  --> $DIR/if_same_then_else.rs:20:13
+  --> $DIR/if_same_then_else.rs:29:12
    |
-LL |       if true {
-   |  _____________^
+LL |       } else {
+   |  ____________^
+LL | |         //~ ERROR same body as `if` block
 LL | |         Foo { bar: 42 };
 LL | |         0..10;
-LL | |         ..;
 ...  |
 LL | |         foo();
-LL | |     } else {
+LL | |     }
    | |_____^
 
 error: this `if` has identical blocks
-  --> $DIR/if_same_then_else.rs:66:12
-   |
-LL |       } else {
-   |  ____________^
-LL | |         //~ ERROR same body as `if` block
-LL | |         0.0
-LL | |     };
-   | |_____^
-   |
-note: same as this
-  --> $DIR/if_same_then_else.rs:64:21
+  --> $DIR/if_same_then_else.rs:65:21
    |
 LL |       let _ = if true {
    |  _____________________^
 LL | |         0.0
 LL | |     } else {
    | |_____^
-
-error: this `if` has identical blocks
-  --> $DIR/if_same_then_else.rs:73:12
+   |
+note: same as this
+  --> $DIR/if_same_then_else.rs:67:12
    |
 LL |       } else {
    |  ____________^
 LL | |         //~ ERROR same body as `if` block
-LL | |         -0.0
+LL | |         0.0
 LL | |     };
    | |_____^
-   |
-note: same as this
-  --> $DIR/if_same_then_else.rs:71:21
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else.rs:72:21
    |
 LL |       let _ = if true {
    |  _____________________^
 LL | |         -0.0
 LL | |     } else {
    | |_____^
-
-error: this `if` has identical blocks
-  --> $DIR/if_same_then_else.rs:89:12
+   |
+note: same as this
+  --> $DIR/if_same_then_else.rs:74:12
    |
 LL |       } else {
    |  ____________^
 LL | |         //~ ERROR same body as `if` block
-LL | |         42
+LL | |         -0.0
 LL | |     };
    | |_____^
-   |
-note: same as this
-  --> $DIR/if_same_then_else.rs:87:21
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else.rs:88:21
    |
 LL |       let _ = if true {
    |  _____________________^
 LL | |         42
 LL | |     } else {
    | |_____^
-
-error: this `if` has identical blocks
-  --> $DIR/if_same_then_else.rs:101:12
+   |
+note: same as this
+  --> $DIR/if_same_then_else.rs:90:12
    |
 LL |       } else {
    |  ____________^
 LL | |         //~ ERROR same body as `if` block
+LL | |         42
+LL | |     };
+   | |_____^
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else.rs:95:13
+   |
+LL |       if true {
+   |  _____________^
 LL | |         let bar = if true { 42 } else { 43 };
 LL | |
+LL | |         while foo() {
 ...  |
 LL | |         bar + 1;
-LL | |     }
+LL | |     } else {
    | |_____^
    |
 note: same as this
-  --> $DIR/if_same_then_else.rs:94:13
+  --> $DIR/if_same_then_else.rs:102:12
    |
-LL |       if true {
-   |  _____________^
+LL |       } else {
+   |  ____________^
+LL | |         //~ ERROR same body as `if` block
 LL | |         let bar = if true { 42 } else { 43 };
 LL | |
-LL | |         while foo() {
 ...  |
 LL | |         bar + 1;
-LL | |     } else {
+LL | |     }
    | |_____^
 
 error: aborting due to 5 previous errors
diff --git a/src/tools/clippy/tests/ui/if_same_then_else2.rs b/src/tools/clippy/tests/ui/if_same_then_else2.rs
index a2ff1b741ca..e4dc5b647df 100644
--- a/src/tools/clippy/tests/ui/if_same_then_else2.rs
+++ b/src/tools/clippy/tests/ui/if_same_then_else2.rs
@@ -5,7 +5,8 @@
     clippy::collapsible_if,
     clippy::ifs_same_cond,
     clippy::needless_return,
-    clippy::single_element_loop
+    clippy::single_element_loop,
+    clippy::branches_sharing_code
 )]
 
 fn if_same_then_else2() -> Result<&'static str, ()> {
diff --git a/src/tools/clippy/tests/ui/if_same_then_else2.stderr b/src/tools/clippy/tests/ui/if_same_then_else2.stderr
index 454322d8aac..6524be0af85 100644
--- a/src/tools/clippy/tests/ui/if_same_then_else2.stderr
+++ b/src/tools/clippy/tests/ui/if_same_then_else2.stderr
@@ -1,19 +1,5 @@
 error: this `if` has identical blocks
-  --> $DIR/if_same_then_else2.rs:21:12
-   |
-LL |       } else {
-   |  ____________^
-LL | |         //~ ERROR same body as `if` block
-LL | |         for _ in &[42] {
-LL | |             let bar: &Option<_> = &Some::<u8>(42);
-...  |
-LL | |         }
-LL | |     }
-   | |_____^
-   |
-   = note: `-D clippy::if-same-then-else` implied by `-D warnings`
-note: same as this
-  --> $DIR/if_same_then_else2.rs:12:13
+  --> $DIR/if_same_then_else2.rs:13:13
    |
 LL |       if true {
    |  _____________^
@@ -24,95 +10,99 @@ LL | |             if foo.is_some() {
 LL | |         }
 LL | |     } else {
    | |_____^
-
-error: this `if` has identical blocks
-  --> $DIR/if_same_then_else2.rs:35:12
+   |
+   = note: `-D clippy::if-same-then-else` implied by `-D warnings`
+note: same as this
+  --> $DIR/if_same_then_else2.rs:22:12
    |
 LL |       } else {
    |  ____________^
 LL | |         //~ ERROR same body as `if` block
-LL | |         if let Some(a) = Some(42) {}
+LL | |         for _ in &[42] {
+LL | |             let bar: &Option<_> = &Some::<u8>(42);
+...  |
+LL | |         }
 LL | |     }
    | |_____^
-   |
-note: same as this
-  --> $DIR/if_same_then_else2.rs:33:13
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else2.rs:34:13
    |
 LL |       if true {
    |  _____________^
 LL | |         if let Some(a) = Some(42) {}
 LL | |     } else {
    | |_____^
-
-error: this `if` has identical blocks
-  --> $DIR/if_same_then_else2.rs:42:12
+   |
+note: same as this
+  --> $DIR/if_same_then_else2.rs:36:12
    |
 LL |       } else {
    |  ____________^
 LL | |         //~ ERROR same body as `if` block
-LL | |         if let (1, .., 3) = (1, 2, 3) {}
+LL | |         if let Some(a) = Some(42) {}
 LL | |     }
    | |_____^
-   |
-note: same as this
-  --> $DIR/if_same_then_else2.rs:40:13
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else2.rs:41:13
    |
 LL |       if true {
    |  _____________^
 LL | |         if let (1, .., 3) = (1, 2, 3) {}
 LL | |     } else {
    | |_____^
-
-error: this `if` has identical blocks
-  --> $DIR/if_same_then_else2.rs:92:12
+   |
+note: same as this
+  --> $DIR/if_same_then_else2.rs:43:12
    |
 LL |       } else {
    |  ____________^
 LL | |         //~ ERROR same body as `if` block
-LL | |         f32::NAN
-LL | |     };
+LL | |         if let (1, .., 3) = (1, 2, 3) {}
+LL | |     }
    | |_____^
-   |
-note: same as this
-  --> $DIR/if_same_then_else2.rs:90:21
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else2.rs:91:21
    |
 LL |       let _ = if true {
    |  _____________________^
 LL | |         f32::NAN
 LL | |     } else {
    | |_____^
-
-error: this `if` has identical blocks
-  --> $DIR/if_same_then_else2.rs:99:12
+   |
+note: same as this
+  --> $DIR/if_same_then_else2.rs:93:12
    |
 LL |       } else {
    |  ____________^
 LL | |         //~ ERROR same body as `if` block
-LL | |         Ok("foo")?;
-LL | |     }
+LL | |         f32::NAN
+LL | |     };
    | |_____^
-   |
-note: same as this
-  --> $DIR/if_same_then_else2.rs:97:13
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else2.rs:98:13
    |
 LL |       if true {
    |  _____________^
 LL | |         Ok("foo")?;
 LL | |     } else {
    | |_____^
-
-error: this `if` has identical blocks
-  --> $DIR/if_same_then_else2.rs:124:12
+   |
+note: same as this
+  --> $DIR/if_same_then_else2.rs:100:12
    |
 LL |       } else {
    |  ____________^
-LL | |         let foo = "";
-LL | |         return Ok(&foo[0..]);
+LL | |         //~ ERROR same body as `if` block
+LL | |         Ok("foo")?;
 LL | |     }
    | |_____^
-   |
-note: same as this
-  --> $DIR/if_same_then_else2.rs:121:20
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else2.rs:122:20
    |
 LL |       } else if true {
    |  ____________________^
@@ -120,6 +110,16 @@ LL | |         let foo = "";
 LL | |         return Ok(&foo[0..]);
 LL | |     } else {
    | |_____^
+   |
+note: same as this
+  --> $DIR/if_same_then_else2.rs:125:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         let foo = "";
+LL | |         return Ok(&foo[0..]);
+LL | |     }
+   | |_____^
 
 error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/implicit_clone.rs b/src/tools/clippy/tests/ui/implicit_clone.rs
index 19101522163..cef71cf79d7 100644
--- a/src/tools/clippy/tests/ui/implicit_clone.rs
+++ b/src/tools/clippy/tests/ui/implicit_clone.rs
@@ -66,7 +66,7 @@ fn main() {
     let _ = vec.to_vec();
 
     let vec_ref = &vec;
-    let _ = return_owned_from_slice(&vec_ref);
+    let _ = return_owned_from_slice(vec_ref);
     let _ = vec_ref.to_owned();
     let _ = vec_ref.to_vec();
 
diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.fixed b/src/tools/clippy/tests/ui/into_iter_on_ref.fixed
index 7f92d0dbdc9..b77f17944d8 100644
--- a/src/tools/clippy/tests/ui/into_iter_on_ref.fixed
+++ b/src/tools/clippy/tests/ui/into_iter_on_ref.fixed
@@ -1,5 +1,5 @@
 // run-rustfix
-#![allow(clippy::useless_vec)]
+#![allow(clippy::useless_vec, clippy::needless_borrow)]
 #![warn(clippy::into_iter_on_ref)]
 
 struct X;
diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.rs b/src/tools/clippy/tests/ui/into_iter_on_ref.rs
index 416056d3fdb..3854bb05af8 100644
--- a/src/tools/clippy/tests/ui/into_iter_on_ref.rs
+++ b/src/tools/clippy/tests/ui/into_iter_on_ref.rs
@@ -1,5 +1,5 @@
 // run-rustfix
-#![allow(clippy::useless_vec)]
+#![allow(clippy::useless_vec, clippy::needless_borrow)]
 #![warn(clippy::into_iter_on_ref)]
 
 struct X;
diff --git a/src/tools/clippy/tests/ui/len_without_is_empty.rs b/src/tools/clippy/tests/ui/len_without_is_empty.rs
index 6b3636a482e..b9d66347c27 100644
--- a/src/tools/clippy/tests/ui/len_without_is_empty.rs
+++ b/src/tools/clippy/tests/ui/len_without_is_empty.rs
@@ -1,3 +1,5 @@
+// edition:2018
+
 #![warn(clippy::len_without_is_empty)]
 #![allow(dead_code, unused)]
 
@@ -172,9 +174,9 @@ pub trait DependsOnFoo: Foo {
     fn len(&mut self) -> usize;
 }
 
+// issue #1562
 pub struct MultipleImpls;
 
-// issue #1562
 impl MultipleImpls {
     pub fn len(&self) -> usize {
         1
@@ -187,4 +189,99 @@ impl MultipleImpls {
     }
 }
 
+// issue #6958
+pub struct OptionalLen;
+
+impl OptionalLen {
+    pub fn len(&self) -> Option<usize> {
+        Some(0)
+    }
+
+    pub fn is_empty(&self) -> Option<bool> {
+        Some(true)
+    }
+}
+
+pub struct OptionalLen2;
+impl OptionalLen2 {
+    pub fn len(&self) -> Option<usize> {
+        Some(0)
+    }
+
+    pub fn is_empty(&self) -> bool {
+        true
+    }
+}
+
+pub struct OptionalLen3;
+impl OptionalLen3 {
+    pub fn len(&self) -> usize {
+        0
+    }
+
+    // should lint, len is not an option
+    pub fn is_empty(&self) -> Option<bool> {
+        None
+    }
+}
+
+pub struct ResultLen;
+impl ResultLen {
+    pub fn len(&self) -> Result<usize, ()> {
+        Ok(0)
+    }
+
+    // Differing result types
+    pub fn is_empty(&self) -> Option<bool> {
+        Some(true)
+    }
+}
+
+pub struct ResultLen2;
+impl ResultLen2 {
+    pub fn len(&self) -> Result<usize, ()> {
+        Ok(0)
+    }
+
+    pub fn is_empty(&self) -> Result<bool, ()> {
+        Ok(true)
+    }
+}
+
+pub struct ResultLen3;
+impl ResultLen3 {
+    pub fn len(&self) -> Result<usize, ()> {
+        Ok(0)
+    }
+
+    // Non-fallible result is ok.
+    pub fn is_empty(&self) -> bool {
+        true
+    }
+}
+
+pub struct OddLenSig;
+impl OddLenSig {
+    // don't lint
+    pub fn len(&self) -> bool {
+        true
+    }
+}
+
+// issue #6958
+pub struct AsyncLen;
+impl AsyncLen {
+    async fn async_task(&self) -> bool {
+        true
+    }
+
+    pub async fn len(&self) -> usize {
+        if self.async_task().await { 0 } else { 1 }
+    }
+
+    pub async fn is_empty(&self) -> bool {
+        self.len().await == 0
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/len_without_is_empty.stderr b/src/tools/clippy/tests/ui/len_without_is_empty.stderr
index f106506faf4..3282709bcd6 100644
--- a/src/tools/clippy/tests/ui/len_without_is_empty.stderr
+++ b/src/tools/clippy/tests/ui/len_without_is_empty.stderr
@@ -1,5 +1,5 @@
 error: struct `PubOne` has a public `len` method, but no `is_empty` method
-  --> $DIR/len_without_is_empty.rs:7:5
+  --> $DIR/len_without_is_empty.rs:9:5
    |
 LL |     pub fn len(&self) -> isize {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     pub fn len(&self) -> isize {
    = note: `-D clippy::len-without-is-empty` implied by `-D warnings`
 
 error: trait `PubTraitsToo` has a `len` method but no (possibly inherited) `is_empty` method
-  --> $DIR/len_without_is_empty.rs:55:1
+  --> $DIR/len_without_is_empty.rs:57:1
    |
 LL | / pub trait PubTraitsToo {
 LL | |     fn len(&self) -> isize;
@@ -15,50 +15,109 @@ LL | | }
    | |_^
 
 error: struct `HasIsEmpty` has a public `len` method, but a private `is_empty` method
-  --> $DIR/len_without_is_empty.rs:68:5
+  --> $DIR/len_without_is_empty.rs:70:5
    |
 LL |     pub fn len(&self) -> isize {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: `is_empty` defined here
-  --> $DIR/len_without_is_empty.rs:72:5
+  --> $DIR/len_without_is_empty.rs:74:5
    |
 LL |     fn is_empty(&self) -> bool {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: struct `HasWrongIsEmpty` has a public `len` method, but the `is_empty` method has an unexpected signature
-  --> $DIR/len_without_is_empty.rs:80:5
+  --> $DIR/len_without_is_empty.rs:82:5
    |
 LL |     pub fn len(&self) -> isize {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: `is_empty` defined here
-  --> $DIR/len_without_is_empty.rs:84:5
+  --> $DIR/len_without_is_empty.rs:86:5
    |
 LL |     pub fn is_empty(&self, x: u32) -> bool {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: expected signature: `(&self) -> bool`
 
 error: struct `MismatchedSelf` has a public `len` method, but the `is_empty` method has an unexpected signature
-  --> $DIR/len_without_is_empty.rs:92:5
+  --> $DIR/len_without_is_empty.rs:94:5
    |
 LL |     pub fn len(self) -> isize {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: `is_empty` defined here
-  --> $DIR/len_without_is_empty.rs:96:5
+  --> $DIR/len_without_is_empty.rs:98:5
    |
 LL |     pub fn is_empty(&self) -> bool {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: expected signature: `(self) -> bool`
 
 error: trait `DependsOnFoo` has a `len` method but no (possibly inherited) `is_empty` method
-  --> $DIR/len_without_is_empty.rs:171:1
+  --> $DIR/len_without_is_empty.rs:173:1
    |
 LL | / pub trait DependsOnFoo: Foo {
 LL | |     fn len(&mut self) -> usize;
 LL | | }
    | |_^
 
-error: aborting due to 6 previous errors
+error: struct `OptionalLen3` has a public `len` method, but the `is_empty` method has an unexpected signature
+  --> $DIR/len_without_is_empty.rs:218:5
+   |
+LL |     pub fn len(&self) -> usize {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `is_empty` defined here
+  --> $DIR/len_without_is_empty.rs:223:5
+   |
+LL |     pub fn is_empty(&self) -> Option<bool> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: expected signature: `(&self) -> bool`
+
+error: struct `ResultLen` has a public `len` method, but the `is_empty` method has an unexpected signature
+  --> $DIR/len_without_is_empty.rs:230:5
+   |
+LL |     pub fn len(&self) -> Result<usize, ()> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `is_empty` defined here
+  --> $DIR/len_without_is_empty.rs:235:5
+   |
+LL |     pub fn is_empty(&self) -> Option<bool> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: expected signature: `(&self) -> bool` or `(&self) -> Result<bool>
+
+error: this returns a `Result<_, ()>`
+  --> $DIR/len_without_is_empty.rs:230:5
+   |
+LL |     pub fn len(&self) -> Result<usize, ()> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::result-unit-err` implied by `-D warnings`
+   = help: use a custom `Error` type instead
+
+error: this returns a `Result<_, ()>`
+  --> $DIR/len_without_is_empty.rs:242:5
+   |
+LL |     pub fn len(&self) -> Result<usize, ()> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use a custom `Error` type instead
+
+error: this returns a `Result<_, ()>`
+  --> $DIR/len_without_is_empty.rs:246:5
+   |
+LL |     pub fn is_empty(&self) -> Result<bool, ()> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use a custom `Error` type instead
+
+error: this returns a `Result<_, ()>`
+  --> $DIR/len_without_is_empty.rs:253:5
+   |
+LL |     pub fn len(&self) -> Result<usize, ()> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use a custom `Error` type instead
+
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/let_if_seq.rs b/src/tools/clippy/tests/ui/let_if_seq.rs
index 32a67f181df..2d8f3c2f0e7 100644
--- a/src/tools/clippy/tests/ui/let_if_seq.rs
+++ b/src/tools/clippy/tests/ui/let_if_seq.rs
@@ -2,7 +2,8 @@
     unused_variables,
     unused_assignments,
     clippy::similar_names,
-    clippy::blacklisted_name
+    clippy::blacklisted_name,
+    clippy::branches_sharing_code
 )]
 #![warn(clippy::useless_let_if_seq)]
 
diff --git a/src/tools/clippy/tests/ui/let_if_seq.stderr b/src/tools/clippy/tests/ui/let_if_seq.stderr
index 7de560c7348..9cf2e10a5ee 100644
--- a/src/tools/clippy/tests/ui/let_if_seq.stderr
+++ b/src/tools/clippy/tests/ui/let_if_seq.stderr
@@ -1,5 +1,5 @@
 error: `if _ { .. } else { .. }` is an expression
-  --> $DIR/let_if_seq.rs:64:5
+  --> $DIR/let_if_seq.rs:65:5
    |
 LL | /     let mut foo = 0;
 LL | |     if f() {
@@ -11,7 +11,7 @@ LL | |     }
    = note: you might not need `mut` at all
 
 error: `if _ { .. } else { .. }` is an expression
-  --> $DIR/let_if_seq.rs:69:5
+  --> $DIR/let_if_seq.rs:70:5
    |
 LL | /     let mut bar = 0;
 LL | |     if f() {
@@ -25,7 +25,7 @@ LL | |     }
    = note: you might not need `mut` at all
 
 error: `if _ { .. } else { .. }` is an expression
-  --> $DIR/let_if_seq.rs:77:5
+  --> $DIR/let_if_seq.rs:78:5
    |
 LL | /     let quz;
 LL | |     if f() {
@@ -36,7 +36,7 @@ LL | |     }
    | |_____^ help: it is more idiomatic to write: `let quz = if f() { 42 } else { 0 };`
 
 error: `if _ { .. } else { .. }` is an expression
-  --> $DIR/let_if_seq.rs:106:5
+  --> $DIR/let_if_seq.rs:107:5
    |
 LL | /     let mut baz = 0;
 LL | |     if f() {
diff --git a/src/tools/clippy/tests/ui/dlist.rs b/src/tools/clippy/tests/ui/linkedlist.rs
index 2940d2d2901..2c3b25cd45e 100644
--- a/src/tools/clippy/tests/ui/dlist.rs
+++ b/src/tools/clippy/tests/ui/linkedlist.rs
@@ -5,6 +5,9 @@
 extern crate alloc;
 use alloc::collections::linked_list::LinkedList;
 
+const C: LinkedList<i32> = LinkedList::new();
+static S: LinkedList<i32> = LinkedList::new();
+
 trait Foo {
     type Baz = LinkedList<u8>;
     fn foo(_: LinkedList<u8>);
diff --git a/src/tools/clippy/tests/ui/dlist.stderr b/src/tools/clippy/tests/ui/linkedlist.stderr
index 234db33ba12..38ae71714d6 100644
--- a/src/tools/clippy/tests/ui/dlist.stderr
+++ b/src/tools/clippy/tests/ui/linkedlist.stderr
@@ -1,14 +1,30 @@
 error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure?
-  --> $DIR/dlist.rs:9:16
+  --> $DIR/linkedlist.rs:8:10
+   |
+LL | const C: LinkedList<i32> = LinkedList::new();
+   |          ^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::linkedlist` implied by `-D warnings`
+   = help: a `VecDeque` might work
+
+error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure?
+  --> $DIR/linkedlist.rs:9:11
+   |
+LL | static S: LinkedList<i32> = LinkedList::new();
+   |           ^^^^^^^^^^^^^^^
+   |
+   = help: a `VecDeque` might work
+
+error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure?
+  --> $DIR/linkedlist.rs:12:16
    |
 LL |     type Baz = LinkedList<u8>;
    |                ^^^^^^^^^^^^^^
    |
-   = note: `-D clippy::linkedlist` implied by `-D warnings`
    = help: a `VecDeque` might work
 
 error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure?
-  --> $DIR/dlist.rs:10:15
+  --> $DIR/linkedlist.rs:13:15
    |
 LL |     fn foo(_: LinkedList<u8>);
    |               ^^^^^^^^^^^^^^
@@ -16,7 +32,7 @@ LL |     fn foo(_: LinkedList<u8>);
    = help: a `VecDeque` might work
 
 error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure?
-  --> $DIR/dlist.rs:11:23
+  --> $DIR/linkedlist.rs:14:23
    |
 LL |     const BAR: Option<LinkedList<u8>>;
    |                       ^^^^^^^^^^^^^^
@@ -24,7 +40,7 @@ LL |     const BAR: Option<LinkedList<u8>>;
    = help: a `VecDeque` might work
 
 error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure?
-  --> $DIR/dlist.rs:22:15
+  --> $DIR/linkedlist.rs:25:15
    |
 LL |     fn foo(_: LinkedList<u8>) {}
    |               ^^^^^^^^^^^^^^
@@ -32,7 +48,7 @@ LL |     fn foo(_: LinkedList<u8>) {}
    = help: a `VecDeque` might work
 
 error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure?
-  --> $DIR/dlist.rs:25:39
+  --> $DIR/linkedlist.rs:28:39
    |
 LL | pub fn test(my_favourite_linked_list: LinkedList<u8>) {
    |                                       ^^^^^^^^^^^^^^
@@ -40,12 +56,12 @@ LL | pub fn test(my_favourite_linked_list: LinkedList<u8>) {
    = help: a `VecDeque` might work
 
 error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure?
-  --> $DIR/dlist.rs:29:29
+  --> $DIR/linkedlist.rs:32:29
    |
 LL | pub fn test_ret() -> Option<LinkedList<u8>> {
    |                             ^^^^^^^^^^^^^^
    |
    = help: a `VecDeque` might work
 
-error: aborting due to 6 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_map_option.fixed b/src/tools/clippy/tests/ui/manual_map_option.fixed
index acb6a580ceb..ee015845777 100644
--- a/src/tools/clippy/tests/ui/manual_map_option.fixed
+++ b/src/tools/clippy/tests/ui/manual_map_option.fixed
@@ -7,6 +7,7 @@
     clippy::map_identity,
     clippy::unit_arg,
     clippy::match_ref_pats,
+    clippy::redundant_pattern_matching,
     dead_code
 )]
 
@@ -130,7 +131,19 @@ fn main() {
     }
 
     // #6847
-    if Some(0).is_some() {
+    if let Some(_) = Some(0) {
         Some(0)
     } else { Some(0).map(|x| x + 1) };
+
+    if true {
+        Some(0)
+    } else { Some(0).map(|x| x + 1) };
+
+    // #6967
+    const fn f4() {
+        match Some(0) {
+            Some(x) => Some(x + 1),
+            None => None,
+        };
+    }
 }
diff --git a/src/tools/clippy/tests/ui/manual_map_option.rs b/src/tools/clippy/tests/ui/manual_map_option.rs
index 3299e617707..29509bddfd9 100644
--- a/src/tools/clippy/tests/ui/manual_map_option.rs
+++ b/src/tools/clippy/tests/ui/manual_map_option.rs
@@ -7,6 +7,7 @@
     clippy::map_identity,
     clippy::unit_arg,
     clippy::match_ref_pats,
+    clippy::redundant_pattern_matching,
     dead_code
 )]
 
@@ -195,4 +196,20 @@ fn main() {
     } else {
         None
     };
+
+    if true {
+        Some(0)
+    } else if let Some(x) = Some(0) {
+        Some(x + 1)
+    } else {
+        None
+    };
+
+    // #6967
+    const fn f4() {
+        match Some(0) {
+            Some(x) => Some(x + 1),
+            None => None,
+        };
+    }
 }
diff --git a/src/tools/clippy/tests/ui/manual_map_option.stderr b/src/tools/clippy/tests/ui/manual_map_option.stderr
index 048ccfb9582..cdc2c0e62a9 100644
--- a/src/tools/clippy/tests/ui/manual_map_option.stderr
+++ b/src/tools/clippy/tests/ui/manual_map_option.stderr
@@ -1,5 +1,5 @@
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:14:5
+  --> $DIR/manual_map_option.rs:15:5
    |
 LL | /     match Some(0) {
 LL | |         Some(_) => Some(2),
@@ -10,7 +10,7 @@ LL | |     };
    = note: `-D clippy::manual-map` implied by `-D warnings`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:19:5
+  --> $DIR/manual_map_option.rs:20:5
    |
 LL | /     match Some(0) {
 LL | |         Some(x) => Some(x + 1),
@@ -19,7 +19,7 @@ LL | |     };
    | |_____^ help: try this: `Some(0).map(|x| x + 1)`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:24:5
+  --> $DIR/manual_map_option.rs:25:5
    |
 LL | /     match Some("") {
 LL | |         Some(x) => Some(x.is_empty()),
@@ -28,7 +28,7 @@ LL | |     };
    | |_____^ help: try this: `Some("").map(|x| x.is_empty())`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:29:5
+  --> $DIR/manual_map_option.rs:30:5
    |
 LL | /     if let Some(x) = Some(0) {
 LL | |         Some(!x)
@@ -38,7 +38,7 @@ LL | |     };
    | |_____^ help: try this: `Some(0).map(|x| !x)`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:36:5
+  --> $DIR/manual_map_option.rs:37:5
    |
 LL | /     match Some(0) {
 LL | |         Some(x) => { Some(std::convert::identity(x)) }
@@ -47,7 +47,7 @@ LL | |     };
    | |_____^ help: try this: `Some(0).map(std::convert::identity)`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:41:5
+  --> $DIR/manual_map_option.rs:42:5
    |
 LL | /     match Some(&String::new()) {
 LL | |         Some(x) => Some(str::len(x)),
@@ -56,7 +56,7 @@ LL | |     };
    | |_____^ help: try this: `Some(&String::new()).map(|x| str::len(x))`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:51:5
+  --> $DIR/manual_map_option.rs:52:5
    |
 LL | /     match &Some([0, 1]) {
 LL | |         Some(x) => Some(x[0]),
@@ -65,7 +65,7 @@ LL | |     };
    | |_____^ help: try this: `Some([0, 1]).as_ref().map(|x| x[0])`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:56:5
+  --> $DIR/manual_map_option.rs:57:5
    |
 LL | /     match &Some(0) {
 LL | |         &Some(x) => Some(x * 2),
@@ -74,7 +74,7 @@ LL | |     };
    | |_____^ help: try this: `Some(0).map(|x| x * 2)`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:61:5
+  --> $DIR/manual_map_option.rs:62:5
    |
 LL | /     match Some(String::new()) {
 LL | |         Some(ref x) => Some(x.is_empty()),
@@ -83,7 +83,7 @@ LL | |     };
    | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.is_empty())`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:66:5
+  --> $DIR/manual_map_option.rs:67:5
    |
 LL | /     match &&Some(String::new()) {
 LL | |         Some(x) => Some(x.len()),
@@ -92,7 +92,7 @@ LL | |     };
    | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.len())`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:71:5
+  --> $DIR/manual_map_option.rs:72:5
    |
 LL | /     match &&Some(0) {
 LL | |         &&Some(x) => Some(x + x),
@@ -101,7 +101,7 @@ LL | |     };
    | |_____^ help: try this: `Some(0).map(|x| x + x)`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:84:9
+  --> $DIR/manual_map_option.rs:85:9
    |
 LL | /         match &mut Some(String::new()) {
 LL | |             Some(x) => Some(x.push_str("")),
@@ -110,7 +110,7 @@ LL | |         };
    | |_________^ help: try this: `Some(String::new()).as_mut().map(|x| x.push_str(""))`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:90:5
+  --> $DIR/manual_map_option.rs:91:5
    |
 LL | /     match &mut Some(String::new()) {
 LL | |         Some(ref x) => Some(x.len()),
@@ -119,7 +119,7 @@ LL | |     };
    | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.len())`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:95:5
+  --> $DIR/manual_map_option.rs:96:5
    |
 LL | /     match &mut &Some(String::new()) {
 LL | |         Some(x) => Some(x.is_empty()),
@@ -128,7 +128,7 @@ LL | |     };
    | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.is_empty())`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:100:5
+  --> $DIR/manual_map_option.rs:101:5
    |
 LL | /     match Some((0, 1, 2)) {
 LL | |         Some((x, y, z)) => Some(x + y + z),
@@ -137,7 +137,7 @@ LL | |     };
    | |_____^ help: try this: `Some((0, 1, 2)).map(|(x, y, z)| x + y + z)`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:105:5
+  --> $DIR/manual_map_option.rs:106:5
    |
 LL | /     match Some([1, 2, 3]) {
 LL | |         Some([first, ..]) => Some(first),
@@ -146,7 +146,7 @@ LL | |     };
    | |_____^ help: try this: `Some([1, 2, 3]).map(|[first, ..]| first)`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:110:5
+  --> $DIR/manual_map_option.rs:111:5
    |
 LL | /     match &Some((String::new(), "test")) {
 LL | |         Some((x, y)) => Some((y, x)),
@@ -155,7 +155,7 @@ LL | |     };
    | |_____^ help: try this: `Some((String::new(), "test")).as_ref().map(|(x, y)| (y, x))`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:168:5
+  --> $DIR/manual_map_option.rs:169:5
    |
 LL | /     match Some(0) {
 LL | |         Some(x) => Some(vec![x]),
@@ -164,7 +164,7 @@ LL | |     };
    | |_____^ help: try this: `Some(0).map(|x| vec![x])`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:173:5
+  --> $DIR/manual_map_option.rs:174:5
    |
 LL | /     match option_env!("") {
 LL | |         Some(x) => Some(String::from(x)),
@@ -172,16 +172,19 @@ LL | |         None => None,
 LL | |     };
    | |_____^ help: try this: `option_env!("").map(String::from)`
 
-error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/manual_map_option.rs:191:12
-   |
-LL |     if let Some(_) = Some(0) {
-   |     -------^^^^^^^---------- help: try this: `if Some(0).is_some()`
+error: manual implementation of `Option::map`
+  --> $DIR/manual_map_option.rs:194:12
    |
-   = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
+LL |       } else if let Some(x) = Some(0) {
+   |  ____________^
+LL | |         Some(x + 1)
+LL | |     } else {
+LL | |         None
+LL | |     };
+   | |_____^ help: try this: `{ Some(0).map(|x| x + 1) }`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:193:12
+  --> $DIR/manual_map_option.rs:202:12
    |
 LL |       } else if let Some(x) = Some(0) {
    |  ____________^
diff --git a/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.stderr b/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.stderr
index 2547b19f5d1..a2f2dfce168 100644
--- a/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.stderr
+++ b/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.stderr
@@ -43,7 +43,7 @@ LL | /     for i in 3..(3 + src.len()) {
 LL | |         dst[i] = src[count];
 LL | |         count += 1;
 LL | |     }
-   | |_____^ help: try replacing the loop by: `dst[3..((3 + src.len()))].clone_from_slice(&src[..((3 + src.len()) - 3)]);`
+   | |_____^ help: try replacing the loop by: `dst[3..(3 + src.len())].clone_from_slice(&src[..((3 + src.len()) - 3)]);`
 
 error: it looks like you're manually copying between slices
   --> $DIR/with_loop_counters.rs:35:5
diff --git a/src/tools/clippy/tests/ui/match_ref_pats.stderr b/src/tools/clippy/tests/ui/match_ref_pats.stderr
index 52cb4a14b72..67474e65cde 100644
--- a/src/tools/clippy/tests/ui/match_ref_pats.stderr
+++ b/src/tools/clippy/tests/ui/match_ref_pats.stderr
@@ -46,6 +46,14 @@ LL |         Some(v) => println!("{:?}", v),
 LL |         None => println!("none"),
    |
 
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/match_ref_pats.rs:35:12
+   |
+LL |     if let &None = a {
+   |     -------^^^^^---- help: try this: `if a.is_none()`
+   |
+   = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
+
 error: you don't need to add `&` to all patterns
   --> $DIR/match_ref_pats.rs:35:5
    |
@@ -59,6 +67,12 @@ help: instead of prefixing all patterns with `&`, you can dereference the expres
 LL |     if let None = *a {
    |            ^^^^   ^^
 
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/match_ref_pats.rs:40:12
+   |
+LL |     if let &None = &b {
+   |     -------^^^^^----- help: try this: `if b.is_none()`
+
 error: you don't need to add `&` to both the expression and the patterns
   --> $DIR/match_ref_pats.rs:40:5
    |
@@ -87,5 +101,5 @@ LL |         match *foo_variant!(0) {
 LL |             Foo::A => println!("A"),
    |
 
-error: aborting due to 6 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed
index d99f9af3faf..31b743f7a18 100644
--- a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed
+++ b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed
@@ -108,4 +108,20 @@ fn main() {
         Bar::B => (),
         _ => (),
     };
+
+    //#6984
+    {
+        #![allow(clippy::manual_non_exhaustive)]
+        pub enum Enum {
+            A,
+            B,
+            #[doc(hidden)]
+            __Private,
+        }
+        match Enum::A {
+            Enum::A => (),
+            Enum::B => (),
+            _ => (),
+        }
+    }
 }
diff --git a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.rs b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.rs
index 1752a95de4b..d19e6ab7eb2 100644
--- a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.rs
+++ b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.rs
@@ -108,4 +108,20 @@ fn main() {
         Bar::B => (),
         _ => (),
     };
+
+    //#6984
+    {
+        #![allow(clippy::manual_non_exhaustive)]
+        pub enum Enum {
+            A,
+            B,
+            #[doc(hidden)]
+            __Private,
+        }
+        match Enum::A {
+            Enum::A => (),
+            Enum::B => (),
+            _ => (),
+        }
+    }
 }
diff --git a/src/tools/clippy/tests/ui/min_rust_version_attr.rs b/src/tools/clippy/tests/ui/min_rust_version_attr.rs
index 0f47f1cbc40..49ace1ca128 100644
--- a/src/tools/clippy/tests/ui/min_rust_version_attr.rs
+++ b/src/tools/clippy/tests/ui/min_rust_version_attr.rs
@@ -123,6 +123,11 @@ fn missing_const_for_fn() -> i32 {
     1
 }
 
+fn unnest_or_patterns() {
+    struct TS(u8, u8);
+    if let TS(0, x) | TS(1, x) = TS(0, 0) {}
+}
+
 fn main() {
     filter_map_next();
     checked_conversion();
@@ -138,6 +143,7 @@ fn main() {
     replace_with_default();
     map_unwrap_or();
     missing_const_for_fn();
+    unnest_or_patterns();
 }
 
 mod meets_msrv {
diff --git a/src/tools/clippy/tests/ui/min_rust_version_attr.stderr b/src/tools/clippy/tests/ui/min_rust_version_attr.stderr
index e3e3b335cbe..8d3575c2da8 100644
--- a/src/tools/clippy/tests/ui/min_rust_version_attr.stderr
+++ b/src/tools/clippy/tests/ui/min_rust_version_attr.stderr
@@ -1,12 +1,12 @@
 error: stripping a prefix manually
-  --> $DIR/min_rust_version_attr.rs:150:24
+  --> $DIR/min_rust_version_attr.rs:156:24
    |
 LL |             assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
    |                        ^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::manual-strip` implied by `-D warnings`
 note: the prefix was tested here
-  --> $DIR/min_rust_version_attr.rs:149:9
+  --> $DIR/min_rust_version_attr.rs:155:9
    |
 LL |         if s.starts_with("hello, ") {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -17,13 +17,13 @@ LL |             assert_eq!(<stripped>.to_uppercase(), "WORLD!");
    |
 
 error: stripping a prefix manually
-  --> $DIR/min_rust_version_attr.rs:162:24
+  --> $DIR/min_rust_version_attr.rs:168:24
    |
 LL |             assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
    |                        ^^^^^^^^^^^^^^^^^^^^
    |
 note: the prefix was tested here
-  --> $DIR/min_rust_version_attr.rs:161:9
+  --> $DIR/min_rust_version_attr.rs:167:9
    |
 LL |         if s.starts_with("hello, ") {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/doc_panics.rs b/src/tools/clippy/tests/ui/missing_panics_doc.rs
index 17e72353f80..2e1379a58a6 100644
--- a/src/tools/clippy/tests/ui/doc_panics.rs
+++ b/src/tools/clippy/tests/ui/missing_panics_doc.rs
@@ -33,6 +33,18 @@ pub fn unreachable_and_panic() {
     if true { unreachable!() } else { panic!() }
 }
 
+/// This needs to be documented
+pub fn assert_eq() {
+    let x = 0;
+    assert_eq!(x, 0);
+}
+
+/// This needs to be documented
+pub fn assert_ne() {
+    let x = 0;
+    assert_ne!(x, 0);
+}
+
 /// This is documented
 ///
 /// # Panics
@@ -83,6 +95,26 @@ pub fn unreachable_amd_panic_documented() {
     if true { unreachable!() } else { panic!() }
 }
 
+/// This is documented
+///
+/// # Panics
+///
+/// Panics if `x` is not 0.
+pub fn assert_eq_documented() {
+    let x = 0;
+    assert_eq!(x, 0);
+}
+
+/// This is documented
+///
+/// # Panics
+///
+/// Panics if `x` is 0.
+pub fn assert_ne_documented() {
+    let x = 0;
+    assert_ne!(x, 0);
+}
+
 /// This is okay because it is private
 fn unwrap_private() {
     let result = Err("Hi");
@@ -112,3 +144,11 @@ fn inner_body_private(opt: Option<u32>) {
 pub fn unreachable() {
     unreachable!("This function panics")
 }
+
+/// #6970.
+/// This is okay because it is expansion of `debug_assert` family.
+pub fn debug_assertions() {
+    debug_assert!(false);
+    debug_assert_eq!(1, 2);
+    debug_assert_ne!(1, 2);
+}
diff --git a/src/tools/clippy/tests/ui/doc_panics.stderr b/src/tools/clippy/tests/ui/missing_panics_doc.stderr
index 2fa88a2f6ec..ba96a6a12b5 100644
--- a/src/tools/clippy/tests/ui/doc_panics.stderr
+++ b/src/tools/clippy/tests/ui/missing_panics_doc.stderr
@@ -1,5 +1,5 @@
 error: docs for function which may panic missing `# Panics` section
-  --> $DIR/doc_panics.rs:7:1
+  --> $DIR/missing_panics_doc.rs:7:1
    |
 LL | / pub fn unwrap() {
 LL | |     let result = Err("Hi");
@@ -9,13 +9,13 @@ LL | | }
    |
    = note: `-D clippy::missing-panics-doc` implied by `-D warnings`
 note: first possible panic found here
-  --> $DIR/doc_panics.rs:9:5
+  --> $DIR/missing_panics_doc.rs:9:5
    |
 LL |     result.unwrap()
    |     ^^^^^^^^^^^^^^^
 
 error: docs for function which may panic missing `# Panics` section
-  --> $DIR/doc_panics.rs:13:1
+  --> $DIR/missing_panics_doc.rs:13:1
    |
 LL | / pub fn panic() {
 LL | |     panic!("This function panics")
@@ -23,14 +23,14 @@ LL | | }
    | |_^
    |
 note: first possible panic found here
-  --> $DIR/doc_panics.rs:14:5
+  --> $DIR/missing_panics_doc.rs:14:5
    |
 LL |     panic!("This function panics")
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: docs for function which may panic missing `# Panics` section
-  --> $DIR/doc_panics.rs:18:1
+  --> $DIR/missing_panics_doc.rs:18:1
    |
 LL | / pub fn todo() {
 LL | |     todo!()
@@ -38,14 +38,14 @@ LL | | }
    | |_^
    |
 note: first possible panic found here
-  --> $DIR/doc_panics.rs:19:5
+  --> $DIR/missing_panics_doc.rs:19:5
    |
 LL |     todo!()
    |     ^^^^^^^
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: docs for function which may panic missing `# Panics` section
-  --> $DIR/doc_panics.rs:23:1
+  --> $DIR/missing_panics_doc.rs:23:1
    |
 LL | / pub fn inner_body(opt: Option<u32>) {
 LL | |     opt.map(|x| {
@@ -57,14 +57,14 @@ LL | | }
    | |_^
    |
 note: first possible panic found here
-  --> $DIR/doc_panics.rs:26:13
+  --> $DIR/missing_panics_doc.rs:26:13
    |
 LL |             panic!()
    |             ^^^^^^^^
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: docs for function which may panic missing `# Panics` section
-  --> $DIR/doc_panics.rs:32:1
+  --> $DIR/missing_panics_doc.rs:32:1
    |
 LL | / pub fn unreachable_and_panic() {
 LL | |     if true { unreachable!() } else { panic!() }
@@ -72,11 +72,43 @@ LL | | }
    | |_^
    |
 note: first possible panic found here
-  --> $DIR/doc_panics.rs:33:39
+  --> $DIR/missing_panics_doc.rs:33:39
    |
 LL |     if true { unreachable!() } else { panic!() }
    |                                       ^^^^^^^^
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 5 previous errors
+error: docs for function which may panic missing `# Panics` section
+  --> $DIR/missing_panics_doc.rs:37:1
+   |
+LL | / pub fn assert_eq() {
+LL | |     let x = 0;
+LL | |     assert_eq!(x, 0);
+LL | | }
+   | |_^
+   |
+note: first possible panic found here
+  --> $DIR/missing_panics_doc.rs:39:5
+   |
+LL |     assert_eq!(x, 0);
+   |     ^^^^^^^^^^^^^^^^^
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: docs for function which may panic missing `# Panics` section
+  --> $DIR/missing_panics_doc.rs:43:1
+   |
+LL | / pub fn assert_ne() {
+LL | |     let x = 0;
+LL | |     assert_ne!(x, 0);
+LL | | }
+   | |_^
+   |
+note: first possible panic found here
+  --> $DIR/missing_panics_doc.rs:45:5
+   |
+LL |     assert_ne!(x, 0);
+   |     ^^^^^^^^^^^^^^^^^
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_bool/simple.rs b/src/tools/clippy/tests/ui/needless_bool/simple.rs
index e9f1428fc3a..588bb88f446 100644
--- a/src/tools/clippy/tests/ui/needless_bool/simple.rs
+++ b/src/tools/clippy/tests/ui/needless_bool/simple.rs
@@ -4,7 +4,8 @@
     dead_code,
     clippy::no_effect,
     clippy::if_same_then_else,
-    clippy::needless_return
+    clippy::needless_return,
+    clippy::branches_sharing_code
 )]
 
 fn main() {
diff --git a/src/tools/clippy/tests/ui/needless_bool/simple.stderr b/src/tools/clippy/tests/ui/needless_bool/simple.stderr
index c57a8a042fb..0ccc9416bcd 100644
--- a/src/tools/clippy/tests/ui/needless_bool/simple.stderr
+++ b/src/tools/clippy/tests/ui/needless_bool/simple.stderr
@@ -1,5 +1,5 @@
 error: this if-then-else expression will always return true
-  --> $DIR/simple.rs:13:5
+  --> $DIR/simple.rs:14:5
    |
 LL | /     if x {
 LL | |         true
@@ -11,7 +11,7 @@ LL | |     };
    = note: `-D clippy::needless-bool` implied by `-D warnings`
 
 error: this if-then-else expression will always return false
-  --> $DIR/simple.rs:18:5
+  --> $DIR/simple.rs:19:5
    |
 LL | /     if x {
 LL | |         false
@@ -21,7 +21,7 @@ LL | |     };
    | |_____^
 
 error: this if-then-else expression will always return true
-  --> $DIR/simple.rs:33:5
+  --> $DIR/simple.rs:34:5
    |
 LL | /     if x {
 LL | |         return true;
@@ -31,7 +31,7 @@ LL | |     };
    | |_____^
 
 error: this if-then-else expression will always return false
-  --> $DIR/simple.rs:41:5
+  --> $DIR/simple.rs:42:5
    |
 LL | /     if x {
 LL | |         return false;
diff --git a/src/tools/clippy/tests/ui/needless_collect_indirect.stderr b/src/tools/clippy/tests/ui/needless_collect_indirect.stderr
index 76e789d9052..c773b841f3b 100644
--- a/src/tools/clippy/tests/ui/needless_collect_indirect.stderr
+++ b/src/tools/clippy/tests/ui/needless_collect_indirect.stderr
@@ -1,9 +1,10 @@
 error: avoid using `collect()` when not needed
-  --> $DIR/needless_collect_indirect.rs:5:5
+  --> $DIR/needless_collect_indirect.rs:5:39
    |
-LL | /     let indirect_iter = sample.iter().collect::<Vec<_>>();
-LL | |     indirect_iter.into_iter().map(|x| (x, x + 1)).collect::<HashMap<_, _>>();
-   | |____^
+LL |     let indirect_iter = sample.iter().collect::<Vec<_>>();
+   |                                       ^^^^^^^
+LL |     indirect_iter.into_iter().map(|x| (x, x + 1)).collect::<HashMap<_, _>>();
+   |     ------------------------- the iterator could be used here instead
    |
    = note: `-D clippy::needless-collect` implied by `-D warnings`
 help: use the original Iterator instead of collecting it and then producing a new one
@@ -13,11 +14,12 @@ LL |     sample.iter().map(|x| (x, x + 1)).collect::<HashMap<_, _>>();
    |
 
 error: avoid using `collect()` when not needed
-  --> $DIR/needless_collect_indirect.rs:7:5
+  --> $DIR/needless_collect_indirect.rs:7:38
    |
-LL | /     let indirect_len = sample.iter().collect::<VecDeque<_>>();
-LL | |     indirect_len.len();
-   | |____^
+LL |     let indirect_len = sample.iter().collect::<VecDeque<_>>();
+   |                                      ^^^^^^^
+LL |     indirect_len.len();
+   |     ------------------ the iterator could be used here instead
    |
 help: take the original Iterator's count instead of collecting it and finding the length
    |
@@ -26,11 +28,12 @@ LL |     sample.iter().count();
    |
 
 error: avoid using `collect()` when not needed
-  --> $DIR/needless_collect_indirect.rs:9:5
+  --> $DIR/needless_collect_indirect.rs:9:40
    |
-LL | /     let indirect_empty = sample.iter().collect::<VecDeque<_>>();
-LL | |     indirect_empty.is_empty();
-   | |____^
+LL |     let indirect_empty = sample.iter().collect::<VecDeque<_>>();
+   |                                        ^^^^^^^
+LL |     indirect_empty.is_empty();
+   |     ------------------------- the iterator could be used here instead
    |
 help: check if the original Iterator has anything instead of collecting it and seeing if it's empty
    |
@@ -39,11 +42,12 @@ LL |     sample.iter().next().is_none();
    |
 
 error: avoid using `collect()` when not needed
-  --> $DIR/needless_collect_indirect.rs:11:5
+  --> $DIR/needless_collect_indirect.rs:11:43
    |
-LL | /     let indirect_contains = sample.iter().collect::<VecDeque<_>>();
-LL | |     indirect_contains.contains(&&5);
-   | |____^
+LL |     let indirect_contains = sample.iter().collect::<VecDeque<_>>();
+   |                                           ^^^^^^^
+LL |     indirect_contains.contains(&&5);
+   |     ------------------------------- the iterator could be used here instead
    |
 help: check if the original Iterator contains an element instead of collecting then checking
    |
@@ -52,11 +56,12 @@ LL |     sample.iter().any(|x| x == &5);
    |
 
 error: avoid using `collect()` when not needed
-  --> $DIR/needless_collect_indirect.rs:23:5
+  --> $DIR/needless_collect_indirect.rs:23:48
    |
-LL | /     let non_copy_contains = sample.into_iter().collect::<Vec<_>>();
-LL | |     non_copy_contains.contains(&a);
-   | |____^
+LL |     let non_copy_contains = sample.into_iter().collect::<Vec<_>>();
+   |                                                ^^^^^^^
+LL |     non_copy_contains.contains(&a);
+   |     ------------------------------ the iterator could be used here instead
    |
 help: check if the original Iterator contains an element instead of collecting then checking
    |
diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed b/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed
new file mode 100644
index 00000000000..f00f9ee4c33
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed
@@ -0,0 +1,113 @@
+// run-rustfix
+#![warn(clippy::needless_for_each)]
+#![allow(unused, clippy::needless_return, clippy::match_single_binding)]
+
+use std::collections::HashMap;
+
+fn should_lint() {
+    let v: Vec<i32> = Vec::new();
+    let mut acc = 0;
+    for elem in v.iter() {
+        acc += elem;
+    }
+    for elem in v.into_iter() {
+        acc += elem;
+    }
+
+    for elem in [1, 2, 3].iter() {
+        acc += elem;
+    }
+
+    let mut hash_map: HashMap<i32, i32> = HashMap::new();
+    for (k, v) in hash_map.iter() {
+        acc += k + v;
+    }
+    for (k, v) in hash_map.iter_mut() {
+        acc += *k + *v;
+    }
+    for k in hash_map.keys() {
+        acc += k;
+    }
+    for v in hash_map.values() {
+        acc += v;
+    }
+
+    fn my_vec() -> Vec<i32> {
+        Vec::new()
+    }
+    for elem in my_vec().iter() {
+        acc += elem;
+    }
+}
+
+fn should_not_lint() {
+    let v: Vec<i32> = Vec::new();
+    let mut acc = 0;
+
+    // `for_each` argument is not closure.
+    fn print(x: &i32) {
+        println!("{}", x);
+    }
+    v.iter().for_each(print);
+
+    // User defined type.
+    struct MyStruct {
+        v: Vec<i32>,
+    }
+    impl MyStruct {
+        fn iter(&self) -> impl Iterator<Item = &i32> {
+            self.v.iter()
+        }
+    }
+    let s = MyStruct { v: Vec::new() };
+    s.iter().for_each(|elem| {
+        acc += elem;
+    });
+
+    // `for_each` follows long iterator chain.
+    v.iter().chain(v.iter()).for_each(|v| {
+        acc += v;
+    });
+    v.as_slice().iter().for_each(|v| {
+        acc += v;
+    });
+    s.v.iter().for_each(|v| {
+        acc += v;
+    });
+
+    // `return` is used in `Loop` of the closure.
+    v.iter().for_each(|v| {
+        for i in 0..*v {
+            if i == 10 {
+                return;
+            } else {
+                println!("{}", v);
+            }
+        }
+        if *v == 20 {
+            return;
+        } else {
+            println!("{}", v);
+        }
+    });
+
+    // Previously transformed iterator variable.
+    let it = v.iter();
+    it.chain(v.iter()).for_each(|elem| {
+        acc += elem;
+    });
+
+    // `for_each` is not directly in a statement.
+    match 1 {
+        _ => v.iter().for_each(|elem| {
+            acc += elem;
+        }),
+    }
+
+    // `for_each` is in a let bingind.
+    let _ = v.iter().for_each(|elem| {
+        acc += elem;
+    });
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.rs b/src/tools/clippy/tests/ui/needless_for_each_fixable.rs
new file mode 100644
index 00000000000..1bd400d348b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.rs
@@ -0,0 +1,113 @@
+// run-rustfix
+#![warn(clippy::needless_for_each)]
+#![allow(unused, clippy::needless_return, clippy::match_single_binding)]
+
+use std::collections::HashMap;
+
+fn should_lint() {
+    let v: Vec<i32> = Vec::new();
+    let mut acc = 0;
+    v.iter().for_each(|elem| {
+        acc += elem;
+    });
+    v.into_iter().for_each(|elem| {
+        acc += elem;
+    });
+
+    [1, 2, 3].iter().for_each(|elem| {
+        acc += elem;
+    });
+
+    let mut hash_map: HashMap<i32, i32> = HashMap::new();
+    hash_map.iter().for_each(|(k, v)| {
+        acc += k + v;
+    });
+    hash_map.iter_mut().for_each(|(k, v)| {
+        acc += *k + *v;
+    });
+    hash_map.keys().for_each(|k| {
+        acc += k;
+    });
+    hash_map.values().for_each(|v| {
+        acc += v;
+    });
+
+    fn my_vec() -> Vec<i32> {
+        Vec::new()
+    }
+    my_vec().iter().for_each(|elem| {
+        acc += elem;
+    });
+}
+
+fn should_not_lint() {
+    let v: Vec<i32> = Vec::new();
+    let mut acc = 0;
+
+    // `for_each` argument is not closure.
+    fn print(x: &i32) {
+        println!("{}", x);
+    }
+    v.iter().for_each(print);
+
+    // User defined type.
+    struct MyStruct {
+        v: Vec<i32>,
+    }
+    impl MyStruct {
+        fn iter(&self) -> impl Iterator<Item = &i32> {
+            self.v.iter()
+        }
+    }
+    let s = MyStruct { v: Vec::new() };
+    s.iter().for_each(|elem| {
+        acc += elem;
+    });
+
+    // `for_each` follows long iterator chain.
+    v.iter().chain(v.iter()).for_each(|v| {
+        acc += v;
+    });
+    v.as_slice().iter().for_each(|v| {
+        acc += v;
+    });
+    s.v.iter().for_each(|v| {
+        acc += v;
+    });
+
+    // `return` is used in `Loop` of the closure.
+    v.iter().for_each(|v| {
+        for i in 0..*v {
+            if i == 10 {
+                return;
+            } else {
+                println!("{}", v);
+            }
+        }
+        if *v == 20 {
+            return;
+        } else {
+            println!("{}", v);
+        }
+    });
+
+    // Previously transformed iterator variable.
+    let it = v.iter();
+    it.chain(v.iter()).for_each(|elem| {
+        acc += elem;
+    });
+
+    // `for_each` is not directly in a statement.
+    match 1 {
+        _ => v.iter().for_each(|elem| {
+            acc += elem;
+        }),
+    }
+
+    // `for_each` is in a let bingind.
+    let _ = v.iter().for_each(|elem| {
+        acc += elem;
+    });
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr b/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr
new file mode 100644
index 00000000000..483a5e6d61d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr
@@ -0,0 +1,123 @@
+error: needless use of `for_each`
+  --> $DIR/needless_for_each_fixable.rs:10:5
+   |
+LL | /     v.iter().for_each(|elem| {
+LL | |         acc += elem;
+LL | |     });
+   | |_______^
+   |
+   = note: `-D clippy::needless-for-each` implied by `-D warnings`
+help: try
+   |
+LL |     for elem in v.iter() {
+LL |         acc += elem;
+LL |     }
+   |
+
+error: needless use of `for_each`
+  --> $DIR/needless_for_each_fixable.rs:13:5
+   |
+LL | /     v.into_iter().for_each(|elem| {
+LL | |         acc += elem;
+LL | |     });
+   | |_______^
+   |
+help: try
+   |
+LL |     for elem in v.into_iter() {
+LL |         acc += elem;
+LL |     }
+   |
+
+error: needless use of `for_each`
+  --> $DIR/needless_for_each_fixable.rs:17:5
+   |
+LL | /     [1, 2, 3].iter().for_each(|elem| {
+LL | |         acc += elem;
+LL | |     });
+   | |_______^
+   |
+help: try
+   |
+LL |     for elem in [1, 2, 3].iter() {
+LL |         acc += elem;
+LL |     }
+   |
+
+error: needless use of `for_each`
+  --> $DIR/needless_for_each_fixable.rs:22:5
+   |
+LL | /     hash_map.iter().for_each(|(k, v)| {
+LL | |         acc += k + v;
+LL | |     });
+   | |_______^
+   |
+help: try
+   |
+LL |     for (k, v) in hash_map.iter() {
+LL |         acc += k + v;
+LL |     }
+   |
+
+error: needless use of `for_each`
+  --> $DIR/needless_for_each_fixable.rs:25:5
+   |
+LL | /     hash_map.iter_mut().for_each(|(k, v)| {
+LL | |         acc += *k + *v;
+LL | |     });
+   | |_______^
+   |
+help: try
+   |
+LL |     for (k, v) in hash_map.iter_mut() {
+LL |         acc += *k + *v;
+LL |     }
+   |
+
+error: needless use of `for_each`
+  --> $DIR/needless_for_each_fixable.rs:28:5
+   |
+LL | /     hash_map.keys().for_each(|k| {
+LL | |         acc += k;
+LL | |     });
+   | |_______^
+   |
+help: try
+   |
+LL |     for k in hash_map.keys() {
+LL |         acc += k;
+LL |     }
+   |
+
+error: needless use of `for_each`
+  --> $DIR/needless_for_each_fixable.rs:31:5
+   |
+LL | /     hash_map.values().for_each(|v| {
+LL | |         acc += v;
+LL | |     });
+   | |_______^
+   |
+help: try
+   |
+LL |     for v in hash_map.values() {
+LL |         acc += v;
+LL |     }
+   |
+
+error: needless use of `for_each`
+  --> $DIR/needless_for_each_fixable.rs:38:5
+   |
+LL | /     my_vec().iter().for_each(|elem| {
+LL | |         acc += elem;
+LL | |     });
+   | |_______^
+   |
+help: try
+   |
+LL |     for elem in my_vec().iter() {
+LL |         acc += elem;
+LL |     }
+   |
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_for_each_unfixable.rs b/src/tools/clippy/tests/ui/needless_for_each_unfixable.rs
new file mode 100644
index 00000000000..d765d7dab65
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_for_each_unfixable.rs
@@ -0,0 +1,14 @@
+#![warn(clippy::needless_for_each)]
+#![allow(clippy::needless_return)]
+
+fn main() {
+    let v: Vec<i32> = Vec::new();
+    // This is unfixable because the closure includes `return`.
+    v.iter().for_each(|v| {
+        if *v == 10 {
+            return;
+        } else {
+            println!("{}", v);
+        }
+    });
+}
diff --git a/src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr b/src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr
new file mode 100644
index 00000000000..8c4507d2328
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr
@@ -0,0 +1,29 @@
+error: needless use of `for_each`
+  --> $DIR/needless_for_each_unfixable.rs:7:5
+   |
+LL | /     v.iter().for_each(|v| {
+LL | |         if *v == 10 {
+LL | |             return;
+LL | |         } else {
+LL | |             println!("{}", v);
+LL | |         }
+LL | |     });
+   | |_______^
+   |
+   = note: `-D clippy::needless-for-each` implied by `-D warnings`
+help: try
+   |
+LL |     for v in v.iter() {
+LL |         if *v == 10 {
+LL |             return;
+LL |         } else {
+LL |             println!("{}", v);
+LL |         }
+ ...
+help: ...and replace `return` with `continue`
+   |
+LL |             continue;
+   |             ^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed
index 990475fcb58..82d95cc041f 100644
--- a/src/tools/clippy/tests/ui/needless_return.fixed
+++ b/src/tools/clippy/tests/ui/needless_return.fixed
@@ -1,7 +1,12 @@
 // run-rustfix
 
-#![allow(unused, clippy::needless_bool)]
-#![allow(clippy::if_same_then_else, clippy::single_match)]
+#![allow(unused)]
+#![allow(
+    clippy::if_same_then_else,
+    clippy::single_match,
+    clippy::branches_sharing_code,
+    clippy::needless_bool
+)]
 #![warn(clippy::needless_return)]
 
 macro_rules! the_answer {
diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs
index dec3d84a020..8a471f802e1 100644
--- a/src/tools/clippy/tests/ui/needless_return.rs
+++ b/src/tools/clippy/tests/ui/needless_return.rs
@@ -1,7 +1,12 @@
 // run-rustfix
 
-#![allow(unused, clippy::needless_bool)]
-#![allow(clippy::if_same_then_else, clippy::single_match)]
+#![allow(unused)]
+#![allow(
+    clippy::if_same_then_else,
+    clippy::single_match,
+    clippy::branches_sharing_code,
+    clippy::needless_bool
+)]
 #![warn(clippy::needless_return)]
 
 macro_rules! the_answer {
diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr
index ae31d607541..075db22456f 100644
--- a/src/tools/clippy/tests/ui/needless_return.stderr
+++ b/src/tools/clippy/tests/ui/needless_return.stderr
@@ -1,5 +1,5 @@
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:18:5
+  --> $DIR/needless_return.rs:23:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^^ help: remove `return`: `true`
@@ -7,103 +7,103 @@ LL |     return true;
    = note: `-D clippy::needless-return` implied by `-D warnings`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:22:5
+  --> $DIR/needless_return.rs:27:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^^ help: remove `return`: `true`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:27:9
+  --> $DIR/needless_return.rs:32:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^^ help: remove `return`: `true`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:29:9
+  --> $DIR/needless_return.rs:34:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^^ help: remove `return`: `false`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:35:17
+  --> $DIR/needless_return.rs:40:17
    |
 LL |         true => return false,
    |                 ^^^^^^^^^^^^ help: remove `return`: `false`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:37:13
+  --> $DIR/needless_return.rs:42:13
    |
 LL |             return true;
    |             ^^^^^^^^^^^^ help: remove `return`: `true`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:44:9
+  --> $DIR/needless_return.rs:49:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^^ help: remove `return`: `true`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:46:16
+  --> $DIR/needless_return.rs:51:16
    |
 LL |     let _ = || return true;
    |                ^^^^^^^^^^^ help: remove `return`: `true`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:54:5
+  --> $DIR/needless_return.rs:59:5
    |
 LL |     return;
    |     ^^^^^^^ help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:59:9
+  --> $DIR/needless_return.rs:64:9
    |
 LL |         return;
    |         ^^^^^^^ help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:61:9
+  --> $DIR/needless_return.rs:66:9
    |
 LL |         return;
    |         ^^^^^^^ help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:68:14
+  --> $DIR/needless_return.rs:73:14
    |
 LL |         _ => return,
    |              ^^^^^^ help: replace `return` with an empty block: `{}`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:83:9
+  --> $DIR/needless_return.rs:88:9
    |
 LL |         return String::from("test");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:85:9
+  --> $DIR/needless_return.rs:90:9
    |
 LL |         return String::new();
    |         ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:106:32
+  --> $DIR/needless_return.rs:111:32
    |
 LL |         bar.unwrap_or_else(|_| return)
    |                                ^^^^^^ help: replace `return` with an empty block: `{}`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:111:13
+  --> $DIR/needless_return.rs:116:13
    |
 LL |             return;
    |             ^^^^^^^ help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:113:20
+  --> $DIR/needless_return.rs:118:20
    |
 LL |         let _ = || return;
    |                    ^^^^^^ help: replace `return` with an empty block: `{}`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:119:32
+  --> $DIR/needless_return.rs:124:32
    |
 LL |         res.unwrap_or_else(|_| return Foo)
    |                                ^^^^^^^^^^ help: remove `return`: `Foo`
diff --git a/src/tools/clippy/tests/ui/non_octal_unix_permissions.fixed b/src/tools/clippy/tests/ui/non_octal_unix_permissions.fixed
new file mode 100644
index 00000000000..a9b2dcfb085
--- /dev/null
+++ b/src/tools/clippy/tests/ui/non_octal_unix_permissions.fixed
@@ -0,0 +1,33 @@
+// ignore-windows
+// run-rustfix
+#![warn(clippy::non_octal_unix_permissions)]
+use std::fs::{DirBuilder, File, OpenOptions, Permissions};
+use std::os::unix::fs::{DirBuilderExt, OpenOptionsExt, PermissionsExt};
+
+fn main() {
+    let permissions = 0o760;
+
+    // OpenOptionsExt::mode
+    let mut options = OpenOptions::new();
+    options.mode(0o440);
+    options.mode(0o400);
+    options.mode(permissions);
+
+    // PermissionsExt::from_mode
+    let _permissions = Permissions::from_mode(0o647);
+    let _permissions = Permissions::from_mode(0o000);
+    let _permissions = Permissions::from_mode(permissions);
+
+    // PermissionsExt::set_mode
+    let f = File::create("foo.txt").unwrap();
+    let metadata = f.metadata().unwrap();
+    let mut permissions = metadata.permissions();
+
+    permissions.set_mode(0o644);
+    permissions.set_mode(0o704);
+
+    // DirBuilderExt::mode
+    let mut builder = DirBuilder::new();
+    builder.mode(0o755);
+    builder.mode(0o406);
+}
diff --git a/src/tools/clippy/tests/ui/non_octal_unix_permissions.rs b/src/tools/clippy/tests/ui/non_octal_unix_permissions.rs
new file mode 100644
index 00000000000..7d2922f494e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/non_octal_unix_permissions.rs
@@ -0,0 +1,33 @@
+// ignore-windows
+// run-rustfix
+#![warn(clippy::non_octal_unix_permissions)]
+use std::fs::{DirBuilder, File, OpenOptions, Permissions};
+use std::os::unix::fs::{DirBuilderExt, OpenOptionsExt, PermissionsExt};
+
+fn main() {
+    let permissions = 0o760;
+
+    // OpenOptionsExt::mode
+    let mut options = OpenOptions::new();
+    options.mode(440);
+    options.mode(0o400);
+    options.mode(permissions);
+
+    // PermissionsExt::from_mode
+    let _permissions = Permissions::from_mode(647);
+    let _permissions = Permissions::from_mode(0o000);
+    let _permissions = Permissions::from_mode(permissions);
+
+    // PermissionsExt::set_mode
+    let f = File::create("foo.txt").unwrap();
+    let metadata = f.metadata().unwrap();
+    let mut permissions = metadata.permissions();
+
+    permissions.set_mode(644);
+    permissions.set_mode(0o704);
+
+    // DirBuilderExt::mode
+    let mut builder = DirBuilder::new();
+    builder.mode(755);
+    builder.mode(0o406);
+}
diff --git a/src/tools/clippy/tests/ui/non_octal_unix_permissions.stderr b/src/tools/clippy/tests/ui/non_octal_unix_permissions.stderr
new file mode 100644
index 00000000000..32845d06594
--- /dev/null
+++ b/src/tools/clippy/tests/ui/non_octal_unix_permissions.stderr
@@ -0,0 +1,28 @@
+error: using a non-octal value to set unix file permissions
+  --> $DIR/non_octal_unix_permissions.rs:12:18
+   |
+LL |     options.mode(440);
+   |                  ^^^ help: consider using an octal literal instead: `0o440`
+   |
+   = note: `-D clippy::non-octal-unix-permissions` implied by `-D warnings`
+
+error: using a non-octal value to set unix file permissions
+  --> $DIR/non_octal_unix_permissions.rs:17:47
+   |
+LL |     let _permissions = Permissions::from_mode(647);
+   |                                               ^^^ help: consider using an octal literal instead: `0o647`
+
+error: using a non-octal value to set unix file permissions
+  --> $DIR/non_octal_unix_permissions.rs:26:26
+   |
+LL |     permissions.set_mode(644);
+   |                          ^^^ help: consider using an octal literal instead: `0o644`
+
+error: using a non-octal value to set unix file permissions
+  --> $DIR/non_octal_unix_permissions.rs:31:18
+   |
+LL |     builder.mode(755);
+   |                  ^^^ help: consider using an octal literal instead: `0o755`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/option_filter_map.fixed b/src/tools/clippy/tests/ui/option_filter_map.fixed
new file mode 100644
index 00000000000..f9d1825ade0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_filter_map.fixed
@@ -0,0 +1,23 @@
+#![warn(clippy::option_filter_map)]
+// run-rustfix
+fn odds_out(x: i32) -> Option<i32> {
+    if x % 2 == 0 { Some(x) } else { None }
+}
+
+fn main() {
+    let _ = Some(Some(1)).flatten();
+    let _ = Some(Some(1)).flatten();
+    let _ = Some(1).map(odds_out).flatten();
+    let _ = Some(1).map(odds_out).flatten();
+
+    let _ = vec![Some(1)].into_iter().flatten();
+    let _ = vec![Some(1)].into_iter().flatten();
+    let _ = vec![1]
+        .into_iter()
+        .map(odds_out)
+        .flatten();
+    let _ = vec![1]
+        .into_iter()
+        .map(odds_out)
+        .flatten();
+}
diff --git a/src/tools/clippy/tests/ui/option_filter_map.rs b/src/tools/clippy/tests/ui/option_filter_map.rs
new file mode 100644
index 00000000000..588e1ccccce
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_filter_map.rs
@@ -0,0 +1,25 @@
+#![warn(clippy::option_filter_map)]
+// run-rustfix
+fn odds_out(x: i32) -> Option<i32> {
+    if x % 2 == 0 { Some(x) } else { None }
+}
+
+fn main() {
+    let _ = Some(Some(1)).filter(Option::is_some).map(Option::unwrap);
+    let _ = Some(Some(1)).filter(|o| o.is_some()).map(|o| o.unwrap());
+    let _ = Some(1).map(odds_out).filter(Option::is_some).map(Option::unwrap);
+    let _ = Some(1).map(odds_out).filter(|o| o.is_some()).map(|o| o.unwrap());
+
+    let _ = vec![Some(1)].into_iter().filter(Option::is_some).map(Option::unwrap);
+    let _ = vec![Some(1)].into_iter().filter(|o| o.is_some()).map(|o| o.unwrap());
+    let _ = vec![1]
+        .into_iter()
+        .map(odds_out)
+        .filter(Option::is_some)
+        .map(Option::unwrap);
+    let _ = vec![1]
+        .into_iter()
+        .map(odds_out)
+        .filter(|o| o.is_some())
+        .map(|o| o.unwrap());
+}
diff --git a/src/tools/clippy/tests/ui/option_filter_map.stderr b/src/tools/clippy/tests/ui/option_filter_map.stderr
new file mode 100644
index 00000000000..31a82969d5a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_filter_map.stderr
@@ -0,0 +1,56 @@
+error: `filter` for `Some` followed by `unwrap`
+  --> $DIR/option_filter_map.rs:8:27
+   |
+LL |     let _ = Some(Some(1)).filter(Option::is_some).map(Option::unwrap);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+   |
+   = note: `-D clippy::option-filter-map` implied by `-D warnings`
+
+error: `filter` for `Some` followed by `unwrap`
+  --> $DIR/option_filter_map.rs:9:27
+   |
+LL |     let _ = Some(Some(1)).filter(|o| o.is_some()).map(|o| o.unwrap());
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `Some` followed by `unwrap`
+  --> $DIR/option_filter_map.rs:10:35
+   |
+LL |     let _ = Some(1).map(odds_out).filter(Option::is_some).map(Option::unwrap);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `Some` followed by `unwrap`
+  --> $DIR/option_filter_map.rs:11:35
+   |
+LL |     let _ = Some(1).map(odds_out).filter(|o| o.is_some()).map(|o| o.unwrap());
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `Some` followed by `unwrap`
+  --> $DIR/option_filter_map.rs:13:39
+   |
+LL |     let _ = vec![Some(1)].into_iter().filter(Option::is_some).map(Option::unwrap);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `Some` followed by `unwrap`
+  --> $DIR/option_filter_map.rs:14:39
+   |
+LL |     let _ = vec![Some(1)].into_iter().filter(|o| o.is_some()).map(|o| o.unwrap());
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `Some` followed by `unwrap`
+  --> $DIR/option_filter_map.rs:18:10
+   |
+LL |           .filter(Option::is_some)
+   |  __________^
+LL | |         .map(Option::unwrap);
+   | |____________________________^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `Some` followed by `unwrap`
+  --> $DIR/option_filter_map.rs:23:10
+   |
+LL |           .filter(|o| o.is_some())
+   |  __________^
+LL | |         .map(|o| o.unwrap());
+   | |____________________________^ help: consider using `flatten` instead: `flatten()`
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/option_option.rs b/src/tools/clippy/tests/ui/option_option.rs
index 6859ba8e5bb..2faab9e035d 100644
--- a/src/tools/clippy/tests/ui/option_option.rs
+++ b/src/tools/clippy/tests/ui/option_option.rs
@@ -1,6 +1,9 @@
 #![deny(clippy::option_option)]
 #![allow(clippy::unnecessary_wraps)]
 
+const C: Option<Option<i32>> = None;
+static S: Option<Option<i32>> = None;
+
 fn input(_: Option<Option<u8>>) {}
 
 fn output() -> Option<Option<u8>> {
diff --git a/src/tools/clippy/tests/ui/option_option.stderr b/src/tools/clippy/tests/ui/option_option.stderr
index ad7f081c713..a925bb35b04 100644
--- a/src/tools/clippy/tests/ui/option_option.stderr
+++ b/src/tools/clippy/tests/ui/option_option.stderr
@@ -1,8 +1,8 @@
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> $DIR/option_option.rs:4:13
+  --> $DIR/option_option.rs:4:10
    |
-LL | fn input(_: Option<Option<u8>>) {}
-   |             ^^^^^^^^^^^^^^^^^^
+LL | const C: Option<Option<i32>> = None;
+   |          ^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/option_option.rs:1:9
@@ -11,58 +11,70 @@ LL | #![deny(clippy::option_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> $DIR/option_option.rs:6:16
+  --> $DIR/option_option.rs:5:11
+   |
+LL | static S: Option<Option<i32>> = None;
+   |           ^^^^^^^^^^^^^^^^^^^
+
+error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
+  --> $DIR/option_option.rs:7:13
+   |
+LL | fn input(_: Option<Option<u8>>) {}
+   |             ^^^^^^^^^^^^^^^^^^
+
+error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
+  --> $DIR/option_option.rs:9:16
    |
 LL | fn output() -> Option<Option<u8>> {
    |                ^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> $DIR/option_option.rs:10:27
+  --> $DIR/option_option.rs:13:27
    |
 LL | fn output_nested() -> Vec<Option<Option<u8>>> {
    |                           ^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> $DIR/option_option.rs:15:30
+  --> $DIR/option_option.rs:18:30
    |
 LL | fn output_nested_nested() -> Option<Option<Option<u8>>> {
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> $DIR/option_option.rs:20:8
+  --> $DIR/option_option.rs:23:8
    |
 LL |     x: Option<Option<u8>>,
    |        ^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> $DIR/option_option.rs:24:23
+  --> $DIR/option_option.rs:27:23
    |
 LL |     fn struct_fn() -> Option<Option<u8>> {
    |                       ^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> $DIR/option_option.rs:30:22
+  --> $DIR/option_option.rs:33:22
    |
 LL |     fn trait_fn() -> Option<Option<u8>>;
    |                      ^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> $DIR/option_option.rs:34:11
+  --> $DIR/option_option.rs:37:11
    |
 LL |     Tuple(Option<Option<u8>>),
    |           ^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> $DIR/option_option.rs:35:17
+  --> $DIR/option_option.rs:38:17
    |
 LL |     Struct { x: Option<Option<u8>> },
    |                 ^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> $DIR/option_option.rs:76:14
+  --> $DIR/option_option.rs:79:14
    |
 LL |         foo: Option<Option<Cow<'a, str>>>,
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 10 previous errors
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/redundant_clone.fixed b/src/tools/clippy/tests/ui/redundant_clone.fixed
index ec309109ed5..f5da703cd1d 100644
--- a/src/tools/clippy/tests/ui/redundant_clone.fixed
+++ b/src/tools/clippy/tests/ui/redundant_clone.fixed
@@ -54,6 +54,7 @@ fn main() {
     not_consumed();
     issue_5405();
     manually_drop();
+    clone_then_move_cloned();
 }
 
 #[derive(Clone)]
@@ -182,3 +183,26 @@ fn manually_drop() {
         Arc::from_raw(p);
     }
 }
+
+fn clone_then_move_cloned() {
+    // issue #5973
+    let x = Some(String::new());
+    // ok, x is moved while the clone is in use.
+    assert_eq!(x.clone(), None, "not equal {}", x.unwrap());
+
+    // issue #5595
+    fn foo<F: Fn()>(_: &Alpha, _: F) {}
+    let x = Alpha;
+    // ok, data is moved while the clone is in use.
+    foo(&x.clone(), move || {
+        let _ = x;
+    });
+
+    // issue #6998
+    struct S(String);
+    impl S {
+        fn m(&mut self) {}
+    }
+    let mut x = S(String::new());
+    x.0.clone().chars().for_each(|_| x.m());
+}
diff --git a/src/tools/clippy/tests/ui/redundant_clone.rs b/src/tools/clippy/tests/ui/redundant_clone.rs
index b57027456e0..fd7f31a1cc5 100644
--- a/src/tools/clippy/tests/ui/redundant_clone.rs
+++ b/src/tools/clippy/tests/ui/redundant_clone.rs
@@ -54,6 +54,7 @@ fn main() {
     not_consumed();
     issue_5405();
     manually_drop();
+    clone_then_move_cloned();
 }
 
 #[derive(Clone)]
@@ -182,3 +183,26 @@ fn manually_drop() {
         Arc::from_raw(p);
     }
 }
+
+fn clone_then_move_cloned() {
+    // issue #5973
+    let x = Some(String::new());
+    // ok, x is moved while the clone is in use.
+    assert_eq!(x.clone(), None, "not equal {}", x.unwrap());
+
+    // issue #5595
+    fn foo<F: Fn()>(_: &Alpha, _: F) {}
+    let x = Alpha;
+    // ok, data is moved while the clone is in use.
+    foo(&x.clone(), move || {
+        let _ = x;
+    });
+
+    // issue #6998
+    struct S(String);
+    impl S {
+        fn m(&mut self) {}
+    }
+    let mut x = S(String::new());
+    x.0.clone().chars().for_each(|_| x.m());
+}
diff --git a/src/tools/clippy/tests/ui/redundant_clone.stderr b/src/tools/clippy/tests/ui/redundant_clone.stderr
index 821e7934be8..529a6de91e2 100644
--- a/src/tools/clippy/tests/ui/redundant_clone.stderr
+++ b/src/tools/clippy/tests/ui/redundant_clone.stderr
@@ -108,61 +108,61 @@ LL |     let _t = tup.0.clone();
    |              ^^^^^
 
 error: redundant clone
-  --> $DIR/redundant_clone.rs:62:25
+  --> $DIR/redundant_clone.rs:63:25
    |
 LL |     if b { (a.clone(), a.clone()) } else { (Alpha, a) }
    |                         ^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> $DIR/redundant_clone.rs:62:24
+  --> $DIR/redundant_clone.rs:63:24
    |
 LL |     if b { (a.clone(), a.clone()) } else { (Alpha, a) }
    |                        ^
 
 error: redundant clone
-  --> $DIR/redundant_clone.rs:119:15
+  --> $DIR/redundant_clone.rs:120:15
    |
 LL |     let _s = s.clone();
    |               ^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> $DIR/redundant_clone.rs:119:14
+  --> $DIR/redundant_clone.rs:120:14
    |
 LL |     let _s = s.clone();
    |              ^
 
 error: redundant clone
-  --> $DIR/redundant_clone.rs:120:15
+  --> $DIR/redundant_clone.rs:121:15
    |
 LL |     let _t = t.clone();
    |               ^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> $DIR/redundant_clone.rs:120:14
+  --> $DIR/redundant_clone.rs:121:14
    |
 LL |     let _t = t.clone();
    |              ^
 
 error: redundant clone
-  --> $DIR/redundant_clone.rs:130:19
+  --> $DIR/redundant_clone.rs:131:19
    |
 LL |         let _f = f.clone();
    |                   ^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> $DIR/redundant_clone.rs:130:18
+  --> $DIR/redundant_clone.rs:131:18
    |
 LL |         let _f = f.clone();
    |                  ^
 
 error: redundant clone
-  --> $DIR/redundant_clone.rs:142:14
+  --> $DIR/redundant_clone.rs:143:14
    |
 LL |     let y = x.clone().join("matthias");
    |              ^^^^^^^^ help: remove this
    |
 note: cloned value is neither consumed nor mutated
-  --> $DIR/redundant_clone.rs:142:13
+  --> $DIR/redundant_clone.rs:143:13
    |
 LL |     let y = x.clone().join("matthias");
    |             ^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/redundant_slicing.rs b/src/tools/clippy/tests/ui/redundant_slicing.rs
index 922b8b4ce57..554b6ba36ae 100644
--- a/src/tools/clippy/tests/ui/redundant_slicing.rs
+++ b/src/tools/clippy/tests/ui/redundant_slicing.rs
@@ -2,10 +2,31 @@
 #![warn(clippy::redundant_slicing)]
 
 fn main() {
-    let x: &[u32] = &[0];
-    let err = &x[..];
+    let slice: &[u32] = &[0];
+    let _ = &slice[..];
 
     let v = vec![0];
-    let ok = &v[..];
-    let err = &(&v[..])[..];
+    let _ = &v[..]; // Changes the type
+    let _ = &(&v[..])[..]; // Outer borrow is redundant
+
+    static S: &[u8] = &[0, 1, 2];
+    let err = &mut &S[..]; // Should reborrow instead of slice
+
+    let mut vec = vec![0];
+    let mut_slice = &mut *vec;
+    let _ = &mut mut_slice[..]; // Should reborrow instead of slice
+
+    macro_rules! m {
+        ($e:expr) => {
+            $e
+        };
+    }
+    let _ = &m!(slice)[..];
+
+    macro_rules! m2 {
+        ($e:expr) => {
+            &$e[..]
+        };
+    }
+    let _ = m2!(slice); // Don't lint in a macro
 }
diff --git a/src/tools/clippy/tests/ui/redundant_slicing.stderr b/src/tools/clippy/tests/ui/redundant_slicing.stderr
index 9efd6484ad0..bbd10eafbbe 100644
--- a/src/tools/clippy/tests/ui/redundant_slicing.stderr
+++ b/src/tools/clippy/tests/ui/redundant_slicing.stderr
@@ -1,16 +1,34 @@
 error: redundant slicing of the whole range
-  --> $DIR/redundant_slicing.rs:6:15
+  --> $DIR/redundant_slicing.rs:6:13
    |
-LL |     let err = &x[..];
-   |               ^^^^^^ help: use the original slice instead: `x`
+LL |     let _ = &slice[..];
+   |             ^^^^^^^^^^ help: use the original value instead: `slice`
    |
    = note: `-D clippy::redundant-slicing` implied by `-D warnings`
 
 error: redundant slicing of the whole range
-  --> $DIR/redundant_slicing.rs:10:15
+  --> $DIR/redundant_slicing.rs:10:13
    |
-LL |     let err = &(&v[..])[..];
-   |               ^^^^^^^^^^^^^ help: use the original slice instead: `(&v[..])`
+LL |     let _ = &(&v[..])[..]; // Outer borrow is redundant
+   |             ^^^^^^^^^^^^^ help: use the original value instead: `(&v[..])`
 
-error: aborting due to 2 previous errors
+error: redundant slicing of the whole range
+  --> $DIR/redundant_slicing.rs:13:20
+   |
+LL |     let err = &mut &S[..]; // Should reborrow instead of slice
+   |                    ^^^^^^ help: reborrow the original value instead: `&*S`
+
+error: redundant slicing of the whole range
+  --> $DIR/redundant_slicing.rs:17:13
+   |
+LL |     let _ = &mut mut_slice[..]; // Should reborrow instead of slice
+   |             ^^^^^^^^^^^^^^^^^^ help: reborrow the original value instead: `&mut *mut_slice`
+
+error: redundant slicing of the whole range
+  --> $DIR/redundant_slicing.rs:24:13
+   |
+LL |     let _ = &m!(slice)[..];
+   |             ^^^^^^^^^^^^^^ help: use the original value instead: `slice`
+
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/ref_option_ref.rs b/src/tools/clippy/tests/ui/ref_option_ref.rs
index b2c275d68af..2df45c927d7 100644
--- a/src/tools/clippy/tests/ui/ref_option_ref.rs
+++ b/src/tools/clippy/tests/ui/ref_option_ref.rs
@@ -9,7 +9,7 @@
 static THRESHOLD: i32 = 10;
 static REF_THRESHOLD: &Option<&i32> = &Some(&THRESHOLD);
 const CONST_THRESHOLD: &i32 = &10;
-const REF_CONST: &Option<&i32> = &Some(&CONST_THRESHOLD);
+const REF_CONST: &Option<&i32> = &Some(CONST_THRESHOLD);
 
 type RefOptRefU32<'a> = &'a Option<&'a u32>;
 type RefOptRef<'a, T> = &'a Option<&'a T>;
diff --git a/src/tools/clippy/tests/ui/ref_option_ref.stderr b/src/tools/clippy/tests/ui/ref_option_ref.stderr
index 4e7fc800061..b61334758e8 100644
--- a/src/tools/clippy/tests/ui/ref_option_ref.stderr
+++ b/src/tools/clippy/tests/ui/ref_option_ref.stderr
@@ -9,7 +9,7 @@ LL | static REF_THRESHOLD: &Option<&i32> = &Some(&THRESHOLD);
 error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>`
   --> $DIR/ref_option_ref.rs:12:18
    |
-LL | const REF_CONST: &Option<&i32> = &Some(&CONST_THRESHOLD);
+LL | const REF_CONST: &Option<&i32> = &Some(CONST_THRESHOLD);
    |                  ^^^^^^^^^^^^^ help: try: `Option<&i32>`
 
 error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>`
diff --git a/src/tools/clippy/tests/ui/result_unit_error.stderr b/src/tools/clippy/tests/ui/result_unit_error.stderr
index 41d8b0a7cb7..8c7573eabda 100644
--- a/src/tools/clippy/tests/ui/result_unit_error.stderr
+++ b/src/tools/clippy/tests/ui/result_unit_error.stderr
@@ -1,43 +1,43 @@
-error: this returns a `Result<_, ()>
+error: this returns a `Result<_, ()>`
   --> $DIR/result_unit_error.rs:3:1
    |
 LL | pub fn returns_unit_error() -> Result<u32, ()> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::result-unit-err` implied by `-D warnings`
-   = help: use a custom Error type instead
+   = help: use a custom `Error` type instead
 
-error: this returns a `Result<_, ()>
+error: this returns a `Result<_, ()>`
   --> $DIR/result_unit_error.rs:12:5
    |
 LL |     fn get_that_error(&self) -> Result<bool, ()>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: use a custom Error type instead
+   = help: use a custom `Error` type instead
 
-error: this returns a `Result<_, ()>
+error: this returns a `Result<_, ()>`
   --> $DIR/result_unit_error.rs:14:5
    |
 LL |     fn get_this_one_too(&self) -> Result<bool, ()> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: use a custom Error type instead
+   = help: use a custom `Error` type instead
 
-error: this returns a `Result<_, ()>
+error: this returns a `Result<_, ()>`
   --> $DIR/result_unit_error.rs:32:5
    |
 LL |     pub fn unit_error(&self) -> Result<usize, ()> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: use a custom Error type instead
+   = help: use a custom `Error` type instead
 
-error: this returns a `Result<_, ()>
+error: this returns a `Result<_, ()>`
   --> $DIR/result_unit_error.rs:41:5
    |
 LL |     pub fn should_lint() -> ResInv<(), usize> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: use a custom Error type instead
+   = help: use a custom `Error` type instead
 
 error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/same_item_push.rs b/src/tools/clippy/tests/ui/same_item_push.rs
index a37c8782ec3..9d420ec672a 100644
--- a/src/tools/clippy/tests/ui/same_item_push.rs
+++ b/src/tools/clippy/tests/ui/same_item_push.rs
@@ -148,4 +148,11 @@ fn main() {
         };
         vec.push(item);
     }
+
+    // Fix #6987
+    let mut vec = Vec::new();
+    for _ in 0..10 {
+        vec.push(1);
+        vec.extend(&[2]);
+    }
 }
diff --git a/src/tools/clippy/tests/ui/stable_sort_primitive.fixed b/src/tools/clippy/tests/ui/stable_sort_primitive.fixed
index 8f8f5665931..f5f18169df2 100644
--- a/src/tools/clippy/tests/ui/stable_sort_primitive.fixed
+++ b/src/tools/clippy/tests/ui/stable_sort_primitive.fixed
@@ -20,7 +20,7 @@ fn main() {
     // Negative examples: behavior changes if made unstable
     let mut vec = vec![1, 3, 2];
     vec.sort_by_key(|i| i / 2);
-    vec.sort_by(|a, b| (a + b).cmp(&b));
+    vec.sort_by(|&a, &b| (a + b).cmp(&b));
     // negative examples - Not of a primitive type
     let mut vec_of_complex = vec![String::from("hello"), String::from("world!")];
     vec_of_complex.sort();
diff --git a/src/tools/clippy/tests/ui/stable_sort_primitive.rs b/src/tools/clippy/tests/ui/stable_sort_primitive.rs
index f9bd9779067..8149c5638e0 100644
--- a/src/tools/clippy/tests/ui/stable_sort_primitive.rs
+++ b/src/tools/clippy/tests/ui/stable_sort_primitive.rs
@@ -20,7 +20,7 @@ fn main() {
     // Negative examples: behavior changes if made unstable
     let mut vec = vec![1, 3, 2];
     vec.sort_by_key(|i| i / 2);
-    vec.sort_by(|a, b| (a + b).cmp(&b));
+    vec.sort_by(|&a, &b| (a + b).cmp(&b));
     // negative examples - Not of a primitive type
     let mut vec_of_complex = vec![String::from("hello"), String::from("world!")];
     vec_of_complex.sort();
diff --git a/src/tools/clippy/tests/ui/complex_types.rs b/src/tools/clippy/tests/ui/type_complexity.rs
index 383bbb49dbe..383bbb49dbe 100644
--- a/src/tools/clippy/tests/ui/complex_types.rs
+++ b/src/tools/clippy/tests/ui/type_complexity.rs
diff --git a/src/tools/clippy/tests/ui/complex_types.stderr b/src/tools/clippy/tests/ui/type_complexity.stderr
index 7fcbb4bce88..7879233fdf2 100644
--- a/src/tools/clippy/tests/ui/complex_types.stderr
+++ b/src/tools/clippy/tests/ui/type_complexity.stderr
@@ -1,5 +1,5 @@
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:7:12
+  --> $DIR/type_complexity.rs:7:12
    |
 LL | const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,85 +7,85 @@ LL | const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
    = note: `-D clippy::type-complexity` implied by `-D warnings`
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:8:12
+  --> $DIR/type_complexity.rs:8:12
    |
 LL | static ST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:11:8
+  --> $DIR/type_complexity.rs:11:8
    |
 LL |     f: Vec<Vec<Box<(u32, u32, u32, u32)>>>,
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:14:11
+  --> $DIR/type_complexity.rs:14:11
    |
 LL | struct Ts(Vec<Vec<Box<(u32, u32, u32, u32)>>>);
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:17:11
+  --> $DIR/type_complexity.rs:17:11
    |
 LL |     Tuple(Vec<Vec<Box<(u32, u32, u32, u32)>>>),
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:18:17
+  --> $DIR/type_complexity.rs:18:17
    |
 LL |     Struct { f: Vec<Vec<Box<(u32, u32, u32, u32)>>> },
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:22:14
+  --> $DIR/type_complexity.rs:22:14
    |
 LL |     const A: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:23:30
+  --> $DIR/type_complexity.rs:23:30
    |
 LL |     fn impl_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:27:14
+  --> $DIR/type_complexity.rs:27:14
    |
 LL |     const A: Vec<Vec<Box<(u32, u32, u32, u32)>>>;
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:28:14
+  --> $DIR/type_complexity.rs:28:14
    |
 LL |     type B = Vec<Vec<Box<(u32, u32, u32, u32)>>>;
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:29:25
+  --> $DIR/type_complexity.rs:29:25
    |
 LL |     fn method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>);
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:30:29
+  --> $DIR/type_complexity.rs:30:29
    |
 LL |     fn def_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:33:15
+  --> $DIR/type_complexity.rs:33:15
    |
 LL | fn test1() -> Vec<Vec<Box<(u32, u32, u32, u32)>>> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:37:14
+  --> $DIR/type_complexity.rs:37:14
    |
 LL | fn test2(_x: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:40:13
+  --> $DIR/type_complexity.rs:40:13
    |
 LL |     let _y: Vec<Vec<Box<(u32, u32, u32, u32)>>> = vec![];
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/upper_case_acronyms.rs b/src/tools/clippy/tests/ui/upper_case_acronyms.rs
index 8c09c6f5b23..48bb9e54b12 100644
--- a/src/tools/clippy/tests/ui/upper_case_acronyms.rs
+++ b/src/tools/clippy/tests/ui/upper_case_acronyms.rs
@@ -24,4 +24,18 @@ struct GCCLLVMSomething;
 pub struct NOWARNINGHERE;
 pub struct ALSONoWarningHERE;
 
+// enum variants should not be linted if the num is pub
+pub enum ParseError<T> {
+    YDB(u8),
+    Utf8(std::string::FromUtf8Error),
+    Parse(T, String),
+}
+
+// private, do lint here
+enum ParseErrorPrivate<T> {
+    WASD(u8),
+    Utf8(std::string::FromUtf8Error),
+    Parse(T, String),
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/upper_case_acronyms.stderr b/src/tools/clippy/tests/ui/upper_case_acronyms.stderr
index bbe38991e52..250b196a99e 100644
--- a/src/tools/clippy/tests/ui/upper_case_acronyms.stderr
+++ b/src/tools/clippy/tests/ui/upper_case_acronyms.stderr
@@ -48,5 +48,11 @@ error: name `FIN` contains a capitalized acronym
 LL |     FIN,
    |     ^^^ help: consider making the acronym lowercase, except the initial letter: `Fin`
 
-error: aborting due to 8 previous errors
+error: name `WASD` contains a capitalized acronym
+  --> $DIR/upper_case_acronyms.rs:36:5
+   |
+LL |     WASD(u8),
+   |     ^^^^ help: consider making the acronym lowercase, except the initial letter: `Wasd`
+
+error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui/vec.fixed b/src/tools/clippy/tests/ui/vec.fixed
index 85677159620..da35f2e5c1b 100644
--- a/src/tools/clippy/tests/ui/vec.fixed
+++ b/src/tools/clippy/tests/ui/vec.fixed
@@ -6,9 +6,14 @@
 struct NonCopy;
 
 fn on_slice(_: &[u8]) {}
+
+fn on_mut_slice(_: &mut [u8]) {}
+
 #[allow(clippy::ptr_arg)]
 fn on_vec(_: &Vec<u8>) {}
 
+fn on_mut_vec(_: &mut Vec<u8>) {}
+
 struct Line {
     length: usize,
 }
@@ -22,28 +27,38 @@ impl Line {
 fn main() {
     on_slice(&[]);
     on_slice(&[]);
+    on_mut_slice(&mut []);
 
     on_slice(&[1, 2]);
     on_slice(&[1, 2]);
+    on_mut_slice(&mut [1, 2]);
 
     on_slice(&[1, 2]);
     on_slice(&[1, 2]);
+    on_mut_slice(&mut [1, 2]);
     #[rustfmt::skip]
     on_slice(&[1, 2]);
     on_slice(&[1, 2]);
+    on_mut_slice(&mut [1, 2]);
 
     on_slice(&[1; 2]);
     on_slice(&[1; 2]);
+    on_mut_slice(&mut [1; 2]);
 
     on_vec(&vec![]);
     on_vec(&vec![1, 2]);
     on_vec(&vec![1; 2]);
+    on_mut_vec(&mut vec![]);
+    on_mut_vec(&mut vec![1, 2]);
+    on_mut_vec(&mut vec![1; 2]);
 
     // Now with non-constant expressions
     let line = Line { length: 2 };
 
     on_slice(&vec![2; line.length]);
     on_slice(&vec![2; line.length()]);
+    on_mut_slice(&mut vec![2; line.length]);
+    on_mut_slice(&mut vec![2; line.length()]);
 
     for a in &[1, 2, 3] {
         println!("{:?}", a);
@@ -54,6 +69,7 @@ fn main() {
     }
 
     on_vec(&vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack`
+    on_mut_vec(&mut vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack`
 
     // Ok
     for a in vec![1; 201] {
diff --git a/src/tools/clippy/tests/ui/vec.rs b/src/tools/clippy/tests/ui/vec.rs
index 03b8ee81665..e9ed83e5c5a 100644
--- a/src/tools/clippy/tests/ui/vec.rs
+++ b/src/tools/clippy/tests/ui/vec.rs
@@ -6,9 +6,14 @@
 struct NonCopy;
 
 fn on_slice(_: &[u8]) {}
+
+fn on_mut_slice(_: &mut [u8]) {}
+
 #[allow(clippy::ptr_arg)]
 fn on_vec(_: &Vec<u8>) {}
 
+fn on_mut_vec(_: &mut Vec<u8>) {}
+
 struct Line {
     length: usize,
 }
@@ -22,28 +27,38 @@ impl Line {
 fn main() {
     on_slice(&vec![]);
     on_slice(&[]);
+    on_mut_slice(&mut vec![]);
 
     on_slice(&vec![1, 2]);
     on_slice(&[1, 2]);
+    on_mut_slice(&mut vec![1, 2]);
 
     on_slice(&vec![1, 2]);
     on_slice(&[1, 2]);
+    on_mut_slice(&mut vec![1, 2]);
     #[rustfmt::skip]
     on_slice(&vec!(1, 2));
     on_slice(&[1, 2]);
+    on_mut_slice(&mut vec![1, 2]);
 
     on_slice(&vec![1; 2]);
     on_slice(&[1; 2]);
+    on_mut_slice(&mut vec![1; 2]);
 
     on_vec(&vec![]);
     on_vec(&vec![1, 2]);
     on_vec(&vec![1; 2]);
+    on_mut_vec(&mut vec![]);
+    on_mut_vec(&mut vec![1, 2]);
+    on_mut_vec(&mut vec![1; 2]);
 
     // Now with non-constant expressions
     let line = Line { length: 2 };
 
     on_slice(&vec![2; line.length]);
     on_slice(&vec![2; line.length()]);
+    on_mut_slice(&mut vec![2; line.length]);
+    on_mut_slice(&mut vec![2; line.length()]);
 
     for a in vec![1, 2, 3] {
         println!("{:?}", a);
@@ -54,6 +69,7 @@ fn main() {
     }
 
     on_vec(&vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack`
+    on_mut_vec(&mut vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack`
 
     // Ok
     for a in vec![1; 201] {
diff --git a/src/tools/clippy/tests/ui/vec.stderr b/src/tools/clippy/tests/ui/vec.stderr
index 37e28ebddb5..7d1de05a5c8 100644
--- a/src/tools/clippy/tests/ui/vec.stderr
+++ b/src/tools/clippy/tests/ui/vec.stderr
@@ -1,5 +1,5 @@
 error: useless use of `vec!`
-  --> $DIR/vec.rs:23:14
+  --> $DIR/vec.rs:28:14
    |
 LL |     on_slice(&vec![]);
    |              ^^^^^^^ help: you can use a slice directly: `&[]`
@@ -7,34 +7,64 @@ LL |     on_slice(&vec![]);
    = note: `-D clippy::useless-vec` implied by `-D warnings`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:26:14
+  --> $DIR/vec.rs:30:18
+   |
+LL |     on_mut_slice(&mut vec![]);
+   |                  ^^^^^^^^^^^ help: you can use a slice directly: `&mut []`
+
+error: useless use of `vec!`
+  --> $DIR/vec.rs:32:14
    |
 LL |     on_slice(&vec![1, 2]);
    |              ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:29:14
+  --> $DIR/vec.rs:34:18
+   |
+LL |     on_mut_slice(&mut vec![1, 2]);
+   |                  ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]`
+
+error: useless use of `vec!`
+  --> $DIR/vec.rs:36:14
    |
 LL |     on_slice(&vec![1, 2]);
    |              ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:32:14
+  --> $DIR/vec.rs:38:18
+   |
+LL |     on_mut_slice(&mut vec![1, 2]);
+   |                  ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]`
+
+error: useless use of `vec!`
+  --> $DIR/vec.rs:40:14
    |
 LL |     on_slice(&vec!(1, 2));
    |              ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:35:14
+  --> $DIR/vec.rs:42:18
+   |
+LL |     on_mut_slice(&mut vec![1, 2]);
+   |                  ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]`
+
+error: useless use of `vec!`
+  --> $DIR/vec.rs:44:14
    |
 LL |     on_slice(&vec![1; 2]);
    |              ^^^^^^^^^^^ help: you can use a slice directly: `&[1; 2]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:48:14
+  --> $DIR/vec.rs:46:18
+   |
+LL |     on_mut_slice(&mut vec![1; 2]);
+   |                  ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1; 2]`
+
+error: useless use of `vec!`
+  --> $DIR/vec.rs:63:14
    |
 LL |     for a in vec![1, 2, 3] {
    |              ^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2, 3]`
 
-error: aborting due to 6 previous errors
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/vec_box_sized.fixed b/src/tools/clippy/tests/ui/vec_box_sized.fixed
index 4fa28b525c3..a40d91fdb18 100644
--- a/src/tools/clippy/tests/ui/vec_box_sized.fixed
+++ b/src/tools/clippy/tests/ui/vec_box_sized.fixed
@@ -9,6 +9,8 @@ struct BigStruct([i32; 10000]);
 /// The following should trigger the lint
 mod should_trigger {
     use super::SizedStruct;
+    const C: Vec<i32> = Vec::new();
+    static S: Vec<i32> = Vec::new();
 
     struct StructWithVecBox {
         sized_type: Vec<SizedStruct>,
diff --git a/src/tools/clippy/tests/ui/vec_box_sized.rs b/src/tools/clippy/tests/ui/vec_box_sized.rs
index 7dc735cd90b..843bbb64e71 100644
--- a/src/tools/clippy/tests/ui/vec_box_sized.rs
+++ b/src/tools/clippy/tests/ui/vec_box_sized.rs
@@ -9,6 +9,8 @@ struct BigStruct([i32; 10000]);
 /// The following should trigger the lint
 mod should_trigger {
     use super::SizedStruct;
+    const C: Vec<Box<i32>> = Vec::new();
+    static S: Vec<Box<i32>> = Vec::new();
 
     struct StructWithVecBox {
         sized_type: Vec<Box<SizedStruct>>,
diff --git a/src/tools/clippy/tests/ui/vec_box_sized.stderr b/src/tools/clippy/tests/ui/vec_box_sized.stderr
index 83435a40aa1..c518267f041 100644
--- a/src/tools/clippy/tests/ui/vec_box_sized.stderr
+++ b/src/tools/clippy/tests/ui/vec_box_sized.stderr
@@ -1,28 +1,40 @@
 error: `Vec<T>` is already on the heap, the boxing is unnecessary
-  --> $DIR/vec_box_sized.rs:14:21
+  --> $DIR/vec_box_sized.rs:12:14
    |
-LL |         sized_type: Vec<Box<SizedStruct>>,
-   |                     ^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec<SizedStruct>`
+LL |     const C: Vec<Box<i32>> = Vec::new();
+   |              ^^^^^^^^^^^^^ help: try: `Vec<i32>`
    |
    = note: `-D clippy::vec-box` implied by `-D warnings`
 
 error: `Vec<T>` is already on the heap, the boxing is unnecessary
-  --> $DIR/vec_box_sized.rs:17:14
+  --> $DIR/vec_box_sized.rs:13:15
+   |
+LL |     static S: Vec<Box<i32>> = Vec::new();
+   |               ^^^^^^^^^^^^^ help: try: `Vec<i32>`
+
+error: `Vec<T>` is already on the heap, the boxing is unnecessary
+  --> $DIR/vec_box_sized.rs:16:21
+   |
+LL |         sized_type: Vec<Box<SizedStruct>>,
+   |                     ^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec<SizedStruct>`
+
+error: `Vec<T>` is already on the heap, the boxing is unnecessary
+  --> $DIR/vec_box_sized.rs:19:14
    |
 LL |     struct A(Vec<Box<SizedStruct>>);
    |              ^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec<SizedStruct>`
 
 error: `Vec<T>` is already on the heap, the boxing is unnecessary
-  --> $DIR/vec_box_sized.rs:18:18
+  --> $DIR/vec_box_sized.rs:20:18
    |
 LL |     struct B(Vec<Vec<Box<(u32)>>>);
    |                  ^^^^^^^^^^^^^^^ help: try: `Vec<u32>`
 
 error: `Vec<T>` is already on the heap, the boxing is unnecessary
-  --> $DIR/vec_box_sized.rs:46:23
+  --> $DIR/vec_box_sized.rs:48:23
    |
 LL |         pub fn f() -> Vec<Box<S>> {
    |                       ^^^^^^^^^^^ help: try: `Vec<S>`
 
-error: aborting due to 4 previous errors
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/wrong_self_convention.rs b/src/tools/clippy/tests/ui/wrong_self_convention.rs
index ba9e19a1722..cdfbdb8b0db 100644
--- a/src/tools/clippy/tests/ui/wrong_self_convention.rs
+++ b/src/tools/clippy/tests/ui/wrong_self_convention.rs
@@ -165,15 +165,10 @@ mod issue6307 {
 }
 
 mod issue6727 {
-    trait ToU64 {
-        fn to_u64(self) -> u64;
-        fn to_u64_v2(&self) -> u64;
-    }
-
     #[derive(Clone, Copy)]
     struct FooCopy;
 
-    impl ToU64 for FooCopy {
+    impl FooCopy {
         fn to_u64(self) -> u64 {
             1
         }
@@ -185,7 +180,7 @@ mod issue6727 {
 
     struct FooNoCopy;
 
-    impl ToU64 for FooNoCopy {
+    impl FooNoCopy {
         // trigger lint
         fn to_u64(self) -> u64 {
             2
diff --git a/src/tools/clippy/tests/ui/wrong_self_convention.stderr b/src/tools/clippy/tests/ui/wrong_self_convention.stderr
index 1d58a12ac79..29f5ba82695 100644
--- a/src/tools/clippy/tests/ui/wrong_self_convention.stderr
+++ b/src/tools/clippy/tests/ui/wrong_self_convention.stderr
@@ -176,7 +176,7 @@ LL |         fn from_i32(self);
    = help: consider choosing a less ambiguous name
 
 error: methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:181:22
+  --> $DIR/wrong_self_convention.rs:176:22
    |
 LL |         fn to_u64_v2(&self) -> u64 {
    |                      ^^^^^
@@ -184,7 +184,7 @@ LL |         fn to_u64_v2(&self) -> u64 {
    = help: consider choosing a less ambiguous name
 
 error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
-  --> $DIR/wrong_self_convention.rs:190:19
+  --> $DIR/wrong_self_convention.rs:185:19
    |
 LL |         fn to_u64(self) -> u64 {
    |                   ^^^^
diff --git a/src/tools/clippy/tests/ui/wrong_self_convention2.rs b/src/tools/clippy/tests/ui/wrong_self_convention2.rs
new file mode 100644
index 00000000000..8b42aa59e13
--- /dev/null
+++ b/src/tools/clippy/tests/ui/wrong_self_convention2.rs
@@ -0,0 +1,32 @@
+// edition:2018
+#![warn(clippy::wrong_self_convention)]
+#![warn(clippy::wrong_pub_self_convention)]
+#![allow(dead_code)]
+
+fn main() {}
+
+mod issue6983 {
+    pub struct Thing;
+    pub trait Trait {
+        fn to_thing(&self) -> Thing;
+    }
+
+    impl Trait for u8 {
+        // don't trigger, e.g. `ToString` from `std` requires `&self`
+        fn to_thing(&self) -> Thing {
+            Thing
+        }
+    }
+
+    trait ToU64 {
+        fn to_u64(self) -> u64;
+    }
+
+    struct FooNoCopy;
+    // trigger lint
+    impl ToU64 for FooNoCopy {
+        fn to_u64(self) -> u64 {
+            2
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/wrong_self_convention2.stderr b/src/tools/clippy/tests/ui/wrong_self_convention2.stderr
new file mode 100644
index 00000000000..0ca1a390974
--- /dev/null
+++ b/src/tools/clippy/tests/ui/wrong_self_convention2.stderr
@@ -0,0 +1,11 @@
+error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
+  --> $DIR/wrong_self_convention2.rs:28:19
+   |
+LL |         fn to_u64(self) -> u64 {
+   |                   ^^^^
+   |
+   = note: `-D clippy::wrong-self-convention` implied by `-D warnings`
+   = help: consider choosing a less ambiguous name
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/util/gh-pages/index.html b/src/tools/clippy/util/gh-pages/index.html
index 1852fb6640e..082cb35c2e0 100644
--- a/src/tools/clippy/util/gh-pages/index.html
+++ b/src/tools/clippy/util/gh-pages/index.html
@@ -8,6 +8,12 @@
 
     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css"/>
     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.5.0/styles/github.min.css"/>
+
+    <!-- The files are not copied over into the Clippy project since they use the MPL-2.0 License -->
+    <link rel="stylesheet" href="https://rust-lang.github.io/mdBook/css/variables.css"/>
+    <link id="styleHighlight" rel="stylesheet" href="https://rust-lang.github.io/mdBook/highlight.css">
+    <link id="styleNight" rel="stylesheet" href="https://rust-lang.github.io/mdBook/tomorrow-night.css" disabled="true">
+    <link id="styleAyu" rel="stylesheet" href="https://rust-lang.github.io/mdBook/ayu-highlight.css" disabled="true">
     <style>
         blockquote { font-size: 1em; }
         [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { display: none !important; }
@@ -15,7 +21,6 @@
         .form-inline .checkbox { margin-right: 0.6em }
 
         .panel-heading { cursor: pointer; }
-        .panel-heading:hover { background-color: #eee; }
 
         .panel-title { display: flex; }
         .panel-title .label { display: inline-block; }
@@ -24,10 +29,134 @@
         .panel-title-name span { vertical-align: bottom; }
 
         .panel .panel-title-name .anchor { display: none; }
-        .panel:hover .panel-title-name .anchor { display: inline; color: #fff; }
+        .panel:hover .panel-title-name .anchor { display: inline;}
+
+    </style>
+    <style>
+        /* Expanding the mdBoom theme*/
+        .light {
+            --inline-code-bg: #f6f7f6;
+        }
+        .rust {
+            --inline-code-bg: #f6f7f6;
+        }
+        .coal {
+            --inline-code-bg: #1d1f21;
+        }
+        .navy {
+            --inline-code-bg: #1d1f21;
+        }
+        .ayu {
+            --inline-code-bg: #191f26;
+        }
+
+        /* Applying the mdBook theme */
+        .theme-icon {
+            position: absolute;
+            text-align: center;
+            width: 2em;
+            height: 2em;
+            margin: 0.7em;
+            line-height: 2em;
+            border: solid 1px var(--icons);
+            border-radius: 5px;
+            user-select: none;
+            cursor: pointer;
+        }
+        .theme-icon:hover {
+            background: var(--theme-hover);
+        }
+        .theme-choice {
+            position: absolute;
+            margin-top: calc(2em + 0.7em);
+            margin-left: 0.7em;
+            list-style: none;
+            border: 1px solid var(--theme-popup-border);
+            border-radius: 5px;
+            color: var(--fg);
+            background: var(--theme-popup-bg);
+            padding: 0 0;
+        }
+        .theme-choice > li {
+            padding: 5px 10px;
+            font-size: 0.8em;
+            user-select: none;
+            cursor: pointer;
+        }
+        .theme-choice > li:hover {
+            background: var(--theme-hover);
+        }
+
+        .alert {
+            color: var(--fg);
+            background: var(--theme-hover);
+            border: 1px solid var(--theme-popup-border);
+        }
+        .page-header {
+            border-color: var(--theme-popup-border);
+        }
+        .panel-default > .panel-heading {
+            background: var(--theme-hover);
+            color: var(--fg);
+            border: 1px solid var(--theme-popup-border);
+        }
+        .panel-default > .panel-heading:hover {
+            filter: brightness(90%);
+        }
+        .list-group-item {
+            background: 0%;
+            border: 1px solid var(--theme-popup-border);
+        }
+        .panel, pre, hr {
+            background: var(--bg);
+            border: 1px solid var(--theme-popup-border);
+        }
+
+        #filter-label, #filter-clear {
+            background: var(--searchbar-bg);
+            color: var(--searchbar-fg);
+            border-color: var(--theme-popup-border);
+            filter: brightness(95%);
+        }
+        #filter-label:hover, #filter-clear:hover {
+            filter: brightness(90%);
+        }
+        #filter-input {
+            background: var(--searchbar-bg);
+            color: var(--searchbar-fg);
+            border-color: var(--theme-popup-border);
+        }
+
+        #filter-input::-webkit-input-placeholder,
+        #filter-input::-moz-placeholder {
+            color: var(--searchbar-fg);
+            opacity: 30%;
+        }
+
+        p > code {
+            color: var(--inline-code-color);
+            background-color: var(--inline-code-bg);
+        }
+        html {
+            scrollbar-color: var(--scrollbar) var(--bg);
+        }
+        body {
+            background: var(--bg);
+            color: var(--fg);
+        }
+
     </style>
 </head>
 <body>
+    <div id="theme-icon" class="theme-icon">&#128396;</div>
+    <ul id="theme-menu" class="theme-choice" style="display: none;">
+        <li id="light">Light</li>
+        <li id="rust">Rust</li>
+        <li id="coal">Coal</li>
+        <li id="navy">Navy</li>
+        <li id="ayu">Ayu</li>
+    </ul>
+
     <div class="container" ng-app="clippy" ng-controller="lintList">
         <div class="page-header">
             <h1>ALL the Clippy Lints</h1>
@@ -49,7 +178,7 @@
             </div>
 
             <div class="panel panel-default" ng-show="data">
-                <div class="panel-body row">
+                <div class="panel-body row filter-panel">
                     <div class="col-md-6 form-inline">
                         <div class="form-group form-group-lg">
                             <p class="h4">Lint levels</p>
@@ -79,7 +208,7 @@
                             <label class="input-group-addon" id="filter-label" for="filter-input">Filter:</label>
                             <input type="text" class="form-control" placeholder="Keywords or search string" id="filter-input" ng-model="search" ng-model-options="{debounce: 50}"/>
                             <span class="input-group-btn">
-                                <button class="btn btn-default" type="button" ng-click="search = ''">
+                                <button id="filter-clear" class="btn" type="button" ng-click="search = ''">
                                     Clear
                                 </button>
                             </span>
@@ -320,6 +449,60 @@
             }
         }
     }
+
+    function setupListeners() {
+        let themeIcon = document.getElementById("theme-icon");
+        let themeMenu = document.getElementById("theme-menu");
+        themeIcon.addEventListener("click", function(e) {
+            if (themeMenu.style.display == "none") {
+                themeMenu.style.display = "block";
+            } else {
+                themeMenu.style.display = "none";
+            }
+        });
+
+        let children = themeMenu.children;
+        for (let index = 0; index < children.length; index++) {
+            let child = children[index]; 
+            child.addEventListener("click", function(e) {
+                setTheme(child.id, true);
+            });
+        }
+    }
+
+    setupListeners();
+
+    function setTheme(theme, store) {
+        let enableHighlight = false;
+        let enableNight = false;
+        let enableAyu = false;
+        
+        if (theme == "ayu") {
+            enableAyu = true;
+        } else if (theme == "coal" || theme == "navy") {
+            enableNight = true;
+        } else if (theme == "rust") {
+            enableHighlight = true;
+        } else {
+            enableHighlight = true;
+            // this makes sure that an unknown theme request gets set to a known one
+            theme = "light";
+        }
+        document.getElementsByTagName("body")[0].className = theme;
+
+        document.getElementById("styleHighlight").disabled = !enableHighlight;
+        document.getElementById("styleNight").disabled = !enableNight;
+        document.getElementById("styleAyu").disabled = !enableAyu;
+
+        if (store) {
+            try {
+                localStorage.setItem('clippy-lint-list-theme', theme);
+            } catch (e) { }
+        }
+    }
+
+    // loading the theme after the initial load
+    setTheme(localStorage.getItem('clippy-lint-list-theme'), false);
     </script>
 </body>
 </html>
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 7c8cd699fe0..ecbaccf744d 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1951,6 +1951,7 @@ impl<'test> TestCx<'test> {
                 if !self.props.compile_flags.iter().any(|s| s.starts_with("--error-format")) {
                     rustc.args(&["--error-format", "json"]);
                 }
+                rustc.arg("-Ccodegen-units=1");
                 rustc.arg("-Zui-testing");
                 rustc.arg("-Zdeduplicate-diagnostics=no");
                 rustc.arg("-Zemit-future-incompat-report");
diff --git a/src/tools/miri b/src/tools/miri
-Subproject 685ad70647c867944128f6c6bacf9483995eff7
+Subproject b9b2af9729243ab8d5b02cca2e19ce93cc23c1b