about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ci/github-actions/ci.yml12
-rw-r--r--src/doc/unstable-book/src/library-features/asm.md14
-rw-r--r--src/librustc_attr/Cargo.toml1
-rw-r--r--src/librustc_attr/builtin.rs12
-rw-r--r--src/librustc_codegen_llvm/builder.rs55
-rw-r--r--src/librustc_codegen_llvm/consts.rs10
-rw-r--r--src/librustc_codegen_ssa/back/link.rs39
-rw-r--r--src/librustc_data_structures/Cargo.toml1
-rw-r--r--src/librustc_data_structures/lib.rs1
-rw-r--r--src/librustc_data_structures/temp_dir.rs34
-rw-r--r--src/librustc_error_codes/error_codes/E0749.md12
-rw-r--r--src/librustc_error_codes/error_codes/E0751.md6
-rw-r--r--src/librustc_expand/proc_macro_server.rs10
-rw-r--r--src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs8
-rw-r--r--src/librustc_interface/passes.rs2
-rw-r--r--src/librustc_lexer/src/lib.rs10
-rw-r--r--src/librustc_lint/lib.rs2
-rw-r--r--src/librustc_lint/non_ascii_idents.rs90
-rw-r--r--src/librustc_lint/unused.rs36
-rw-r--r--src/librustc_middle/lib.rs1
-rw-r--r--src/librustc_middle/mir/interpret/allocation.rs24
-rw-r--r--src/librustc_middle/mir/interpret/error.rs169
-rw-r--r--src/librustc_middle/mir/interpret/mod.rs6
-rw-r--r--src/librustc_middle/mir/interpret/queries.rs23
-rw-r--r--src/librustc_middle/mir/interpret/value.rs2
-rw-r--r--src/librustc_middle/ty/flags.rs6
-rw-r--r--src/librustc_middle/ty/fold.rs6
-rw-r--r--src/librustc_middle/ty/instance.rs53
-rw-r--r--src/librustc_middle/ty/layout.rs26
-rw-r--r--src/librustc_middle/ty/mod.rs4
-rw-r--r--src/librustc_middle/ty/print/pretty.rs4
-rw-r--r--src/librustc_mir/const_eval/error.rs170
-rw-r--r--src/librustc_mir/const_eval/eval_queries.rs9
-rw-r--r--src/librustc_mir/const_eval/machine.rs13
-rw-r--r--src/librustc_mir/interpret/eval_context.rs97
-rw-r--r--src/librustc_mir/interpret/intrinsics/caller_location.rs3
-rw-r--r--src/librustc_mir/interpret/machine.rs8
-rw-r--r--src/librustc_mir/interpret/memory.rs26
-rw-r--r--src/librustc_mir/interpret/mod.rs4
-rw-r--r--src/librustc_mir/interpret/operand.rs2
-rw-r--r--src/librustc_mir/interpret/place.rs4
-rw-r--r--src/librustc_mir/interpret/step.rs10
-rw-r--r--src/librustc_mir/interpret/validity.rs8
-rw-r--r--src/librustc_mir/monomorphize/polymorphize.rs14
-rw-r--r--src/librustc_mir/transform/const_prop.rs40
-rw-r--r--src/librustc_mir/transform/mod.rs11
-rw-r--r--src/librustc_mir/util/pretty.rs6
-rw-r--r--src/librustc_parse/parser/expr.rs23
-rw-r--r--src/librustc_privacy/lib.rs17
-rw-r--r--src/librustc_resolve/diagnostics.rs47
-rw-r--r--src/librustc_resolve/late/diagnostics.rs220
-rw-r--r--src/librustc_resolve/late/lifetimes.rs47
-rw-r--r--src/librustc_serialize/collection_impls.rs24
-rw-r--r--src/librustc_serialize/json.rs88
-rw-r--r--src/librustc_serialize/opaque.rs4
-rw-r--r--src/librustc_session/parse.rs3
-rw-r--r--src/librustc_trait_selection/traits/auto_trait.rs7
-rw-r--r--src/librustc_typeck/check/cast.rs4
-rw-r--r--src/librustc_typeck/check/mod.rs18
-rw-r--r--src/librustc_typeck/check/pat.rs11
-rw-r--r--src/librustc_typeck/check/place_op.rs37
-rw-r--r--src/librustc_typeck/lib.rs5
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/librustdoc/clean/types.rs2
-rw-r--r--src/librustdoc/core.rs12
-rw-r--r--src/librustdoc/html/layout.rs3
-rw-r--r--src/librustdoc/html/render/mod.rs84
-rw-r--r--src/librustdoc/html/render/tests.rs38
-rw-r--r--src/librustdoc/html/static/main.js8
-rw-r--r--src/librustdoc/html/static/rustdoc.css18
-rw-r--r--src/librustdoc/html/static/themes/ayu.css12
-rw-r--r--src/librustdoc/html/static/themes/dark.css12
-rw-r--r--src/librustdoc/html/static/themes/light.css9
-rw-r--r--src/test/codegen-units/polymorphization/pr-75255.rs52
-rw-r--r--src/test/codegen/consts.rs4
-rw-r--r--src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.32bit30
-rw-r--r--src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.64bit32
-rw-r--r--src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff4
-rw-r--r--src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.32bit22
-rw-r--r--src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.64bit22
-rw-r--r--src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff9
-rw-r--r--src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff24
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff9
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff3
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff9
-rw-r--r--src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.32bit3
-rw-r--r--src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.64bit3
-rw-r--r--src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff9
-rw-r--r--src/test/mir-opt/const_prop_miscompile.bar.ConstProp.diff12
-rw-r--r--src/test/mir-opt/const_prop_miscompile.foo.ConstProp.diff12
-rw-r--r--src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff162
-rw-r--r--src/test/mir-opt/funky_arms.rs56
-rw-r--r--src/test/mir-opt/generator_storage_dead_unwind.main-{{closure}}.StateTransform.before.mir5
-rw-r--r--src/test/mir-opt/generator_tiny.main-{{closure}}.generator_resume.0.mir17
-rw-r--r--src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir12
-rw-r--r--src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir12
-rw-r--r--src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir13
-rw-r--r--src/test/mir-opt/issue_73223.main.PreCodegen.diff.32bit161
-rw-r--r--src/test/mir-opt/issue_73223.main.PreCodegen.diff.64bit161
-rw-r--r--src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.32bit16
-rw-r--r--src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.64bit16
-rw-r--r--src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.32bit9
-rw-r--r--src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.64bit9
-rw-r--r--src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff42
-rw-r--r--src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.32bit8
-rw-r--r--src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.64bit8
-rw-r--r--src/test/mir-opt/uninhabited_enum_branching.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir4
-rw-r--r--src/test/mir-opt/uninhabited_enum_branching.main.UninhabitedEnumBranching.diff4
-rw-r--r--src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.32bit84
-rw-r--r--src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.64bit84
-rw-r--r--src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.32bit33
-rw-r--r--src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.64bit33
-rw-r--r--src/test/mir-opt/while_let_loops.rs15
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/async.rs7
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/async.stderr12
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/closure.rs2
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/closure.stderr12
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs2
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/generic-argument.stderr12
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs2
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr12
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs2
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr12
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/realistic-async.rs28
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs2
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr12
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs2
-rw-r--r--src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr12
-rw-r--r--src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs15
-rw-r--r--src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr17
-rw-r--r--src/test/rustdoc-ui/infinite-recursive-type-impl-trait.rs7
-rw-r--r--src/test/rustdoc-ui/infinite-recursive-type-impl-trait.stderr17
-rw-r--r--src/test/rustdoc/synthetic_auto/issue-72213-projection-lifetime.rs25
-rw-r--r--src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr5
-rw-r--r--src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr5
-rw-r--r--src/test/ui/const-generics/struct-with-invalid-const-param.stderr5
-rw-r--r--src/test/ui/const-generics/unused_braces.fixed2
-rw-r--r--src/test/ui/consts/const-err-multi.stderr10
-rw-r--r--src/test/ui/consts/const-eval/erroneous-const.rs20
-rw-r--r--src/test/ui/consts/const-eval/erroneous-const.stderr41
-rw-r--r--src/test/ui/consts/uninhabited-const-issue-61744.rs4
-rw-r--r--src/test/ui/consts/uninhabited-const-issue-61744.stderr9
-rw-r--r--src/test/ui/empty/empty-struct-braces-expr.stderr44
-rw-r--r--src/test/ui/empty/empty-struct-braces-pat-1.stderr12
-rw-r--r--src/test/ui/empty/empty-struct-braces-pat-2.stderr50
-rw-r--r--src/test/ui/empty/empty-struct-braces-pat-3.stderr28
-rw-r--r--src/test/ui/empty/empty-struct-tuple-pat.stderr18
-rw-r--r--src/test/ui/error-codes/E0106.stderr9
-rw-r--r--src/test/ui/error-codes/E0423.stderr13
-rw-r--r--src/test/ui/hygiene/rustc-macro-transparency.stderr4
-rw-r--r--src/test/ui/issues/issue-17800.rs2
-rw-r--r--src/test/ui/issues/issue-17800.stderr11
-rw-r--r--src/test/ui/issues/issue-31845.stderr4
-rw-r--r--src/test/ui/issues/issue-32004.stderr14
-rw-r--r--src/test/ui/issues/issue-63983.stderr2
-rw-r--r--src/test/ui/issues/issue-64792-bad-unicode-ctor.stderr11
-rw-r--r--src/test/ui/issues/issue-74739.rs14
-rw-r--r--src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs2
-rw-r--r--src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr13
-rw-r--r--src/test/ui/lint/unused_braces.fixed8
-rw-r--r--src/test/ui/lint/unused_braces_borrow.fixed2
-rw-r--r--src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs28
-rw-r--r--src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr30
-rw-r--r--src/test/ui/mismatched_types/issue-75361-mismatched-impl.rs24
-rw-r--r--src/test/ui/mismatched_types/issue-75361-mismatched-impl.stderr19
-rw-r--r--src/test/ui/namespace/namespace-mix.stderr20
-rw-r--r--src/test/ui/parser/recover-from-bad-variant.rs3
-rw-r--r--src/test/ui/parser/recover-from-bad-variant.stderr11
-rw-r--r--src/test/ui/polymorphization/promoted-function-3.rs14
-rw-r--r--src/test/ui/print_type_sizes/niche-filling.stdout6
-rw-r--r--src/test/ui/privacy/legacy-ctor-visibility.stderr4
-rw-r--r--src/test/ui/proc-macro/attributes-on-modules-fail.stderr12
-rw-r--r--src/test/ui/resolve/issue-19452.stderr5
-rw-r--r--src/test/ui/resolve/issue-39226.stderr8
-rw-r--r--src/test/ui/resolve/privacy-enum-ctor.stderr15
-rw-r--r--src/test/ui/resolve/resolve-hint-macro.stderr2
-rw-r--r--src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr16
-rw-r--r--src/test/ui/struct-literal-variant-in-if.stderr2
-rw-r--r--src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr8
-rw-r--r--src/test/ui/suggestions/js-style-comparison-op-separate-eq-token.rs5
-rw-r--r--src/test/ui/suggestions/js-style-comparison-op-separate-eq-token.stderr8
-rw-r--r--src/test/ui/suggestions/js-style-comparison-op.fixed8
-rw-r--r--src/test/ui/suggestions/js-style-comparison-op.rs8
-rw-r--r--src/test/ui/suggestions/js-style-comparison-op.stderr14
-rw-r--r--src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.rs16
-rw-r--r--src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr73
-rw-r--r--src/test/ui/suggestions/missing-lt-for-hrtb.rs15
-rw-r--r--src/test/ui/suggestions/missing-lt-for-hrtb.stderr63
-rw-r--r--src/test/ui/try-block/try-block-in-edition2015.stderr2
-rw-r--r--src/test/ui/try-block/try-block-unused-delims.fixed2
-rw-r--r--src/test/ui/type-sizes.rs25
-rw-r--r--src/test/ui/type/type-ascription-with-fn-call.stderr5
-rw-r--r--src/test/ui/typeck/issue-74933.rs38
-rw-r--r--src/test/ui/ui-testing-optout.stderr5
-rw-r--r--src/test/ui/xcrate/xcrate-unit-struct.stderr5
-rw-r--r--src/tools/clippy/CHANGELOG.md10
-rw-r--r--src/tools/clippy/CONTRIBUTING.md27
-rw-r--r--src/tools/clippy/clippy_dev/src/ra_setup.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/bytecount.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/checked_conversions.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/consts.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/default_trait_access.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs120
-rw-r--r--src/tools/clippy/clippy_lints/src/double_comparison.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/double_parens.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/drop_bounds.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/functions.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs25
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/loops.rs351
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_async_fn.rs63
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs67
-rw-r--r--src/tools/clippy/clippy_lints/src/minmax.rs55
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs118
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_bool.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/neg_multiply.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/ranges.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/reference.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/shadow.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs130
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs41
-rw-r--r--src/tools/clippy/clippy_lints/src/trait_bounds.rs94
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute.rs107
-rw-r--r--src/tools/clippy/clippy_lints/src/try_err.rs112
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs6
-rw-r--r--[-rwxr-xr-x]src/tools/clippy/clippy_lints/src/utils/ast_utils.rs0
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/attrs.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/mod.rs54
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/paths.rs2
-rw-r--r--src/tools/clippy/doc/adding_lints.md21
-rw-r--r--src/tools/clippy/doc/basics.md112
-rw-r--r--src/tools/clippy/src/lintlist/mod.rs44
-rw-r--r--src/tools/clippy/tests/compile-test.rs11
-rw-r--r--src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr4
-rw-r--r--src/tools/clippy/tests/ui/await_holding_lock.rs1
-rw-r--r--src/tools/clippy/tests/ui/await_holding_lock.stderr4
-rw-r--r--src/tools/clippy/tests/ui/bool_comparison.stderr8
-rw-r--r--src/tools/clippy/tests/ui/builtin-type-shadow.stderr2
-rw-r--r--src/tools/clippy/tests/ui/bytecount.stderr12
-rw-r--r--src/tools/clippy/tests/ui/checked_conversions.stderr32
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr40
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.stderr4
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr26
-rw-r--r--src/tools/clippy/tests/ui/cmp_null.stderr4
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-5872.rs5
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-5872.stderr10
-rw-r--r--src/tools/clippy/tests/ui/default_trait_access.stderr16
-rw-r--r--src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.rs68
-rw-r--r--src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr71
-rw-r--r--src/tools/clippy/tests/ui/double_comparison.stderr16
-rw-r--r--src/tools/clippy/tests/ui/double_parens.stderr12
-rw-r--r--src/tools/clippy/tests/ui/drop_bounds.stderr4
-rw-r--r--src/tools/clippy/tests/ui/empty_line_after_outer_attribute.stderr12
-rw-r--r--src/tools/clippy/tests/ui/extra_unused_lifetimes.rs8
-rw-r--r--src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr8
-rw-r--r--src/tools/clippy/tests/ui/functions_maxlines.stderr2
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_next.fixed22
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_next.rs8
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_next.stderr23
-rw-r--r--src/tools/clippy/tests/ui/len_without_is_empty.rs40
-rw-r--r--src/tools/clippy/tests/ui/len_without_is_empty.stderr8
-rw-r--r--src/tools/clippy/tests/ui/len_zero.fixed20
-rw-r--r--src/tools/clippy/tests/ui/len_zero.rs20
-rw-r--r--src/tools/clippy/tests/ui/manual_async_fn.fixed40
-rw-r--r--src/tools/clippy/tests/ui/manual_async_fn.rs48
-rw-r--r--src/tools/clippy/tests/ui/manual_async_fn.stderr30
-rw-r--r--src/tools/clippy/tests/ui/map_flatten.fixed14
-rw-r--r--src/tools/clippy/tests/ui/map_flatten.rs14
-rw-r--r--src/tools/clippy/tests/ui/map_flatten.stderr40
-rw-r--r--src/tools/clippy/tests/ui/min_max.rs32
-rw-r--r--src/tools/clippy/tests/ui/min_max.stderr52
-rw-r--r--src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed69
-rw-r--r--src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs69
-rw-r--r--src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr40
-rw-r--r--src/tools/clippy/tests/ui/needless_collect.fixed4
-rw-r--r--src/tools/clippy/tests/ui/needless_collect.rs2
-rw-r--r--src/tools/clippy/tests/ui/needless_collect.stderr4
-rw-r--r--src/tools/clippy/tests/ui/needless_collect_indirect.rs19
-rw-r--r--src/tools/clippy/tests/ui/needless_collect_indirect.stderr55
-rw-r--r--src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr8
-rw-r--r--src/tools/clippy/tests/ui/neg_multiply.stderr4
-rw-r--r--src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed4
-rw-r--r--src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs4
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.fixed8
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.rs8
-rw-r--r--src/tools/clippy/tests/ui/overflow_check_conditional.stderr16
-rw-r--r--src/tools/clippy/tests/ui/path_buf_push_overwrite.stderr2
-rw-r--r--src/tools/clippy/tests/ui/range.stderr2
-rw-r--r--src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr32
-rw-r--r--src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.stderr20
-rw-r--r--src/tools/clippy/tests/ui/renamed_builtin_attr.stderr2
-rw-r--r--src/tools/clippy/tests/ui/result_map_unit_fn_fixable.fixed4
-rw-r--r--src/tools/clippy/tests/ui/result_map_unit_fn_fixable.rs4
-rw-r--r--src/tools/clippy/tests/ui/same_item_push.rs89
-rw-r--r--src/tools/clippy/tests/ui/same_item_push.stderr35
-rw-r--r--src/tools/clippy/tests/ui/stable_sort_primitive.fixed32
-rw-r--r--src/tools/clippy/tests/ui/stable_sort_primitive.rs32
-rw-r--r--src/tools/clippy/tests/ui/stable_sort_primitive.stderr46
-rw-r--r--src/tools/clippy/tests/ui/suspicious_arithmetic_impl.rs30
-rw-r--r--src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr6
-rw-r--r--src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs31
-rw-r--r--src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr23
-rw-r--r--src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed78
-rw-r--r--src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs78
-rw-r--r--src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr56
-rw-r--r--src/tools/clippy/tests/ui/try_err.fixed21
-rw-r--r--src/tools/clippy/tests/ui/try_err.rs21
-rw-r--r--src/tools/clippy/tests/ui/try_err.stderr30
-rw-r--r--src/tools/clippy/tests/ui/unknown_attribute.stderr2
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_ref.stderr2
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_sort_by.fixed2
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_sort_by.rs2
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_sort_by.stderr14
-rw-r--r--src/tools/clippy/tests/ui/unneeded_field_pattern.stderr8
-rw-r--r--src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs10
-rwxr-xr-xsrc/tools/publish_toolstate.py5
m---------src/tools/rls0
m---------src/tools/rustfmt23
-rw-r--r--src/tools/tidy/src/style.rs2
327 files changed, 5742 insertions, 1986 deletions
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index 0ff77de003d..165ecc79180 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -490,15 +490,17 @@ jobs:
 
           # 32/64-bit MinGW builds.
           #
-          # We are using MinGW with posix threads since LLVM does not compile with
-          # the win32 threads version due to missing support for C++'s std::thread.
+          # We are using MinGW with POSIX threads since LLVM requires
+          # C++'s std::thread which is disabled in libstdc++ with win32 threads.
+          # FIXME: Libc++ doesn't have this limitation so we can avoid 
+          # winpthreads if we switch to it.
           #
-          # Instead of relying on the MinGW version installed on appveryor we download
-          # and install one ourselves so we won't be surprised by changes to appveyor's
+          # Instead of relying on the MinGW version installed on CI we download
+          # and install one ourselves so we won't be surprised by changes to CI's
           # build image.
           #
           # Finally, note that the downloads below are all in the `rust-lang-ci` S3
-          # bucket, but they cleraly didn't originate there! The downloads originally
+          # bucket, but they clearly didn't originate there! The downloads originally
           # came from the mingw-w64 SourceForge download site. Unfortunately
           # SourceForge is notoriously flaky, so we mirror it on our own infrastructure.
 
diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md
index c4c985dd134..28a5fe31fc4 100644
--- a/src/doc/unstable-book/src/library-features/asm.md
+++ b/src/doc/unstable-book/src/library-features/asm.md
@@ -18,7 +18,15 @@ It can be used to embed handwritten assembly in the assembly output generated by
 Generally this should not be necessary, but might be where the required performance or timing
 cannot be otherwise achieved. Accessing low level hardware primitives, e.g. in kernel code, may also demand this functionality.
 
-> **Note**: the examples here are given in x86/x86-64 assembly, but ARM, AArch64 and RISC-V are also supported.
+> **Note**: the examples here are given in x86/x86-64 assembly, but other architectures are also supported.
+
+Inline assembly is currently supported on the following architectures:
+- x86 and x86-64
+- ARM
+- AArch64
+- RISC-V
+- NVPTX
+- Hexagon
 
 ## Basic usage
 
@@ -606,6 +614,10 @@ Some registers cannot be used for input or output operands:
 | RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. |
 | Hexagon | `lr` | This is the link register which cannot be used as an input or output. |
 
+In some cases LLVM will allocate a "reserved register" for `reg` operands even though this register cannot be explicitly specified. Assembly code making use of reserved registers should be careful since `reg` operands may alias with those registers. Reserved registers are:
+- The frame pointer on all architectures.
+- `r6` on ARM.
+
 ## Template modifiers
 
 The placeholders can be augmented by modifiers which are specified after the `:` in the curly braces. These modifiers do not affect register allocation, but change the way operands are formatted when inserted into the template string. Only one modifier is allowed per template placeholder.
diff --git a/src/librustc_attr/Cargo.toml b/src/librustc_attr/Cargo.toml
index 496becb8f1b..35bdf747f08 100644
--- a/src/librustc_attr/Cargo.toml
+++ b/src/librustc_attr/Cargo.toml
@@ -16,6 +16,7 @@ rustc_errors = { path = "../librustc_errors" }
 rustc_span = { path = "../librustc_span" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_feature = { path = "../librustc_feature" }
+rustc_lexer = { path = "../librustc_lexer" }
 rustc_macros = { path = "../librustc_macros" }
 rustc_session = { path = "../librustc_session" }
 rustc_ast = { path = "../librustc_ast" }
diff --git a/src/librustc_attr/builtin.rs b/src/librustc_attr/builtin.rs
index 552584bb4d0..5f131fae385 100644
--- a/src/librustc_attr/builtin.rs
+++ b/src/librustc_attr/builtin.rs
@@ -20,6 +20,7 @@ enum AttrError {
     MultipleItem(String),
     UnknownMetaItem(String, &'static [&'static str]),
     MissingSince,
+    NonIdentFeature,
     MissingFeature,
     MultipleStabilityLevels,
     UnsupportedLiteral(&'static str, /* is_bytestr */ bool),
@@ -40,6 +41,9 @@ fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
         AttrError::MissingSince => {
             struct_span_err!(diag, span, E0542, "missing 'since'").emit();
         }
+        AttrError::NonIdentFeature => {
+            struct_span_err!(diag, span, E0546, "'feature' is not an identifier").emit();
+        }
         AttrError::MissingFeature => {
             struct_span_err!(diag, span, E0546, "missing 'feature'").emit();
         }
@@ -344,6 +348,14 @@ where
 
                     match (feature, reason, issue) {
                         (Some(feature), reason, Some(_)) => {
+                            if !rustc_lexer::is_ident(&feature.as_str()) {
+                                handle_errors(
+                                    &sess.parse_sess,
+                                    attr.span,
+                                    AttrError::NonIdentFeature,
+                                );
+                                continue;
+                            }
                             let level = Unstable { reason, issue: issue_num, is_soft };
                             if sym::unstable == meta_name {
                                 stab = Some(Stability { level, feature });
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index 1124e91bf71..a0f4311b33a 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -728,20 +728,25 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         // codegen. Note that this has a semantic difference in that the
         // intrinsic can trap whereas `fptoui` never traps. That difference,
         // however, is handled by `fptosui_may_trap` above.
+        //
+        // Note that we skip the wasm intrinsics for vector types where `fptoui`
+        // must be used instead.
         if self.wasm_and_missing_nontrapping_fptoint() {
             let src_ty = self.cx.val_ty(val);
-            let float_width = self.cx.float_width(src_ty);
-            let int_width = self.cx.int_width(dest_ty);
-            let name = match (int_width, float_width) {
-                (32, 32) => Some("llvm.wasm.trunc.unsigned.i32.f32"),
-                (32, 64) => Some("llvm.wasm.trunc.unsigned.i32.f64"),
-                (64, 32) => Some("llvm.wasm.trunc.unsigned.i64.f32"),
-                (64, 64) => Some("llvm.wasm.trunc.unsigned.i64.f64"),
-                _ => None,
-            };
-            if let Some(name) = name {
-                let intrinsic = self.get_intrinsic(name);
-                return self.call(intrinsic, &[val], None);
+            if self.cx.type_kind(src_ty) != TypeKind::Vector {
+                let float_width = self.cx.float_width(src_ty);
+                let int_width = self.cx.int_width(dest_ty);
+                let name = match (int_width, float_width) {
+                    (32, 32) => Some("llvm.wasm.trunc.unsigned.i32.f32"),
+                    (32, 64) => Some("llvm.wasm.trunc.unsigned.i32.f64"),
+                    (64, 32) => Some("llvm.wasm.trunc.unsigned.i64.f32"),
+                    (64, 64) => Some("llvm.wasm.trunc.unsigned.i64.f64"),
+                    _ => None,
+                };
+                if let Some(name) = name {
+                    let intrinsic = self.get_intrinsic(name);
+                    return self.call(intrinsic, &[val], None);
+                }
             }
         }
         unsafe { llvm::LLVMBuildFPToUI(self.llbuilder, val, dest_ty, UNNAMED) }
@@ -750,18 +755,20 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     fn fptosi(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
         if self.wasm_and_missing_nontrapping_fptoint() {
             let src_ty = self.cx.val_ty(val);
-            let float_width = self.cx.float_width(src_ty);
-            let int_width = self.cx.int_width(dest_ty);
-            let name = match (int_width, float_width) {
-                (32, 32) => Some("llvm.wasm.trunc.signed.i32.f32"),
-                (32, 64) => Some("llvm.wasm.trunc.signed.i32.f64"),
-                (64, 32) => Some("llvm.wasm.trunc.signed.i64.f32"),
-                (64, 64) => Some("llvm.wasm.trunc.signed.i64.f64"),
-                _ => None,
-            };
-            if let Some(name) = name {
-                let intrinsic = self.get_intrinsic(name);
-                return self.call(intrinsic, &[val], None);
+            if self.cx.type_kind(src_ty) != TypeKind::Vector {
+                let float_width = self.cx.float_width(src_ty);
+                let int_width = self.cx.int_width(dest_ty);
+                let name = match (int_width, float_width) {
+                    (32, 32) => Some("llvm.wasm.trunc.signed.i32.f32"),
+                    (32, 64) => Some("llvm.wasm.trunc.signed.i32.f64"),
+                    (64, 32) => Some("llvm.wasm.trunc.signed.i64.f32"),
+                    (64, 64) => Some("llvm.wasm.trunc.signed.i64.f64"),
+                    _ => None,
+                };
+                if let Some(name) = name {
+                    let intrinsic = self.get_intrinsic(name);
+                    return self.call(intrinsic, &[val], None);
+                }
             }
         }
         unsafe { llvm::LLVMBuildFPToSI(self.llbuilder, val, dest_ty, UNNAMED) }
diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs
index acfb294f7c1..024834bfe2a 100644
--- a/src/librustc_codegen_llvm/consts.rs
+++ b/src/librustc_codegen_llvm/consts.rs
@@ -41,7 +41,7 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll
             // some arbitrary byte value.
             //
             // FIXME: relay undef bytes to codegen as undef const bytes
-            let bytes = alloc.inspect_with_undef_and_ptr_outside_interpreter(next_offset..offset);
+            let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(next_offset..offset);
             llvals.push(cx.const_bytes(bytes));
         }
         let ptr_offset = read_target_uint(
@@ -49,7 +49,7 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll
             // This `inspect` is okay since it is within the bounds of the allocation, it doesn't
             // affect interpreter execution (we inspect the result after interpreter execution),
             // and we properly interpret the relocation as a relocation pointer offset.
-            alloc.inspect_with_undef_and_ptr_outside_interpreter(offset..(offset + pointer_size)),
+            alloc.inspect_with_uninit_and_ptr_outside_interpreter(offset..(offset + pointer_size)),
         )
         .expect("const_alloc_to_llvm: could not read relocation pointer")
             as u64;
@@ -74,7 +74,7 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll
         // arbitrary byte value.
         //
         // FIXME: relay undef bytes to codegen as undef const bytes
-        let bytes = alloc.inspect_with_undef_and_ptr_outside_interpreter(range);
+        let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(range);
         llvals.push(cx.const_bytes(bytes));
     }
 
@@ -452,7 +452,7 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
                     // BSS.
                     let all_bytes_are_zero = alloc.relocations().is_empty()
                         && alloc
-                            .inspect_with_undef_and_ptr_outside_interpreter(0..alloc.len())
+                            .inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len())
                             .iter()
                             .all(|&byte| byte == 0);
 
@@ -480,7 +480,7 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
                     // because we are doing this access to inspect the final interpreter state (not
                     // as part of the interpreter execution).
                     let bytes =
-                        alloc.inspect_with_undef_and_ptr_outside_interpreter(0..alloc.len());
+                        alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len());
                     let alloc = llvm::LLVMMDStringInContext(
                         self.llcx,
                         bytes.as_ptr().cast(),
diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs
index 6912667c391..d725a60118e 100644
--- a/src/librustc_codegen_ssa/back/link.rs
+++ b/src/librustc_codegen_ssa/back/link.rs
@@ -1,4 +1,5 @@
 use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_fs_util::fix_windows_verbatim_for_gcc;
 use rustc_hir::def_id::CrateNum;
 use rustc_middle::middle::cstore::{EncodedMetadata, LibSource, NativeLib};
@@ -23,7 +24,7 @@ use super::rpath::{self, RPathConfig};
 use crate::{looks_like_rust_object_file, CodegenResults, CrateInfo, METADATA_FILENAME};
 
 use cc::windows_registry;
-use tempfile::{Builder as TempFileBuilder, TempDir};
+use tempfile::Builder as TempFileBuilder;
 
 use std::ffi::OsString;
 use std::path::{Path, PathBuf};
@@ -70,27 +71,21 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
             }
         });
 
-        let tmpdir = TempFileBuilder::new()
-            .prefix("rustc")
-            .tempdir()
-            .unwrap_or_else(|err| sess.fatal(&format!("couldn't create a temp dir: {}", err)));
-
         if outputs.outputs.should_codegen() {
+            let tmpdir = TempFileBuilder::new()
+                .prefix("rustc")
+                .tempdir()
+                .unwrap_or_else(|err| sess.fatal(&format!("couldn't create a temp dir: {}", err)));
+            let path = MaybeTempDir::new(tmpdir, sess.opts.cg.save_temps);
             let out_filename = out_filename(sess, crate_type, outputs, crate_name);
             match crate_type {
                 CrateType::Rlib => {
                     let _timer = sess.timer("link_rlib");
-                    link_rlib::<B>(
-                        sess,
-                        codegen_results,
-                        RlibFlavor::Normal,
-                        &out_filename,
-                        &tmpdir,
-                    )
-                    .build();
+                    link_rlib::<B>(sess, codegen_results, RlibFlavor::Normal, &out_filename, &path)
+                        .build();
                 }
                 CrateType::Staticlib => {
-                    link_staticlib::<B>(sess, codegen_results, &out_filename, &tmpdir);
+                    link_staticlib::<B>(sess, codegen_results, &out_filename, &path);
                 }
                 _ => {
                     link_natively::<B>(
@@ -98,7 +93,7 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
                         crate_type,
                         &out_filename,
                         codegen_results,
-                        tmpdir.path(),
+                        path.as_ref(),
                         target_cpu,
                     );
                 }
@@ -107,10 +102,6 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
                 sess.parse_sess.span_diagnostic.emit_artifact_notification(&out_filename, "link");
             }
         }
-
-        if sess.opts.cg.save_temps {
-            let _ = tmpdir.into_path();
-        }
     }
 
     // Remove the temporary object file and metadata if we aren't saving temps
@@ -279,8 +270,8 @@ pub fn each_linked_rlib(
 /// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a
 /// directory being searched for `extern crate` (observing an incomplete file).
 /// The returned path is the temporary file containing the complete metadata.
-pub fn emit_metadata(sess: &Session, metadata: &EncodedMetadata, tmpdir: &TempDir) -> PathBuf {
-    let out_filename = tmpdir.path().join(METADATA_FILENAME);
+pub fn emit_metadata(sess: &Session, metadata: &EncodedMetadata, tmpdir: &MaybeTempDir) -> PathBuf {
+    let out_filename = tmpdir.as_ref().join(METADATA_FILENAME);
     let result = fs::write(&out_filename, &metadata.raw_data);
 
     if let Err(e) = result {
@@ -301,7 +292,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
     codegen_results: &CodegenResults,
     flavor: RlibFlavor,
     out_filename: &Path,
-    tmpdir: &TempDir,
+    tmpdir: &MaybeTempDir,
 ) -> B {
     info!("preparing rlib to {:?}", out_filename);
     let mut ab = <B as ArchiveBuilder>::new(sess, out_filename, None);
@@ -406,7 +397,7 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>(
     sess: &'a Session,
     codegen_results: &CodegenResults,
     out_filename: &Path,
-    tempdir: &TempDir,
+    tempdir: &MaybeTempDir,
 ) {
     let mut ab =
         link_rlib::<B>(sess, codegen_results, RlibFlavor::StaticlibBase, out_filename, tempdir);
diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml
index d0dbad5d2af..36c32e60031 100644
--- a/src/librustc_data_structures/Cargo.toml
+++ b/src/librustc_data_structures/Cargo.toml
@@ -30,6 +30,7 @@ bitflags = "1.2.1"
 measureme = "0.7.1"
 libc = "0.2"
 stacker = "0.1.9"
+tempfile = "3.0.5"
 
 [dependencies.parking_lot]
 version = "0.10"
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index 0b2e7cda1b4..3884fc05105 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -95,6 +95,7 @@ pub mod vec_linked_list;
 pub mod work_queue;
 pub use atomic_ref::AtomicRef;
 pub mod frozen;
+pub mod temp_dir;
 
 pub struct OnDrop<F: Fn()>(pub F);
 
diff --git a/src/librustc_data_structures/temp_dir.rs b/src/librustc_data_structures/temp_dir.rs
new file mode 100644
index 00000000000..0d9b3e3ca25
--- /dev/null
+++ b/src/librustc_data_structures/temp_dir.rs
@@ -0,0 +1,34 @@
+use std::mem::ManuallyDrop;
+use std::path::Path;
+use tempfile::TempDir;
+
+/// This is used to avoid TempDir being dropped on error paths unintentionally.
+#[derive(Debug)]
+pub struct MaybeTempDir {
+    dir: ManuallyDrop<TempDir>,
+    // Whether the TempDir should be deleted on drop.
+    keep: bool,
+}
+
+impl Drop for MaybeTempDir {
+    fn drop(&mut self) {
+        // Safety: We are in the destructor, and no further access will
+        // occur.
+        let dir = unsafe { ManuallyDrop::take(&mut self.dir) };
+        if self.keep {
+            dir.into_path();
+        }
+    }
+}
+
+impl AsRef<Path> for MaybeTempDir {
+    fn as_ref(&self) -> &Path {
+        self.dir.path()
+    }
+}
+
+impl MaybeTempDir {
+    pub fn new(dir: TempDir, keep_on_drop: bool) -> MaybeTempDir {
+        MaybeTempDir { dir: ManuallyDrop::new(dir), keep: keep_on_drop }
+    }
+}
diff --git a/src/librustc_error_codes/error_codes/E0749.md b/src/librustc_error_codes/error_codes/E0749.md
index 7a1a745b53c..dfe90ae89e4 100644
--- a/src/librustc_error_codes/error_codes/E0749.md
+++ b/src/librustc_error_codes/error_codes/E0749.md
@@ -11,9 +11,19 @@ trait MyTrait {
 impl !MyTrait for u32 {
     type Foo = i32; // error!
 }
-# fn main() {}
 ```
 
 Negative impls are not allowed to have any items. Negative impls declare that a
 trait is **not** implemented (and never will be) and hence there is no need to
 specify the values for trait methods or other items.
+
+One way to fix this is to remove the items in negative impls:
+
+```
+# #![feature(negative_impls)]
+trait MyTrait {
+    type Foo;
+}
+
+impl !MyTrait for u32 {}
+```
diff --git a/src/librustc_error_codes/error_codes/E0751.md b/src/librustc_error_codes/error_codes/E0751.md
index 809b888d92a..8794f7868f3 100644
--- a/src/librustc_error_codes/error_codes/E0751.md
+++ b/src/librustc_error_codes/error_codes/E0751.md
@@ -5,8 +5,8 @@ Erroneous code example:
 ```compile_fail,E0751
 trait MyTrait {}
 impl MyTrait for i32 { }
-impl !MyTrait for i32 { }
+impl !MyTrait for i32 { } // error!
 ```
 
-Negative implementations are a promise that the trait will never be
-implemented for the given types.
+Negative implementations are a promise that the trait will never be implemented
+for the given types. Therefore, both cannot exists at the same time.
diff --git a/src/librustc_expand/proc_macro_server.rs b/src/librustc_expand/proc_macro_server.rs
index dc7ba2d0424..83a650443bc 100644
--- a/src/librustc_expand/proc_macro_server.rs
+++ b/src/librustc_expand/proc_macro_server.rs
@@ -319,18 +319,10 @@ pub struct Ident {
 }
 
 impl Ident {
-    fn is_valid(string: &str) -> bool {
-        let mut chars = string.chars();
-        if let Some(start) = chars.next() {
-            rustc_lexer::is_id_start(start) && chars.all(rustc_lexer::is_id_continue)
-        } else {
-            false
-        }
-    }
     fn new(sess: &ParseSess, sym: Symbol, is_raw: bool, span: Span) -> Ident {
         let sym = nfc_normalize(&sym.as_str());
         let string = sym.as_str();
-        if !Self::is_valid(&string) {
+        if !rustc_lexer::is_ident(&string) {
             panic!("`{:?}` is not a valid identifier", string)
         }
         if is_raw && !sym.can_be_raw() {
diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index 45aee2b3965..1ddf88c0306 100644
--- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -2,7 +2,7 @@
 
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
-use crate::infer::{Subtype, TyCtxtInferExt, ValuePairs};
+use crate::infer::{Subtype, ValuePairs};
 use crate::traits::ObligationCauseCode::CompareImplMethodObligation;
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
@@ -53,7 +53,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     }
 
     fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, trait_def_id: DefId) {
-        let tcx = self.tcx();
         let trait_sp = self.tcx().def_span(trait_def_id);
         let mut err = self
             .tcx()
@@ -85,9 +84,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             );
         }
 
-        if let Some((expected, found)) = tcx
-            .infer_ctxt()
-            .enter(|infcx| infcx.expected_found_str_ty(&ExpectedFound { expected, found }))
+        if let Some((expected, found)) =
+            self.infcx.expected_found_str_ty(&ExpectedFound { expected, found })
         {
             // Highlighted the differences when showing the "expected/found" note.
             err.note_expected_found(&"", expected, &"", found);
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index 6c0343330c8..701fca8e4b5 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -9,6 +9,7 @@ use rustc_ast::{self, ast, visit};
 use rustc_codegen_ssa::back::link::emit_metadata;
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::sync::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal};
+use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel};
 use rustc_errors::{ErrorReported, PResult};
 use rustc_expand::base::ExtCtxt;
@@ -974,6 +975,7 @@ fn encode_and_write_metadata(
             .prefix("rmeta")
             .tempdir_in(out_filename.parent().unwrap())
             .unwrap_or_else(|err| tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err)));
+        let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps);
         let metadata_filename = emit_metadata(tcx.sess, &metadata, &metadata_tmpdir);
         if let Err(e) = fs::rename(&metadata_filename, &out_filename) {
             tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
diff --git a/src/librustc_lexer/src/lib.rs b/src/librustc_lexer/src/lib.rs
index 862ffd50d38..7949a232b9b 100644
--- a/src/librustc_lexer/src/lib.rs
+++ b/src/librustc_lexer/src/lib.rs
@@ -274,6 +274,16 @@ pub fn is_id_continue(c: char) -> bool {
         || (c > '\x7f' && unicode_xid::UnicodeXID::is_xid_continue(c))
 }
 
+/// The passed string is lexically an identifier.
+pub fn is_ident(string: &str) -> bool {
+    let mut chars = string.chars();
+    if let Some(start) = chars.next() {
+        is_id_start(start) && chars.all(is_id_continue)
+    } else {
+        false
+    }
+}
+
 impl Cursor<'_> {
     /// Parses a token from the input string.
     fn advance_token(&mut self) -> Token {
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 15a9affbff7..1f17c7dcba4 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -219,7 +219,7 @@ pub fn new_lint_store(no_interleave_lints: bool, internal_lints: bool) -> LintSt
 
 /// Tell the `LintStore` about all the built-in lints (the ones
 /// defined in this crate and the ones defined in
-/// `rustc::lint::builtin`).
+/// `rustc_session::lint::builtin`).
 fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) {
     macro_rules! add_lint_group {
         ($name:expr, $($lint:ident),*) => (
diff --git a/src/librustc_lint/non_ascii_idents.rs b/src/librustc_lint/non_ascii_idents.rs
index 30dbd069c29..ab1658b2229 100644
--- a/src/librustc_lint/non_ascii_idents.rs
+++ b/src/librustc_lint/non_ascii_idents.rs
@@ -1,7 +1,7 @@
 use crate::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_ast::ast;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_span::symbol::SymbolStr;
+use rustc_span::symbol::Symbol;
 
 declare_lint! {
     pub NON_ASCII_IDENTS,
@@ -39,7 +39,6 @@ impl EarlyLintPass for NonAsciiIdents {
         use rustc_span::Span;
         use std::collections::BTreeMap;
         use unicode_security::GeneralSecurityProfile;
-        use utils::CowBoxSymStr;
 
         let check_non_ascii_idents = cx.builder.lint_level(NON_ASCII_IDENTS).0 != Level::Allow;
         let check_uncommon_codepoints =
@@ -58,6 +57,12 @@ impl EarlyLintPass for NonAsciiIdents {
 
         let mut has_non_ascii_idents = false;
         let symbols = cx.sess.parse_sess.symbol_gallery.symbols.lock();
+
+        // Sort by `Span` so that error messages make sense with respect to the
+        // order of identifier locations in the code.
+        let mut symbols: Vec<_> = symbols.iter().collect();
+        symbols.sort_by_key(|k| k.1);
+
         for (symbol, &sp) in symbols.iter() {
             let symbol_str = symbol.as_str();
             if symbol_str.is_ascii() {
@@ -77,33 +82,34 @@ impl EarlyLintPass for NonAsciiIdents {
         }
 
         if has_non_ascii_idents && check_confusable_idents {
-            let mut skeleton_map: FxHashMap<CowBoxSymStr, (SymbolStr, Span, bool)> =
+            let mut skeleton_map: FxHashMap<Symbol, (Symbol, Span, bool)> =
                 FxHashMap::with_capacity_and_hasher(symbols.len(), Default::default());
-            let mut str_buf = String::new();
-            for (symbol, &sp) in symbols.iter() {
-                fn calc_skeleton(symbol_str: &SymbolStr, buffer: &mut String) -> CowBoxSymStr {
-                    use std::mem::replace;
-                    use unicode_security::confusable_detection::skeleton;
-                    buffer.clear();
-                    buffer.extend(skeleton(symbol_str));
-                    if *symbol_str == *buffer {
-                        CowBoxSymStr::Interned(symbol_str.clone())
-                    } else {
-                        let owned = replace(buffer, String::new());
-                        CowBoxSymStr::Owned(owned.into_boxed_str())
-                    }
-                }
+            let mut skeleton_buf = String::new();
+
+            for (&symbol, &sp) in symbols.iter() {
+                use unicode_security::confusable_detection::skeleton;
+
                 let symbol_str = symbol.as_str();
                 let is_ascii = symbol_str.is_ascii();
-                let skeleton = calc_skeleton(&symbol_str, &mut str_buf);
+
+                // Get the skeleton as a `Symbol`.
+                skeleton_buf.clear();
+                skeleton_buf.extend(skeleton(&symbol_str));
+                let skeleton_sym = if *symbol_str == *skeleton_buf {
+                    symbol
+                } else {
+                    Symbol::intern(&skeleton_buf)
+                };
+
                 skeleton_map
-                    .entry(skeleton)
-                    .and_modify(|(existing_symbolstr, existing_span, existing_is_ascii)| {
+                    .entry(skeleton_sym)
+                    .and_modify(|(existing_symbol, existing_span, existing_is_ascii)| {
                         if !*existing_is_ascii || !is_ascii {
                             cx.struct_span_lint(CONFUSABLE_IDENTS, sp, |lint| {
                                 lint.build(&format!(
                                     "identifier pair considered confusable between `{}` and `{}`",
-                                    existing_symbolstr, symbol_str
+                                    existing_symbol.as_str(),
+                                    symbol.as_str()
                                 ))
                                 .span_label(
                                     *existing_span,
@@ -113,12 +119,12 @@ impl EarlyLintPass for NonAsciiIdents {
                             });
                         }
                         if *existing_is_ascii && !is_ascii {
-                            *existing_symbolstr = symbol_str.clone();
+                            *existing_symbol = symbol;
                             *existing_span = sp;
                             *existing_is_ascii = is_ascii;
                         }
                     })
-                    .or_insert((symbol_str, sp, is_ascii));
+                    .or_insert((symbol, sp, is_ascii));
             }
         }
 
@@ -232,41 +238,3 @@ impl EarlyLintPass for NonAsciiIdents {
         }
     }
 }
-
-mod utils {
-    use rustc_span::symbol::SymbolStr;
-    use std::hash::{Hash, Hasher};
-    use std::ops::Deref;
-
-    pub(super) enum CowBoxSymStr {
-        Interned(SymbolStr),
-        Owned(Box<str>),
-    }
-
-    impl Deref for CowBoxSymStr {
-        type Target = str;
-
-        fn deref(&self) -> &str {
-            match self {
-                CowBoxSymStr::Interned(interned) => interned,
-                CowBoxSymStr::Owned(ref owned) => owned,
-            }
-        }
-    }
-
-    impl Hash for CowBoxSymStr {
-        #[inline]
-        fn hash<H: Hasher>(&self, state: &mut H) {
-            Hash::hash(&**self, state)
-        }
-    }
-
-    impl PartialEq<CowBoxSymStr> for CowBoxSymStr {
-        #[inline]
-        fn eq(&self, other: &CowBoxSymStr) -> bool {
-            PartialEq::eq(&**self, &**other)
-        }
-    }
-
-    impl Eq for CowBoxSymStr {}
-}
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 5de9a16e098..ecc8a192f18 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -481,25 +481,27 @@ trait UnusedDelimLint {
             let mut err = lint.build(&span_msg);
             let mut ate_left_paren = false;
             let mut ate_right_paren = false;
-            let parens_removed = pattern.trim_matches(|c| match c {
-                '(' | '{' => {
-                    if ate_left_paren {
-                        false
-                    } else {
-                        ate_left_paren = true;
-                        true
+            let parens_removed = pattern
+                .trim_matches(|c| match c {
+                    '(' | '{' => {
+                        if ate_left_paren {
+                            false
+                        } else {
+                            ate_left_paren = true;
+                            true
+                        }
                     }
-                }
-                ')' | '}' => {
-                    if ate_right_paren {
-                        false
-                    } else {
-                        ate_right_paren = true;
-                        true
+                    ')' | '}' => {
+                        if ate_right_paren {
+                            false
+                        } else {
+                            ate_right_paren = true;
+                            true
+                        }
                     }
-                }
-                _ => false,
-            });
+                    _ => false,
+                })
+                .trim();
 
             let replace = {
                 let mut replace = if keep_space.0 {
diff --git a/src/librustc_middle/lib.rs b/src/librustc_middle/lib.rs
index a49287840e1..4c06472ceb8 100644
--- a/src/librustc_middle/lib.rs
+++ b/src/librustc_middle/lib.rs
@@ -27,6 +27,7 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
+#![feature(cmp_min_max_by)]
 #![feature(const_fn)]
 #![feature(const_panic)]
 #![feature(const_fn_transmute)]
diff --git a/src/librustc_middle/mir/interpret/allocation.rs b/src/librustc_middle/mir/interpret/allocation.rs
index dd4fc7adff1..b23deb2e3bc 100644
--- a/src/librustc_middle/mir/interpret/allocation.rs
+++ b/src/librustc_middle/mir/interpret/allocation.rs
@@ -154,10 +154,10 @@ impl<Tag, Extra> Allocation<Tag, Extra> {
     }
 
     /// Looks at a slice which may describe uninitialized bytes or describe a relocation. This differs
-    /// from `get_bytes_with_undef_and_ptr` in that it does no relocation checks (even on the
+    /// from `get_bytes_with_uninit_and_ptr` in that it does no relocation checks (even on the
     /// edges) at all. It further ignores `AllocationExtra` callbacks.
     /// This must not be used for reads affecting the interpreter execution.
-    pub fn inspect_with_undef_and_ptr_outside_interpreter(&self, range: Range<usize>) -> &[u8] {
+    pub fn inspect_with_uninit_and_ptr_outside_interpreter(&self, range: Range<usize>) -> &[u8] {
         &self.bytes[range]
     }
 
@@ -194,7 +194,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
 
     /// The last argument controls whether we error out when there are uninitialized
     /// or pointer bytes. You should never call this, call `get_bytes` or
-    /// `get_bytes_with_undef_and_ptr` instead,
+    /// `get_bytes_with_uninit_and_ptr` instead,
     ///
     /// This function also guarantees that the resulting pointer will remain stable
     /// even when new allocations are pushed to the `HashMap`. `copy_repeatedly` relies
@@ -244,7 +244,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
     ///
     /// It is the caller's responsibility to check bounds and alignment beforehand.
     #[inline]
-    pub fn get_bytes_with_undef_and_ptr(
+    pub fn get_bytes_with_uninit_and_ptr(
         &self,
         cx: &impl HasDataLayout,
         ptr: Pointer<Tag>,
@@ -302,19 +302,19 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
     }
 
     /// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a
-    /// relocation. If `allow_ptr_and_undef` is `false`, also enforces that the memory in the
+    /// relocation. If `allow_uninit_and_ptr` is `false`, also enforces that the memory in the
     /// given range contains neither relocations nor uninitialized bytes.
     pub fn check_bytes(
         &self,
         cx: &impl HasDataLayout,
         ptr: Pointer<Tag>,
         size: Size,
-        allow_ptr_and_undef: bool,
+        allow_uninit_and_ptr: bool,
     ) -> InterpResult<'tcx> {
         // Check bounds and relocations on the edges.
-        self.get_bytes_with_undef_and_ptr(cx, ptr, size)?;
+        self.get_bytes_with_uninit_and_ptr(cx, ptr, size)?;
         // Check uninit and ptr.
-        if !allow_ptr_and_undef {
+        if !allow_uninit_and_ptr {
             self.check_init(ptr, size)?;
             self.check_relocations(cx, ptr, size)?;
         }
@@ -361,7 +361,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
         size: Size,
     ) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
         // `get_bytes_unchecked` tests relocation edges.
-        let bytes = self.get_bytes_with_undef_and_ptr(cx, ptr, size)?;
+        let bytes = self.get_bytes_with_uninit_and_ptr(cx, ptr, size)?;
         // Uninit check happens *after* we established that the alignment is correct.
         // We must not return `Ok()` for unaligned pointers!
         if self.is_init(ptr, size).is_err() {
@@ -594,7 +594,7 @@ impl InitMaskCompressed {
 /// Transferring the initialization mask to other allocations.
 impl<Tag, Extra> Allocation<Tag, Extra> {
     /// Creates a run-length encoding of the initialization mask.
-    pub fn compress_undef_range(&self, src: Pointer<Tag>, size: Size) -> InitMaskCompressed {
+    pub fn compress_uninit_range(&self, src: Pointer<Tag>, size: Size) -> InitMaskCompressed {
         // Since we are copying `size` bytes from `src` to `dest + i * size` (`for i in 0..repeat`),
         // a naive initialization mask copying algorithm would repeatedly have to read the initialization mask from
         // the source and write it to the destination. Even if we optimized the memory accesses,
@@ -636,8 +636,8 @@ impl<Tag, Extra> Allocation<Tag, Extra> {
         size: Size,
         repeat: u64,
     ) {
-        // An optimization where we can just overwrite an entire range of definedness bits if
-        // they are going to be uniformly `1` or `0`.
+        // An optimization where we can just overwrite an entire range of initialization
+        // bits if they are going to be uniformly `1` or `0`.
         if defined.ranges.len() <= 1 {
             self.init_mask.set_range_inbounds(
                 dest.offset,
diff --git a/src/librustc_middle/mir/interpret/error.rs b/src/librustc_middle/mir/interpret/error.rs
index c904cd83a78..5be09c0e9bc 100644
--- a/src/librustc_middle/mir/interpret/error.rs
+++ b/src/librustc_middle/mir/interpret/error.rs
@@ -1,17 +1,13 @@
 use super::{AllocId, Pointer, RawConst, Scalar};
 
 use crate::mir::interpret::ConstValue;
-use crate::ty::layout::LayoutError;
-use crate::ty::query::TyCtxtAt;
-use crate::ty::{self, layout, tls, FnSig, Ty};
+use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty};
 
 use rustc_data_structures::sync::Lock;
 use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorReported};
-use rustc_hir as hir;
-use rustc_hir::definitions::DefPathData;
 use rustc_macros::HashStable;
 use rustc_session::CtfeBacktrace;
-use rustc_span::{def_id::DefId, Pos, Span};
+use rustc_span::def_id::DefId;
 use rustc_target::abi::{Align, Size};
 use std::{any::Any, backtrace::Backtrace, fmt, mem};
 
@@ -34,167 +30,6 @@ CloneTypeFoldableAndLiftImpls! {
 pub type ConstEvalRawResult<'tcx> = Result<RawConst<'tcx>, ErrorHandled>;
 pub type ConstEvalResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
 
-#[derive(Debug)]
-pub struct ConstEvalErr<'tcx> {
-    pub span: Span,
-    pub error: crate::mir::interpret::InterpError<'tcx>,
-    pub stacktrace: Vec<FrameInfo<'tcx>>,
-}
-
-#[derive(Debug)]
-pub struct FrameInfo<'tcx> {
-    pub instance: ty::Instance<'tcx>,
-    pub span: Span,
-    pub lint_root: Option<hir::HirId>,
-}
-
-impl<'tcx> fmt::Display for FrameInfo<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        ty::tls::with(|tcx| {
-            if tcx.def_key(self.instance.def_id()).disambiguated_data.data
-                == DefPathData::ClosureExpr
-            {
-                write!(f, "inside closure")?;
-            } else {
-                write!(f, "inside `{}`", self.instance)?;
-            }
-            if !self.span.is_dummy() {
-                let lo = tcx.sess.source_map().lookup_char_pos(self.span.lo());
-                write!(f, " at {}:{}:{}", lo.file.name, lo.line, lo.col.to_usize() + 1)?;
-            }
-            Ok(())
-        })
-    }
-}
-
-impl<'tcx> ConstEvalErr<'tcx> {
-    pub fn struct_error(
-        &self,
-        tcx: TyCtxtAt<'tcx>,
-        message: &str,
-        emit: impl FnOnce(DiagnosticBuilder<'_>),
-    ) -> ErrorHandled {
-        self.struct_generic(tcx, message, emit, None)
-    }
-
-    pub fn report_as_error(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled {
-        self.struct_error(tcx, message, |mut e| e.emit())
-    }
-
-    pub fn report_as_lint(
-        &self,
-        tcx: TyCtxtAt<'tcx>,
-        message: &str,
-        lint_root: hir::HirId,
-        span: Option<Span>,
-    ) -> ErrorHandled {
-        self.struct_generic(
-            tcx,
-            message,
-            |mut lint: DiagnosticBuilder<'_>| {
-                // Apply the span.
-                if let Some(span) = span {
-                    let primary_spans = lint.span.primary_spans().to_vec();
-                    // point at the actual error as the primary span
-                    lint.replace_span_with(span);
-                    // point to the `const` statement as a secondary span
-                    // they don't have any label
-                    for sp in primary_spans {
-                        if sp != span {
-                            lint.span_label(sp, "");
-                        }
-                    }
-                }
-                lint.emit();
-            },
-            Some(lint_root),
-        )
-    }
-
-    /// Create a diagnostic for this const eval error.
-    ///
-    /// Sets the message passed in via `message` and adds span labels with detailed error
-    /// information before handing control back to `emit` to do any final processing.
-    /// It's the caller's responsibility to call emit(), stash(), etc. within the `emit`
-    /// function to dispose of the diagnostic properly.
-    ///
-    /// If `lint_root.is_some()` report it as a lint, else report it as a hard error.
-    /// (Except that for some errors, we ignore all that -- see `must_error` below.)
-    fn struct_generic(
-        &self,
-        tcx: TyCtxtAt<'tcx>,
-        message: &str,
-        emit: impl FnOnce(DiagnosticBuilder<'_>),
-        lint_root: Option<hir::HirId>,
-    ) -> ErrorHandled {
-        let must_error = match self.error {
-            err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
-                return ErrorHandled::TooGeneric;
-            }
-            err_inval!(TypeckError(error_reported)) => {
-                return ErrorHandled::Reported(error_reported);
-            }
-            // We must *always* hard error on these, even if the caller wants just a lint.
-            err_inval!(Layout(LayoutError::SizeOverflow(_))) => true,
-            _ => false,
-        };
-        trace!("reporting const eval failure at {:?}", self.span);
-
-        let err_msg = match &self.error {
-            InterpError::MachineStop(msg) => {
-                // A custom error (`ConstEvalErrKind` in `librustc_mir/interp/const_eval/error.rs`).
-                // Should be turned into a string by now.
-                msg.downcast_ref::<String>().expect("invalid MachineStop payload").clone()
-            }
-            err => err.to_string(),
-        };
-
-        let finish = |mut err: DiagnosticBuilder<'_>, span_msg: Option<String>| {
-            if let Some(span_msg) = span_msg {
-                err.span_label(self.span, span_msg);
-            }
-            // Add spans for the stacktrace. Don't print a single-line backtrace though.
-            if self.stacktrace.len() > 1 {
-                for frame_info in &self.stacktrace {
-                    err.span_label(frame_info.span, frame_info.to_string());
-                }
-            }
-            // Let the caller finish the job.
-            emit(err)
-        };
-
-        if must_error {
-            // The `message` makes little sense here, this is a more serious error than the
-            // caller thinks anyway.
-            // See <https://github.com/rust-lang/rust/pull/63152>.
-            finish(struct_error(tcx, &err_msg), None);
-            ErrorHandled::Reported(ErrorReported)
-        } else {
-            // Regular case.
-            if let Some(lint_root) = lint_root {
-                // Report as lint.
-                let hir_id = self
-                    .stacktrace
-                    .iter()
-                    .rev()
-                    .find_map(|frame| frame.lint_root)
-                    .unwrap_or(lint_root);
-                tcx.struct_span_lint_hir(
-                    rustc_session::lint::builtin::CONST_ERR,
-                    hir_id,
-                    tcx.span,
-                    |lint| finish(lint.build(message), Some(err_msg)),
-                );
-                ErrorHandled::Linted
-            } else {
-                // Report as hard error.
-                finish(struct_error(tcx, message), Some(err_msg));
-                ErrorHandled::Reported(ErrorReported)
-            }
-        }
-    }
-}
-
 pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> {
     struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
 }
diff --git a/src/librustc_middle/mir/interpret/mod.rs b/src/librustc_middle/mir/interpret/mod.rs
index 5e57b60894a..2507f2184ff 100644
--- a/src/librustc_middle/mir/interpret/mod.rs
+++ b/src/librustc_middle/mir/interpret/mod.rs
@@ -117,9 +117,9 @@ use crate::ty::subst::GenericArgKind;
 use crate::ty::{self, Instance, Ty, TyCtxt};
 
 pub use self::error::{
-    struct_error, CheckInAllocMsg, ConstEvalErr, ConstEvalRawResult, ConstEvalResult, ErrorHandled,
-    FrameInfo, InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType,
-    ResourceExhaustionInfo, UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo,
+    struct_error, CheckInAllocMsg, ConstEvalRawResult, ConstEvalResult, ErrorHandled, InterpError,
+    InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType, ResourceExhaustionInfo,
+    UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo,
 };
 
 pub use self::value::{get_slice_bytes, ConstValue, RawConst, Scalar, ScalarMaybeUninit};
diff --git a/src/librustc_middle/mir/interpret/queries.rs b/src/librustc_middle/mir/interpret/queries.rs
index 442e7f6b0f4..dcc1f8b1a4b 100644
--- a/src/librustc_middle/mir/interpret/queries.rs
+++ b/src/librustc_middle/mir/interpret/queries.rs
@@ -74,4 +74,27 @@ impl<'tcx> TyCtxt<'tcx> {
             self.const_eval_validated(inputs)
         }
     }
+
+    /// Evaluate a static's initializer, returning the allocation of the initializer's memory.
+    pub fn eval_static_initializer(
+        self,
+        def_id: DefId,
+    ) -> Result<&'tcx mir::Allocation, ErrorHandled> {
+        trace!("eval_static_initializer: Need to compute {:?}", def_id);
+        assert!(self.is_static(def_id));
+        let instance = ty::Instance::mono(self, def_id);
+        let gid = GlobalId { instance, promoted: None };
+        self.eval_to_allocation(gid, ty::ParamEnv::reveal_all())
+    }
+
+    /// Evaluate anything constant-like, returning the allocation of the final memory.
+    fn eval_to_allocation(
+        self,
+        gid: GlobalId<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> Result<&'tcx mir::Allocation, ErrorHandled> {
+        trace!("eval_to_allocation: Need to compute {:?}", gid);
+        let raw_const = self.const_eval_raw(param_env.and(gid))?;
+        Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory())
+    }
 }
diff --git a/src/librustc_middle/mir/interpret/value.rs b/src/librustc_middle/mir/interpret/value.rs
index b4e7a5b98e3..50c76e29663 100644
--- a/src/librustc_middle/mir/interpret/value.rs
+++ b/src/librustc_middle/mir/interpret/value.rs
@@ -58,7 +58,7 @@ impl<'tcx> ConstValue<'tcx> {
 
     pub fn try_to_str_slice(&self) -> Option<&'tcx str> {
         if let ConstValue::Slice { data, start, end } = *self {
-            ::std::str::from_utf8(data.inspect_with_undef_and_ptr_outside_interpreter(start..end))
+            ::std::str::from_utf8(data.inspect_with_uninit_and_ptr_outside_interpreter(start..end))
                 .ok()
         } else {
             None
diff --git a/src/librustc_middle/ty/flags.rs b/src/librustc_middle/ty/flags.rs
index 81f7474962c..27f50c240db 100644
--- a/src/librustc_middle/ty/flags.rs
+++ b/src/librustc_middle/ty/flags.rs
@@ -85,8 +85,6 @@ impl FlagComputation {
             }
 
             &ty::Generator(_, ref substs, _) => {
-                self.add_flags(TypeFlags::MAY_POLYMORPHIZE);
-
                 let substs = substs.as_generator();
                 let should_remove_further_specializable =
                     !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
@@ -109,8 +107,6 @@ impl FlagComputation {
             }
 
             &ty::Closure(_, substs) => {
-                self.add_flags(TypeFlags::MAY_POLYMORPHIZE);
-
                 let substs = substs.as_closure();
                 let should_remove_further_specializable =
                     !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
@@ -196,8 +192,6 @@ impl FlagComputation {
             }
 
             &ty::FnDef(_, substs) => {
-                self.add_flags(TypeFlags::MAY_POLYMORPHIZE);
-
                 self.add_substs(substs);
             }
 
diff --git a/src/librustc_middle/ty/fold.rs b/src/librustc_middle/ty/fold.rs
index 87434f3f267..492f8ce9ef1 100644
--- a/src/librustc_middle/ty/fold.rs
+++ b/src/librustc_middle/ty/fold.rs
@@ -150,12 +150,6 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
         self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE)
     }
 
-    /// Does this value contain closures, generators or functions such that it may require
-    /// polymorphization?
-    fn may_polymorphize(&self) -> bool {
-        self.has_type_flags(TypeFlags::MAY_POLYMORPHIZE)
-    }
-
     /// A visitor that does not recurse into types, works like `fn walk_shallow` in `Ty`.
     fn visit_tys_shallow(&self, visit: impl FnMut(Ty<'tcx>) -> bool) -> bool {
         pub struct Visitor<F>(F);
diff --git a/src/librustc_middle/ty/instance.rs b/src/librustc_middle/ty/instance.rs
index cf876db26bc..2def000da64 100644
--- a/src/librustc_middle/ty/instance.rs
+++ b/src/librustc_middle/ty/instance.rs
@@ -492,6 +492,20 @@ fn polymorphize<'tcx>(
     let unused = tcx.unused_generic_params(def_id);
     debug!("polymorphize: unused={:?}", unused);
 
+    // If this is a closure or generator then we need to handle the case where another closure
+    // from the function is captured as an upvar and hasn't been polymorphized. In this case,
+    // the unpolymorphized upvar closure would result in a polymorphized closure producing
+    // multiple mono items (and eventually symbol clashes).
+    let upvars_ty = if tcx.is_closure(def_id) {
+        Some(substs.as_closure().tupled_upvars_ty())
+    } else if tcx.type_of(def_id).is_generator() {
+        Some(substs.as_generator().tupled_upvars_ty())
+    } else {
+        None
+    };
+    let has_upvars = upvars_ty.map(|ty| ty.tuple_fields().count() > 0).unwrap_or(false);
+    debug!("polymorphize: upvars_ty={:?} has_upvars={:?}", upvars_ty, has_upvars);
+
     struct PolymorphizationFolder<'tcx> {
         tcx: TyCtxt<'tcx>,
     };
@@ -512,14 +526,6 @@ fn polymorphize<'tcx>(
                         self.tcx.mk_closure(def_id, polymorphized_substs)
                     }
                 }
-                ty::FnDef(def_id, substs) => {
-                    let polymorphized_substs = polymorphize(self.tcx, def_id, substs);
-                    if substs == polymorphized_substs {
-                        ty
-                    } else {
-                        self.tcx.mk_fn_def(def_id, polymorphized_substs)
-                    }
-                }
                 ty::Generator(def_id, substs, movability) => {
                     let polymorphized_substs = polymorphize(self.tcx, def_id, substs);
                     if substs == polymorphized_substs {
@@ -537,24 +543,31 @@ fn polymorphize<'tcx>(
         let is_unused = unused.contains(param.index).unwrap_or(false);
         debug!("polymorphize: param={:?} is_unused={:?}", param, is_unused);
         match param.kind {
-            // If parameter is a const or type parameter..
+            // Upvar case: If parameter is a type parameter..
+            ty::GenericParamDefKind::Type { .. } if
+                // ..and has upvars..
+                has_upvars &&
+                // ..and this param has the same type as the tupled upvars..
+                upvars_ty == Some(substs[param.index as usize].expect_ty()) => {
+                    // ..then double-check that polymorphization marked it used..
+                    debug_assert!(!is_unused);
+                    // ..and polymorphize any closures/generators captured as upvars.
+                    let upvars_ty = upvars_ty.unwrap();
+                    let polymorphized_upvars_ty = upvars_ty.fold_with(
+                        &mut PolymorphizationFolder { tcx });
+                    debug!("polymorphize: polymorphized_upvars_ty={:?}", polymorphized_upvars_ty);
+                    ty::GenericArg::from(polymorphized_upvars_ty)
+                },
+
+            // Simple case: If parameter is a const or type parameter..
             ty::GenericParamDefKind::Const | ty::GenericParamDefKind::Type { .. } if
                 // ..and is within range and unused..
                 unused.contains(param.index).unwrap_or(false) =>
                     // ..then use the identity for this parameter.
                     tcx.mk_param_from_def(param),
 
-            // If the parameter does not contain any closures or generators, then use the
-            // substitution directly.
-            _ if !substs.may_polymorphize() => substs[param.index as usize],
-
-            // Otherwise, use the substitution after polymorphizing.
-            _ => {
-                let arg = substs[param.index as usize];
-                let polymorphized_arg = arg.fold_with(&mut PolymorphizationFolder { tcx });
-                debug!("polymorphize: arg={:?} polymorphized_arg={:?}", arg, polymorphized_arg);
-                ty::GenericArg::from(polymorphized_arg)
-            }
+            // Otherwise, use the parameter as before.
+            _ => substs[param.index as usize],
         }
     })
 }
diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs
index 143d3c4e1e9..5aa94ba3d09 100644
--- a/src/librustc_middle/ty/layout.rs
+++ b/src/librustc_middle/ty/layout.rs
@@ -876,6 +876,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                     .iter_enumerated()
                     .all(|(i, v)| v.discr == ty::VariantDiscr::Relative(i.as_u32()));
 
+                let mut niche_filling_layout = None;
+
                 // Niche-filling enum optimization.
                 if !def.repr.inhibit_enum_layout_opt() && no_explicit_discriminants {
                     let mut dataful_variant = None;
@@ -972,7 +974,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                             let largest_niche =
                                 Niche::from_scalar(dl, offset, niche_scalar.clone());
 
-                            return Ok(tcx.intern_layout(Layout {
+                            niche_filling_layout = Some(Layout {
                                 variants: Variants::Multiple {
                                     tag: niche_scalar,
                                     tag_encoding: TagEncoding::Niche {
@@ -991,7 +993,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                                 largest_niche,
                                 size,
                                 align,
-                            }));
+                            });
                         }
                     }
                 }
@@ -1214,7 +1216,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
 
                 let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag.clone());
 
-                tcx.intern_layout(Layout {
+                let tagged_layout = Layout {
                     variants: Variants::Multiple {
                         tag,
                         tag_encoding: TagEncoding::Direct,
@@ -1229,7 +1231,23 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                     abi,
                     align,
                     size,
-                })
+                };
+
+                let best_layout = match (tagged_layout, niche_filling_layout) {
+                    (tagged_layout, Some(niche_filling_layout)) => {
+                        // Pick the smaller layout; otherwise,
+                        // pick the layout with the larger niche; otherwise,
+                        // pick tagged as it has simpler codegen.
+                        cmp::min_by_key(tagged_layout, niche_filling_layout, |layout| {
+                            let niche_size =
+                                layout.largest_niche.as_ref().map_or(0, |n| n.available(dl));
+                            (layout.size, cmp::Reverse(niche_size))
+                        })
+                    }
+                    (tagged_layout, None) => tagged_layout,
+                };
+
+                tcx.intern_layout(best_layout)
             }
 
             // Types with no meaningful known layout.
diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs
index 0102225b9b5..6798addb8aa 100644
--- a/src/librustc_middle/ty/mod.rs
+++ b/src/librustc_middle/ty/mod.rs
@@ -575,10 +575,6 @@ bitflags! {
         /// Does this value have parameters/placeholders/inference variables which could be
         /// replaced later, in a way that would change the results of `impl` specialization?
         const STILL_FURTHER_SPECIALIZABLE = 1 << 17;
-
-        /// Does this value contain closures, generators or functions such that it may require
-        /// polymorphization?
-        const MAY_POLYMORPHIZE = 1 << 18;
     }
 }
 
diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs
index 3bb9c20370e..87944db60de 100644
--- a/src/librustc_middle/ty/print/pretty.rs
+++ b/src/librustc_middle/ty/print/pretty.rs
@@ -1107,7 +1107,7 @@ pub trait PrettyPrinter<'tcx>:
                 // The `inspect` here is okay since we checked the bounds, and there are
                 // no relocations (we have an active slice reference here). We don't use
                 // this result to affect interpreter execution.
-                let byte_str = data.inspect_with_undef_and_ptr_outside_interpreter(start..end);
+                let byte_str = data.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
                 self.pretty_print_byte_str(byte_str)
             }
             (
@@ -1117,7 +1117,7 @@ pub trait PrettyPrinter<'tcx>:
                 // The `inspect` here is okay since we checked the bounds, and there are no
                 // relocations (we have an active `str` reference here). We don't use this
                 // result to affect interpreter execution.
-                let slice = data.inspect_with_undef_and_ptr_outside_interpreter(start..end);
+                let slice = data.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
                 let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri");
                 p!(write("{:?}", s));
                 Ok(self)
diff --git a/src/librustc_mir/const_eval/error.rs b/src/librustc_mir/const_eval/error.rs
index 8a72be33b84..044d27a6a9d 100644
--- a/src/librustc_mir/const_eval/error.rs
+++ b/src/librustc_mir/const_eval/error.rs
@@ -1,12 +1,16 @@
 use std::error::Error;
 use std::fmt;
 
+use rustc_errors::{DiagnosticBuilder, ErrorReported};
+use rustc_hir as hir;
 use rustc_middle::mir::AssertKind;
-use rustc_middle::ty::ConstInt;
+use rustc_middle::ty::{layout::LayoutError, query::TyCtxtAt, ConstInt};
 use rustc_span::{Span, Symbol};
 
 use super::InterpCx;
-use crate::interpret::{ConstEvalErr, InterpErrorInfo, Machine};
+use crate::interpret::{
+    struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine,
+};
 
 /// The CTFE machine has some custom error kinds.
 #[derive(Clone, Debug)]
@@ -48,15 +52,155 @@ impl fmt::Display for ConstEvalErrKind {
 
 impl Error for ConstEvalErrKind {}
 
-/// Turn an interpreter error into something to report to the user.
-/// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace.
-/// Should be called only if the error is actually going to to be reported!
-pub fn error_to_const_error<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>(
-    ecx: &InterpCx<'mir, 'tcx, M>,
-    error: InterpErrorInfo<'tcx>,
-    span: Option<Span>,
-) -> ConstEvalErr<'tcx> {
-    error.print_backtrace();
-    let stacktrace = ecx.generate_stacktrace();
-    ConstEvalErr { error: error.kind, stacktrace, span: span.unwrap_or_else(|| ecx.cur_span()) }
+/// When const-evaluation errors, this type is constructed with the resulting information,
+/// and then used to emit the error as a lint or hard error.
+#[derive(Debug)]
+pub struct ConstEvalErr<'tcx> {
+    pub span: Span,
+    pub error: InterpError<'tcx>,
+    pub stacktrace: Vec<FrameInfo<'tcx>>,
+}
+
+impl<'tcx> ConstEvalErr<'tcx> {
+    /// Turn an interpreter error into something to report to the user.
+    /// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace.
+    /// Should be called only if the error is actually going to to be reported!
+    pub fn new<'mir, M: Machine<'mir, 'tcx>>(
+        ecx: &InterpCx<'mir, 'tcx, M>,
+        error: InterpErrorInfo<'tcx>,
+        span: Option<Span>,
+    ) -> ConstEvalErr<'tcx>
+    where
+        'tcx: 'mir,
+    {
+        error.print_backtrace();
+        let stacktrace = ecx.generate_stacktrace();
+        ConstEvalErr { error: error.kind, stacktrace, span: span.unwrap_or_else(|| ecx.cur_span()) }
+    }
+
+    pub fn struct_error(
+        &self,
+        tcx: TyCtxtAt<'tcx>,
+        message: &str,
+        emit: impl FnOnce(DiagnosticBuilder<'_>),
+    ) -> ErrorHandled {
+        self.struct_generic(tcx, message, emit, None)
+    }
+
+    pub fn report_as_error(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled {
+        self.struct_error(tcx, message, |mut e| e.emit())
+    }
+
+    pub fn report_as_lint(
+        &self,
+        tcx: TyCtxtAt<'tcx>,
+        message: &str,
+        lint_root: hir::HirId,
+        span: Option<Span>,
+    ) -> ErrorHandled {
+        self.struct_generic(
+            tcx,
+            message,
+            |mut lint: DiagnosticBuilder<'_>| {
+                // Apply the span.
+                if let Some(span) = span {
+                    let primary_spans = lint.span.primary_spans().to_vec();
+                    // point at the actual error as the primary span
+                    lint.replace_span_with(span);
+                    // point to the `const` statement as a secondary span
+                    // they don't have any label
+                    for sp in primary_spans {
+                        if sp != span {
+                            lint.span_label(sp, "");
+                        }
+                    }
+                }
+                lint.emit();
+            },
+            Some(lint_root),
+        )
+    }
+
+    /// Create a diagnostic for this const eval error.
+    ///
+    /// Sets the message passed in via `message` and adds span labels with detailed error
+    /// information before handing control back to `emit` to do any final processing.
+    /// It's the caller's responsibility to call emit(), stash(), etc. within the `emit`
+    /// function to dispose of the diagnostic properly.
+    ///
+    /// If `lint_root.is_some()` report it as a lint, else report it as a hard error.
+    /// (Except that for some errors, we ignore all that -- see `must_error` below.)
+    fn struct_generic(
+        &self,
+        tcx: TyCtxtAt<'tcx>,
+        message: &str,
+        emit: impl FnOnce(DiagnosticBuilder<'_>),
+        lint_root: Option<hir::HirId>,
+    ) -> ErrorHandled {
+        let must_error = match self.error {
+            err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
+                return ErrorHandled::TooGeneric;
+            }
+            err_inval!(TypeckError(error_reported)) => {
+                return ErrorHandled::Reported(error_reported);
+            }
+            // We must *always* hard error on these, even if the caller wants just a lint.
+            err_inval!(Layout(LayoutError::SizeOverflow(_))) => true,
+            _ => false,
+        };
+        trace!("reporting const eval failure at {:?}", self.span);
+
+        let err_msg = match &self.error {
+            InterpError::MachineStop(msg) => {
+                // A custom error (`ConstEvalErrKind` in `librustc_mir/interp/const_eval/error.rs`).
+                // Should be turned into a string by now.
+                msg.downcast_ref::<String>().expect("invalid MachineStop payload").clone()
+            }
+            err => err.to_string(),
+        };
+
+        let finish = |mut err: DiagnosticBuilder<'_>, span_msg: Option<String>| {
+            if let Some(span_msg) = span_msg {
+                err.span_label(self.span, span_msg);
+            }
+            // Add spans for the stacktrace. Don't print a single-line backtrace though.
+            if self.stacktrace.len() > 1 {
+                for frame_info in &self.stacktrace {
+                    err.span_label(frame_info.span, frame_info.to_string());
+                }
+            }
+            // Let the caller finish the job.
+            emit(err)
+        };
+
+        if must_error {
+            // The `message` makes little sense here, this is a more serious error than the
+            // caller thinks anyway.
+            // See <https://github.com/rust-lang/rust/pull/63152>.
+            finish(struct_error(tcx, &err_msg), None);
+            ErrorHandled::Reported(ErrorReported)
+        } else {
+            // Regular case.
+            if let Some(lint_root) = lint_root {
+                // Report as lint.
+                let hir_id = self
+                    .stacktrace
+                    .iter()
+                    .rev()
+                    .find_map(|frame| frame.lint_root)
+                    .unwrap_or(lint_root);
+                tcx.struct_span_lint_hir(
+                    rustc_session::lint::builtin::CONST_ERR,
+                    hir_id,
+                    tcx.span,
+                    |lint| finish(lint.build(message), Some(err_msg)),
+                );
+                ErrorHandled::Linted
+            } else {
+                // Report as hard error.
+                finish(struct_error(tcx, message), Some(err_msg));
+                ErrorHandled::Reported(ErrorReported)
+            }
+        }
+    }
 }
diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs
index 42fba8982d2..7fbe5c409d3 100644
--- a/src/librustc_mir/const_eval/eval_queries.rs
+++ b/src/librustc_mir/const_eval/eval_queries.rs
@@ -1,13 +1,14 @@
-use super::{error_to_const_error, CompileTimeEvalContext, CompileTimeInterpreter, MemoryExtra};
+use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr, MemoryExtra};
 use crate::interpret::eval_nullary_intrinsic;
 use crate::interpret::{
     intern_const_alloc_recursive, Allocation, ConstValue, GlobalId, Immediate, InternKind,
     InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RawConst, RefTracking, Scalar,
     ScalarMaybeUninit, StackPopCleanup,
 };
+
 use rustc_hir::def::DefKind;
 use rustc_middle::mir;
-use rustc_middle::mir::interpret::{ConstEvalErr, ErrorHandled};
+use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::{self, subst::Subst, TyCtxt};
 use rustc_span::source_map::Span;
@@ -213,7 +214,7 @@ fn validate_and_turn_into_const<'tcx>(
     })();
 
     val.map_err(|error| {
-        let err = error_to_const_error(&ecx, error, None);
+        let err = ConstEvalErr::new(&ecx, error, None);
         err.struct_error(ecx.tcx, "it is undefined behavior to use this value", |mut diag| {
             diag.note(note_on_undefined_behavior_error());
             diag.emit();
@@ -312,7 +313,7 @@ pub fn const_eval_raw_provider<'tcx>(
     res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body))
         .map(|place| RawConst { alloc_id: place.ptr.assert_ptr().alloc_id, ty: place.layout.ty })
         .map_err(|error| {
-            let err = error_to_const_error(&ecx, error, None);
+            let err = ConstEvalErr::new(&ecx, error, None);
             // errors in statics are always emitted as fatal errors
             if is_static {
                 // Ensure that if the above error was either `TooGeneric` or `Reported`
diff --git a/src/librustc_mir/const_eval/machine.rs b/src/librustc_mir/const_eval/machine.rs
index 0dac8b64910..2d0e68d5894 100644
--- a/src/librustc_mir/const_eval/machine.rs
+++ b/src/librustc_mir/const_eval/machine.rs
@@ -302,6 +302,19 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
     }
 
     #[inline(always)]
+    fn init_frame_extra(
+        ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        frame: Frame<'mir, 'tcx>,
+    ) -> InterpResult<'tcx, Frame<'mir, 'tcx>> {
+        // Enforce stack size limit. Add 1 because this is run before the new frame is pushed.
+        if !ecx.tcx.sess.recursion_limit().value_within_limit(ecx.stack().len() + 1) {
+            throw_exhaust!(StackFrameLimitReached)
+        } else {
+            Ok(frame)
+        }
+    }
+
+    #[inline(always)]
     fn stack(
         ecx: &'a InterpCx<'mir, 'tcx, Self>,
     ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] {
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 1e9be097815..525da87463a 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -1,22 +1,22 @@
 use std::cell::Cell;
+use std::fmt;
 use std::mem;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_hir::def::DefKind;
-use rustc_hir::def_id::DefId;
+use rustc_hir::{self as hir, def::DefKind, def_id::DefId, definitions::DefPathData};
 use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable;
 use rustc_middle::ich::StableHashingContext;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::{
-    sign_extend, truncate, FrameInfo, GlobalId, InterpResult, Pointer, Scalar,
+    sign_extend, truncate, GlobalId, InterpResult, Pointer, Scalar,
 };
 use rustc_middle::ty::layout::{self, TyAndLayout};
 use rustc_middle::ty::{
     self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable,
 };
-use rustc_span::{source_map::DUMMY_SP, Span};
+use rustc_span::{Pos, Span};
 use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size, TargetDataLayout};
 
 use super::{
@@ -83,9 +83,19 @@ pub struct Frame<'mir, 'tcx, Tag = (), Extra = ()> {
     ////////////////////////////////////////////////////////////////////////////////
     // Current position within the function
     ////////////////////////////////////////////////////////////////////////////////
-    /// If this is `None`, we are unwinding and this function doesn't need any clean-up.
-    /// Just continue the same as with `Resume`.
-    pub loc: Option<mir::Location>,
+    /// If this is `Err`, we are not currently executing any particular statement in
+    /// this frame (can happen e.g. during frame initialization, and during unwinding on
+    /// frames without cleanup code).
+    /// We basically abuse `Result` as `Either`.
+    pub(super) loc: Result<mir::Location, Span>,
+}
+
+/// What we store about a frame in an interpreter backtrace.
+#[derive(Debug)]
+pub struct FrameInfo<'tcx> {
+    pub instance: ty::Instance<'tcx>,
+    pub span: Span,
+    pub lint_root: Option<hir::HirId>,
 }
 
 #[derive(Clone, Eq, PartialEq, Debug, HashStable)] // Miri debug-prints these
@@ -181,7 +191,33 @@ impl<'mir, 'tcx, Tag> Frame<'mir, 'tcx, Tag> {
 impl<'mir, 'tcx, Tag, Extra> Frame<'mir, 'tcx, Tag, Extra> {
     /// Return the `SourceInfo` of the current instruction.
     pub fn current_source_info(&self) -> Option<&mir::SourceInfo> {
-        self.loc.map(|loc| self.body.source_info(loc))
+        self.loc.ok().map(|loc| self.body.source_info(loc))
+    }
+
+    pub fn current_span(&self) -> Span {
+        match self.loc {
+            Ok(loc) => self.body.source_info(loc).span,
+            Err(span) => span,
+        }
+    }
+}
+
+impl<'tcx> fmt::Display for FrameInfo<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        ty::tls::with(|tcx| {
+            if tcx.def_key(self.instance.def_id()).disambiguated_data.data
+                == DefPathData::ClosureExpr
+            {
+                write!(f, "inside closure")?;
+            } else {
+                write!(f, "inside `{}`", self.instance)?;
+            }
+            if !self.span.is_dummy() {
+                let lo = tcx.sess.source_map().lookup_char_pos(self.span.lo());
+                write!(f, " at {}:{}:{}", lo.file.name, lo.line, lo.col.to_usize() + 1)?;
+            }
+            Ok(())
+        })
     }
 }
 
@@ -297,11 +333,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     #[inline(always)]
     pub fn cur_span(&self) -> Span {
-        self.stack()
-            .last()
-            .and_then(|f| f.current_source_info())
-            .map(|si| si.span)
-            .unwrap_or(self.tcx.span)
+        self.stack().last().map(|f| f.current_span()).unwrap_or(self.tcx.span)
     }
 
     #[inline(always)]
@@ -613,7 +645,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // first push a stack frame so we have access to the local substs
         let pre_frame = Frame {
             body,
-            loc: Some(mir::Location::START),
+            loc: Err(body.span), // Span used for errors caused during preamble.
             return_to_block,
             return_place,
             // empty local array, we fill it in below, after we are inside the stack frame and
@@ -625,6 +657,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let frame = M::init_frame_extra(self, pre_frame)?;
         self.stack_mut().push(frame);
 
+        // Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
+        for const_ in &body.required_consts {
+            let span = const_.span;
+            let const_ =
+                self.subst_from_current_frame_and_normalize_erasing_regions(const_.literal);
+            self.const_to_op(const_, None).map_err(|err| {
+                // If there was an error, set the span of the current frame to this constant.
+                // Avoiding doing this when evaluation succeeds.
+                self.frame_mut().loc = Err(span);
+                err
+            })?;
+        }
+
         // Locals are initially uninitialized.
         let dummy = LocalState { value: LocalValue::Uninitialized, layout: Cell::new(None) };
         let mut locals = IndexVec::from_elem(dummy, &body.local_decls);
@@ -649,21 +694,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         }
         // done
         self.frame_mut().locals = locals;
-
         M::after_stack_push(self)?;
+        self.frame_mut().loc = Ok(mir::Location::START);
         info!("ENTERING({}) {}", self.frame_idx(), self.frame().instance);
 
-        if !self.tcx.sess.recursion_limit().value_within_limit(self.stack().len()) {
-            throw_exhaust!(StackFrameLimitReached)
-        } else {
-            Ok(())
-        }
+        Ok(())
     }
 
     /// Jump to the given block.
     #[inline]
     pub fn go_to_block(&mut self, target: mir::BasicBlock) {
-        self.frame_mut().loc = Some(mir::Location { block: target, statement_index: 0 });
+        self.frame_mut().loc = Ok(mir::Location { block: target, statement_index: 0 });
     }
 
     /// *Return* to the given `target` basic block.
@@ -685,7 +726,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// If `target` is `None`, that indicates the function does not need cleanup during
     /// unwinding, and we will just keep propagating that upwards.
     pub fn unwind_to_block(&mut self, target: Option<mir::BasicBlock>) {
-        self.frame_mut().loc = target.map(|block| mir::Location { block, statement_index: 0 });
+        self.frame_mut().loc = match target {
+            Some(block) => Ok(mir::Location { block, statement_index: 0 }),
+            None => Err(self.frame_mut().body.span),
+        };
     }
 
     /// Pops the current frame from the stack, deallocating the
@@ -713,8 +757,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         assert_eq!(
             unwinding,
             match self.frame().loc {
-                None => true,
-                Some(loc) => self.body().basic_blocks()[loc.block].is_cleanup,
+                Ok(loc) => self.body().basic_blocks()[loc.block].is_cleanup,
+                Err(_) => true,
             }
         );
 
@@ -890,14 +934,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn generate_stacktrace(&self) -> Vec<FrameInfo<'tcx>> {
         let mut frames = Vec::new();
         for frame in self.stack().iter().rev() {
-            let source_info = frame.current_source_info();
-            let lint_root = source_info.and_then(|source_info| {
+            let lint_root = frame.current_source_info().and_then(|source_info| {
                 match &frame.body.source_scopes[source_info.scope].local_data {
                     mir::ClearCrossCrate::Set(data) => Some(data.lint_root),
                     mir::ClearCrossCrate::Clear => None,
                 }
             });
-            let span = source_info.map_or(DUMMY_SP, |source_info| source_info.span);
+            let span = frame.current_span();
 
             frames.push(FrameInfo { span, instance: frame.instance, lint_root });
         }
diff --git a/src/librustc_mir/interpret/intrinsics/caller_location.rs b/src/librustc_mir/interpret/intrinsics/caller_location.rs
index 9adef8c43c7..fb3a670714b 100644
--- a/src/librustc_mir/interpret/intrinsics/caller_location.rs
+++ b/src/librustc_mir/interpret/intrinsics/caller_location.rs
@@ -30,8 +30,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             // Assert that there is always such a frame.
             .unwrap();
         // Assert that the frame we look at is actually executing code currently
-        // (`current_source_info` is None when we are unwinding and the frame does
-        // not require cleanup).
+        // (`loc` is `Err` when we are unwinding and the frame does not require cleanup).
         let loc = frame.loc.unwrap();
         // If this is a `Call` terminator, use the `fn_span` instead.
         let block = &frame.body.basic_blocks()[loc.block];
diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs
index 634f3c96e6c..5cab4ba37e3 100644
--- a/src/librustc_mir/interpret/machine.rs
+++ b/src/librustc_mir/interpret/machine.rs
@@ -409,12 +409,4 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
     ) -> Self::PointerTag {
         ()
     }
-
-    #[inline(always)]
-    fn init_frame_extra(
-        _ecx: &mut InterpCx<$mir, $tcx, Self>,
-        frame: Frame<$mir, $tcx>,
-    ) -> InterpResult<$tcx, Frame<$mir, $tcx>> {
-        Ok(frame)
-    }
 }
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index 7dfa913fd08..49d97ff7cec 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -14,13 +14,12 @@ use std::ptr;
 
 use rustc_ast::ast::Mutability;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::def_id::DefId;
-use rustc_middle::ty::{self, Instance, ParamEnv, TyCtxt};
+use rustc_middle::ty::{Instance, ParamEnv, TyCtxt};
 use rustc_target::abi::{Align, HasDataLayout, Size, TargetDataLayout};
 
 use super::{
-    AllocId, AllocMap, Allocation, AllocationExtra, CheckInAllocMsg, GlobalAlloc, GlobalId,
-    InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Scalar,
+    AllocId, AllocMap, Allocation, AllocationExtra, CheckInAllocMsg, GlobalAlloc, InterpResult,
+    Machine, MayLeak, Pointer, PointerArithmetic, Scalar,
 };
 use crate::util::pretty;
 
@@ -119,17 +118,6 @@ pub struct Memory<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
     pub tcx: TyCtxt<'tcx>,
 }
 
-/// Return the `tcx` allocation containing the initial value of the given static
-pub fn get_static(tcx: TyCtxt<'tcx>, def_id: DefId) -> InterpResult<'tcx, &'tcx Allocation> {
-    trace!("get_static: Need to compute {:?}", def_id);
-    let instance = Instance::mono(tcx, def_id);
-    let gid = GlobalId { instance, promoted: None };
-    // Use the raw query here to break validation cycles. Later uses of the static
-    // will call the full query anyway.
-    let raw_const = tcx.const_eval_raw(ty::ParamEnv::reveal_all().and(gid))?;
-    Ok(tcx.global_alloc(raw_const.alloc_id).unwrap_memory())
-}
-
 impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for Memory<'mir, 'tcx, M> {
     #[inline]
     fn data_layout(&self) -> &TargetDataLayout {
@@ -489,7 +477,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
                     throw_unsup!(ReadExternStatic(def_id));
                 }
 
-                (get_static(tcx, def_id)?, Some(def_id))
+                (tcx.eval_static_initializer(def_id)?, Some(def_id))
             }
         };
         M::before_access_global(memory_extra, id, alloc, def_id, is_write)?;
@@ -926,7 +914,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
         // first copy the relocations to a temporary buffer, because
         // `get_bytes_mut` will clear the relocations, which is correct,
         // since we don't want to keep any relocations at the target.
-        // (`get_bytes_with_undef_and_ptr` below checks that there are no
+        // (`get_bytes_with_uninit_and_ptr` below checks that there are no
         // relocations overlapping the edges; those would not be handled correctly).
         let relocations =
             self.get_raw(src.alloc_id)?.prepare_relocation_copy(self, src, size, dest, length);
@@ -935,7 +923,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
 
         // This checks relocation edges on the src.
         let src_bytes =
-            self.get_raw(src.alloc_id)?.get_bytes_with_undef_and_ptr(&tcx, src, size)?.as_ptr();
+            self.get_raw(src.alloc_id)?.get_bytes_with_uninit_and_ptr(&tcx, src, size)?.as_ptr();
         let dest_bytes =
             self.get_raw_mut(dest.alloc_id)?.get_bytes_mut(&tcx, dest, size * length)?; // `Size` multiplication
 
@@ -948,7 +936,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
         let dest_bytes = dest_bytes.as_mut_ptr();
 
         // Prepare a copy of the initialization mask.
-        let compressed = self.get_raw(src.alloc_id)?.compress_undef_range(src, size);
+        let compressed = self.get_raw(src.alloc_id)?.compress_uninit_range(src, size);
 
         if compressed.no_bytes_init() {
             // Fast path: If all bytes are `uninit` then there is nothing to copy. The target range
diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs
index ebb061f4851..a931b0bbe97 100644
--- a/src/librustc_mir/interpret/mod.rs
+++ b/src/librustc_mir/interpret/mod.rs
@@ -18,10 +18,10 @@ mod visitor;
 
 pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here
 
-pub use self::eval_context::{Frame, InterpCx, LocalState, LocalValue, StackPopCleanup};
+pub use self::eval_context::{Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup};
 pub use self::intern::{intern_const_alloc_recursive, InternKind};
 pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump};
-pub use self::memory::{get_static, AllocCheck, FnVal, Memory, MemoryKind};
+pub use self::memory::{AllocCheck, FnVal, Memory, MemoryKind};
 pub use self::operand::{ImmTy, Immediate, OpTy, Operand};
 pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy};
 pub use self::validity::RefTracking;
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 49fde400913..0b58caef54d 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -106,7 +106,7 @@ impl<Tag: Copy> std::fmt::Display for ImmTy<'tcx, Tag> {
                 }
                 ScalarMaybeUninit::Uninit => cx.typed_value(
                     |mut this| {
-                        this.write_str("{undef ")?;
+                        this.write_str("{uninit ")?;
                         Ok(this)
                     },
                     |this| this.print_type(ty),
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 15e341d9c4c..20fd8e43361 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -61,7 +61,7 @@ impl<Tag> MemPlaceMeta<Tag> {
 pub struct MemPlace<Tag = ()> {
     /// A place may have an integral pointer for ZSTs, and since it might
     /// be turned back into a reference before ever being dereferenced.
-    /// However, it may never be undef.
+    /// However, it may never be uninit.
     pub ptr: Scalar<Tag>,
     pub align: Align,
     /// Metadata for unsized places. Interpretation is up to the type.
@@ -729,7 +729,7 @@ where
                         "Size mismatch when writing bits"
                     )
                 }
-                Immediate::Scalar(ScalarMaybeUninit::Uninit) => {} // undef can have any size
+                Immediate::Scalar(ScalarMaybeUninit::Uninit) => {} // uninit can have any size
                 Immediate::ScalarPair(_, _) => {
                     // FIXME: Can we check anything here?
                 }
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index fcd26c86c47..adecee3f7cb 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -47,8 +47,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         }
 
         let loc = match self.frame().loc {
-            Some(loc) => loc,
-            None => {
+            Ok(loc) => loc,
+            Err(_) => {
                 // We are unwinding and this fn has no cleanup code.
                 // Just go on unwinding.
                 trace!("unwinding: skipping frame");
@@ -74,7 +74,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         Ok(true)
     }
 
-    fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
+    /// Runs the interpretation logic for the given `mir::Statement` at the current frame and
+    /// statement counter. This also moves the statement counter forward.
+    crate fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
         info!("{:?}", stmt);
 
         use rustc_middle::mir::StatementKind::*;
@@ -281,7 +283,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
         self.eval_terminator(terminator)?;
         if !self.stack().is_empty() {
-            if let Some(loc) = self.frame().loc {
+            if let Ok(loc) = self.frame().loc {
                 info!("// executing {:?}", loc.block);
             }
         }
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index f1c5a67ed33..9cd20340138 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -508,12 +508,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                     }
                 } else {
                     // At run-time, for now, we accept *anything* for these types, including
-                    // undef. We should fix that, but let's start low.
+                    // uninit. We should fix that, but let's start low.
                 }
                 Ok(true)
             }
             ty::RawPtr(..) => {
-                // We are conservative with undef for integers, but try to
+                // We are conservative with uninit for integers, but try to
                 // actually enforce the strict rules for raw pointers (mostly because
                 // that lets us re-use `ref_to_mplace`).
                 let place = try_validation!(
@@ -807,12 +807,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
                 // reject it.  However, that's good: We don't inherently want
                 // to reject those pointers, we just do not have the machinery to
                 // talk about parts of a pointer.
-                // We also accept undef, for consistency with the slow path.
+                // We also accept uninit, for consistency with the slow path.
                 match self.ecx.memory.get_raw(ptr.alloc_id)?.check_bytes(
                     self.ecx,
                     ptr,
                     size,
-                    /*allow_ptr_and_undef*/ self.ref_tracking_for_consts.is_none(),
+                    /*allow_uninit_and_ptr*/ self.ref_tracking_for_consts.is_none(),
                 ) {
                     // In the happy case, we needn't check anything else.
                     Ok(()) => {}
diff --git a/src/librustc_mir/monomorphize/polymorphize.rs b/src/librustc_mir/monomorphize/polymorphize.rs
index a996b6fb9d9..fc9f7f1af62 100644
--- a/src/librustc_mir/monomorphize/polymorphize.rs
+++ b/src/librustc_mir/monomorphize/polymorphize.rs
@@ -269,15 +269,21 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UsedGenericParametersVisitor<'a, 'tcx> {
                 self.unused_parameters.clear(param.index);
                 false
             }
-            ty::ConstKind::Unevaluated(_, _, Some(p)) => {
+            ty::ConstKind::Unevaluated(def, _, Some(p))
+                // Avoid considering `T` unused when constants are of the form:
+                //   `<Self as Foo<T>>::foo::promoted[p]`
+                if self.def_id == def.did && !self.tcx.generics_of(def.did).has_self =>
+            {
                 // If there is a promoted, don't look at the substs - since it will always contain
                 // the generic parameters, instead, traverse the promoted MIR.
-                let promoted = self.tcx.promoted_mir(self.def_id);
+                let promoted = self.tcx.promoted_mir(def.did);
                 self.visit_body(&promoted[p]);
                 false
             }
-            ty::ConstKind::Unevaluated(def_id, unevaluated_substs, None) => {
-                self.visit_child_body(def_id.did, unevaluated_substs);
+            ty::ConstKind::Unevaluated(def, unevaluated_substs, None)
+                if self.tcx.def_kind(def.did) == DefKind::AnonConst =>
+            {
+                self.visit_child_body(def.did, unevaluated_substs);
                 false
             }
             _ => c.super_visit_with(self),
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index db0b0415728..3b39d5f66b7 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -26,7 +26,7 @@ use rustc_span::{def_id::DefId, Span};
 use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TargetDataLayout};
 use rustc_trait_selection::traits;
 
-use crate::const_eval::error_to_const_error;
+use crate::const_eval::ConstEvalErr;
 use crate::interpret::{
     self, compile_time_machine, truncate, AllocId, Allocation, Frame, ImmTy, Immediate, InterpCx,
     LocalState, LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy,
@@ -252,6 +252,11 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
             throw_machine_stop_str!("tried to write to a local that is marked as not propagatable")
         }
         if frame == 0 && ecx.machine.only_propagate_inside_block_locals.contains(local) {
+            trace!(
+                "mutating local {:?} which is restricted to its block. \
+                Will remove it from const-prop after block is finished.",
+                local
+            );
             ecx.machine.written_only_inside_own_block_locals.insert(local);
         }
         ecx.machine.stack[frame].locals[local].access_mut()
@@ -277,6 +282,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
     }
 
     #[inline(always)]
+    fn init_frame_extra(
+        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        frame: Frame<'mir, 'tcx>,
+    ) -> InterpResult<'tcx, Frame<'mir, 'tcx>> {
+        Ok(frame)
+    }
+
+    #[inline(always)]
     fn stack(
         ecx: &'a InterpCx<'mir, 'tcx, Self>,
     ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] {
@@ -427,6 +440,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         match f(self) {
             Ok(val) => Some(val),
             Err(error) => {
+                trace!("InterpCx operation failed: {:?}", error);
                 // Some errors shouldn't come up because creating them causes
                 // an allocation, which we should avoid. When that happens,
                 // dedicated error variants should be introduced instead.
@@ -451,7 +465,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             Ok(op) => Some(op),
             Err(error) => {
                 let tcx = self.ecx.tcx.at(c.span);
-                let err = error_to_const_error(&self.ecx, error, Some(c.span));
+                let err = ConstEvalErr::new(&self.ecx, error, Some(c.span));
                 if let Some(lint_root) = self.lint_root(source_info) {
                     let lint_only = match c.literal.val {
                         // Promoteds must lint and not error as the user didn't ask for them
@@ -969,10 +983,10 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
                         ConstPropMode::OnlyPropagateInto => {}
                         other @ ConstPropMode::FullConstProp => {
                             trace!(
-                                "local {:?} can't be propagated because of multiple assignments",
-                                local,
+                                "local {:?} can't be propagated because of multiple assignments. Previous state: {:?}",
+                                local, other,
                             );
-                            *other = ConstPropMode::OnlyPropagateInto;
+                            *other = ConstPropMode::OnlyInsideOwnBlock;
                         }
                     }
                 }
@@ -1076,7 +1090,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
                 // ```rust
                 // let mut x = 42;
                 // x = SOME_MUTABLE_STATIC;
-                // // x must now be undefined
+                // // x must now be uninit
                 // ```
                 // FIXME: we overzealously erase the entire local, because that's easier to
                 // implement.
@@ -1089,6 +1103,20 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
             }
         } else {
             match statement.kind {
+                StatementKind::SetDiscriminant { ref place, .. } => {
+                    match self.ecx.machine.can_const_prop[place.local] {
+                        ConstPropMode::FullConstProp | ConstPropMode::OnlyInsideOwnBlock => {
+                            if self.use_ecx(|this| this.ecx.statement(statement)).is_some() {
+                                trace!("propped discriminant into {:?}", place);
+                            } else {
+                                Self::remove_const(&mut self.ecx, place.local);
+                            }
+                        }
+                        ConstPropMode::OnlyPropagateInto | ConstPropMode::NoPropagation => {
+                            Self::remove_const(&mut self.ecx, place.local);
+                        }
+                    }
+                }
                 StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => {
                     let frame = self.ecx.frame_mut();
                     frame.locals[local].value =
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 26b4a696897..3803ee78fd4 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -408,6 +408,9 @@ fn run_post_borrowck_cleanup_passes<'tcx>(
         // but before optimizations begin.
         &add_retag::AddRetag,
         &simplify::SimplifyCfg::new("elaborate-drops"),
+        // `Deaggregator` is conceptually part of MIR building, some backends rely on it happening
+        // and it can help optimizations.
+        &deaggregator::Deaggregator,
     ];
 
     run_passes(
@@ -439,11 +442,6 @@ fn run_optimization_passes<'tcx>(
         &instcombine::InstCombine,
         &const_prop::ConstProp,
         &simplify_branches::SimplifyBranches::new("after-const-prop"),
-        // Run deaggregation here because:
-        //   1. Some codegen backends require it
-        //   2. It creates additional possibilities for some MIR optimizations to trigger
-        // FIXME(#70073): Why is this done here and not in `post_borrowck_cleanup`?
-        &deaggregator::Deaggregator,
         &simplify_try::SimplifyArmIdentity,
         &simplify_try::SimplifyBranchSame,
         &copy_prop::CopyPropagation,
@@ -460,9 +458,6 @@ fn run_optimization_passes<'tcx>(
         &generator::StateTransform,
         // FIXME(#70073): This pass is responsible for both optimization as well as some lints.
         &const_prop::ConstProp,
-        // Even if we don't do optimizations, still run deaggregation because some backends assume
-        // that deaggregation always occurs.
-        &deaggregator::Deaggregator,
     ];
 
     let pre_codegen_cleanup: &[&dyn MirPass<'tcx>] = &[
diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs
index 25657ba98b8..c3dbac08ed8 100644
--- a/src/librustc_mir/util/pretty.rs
+++ b/src/librustc_mir/util/pretty.rs
@@ -743,8 +743,8 @@ fn write_allocation_bytes<Tag: Copy + Debug, Extra>(
         if let Some(&(tag, target_id)) = alloc.relocations().get(&i) {
             // Memory with a relocation must be defined
             let j = i.bytes_usize();
-            let offset =
-                alloc.inspect_with_undef_and_ptr_outside_interpreter(j..j + ptr_size.bytes_usize());
+            let offset = alloc
+                .inspect_with_uninit_and_ptr_outside_interpreter(j..j + ptr_size.bytes_usize());
             let offset = read_target_uint(tcx.data_layout.endian, offset).unwrap();
             let offset = Size::from_bytes(offset);
             let relocation_width = |bytes| bytes * 3;
@@ -803,7 +803,7 @@ fn write_allocation_bytes<Tag: Copy + Debug, Extra>(
 
             // Checked definedness (and thus range) and relocations. This access also doesn't
             // influence interpreter execution but is only for debugging.
-            let c = alloc.inspect_with_undef_and_ptr_outside_interpreter(j..j + 1)[0];
+            let c = alloc.inspect_with_uninit_and_ptr_outside_interpreter(j..j + 1)[0];
             write!(w, "{:02x}", c)?;
             if c.is_ascii_control() || c >= 0x80 {
                 ascii.push('.');
diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs
index 55a134ae091..9b99eb2e0bd 100644
--- a/src/librustc_parse/parser/expr.rs
+++ b/src/librustc_parse/parser/expr.rs
@@ -195,6 +195,29 @@ impl<'a> Parser<'a> {
                     return Ok(expr);
                 }
             }
+
+            if (op.node == AssocOp::Equal || op.node == AssocOp::NotEqual)
+                && self.token.kind == token::Eq
+                && self.prev_token.span.hi() == self.token.span.lo()
+            {
+                // Look for JS' `===` and `!==` and recover 😇
+                let sp = op.span.to(self.token.span);
+                let sugg = match op.node {
+                    AssocOp::Equal => "==",
+                    AssocOp::NotEqual => "!=",
+                    _ => unreachable!(),
+                };
+                self.struct_span_err(sp, &format!("invalid comparison operator `{}=`", sugg))
+                    .span_suggestion_short(
+                        sp,
+                        &format!("`{s}=` is not a valid comparison operator, use `{s}`", s = sugg),
+                        sugg.to_string(),
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
+                self.bump();
+            }
+
             let op = op.node;
             // Special cases:
             if op == AssocOp::As {
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 2aa7780aaaf..3ba5acd00a0 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -784,11 +784,18 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
             // The interface is empty.
             hir::ItemKind::GlobalAsm(..) => {}
             hir::ItemKind::OpaqueTy(..) => {
-                // FIXME: This is some serious pessimization intended to workaround deficiencies
-                // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time
-                // reachable if they are returned via `impl Trait`, even from private functions.
-                let exist_level = cmp::max(item_level, Some(AccessLevel::ReachableFromImplTrait));
-                self.reach(item.hir_id, exist_level).generics().predicates().ty();
+                // HACK(jynelson): trying to infer the type of `impl trait` breaks `async-std` (and `pub async fn` in general)
+                // Since rustdoc never need to do codegen and doesn't care about link-time reachability,
+                // mark this as unreachable.
+                // See https://github.com/rust-lang/rust/issues/75100
+                if !self.tcx.sess.opts.actually_rustdoc {
+                    // FIXME: This is some serious pessimization intended to workaround deficiencies
+                    // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time
+                    // reachable if they are returned via `impl Trait`, even from private functions.
+                    let exist_level =
+                        cmp::max(item_level, Some(AccessLevel::ReachableFromImplTrait));
+                    self.reach(item.hir_id, exist_level).generics().predicates().ty();
+                }
             }
             // Visit everything.
             hir::ItemKind::Const(..)
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index 9502be728de..de92204a7c2 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -942,17 +942,6 @@ impl<'a> Resolver<'a> {
             Some(suggestion) if suggestion.candidate == kw::Underscore => return false,
             Some(suggestion) => suggestion,
         };
-        let msg = format!(
-            "{} {} with a similar name exists",
-            suggestion.res.article(),
-            suggestion.res.descr()
-        );
-        err.span_suggestion(
-            span,
-            &msg,
-            suggestion.candidate.to_string(),
-            Applicability::MaybeIncorrect,
-        );
         let def_span = suggestion.res.opt_def_id().and_then(|def_id| match def_id.krate {
             LOCAL_CRATE => self.opt_span(def_id),
             _ => Some(
@@ -961,9 +950,30 @@ impl<'a> Resolver<'a> {
                     .guess_head_span(self.cstore().get_span_untracked(def_id, self.session)),
             ),
         });
-        if let Some(span) = def_span {
+        if let Some(def_span) = def_span {
+            if span.overlaps(def_span) {
+                // Don't suggest typo suggestion for itself like in the followoing:
+                // error[E0423]: expected function, tuple struct or tuple variant, found struct `X`
+                //   --> $DIR/issue-64792-bad-unicode-ctor.rs:3:14
+                //    |
+                // LL | struct X {}
+                //    | ----------- `X` defined here
+                // LL |
+                // LL | const Y: X = X("ö");
+                //    | -------------^^^^^^- similarly named constant `Y` defined here
+                //    |
+                // help: use struct literal syntax instead
+                //    |
+                // LL | const Y: X = X {};
+                //    |              ^^^^
+                // help: a constant with a similar name exists
+                //    |
+                // LL | const Y: X = Y("ö");
+                //    |              ^
+                return false;
+            }
             err.span_label(
-                self.session.source_map().guess_head_span(span),
+                self.session.source_map().guess_head_span(def_span),
                 &format!(
                     "similarly named {} `{}` defined here",
                     suggestion.res.descr(),
@@ -971,6 +981,17 @@ impl<'a> Resolver<'a> {
                 ),
             );
         }
+        let msg = format!(
+            "{} {} with a similar name exists",
+            suggestion.res.article(),
+            suggestion.res.descr()
+        );
+        err.span_suggestion(
+            span,
+            &msg,
+            suggestion.candidate.to_string(),
+            Applicability::MaybeIncorrect,
+        );
         true
     }
 
diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs
index ec6dbb070df..a7d36974057 100644
--- a/src/librustc_resolve/late/diagnostics.rs
+++ b/src/librustc_resolve/late/diagnostics.rs
@@ -12,12 +12,12 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}
 use rustc_hir as hir;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, DefKind};
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::PrimTy;
 use rustc_session::config::nightly_options;
 use rustc_span::hygiene::MacroKind;
-use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::{BytePos, Span};
+use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::{BytePos, Span, DUMMY_SP};
 
 use log::debug;
 
@@ -33,6 +33,7 @@ enum AssocSuggestion {
 crate enum MissingLifetimeSpot<'tcx> {
     Generics(&'tcx hir::Generics<'tcx>),
     HigherRanked { span: Span, span_type: ForLifetimeSpanType },
+    Static,
 }
 
 crate enum ForLifetimeSpanType {
@@ -88,6 +89,18 @@ fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, Str
 }
 
 impl<'a> LateResolutionVisitor<'a, '_, '_> {
+    fn def_span(&self, def_id: DefId) -> Option<Span> {
+        match def_id.krate {
+            LOCAL_CRATE => self.r.opt_span(def_id),
+            _ => Some(
+                self.r
+                    .session
+                    .source_map()
+                    .guess_head_span(self.r.cstore().get_span_untracked(def_id, self.r.session)),
+            ),
+        }
+    }
+
     /// Handles error reporting for `smart_resolve_path_fragment` function.
     /// Creates base error and amends it with one short label and possibly some longer helps/notes.
     pub(crate) fn smart_resolve_report_errors(
@@ -339,8 +352,6 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
 
         // Try Levenshtein algorithm.
         let typo_sugg = self.lookup_typo_candidate(path, ns, is_expected, span);
-        let levenshtein_worked = self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span);
-
         // Try context-dependent help if relaxed lookup didn't work.
         if let Some(res) = res {
             if self.smart_resolve_context_dependent_help(
@@ -351,14 +362,18 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
                 &path_str,
                 &fallback_label,
             ) {
+                // We do this to avoid losing a secondary span when we override the main error span.
+                self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span);
                 return (err, candidates);
             }
         }
 
-        // Fallback label.
-        if !levenshtein_worked {
+        if !self.type_ascription_suggestion(&mut err, base_span)
+            && !self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span)
+        {
+            // Fallback label.
             err.span_label(base_span, fallback_label);
-            self.type_ascription_suggestion(&mut err, base_span);
+
             match self.diagnostic_metadata.current_let_binding {
                 Some((pat_sp, Some(ty_sp), None)) if ty_sp.contains(base_span) && could_be_expr => {
                     err.span_suggestion_short(
@@ -378,15 +393,15 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
     /// return the span of whole call and the span for all arguments expect the first one (`self`).
     fn call_has_self_arg(&self, source: PathSource<'_>) -> Option<(Span, Option<Span>)> {
         let mut has_self_arg = None;
-        if let PathSource::Expr(parent) = source {
-            match &parent?.kind {
+        if let PathSource::Expr(Some(parent)) = source {
+            match &parent.kind {
                 ExprKind::Call(_, args) if !args.is_empty() => {
                     let mut expr_kind = &args[0].kind;
                     loop {
                         match expr_kind {
                             ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => {
                                 if arg_name.segments[0].ident.name == kw::SelfLower {
-                                    let call_span = parent.unwrap().span;
+                                    let call_span = parent.span;
                                     let tail_args_span = if args.len() > 1 {
                                         Some(Span::new(
                                             args[1].span.lo(),
@@ -518,6 +533,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
                     }),
                 ) if followed_by_brace => {
                     if let Some(sp) = closing_brace {
+                        err.span_label(span, fallback_label);
                         err.multipart_suggestion(
                             "surround the struct literal with parentheses",
                             vec![
@@ -550,7 +566,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
                         }
                         _ => span,
                     };
-                    if let Some(span) = self.r.opt_span(def_id) {
+                    if let Some(span) = self.def_span(def_id) {
                         err.span_label(span, &format!("`{}` defined here", path_str));
                     }
                     let (tail, descr, applicability) = match source {
@@ -581,12 +597,15 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
                         applicability,
                     );
                 }
-                _ => {}
+                _ => {
+                    err.span_label(span, fallback_label);
+                }
             }
         };
 
         match (res, source) {
             (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
+                err.span_label(span, fallback_label);
                 err.span_suggestion_verbose(
                     span.shrink_to_hi(),
                     "use `!` to invoke the macro",
@@ -602,7 +621,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
                 if nightly_options::is_nightly_build() {
                     let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \
                                `type` alias";
-                    if let Some(span) = self.r.opt_span(def_id) {
+                    if let Some(span) = self.def_span(def_id) {
                         err.span_help(span, msg);
                     } else {
                         err.help(msg);
@@ -680,10 +699,19 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
                 bad_struct_syntax_suggestion(def_id);
             }
             (Res::Def(DefKind::Ctor(_, CtorKind::Fn), def_id), _) if ns == ValueNS => {
-                if let Some(span) = self.r.opt_span(def_id) {
+                if let Some(span) = self.def_span(def_id) {
                     err.span_label(span, &format!("`{}` defined here", path_str));
                 }
-                err.span_label(span, format!("did you mean `{}( /* fields */ )`?", path_str));
+                let fields =
+                    self.r.field_names.get(&def_id).map_or("/* fields */".to_string(), |fields| {
+                        vec!["_"; fields.len()].join(", ")
+                    });
+                err.span_suggestion(
+                    span,
+                    "use the tuple variant pattern syntax instead",
+                    format!("{}({})", path_str, fields),
+                    Applicability::HasPlaceholders,
+                );
             }
             (Res::SelfTy(..), _) if ns == ValueNS => {
                 err.span_label(span, fallback_label);
@@ -869,7 +897,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
         start.to(sm.next_point(start))
     }
 
-    fn type_ascription_suggestion(&self, err: &mut DiagnosticBuilder<'_>, base_span: Span) {
+    fn type_ascription_suggestion(&self, err: &mut DiagnosticBuilder<'_>, base_span: Span) -> bool {
         let sm = self.r.session.source_map();
         let base_snippet = sm.span_to_snippet(base_span);
         if let Some(&sp) = self.diagnostic_metadata.current_type_ascription.last() {
@@ -939,9 +967,11 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
                             "expecting a type here because of type ascription",
                         );
                     }
+                    return show_label;
                 }
             }
         }
+        false
     }
 
     fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> {
@@ -1166,6 +1196,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
                             https://doc.rust-lang.org/nomicon/hrtb.html",
                     );
                 }
+                _ => {}
             }
         }
         if nightly_options::is_nightly_build()
@@ -1224,7 +1255,8 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
         err: &mut DiagnosticBuilder<'_>,
         span: Span,
         count: usize,
-        lifetime_names: &FxHashSet<Ident>,
+        lifetime_names: &FxHashSet<Symbol>,
+        lifetime_spans: Vec<Span>,
         params: &[ElisionFailureInfo],
     ) {
         let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok();
@@ -1238,11 +1270,60 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
             ),
         );
 
-        let suggest_existing = |err: &mut DiagnosticBuilder<'_>, sugg| {
+        let suggest_existing = |err: &mut DiagnosticBuilder<'_>,
+                                name: &str,
+                                formatter: &dyn Fn(&str) -> String| {
+            if let Some(MissingLifetimeSpot::HigherRanked { span: for_span, span_type }) =
+                self.missing_named_lifetime_spots.iter().rev().next()
+            {
+                // When we have `struct S<'a>(&'a dyn Fn(&X) -> &X);` we want to not only suggest
+                // using `'a`, but also introduce the concept of HRLTs by suggesting
+                // `struct S<'a>(&'a dyn for<'b> Fn(&X) -> &'b X);`. (#72404)
+                let mut introduce_suggestion = vec![];
+
+                let a_to_z_repeat_n = |n| {
+                    (b'a'..=b'z').map(move |c| {
+                        let mut s = '\''.to_string();
+                        s.extend(std::iter::repeat(char::from(c)).take(n));
+                        s
+                    })
+                };
+
+                // If all single char lifetime names are present, we wrap around and double the chars.
+                let lt_name = (1..)
+                    .flat_map(a_to_z_repeat_n)
+                    .find(|lt| !lifetime_names.contains(&Symbol::intern(&lt)))
+                    .unwrap();
+                let msg = format!(
+                    "consider making the {} lifetime-generic with a new `{}` lifetime",
+                    span_type.descr(),
+                    lt_name,
+                );
+                err.note(
+                    "for more information on higher-ranked polymorphism, visit \
+                    https://doc.rust-lang.org/nomicon/hrtb.html",
+                );
+                let for_sugg = span_type.suggestion(&lt_name);
+                for param in params {
+                    if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) {
+                        if snippet.starts_with('&') && !snippet.starts_with("&'") {
+                            introduce_suggestion
+                                .push((param.span, format!("&{} {}", lt_name, &snippet[1..])));
+                        } else if snippet.starts_with("&'_ ") {
+                            introduce_suggestion
+                                .push((param.span, format!("&{} {}", lt_name, &snippet[4..])));
+                        }
+                    }
+                }
+                introduce_suggestion.push((*for_span, for_sugg.to_string()));
+                introduce_suggestion.push((span, formatter(&lt_name)));
+                err.multipart_suggestion(&msg, introduce_suggestion, Applicability::MaybeIncorrect);
+            }
+
             err.span_suggestion_verbose(
                 span,
                 &format!("consider using the `{}` lifetime", lifetime_names.iter().next().unwrap()),
-                sugg,
+                formatter(name),
                 Applicability::MaybeIncorrect,
             );
         };
@@ -1253,6 +1334,15 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
                 let should_break;
                 introduce_suggestion.push(match missing {
                     MissingLifetimeSpot::Generics(generics) => {
+                        if generics.span == DUMMY_SP {
+                            // Account for malformed generics in the HIR. This shouldn't happen,
+                            // but if we make a mistake elsewhere, mainly by keeping something in
+                            // `missing_named_lifetime_spots` that we shouldn't, like associated
+                            // `const`s or making a mistake in the AST lowering we would provide
+                            // non-sensical suggestions. Guard against that by skipping these.
+                            // (#74264)
+                            continue;
+                        }
                         msg = "consider introducing a named lifetime parameter".to_string();
                         should_break = true;
                         if let Some(param) = generics.params.iter().find(|p| match p.kind {
@@ -1279,6 +1369,42 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
                         );
                         (*span, span_type.suggestion("'a"))
                     }
+                    MissingLifetimeSpot::Static => {
+                        let (span, sugg) = match snippet.as_deref() {
+                            Some("&") => (span.shrink_to_hi(), "'static ".to_owned()),
+                            Some("'_") => (span, "'static".to_owned()),
+                            Some(snippet) if !snippet.ends_with('>') => {
+                                if snippet == "" {
+                                    (
+                                        span,
+                                        std::iter::repeat("'static")
+                                            .take(count)
+                                            .collect::<Vec<_>>()
+                                            .join(", "),
+                                    )
+                                } else {
+                                    (
+                                        span.shrink_to_hi(),
+                                        format!(
+                                            "<{}>",
+                                            std::iter::repeat("'static")
+                                                .take(count)
+                                                .collect::<Vec<_>>()
+                                                .join(", ")
+                                        ),
+                                    )
+                                }
+                            }
+                            _ => continue,
+                        };
+                        err.span_suggestion_verbose(
+                            span,
+                            "consider using the `'static` lifetime",
+                            sugg.to_string(),
+                            Applicability::MaybeIncorrect,
+                        );
+                        continue;
+                    }
                 });
                 for param in params {
                     if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) {
@@ -1299,19 +1425,19 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
             }
         };
 
-        match (lifetime_names.len(), lifetime_names.iter().next(), snippet.as_deref()) {
-            (1, Some(name), Some("&")) => {
-                suggest_existing(err, format!("&{} ", name));
+        let lifetime_names: Vec<_> = lifetime_names.into_iter().collect();
+        match (&lifetime_names[..], snippet.as_deref()) {
+            ([name], Some("&")) => {
+                suggest_existing(err, &name.as_str()[..], &|name| format!("&{} ", name));
             }
-            (1, Some(name), Some("'_")) => {
-                suggest_existing(err, name.to_string());
+            ([name], Some("'_")) => {
+                suggest_existing(err, &name.as_str()[..], &|n| n.to_string());
             }
-            (1, Some(name), Some("")) => {
-                suggest_existing(err, format!("{}, ", name).repeat(count));
+            ([name], Some("")) => {
+                suggest_existing(err, &name.as_str()[..], &|n| format!("{}, ", n).repeat(count));
             }
-            (1, Some(name), Some(snippet)) if !snippet.ends_with('>') => {
-                suggest_existing(
-                    err,
+            ([name], Some(snippet)) if !snippet.ends_with('>') => {
+                let f = |name: &str| {
                     format!(
                         "{}<{}>",
                         snippet,
@@ -1319,21 +1445,37 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
                             .take(count)
                             .collect::<Vec<_>>()
                             .join(", ")
-                    ),
-                );
+                    )
+                };
+                suggest_existing(err, &name.as_str()[..], &f);
             }
-            (0, _, Some("&")) if count == 1 => {
+            ([], Some("&")) if count == 1 => {
                 suggest_new(err, "&'a ");
             }
-            (0, _, Some("'_")) if count == 1 => {
+            ([], Some("'_")) if count == 1 => {
                 suggest_new(err, "'a");
             }
-            (0, _, Some(snippet)) if !snippet.ends_with('>') && count == 1 => {
-                suggest_new(err, &format!("{}<'a>", snippet));
+            ([], Some(snippet)) if !snippet.ends_with('>') => {
+                if snippet == "" {
+                    // This happens when we have `type Bar<'a> = Foo<T>` where we point at the space
+                    // before `T`. We will suggest `type Bar<'a> = Foo<'a, T>`.
+                    suggest_new(
+                        err,
+                        &std::iter::repeat("'a, ").take(count).collect::<Vec<_>>().join(""),
+                    );
+                } else {
+                    suggest_new(
+                        err,
+                        &format!(
+                            "{}<{}>",
+                            snippet,
+                            std::iter::repeat("'a").take(count).collect::<Vec<_>>().join(", ")
+                        ),
+                    );
+                }
             }
-            (n, ..) if n > 1 => {
-                let spans: Vec<Span> = lifetime_names.iter().map(|lt| lt.span).collect();
-                err.span_note(spans, "these named lifetimes are available to use");
+            (lts, ..) if lts.len() > 1 => {
+                err.span_note(lifetime_spans, "these named lifetimes are available to use");
                 if Some("") == snippet.as_deref() {
                     // This happens when we have `Foo<T>` where we point at the space before `T`,
                     // but this can be confusing so we give a suggestion with placeholders.
diff --git a/src/librustc_resolve/late/lifetimes.rs b/src/librustc_resolve/late/lifetimes.rs
index 0b881b089de..2046419d984 100644
--- a/src/librustc_resolve/late/lifetimes.rs
+++ b/src/librustc_resolve/late/lifetimes.rs
@@ -711,9 +711,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
 
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
         use self::hir::TraitItemKind::*;
-        self.missing_named_lifetime_spots.push((&trait_item.generics).into());
         match trait_item.kind {
             Fn(ref sig, _) => {
+                self.missing_named_lifetime_spots.push((&trait_item.generics).into());
                 let tcx = self.tcx;
                 self.visit_early_late(
                     Some(tcx.hir().get_parent_item(trait_item.hir_id)),
@@ -721,8 +721,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     &trait_item.generics,
                     |this| intravisit::walk_trait_item(this, trait_item),
                 );
+                self.missing_named_lifetime_spots.pop();
             }
             Type(bounds, ref ty) => {
+                self.missing_named_lifetime_spots.push((&trait_item.generics).into());
                 let generics = &trait_item.generics;
                 let mut index = self.next_early_index();
                 debug!("visit_ty: index = {}", index);
@@ -757,31 +759,35 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         this.visit_ty(ty);
                     }
                 });
+                self.missing_named_lifetime_spots.pop();
             }
             Const(_, _) => {
                 // Only methods and types support generics.
                 assert!(trait_item.generics.params.is_empty());
+                self.missing_named_lifetime_spots.push(MissingLifetimeSpot::Static);
                 intravisit::walk_trait_item(self, trait_item);
+                self.missing_named_lifetime_spots.pop();
             }
         }
-        self.missing_named_lifetime_spots.pop();
     }
 
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
         use self::hir::ImplItemKind::*;
-        self.missing_named_lifetime_spots.push((&impl_item.generics).into());
         match impl_item.kind {
             Fn(ref sig, _) => {
+                self.missing_named_lifetime_spots.push((&impl_item.generics).into());
                 let tcx = self.tcx;
                 self.visit_early_late(
                     Some(tcx.hir().get_parent_item(impl_item.hir_id)),
                     &sig.decl,
                     &impl_item.generics,
                     |this| intravisit::walk_impl_item(this, impl_item),
-                )
+                );
+                self.missing_named_lifetime_spots.pop();
             }
             TyAlias(ref ty) => {
                 let generics = &impl_item.generics;
+                self.missing_named_lifetime_spots.push(generics.into());
                 let mut index = self.next_early_index();
                 let mut non_lifetime_count = 0;
                 debug!("visit_ty: index = {}", index);
@@ -810,14 +816,16 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     this.visit_generics(generics);
                     this.visit_ty(ty);
                 });
+                self.missing_named_lifetime_spots.pop();
             }
             Const(_, _) => {
                 // Only methods and types support generics.
                 assert!(impl_item.generics.params.is_empty());
+                self.missing_named_lifetime_spots.push(MissingLifetimeSpot::Static);
                 intravisit::walk_impl_item(self, impl_item);
+                self.missing_named_lifetime_spots.pop();
             }
         }
-        self.missing_named_lifetime_spots.pop();
     }
 
     fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
@@ -2315,6 +2323,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         let mut late_depth = 0;
         let mut scope = self.scope;
         let mut lifetime_names = FxHashSet::default();
+        let mut lifetime_spans = vec![];
         let error = loop {
             match *scope {
                 // Do not assign any resolution, it will be inferred.
@@ -2326,7 +2335,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     // collect named lifetimes for suggestions
                     for name in lifetimes.keys() {
                         if let hir::ParamName::Plain(name) = name {
-                            lifetime_names.insert(*name);
+                            lifetime_names.insert(name.name);
+                            lifetime_spans.push(name.span);
                         }
                     }
                     late_depth += 1;
@@ -2344,12 +2354,24 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                         }
                         Elide::Exact(l) => l.shifted(late_depth),
                         Elide::Error(ref e) => {
-                            if let Scope::Binder { ref lifetimes, .. } = s {
-                                // collect named lifetimes for suggestions
-                                for name in lifetimes.keys() {
-                                    if let hir::ParamName::Plain(name) = name {
-                                        lifetime_names.insert(*name);
+                            let mut scope = s;
+                            loop {
+                                match scope {
+                                    Scope::Binder { ref lifetimes, s, .. } => {
+                                        // Collect named lifetimes for suggestions.
+                                        for name in lifetimes.keys() {
+                                            if let hir::ParamName::Plain(name) = name {
+                                                lifetime_names.insert(name.name);
+                                                lifetime_spans.push(name.span);
+                                            }
+                                        }
+                                        scope = s;
+                                    }
+                                    Scope::ObjectLifetimeDefault { ref s, .. }
+                                    | Scope::Elision { ref s, .. } => {
+                                        scope = s;
                                     }
+                                    _ => break,
                                 }
                             }
                             break Some(e);
@@ -2373,7 +2395,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         if let Some(params) = error {
             // If there's no lifetime available, suggest `'static`.
             if self.report_elision_failure(&mut err, params) && lifetime_names.is_empty() {
-                lifetime_names.insert(Ident::with_dummy_span(kw::StaticLifetime));
+                lifetime_names.insert(kw::StaticLifetime);
             }
         }
         self.add_missing_lifetime_specifiers_label(
@@ -2381,6 +2403,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             span,
             lifetime_refs.len(),
             &lifetime_names,
+            lifetime_spans,
             error.map(|p| &p[..]).unwrap_or(&[]),
         );
         err.emit();
diff --git a/src/librustc_serialize/collection_impls.rs b/src/librustc_serialize/collection_impls.rs
index c602de37b14..49b8094abd0 100644
--- a/src/librustc_serialize/collection_impls.rs
+++ b/src/librustc_serialize/collection_impls.rs
@@ -86,11 +86,9 @@ where
 {
     fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
         e.emit_map(self.len(), |e| {
-            let mut i = 0;
-            for (key, val) in self {
+            for (i, (key, val)) in self.iter().enumerate() {
                 e.emit_map_elt_key(i, |e| key.encode(e))?;
                 e.emit_map_elt_val(i, |e| val.encode(e))?;
-                i += 1;
             }
             Ok(())
         })
@@ -121,10 +119,8 @@ where
 {
     fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_seq(self.len(), |s| {
-            let mut i = 0;
-            for e in self {
+            for (i, e) in self.iter().enumerate() {
                 s.emit_seq_elt(i, |s| e.encode(s))?;
-                i += 1;
             }
             Ok(())
         })
@@ -154,11 +150,9 @@ where
 {
     fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
         e.emit_map(self.len(), |e| {
-            let mut i = 0;
-            for (key, val) in self {
+            for (i, (key, val)) in self.iter().enumerate() {
                 e.emit_map_elt_key(i, |e| key.encode(e))?;
                 e.emit_map_elt_val(i, |e| val.encode(e))?;
-                i += 1;
             }
             Ok(())
         })
@@ -192,10 +186,8 @@ where
 {
     fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> {
         s.emit_seq(self.len(), |s| {
-            let mut i = 0;
-            for e in self {
+            for (i, e) in self.iter().enumerate() {
                 s.emit_seq_elt(i, |s| e.encode(s))?;
-                i += 1;
             }
             Ok(())
         })
@@ -227,11 +219,9 @@ where
 {
     fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
         e.emit_map(self.len(), |e| {
-            let mut i = 0;
-            for (key, val) in self {
+            for (i, (key, val)) in self.iter().enumerate() {
                 e.emit_map_elt_key(i, |e| key.encode(e))?;
                 e.emit_map_elt_val(i, |e| val.encode(e))?;
-                i += 1;
             }
             Ok(())
         })
@@ -265,10 +255,8 @@ where
 {
     fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> {
         s.emit_seq(self.len(), |s| {
-            let mut i = 0;
-            for e in self {
+            for (i, e) in self.iter().enumerate() {
                 s.emit_seq_elt(i, |s| e.encode(s))?;
-                i += 1;
             }
             Ok(())
         })
diff --git a/src/librustc_serialize/json.rs b/src/librustc_serialize/json.rs
index 820ebdc9baa..ab7f6975325 100644
--- a/src/librustc_serialize/json.rs
+++ b/src/librustc_serialize/json.rs
@@ -78,19 +78,17 @@
 //!     data_vector: Vec<u8>,
 //! }
 //!
-//! fn main() {
-//!     let object = TestStruct {
-//!         data_int: 1,
-//!         data_str: "homura".to_string(),
-//!         data_vector: vec![2,3,4,5],
-//!     };
+//! let object = TestStruct {
+//!     data_int: 1,
+//!     data_str: "homura".to_string(),
+//!     data_vector: vec![2,3,4,5],
+//! };
 //!
-//!     // Serialize using `json::encode`
-//!     let encoded = json::encode(&object).unwrap();
+//! // Serialize using `json::encode`
+//! let encoded = json::encode(&object).unwrap();
 //!
-//!     // Deserialize using `json::decode`
-//!     let decoded: TestStruct = json::decode(&encoded[..]).unwrap();
-//! }
+//! // Deserialize using `json::decode`
+//! let decoded: TestStruct = json::decode(&encoded[..]).unwrap();
 //! ```
 //!
 //! ## Using the `ToJson` trait
@@ -125,16 +123,14 @@
 //!     val: Json,
 //! }
 //!
-//! fn main() {
-//!     let num = ComplexNum { a: 0.0001, b: 12.539 };
-//!     let data: String = json::encode(&ComplexNumRecord{
-//!         uid: 1,
-//!         dsc: "test".to_string(),
-//!         val: num.to_json(),
-//!     }).unwrap();
-//!     println!("data: {}", data);
-//!     // data: {"uid":1,"dsc":"test","val":"0.0001+12.539i"};
-//! }
+//! let num = ComplexNum { a: 0.0001, b: 12.539 };
+//! let data: String = json::encode(&ComplexNumRecord{
+//!     uid: 1,
+//!     dsc: "test".to_string(),
+//!     val: num.to_json(),
+//! }).unwrap();
+//! println!("data: {}", data);
+//! // data: {"uid":1,"dsc":"test","val":"0.0001+12.539i"};
 //! ```
 //!
 //! ### Verbose example of `ToJson` usage
@@ -164,19 +160,17 @@
 //!     }
 //! }
 //!
-//! fn main() {
-//!     // Serialize using `ToJson`
-//!     let input_data = TestStruct {
-//!         data_int: 1,
-//!         data_str: "madoka".to_string(),
-//!         data_vector: vec![2,3,4,5],
-//!     };
-//!     let json_obj: Json = input_data.to_json();
-//!     let json_str: String = json_obj.to_string();
+//! // Serialize using `ToJson`
+//! let input_data = TestStruct {
+//!     data_int: 1,
+//!     data_str: "madoka".to_string(),
+//!     data_vector: vec![2,3,4,5],
+//! };
+//! let json_obj: Json = input_data.to_json();
+//! let json_str: String = json_obj.to_string();
 //!
-//!     // Deserialize like before
-//!     let decoded: TestStruct = json::decode(&json_str).unwrap();
-//! }
+//! // Deserialize like before
+//! let decoded: TestStruct = json::decode(&json_str).unwrap();
 //! ```
 
 use self::DecoderError::*;
@@ -1269,34 +1263,22 @@ impl Json {
 
     /// Returns `true` if the Json value is a `Number`.
     pub fn is_number(&self) -> bool {
-        match *self {
-            Json::I64(_) | Json::U64(_) | Json::F64(_) => true,
-            _ => false,
-        }
+        matches!(*self, Json::I64(_) | Json::U64(_) | Json::F64(_))
     }
 
     /// Returns `true` if the Json value is a `i64`.
     pub fn is_i64(&self) -> bool {
-        match *self {
-            Json::I64(_) => true,
-            _ => false,
-        }
+        matches!(*self, Json::I64(_))
     }
 
     /// Returns `true` if the Json value is a `u64`.
     pub fn is_u64(&self) -> bool {
-        match *self {
-            Json::U64(_) => true,
-            _ => false,
-        }
+        matches!(*self, Json::U64(_))
     }
 
     /// Returns `true` if the Json value is a `f64`.
     pub fn is_f64(&self) -> bool {
-        match *self {
-            Json::F64(_) => true,
-            _ => false,
-        }
+        matches!(*self, Json::F64(_))
     }
 
     /// If the Json value is a number, returns or cast it to a `i64`;
@@ -1416,6 +1398,7 @@ enum ParserState {
 /// structure of the JSON stream.
 ///
 /// An example is `foo.bar[3].x`.
+#[derive(Default)]
 pub struct Stack {
     stack: Vec<InternalStackElement>,
     str_buffer: Vec<u8>,
@@ -1442,7 +1425,7 @@ enum InternalStackElement {
 
 impl Stack {
     pub fn new() -> Stack {
-        Stack { stack: Vec::new(), str_buffer: Vec::new() }
+        Self::default()
     }
 
     /// Returns The number of elements in the Stack.
@@ -1547,10 +1530,7 @@ impl Stack {
 
     // Used by Parser to test whether the top-most element is an index.
     fn last_is_index(&self) -> bool {
-        match self.stack.last() {
-            Some(InternalIndex(_)) => true,
-            _ => false,
-        }
+        matches!(self.stack.last(), Some(InternalIndex(_)))
     }
 
     // Used by Parser to increment the index of the top-most element.
diff --git a/src/librustc_serialize/opaque.rs b/src/librustc_serialize/opaque.rs
index 39f3abb7527..fa4423e261d 100644
--- a/src/librustc_serialize/opaque.rs
+++ b/src/librustc_serialize/opaque.rs
@@ -118,13 +118,13 @@ impl serialize::Encoder for Encoder {
 
     #[inline]
     fn emit_f64(&mut self, v: f64) -> EncodeResult {
-        let as_u64: u64 = unsafe { ::std::mem::transmute(v) };
+        let as_u64: u64 = v.to_bits();
         self.emit_u64(as_u64)
     }
 
     #[inline]
     fn emit_f32(&mut self, v: f32) -> EncodeResult {
-        let as_u32: u32 = unsafe { ::std::mem::transmute(v) };
+        let as_u32: u32 = v.to_bits();
         self.emit_u32(as_u32)
     }
 
diff --git a/src/librustc_session/parse.rs b/src/librustc_session/parse.rs
index 9cdb7e966fe..a2bb8c4f91f 100644
--- a/src/librustc_session/parse.rs
+++ b/src/librustc_session/parse.rs
@@ -13,7 +13,6 @@ use rustc_span::hygiene::ExpnId;
 use rustc_span::source_map::{FilePathMapping, SourceMap};
 use rustc_span::{MultiSpan, Span, Symbol};
 
-use std::collections::BTreeMap;
 use std::path::PathBuf;
 use std::str;
 
@@ -64,7 +63,7 @@ impl GatedSpans {
 #[derive(Default)]
 pub struct SymbolGallery {
     /// All symbols occurred and their first occurrence span.
-    pub symbols: Lock<BTreeMap<Symbol, Span>>,
+    pub symbols: Lock<FxHashMap<Symbol, Span>>,
 }
 
 impl SymbolGallery {
diff --git a/src/librustc_trait_selection/traits/auto_trait.rs b/src/librustc_trait_selection/traits/auto_trait.rs
index 05a0c52badb..820f8716f05 100644
--- a/src/librustc_trait_selection/traits/auto_trait.rs
+++ b/src/librustc_trait_selection/traits/auto_trait.rs
@@ -270,6 +270,13 @@ impl AutoTraitFinder<'tcx> {
     ) -> Option<(ty::ParamEnv<'tcx>, ty::ParamEnv<'tcx>)> {
         let tcx = infcx.tcx;
 
+        // Don't try to proess any nested obligations involving predicates
+        // that are already in the `ParamEnv` (modulo regions): we already
+        // know that they must hold.
+        for predicate in param_env.caller_bounds() {
+            fresh_preds.insert(self.clean_pred(infcx, predicate));
+        }
+
         let mut select = SelectionContext::with_negative(&infcx, true);
 
         let mut already_visited = FxHashSet::default();
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index a877df68326..418ea29b84f 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -147,7 +147,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 }
 
 #[derive(Copy, Clone)]
-enum CastError {
+pub enum CastError {
     ErrorReported,
 
     CastToBool,
@@ -593,7 +593,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
     /// Checks a cast, and report an error if one exists. In some cases, this
     /// can return Ok and create type errors in the fcx rather than returning
     /// directly. coercion-cast is handled in check instead of here.
-    fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
+    pub fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
         use rustc_middle::ty::cast::CastTy::*;
         use rustc_middle::ty::cast::IntTy::*;
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 3d58fb30d91..a40b6860f77 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -67,7 +67,7 @@ type parameter).
 pub mod _match;
 mod autoderef;
 mod callee;
-mod cast;
+pub mod cast;
 mod closure;
 pub mod coercion;
 mod compare_method;
@@ -648,7 +648,7 @@ impl Inherited<'_, 'tcx> {
 }
 
 impl<'tcx> InheritedBuilder<'tcx> {
-    fn enter<F, R>(&mut self, f: F) -> R
+    pub fn enter<F, R>(&mut self, f: F) -> R
     where
         F: for<'a> FnOnce(Inherited<'a, 'tcx>) -> R,
     {
@@ -1967,10 +1967,16 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
             check_union(tcx, it.hir_id, it.span);
         }
         hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
-            let def_id = tcx.hir().local_def_id(it.hir_id);
-
-            let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
-            check_opaque(tcx, def_id, substs, it.span, &origin);
+            // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting
+            // `async-std` (and `pub async fn` in general).
+            // Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it!
+            // See https://github.com/rust-lang/rust/issues/75100
+            if !tcx.sess.opts.actually_rustdoc {
+                let def_id = tcx.hir().local_def_id(it.hir_id);
+
+                let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+                check_opaque(tcx, def_id, substs, it.span, &origin);
+            }
         }
         hir::ItemKind::TyAlias(..) => {
             let def_id = tcx.hir().local_def_id(it.hir_id);
diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs
index f598ada900f..1c78bef9852 100644
--- a/src/librustc_typeck/check/pat.rs
+++ b/src/librustc_typeck/check/pat.rs
@@ -1229,8 +1229,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         Applicability::MaybeIncorrect,
                     );
 
-                    // we don't want to throw `E0027` in case we have thrown `E0026` for them
-                    unmentioned_fields.retain(|&x| x.name != suggested_name);
+                    // When we have a tuple struct used with struct we don't want to suggest using
+                    // the (valid) struct syntax with numeric field names. Instead we want to
+                    // suggest the expected syntax. We infer that this is the case by parsing the
+                    // `Ident` into an unsized integer. The suggestion will be emitted elsewhere in
+                    // `smart_resolve_context_dependent_help`.
+                    if suggested_name.to_ident_string().parse::<usize>().is_err() {
+                        // We don't want to throw `E0027` in case we have thrown `E0026` for them.
+                        unmentioned_fields.retain(|&x| x.name != suggested_name);
+                    }
                 }
             }
         }
diff --git a/src/librustc_typeck/check/place_op.rs b/src/librustc_typeck/check/place_op.rs
index 84f34c0039a..4bef9aecd2e 100644
--- a/src/librustc_typeck/check/place_op.rs
+++ b/src/librustc_typeck/check/place_op.rs
@@ -9,6 +9,7 @@ use rustc_middle::ty::{self, Ty};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use rustc_trait_selection::autoderef::Autoderef;
+use std::slice;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Type-check `*oprnd_expr` with `oprnd_expr` type-checked already.
@@ -243,19 +244,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
 
             match expr.kind {
-                hir::ExprKind::Index(ref base_expr, ref index_expr) => {
-                    // We need to get the final type in case dereferences were needed for the trait
-                    // to apply (#72002).
-                    let index_expr_ty = self.typeck_results.borrow().expr_ty_adjusted(index_expr);
-                    self.convert_place_op_to_mutable(
-                        PlaceOp::Index,
-                        expr,
-                        base_expr,
-                        &[index_expr_ty],
-                    );
+                hir::ExprKind::Index(ref base_expr, ..) => {
+                    self.convert_place_op_to_mutable(PlaceOp::Index, expr, base_expr);
                 }
                 hir::ExprKind::Unary(hir::UnOp::UnDeref, ref base_expr) => {
-                    self.convert_place_op_to_mutable(PlaceOp::Deref, expr, base_expr, &[]);
+                    self.convert_place_op_to_mutable(PlaceOp::Deref, expr, base_expr);
                 }
                 _ => {}
             }
@@ -267,9 +260,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         op: PlaceOp,
         expr: &hir::Expr<'_>,
         base_expr: &hir::Expr<'_>,
-        arg_tys: &[Ty<'tcx>],
     ) {
-        debug!("convert_place_op_to_mutable({:?}, {:?}, {:?}, {:?})", op, expr, base_expr, arg_tys);
+        debug!("convert_place_op_to_mutable({:?}, {:?}, {:?})", op, expr, base_expr);
         if !self.typeck_results.borrow().is_method_call(expr) {
             debug!("convert_place_op_to_mutable - builtin, nothing to do");
             return;
@@ -284,6 +276,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .expect("place op takes something that is not a ref")
             .ty;
 
+        let arg_ty = match op {
+            PlaceOp::Deref => None,
+            PlaceOp::Index => {
+                // We would need to recover the `T` used when we resolve `<_ as Index<T>>::index`
+                // in try_index_step. This is the subst at index 1.
+                //
+                // Note: we should *not* use `expr_ty` of index_expr here because autoderef
+                // during coercions can cause type of index_expr to differ from `T` (#72002).
+                // We also could not use `expr_ty_adjusted` of index_expr because reborrowing
+                // during coercions can also cause type of index_expr to differ from `T`,
+                // which can potentially cause regionck failure (#74933).
+                Some(self.typeck_results.borrow().node_substs(expr.hir_id).type_at(1))
+            }
+        };
+        let arg_tys = match arg_ty {
+            None => &[],
+            Some(ref ty) => slice::from_ref(ty),
+        };
+
         let method = self.try_mutable_overloaded_place_op(expr.span, base_ty, arg_tys, op);
         let method = match method {
             Some(ok) => self.register_infer_ok_obligations(ok),
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index a8247e2f494..49843fa43dd 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -74,11 +74,11 @@ extern crate log;
 #[macro_use]
 extern crate rustc_middle;
 
-// This is used by Clippy.
+// These are used by Clippy.
+pub mod check;
 pub mod expr_use_visitor;
 
 mod astconv;
-mod check;
 mod check_unused;
 mod coherence;
 mod collect;
@@ -390,6 +390,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> {
         tcx.sess.time("wf_checking", || check::check_wf_new(tcx));
     })?;
 
+    // NOTE: This is copy/pasted in librustdoc/core.rs and should be kept in sync.
     tcx.sess.time("item_types_checking", || {
         for &module in tcx.hir().krate().modules.keys() {
             tcx.ensure().check_mod_item_types(tcx.hir().local_def_id(module));
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 3afd3671d6b..801d06e6101 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2358,7 +2358,7 @@ impl Clean<Stability> for attr::Stability {
     fn clean(&self, _: &DocContext<'_>) -> Stability {
         Stability {
             level: stability::StabilityLevel::from_attr_level(&self.level),
-            feature: Some(self.feature.to_string()).filter(|f| !f.is_empty()),
+            feature: self.feature.to_string(),
             since: match self.level {
                 attr::Stable { ref since } => since.to_string(),
                 _ => String::new(),
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 50eca75d7ca..627f88df45c 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1525,7 +1525,7 @@ pub struct ProcMacro {
 #[derive(Clone, Debug)]
 pub struct Stability {
     pub level: stability::StabilityLevel,
-    pub feature: Option<String>,
+    pub feature: String,
     pub since: String,
     pub unstable_reason: Option<String>,
     pub issue: Option<NonZeroU32>,
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index cbd0ca0de64..b13acaae1bf 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -452,10 +452,20 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
                 // Certain queries assume that some checks were run elsewhere
                 // (see https://github.com/rust-lang/rust/pull/73566#issuecomment-656954425),
                 // so type-check everything other than function bodies in this crate before running lints.
+
                 // NOTE: this does not call `tcx.analysis()` so that we won't
                 // typeck function bodies or run the default rustc lints.
                 // (see `override_queries` in the `config`)
-                let _ = rustc_typeck::check_crate(tcx);
+
+                // HACK(jynelson) this calls an _extremely_ limited subset of `typeck`
+                // and might break if queries change their assumptions in the future.
+
+                // NOTE: This is copy/pasted from typeck/lib.rs and should be kept in sync with those changes.
+                tcx.sess.time("item_types_checking", || {
+                    for &module in tcx.hir().krate().modules.keys() {
+                        tcx.ensure().check_mod_item_types(tcx.hir().local_def_id(module));
+                    }
+                });
                 tcx.sess.abort_if_errors();
                 sess.time("missing_docs", || {
                     rustc_lint::check_crate(tcx, rustc_lint::builtin::MissingDoc::new);
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index cc6b38ebcdb..fd67a66395d 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -95,6 +95,7 @@ pub fn render<T: Print, S: Print>(
                            placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
                            type=\"search\">\
                 </div>\
+                <span class=\"help-button\">?</span>
                 <a id=\"settings-menu\" href=\"{root_path}settings.html\">\
                     <img src=\"{static_root_path}wheel{suffix}.svg\" \
                          width=\"18\" \
@@ -138,7 +139,7 @@ pub fn render<T: Print, S: Print>(
             if layout.logo.is_empty() {
                 format!(
                     "<a href='{path}index.html'>\
-                     <div class='logo-container'>\
+                     <div class='logo-container rust-logo'>\
                      <img src='{static_root_path}rust-logo{suffix}.png' alt='logo'></div></a>",
                     path = p,
                     static_root_path = static_root_path,
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 4cbc56333b1..bd919205dd1 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1903,23 +1903,41 @@ fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) {
     }
 }
 
-fn name_key(name: &str) -> (&str, u64, usize) {
-    let end = name.bytes().rposition(|b| b.is_ascii_digit()).map_or(name.len(), |i| i + 1);
-
-    // find number at end
-    let split = name[0..end].bytes().rposition(|b| !b.is_ascii_digit()).map_or(0, |i| i + 1);
-
-    // count leading zeroes
-    let after_zeroes =
-        name[split..end].bytes().position(|b| b != b'0').map_or(name.len(), |extra| split + extra);
-
-    // sort leading zeroes last
-    let num_zeroes = after_zeroes - split;
-
-    match name[split..end].parse() {
-        Ok(n) => (&name[..split], n, num_zeroes),
-        Err(_) => (name, 0, num_zeroes),
+/// Compare two strings treating multi-digit numbers as single units (i.e. natural sort order).
+pub fn compare_names(mut lhs: &str, mut rhs: &str) -> Ordering {
+    /// Takes a non-numeric and a numeric part from the given &str.
+    fn take_parts<'a>(s: &mut &'a str) -> (&'a str, &'a str) {
+        let i = s.find(|c: char| c.is_ascii_digit());
+        let (a, b) = s.split_at(i.unwrap_or(s.len()));
+        let i = b.find(|c: char| !c.is_ascii_digit());
+        let (b, c) = b.split_at(i.unwrap_or(b.len()));
+        *s = c;
+        (a, b)
+    }
+
+    while !lhs.is_empty() || !rhs.is_empty() {
+        let (la, lb) = take_parts(&mut lhs);
+        let (ra, rb) = take_parts(&mut rhs);
+        // First process the non-numeric part.
+        match la.cmp(ra) {
+            Ordering::Equal => (),
+            x => return x,
+        }
+        // Then process the numeric part, if both sides have one (and they fit in a u64).
+        if let (Ok(ln), Ok(rn)) = (lb.parse::<u64>(), rb.parse::<u64>()) {
+            match ln.cmp(&rn) {
+                Ordering::Equal => (),
+                x => return x,
+            }
+        }
+        // Then process the numeric part again, but this time as strings.
+        match lb.cmp(rb) {
+            Ordering::Equal => (),
+            x => return x,
+        }
     }
+
+    Ordering::Equal
 }
 
 fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean::Item]) {
@@ -1962,7 +1980,7 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean:
         }
         let lhs = i1.name.as_ref().map_or("", |s| &**s);
         let rhs = i2.name.as_ref().map_or("", |s| &**s);
-        name_key(lhs).cmp(&name_key(rhs))
+        compare_names(lhs, rhs)
     }
 
     if cx.shared.sort_modules_alphabetically {
@@ -2126,7 +2144,7 @@ fn stability_tags(item: &clean::Item) -> String {
     if item
         .stability
         .as_ref()
-        .map(|s| s.level == stability::Unstable && s.feature.as_deref() != Some("rustc_private"))
+        .map(|s| s.level == stability::Unstable && s.feature != "rustc_private")
         == Some(true)
     {
         tags += &tag_html("unstable", "Experimental");
@@ -2177,25 +2195,25 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
 
     // Render unstable items. But don't render "rustc_private" crates (internal compiler crates).
     // Those crates are permanently unstable so it makes no sense to render "unstable" everywhere.
-    if let Some(stab) = item.stability.as_ref().filter(|stab| {
-        stab.level == stability::Unstable && stab.feature.as_deref() != Some("rustc_private")
-    }) {
+    if let Some(stab) = item
+        .stability
+        .as_ref()
+        .filter(|stab| stab.level == stability::Unstable && stab.feature != "rustc_private")
+    {
         let mut message =
             "<span class='emoji'>🔬</span> This is a nightly-only experimental API.".to_owned();
 
-        if let Some(feature) = stab.feature.as_deref() {
-            let mut feature = format!("<code>{}</code>", Escape(&feature));
-            if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, stab.issue) {
-                feature.push_str(&format!(
-                    "&nbsp;<a href=\"{url}{issue}\">#{issue}</a>",
-                    url = url,
-                    issue = issue
-                ));
-            }
-
-            message.push_str(&format!(" ({})", feature));
+        let mut feature = format!("<code>{}</code>", Escape(&stab.feature));
+        if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, stab.issue) {
+            feature.push_str(&format!(
+                "&nbsp;<a href=\"{url}{issue}\">#{issue}</a>",
+                url = url,
+                issue = issue
+            ));
         }
 
+        message.push_str(&format!(" ({})", feature));
+
         if let Some(unstable_reason) = &stab.unstable_reason {
             let mut ids = cx.id_map.borrow_mut();
             message = format!(
@@ -2395,7 +2413,7 @@ fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl) -> Ordering {
     let rhs = format!("{}", rhs.inner_impl().print());
 
     // lhs and rhs are formatted as HTML, which may be unnecessary
-    name_key(&lhs).cmp(&name_key(&rhs))
+    compare_names(&lhs, &rhs)
 }
 
 fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, cache: &Cache) {
diff --git a/src/librustdoc/html/render/tests.rs b/src/librustdoc/html/render/tests.rs
index 99ad26549f5..abf5f05fe58 100644
--- a/src/librustdoc/html/render/tests.rs
+++ b/src/librustdoc/html/render/tests.rs
@@ -1,24 +1,40 @@
 use super::*;
 
 #[test]
-fn test_name_key() {
-    assert_eq!(name_key("0"), ("", 0, 1));
-    assert_eq!(name_key("123"), ("", 123, 0));
-    assert_eq!(name_key("Fruit"), ("Fruit", 0, 0));
-    assert_eq!(name_key("Fruit0"), ("Fruit", 0, 1));
-    assert_eq!(name_key("Fruit0000"), ("Fruit", 0, 4));
-    assert_eq!(name_key("Fruit01"), ("Fruit", 1, 1));
-    assert_eq!(name_key("Fruit10"), ("Fruit", 10, 0));
-    assert_eq!(name_key("Fruit123"), ("Fruit", 123, 0));
+fn test_compare_names() {
+    for &(a, b) in &[
+        ("hello", "world"),
+        ("", "world"),
+        ("123", "hello"),
+        ("123", ""),
+        ("123test", "123"),
+        ("hello", ""),
+        ("hello", "hello"),
+        ("hello123", "hello123"),
+        ("hello123", "hello12"),
+        ("hello12", "hello123"),
+        ("hello01abc", "hello01xyz"),
+        ("hello0abc", "hello0"),
+        ("hello0", "hello0abc"),
+        ("01", "1"),
+    ] {
+        assert_eq!(compare_names(a, b), a.cmp(b), "{:?} - {:?}", a, b);
+    }
+    assert_eq!(compare_names("u8", "u16"), Ordering::Less);
+    assert_eq!(compare_names("u32", "u16"), Ordering::Greater);
+    assert_eq!(compare_names("u8_to_f64", "u16_to_f64"), Ordering::Less);
+    assert_eq!(compare_names("u32_to_f64", "u16_to_f64"), Ordering::Greater);
+    assert_eq!(compare_names("u16_to_f64", "u16_to_f64"), Ordering::Equal);
+    assert_eq!(compare_names("u16_to_f32", "u16_to_f64"), Ordering::Less);
 }
 
 #[test]
 fn test_name_sorting() {
     let names = [
-        "Apple", "Banana", "Fruit", "Fruit0", "Fruit00", "Fruit1", "Fruit01", "Fruit2", "Fruit02",
+        "Apple", "Banana", "Fruit", "Fruit0", "Fruit00", "Fruit01", "Fruit1", "Fruit02", "Fruit2",
         "Fruit20", "Fruit30x", "Fruit100", "Pear",
     ];
     let mut sorted = names.to_owned();
-    sorted.sort_by_key(|&s| name_key(s));
+    sorted.sort_by(|&l, r| compare_names(l, r));
     assert_eq!(names, sorted);
 }
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index 19284018a30..462a696dee6 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -408,9 +408,7 @@ function defocusSearchBar() {
                 break;
 
             case "?":
-                if (ev.shiftKey) {
-                    displayHelp(true, ev);
-                }
+                displayHelp(true, ev);
                 break;
             }
         }
@@ -473,7 +471,9 @@ function defocusSearchBar() {
     }());
 
     document.addEventListener("click", function(ev) {
-        if (hasClass(ev.target, "collapse-toggle")) {
+        if (hasClass(ev.target, "help-button")) {
+            displayHelp(true, ev);
+        } else if (hasClass(ev.target, "collapse-toggle")) {
             collapseDocs(ev.target, "toggle");
         } else if (hasClass(ev.target.parentNode, "collapse-toggle")) {
             collapseDocs(ev.target.parentNode, "toggle");
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index db0e4f4d31d..346ceacc928 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -674,7 +674,7 @@ a {
 }
 .search-container > div {
 	display: inline-flex;
-	width: calc(100% - 34px);
+	width: calc(100% - 63px);
 }
 #crate-search {
 	margin-top: 5px;
@@ -1250,14 +1250,24 @@ h4 > .notable-traits {
 	outline: none;
 }
 
-#settings-menu {
+#settings-menu, .help-button {
 	position: absolute;
-	right: 0;
 	top: 10px;
+}
+
+#settings-menu {
+	right: 0;
 	outline: none;
 }
 
-#theme-picker, #settings-menu {
+.help-button {
+	right: 30px;
+	font-family: "Fira Sans",sans-serif;
+	text-align: center;
+	font-size: 17px;
+}
+
+#theme-picker, #settings-menu, .help-button {
 	padding: 4px;
 	width: 27px;
 	height: 29px;
diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css
index 60f0d25b219..6e8db1e9eb7 100644
--- a/src/librustdoc/html/static/themes/ayu.css
+++ b/src/librustdoc/html/static/themes/ayu.css
@@ -62,8 +62,11 @@ pre {
 	background-color: #14191f;
 }
 
-.logo-container > img {
-	filter: drop-shadow(0 0 5px #fff);
+.logo-container.rust-logo > img {
+	filter: drop-shadow(1px 0 0px #fff)
+		drop-shadow(0 1px 0 #fff)
+		drop-shadow(-1px 0 0 #fff)
+		drop-shadow(0 -1px 0 #fff);
 }
 
 /* Improve the scrollbar display on firefox */
@@ -489,7 +492,7 @@ kbd {
 	box-shadow-color: #c6cbd1;
 }
 
-#theme-picker, #settings-menu {
+#theme-picker, #settings-menu, .help-button {
 	border-color: #5c6773;
 	background-color: #0f1419;
 }
@@ -499,7 +502,8 @@ kbd {
 }
 
 #theme-picker:hover, #theme-picker:focus,
-#settings-menu:hover, #settings-menu:focus {
+#settings-menu:hover, #settings-menu:focus,
+.help-button:hover, .help-button:focus {
 	border-color: #e0e0e0;
 }
 
diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css
index 34c6cbbf4fa..eeb1f0a3d4a 100644
--- a/src/librustdoc/html/static/themes/dark.css
+++ b/src/librustdoc/html/static/themes/dark.css
@@ -34,8 +34,11 @@ pre {
 	background-color: #505050;
 }
 
-.logo-container > img {
-	filter: drop-shadow(0 0 5px #fff);
+.logo-container.rust-logo > img {
+	filter: drop-shadow(1px 0 0px #fff)
+		drop-shadow(0 1px 0 #fff)
+		drop-shadow(-1px 0 0 #fff)
+		drop-shadow(0 -1px 0 #fff)
 }
 
 /* Improve the scrollbar display on firefox */
@@ -383,13 +386,14 @@ kbd {
 	box-shadow-color: #c6cbd1;
 }
 
-#theme-picker, #settings-menu {
+#theme-picker, #settings-menu, .help-button {
 	border-color: #e0e0e0;
 	background: #f0f0f0;
 }
 
 #theme-picker:hover, #theme-picker:focus,
-#settings-menu:hover, #settings-menu:focus {
+#settings-menu:hover, #settings-menu:focus,
+.help-button:hover, .help-button:focus {
 	border-color: #ffb900;
 }
 
diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css
index 137aad4ed43..9dea875b877 100644
--- a/src/librustdoc/html/static/themes/light.css
+++ b/src/librustdoc/html/static/themes/light.css
@@ -45,8 +45,8 @@ pre {
 	scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9;
 }
 
-.logo-container > img {
-	filter: drop-shadow(0 0 5px #aaa);
+.logo-container.rust-logo > img {
+	/* No need for a border in here! */
 }
 
 /* Improve the scrollbar display on webkit-based browsers */
@@ -377,13 +377,14 @@ kbd {
 	box-shadow-color: #c6cbd1;
 }
 
-#theme-picker, #settings-menu {
+#theme-picker, #settings-menu, .help-button {
 	border-color: #e0e0e0;
 	background-color: #fff;
 }
 
 #theme-picker:hover, #theme-picker:focus,
-#settings-menu:hover, #settings-menu:focus {
+#settings-menu:hover, #settings-menu:focus,
+.help-button:hover, .help-button:focus {
 	border-color: #717171;
 }
 
diff --git a/src/test/codegen-units/polymorphization/pr-75255.rs b/src/test/codegen-units/polymorphization/pr-75255.rs
deleted file mode 100644
index af47b440640..00000000000
--- a/src/test/codegen-units/polymorphization/pr-75255.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-// compile-flags:-Zpolymorphize=on -Zprint-mono-items=lazy -Copt-level=1
-// ignore-tidy-linelength
-
-#![crate_type = "rlib"]
-
-// Test that only one copy of `Iter::map` and `iter::repeat` are generated.
-
-fn unused<T>() -> u64 {
-    42
-}
-
-fn foo<T>() {
-    let x = [1, 2, 3, std::mem::size_of::<T>()];
-    x.iter().map(|_| ());
-}
-
-//~ MONO_ITEM fn core::iter[0]::adapters[0]::{{impl}}[29]::new[0]<core::slice[0]::Iter[0]<usize>, pr_75255::foo[0]::{{closure}}[0]<T>> @@ pr_75255-cgu.0[External]
-//~ MONO_ITEM fn core::iter[0]::traits[0]::iterator[0]::Iterator[0]::map[0]<core::slice[0]::Iter[0]<usize>, (), pr_75255::foo[0]::{{closure}}[0]<T>> @@ pr_75255-cgu.1[Internal]
-
-fn bar<T>() {
-    std::iter::repeat(unused::<T>);
-}
-
-//~ MONO_ITEM fn core::iter[0]::sources[0]::repeat[0]<fn() -> u64> @@ pr_75255-cgu.1[Internal]
-
-pub fn dispatch() {
-    foo::<String>();
-    foo::<Vec<String>>();
-
-    bar::<String>();
-    bar::<Vec<String>>();
-}
-
-// These are all the items that aren't relevant to the test.
-//~ MONO_ITEM fn core::mem[0]::size_of[0]<alloc::string[0]::String[0]> @@ pr_75255-cgu.1[Internal]
-//~ MONO_ITEM fn core::mem[0]::size_of[0]<alloc::vec[0]::Vec[0]<alloc::string[0]::String[0]>> @@ pr_75255-cgu.1[Internal]
-//~ MONO_ITEM fn core::mem[0]::size_of[0]<usize> @@ pr_75255-cgu.1[Internal]
-//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::add[0]<usize> @@ pr_75255-cgu.1[Internal]
-//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::is_null[0]<usize> @@ pr_75255-cgu.1[Internal]
-//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::offset[0]<usize> @@ pr_75255-cgu.1[Internal]
-//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::wrapping_add[0]<u8> @@ pr_75255-cgu.1[Internal]
-//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::wrapping_offset[0]<u8> @@ pr_75255-cgu.1[Internal]
-//~ MONO_ITEM fn core::ptr[0]::non_null[0]::{{impl}}[3]::new_unchecked[0]<usize> @@ pr_75255-cgu.1[Internal]
-//~ MONO_ITEM fn core::ptr[0]::null[0]<u8> @@ pr_75255-cgu.1[Internal]
-//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::as_ptr[0]<usize> @@ pr_75255-cgu.1[Internal]
-//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::iter[0]<usize> @@ pr_75255-cgu.1[Internal]
-//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::len[0]<usize> @@ pr_75255-cgu.1[Internal]
-//~ MONO_ITEM fn pr_75255::dispatch[0] @@ pr_75255-cgu.1[External]
-//~ MONO_ITEM fn pr_75255::foo[0]<alloc::string[0]::String[0]> @@ pr_75255-cgu.1[Internal]
-//~ MONO_ITEM fn pr_75255::foo[0]<alloc::vec[0]::Vec[0]<alloc::string[0]::String[0]>> @@ pr_75255-cgu.1[Internal]
-//~ MONO_ITEM fn pr_75255::bar[0]<alloc::string[0]::String[0]> @@ pr_75255-cgu.1[Internal]
-//~ MONO_ITEM fn pr_75255::bar[0]<alloc::vec[0]::Vec[0]<alloc::string[0]::String[0]>> @@ pr_75255-cgu.1[Internal]
diff --git a/src/test/codegen/consts.rs b/src/test/codegen/consts.rs
index ed93af2f993..318f9b0eec3 100644
--- a/src/test/codegen/consts.rs
+++ b/src/test/codegen/consts.rs
@@ -10,11 +10,11 @@
 // CHECK: @STATIC = {{.*}}, align 4
 
 // This checks the constants from inline_enum_const
-// CHECK: @alloc7 = {{.*}}, align 2
+// CHECK: @alloc8 = {{.*}}, align 2
 
 // This checks the constants from {low,high}_align_const, they share the same
 // constant, but the alignment differs, so the higher one should be used
-// CHECK: [[LOW_HIGH:@[0-9]+]] = {{.*}} getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* @alloc19, i32 0, i32 0, i32 0), {{.*}}
+// CHECK: [[LOW_HIGH:@[0-9]+]] = {{.*}} getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* @alloc20, i32 0, i32 0, i32 0), {{.*}}
 
 #[derive(Copy, Clone)]
 // repr(i16) is required for the {low,high}_align_const test
diff --git a/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.32bit b/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.32bit
index d386d247829..71d55dbb96e 100644
--- a/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.32bit
+++ b/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.32bit
@@ -30,41 +30,41 @@ fn main() -> () {
 }
 
 alloc0 (static: FOO, size: 8, align: 4) {
-    ╾─alloc21─╼ 03 00 00 00                         │ ╾──╼....
+    ╾─alloc23─╼ 03 00 00 00                         │ ╾──╼....
 }
 
-alloc21 (size: 48, align: 4) {
-    0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc4──╼ 00 00 00 00 │ ....░░░░╾──╼....
-    0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc9──╼ 02 00 00 00 │ ....░░░░╾──╼....
-    0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc19─╼ 03 00 00 00 │ ....*...╾──╼....
+alloc23 (size: 48, align: 4) {
+    0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc8──╼ 00 00 00 00 │ ....░░░░╾──╼....
+    0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc13─╼ 02 00 00 00 │ ....░░░░╾──╼....
+    0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc21─╼ 03 00 00 00 │ ....*...╾──╼....
 }
 
-alloc4 (size: 0, align: 4) {}
+alloc8 (size: 0, align: 4) {}
 
-alloc9 (size: 8, align: 4) {
-    ╾─alloc7──╼ ╾─alloc8──╼                         │ ╾──╼╾──╼
+alloc13 (size: 8, align: 4) {
+    ╾─alloc11─╼ ╾─alloc12─╼                         │ ╾──╼╾──╼
 }
 
-alloc7 (size: 1, align: 1) {
+alloc11 (size: 1, align: 1) {
     05                                              │ .
 }
 
-alloc8 (size: 1, align: 1) {
+alloc12 (size: 1, align: 1) {
     06                                              │ .
 }
 
-alloc19 (size: 12, align: 4) {
-    ╾─a15+0x3─╼ ╾─alloc16─╼ ╾─a18+0x2─╼             │ ╾──╼╾──╼╾──╼
+alloc21 (size: 12, align: 4) {
+    ╾─a17+0x3─╼ ╾─alloc18─╼ ╾─a20+0x2─╼             │ ╾──╼╾──╼╾──╼
 }
 
-alloc15 (size: 4, align: 1) {
+alloc17 (size: 4, align: 1) {
     2a 45 15 6f                                     │ *E.o
 }
 
-alloc16 (size: 1, align: 1) {
+alloc18 (size: 1, align: 1) {
     2a                                              │ *
 }
 
-alloc18 (size: 4, align: 1) {
+alloc20 (size: 4, align: 1) {
     2a 45 15 6f                                     │ *E.o
 }
diff --git a/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.64bit b/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.64bit
index d7acd0f0f43..79bad7ea926 100644
--- a/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.64bit
+++ b/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.64bit
@@ -30,44 +30,44 @@ fn main() -> () {
 }
 
 alloc0 (static: FOO, size: 16, align: 8) {
-    ╾───────alloc21───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    ╾───────alloc23───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
 }
 
-alloc21 (size: 72, align: 8) {
-    0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc4────────╼ │ ....░░░░╾──────╼
+alloc23 (size: 72, align: 8) {
+    0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc8────────╼ │ ....░░░░╾──────╼
     0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░
-    0x20 │ ╾───────alloc9────────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc19───────╼ │ ....*...╾──────╼
+    0x20 │ ╾───────alloc13───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc21───────╼ │ ....*...╾──────╼
     0x40 │ 03 00 00 00 00 00 00 00                         │ ........
 }
 
-alloc4 (size: 0, align: 8) {}
+alloc8 (size: 0, align: 8) {}
 
-alloc9 (size: 16, align: 8) {
-    ╾───────alloc7────────╼ ╾───────alloc8────────╼ │ ╾──────╼╾──────╼
+alloc13 (size: 16, align: 8) {
+    ╾───────alloc11───────╼ ╾───────alloc12───────╼ │ ╾──────╼╾──────╼
 }
 
-alloc7 (size: 1, align: 1) {
+alloc11 (size: 1, align: 1) {
     05                                              │ .
 }
 
-alloc8 (size: 1, align: 1) {
+alloc12 (size: 1, align: 1) {
     06                                              │ .
 }
 
-alloc19 (size: 24, align: 8) {
-    0x00 │ ╾─────alloc15+0x3─────╼ ╾───────alloc16───────╼ │ ╾──────╼╾──────╼
-    0x10 │ ╾─────alloc18+0x2─────╼                         │ ╾──────╼
+alloc21 (size: 24, align: 8) {
+    0x00 │ ╾─────alloc17+0x3─────╼ ╾───────alloc18───────╼ │ ╾──────╼╾──────╼
+    0x10 │ ╾─────alloc20+0x2─────╼                         │ ╾──────╼
 }
 
-alloc15 (size: 4, align: 1) {
+alloc17 (size: 4, align: 1) {
     2a 45 15 6f                                     │ *E.o
 }
 
-alloc16 (size: 1, align: 1) {
+alloc18 (size: 1, align: 1) {
     2a                                              │ *
 }
 
-alloc18 (size: 4, align: 1) {
+alloc20 (size: 4, align: 1) {
     2a 45 15 6f                                     │ *E.o
 }
diff --git a/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff b/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff
index e84e88b93fc..6992abae6c2 100644
--- a/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff
@@ -14,19 +14,21 @@
           StorageLive(_1);                 // scope 0 at $DIR/aggregate.rs:5:9: 5:10
           StorageLive(_2);                 // scope 0 at $DIR/aggregate.rs:5:13: 5:24
           StorageLive(_3);                 // scope 0 at $DIR/aggregate.rs:5:13: 5:22
-          _3 = (const 0_i32, const 1_i32, const 2_i32); // scope 0 at $DIR/aggregate.rs:5:13: 5:22
+          (_3.0: i32) = const 0_i32;       // scope 0 at $DIR/aggregate.rs:5:13: 5:22
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000000))
                                            // mir::Constant
                                            // + span: $DIR/aggregate.rs:5:14: 5:15
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
+          (_3.1: i32) = const 1_i32;       // scope 0 at $DIR/aggregate.rs:5:13: 5:22
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000001))
                                            // mir::Constant
                                            // + span: $DIR/aggregate.rs:5:17: 5:18
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
+          (_3.2: i32) = const 2_i32;       // scope 0 at $DIR/aggregate.rs:5:13: 5:22
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000002))
diff --git a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.32bit
index 539a16f52dc..be9b24bfde8 100644
--- a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.32bit
+++ b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.32bit
@@ -15,19 +15,16 @@
           StorageLive(_1);                 // scope 0 at $DIR/discriminant.rs:11:9: 11:10
           StorageLive(_2);                 // scope 0 at $DIR/discriminant.rs:11:13: 11:64
           StorageLive(_3);                 // scope 0 at $DIR/discriminant.rs:11:34: 11:44
--         _3 = std::option::Option::<bool>::Some(const true); // scope 0 at $DIR/discriminant.rs:11:34: 11:44
-+         _3 = const std::option::Option::<bool>::Some(true); // scope 0 at $DIR/discriminant.rs:11:34: 11:44
+          ((_3 as Some).0: bool) = const true; // scope 0 at $DIR/discriminant.rs:11:34: 11:44
                                            // ty::Const
--                                          // + ty: bool
-+                                          // + ty: std::option::Option<bool>
+                                           // + ty: bool
                                            // + val: Value(Scalar(0x01))
                                            // mir::Constant
--                                          // + span: $DIR/discriminant.rs:11:39: 11:43
--                                          // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+                                           // + span: $DIR/discriminant.rs:11:39: 11:43
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+          discriminant(_3) = 1;            // scope 0 at $DIR/discriminant.rs:11:34: 11:44
 -         _4 = discriminant(_3);           // scope 0 at $DIR/discriminant.rs:11:21: 11:31
 -         switchInt(move _4) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:11:21: 11:31
-+                                          // + span: $DIR/discriminant.rs:11:34: 11:44
-+                                          // + literal: Const { ty: std::option::Option<bool>, val: Value(Scalar(0x01)) }
 +         _4 = const 1_isize;              // scope 0 at $DIR/discriminant.rs:11:21: 11:31
 +                                          // ty::Const
 +                                          // + ty: isize
@@ -56,14 +53,7 @@
       }
   
       bb2: {
--         switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:11:26: 11:30
-+         switchInt(const true) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:11:26: 11:30
-+                                          // ty::Const
-+                                          // + ty: bool
-+                                          // + val: Value(Scalar(0x01))
-+                                          // mir::Constant
-+                                          // + span: $DIR/discriminant.rs:11:26: 11:30
-+                                          // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+          switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:11:26: 11:30
       }
   
       bb3: {
diff --git a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.64bit
index 20875448edd..05b57a6c280 100644
--- a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.64bit
+++ b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.64bit
@@ -15,19 +15,16 @@
           StorageLive(_1);                 // scope 0 at $DIR/discriminant.rs:11:9: 11:10
           StorageLive(_2);                 // scope 0 at $DIR/discriminant.rs:11:13: 11:64
           StorageLive(_3);                 // scope 0 at $DIR/discriminant.rs:11:34: 11:44
--         _3 = std::option::Option::<bool>::Some(const true); // scope 0 at $DIR/discriminant.rs:11:34: 11:44
-+         _3 = const std::option::Option::<bool>::Some(true); // scope 0 at $DIR/discriminant.rs:11:34: 11:44
+          ((_3 as Some).0: bool) = const true; // scope 0 at $DIR/discriminant.rs:11:34: 11:44
                                            // ty::Const
--                                          // + ty: bool
-+                                          // + ty: std::option::Option<bool>
+                                           // + ty: bool
                                            // + val: Value(Scalar(0x01))
                                            // mir::Constant
--                                          // + span: $DIR/discriminant.rs:11:39: 11:43
--                                          // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+                                           // + span: $DIR/discriminant.rs:11:39: 11:43
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+          discriminant(_3) = 1;            // scope 0 at $DIR/discriminant.rs:11:34: 11:44
 -         _4 = discriminant(_3);           // scope 0 at $DIR/discriminant.rs:11:21: 11:31
 -         switchInt(move _4) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:11:21: 11:31
-+                                          // + span: $DIR/discriminant.rs:11:34: 11:44
-+                                          // + literal: Const { ty: std::option::Option<bool>, val: Value(Scalar(0x01)) }
 +         _4 = const 1_isize;              // scope 0 at $DIR/discriminant.rs:11:21: 11:31
 +                                          // ty::Const
 +                                          // + ty: isize
@@ -56,14 +53,7 @@
       }
   
       bb2: {
--         switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:11:26: 11:30
-+         switchInt(const true) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:11:26: 11:30
-+                                          // ty::Const
-+                                          // + ty: bool
-+                                          // + val: Value(Scalar(0x01))
-+                                          // mir::Constant
-+                                          // + span: $DIR/discriminant.rs:11:26: 11:30
-+                                          // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+          switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:11:26: 11:30
       }
   
       bb3: {
diff --git a/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff b/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff
index 242907b5599..59e5b207f12 100644
--- a/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff
@@ -11,21 +11,22 @@
           StorageLive(_1);                 // scope 0 at $DIR/issue-66971.rs:16:5: 16:23
           StorageLive(_2);                 // scope 0 at $DIR/issue-66971.rs:16:12: 16:22
           StorageLive(_3);                 // scope 0 at $DIR/issue-66971.rs:16:13: 16:15
--         _3 = ();                         // scope 0 at $DIR/issue-66971.rs:16:13: 16:15
-+         _3 = const ();                   // scope 0 at $DIR/issue-66971.rs:16:13: 16:15
+-         (_2.0: ()) = move _3;            // scope 0 at $DIR/issue-66971.rs:16:12: 16:22
++         (_2.0: ()) = const ();           // scope 0 at $DIR/issue-66971.rs:16:12: 16:22
 +                                          // ty::Const
 +                                          // + ty: ()
 +                                          // + val: Value(Scalar(<ZST>))
 +                                          // mir::Constant
-+                                          // + span: $DIR/issue-66971.rs:16:13: 16:15
++                                          // + span: $DIR/issue-66971.rs:16:12: 16:22
 +                                          // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
-          _2 = (move _3, const 0_u8, const 0_u8); // scope 0 at $DIR/issue-66971.rs:16:12: 16:22
+          (_2.1: u8) = const 0_u8;         // scope 0 at $DIR/issue-66971.rs:16:12: 16:22
                                            // ty::Const
                                            // + ty: u8
                                            // + val: Value(Scalar(0x00))
                                            // mir::Constant
                                            // + span: $DIR/issue-66971.rs:16:17: 16:18
                                            // + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
+          (_2.2: u8) = const 0_u8;         // scope 0 at $DIR/issue-66971.rs:16:12: 16:22
                                            // ty::Const
                                            // + ty: u8
                                            // + val: Value(Scalar(0x00))
diff --git a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff
index d5c1105d7ca..d3e5e9fe5b4 100644
--- a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff
@@ -11,22 +11,34 @@
           StorageLive(_1);                 // scope 0 at $DIR/issue-67019.rs:11:5: 11:20
           StorageLive(_2);                 // scope 0 at $DIR/issue-67019.rs:11:10: 11:19
           StorageLive(_3);                 // scope 0 at $DIR/issue-67019.rs:11:11: 11:17
-          _3 = (const 1_u8, const 2_u8);   // scope 0 at $DIR/issue-67019.rs:11:11: 11:17
+          (_3.0: u8) = const 1_u8;         // scope 0 at $DIR/issue-67019.rs:11:11: 11:17
                                            // ty::Const
                                            // + ty: u8
                                            // + val: Value(Scalar(0x01))
                                            // mir::Constant
--                                          // + span: $DIR/issue-67019.rs:11:12: 11:13
-+                                          // + span: $DIR/issue-67019.rs:11:11: 11:17
+                                           // + span: $DIR/issue-67019.rs:11:12: 11:13
                                            // + literal: Const { ty: u8, val: Value(Scalar(0x01)) }
+          (_3.1: u8) = const 2_u8;         // scope 0 at $DIR/issue-67019.rs:11:11: 11:17
                                            // ty::Const
                                            // + ty: u8
                                            // + val: Value(Scalar(0x02))
                                            // mir::Constant
--                                          // + span: $DIR/issue-67019.rs:11:15: 11:16
-+                                          // + span: $DIR/issue-67019.rs:11:11: 11:17
+                                           // + span: $DIR/issue-67019.rs:11:15: 11:16
                                            // + literal: Const { ty: u8, val: Value(Scalar(0x02)) }
-          _2 = (move _3,);                 // scope 0 at $DIR/issue-67019.rs:11:10: 11:19
+-         (_2.0: (u8, u8)) = move _3;      // scope 0 at $DIR/issue-67019.rs:11:10: 11:19
++         (_2.0: (u8, u8)) = (const 1_u8, const 2_u8); // scope 0 at $DIR/issue-67019.rs:11:10: 11:19
++                                          // ty::Const
++                                          // + ty: u8
++                                          // + val: Value(Scalar(0x01))
++                                          // mir::Constant
++                                          // + span: $DIR/issue-67019.rs:11:10: 11:19
++                                          // + literal: Const { ty: u8, val: Value(Scalar(0x01)) }
++                                          // ty::Const
++                                          // + ty: u8
++                                          // + val: Value(Scalar(0x02))
++                                          // mir::Constant
++                                          // + span: $DIR/issue-67019.rs:11:10: 11:19
++                                          // + literal: Const { ty: u8, val: Value(Scalar(0x02)) }
           StorageDead(_3);                 // scope 0 at $DIR/issue-67019.rs:11:18: 11:19
           _1 = const test(move _2) -> bb1; // scope 0 at $DIR/issue-67019.rs:11:5: 11:20
                                            // ty::Const
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff
index f581b222c83..617702a5209 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff
@@ -14,20 +14,19 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_aggregate.rs:5:9: 5:14
-          _1 = (const 42_i32, const 43_i32); // scope 0 at $DIR/mutable_variable_aggregate.rs:5:17: 5:25
+          (_1.0: i32) = const 42_i32;      // scope 0 at $DIR/mutable_variable_aggregate.rs:5:17: 5:25
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x0000002a))
                                            // mir::Constant
--                                          // + span: $DIR/mutable_variable_aggregate.rs:5:18: 5:20
-+                                          // + span: $DIR/mutable_variable_aggregate.rs:5:17: 5:25
+                                           // + span: $DIR/mutable_variable_aggregate.rs:5:18: 5:20
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
+          (_1.1: i32) = const 43_i32;      // scope 0 at $DIR/mutable_variable_aggregate.rs:5:17: 5:25
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x0000002b))
                                            // mir::Constant
--                                          // + span: $DIR/mutable_variable_aggregate.rs:5:22: 5:24
-+                                          // + span: $DIR/mutable_variable_aggregate.rs:5:17: 5:25
+                                           // + span: $DIR/mutable_variable_aggregate.rs:5:22: 5:24
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x0000002b)) }
           (_1.1: i32) = const 99_i32;      // scope 1 at $DIR/mutable_variable_aggregate.rs:6:5: 6:13
                                            // ty::Const
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff
index 6e2ee0957ab..dbf77cf6b37 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff
@@ -18,13 +18,14 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:9: 5:14
-          _1 = (const 42_i32, const 43_i32); // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25
+          (_1.0: i32) = const 42_i32;      // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x0000002a))
                                            // mir::Constant
                                            // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:18: 5:20
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
+          (_1.1: i32) = const 43_i32;      // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x0000002b))
diff --git a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
index b59b180b07d..84e858debdd 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
@@ -34,20 +34,19 @@
   
       bb1: {
           StorageLive(_2);                 // scope 1 at $DIR/mutable_variable_unprop_assign.rs:6:9: 6:14
-          _2 = (const 1_i32, const 2_i32); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:6:29: 6:35
+          (_2.0: i32) = const 1_i32;       // scope 1 at $DIR/mutable_variable_unprop_assign.rs:6:29: 6:35
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000001))
                                            // mir::Constant
--                                          // + span: $DIR/mutable_variable_unprop_assign.rs:6:30: 6:31
-+                                          // + span: $DIR/mutable_variable_unprop_assign.rs:6:29: 6:35
+                                           // + span: $DIR/mutable_variable_unprop_assign.rs:6:30: 6:31
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
+          (_2.1: i32) = const 2_i32;       // scope 1 at $DIR/mutable_variable_unprop_assign.rs:6:29: 6:35
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000002))
                                            // mir::Constant
--                                          // + span: $DIR/mutable_variable_unprop_assign.rs:6:33: 6:34
-+                                          // + span: $DIR/mutable_variable_unprop_assign.rs:6:29: 6:35
+                                           // + span: $DIR/mutable_variable_unprop_assign.rs:6:33: 6:34
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) }
           StorageLive(_3);                 // scope 2 at $DIR/mutable_variable_unprop_assign.rs:7:11: 7:12
           _3 = _1;                         // scope 2 at $DIR/mutable_variable_unprop_assign.rs:7:11: 7:12
diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.32bit
index 5312784bc8a..c2381f3da90 100644
--- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.32bit
+++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.32bit
@@ -173,13 +173,14 @@
           StorageDead(_4);                 // scope 1 at $DIR/optimizes_into_variable.rs:13:34: 13:35
           StorageLive(_8);                 // scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10
           StorageLive(_9);                 // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
-          _9 = Point { x: const 12_u32, y: const 42_u32 }; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
+          (_9.0: u32) = const 12_u32;      // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
                                            // ty::Const
                                            // + ty: u32
                                            // + val: Value(Scalar(0x0000000c))
                                            // mir::Constant
                                            // + span: $DIR/optimizes_into_variable.rs:14:25: 14:27
                                            // + literal: Const { ty: u32, val: Value(Scalar(0x0000000c)) }
+          (_9.1: u32) = const 42_u32;      // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
                                            // ty::Const
                                            // + ty: u32
                                            // + val: Value(Scalar(0x0000002a))
diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.64bit
index 7af99841366..bc965b4ade7 100644
--- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.64bit
+++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.64bit
@@ -173,13 +173,14 @@
           StorageDead(_4);                 // scope 1 at $DIR/optimizes_into_variable.rs:13:34: 13:35
           StorageLive(_8);                 // scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10
           StorageLive(_9);                 // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
-          _9 = Point { x: const 12_u32, y: const 42_u32 }; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
+          (_9.0: u32) = const 12_u32;      // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
                                            // ty::Const
                                            // + ty: u32
                                            // + val: Value(Scalar(0x0000000c))
                                            // mir::Constant
                                            // + span: $DIR/optimizes_into_variable.rs:14:25: 14:27
                                            // + literal: Const { ty: u32, val: Value(Scalar(0x0000000c)) }
+          (_9.1: u32) = const 42_u32;      // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
                                            // ty::Const
                                            // + ty: u32
                                            // + val: Value(Scalar(0x0000002a))
diff --git a/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff b/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
index 941ec64a3cc..e4a0ef27b24 100644
--- a/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
@@ -12,20 +12,19 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/tuple_literal_propagation.rs:3:9: 3:10
-          _1 = (const 1_u32, const 2_u32); // scope 0 at $DIR/tuple_literal_propagation.rs:3:13: 3:19
+          (_1.0: u32) = const 1_u32;       // scope 0 at $DIR/tuple_literal_propagation.rs:3:13: 3:19
                                            // ty::Const
                                            // + ty: u32
                                            // + val: Value(Scalar(0x00000001))
                                            // mir::Constant
--                                          // + span: $DIR/tuple_literal_propagation.rs:3:14: 3:15
-+                                          // + span: $DIR/tuple_literal_propagation.rs:3:13: 3:19
+                                           // + span: $DIR/tuple_literal_propagation.rs:3:14: 3:15
                                            // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
+          (_1.1: u32) = const 2_u32;       // scope 0 at $DIR/tuple_literal_propagation.rs:3:13: 3:19
                                            // ty::Const
                                            // + ty: u32
                                            // + val: Value(Scalar(0x00000002))
                                            // mir::Constant
--                                          // + span: $DIR/tuple_literal_propagation.rs:3:17: 3:18
-+                                          // + span: $DIR/tuple_literal_propagation.rs:3:13: 3:19
+                                           // + span: $DIR/tuple_literal_propagation.rs:3:17: 3:18
                                            // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
           StorageLive(_2);                 // scope 1 at $DIR/tuple_literal_propagation.rs:5:5: 5:15
           StorageLive(_3);                 // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
diff --git a/src/test/mir-opt/const_prop_miscompile.bar.ConstProp.diff b/src/test/mir-opt/const_prop_miscompile.bar.ConstProp.diff
index 5fe35b479c1..b4733b5ed39 100644
--- a/src/test/mir-opt/const_prop_miscompile.bar.ConstProp.diff
+++ b/src/test/mir-opt/const_prop_miscompile.bar.ConstProp.diff
@@ -19,17 +19,13 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:12:9: 12:14
--         _1 = (const 1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:12:17: 12:21
-+         _1 = const (1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:12:17: 12:21
+          (_1.0: i32) = const 1_i32;       // scope 0 at $DIR/const_prop_miscompile.rs:12:17: 12:21
                                            // ty::Const
--                                          // + ty: i32
-+                                          // + ty: (i32,)
+                                           // + ty: i32
                                            // + val: Value(Scalar(0x00000001))
                                            // mir::Constant
--                                          // + span: $DIR/const_prop_miscompile.rs:12:18: 12:19
--                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
-+                                          // + span: $DIR/const_prop_miscompile.rs:12:17: 12:21
-+                                          // + literal: Const { ty: (i32,), val: Value(Scalar(0x00000001)) }
+                                           // + span: $DIR/const_prop_miscompile.rs:12:18: 12:19
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
           StorageLive(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:13:5: 15:6
           StorageLive(_3);                 // scope 2 at $DIR/const_prop_miscompile.rs:14:10: 14:22
           _3 = &raw mut (_1.0: i32);       // scope 2 at $DIR/const_prop_miscompile.rs:14:10: 14:22
diff --git a/src/test/mir-opt/const_prop_miscompile.foo.ConstProp.diff b/src/test/mir-opt/const_prop_miscompile.foo.ConstProp.diff
index 98e9825c1c4..b54fc41d0b4 100644
--- a/src/test/mir-opt/const_prop_miscompile.foo.ConstProp.diff
+++ b/src/test/mir-opt/const_prop_miscompile.foo.ConstProp.diff
@@ -16,17 +16,13 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:5:9: 5:14
--         _1 = (const 1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:5:17: 5:21
-+         _1 = const (1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:5:17: 5:21
+          (_1.0: i32) = const 1_i32;       // scope 0 at $DIR/const_prop_miscompile.rs:5:17: 5:21
                                            // ty::Const
--                                          // + ty: i32
-+                                          // + ty: (i32,)
+                                           // + ty: i32
                                            // + val: Value(Scalar(0x00000001))
                                            // mir::Constant
--                                          // + span: $DIR/const_prop_miscompile.rs:5:18: 5:19
--                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
-+                                          // + span: $DIR/const_prop_miscompile.rs:5:17: 5:21
-+                                          // + literal: Const { ty: (i32,), val: Value(Scalar(0x00000001)) }
+                                           // + span: $DIR/const_prop_miscompile.rs:5:18: 5:19
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
           StorageLive(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:6:6: 6:14
           _2 = &mut (_1.0: i32);           // scope 1 at $DIR/const_prop_miscompile.rs:6:6: 6:14
           (*_2) = const 5_i32;             // scope 1 at $DIR/const_prop_miscompile.rs:6:5: 6:18
diff --git a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff
new file mode 100644
index 00000000000..5f928ea2a16
--- /dev/null
+++ b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff
@@ -0,0 +1,162 @@
+- // MIR for `float_to_exponential_common` before ConstProp
++ // MIR for `float_to_exponential_common` after ConstProp
+  
+  fn float_to_exponential_common(_1: &mut std::fmt::Formatter, _2: &T, _3: bool) -> std::result::Result<(), std::fmt::Error> {
+      debug fmt => _1;                     // in scope 0 at $DIR/funky_arms.rs:11:35: 11:38
+      debug num => _2;                     // in scope 0 at $DIR/funky_arms.rs:11:60: 11:63
+      debug upper => _3;                   // in scope 0 at $DIR/funky_arms.rs:11:69: 11:74
+      let mut _0: std::result::Result<(), std::fmt::Error>; // return place in scope 0 at $DIR/funky_arms.rs:11:85: 11:91
+      let _4: bool;                        // in scope 0 at $DIR/funky_arms.rs:15:9: 15:19
+      let mut _5: &std::fmt::Formatter;    // in scope 0 at $DIR/funky_arms.rs:15:22: 15:25
+      let mut _7: std::option::Option<usize>; // in scope 0 at $DIR/funky_arms.rs:24:30: 24:45
+      let mut _8: &std::fmt::Formatter;    // in scope 0 at $DIR/funky_arms.rs:24:30: 24:33
+      let mut _9: isize;                   // in scope 0 at $DIR/funky_arms.rs:24:12: 24:27
+      let mut _11: &mut std::fmt::Formatter; // in scope 0 at $DIR/funky_arms.rs:26:43: 26:46
+      let mut _12: &T;                     // in scope 0 at $DIR/funky_arms.rs:26:48: 26:51
+      let mut _13: core::num::flt2dec::Sign; // in scope 0 at $DIR/funky_arms.rs:26:53: 26:57
+      let mut _14: u32;                    // in scope 0 at $DIR/funky_arms.rs:26:59: 26:79
+      let mut _15: u32;                    // in scope 0 at $DIR/funky_arms.rs:26:59: 26:75
+      let mut _16: usize;                  // in scope 0 at $DIR/funky_arms.rs:26:59: 26:68
+      let mut _17: bool;                   // in scope 0 at $DIR/funky_arms.rs:26:81: 26:86
+      let mut _18: &mut std::fmt::Formatter; // in scope 0 at $DIR/funky_arms.rs:28:46: 28:49
+      let mut _19: &T;                     // in scope 0 at $DIR/funky_arms.rs:28:51: 28:54
+      let mut _20: core::num::flt2dec::Sign; // in scope 0 at $DIR/funky_arms.rs:28:56: 28:60
+      let mut _21: bool;                   // in scope 0 at $DIR/funky_arms.rs:28:62: 28:67
+      scope 1 {
+          debug force_sign => _4;          // in scope 1 at $DIR/funky_arms.rs:15:9: 15:19
+          let _6: core::num::flt2dec::Sign; // in scope 1 at $DIR/funky_arms.rs:19:9: 19:13
+          scope 2 {
+              debug sign => _6;            // in scope 2 at $DIR/funky_arms.rs:19:9: 19:13
+              let _10: usize;              // in scope 2 at $DIR/funky_arms.rs:24:17: 24:26
+              scope 3 {
+                  debug precision => _10;  // in scope 3 at $DIR/funky_arms.rs:24:17: 24:26
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_4);                 // scope 0 at $DIR/funky_arms.rs:15:9: 15:19
+          StorageLive(_5);                 // scope 0 at $DIR/funky_arms.rs:15:22: 15:25
+          _5 = &(*_1);                     // scope 0 at $DIR/funky_arms.rs:15:22: 15:25
+          _4 = const std::fmt::Formatter::sign_plus(move _5) -> bb1; // scope 0 at $DIR/funky_arms.rs:15:22: 15:37
+                                           // ty::Const
+                                           // + ty: for<'r> fn(&'r std::fmt::Formatter) -> bool {std::fmt::Formatter::sign_plus}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/funky_arms.rs:15:26: 15:35
+                                           // + literal: Const { ty: for<'r> fn(&'r std::fmt::Formatter) -> bool {std::fmt::Formatter::sign_plus}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+          StorageDead(_5);                 // scope 0 at $DIR/funky_arms.rs:15:36: 15:37
+          StorageLive(_6);                 // scope 1 at $DIR/funky_arms.rs:19:9: 19:13
+          switchInt(_4) -> [false: bb3, otherwise: bb2]; // scope 1 at $DIR/funky_arms.rs:20:9: 20:14
+      }
+  
+      bb2: {
+          discriminant(_6) = 2;            // scope 1 at $DIR/funky_arms.rs:21:17: 21:41
+          goto -> bb4;                     // scope 1 at $DIR/funky_arms.rs:19:16: 22:6
+      }
+  
+      bb3: {
+          discriminant(_6) = 0;            // scope 1 at $DIR/funky_arms.rs:20:18: 20:38
+          goto -> bb4;                     // scope 1 at $DIR/funky_arms.rs:19:16: 22:6
+      }
+  
+      bb4: {
+          StorageLive(_7);                 // scope 2 at $DIR/funky_arms.rs:24:30: 24:45
+          StorageLive(_8);                 // scope 2 at $DIR/funky_arms.rs:24:30: 24:33
+          _8 = &(*_1);                     // scope 2 at $DIR/funky_arms.rs:24:30: 24:33
+          _7 = const std::fmt::Formatter::precision(move _8) -> bb5; // scope 2 at $DIR/funky_arms.rs:24:30: 24:45
+                                           // ty::Const
+                                           // + ty: for<'r> fn(&'r std::fmt::Formatter) -> std::option::Option<usize> {std::fmt::Formatter::precision}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/funky_arms.rs:24:34: 24:43
+                                           // + literal: Const { ty: for<'r> fn(&'r std::fmt::Formatter) -> std::option::Option<usize> {std::fmt::Formatter::precision}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb5: {
+          StorageDead(_8);                 // scope 2 at $DIR/funky_arms.rs:24:44: 24:45
+          _9 = discriminant(_7);           // scope 2 at $DIR/funky_arms.rs:24:12: 24:27
+          switchInt(move _9) -> [1_isize: bb7, otherwise: bb6]; // scope 2 at $DIR/funky_arms.rs:24:12: 24:27
+      }
+  
+      bb6: {
+          StorageLive(_18);                // scope 2 at $DIR/funky_arms.rs:28:46: 28:49
+          _18 = &mut (*_1);                // scope 2 at $DIR/funky_arms.rs:28:46: 28:49
+          StorageLive(_19);                // scope 2 at $DIR/funky_arms.rs:28:51: 28:54
+          _19 = _2;                        // scope 2 at $DIR/funky_arms.rs:28:51: 28:54
+          StorageLive(_20);                // scope 2 at $DIR/funky_arms.rs:28:56: 28:60
+          _20 = _6;                        // scope 2 at $DIR/funky_arms.rs:28:56: 28:60
+          StorageLive(_21);                // scope 2 at $DIR/funky_arms.rs:28:62: 28:67
+          _21 = _3;                        // scope 2 at $DIR/funky_arms.rs:28:62: 28:67
+          _0 = const float_to_exponential_common_shortest::<T>(move _18, move _19, move _20, move _21) -> bb9; // scope 2 at $DIR/funky_arms.rs:28:9: 28:68
+                                           // ty::Const
+                                           // + ty: for<'r, 's, 't0> fn(&'r mut std::fmt::Formatter<'s>, &'t0 T, core::num::flt2dec::Sign, bool) -> std::result::Result<(), std::fmt::Error> {float_to_exponential_common_shortest::<T>}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/funky_arms.rs:28:9: 28:45
+                                           // + literal: Const { ty: for<'r, 's, 't0> fn(&'r mut std::fmt::Formatter<'s>, &'t0 T, core::num::flt2dec::Sign, bool) -> std::result::Result<(), std::fmt::Error> {float_to_exponential_common_shortest::<T>}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb7: {
+          StorageLive(_10);                // scope 2 at $DIR/funky_arms.rs:24:17: 24:26
+          _10 = ((_7 as Some).0: usize);   // scope 2 at $DIR/funky_arms.rs:24:17: 24:26
+          StorageLive(_11);                // scope 3 at $DIR/funky_arms.rs:26:43: 26:46
+          _11 = &mut (*_1);                // scope 3 at $DIR/funky_arms.rs:26:43: 26:46
+          StorageLive(_12);                // scope 3 at $DIR/funky_arms.rs:26:48: 26:51
+          _12 = _2;                        // scope 3 at $DIR/funky_arms.rs:26:48: 26:51
+          StorageLive(_13);                // scope 3 at $DIR/funky_arms.rs:26:53: 26:57
+          _13 = _6;                        // scope 3 at $DIR/funky_arms.rs:26:53: 26:57
+          StorageLive(_14);                // scope 3 at $DIR/funky_arms.rs:26:59: 26:79
+          StorageLive(_15);                // scope 3 at $DIR/funky_arms.rs:26:59: 26:75
+          StorageLive(_16);                // scope 3 at $DIR/funky_arms.rs:26:59: 26:68
+          _16 = _10;                       // scope 3 at $DIR/funky_arms.rs:26:59: 26:68
+          _15 = move _16 as u32 (Misc);    // scope 3 at $DIR/funky_arms.rs:26:59: 26:75
+          StorageDead(_16);                // scope 3 at $DIR/funky_arms.rs:26:74: 26:75
+          _14 = Add(move _15, const 1_u32); // scope 3 at $DIR/funky_arms.rs:26:59: 26:79
+                                           // ty::Const
+                                           // + ty: u32
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+                                           // + span: $DIR/funky_arms.rs:26:78: 26:79
+                                           // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
+          StorageDead(_15);                // scope 3 at $DIR/funky_arms.rs:26:78: 26:79
+          StorageLive(_17);                // scope 3 at $DIR/funky_arms.rs:26:81: 26:86
+          _17 = _3;                        // scope 3 at $DIR/funky_arms.rs:26:81: 26:86
+          _0 = const float_to_exponential_common_exact::<T>(move _11, move _12, move _13, move _14, move _17) -> bb8; // scope 3 at $DIR/funky_arms.rs:26:9: 26:87
+                                           // ty::Const
+                                           // + ty: for<'r, 's, 't0> fn(&'r mut std::fmt::Formatter<'s>, &'t0 T, core::num::flt2dec::Sign, u32, bool) -> std::result::Result<(), std::fmt::Error> {float_to_exponential_common_exact::<T>}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/funky_arms.rs:26:9: 26:42
+                                           // + literal: Const { ty: for<'r, 's, 't0> fn(&'r mut std::fmt::Formatter<'s>, &'t0 T, core::num::flt2dec::Sign, u32, bool) -> std::result::Result<(), std::fmt::Error> {float_to_exponential_common_exact::<T>}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb8: {
+          StorageDead(_17);                // scope 3 at $DIR/funky_arms.rs:26:86: 26:87
+          StorageDead(_14);                // scope 3 at $DIR/funky_arms.rs:26:86: 26:87
+          StorageDead(_13);                // scope 3 at $DIR/funky_arms.rs:26:86: 26:87
+          StorageDead(_12);                // scope 3 at $DIR/funky_arms.rs:26:86: 26:87
+          StorageDead(_11);                // scope 3 at $DIR/funky_arms.rs:26:86: 26:87
+          StorageDead(_10);                // scope 2 at $DIR/funky_arms.rs:27:5: 27:6
+          goto -> bb10;                    // scope 2 at $DIR/funky_arms.rs:24:5: 29:6
+      }
+  
+      bb9: {
+          StorageDead(_21);                // scope 2 at $DIR/funky_arms.rs:28:67: 28:68
+          StorageDead(_20);                // scope 2 at $DIR/funky_arms.rs:28:67: 28:68
+          StorageDead(_19);                // scope 2 at $DIR/funky_arms.rs:28:67: 28:68
+          StorageDead(_18);                // scope 2 at $DIR/funky_arms.rs:28:67: 28:68
+          goto -> bb10;                    // scope 2 at $DIR/funky_arms.rs:24:5: 29:6
+      }
+  
+      bb10: {
+          StorageDead(_6);                 // scope 1 at $DIR/funky_arms.rs:30:1: 30:2
+          StorageDead(_4);                 // scope 0 at $DIR/funky_arms.rs:30:1: 30:2
+          StorageDead(_7);                 // scope 0 at $DIR/funky_arms.rs:30:1: 30:2
+          return;                          // scope 0 at $DIR/funky_arms.rs:30:2: 30:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/funky_arms.rs b/src/test/mir-opt/funky_arms.rs
new file mode 100644
index 00000000000..3e70d85e0d4
--- /dev/null
+++ b/src/test/mir-opt/funky_arms.rs
@@ -0,0 +1,56 @@
+// compile-flags: --crate-type lib -Cdebug-assertions=no
+
+#![feature(flt2dec)]
+
+extern crate core;
+
+use core::num::flt2dec;
+use std::fmt::{Formatter, Result};
+
+// EMIT_MIR funky_arms.float_to_exponential_common.ConstProp.diff
+fn float_to_exponential_common<T>(fmt: &mut Formatter<'_>, num: &T, upper: bool) -> Result
+where
+    T: flt2dec::DecodableFloat,
+{
+    let force_sign = fmt.sign_plus();
+    // A bug in const propagation (never reached master, but during dev of a PR) caused the
+    // `sign = Minus` assignment to get propagated into all future reads of `sign`. This is
+    // wrong because `sign` could also have `MinusPlus` value.
+    let sign = match force_sign {
+        false => flt2dec::Sign::Minus,
+        true => flt2dec::Sign::MinusPlus,
+    };
+
+    if let Some(precision) = fmt.precision() {
+        // 1 integral digit + `precision` fractional digits = `precision + 1` total digits
+        float_to_exponential_common_exact(fmt, num, sign, precision as u32 + 1, upper)
+    } else {
+        float_to_exponential_common_shortest(fmt, num, sign, upper)
+    }
+}
+#[inline(never)]
+fn float_to_exponential_common_exact<T>(
+    fmt: &mut Formatter<'_>,
+    num: &T,
+    sign: flt2dec::Sign,
+    precision: u32,
+    upper: bool,
+) -> Result
+where
+    T: flt2dec::DecodableFloat,
+{
+    unimplemented!()
+}
+
+#[inline(never)]
+fn float_to_exponential_common_shortest<T>(
+    fmt: &mut Formatter<'_>,
+    num: &T,
+    sign: flt2dec::Sign,
+    upper: bool,
+) -> Result
+where
+    T: flt2dec::DecodableFloat,
+{
+    unimplemented!()
+}
diff --git a/src/test/mir-opt/generator_storage_dead_unwind.main-{{closure}}.StateTransform.before.mir b/src/test/mir-opt/generator_storage_dead_unwind.main-{{closure}}.StateTransform.before.mir
index 7dcfda32ca4..356470f8fec 100644
--- a/src/test/mir-opt/generator_storage_dead_unwind.main-{{closure}}.StateTransform.before.mir
+++ b/src/test/mir-opt/generator_storage_dead_unwind.main-{{closure}}.StateTransform.before.mir
@@ -21,7 +21,7 @@ yields ()
 
     bb0: {
         StorageLive(_3);                 // scope 0 at $DIR/generator-storage-dead-unwind.rs:23:13: 23:14
-        _3 = Foo(const 5_i32);           // scope 0 at $DIR/generator-storage-dead-unwind.rs:23:17: 23:23
+        (_3.0: i32) = const 5_i32;       // scope 0 at $DIR/generator-storage-dead-unwind.rs:23:17: 23:23
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000005))
@@ -29,7 +29,7 @@ yields ()
                                          // + span: $DIR/generator-storage-dead-unwind.rs:23:21: 23:22
                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
         StorageLive(_4);                 // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:13: 24:14
-        _4 = Bar(const 6_i32);           // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:17: 24:23
+        (_4.0: i32) = const 6_i32;       // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:17: 24:23
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000006))
@@ -38,7 +38,6 @@ yields ()
                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000006)) }
         StorageLive(_5);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
         StorageLive(_6);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
-        _6 = ();                         // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
         _5 = yield(move _6) -> [resume: bb2, drop: bb4]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
     }
 
diff --git a/src/test/mir-opt/generator_tiny.main-{{closure}}.generator_resume.0.mir b/src/test/mir-opt/generator_tiny.main-{{closure}}.generator_resume.0.mir
index 8776e5919bd..41fc04774db 100644
--- a/src/test/mir-opt/generator_tiny.main-{{closure}}.generator_resume.0.mir
+++ b/src/test/mir-opt/generator_tiny.main-{{closure}}.generator_resume.0.mir
@@ -1,17 +1,13 @@
 // MIR for `main::{{closure}}#0` 0 generator_resume
 /* generator_layout = GeneratorLayout {
-    field_tys: {
-        _0: HasDrop,
-    },
+    field_tys: {},
     variant_fields: {
         Unresumed(0): [],
         Returned (1): [],
         Panicked (2): [],
-        Suspend0 (3): [_0],
-    },
-    storage_conflicts: BitMatrix(1x1) {
-        (_0, _0),
+        Suspend0 (3): [],
     },
+    storage_conflicts: BitMatrix(0x0) {},
 } */
 
 fn main::{{closure}}#0(_1: std::pin::Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}]>, _2: u8) -> std::ops::GeneratorState<(), ()> {
@@ -27,7 +23,7 @@ fn main::{{closure}}#0(_1: std::pin::Pin<&mut [generator@$DIR/generator-tiny.rs:
     let _10: u8;                         // in scope 0 at $DIR/generator-tiny.rs:19:17: 19:19
     let mut _11: u32;                    // in scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
     scope 1 {
-        debug _d => (((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}])) as variant#3).0: HasDrop); // in scope 1 at $DIR/generator-tiny.rs:20:13: 20:15
+        debug _d => _3;                  // in scope 1 at $DIR/generator-tiny.rs:20:13: 20:15
     }
 
     bb0: {
@@ -37,8 +33,7 @@ fn main::{{closure}}#0(_1: std::pin::Pin<&mut [generator@$DIR/generator-tiny.rs:
 
     bb1: {
         _10 = move _2;                   // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
-        nop;                             // scope 0 at $DIR/generator-tiny.rs:20:13: 20:15
-        (((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}])) as variant#3).0: HasDrop) = HasDrop; // scope 0 at $DIR/generator-tiny.rs:20:18: 20:25
+        StorageLive(_3);                 // scope 0 at $DIR/generator-tiny.rs:20:13: 20:15
         StorageLive(_4);                 // scope 1 at $DIR/generator-tiny.rs:21:9: 24:10
         goto -> bb2;                     // scope 1 at $DIR/generator-tiny.rs:21:9: 24:10
     }
@@ -46,7 +41,6 @@ fn main::{{closure}}#0(_1: std::pin::Pin<&mut [generator@$DIR/generator-tiny.rs:
     bb2: {
         StorageLive(_6);                 // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
         StorageLive(_7);                 // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
-        _7 = ();                         // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
         _0 = std::ops::GeneratorState::<(), ()>::Yielded(move _7); // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
         discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}]))) = 3; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
         return;                          // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
@@ -78,6 +72,7 @@ fn main::{{closure}}#0(_1: std::pin::Pin<&mut [generator@$DIR/generator-tiny.rs:
     }
 
     bb5: {
+        StorageLive(_3);                 // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
         StorageLive(_4);                 // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
         StorageLive(_6);                 // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
         StorageLive(_7);                 // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
diff --git a/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir
index bd0ec8c7ddb..b40a8047c41 100644
--- a/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir
@@ -21,15 +21,6 @@ fn foo(_1: T, _2: i32) -> i32 {
 
     bb0: {
         StorageLive(_3);                 // scope 0 at $DIR/inline-closure.rs:11:9: 11:10
-        _3 = [closure@foo::<T>::{{closure}}#0]; // scope 0 at $DIR/inline-closure.rs:11:13: 11:24
-                                         // closure
-                                         // + def_id: DefId(0:6 ~ inline_closure[317d]::foo[0]::{{closure}}[0])
-                                         // + substs: [
-                                         //     T,
-                                         //     i8,
-                                         //     extern "rust-call" fn((i32, i32)) -> i32,
-                                         //     (),
-                                         // ]
         StorageLive(_4);                 // scope 1 at $DIR/inline-closure.rs:12:5: 12:6
         _4 = &_3;                        // scope 1 at $DIR/inline-closure.rs:12:5: 12:6
         StorageLive(_5);                 // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
@@ -37,7 +28,8 @@ fn foo(_1: T, _2: i32) -> i32 {
         _6 = _2;                         // scope 1 at $DIR/inline-closure.rs:12:7: 12:8
         StorageLive(_7);                 // scope 1 at $DIR/inline-closure.rs:12:10: 12:11
         _7 = _2;                         // scope 1 at $DIR/inline-closure.rs:12:10: 12:11
-        _5 = (move _6, move _7);         // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
+        (_5.0: i32) = move _6;           // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
+        (_5.1: i32) = move _7;           // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
         _8 = move (_5.0: i32);           // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
         _9 = move (_5.1: i32);           // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
         _0 = _8;                         // scope 2 at $DIR/inline-closure.rs:11:22: 11:24
diff --git a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir
index cea3c59a3e4..f6dd7413640 100644
--- a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir
@@ -24,15 +24,6 @@ fn foo(_1: T, _2: &i32) -> i32 {
 
     bb0: {
         StorageLive(_3);                 // scope 0 at $DIR/inline-closure-borrows-arg.rs:12:9: 12:10
-        _3 = [closure@foo::<T>::{{closure}}#0]; // scope 0 at $DIR/inline-closure-borrows-arg.rs:12:13: 15:6
-                                         // closure
-                                         // + def_id: DefId(0:6 ~ inline_closure_borrows_arg[317d]::foo[0]::{{closure}}[0])
-                                         // + substs: [
-                                         //     T,
-                                         //     i8,
-                                         //     for<'r, 's> extern "rust-call" fn((&'r i32, &'s i32)) -> i32,
-                                         //     (),
-                                         // ]
         StorageLive(_4);                 // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:6
         _4 = &_3;                        // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:6
         StorageLive(_5);                 // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
@@ -40,7 +31,8 @@ fn foo(_1: T, _2: &i32) -> i32 {
         _6 = &(*_2);                     // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:7: 16:8
         StorageLive(_7);                 // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:10: 16:11
         _7 = &(*_2);                     // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:10: 16:11
-        _5 = (move _6, move _7);         // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
+        (_5.0: &i32) = move _6;          // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
+        (_5.1: &i32) = move _7;          // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
         _8 = move (_5.0: &i32);          // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
         _9 = move (_5.1: &i32);          // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
         _0 = (*_8);                      // scope 3 at $DIR/inline-closure-borrows-arg.rs:14:9: 14:18
diff --git a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
index eeff914ccff..e2b5d6567c2 100644
--- a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
@@ -28,15 +28,8 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
         _4 = &_2;                        // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24
         StorageLive(_5);                 // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24
         _5 = &_1;                        // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24
-        _3 = [closure@foo::<T>::{{closure}}#0] { q: move _4, t: move _5 }; // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24
-                                         // closure
-                                         // + def_id: DefId(0:6 ~ inline_closure_captures[317d]::foo[0]::{{closure}}[0])
-                                         // + substs: [
-                                         //     T,
-                                         //     i8,
-                                         //     extern "rust-call" fn((i32,)) -> (i32, T),
-                                         //     (&i32, &T),
-                                         // ]
+        (_3.0: &i32) = move _4;          // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24
+        (_3.1: &T) = move _5;            // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24
         StorageDead(_5);                 // scope 0 at $DIR/inline-closure-captures.rs:11:23: 11:24
         StorageDead(_4);                 // scope 0 at $DIR/inline-closure-captures.rs:11:23: 11:24
         StorageLive(_6);                 // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:6
@@ -44,7 +37,7 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
         StorageLive(_7);                 // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
         StorageLive(_8);                 // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8
         _8 = _2;                         // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8
-        _7 = (move _8,);                 // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
+        (_7.0: i32) = move _8;           // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
         _11 = move (_7.0: i32);          // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
         StorageLive(_9);                 // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
         _9 = (*((*_6).0: &i32));         // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.diff.32bit b/src/test/mir-opt/issue_73223.main.PreCodegen.diff.32bit
index 4c9da471f0b..919c37a5fc3 100644
--- a/src/test/mir-opt/issue_73223.main.PreCodegen.diff.32bit
+++ b/src/test/mir-opt/issue_73223.main.PreCodegen.diff.32bit
@@ -11,22 +11,20 @@
       let mut _9: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _10: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _11: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _12: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _13: &std::fmt::Arguments;       // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let _14: std::fmt::Arguments;        // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let mut _15: &[&str];                // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _16: &[std::fmt::ArgumentV1]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let _17: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let _18: [std::fmt::ArgumentV1; 2];  // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let mut _19: (&&i32, &&i32);         // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let mut _20: &&i32;                  // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _21: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _22: &&i32;                  // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _23: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let _12: &std::fmt::Arguments;       // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let _13: std::fmt::Arguments;        // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let mut _14: &[&str];                // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _15: &[std::fmt::ArgumentV1]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let _16: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let _17: [std::fmt::ArgumentV1; 2];  // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let mut _18: (&&i32, &&i32);         // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let mut _19: &&i32;                  // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let _20: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _21: &&i32;                  // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _24: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let mut _25: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _26: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
       let mut _27: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _28: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let mut _29: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       scope 1 {
           debug split => _2;               // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14
           let _3: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14
@@ -37,28 +35,28 @@
               scope 4 {
                   debug left_val => _7;    // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                   debug right_val => _8;   // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  let _24: &&i32;          // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  let _25: &&i32;          // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                  let _22: &&i32;          // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                  let _23: &&i32;          // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                   scope 5 {
-                      debug arg0 => _24;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                      debug arg1 => _25;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                      debug arg0 => _22;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                      debug arg1 => _23;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                       scope 6 {
-                          debug x => _24;  // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                          debug f => _27;  // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                          let mut _30: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
-                          let mut _31: &core::fmt::Opaque; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
+                          debug x => _22;  // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                          debug f => _25;  // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                          let mut _28: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
+                          let mut _29: &core::fmt::Opaque; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
                       }
                       scope 8 {
-                          debug x => _25;  // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                          debug f => _29;  // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                          let mut _32: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
-                          let mut _33: &core::fmt::Opaque; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
+                          debug x => _23;  // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                          debug f => _27;  // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                          let mut _30: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
+                          let mut _31: &core::fmt::Opaque; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
                       }
                   }
                   scope 10 {
-                      debug pieces => _15; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                      debug args => _16;   // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                      let mut _34: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
+                      debug pieces => _14; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                      debug args => _15;   // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                      let mut _32: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
                   }
               }
           }
@@ -103,16 +101,18 @@
           StorageDead(_6);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_7);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _7 = (_5.0: &i32);               // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _8 = (_5.1: &i32);               // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_9);                 // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_10);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_11);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _11 = (*_7);                     // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_12);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _12 = (*_8);                     // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _10 = Eq(move _11, move _12);    // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_12);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _10 = Eq(move _11, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
           StorageDead(_11);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _9 = Not(move _10);              // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_10);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -121,7 +121,6 @@
   
       bb1: {
           StorageDead(_9);                 // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_7);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_5);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _0 = const ();                   // scope 0 at $DIR/issue-73223.rs:1:11: 9:2
@@ -136,40 +135,38 @@
       }
   
       bb2: {
-          StorageLive(_14);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          _15 = const main::promoted[0] as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_13);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _14 = const main::promoted[0] as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: &[&str; 3]
                                            // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) }
+          StorageLive(_17);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
           StorageLive(_18);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          StorageLive(_19);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageLive(_19);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_20);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _20 = _7;                        // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _19 = &_20;                      // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_21);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _21 = _7;                        // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _20 = &_21;                      // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_22);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_23);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _23 = _8;                        // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _22 = &_23;                      // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          (_19.0: &&i32) = move _20;       // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          (_19.1: &&i32) = move _22;       // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          StorageDead(_22);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          StorageDead(_20);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          _24 = (_19.0: &&i32);            // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _25 = (_19.1: &&i32);            // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_26);                // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
-          _27 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _21 = &_8;                       // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          (_18.0: &&i32) = move _19;       // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          (_18.1: &&i32) = move _21;       // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_21);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_19);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _22 = (_18.0: &&i32);            // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _23 = (_18.1: &&i32);            // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_24);                // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _25 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}
                                            // + val: Value(Scalar(<ZST>))
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
-          StorageLive(_30);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _30 = const std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _27) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageLive(_28);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _28 = const std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _25) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}
                                            // + val: Value(Scalar(<ZST>))
@@ -179,8 +176,8 @@
       }
   
       bb3: {
-          StorageLive(_31);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _31 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _24) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageLive(_29);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _29 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _22) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}
                                            // + val: Value(Scalar(<ZST>))
@@ -190,20 +187,20 @@
       }
   
       bb4: {
-          (_26.0: &core::fmt::Opaque) = move _31; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          (_26.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _30; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          StorageDead(_31);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          StorageDead(_30);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          StorageLive(_28);                // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
-          _29 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          (_24.0: &core::fmt::Opaque) = move _29; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          (_24.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _28; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageDead(_29);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageDead(_28);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageLive(_26);                // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _27 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}
                                            // + val: Value(Scalar(<ZST>))
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
-          StorageLive(_32);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _32 = const std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _29) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageLive(_30);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _30 = const std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _27) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}
                                            // + val: Value(Scalar(<ZST>))
@@ -213,8 +210,8 @@
       }
   
       bb5: {
-          StorageLive(_33);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _33 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _25) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageLive(_31);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _31 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _23) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}
                                            // + val: Value(Scalar(<ZST>))
@@ -224,23 +221,23 @@
       }
   
       bb6: {
-          (_28.0: &core::fmt::Opaque) = move _33; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          (_28.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _32; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          StorageDead(_33);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          StorageDead(_32);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _18 = [move _26, move _28];      // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
-          StorageDead(_28);                // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
+          (_26.0: &core::fmt::Opaque) = move _31; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          (_26.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _30; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageDead(_31);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageDead(_30);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _17 = [move _24, move _26];      // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
           StorageDead(_26);                // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
-          _17 = &_18;                      // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          _16 = move _17 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          StorageLive(_34);                // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          discriminant(_34) = 0;           // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          (_14.0: &[&str]) = move _15;     // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          (_14.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _34; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          (_14.2: &[std::fmt::ArgumentV1]) = move _16; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          StorageDead(_34);                // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _13 = &_14;                      // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          const std::rt::begin_panic_fmt(move _13); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_24);                // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _16 = &_17;                      // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _15 = move _16 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageLive(_32);                // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          discriminant(_32) = 0;           // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          (_13.0: &[&str]) = move _14;     // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          (_13.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _32; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          (_13.2: &[std::fmt::ArgumentV1]) = move _15; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageDead(_32);                // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _12 = &_13;                      // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          const std::rt::begin_panic_fmt(move _12); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
                                            // ty::Const
                                            // + ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt}
                                            // + val: Value(Scalar(<ZST>))
diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.diff.64bit b/src/test/mir-opt/issue_73223.main.PreCodegen.diff.64bit
index 4c9da471f0b..919c37a5fc3 100644
--- a/src/test/mir-opt/issue_73223.main.PreCodegen.diff.64bit
+++ b/src/test/mir-opt/issue_73223.main.PreCodegen.diff.64bit
@@ -11,22 +11,20 @@
       let mut _9: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _10: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _11: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _12: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _13: &std::fmt::Arguments;       // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let _14: std::fmt::Arguments;        // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let mut _15: &[&str];                // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _16: &[std::fmt::ArgumentV1]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let _17: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let _18: [std::fmt::ArgumentV1; 2];  // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let mut _19: (&&i32, &&i32);         // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let mut _20: &&i32;                  // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _21: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _22: &&i32;                  // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _23: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let _12: &std::fmt::Arguments;       // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let _13: std::fmt::Arguments;        // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let mut _14: &[&str];                // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _15: &[std::fmt::ArgumentV1]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let _16: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let _17: [std::fmt::ArgumentV1; 2];  // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let mut _18: (&&i32, &&i32);         // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let mut _19: &&i32;                  // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let _20: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _21: &&i32;                  // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _24: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let mut _25: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _26: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
       let mut _27: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _28: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let mut _29: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       scope 1 {
           debug split => _2;               // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14
           let _3: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14
@@ -37,28 +35,28 @@
               scope 4 {
                   debug left_val => _7;    // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                   debug right_val => _8;   // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  let _24: &&i32;          // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  let _25: &&i32;          // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                  let _22: &&i32;          // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                  let _23: &&i32;          // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                   scope 5 {
-                      debug arg0 => _24;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                      debug arg1 => _25;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                      debug arg0 => _22;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                      debug arg1 => _23;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                       scope 6 {
-                          debug x => _24;  // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                          debug f => _27;  // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                          let mut _30: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
-                          let mut _31: &core::fmt::Opaque; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
+                          debug x => _22;  // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                          debug f => _25;  // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                          let mut _28: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
+                          let mut _29: &core::fmt::Opaque; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
                       }
                       scope 8 {
-                          debug x => _25;  // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                          debug f => _29;  // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                          let mut _32: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
-                          let mut _33: &core::fmt::Opaque; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
+                          debug x => _23;  // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                          debug f => _27;  // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                          let mut _30: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
+                          let mut _31: &core::fmt::Opaque; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
                       }
                   }
                   scope 10 {
-                      debug pieces => _15; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                      debug args => _16;   // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                      let mut _34: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
+                      debug pieces => _14; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                      debug args => _15;   // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                      let mut _32: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
                   }
               }
           }
@@ -103,16 +101,18 @@
           StorageDead(_6);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_7);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _7 = (_5.0: &i32);               // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _8 = (_5.1: &i32);               // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_9);                 // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_10);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_11);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _11 = (*_7);                     // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_12);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _12 = (*_8);                     // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _10 = Eq(move _11, move _12);    // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_12);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _10 = Eq(move _11, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
           StorageDead(_11);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _9 = Not(move _10);              // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_10);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -121,7 +121,6 @@
   
       bb1: {
           StorageDead(_9);                 // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_7);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_5);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _0 = const ();                   // scope 0 at $DIR/issue-73223.rs:1:11: 9:2
@@ -136,40 +135,38 @@
       }
   
       bb2: {
-          StorageLive(_14);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          _15 = const main::promoted[0] as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_13);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _14 = const main::promoted[0] as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: &[&str; 3]
                                            // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) }
+          StorageLive(_17);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
           StorageLive(_18);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          StorageLive(_19);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageLive(_19);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_20);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _20 = _7;                        // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _19 = &_20;                      // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_21);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _21 = _7;                        // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _20 = &_21;                      // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_22);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_23);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _23 = _8;                        // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _22 = &_23;                      // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          (_19.0: &&i32) = move _20;       // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          (_19.1: &&i32) = move _22;       // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          StorageDead(_22);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          StorageDead(_20);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          _24 = (_19.0: &&i32);            // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _25 = (_19.1: &&i32);            // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_26);                // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
-          _27 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _21 = &_8;                       // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          (_18.0: &&i32) = move _19;       // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          (_18.1: &&i32) = move _21;       // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_21);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_19);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _22 = (_18.0: &&i32);            // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _23 = (_18.1: &&i32);            // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_24);                // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _25 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}
                                            // + val: Value(Scalar(<ZST>))
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
-          StorageLive(_30);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _30 = const std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _27) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageLive(_28);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _28 = const std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _25) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}
                                            // + val: Value(Scalar(<ZST>))
@@ -179,8 +176,8 @@
       }
   
       bb3: {
-          StorageLive(_31);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _31 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _24) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageLive(_29);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _29 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _22) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}
                                            // + val: Value(Scalar(<ZST>))
@@ -190,20 +187,20 @@
       }
   
       bb4: {
-          (_26.0: &core::fmt::Opaque) = move _31; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          (_26.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _30; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          StorageDead(_31);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          StorageDead(_30);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          StorageLive(_28);                // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
-          _29 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          (_24.0: &core::fmt::Opaque) = move _29; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          (_24.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _28; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageDead(_29);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageDead(_28);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageLive(_26);                // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _27 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}
                                            // + val: Value(Scalar(<ZST>))
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
-          StorageLive(_32);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _32 = const std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _29) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageLive(_30);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _30 = const std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _27) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}
                                            // + val: Value(Scalar(<ZST>))
@@ -213,8 +210,8 @@
       }
   
       bb5: {
-          StorageLive(_33);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _33 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _25) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageLive(_31);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _31 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _23) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}
                                            // + val: Value(Scalar(<ZST>))
@@ -224,23 +221,23 @@
       }
   
       bb6: {
-          (_28.0: &core::fmt::Opaque) = move _33; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          (_28.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _32; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          StorageDead(_33);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          StorageDead(_32);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _18 = [move _26, move _28];      // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
-          StorageDead(_28);                // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
+          (_26.0: &core::fmt::Opaque) = move _31; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          (_26.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _30; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageDead(_31);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageDead(_30);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _17 = [move _24, move _26];      // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
           StorageDead(_26);                // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
-          _17 = &_18;                      // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          _16 = move _17 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          StorageLive(_34);                // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          discriminant(_34) = 0;           // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          (_14.0: &[&str]) = move _15;     // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          (_14.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _34; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          (_14.2: &[std::fmt::ArgumentV1]) = move _16; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          StorageDead(_34);                // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _13 = &_14;                      // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          const std::rt::begin_panic_fmt(move _13); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_24);                // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _16 = &_17;                      // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _15 = move _16 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageLive(_32);                // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          discriminant(_32) = 0;           // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          (_13.0: &[&str]) = move _14;     // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          (_13.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _32; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          (_13.2: &[std::fmt::ArgumentV1]) = move _15; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageDead(_32);                // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _12 = &_13;                      // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          const std::rt::begin_panic_fmt(move _12); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
                                            // ty::Const
                                            // + ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt}
                                            // + val: Value(Scalar(<ZST>))
diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.32bit b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.32bit
index dd0e8f4b2ad..28d949be271 100644
--- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.32bit
+++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.32bit
@@ -165,8 +165,20 @@
           StorageLive(_17);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _17 = (*_13);                    // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_18);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _18 = (*_14);                    // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _16 = Eq(move _17, move _18);    // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _18 = const 1_i32;               // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
+          _16 = Eq(move _17, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
           StorageDead(_18);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_17);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _15 = Not(move _16);             // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.64bit b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.64bit
index d465f60f34d..2b854850dea 100644
--- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.64bit
+++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.64bit
@@ -165,8 +165,20 @@
           StorageLive(_17);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _17 = (*_13);                    // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_18);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _18 = (*_14);                    // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _16 = Eq(move _17, move _18);    // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _18 = const 1_i32;               // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
+          _16 = Eq(move _17, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
           StorageDead(_18);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_17);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _15 = Not(move _16);             // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
diff --git a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.32bit b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.32bit
index 0de80f72a1e..b7b239ea414 100644
--- a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.32bit
+++ b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.32bit
@@ -39,13 +39,14 @@
       }
   
       bb1: {
-          _2 = const Dst::Foo(0_u8);       // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
+          ((_2 as Foo).0: u8) = const 0_u8; // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
                                            // ty::Const
-                                           // + ty: Dst
+                                           // + ty: u8
                                            // + val: Value(Scalar(0x00))
                                            // mir::Constant
-                                           // + span: $DIR/simplify-arm-identity.rs:21:21: 21:32
-                                           // + literal: Const { ty: Dst, val: Value(Scalar(0x00)) }
+                                           // + span: $DIR/simplify-arm-identity.rs:21:30: 21:31
+                                           // + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
+          discriminant(_2) = 0;            // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
           goto -> bb4;                     // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
       }
   
diff --git a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.64bit b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.64bit
index 4fa0aff8fa0..34282526da0 100644
--- a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.64bit
+++ b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.64bit
@@ -39,13 +39,14 @@
       }
   
       bb1: {
-          _2 = const Dst::Foo(0_u8);       // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
+          ((_2 as Foo).0: u8) = const 0_u8; // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
                                            // ty::Const
-                                           // + ty: Dst
+                                           // + ty: u8
                                            // + val: Value(Scalar(0x00))
                                            // mir::Constant
-                                           // + span: $DIR/simplify-arm-identity.rs:21:21: 21:32
-                                           // + literal: Const { ty: Dst, val: Value(Scalar(0x00)) }
+                                           // + span: $DIR/simplify-arm-identity.rs:21:30: 21:31
+                                           // + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
+          discriminant(_2) = 0;            // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
           goto -> bb4;                     // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
       }
   
diff --git a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff
index db06b0392df..8b5936116b3 100644
--- a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff
+++ b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff
@@ -22,58 +22,44 @@
       bb0: {
 -         StorageLive(_1);                 // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:20: 13:28
 -         StorageLive(_2);                 // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:21: 13:23
--         _2 = const ();                   // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:21: 13:23
+-         StorageLive(_3);                 // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:25: 13:27
+-         (_1.0: ()) = const ();           // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:20: 13:28
 +         StorageLive(_1);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22
 +         _1 = const use_zst(const ((), ())) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22
                                            // ty::Const
 -                                          // + ty: ()
 -                                          // + val: Value(Scalar(<ZST>))
 -                                          // mir::Constant
--                                          // + span: $DIR/simplify-locals-removes-unused-consts.rs:13:21: 13:23
+-                                          // + span: $DIR/simplify-locals-removes-unused-consts.rs:13:20: 13:28
 -                                          // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
--         StorageLive(_3);                 // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:25: 13:27
--         _3 = const ();                   // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:25: 13:27
+-         (_1.1: ()) = const ();           // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:20: 13:28
 -                                          // ty::Const
 -                                          // + ty: ()
 -                                          // + val: Value(Scalar(<ZST>))
 -                                          // mir::Constant
--                                          // + span: $DIR/simplify-locals-removes-unused-consts.rs:13:25: 13:27
--                                          // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
--         _1 = const ((), ());             // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:20: 13:28
--                                          // ty::Const
--                                          // + ty: ((), ())
--                                          // + val: Value(Scalar(<ZST>))
--                                          // mir::Constant
 -                                          // + span: $DIR/simplify-locals-removes-unused-consts.rs:13:20: 13:28
--                                          // + literal: Const { ty: ((), ()), val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
 -         StorageDead(_3);                 // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:27: 13:28
 -         StorageDead(_2);                 // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:27: 13:28
 -         StorageDead(_1);                 // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:28: 13:29
 -         StorageLive(_4);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22
 -         StorageLive(_5);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21
 -         StorageLive(_6);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:14: 14:16
--         _6 = const ();                   // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:14: 14:16
--                                          // ty::Const
--                                          // + ty: ()
--                                          // + val: Value(Scalar(<ZST>))
--                                          // mir::Constant
--                                          // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:14: 14:16
--                                          // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
 -         StorageLive(_7);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:18: 14:20
--         _7 = const ();                   // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:18: 14:20
+-         (_5.0: ()) = const ();           // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21
 -                                          // ty::Const
 -                                          // + ty: ()
 -                                          // + val: Value(Scalar(<ZST>))
 -                                          // mir::Constant
--                                          // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:18: 14:20
+-                                          // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21
 -                                          // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
--         _5 = const ((), ());             // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21
+-         (_5.1: ()) = const ();           // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21
 -                                          // ty::Const
--                                          // + ty: ((), ())
+-                                          // + ty: ()
 -                                          // + val: Value(Scalar(<ZST>))
 -                                          // mir::Constant
 -                                          // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21
--                                          // + literal: Const { ty: ((), ()), val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
 -         StorageDead(_7);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:20: 14:21
 -         StorageDead(_6);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:20: 14:21
 -         _4 = const use_zst(const ((), ())) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22
@@ -98,16 +84,16 @@
 -         StorageLive(_9);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:34
 -         StorageLive(_10);                // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:30
 -         StorageLive(_11);                // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28
--         _11 = const Temp { x: 40_u8 };   // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28
+-         (_11.0: u8) = const 40_u8;       // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28
 +         StorageDead(_1);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:22: 14:23
 +         StorageLive(_2);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35
 +         _2 = const use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35
                                            // ty::Const
--                                          // + ty: Temp
+-                                          // + ty: u8
 -                                          // + val: Value(Scalar(0x28))
 -                                          // mir::Constant
--                                          // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28
--                                          // + literal: Const { ty: Temp, val: Value(Scalar(0x28)) }
+-                                          // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:23: 16:25
+-                                          // + literal: Const { ty: u8, val: Value(Scalar(0x28)) }
 -         _10 = const 40_u8;               // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:30
 -                                          // ty::Const
 -                                          // + ty: u8
diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.32bit b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.32bit
index 440c5f8772e..0bd13e009dd 100644
--- a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.32bit
+++ b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.32bit
@@ -39,13 +39,7 @@
       }
   
       bb2: {
-          _0 = const std::option::Option::<std::boxed::Box<()>>::None; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:17: 3:21
-                                           // ty::Const
-                                           // + ty: std::option::Option<std::boxed::Box<()>>
-                                           // + val: Value(Scalar(0x00000000))
-                                           // mir::Constant
-                                           // + span: $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:17: 3:21
-                                           // + literal: Const { ty: std::option::Option<std::boxed::Box<()>>, val: Value(Scalar(0x00000000)) }
+          discriminant(_0) = 0;            // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:17: 3:21
           goto -> bb3;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:2:5: 5:6
       }
   
diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.64bit b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.64bit
index c12d1715b48..0bd13e009dd 100644
--- a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.64bit
+++ b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.64bit
@@ -39,13 +39,7 @@
       }
   
       bb2: {
-          _0 = const std::option::Option::<std::boxed::Box<()>>::None; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:17: 3:21
-                                           // ty::Const
-                                           // + ty: std::option::Option<std::boxed::Box<()>>
-                                           // + val: Value(Scalar(0x0000000000000000))
-                                           // mir::Constant
-                                           // + span: $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:17: 3:21
-                                           // + literal: Const { ty: std::option::Option<std::boxed::Box<()>>, val: Value(Scalar(0x0000000000000000)) }
+          discriminant(_0) = 0;            // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:17: 3:21
           goto -> bb3;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:2:5: 5:6
       }
   
diff --git a/src/test/mir-opt/uninhabited_enum_branching.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir b/src/test/mir-opt/uninhabited_enum_branching.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir
index 4f4fb7defc3..24fd26591bd 100644
--- a/src/test/mir-opt/uninhabited_enum_branching.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir
+++ b/src/test/mir-opt/uninhabited_enum_branching.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir
@@ -15,7 +15,7 @@ fn main() -> () {
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:20:5: 24:6
         StorageLive(_2);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19
-        _2 = Test1::C;                   // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19
+        discriminant(_2) = 2;            // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19
         _3 = discriminant(_2);           // scope 0 at $DIR/uninhabited_enum_branching.rs:21:9: 21:20
         StorageLive(_5);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:23:21: 23:24
         _5 = const "C";                  // scope 0 at $DIR/uninhabited_enum_branching.rs:23:21: 23:24
@@ -31,7 +31,7 @@ fn main() -> () {
         StorageDead(_1);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:24:6: 24:7
         StorageLive(_6);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:26:5: 29:6
         StorageLive(_7);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19
-        _7 = Test2::D;                   // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19
+        discriminant(_7) = 0;            // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19
         _8 = discriminant(_7);           // scope 0 at $DIR/uninhabited_enum_branching.rs:27:9: 27:17
         switchInt(move _8) -> [4_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/uninhabited_enum_branching.rs:27:9: 27:17
     }
diff --git a/src/test/mir-opt/uninhabited_enum_branching.main.UninhabitedEnumBranching.diff b/src/test/mir-opt/uninhabited_enum_branching.main.UninhabitedEnumBranching.diff
index d262c9432ca..7e0a95edf3e 100644
--- a/src/test/mir-opt/uninhabited_enum_branching.main.UninhabitedEnumBranching.diff
+++ b/src/test/mir-opt/uninhabited_enum_branching.main.UninhabitedEnumBranching.diff
@@ -16,7 +16,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:20:5: 24:6
           StorageLive(_2);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19
-          _2 = Test1::C;                   // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19
+          discriminant(_2) = 2;            // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19
           _3 = discriminant(_2);           // scope 0 at $DIR/uninhabited_enum_branching.rs:21:9: 21:20
 -         switchInt(move _3) -> [0_isize: bb2, 1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/uninhabited_enum_branching.rs:21:9: 21:20
 +         switchInt(move _3) -> bb1;       // scope 0 at $DIR/uninhabited_enum_branching.rs:21:9: 21:20
@@ -66,7 +66,7 @@
           StorageDead(_1);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:24:6: 24:7
           StorageLive(_6);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:26:5: 29:6
           StorageLive(_7);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19
-          _7 = Test2::D;                   // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19
+          discriminant(_7) = 0;            // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19
           _8 = discriminant(_7);           // scope 0 at $DIR/uninhabited_enum_branching.rs:27:9: 27:17
           switchInt(move _8) -> [4_isize: bb6, otherwise: bb5]; // scope 0 at $DIR/uninhabited_enum_branching.rs:27:9: 27:17
       }
diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.32bit b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.32bit
new file mode 100644
index 00000000000..ff98b0e3226
--- /dev/null
+++ b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.32bit
@@ -0,0 +1,84 @@
+- // MIR for `change_loop_body` before ConstProp
++ // MIR for `change_loop_body` after ConstProp
+  
+  fn change_loop_body() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/while_let_loops.rs:5:27: 5:27
+      let mut _1: i32;                     // in scope 0 at $DIR/while_let_loops.rs:6:9: 6:15
+      let mut _2: ();                      // in scope 0 at $DIR/while_let_loops.rs:5:1: 11:2
+      let mut _3: std::option::Option<u32>; // in scope 0 at $DIR/while_let_loops.rs:7:28: 7:32
+      let mut _4: isize;                   // in scope 0 at $DIR/while_let_loops.rs:7:15: 7:25
+      let mut _5: !;                       // in scope 0 at $DIR/while_let_loops.rs:7:33: 10:6
+      let mut _6: !;                       // in scope 0 at $DIR/while_let_loops.rs:7:5: 10:6
+      scope 1 {
+          debug _x => _1;                  // in scope 1 at $DIR/while_let_loops.rs:6:9: 6:15
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/while_let_loops.rs:6:9: 6:15
+          _1 = const 0_i32;                // scope 0 at $DIR/while_let_loops.rs:6:18: 6:19
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000000))
+                                           // mir::Constant
+                                           // + span: $DIR/while_let_loops.rs:6:18: 6:19
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
+          StorageLive(_3);                 // scope 1 at $DIR/while_let_loops.rs:7:28: 7:32
+          discriminant(_3) = 0;            // scope 1 at $DIR/while_let_loops.rs:7:28: 7:32
+-         _4 = discriminant(_3);           // scope 1 at $DIR/while_let_loops.rs:7:15: 7:25
+-         switchInt(move _4) -> [1_isize: bb2, otherwise: bb1]; // scope 1 at $DIR/while_let_loops.rs:7:15: 7:25
++         _4 = const 0_isize;              // scope 1 at $DIR/while_let_loops.rs:7:15: 7:25
++                                          // ty::Const
++                                          // + ty: isize
++                                          // + val: Value(Scalar(0x00000000))
++                                          // mir::Constant
++                                          // + span: $DIR/while_let_loops.rs:7:15: 7:25
++                                          // + literal: Const { ty: isize, val: Value(Scalar(0x00000000)) }
++         switchInt(const 0_isize) -> [1_isize: bb2, otherwise: bb1]; // scope 1 at $DIR/while_let_loops.rs:7:15: 7:25
++                                          // ty::Const
++                                          // + ty: isize
++                                          // + val: Value(Scalar(0x00000000))
++                                          // mir::Constant
++                                          // + span: $DIR/while_let_loops.rs:7:15: 7:25
++                                          // + literal: Const { ty: isize, val: Value(Scalar(0x00000000)) }
+      }
+  
+      bb1: {
+          _0 = const ();                   // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/while_let_loops.rs:7:5: 10:6
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          goto -> bb4;                     // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6
+      }
+  
+      bb2: {
+          switchInt(((_3 as Some).0: u32)) -> [0_u32: bb3, otherwise: bb1]; // scope 1 at $DIR/while_let_loops.rs:7:20: 7:24
+      }
+  
+      bb3: {
+          _1 = const 1_i32;                // scope 1 at $DIR/while_let_loops.rs:8:9: 8:15
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+                                           // + span: $DIR/while_let_loops.rs:8:14: 8:15
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
+          _0 = const ();                   // scope 1 at $DIR/while_let_loops.rs:9:9: 9:14
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/while_let_loops.rs:9:9: 9:14
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          goto -> bb4;                     // scope 1 at $DIR/while_let_loops.rs:9:9: 9:14
+      }
+  
+      bb4: {
+          StorageDead(_3);                 // scope 1 at $DIR/while_let_loops.rs:10:5: 10:6
+          StorageDead(_1);                 // scope 0 at $DIR/while_let_loops.rs:11:1: 11:2
+          return;                          // scope 0 at $DIR/while_let_loops.rs:11:2: 11:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.64bit b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.64bit
new file mode 100644
index 00000000000..612d44f413f
--- /dev/null
+++ b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.64bit
@@ -0,0 +1,84 @@
+- // MIR for `change_loop_body` before ConstProp
++ // MIR for `change_loop_body` after ConstProp
+  
+  fn change_loop_body() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/while_let_loops.rs:5:27: 5:27
+      let mut _1: i32;                     // in scope 0 at $DIR/while_let_loops.rs:6:9: 6:15
+      let mut _2: ();                      // in scope 0 at $DIR/while_let_loops.rs:5:1: 11:2
+      let mut _3: std::option::Option<u32>; // in scope 0 at $DIR/while_let_loops.rs:7:28: 7:32
+      let mut _4: isize;                   // in scope 0 at $DIR/while_let_loops.rs:7:15: 7:25
+      let mut _5: !;                       // in scope 0 at $DIR/while_let_loops.rs:7:33: 10:6
+      let mut _6: !;                       // in scope 0 at $DIR/while_let_loops.rs:7:5: 10:6
+      scope 1 {
+          debug _x => _1;                  // in scope 1 at $DIR/while_let_loops.rs:6:9: 6:15
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/while_let_loops.rs:6:9: 6:15
+          _1 = const 0_i32;                // scope 0 at $DIR/while_let_loops.rs:6:18: 6:19
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000000))
+                                           // mir::Constant
+                                           // + span: $DIR/while_let_loops.rs:6:18: 6:19
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
+          StorageLive(_3);                 // scope 1 at $DIR/while_let_loops.rs:7:28: 7:32
+          discriminant(_3) = 0;            // scope 1 at $DIR/while_let_loops.rs:7:28: 7:32
+-         _4 = discriminant(_3);           // scope 1 at $DIR/while_let_loops.rs:7:15: 7:25
+-         switchInt(move _4) -> [1_isize: bb2, otherwise: bb1]; // scope 1 at $DIR/while_let_loops.rs:7:15: 7:25
++         _4 = const 0_isize;              // scope 1 at $DIR/while_let_loops.rs:7:15: 7:25
++                                          // ty::Const
++                                          // + ty: isize
++                                          // + val: Value(Scalar(0x0000000000000000))
++                                          // mir::Constant
++                                          // + span: $DIR/while_let_loops.rs:7:15: 7:25
++                                          // + literal: Const { ty: isize, val: Value(Scalar(0x0000000000000000)) }
++         switchInt(const 0_isize) -> [1_isize: bb2, otherwise: bb1]; // scope 1 at $DIR/while_let_loops.rs:7:15: 7:25
++                                          // ty::Const
++                                          // + ty: isize
++                                          // + val: Value(Scalar(0x0000000000000000))
++                                          // mir::Constant
++                                          // + span: $DIR/while_let_loops.rs:7:15: 7:25
++                                          // + literal: Const { ty: isize, val: Value(Scalar(0x0000000000000000)) }
+      }
+  
+      bb1: {
+          _0 = const ();                   // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/while_let_loops.rs:7:5: 10:6
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          goto -> bb4;                     // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6
+      }
+  
+      bb2: {
+          switchInt(((_3 as Some).0: u32)) -> [0_u32: bb3, otherwise: bb1]; // scope 1 at $DIR/while_let_loops.rs:7:20: 7:24
+      }
+  
+      bb3: {
+          _1 = const 1_i32;                // scope 1 at $DIR/while_let_loops.rs:8:9: 8:15
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+                                           // + span: $DIR/while_let_loops.rs:8:14: 8:15
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
+          _0 = const ();                   // scope 1 at $DIR/while_let_loops.rs:9:9: 9:14
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/while_let_loops.rs:9:9: 9:14
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          goto -> bb4;                     // scope 1 at $DIR/while_let_loops.rs:9:9: 9:14
+      }
+  
+      bb4: {
+          StorageDead(_3);                 // scope 1 at $DIR/while_let_loops.rs:10:5: 10:6
+          StorageDead(_1);                 // scope 0 at $DIR/while_let_loops.rs:11:1: 11:2
+          return;                          // scope 0 at $DIR/while_let_loops.rs:11:2: 11:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.32bit b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.32bit
new file mode 100644
index 00000000000..f6fe1248919
--- /dev/null
+++ b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.32bit
@@ -0,0 +1,33 @@
+// MIR for `change_loop_body` after PreCodegen
+
+fn change_loop_body() -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/while_let_loops.rs:5:27: 5:27
+    let mut _1: i32;                     // in scope 0 at $DIR/while_let_loops.rs:6:9: 6:15
+    let mut _2: std::option::Option<u32>; // in scope 0 at $DIR/while_let_loops.rs:7:28: 7:32
+    scope 1 {
+        debug _x => _1;                  // in scope 1 at $DIR/while_let_loops.rs:6:9: 6:15
+    }
+
+    bb0: {
+        StorageLive(_1);                 // scope 0 at $DIR/while_let_loops.rs:6:9: 6:15
+        _1 = const 0_i32;                // scope 0 at $DIR/while_let_loops.rs:6:18: 6:19
+                                         // ty::Const
+                                         // + ty: i32
+                                         // + val: Value(Scalar(0x00000000))
+                                         // mir::Constant
+                                         // + span: $DIR/while_let_loops.rs:6:18: 6:19
+                                         // + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
+        StorageLive(_2);                 // scope 1 at $DIR/while_let_loops.rs:7:28: 7:32
+        discriminant(_2) = 0;            // scope 1 at $DIR/while_let_loops.rs:7:28: 7:32
+        _0 = const ();                   // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6
+                                         // ty::Const
+                                         // + ty: ()
+                                         // + val: Value(Scalar(<ZST>))
+                                         // mir::Constant
+                                         // + span: $DIR/while_let_loops.rs:7:5: 10:6
+                                         // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+        StorageDead(_2);                 // scope 1 at $DIR/while_let_loops.rs:10:5: 10:6
+        StorageDead(_1);                 // scope 0 at $DIR/while_let_loops.rs:11:1: 11:2
+        return;                          // scope 0 at $DIR/while_let_loops.rs:11:2: 11:2
+    }
+}
diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.64bit b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.64bit
new file mode 100644
index 00000000000..f6fe1248919
--- /dev/null
+++ b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.64bit
@@ -0,0 +1,33 @@
+// MIR for `change_loop_body` after PreCodegen
+
+fn change_loop_body() -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/while_let_loops.rs:5:27: 5:27
+    let mut _1: i32;                     // in scope 0 at $DIR/while_let_loops.rs:6:9: 6:15
+    let mut _2: std::option::Option<u32>; // in scope 0 at $DIR/while_let_loops.rs:7:28: 7:32
+    scope 1 {
+        debug _x => _1;                  // in scope 1 at $DIR/while_let_loops.rs:6:9: 6:15
+    }
+
+    bb0: {
+        StorageLive(_1);                 // scope 0 at $DIR/while_let_loops.rs:6:9: 6:15
+        _1 = const 0_i32;                // scope 0 at $DIR/while_let_loops.rs:6:18: 6:19
+                                         // ty::Const
+                                         // + ty: i32
+                                         // + val: Value(Scalar(0x00000000))
+                                         // mir::Constant
+                                         // + span: $DIR/while_let_loops.rs:6:18: 6:19
+                                         // + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
+        StorageLive(_2);                 // scope 1 at $DIR/while_let_loops.rs:7:28: 7:32
+        discriminant(_2) = 0;            // scope 1 at $DIR/while_let_loops.rs:7:28: 7:32
+        _0 = const ();                   // scope 1 at $DIR/while_let_loops.rs:7:5: 10:6
+                                         // ty::Const
+                                         // + ty: ()
+                                         // + val: Value(Scalar(<ZST>))
+                                         // mir::Constant
+                                         // + span: $DIR/while_let_loops.rs:7:5: 10:6
+                                         // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+        StorageDead(_2);                 // scope 1 at $DIR/while_let_loops.rs:10:5: 10:6
+        StorageDead(_1);                 // scope 0 at $DIR/while_let_loops.rs:11:1: 11:2
+        return;                          // scope 0 at $DIR/while_let_loops.rs:11:2: 11:2
+    }
+}
diff --git a/src/test/mir-opt/while_let_loops.rs b/src/test/mir-opt/while_let_loops.rs
new file mode 100644
index 00000000000..f320a218c85
--- /dev/null
+++ b/src/test/mir-opt/while_let_loops.rs
@@ -0,0 +1,15 @@
+// EMIT_MIR while_let_loops.change_loop_body.ConstProp.diff
+// EMIT_MIR while_let_loops.change_loop_body.PreCodegen.after.mir
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
+pub fn change_loop_body() {
+    let mut _x = 0;
+    while let Some(0u32) = None {
+        _x = 1;
+        break;
+    }
+}
+
+fn main() {
+    change_loop_body();
+}
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/async.rs b/src/test/rustdoc-ui/error-in-impl-trait/async.rs
index 112a2c494a5..cda53bff07a 100644
--- a/src/test/rustdoc-ui/error-in-impl-trait/async.rs
+++ b/src/test/rustdoc-ui/error-in-impl-trait/async.rs
@@ -1,10 +1,7 @@
 // edition:2018
+// check-pass
 
-/// This used to work with ResolveBodyWithLoop.
-/// However now that we ignore type checking instead of modifying the function body,
-/// the return type is seen as `impl Future<Output = u32>`, not a `u32`.
-/// So it no longer allows errors in the function body.
+/// Should compile fine
 pub async fn a() -> u32 {
     error::_in::async_fn()
-    //~^ ERROR failed to resolve
 }
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/async.stderr b/src/test/rustdoc-ui/error-in-impl-trait/async.stderr
deleted file mode 100644
index 086db1be722..00000000000
--- a/src/test/rustdoc-ui/error-in-impl-trait/async.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0433]: failed to resolve: could not resolve path `error::_in::async_fn`
-  --> $DIR/async.rs:8:5
-   |
-LL |     error::_in::async_fn()
-   |     ^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::async_fn`
-   |
-   = note: this error was originally ignored because you are running `rustdoc`
-   = note: try running again with `rustc` or `cargo check` and you may get a more detailed error
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/closure.rs
index df40c121d57..f1fd85bb23c 100644
--- a/src/test/rustdoc-ui/error-in-impl-trait/closure.rs
+++ b/src/test/rustdoc-ui/error-in-impl-trait/closure.rs
@@ -1,5 +1,5 @@
+// check-pass
 // manually desugared version of an `async fn` (but with a closure instead of a generator)
 pub fn a() -> impl Fn() -> u32 {
     || content::doesnt::matter()
-    //~^ ERROR failed to resolve
 }
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/closure.stderr b/src/test/rustdoc-ui/error-in-impl-trait/closure.stderr
deleted file mode 100644
index 4ee9c4d1f43..00000000000
--- a/src/test/rustdoc-ui/error-in-impl-trait/closure.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0433]: failed to resolve: could not resolve path `content::doesnt::matter`
-  --> $DIR/closure.rs:3:8
-   |
-LL |     || content::doesnt::matter()
-   |        ^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `content::doesnt::matter`
-   |
-   = note: this error was originally ignored because you are running `rustdoc`
-   = note: try running again with `rustc` or `cargo check` and you may get a more detailed error
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs
index 0ccf2e3866f..dcec379d47e 100644
--- a/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs
+++ b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs
@@ -1,7 +1,7 @@
+// check-pass
 trait ValidTrait {}
 
 /// This has docs
 pub fn f() -> impl ValidTrait {
     Vec::<DoesNotExist>::new()
-    //~^ ERROR failed to resolve
 }
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.stderr b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.stderr
deleted file mode 100644
index 72716c258dc..00000000000
--- a/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0433]: failed to resolve: could not resolve path `DoesNotExist`
-  --> $DIR/generic-argument.rs:5:11
-   |
-LL |     Vec::<DoesNotExist>::new()
-   |           ^^^^^^^^^^^^ could not resolve path `DoesNotExist`
-   |
-   = note: this error was originally ignored because you are running `rustdoc`
-   = note: try running again with `rustc` or `cargo check` and you may get a more detailed error
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs
index 399fb827517..b935b0832f0 100644
--- a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs
+++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs
@@ -1,6 +1,6 @@
+// check-pass
 pub trait ValidTrait {}
 /// This returns impl trait
 pub fn g() -> impl ValidTrait {
     (|| error::_in::impl_trait::alias::nested::closure())()
-    //~^ ERROR failed to resolve
 }
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr
deleted file mode 100644
index 55f9b609a11..00000000000
--- a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias::nested::closure`
-  --> $DIR/impl-keyword-closure.rs:4:9
-   |
-LL |     (|| error::_in::impl_trait::alias::nested::closure())()
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias::nested::closure`
-   |
-   = note: this error was originally ignored because you are running `rustdoc`
-   = note: try running again with `rustc` or `cargo check` and you may get a more detailed error
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs
index 24b5734dbd0..701126f87a1 100644
--- a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs
+++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs
@@ -1,6 +1,6 @@
+// check-pass
 pub trait ValidTrait {}
 /// This returns impl trait
 pub fn g() -> impl ValidTrait {
     error::_in::impl_trait()
-    //~^ ERROR failed to resolve
 }
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr
deleted file mode 100644
index 3257079f942..00000000000
--- a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait`
-  --> $DIR/impl-keyword.rs:4:5
-   |
-LL |     error::_in::impl_trait()
-   |     ^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait`
-   |
-   = note: this error was originally ignored because you are running `rustdoc`
-   = note: try running again with `rustc` or `cargo check` and you may get a more detailed error
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/realistic-async.rs b/src/test/rustdoc-ui/error-in-impl-trait/realistic-async.rs
new file mode 100644
index 00000000000..248575d3528
--- /dev/null
+++ b/src/test/rustdoc-ui/error-in-impl-trait/realistic-async.rs
@@ -0,0 +1,28 @@
+// edition:2018
+// check-pass
+
+mod windows {
+    pub trait WinFoo {
+        fn foo(&self) {}
+    }
+
+    impl WinFoo for () {}
+}
+
+#[cfg(any(windows, doc))]
+use windows::*;
+
+mod unix {
+    pub trait UnixFoo {
+        fn foo(&self) {}
+    }
+
+    impl UnixFoo for () {}
+}
+
+#[cfg(any(unix, doc))]
+use unix::*;
+
+async fn bar() {
+    ().foo()
+}
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs
index 1498fa4f890..31dd786cbbf 100644
--- a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs
+++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs
@@ -1,3 +1,4 @@
+// check-pass
 #![feature(type_alias_impl_trait)]
 
 pub trait ValidTrait {}
@@ -6,5 +7,4 @@ type ImplTrait = impl ValidTrait;
 /// This returns impl trait, but using a type alias
 pub fn h() -> ImplTrait {
     (|| error::_in::impl_trait::alias::nested::closure())()
-    //~^ ERROR failed to resolve
 }
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr
deleted file mode 100644
index 84b28139dbc..00000000000
--- a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias::nested::closure`
-  --> $DIR/trait-alias-closure.rs:8:9
-   |
-LL |     (|| error::_in::impl_trait::alias::nested::closure())()
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias::nested::closure`
-   |
-   = note: this error was originally ignored because you are running `rustdoc`
-   = note: try running again with `rustc` or `cargo check` and you may get a more detailed error
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs
index cf9bc48c7f8..c18a024af4b 100644
--- a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs
+++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs
@@ -1,3 +1,4 @@
+// check-pass
 #![feature(type_alias_impl_trait)]
 
 pub trait ValidTrait {}
@@ -6,5 +7,4 @@ type ImplTrait = impl ValidTrait;
 /// This returns impl trait, but using a type alias
 pub fn h() -> ImplTrait {
     error::_in::impl_trait::alias()
-    //~^ ERROR failed to resolve
 }
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr
deleted file mode 100644
index 9be6a3d8d6b..00000000000
--- a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias`
-  --> $DIR/trait-alias.rs:8:5
-   |
-LL |     error::_in::impl_trait::alias()
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias`
-   |
-   = note: this error was originally ignored because you are running `rustdoc`
-   = note: try running again with `rustc` or `cargo check` and you may get a more detailed error
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs
new file mode 100644
index 00000000000..acce0f77a25
--- /dev/null
+++ b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs
@@ -0,0 +1,15 @@
+// normalize-stderr-test: "`.*`" -> "`DEF_ID`"
+// normalize-stdout-test: "`.*`" -> "`DEF_ID`"
+// edition:2018
+
+pub async fn f() -> impl std::fmt::Debug {
+    #[derive(Debug)]
+    enum E {
+    //~^ ERROR recursive type `f::{{closure}}#0::E` has infinite size
+        This(E),
+        Unit,
+    }
+    E::Unit
+}
+
+fn main() {}
diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr
new file mode 100644
index 00000000000..991dc6eec1d
--- /dev/null
+++ b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr
@@ -0,0 +1,17 @@
+error[E0072]: recursive type `DEF_ID` has infinite size
+  --> $DIR/infinite-recursive-type-impl-trait-return.rs:7:5
+   |
+LL |     enum E {
+   |     ^^^^^^ recursive type has infinite size
+LL |
+LL |         This(E),
+   |              - recursive without indirection
+   |
+help: insert some indirection (e.g., a `DEF_ID` representable
+   |
+LL |         This(Box<E>),
+   |              ^^^^ ^
+
+error: aborting due to previous error
+
+For more information about this error, try `DEF_ID`.
diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.rs b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.rs
new file mode 100644
index 00000000000..b3a7ee56313
--- /dev/null
+++ b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.rs
@@ -0,0 +1,7 @@
+fn f() -> impl Sized {
+    enum E {
+    //~^ ERROR recursive type `f::E` has infinite size
+        V(E),
+    }
+    unimplemented!()
+}
diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.stderr b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.stderr
new file mode 100644
index 00000000000..ec1bb786fe5
--- /dev/null
+++ b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.stderr
@@ -0,0 +1,17 @@
+error[E0072]: recursive type `f::E` has infinite size
+  --> $DIR/infinite-recursive-type-impl-trait.rs:2:5
+   |
+LL |     enum E {
+   |     ^^^^^^ recursive type has infinite size
+LL |
+LL |         V(E),
+   |           - recursive without indirection
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `f::E` representable
+   |
+LL |         V(Box<E>),
+   |           ^^^^ ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0072`.
diff --git a/src/test/rustdoc/synthetic_auto/issue-72213-projection-lifetime.rs b/src/test/rustdoc/synthetic_auto/issue-72213-projection-lifetime.rs
new file mode 100644
index 00000000000..6f66b8e5563
--- /dev/null
+++ b/src/test/rustdoc/synthetic_auto/issue-72213-projection-lifetime.rs
@@ -0,0 +1,25 @@
+// Regression test for issue #72213
+// Tests that we don't ICE when we have projection predicates
+// in our initial ParamEnv
+
+pub struct Lines<'a, L>
+where
+    L: Iterator<Item = &'a ()>,
+{
+    words: std::iter::Peekable<Words<'a, L>>,
+}
+
+pub struct Words<'a, L> {
+    _m: std::marker::PhantomData<&'a L>,
+}
+
+impl<'a, L> Iterator for Words<'a, L>
+where
+    L: Iterator<Item = &'a ()>,
+{
+    type Item = ();
+
+    fn next(&mut self) -> Option<Self::Item> {
+        unimplemented!()
+    }
+}
diff --git a/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr b/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr
index 00f44129cc8..6c68cc7bc61 100644
--- a/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr
+++ b/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr
@@ -5,6 +5,11 @@ LL | fn elision<T: Fn() -> &i32>() {
    |                       ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
+   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL | fn elision<T: for<'a> Fn() -> &'a i32>() {
+   |               ^^^^^^^         ^^^
 help: consider using the `'static` lifetime
    |
 LL | fn elision<T: Fn() -> &'static i32>() {
diff --git a/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr b/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr
index a5242707c71..93d2f8e7911 100644
--- a/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr
+++ b/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr
@@ -5,6 +5,11 @@ LL | fn elision(_: fn() -> &i32) {
    |                       ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
+   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the type lifetime-generic with a new `'a` lifetime
+   |
+LL | fn elision(_: for<'a> fn() -> &'a i32) {
+   |               ^^^^^^^         ^^^
 help: consider using the `'static` lifetime
    |
 LL | fn elision(_: fn() -> &'static i32) {
diff --git a/src/test/ui/const-generics/struct-with-invalid-const-param.stderr b/src/test/ui/const-generics/struct-with-invalid-const-param.stderr
index a968b26bc26..47617c7849f 100644
--- a/src/test/ui/const-generics/struct-with-invalid-const-param.stderr
+++ b/src/test/ui/const-generics/struct-with-invalid-const-param.stderr
@@ -2,10 +2,7 @@ error[E0573]: expected type, found const parameter `C`
   --> $DIR/struct-with-invalid-const-param.rs:4:23
    |
 LL | struct S<const C: u8>(C);
-   | ----------------------^--
-   | |                     |
-   | |                     help: a struct with a similar name exists: `S`
-   | similarly named struct `S` defined here
+   |                       ^ not a type
 
 warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/struct-with-invalid-const-param.rs:1:12
diff --git a/src/test/ui/const-generics/unused_braces.fixed b/src/test/ui/const-generics/unused_braces.fixed
index 5c2b9267af5..836f26efc96 100644
--- a/src/test/ui/const-generics/unused_braces.fixed
+++ b/src/test/ui/const-generics/unused_braces.fixed
@@ -10,6 +10,6 @@ struct A<const N: usize>;
 
 fn main() {
     let _: A<7>; // ok
-    let _: A< 7 >; //~ WARN unnecessary braces
+    let _: A<7>; //~ WARN unnecessary braces
     let _: A<{ 3 + 5 }>; // ok
 }
diff --git a/src/test/ui/consts/const-err-multi.stderr b/src/test/ui/consts/const-err-multi.stderr
index 4ac4a8754d3..a0c91ff6b54 100644
--- a/src/test/ui/consts/const-err-multi.stderr
+++ b/src/test/ui/consts/const-err-multi.stderr
@@ -24,17 +24,17 @@ error: any use of this value will cause an error
   --> $DIR/const-err-multi.rs:7:19
    |
 LL | pub const C: u8 = A as u8;
-   | ------------------^^^^^^^-
+   | ------------------^-------
    |                   |
    |                   referenced constant has errors
 
 error: any use of this value will cause an error
-  --> $DIR/const-err-multi.rs:9:19
+  --> $DIR/const-err-multi.rs:9:24
    |
 LL | pub const D: i8 = 50 - A;
-   | ------------------^^^^^^-
-   |                   |
-   |                   referenced constant has errors
+   | -----------------------^-
+   |                        |
+   |                        referenced constant has errors
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/consts/const-eval/erroneous-const.rs b/src/test/ui/consts/const-eval/erroneous-const.rs
new file mode 100644
index 00000000000..3df491bf229
--- /dev/null
+++ b/src/test/ui/consts/const-eval/erroneous-const.rs
@@ -0,0 +1,20 @@
+//! Make sure we error on erroneous consts even if they are unused.
+#![warn(const_err, unconditional_panic)]
+
+struct PrintName<T>(T);
+impl<T> PrintName<T> {
+    const VOID: () = [()][2]; //~WARN any use of this value will cause an error
+    //~^ WARN this operation will panic at runtime
+}
+
+const fn no_codegen<T>() {
+    if false {
+        let _ = PrintName::<T>::VOID; //~ERROR evaluation of constant value failed
+    }
+}
+
+pub static FOO: () = no_codegen::<i32>(); //~ERROR could not evaluate static initializer
+
+fn main() {
+    FOO
+}
diff --git a/src/test/ui/consts/const-eval/erroneous-const.stderr b/src/test/ui/consts/const-eval/erroneous-const.stderr
new file mode 100644
index 00000000000..f06e2c33fd0
--- /dev/null
+++ b/src/test/ui/consts/const-eval/erroneous-const.stderr
@@ -0,0 +1,41 @@
+warning: this operation will panic at runtime
+  --> $DIR/erroneous-const.rs:6:22
+   |
+LL |     const VOID: () = [()][2];
+   |                      ^^^^^^^ index out of bounds: the len is 1 but the index is 2
+   |
+note: the lint level is defined here
+  --> $DIR/erroneous-const.rs:2:20
+   |
+LL | #![warn(const_err, unconditional_panic)]
+   |                    ^^^^^^^^^^^^^^^^^^^
+
+warning: any use of this value will cause an error
+  --> $DIR/erroneous-const.rs:6:22
+   |
+LL |     const VOID: () = [()][2];
+   |     -----------------^^^^^^^-
+   |                      |
+   |                      index out of bounds: the len is 1 but the index is 2
+   |
+note: the lint level is defined here
+  --> $DIR/erroneous-const.rs:2:9
+   |
+LL | #![warn(const_err, unconditional_panic)]
+   |         ^^^^^^^^^
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/erroneous-const.rs:12:17
+   |
+LL |         let _ = PrintName::<T>::VOID;
+   |                 ^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+
+error[E0080]: could not evaluate static initializer
+  --> $DIR/erroneous-const.rs:16:22
+   |
+LL | pub static FOO: () = no_codegen::<i32>();
+   |                      ^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+
+error: aborting due to 2 previous errors; 2 warnings emitted
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/uninhabited-const-issue-61744.rs b/src/test/ui/consts/uninhabited-const-issue-61744.rs
index 55f42d84f9c..15436f9c1b2 100644
--- a/src/test/ui/consts/uninhabited-const-issue-61744.rs
+++ b/src/test/ui/consts/uninhabited-const-issue-61744.rs
@@ -1,11 +1,11 @@
 // build-fail
 
 pub const unsafe fn fake_type<T>() -> T {
-    hint_unreachable() //~ ERROR evaluation of constant value failed
+    hint_unreachable()
 }
 
 pub const unsafe fn hint_unreachable() -> ! {
-    fake_type()
+    fake_type() //~ ERROR evaluation of constant value failed
 }
 
 trait Const {
diff --git a/src/test/ui/consts/uninhabited-const-issue-61744.stderr b/src/test/ui/consts/uninhabited-const-issue-61744.stderr
index fc908b2b222..024f9782d4a 100644
--- a/src/test/ui/consts/uninhabited-const-issue-61744.stderr
+++ b/src/test/ui/consts/uninhabited-const-issue-61744.stderr
@@ -1,11 +1,9 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
    |
 LL |     hint_unreachable()
-   |     ^^^^^^^^^^^^^^^^^^
+   |     ------------------
    |     |
-   |     reached the configured maximum number of stack frames
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
    |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
    |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
    |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
@@ -72,8 +70,9 @@ LL |     hint_unreachable()
    |     inside `fake_type::<i32>` at $DIR/uninhabited-const-issue-61744.rs:4:5
 ...
 LL |     fake_type()
-   |     -----------
+   |     ^^^^^^^^^^^
    |     |
+   |     reached the configured maximum number of stack frames
    |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
    |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
    |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
diff --git a/src/test/ui/empty/empty-struct-braces-expr.stderr b/src/test/ui/empty/empty-struct-braces-expr.stderr
index c0ba9716fb0..6292ed44697 100644
--- a/src/test/ui/empty/empty-struct-braces-expr.stderr
+++ b/src/test/ui/empty/empty-struct-braces-expr.stderr
@@ -12,14 +12,14 @@ LL |     let e1 = Empty1;
 LL | pub struct XEmpty2;
    | ------------------- similarly named unit struct `XEmpty2` defined here
    |
-help: a unit struct with a similar name exists
-   |
-LL |     let e1 = XEmpty2;
-   |              ^^^^^^^
 help: use struct literal syntax instead
    |
 LL |     let e1 = Empty1 {};
    |              ^^^^^^^^^
+help: a unit struct with a similar name exists
+   |
+LL |     let e1 = XEmpty2;
+   |              ^^^^^^^
 
 error[E0423]: expected function, tuple struct or tuple variant, found struct `Empty1`
   --> $DIR/empty-struct-braces-expr.rs:16:14
@@ -29,15 +29,20 @@ LL | struct Empty1 {}
 ...
 LL |     let e1 = Empty1();
    |              ^^^^^^^^
+   | 
+  ::: $DIR/auxiliary/empty-struct.rs:2:1
    |
-help: a unit struct with a similar name exists
+LL | pub struct XEmpty2;
+   | ------------------- similarly named unit struct `XEmpty2` defined here
    |
-LL |     let e1 = XEmpty2();
-   |              ^^^^^^^
 help: use struct literal syntax instead
    |
 LL |     let e1 = Empty1 {};
    |              ^^^^^^^^^
+help: a unit struct with a similar name exists
+   |
+LL |     let e1 = XEmpty2();
+   |              ^^^^^^^
 
 error[E0423]: expected value, found struct variant `E::Empty3`
   --> $DIR/empty-struct-braces-expr.rs:18:14
@@ -63,34 +68,43 @@ error[E0423]: expected value, found struct `XEmpty1`
 LL |     let xe1 = XEmpty1;
    |               ^^^^^^^
    | 
-  ::: $DIR/auxiliary/empty-struct.rs:2:1
+  ::: $DIR/auxiliary/empty-struct.rs:1:1
    |
+LL | pub struct XEmpty1 {}
+   | ------------------ `XEmpty1` defined here
 LL | pub struct XEmpty2;
    | ------------------- similarly named unit struct `XEmpty2` defined here
    |
-help: a unit struct with a similar name exists
-   |
-LL |     let xe1 = XEmpty2;
-   |               ^^^^^^^
 help: use struct literal syntax instead
    |
 LL |     let xe1 = XEmpty1 {};
    |               ^^^^^^^^^^
+help: a unit struct with a similar name exists
+   |
+LL |     let xe1 = XEmpty2;
+   |               ^^^^^^^
 
 error[E0423]: expected function, tuple struct or tuple variant, found struct `XEmpty1`
   --> $DIR/empty-struct-braces-expr.rs:23:15
    |
 LL |     let xe1 = XEmpty1();
    |               ^^^^^^^^^
+   | 
+  ::: $DIR/auxiliary/empty-struct.rs:1:1
    |
-help: a unit struct with a similar name exists
+LL | pub struct XEmpty1 {}
+   | ------------------ `XEmpty1` defined here
+LL | pub struct XEmpty2;
+   | ------------------- similarly named unit struct `XEmpty2` defined here
    |
-LL |     let xe1 = XEmpty2();
-   |               ^^^^^^^
 help: use struct literal syntax instead
    |
 LL |     let xe1 = XEmpty1 {};
    |               ^^^^^^^^^^
+help: a unit struct with a similar name exists
+   |
+LL |     let xe1 = XEmpty2();
+   |               ^^^^^^^
 
 error[E0599]: no variant or associated item named `Empty3` found for enum `empty_struct::XE` in the current scope
   --> $DIR/empty-struct-braces-expr.rs:25:19
diff --git a/src/test/ui/empty/empty-struct-braces-pat-1.stderr b/src/test/ui/empty/empty-struct-braces-pat-1.stderr
index b027c82f7dd..3570012fc37 100644
--- a/src/test/ui/empty/empty-struct-braces-pat-1.stderr
+++ b/src/test/ui/empty/empty-struct-braces-pat-1.stderr
@@ -13,19 +13,21 @@ error[E0532]: expected unit struct, unit variant or constant, found struct varia
 LL |         XE::XEmpty3 => ()
    |         ^^^^^^^^^^^
    | 
-  ::: $DIR/auxiliary/empty-struct.rs:7:5
+  ::: $DIR/auxiliary/empty-struct.rs:6:5
    |
+LL |     XEmpty3 {},
+   |     ------- `XE::XEmpty3` defined here
 LL |     XEmpty4,
    |     ------- similarly named unit variant `XEmpty4` defined here
    |
-help: a unit variant with a similar name exists
-   |
-LL |         XE::XEmpty4 => ()
-   |             ^^^^^^^
 help: use struct pattern syntax instead
    |
 LL |         XE::XEmpty3 { /* fields */ } => ()
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: a unit variant with a similar name exists
+   |
+LL |         XE::XEmpty4 => ()
+   |             ^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/empty/empty-struct-braces-pat-2.stderr b/src/test/ui/empty/empty-struct-braces-pat-2.stderr
index a53b88db7d1..3bd3f6a9644 100644
--- a/src/test/ui/empty/empty-struct-braces-pat-2.stderr
+++ b/src/test/ui/empty/empty-struct-braces-pat-2.stderr
@@ -6,30 +6,43 @@ LL | struct Empty1 {}
 ...
 LL |         Empty1() => ()
    |         ^^^^^^^^
+   | 
+  ::: $DIR/auxiliary/empty-struct.rs:3:1
    |
-help: a tuple struct with a similar name exists
+LL | pub struct XEmpty6();
+   | --------------------- similarly named tuple struct `XEmpty6` defined here
    |
-LL |         XEmpty6() => ()
-   |         ^^^^^^^
 help: use struct pattern syntax instead
    |
 LL |         Empty1 {} => ()
    |         ^^^^^^^^^
+help: a tuple struct with a similar name exists
+   |
+LL |         XEmpty6() => ()
+   |         ^^^^^^^
 
 error[E0532]: expected tuple struct or tuple variant, found struct `XEmpty1`
   --> $DIR/empty-struct-braces-pat-2.rs:18:9
    |
 LL |         XEmpty1() => ()
    |         ^^^^^^^^^
+   | 
+  ::: $DIR/auxiliary/empty-struct.rs:1:1
    |
-help: a tuple struct with a similar name exists
+LL | pub struct XEmpty1 {}
+   | ------------------ `XEmpty1` defined here
+LL | pub struct XEmpty2;
+LL | pub struct XEmpty6();
+   | --------------------- similarly named tuple struct `XEmpty6` defined here
    |
-LL |         XEmpty6() => ()
-   |         ^^^^^^^
 help: use struct pattern syntax instead
    |
 LL |         XEmpty1 {} => ()
    |         ^^^^^^^^^^
+help: a tuple struct with a similar name exists
+   |
+LL |         XEmpty6() => ()
+   |         ^^^^^^^
 
 error[E0532]: expected tuple struct or tuple variant, found struct `Empty1`
   --> $DIR/empty-struct-braces-pat-2.rs:21:9
@@ -39,30 +52,43 @@ LL | struct Empty1 {}
 ...
 LL |         Empty1(..) => ()
    |         ^^^^^^^^^^
+   | 
+  ::: $DIR/auxiliary/empty-struct.rs:3:1
    |
-help: a tuple struct with a similar name exists
+LL | pub struct XEmpty6();
+   | --------------------- similarly named tuple struct `XEmpty6` defined here
    |
-LL |         XEmpty6(..) => ()
-   |         ^^^^^^^
 help: use struct pattern syntax instead
    |
 LL |         Empty1 {} => ()
    |         ^^^^^^^^^
+help: a tuple struct with a similar name exists
+   |
+LL |         XEmpty6(..) => ()
+   |         ^^^^^^^
 
 error[E0532]: expected tuple struct or tuple variant, found struct `XEmpty1`
   --> $DIR/empty-struct-braces-pat-2.rs:24:9
    |
 LL |         XEmpty1(..) => ()
    |         ^^^^^^^^^^^
+   | 
+  ::: $DIR/auxiliary/empty-struct.rs:1:1
    |
-help: a tuple struct with a similar name exists
+LL | pub struct XEmpty1 {}
+   | ------------------ `XEmpty1` defined here
+LL | pub struct XEmpty2;
+LL | pub struct XEmpty6();
+   | --------------------- similarly named tuple struct `XEmpty6` defined here
    |
-LL |         XEmpty6(..) => ()
-   |         ^^^^^^^
 help: use struct pattern syntax instead
    |
 LL |         XEmpty1 {} => ()
    |         ^^^^^^^^^^
+help: a tuple struct with a similar name exists
+   |
+LL |         XEmpty6(..) => ()
+   |         ^^^^^^^
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/empty/empty-struct-braces-pat-3.stderr b/src/test/ui/empty/empty-struct-braces-pat-3.stderr
index 93ace3eccef..aac872ba0ec 100644
--- a/src/test/ui/empty/empty-struct-braces-pat-3.stderr
+++ b/src/test/ui/empty/empty-struct-braces-pat-3.stderr
@@ -12,15 +12,23 @@ error[E0532]: expected tuple struct or tuple variant, found struct variant `XE::
    |
 LL |         XE::XEmpty3() => ()
    |         ^^^^^^^^^^^^^
+   | 
+  ::: $DIR/auxiliary/empty-struct.rs:6:5
    |
-help: a tuple variant with a similar name exists
+LL |     XEmpty3 {},
+   |     ------- `XE::XEmpty3` defined here
+LL |     XEmpty4,
+LL |     XEmpty5(),
+   |     --------- similarly named tuple variant `XEmpty5` defined here
    |
-LL |         XE::XEmpty5() => ()
-   |             ^^^^^^^
 help: use struct pattern syntax instead
    |
 LL |         XE::XEmpty3 { /* fields */ } => ()
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: a tuple variant with a similar name exists
+   |
+LL |         XE::XEmpty5() => ()
+   |             ^^^^^^^
 
 error[E0532]: expected tuple struct or tuple variant, found struct variant `E::Empty3`
   --> $DIR/empty-struct-braces-pat-3.rs:25:9
@@ -36,15 +44,23 @@ error[E0532]: expected tuple struct or tuple variant, found struct variant `XE::
    |
 LL |         XE::XEmpty3(..) => ()
    |         ^^^^^^^^^^^^^^^
+   | 
+  ::: $DIR/auxiliary/empty-struct.rs:6:5
    |
-help: a tuple variant with a similar name exists
+LL |     XEmpty3 {},
+   |     ------- `XE::XEmpty3` defined here
+LL |     XEmpty4,
+LL |     XEmpty5(),
+   |     --------- similarly named tuple variant `XEmpty5` defined here
    |
-LL |         XE::XEmpty5(..) => ()
-   |             ^^^^^^^
 help: use struct pattern syntax instead
    |
 LL |         XE::XEmpty3 { /* fields */ } => ()
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: a tuple variant with a similar name exists
+   |
+LL |         XE::XEmpty5(..) => ()
+   |             ^^^^^^^
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/empty/empty-struct-tuple-pat.stderr b/src/test/ui/empty/empty-struct-tuple-pat.stderr
index 9388ed26657..7b0d9717e63 100644
--- a/src/test/ui/empty/empty-struct-tuple-pat.stderr
+++ b/src/test/ui/empty/empty-struct-tuple-pat.stderr
@@ -23,21 +23,29 @@ LL |     Empty4()
    |     -------- `E::Empty4` defined here
 ...
 LL |         E::Empty4 => ()
-   |         ^^^^^^^^^ did you mean `E::Empty4( /* fields */ )`?
+   |         ^^^^^^^^^ help: use the tuple variant pattern syntax instead: `E::Empty4()`
 
 error[E0532]: expected unit struct, unit variant or constant, found tuple variant `XE::XEmpty5`
   --> $DIR/empty-struct-tuple-pat.rs:33:9
    |
 LL |         XE::XEmpty5 => (),
-   |         ^^^^-------
-   |         |   |
-   |         |   help: a unit variant with a similar name exists: `XEmpty4`
-   |         did you mean `XE::XEmpty5( /* fields */ )`?
+   |         ^^^^^^^^^^^
    | 
   ::: $DIR/auxiliary/empty-struct.rs:7:5
    |
 LL |     XEmpty4,
    |     ------- similarly named unit variant `XEmpty4` defined here
+LL |     XEmpty5(),
+   |     --------- `XE::XEmpty5` defined here
+   |
+help: use the tuple variant pattern syntax instead
+   |
+LL |         XE::XEmpty5(/* fields */) => (),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: a unit variant with a similar name exists
+   |
+LL |         XE::XEmpty4 => (),
+   |             ^^^^^^^
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/error-codes/E0106.stderr b/src/test/ui/error-codes/E0106.stderr
index a23bcbfd71a..ac70e887626 100644
--- a/src/test/ui/error-codes/E0106.stderr
+++ b/src/test/ui/error-codes/E0106.stderr
@@ -51,6 +51,15 @@ error[E0106]: missing lifetime specifiers
    |
 LL |     buzz: Buzz,
    |           ^^^^ expected 2 lifetime parameters
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | struct Quux<'a> {
+LL |     baz: Baz,
+LL |
+LL |
+LL |     buzz: Buzz<'a, 'a>,
+   |
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/error-codes/E0423.stderr b/src/test/ui/error-codes/E0423.stderr
index 077367de9d8..a9aecb520b2 100644
--- a/src/test/ui/error-codes/E0423.stderr
+++ b/src/test/ui/error-codes/E0423.stderr
@@ -34,21 +34,24 @@ LL |     struct Foo { a: bool };
 LL | 
 LL |     let f = Foo();
    |             ^^^^^
+...
+LL | fn foo() {
+   | -------- similarly named function `foo` defined here
    |
-help: a function with a similar name exists
-   |
-LL |     let f = foo();
-   |             ^^^
 help: use struct literal syntax instead
    |
 LL |     let f = Foo { a: val };
    |             ^^^^^^^^^^^^^^
+help: a function with a similar name exists
+   |
+LL |     let f = foo();
+   |             ^^^
 
 error[E0423]: expected value, found struct `T`
   --> $DIR/E0423.rs:14:8
    |
 LL |     if T {} == T {} { println!("Ok"); }
-   |        ^
+   |        ^ not a value
    |
 help: surround the struct literal with parentheses
    |
diff --git a/src/test/ui/hygiene/rustc-macro-transparency.stderr b/src/test/ui/hygiene/rustc-macro-transparency.stderr
index 024ce820760..94256b2eb79 100644
--- a/src/test/ui/hygiene/rustc-macro-transparency.stderr
+++ b/src/test/ui/hygiene/rustc-macro-transparency.stderr
@@ -8,7 +8,7 @@ error[E0423]: expected value, found macro `semitransparent`
   --> $DIR/rustc-macro-transparency.rs:29:5
    |
 LL |     semitransparent;
-   |     ^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^ not a value
    |
 help: use `!` to invoke the macro
    |
@@ -19,7 +19,7 @@ error[E0423]: expected value, found macro `opaque`
   --> $DIR/rustc-macro-transparency.rs:30:5
    |
 LL |     opaque;
-   |     ^^^^^^
+   |     ^^^^^^ not a value
    |
 help: use `!` to invoke the macro
    |
diff --git a/src/test/ui/issues/issue-17800.rs b/src/test/ui/issues/issue-17800.rs
index 45879d68b35..5254f45d7c2 100644
--- a/src/test/ui/issues/issue-17800.rs
+++ b/src/test/ui/issues/issue-17800.rs
@@ -6,7 +6,7 @@ enum MyOption<T> {
 fn main() {
     match MyOption::MySome(42) {
         MyOption::MySome { x: 42 } => (),
-        //~^ ERROR variant `MyOption::MySome` does not have a field named `x`
+        //~^ ERROR tuple variant `MyOption::MySome` written as struct variant
         _ => (),
     }
 }
diff --git a/src/test/ui/issues/issue-17800.stderr b/src/test/ui/issues/issue-17800.stderr
index 6efc7f0c06e..fc034a0cbf3 100644
--- a/src/test/ui/issues/issue-17800.stderr
+++ b/src/test/ui/issues/issue-17800.stderr
@@ -1,12 +1,9 @@
-error[E0026]: variant `MyOption::MySome` does not have a field named `x`
-  --> $DIR/issue-17800.rs:8:28
+error[E0769]: tuple variant `MyOption::MySome` written as struct variant
+  --> $DIR/issue-17800.rs:8:9
    |
 LL |         MyOption::MySome { x: 42 } => (),
-   |                            ^
-   |                            |
-   |                            variant `MyOption::MySome` does not have this field
-   |                            help: a field with a similar name exists: `0`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `MyOption::MySome(42)`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0026`.
+For more information about this error, try `rustc --explain E0769`.
diff --git a/src/test/ui/issues/issue-31845.stderr b/src/test/ui/issues/issue-31845.stderr
index fe51fa0699f..56281938559 100644
--- a/src/test/ui/issues/issue-31845.stderr
+++ b/src/test/ui/issues/issue-31845.stderr
@@ -1,10 +1,8 @@
 error[E0425]: cannot find function `g` in this scope
   --> $DIR/issue-31845.rs:7:12
    |
-LL |         fn h() {
-   |         ------ similarly named function `h` defined here
 LL |            g();
-   |            ^ help: a function with a similar name exists: `h`
+   |            ^ not found in this scope
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-32004.stderr b/src/test/ui/issues/issue-32004.stderr
index ab723e26680..f95afb9c1fd 100644
--- a/src/test/ui/issues/issue-32004.stderr
+++ b/src/test/ui/issues/issue-32004.stderr
@@ -7,10 +7,16 @@ LL |     Baz
    |     --- similarly named unit variant `Baz` defined here
 ...
 LL |         Foo::Bar => {}
-   |         ^^^^^---
-   |         |    |
-   |         |    help: a unit variant with a similar name exists: `Baz`
-   |         did you mean `Foo::Bar( /* fields */ )`?
+   |         ^^^^^^^^
+   |
+help: use the tuple variant pattern syntax instead
+   |
+LL |         Foo::Bar(_) => {}
+   |         ^^^^^^^^^^^
+help: a unit variant with a similar name exists
+   |
+LL |         Foo::Baz => {}
+   |              ^^^
 
 error[E0532]: expected tuple struct or tuple variant, found unit struct `S`
   --> $DIR/issue-32004.rs:16:9
diff --git a/src/test/ui/issues/issue-63983.stderr b/src/test/ui/issues/issue-63983.stderr
index 771a5c285af..eb042834102 100644
--- a/src/test/ui/issues/issue-63983.stderr
+++ b/src/test/ui/issues/issue-63983.stderr
@@ -5,7 +5,7 @@ LL |     Tuple(i32),
    |     ---------- `MyEnum::Tuple` defined here
 ...
 LL |         MyEnum::Tuple => "",
-   |         ^^^^^^^^^^^^^ did you mean `MyEnum::Tuple( /* fields */ )`?
+   |         ^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `MyEnum::Tuple(_)`
 
 error[E0532]: expected unit struct, unit variant or constant, found struct variant `MyEnum::Struct`
   --> $DIR/issue-63983.rs:10:9
diff --git a/src/test/ui/issues/issue-64792-bad-unicode-ctor.stderr b/src/test/ui/issues/issue-64792-bad-unicode-ctor.stderr
index 12053d8a129..c3dda704b0e 100644
--- a/src/test/ui/issues/issue-64792-bad-unicode-ctor.stderr
+++ b/src/test/ui/issues/issue-64792-bad-unicode-ctor.stderr
@@ -5,16 +5,7 @@ LL | struct X {}
    | ----------- `X` defined here
 LL | 
 LL | const Y: X = X("ö");
-   |              ^^^^^^
-   |
-help: a constant with a similar name exists
-   |
-LL | const Y: X = Y("ö");
-   |              ^
-help: use struct literal syntax instead
-   |
-LL | const Y: X = X {};
-   |              ^^^^
+   |              ^^^^^^ help: use struct literal syntax instead: `X {}`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-74739.rs b/src/test/ui/issues/issue-74739.rs
new file mode 100644
index 00000000000..03622358ae1
--- /dev/null
+++ b/src/test/ui/issues/issue-74739.rs
@@ -0,0 +1,14 @@
+// compile-flags: -O
+// run-pass
+
+struct Foo {
+    x: i32,
+}
+
+pub fn main() {
+    let mut foo = Foo { x: 42 };
+    let x = &mut foo.x;
+    *x = 13;
+    let y = foo;
+    assert_eq!(y.x, 13); // used to print 42 due to mir-opt bug
+}
diff --git a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs
index e15ed2e70b8..2c711f99404 100644
--- a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs
+++ b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs
@@ -3,9 +3,11 @@
 #![allow(uncommon_codepoints, non_upper_case_globals)]
 
 const s: usize = 42;
+const s_s: usize = 42;
 
 fn main() {
     let s = "rust"; //~ ERROR identifier pair considered confusable
+    let s_s = "rust2"; //~ ERROR identifier pair considered confusable
     not_affected();
 }
 
diff --git a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr
index 218f94f7b58..b9af60963ad 100644
--- a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr
+++ b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr
@@ -1,5 +1,5 @@
 error: identifier pair considered confusable between `s` and `s`
-  --> $DIR/lint-confusable-idents.rs:8:9
+  --> $DIR/lint-confusable-idents.rs:9:9
    |
 LL | const s: usize = 42;
    |       -- this is where the previous identifier occurred
@@ -13,5 +13,14 @@ note: the lint level is defined here
 LL | #![deny(confusable_idents)]
    |         ^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: identifier pair considered confusable between `s_s` and `s_s`
+  --> $DIR/lint-confusable-idents.rs:10:9
+   |
+LL | const s_s: usize = 42;
+   |       --- this is where the previous identifier occurred
+...
+LL |     let s_s = "rust2";
+   |         ^^^^^
+
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/lint/unused_braces.fixed b/src/test/ui/lint/unused_braces.fixed
index c0225911c6e..1a88d985dd8 100644
--- a/src/test/ui/lint/unused_braces.fixed
+++ b/src/test/ui/lint/unused_braces.fixed
@@ -23,18 +23,18 @@ fn main() {
         }
     }
 
-    if  true  {
+    if true {
         //~^ WARN unnecessary braces
     }
 
-    while  false  {
+    while false {
         //~^ WARN unnecessary braces
     }
 
-    let _: [u8;  3 ];
+    let _: [u8; 3];
     //~^ WARN unnecessary braces
 
-    consume( 7 );
+    consume(7);
     //~^ WARN unnecessary braces
 
     // Do not emit lint for multiline blocks.
diff --git a/src/test/ui/lint/unused_braces_borrow.fixed b/src/test/ui/lint/unused_braces_borrow.fixed
index 25950334549..583506f891d 100644
--- a/src/test/ui/lint/unused_braces_borrow.fixed
+++ b/src/test/ui/lint/unused_braces_borrow.fixed
@@ -21,6 +21,6 @@ fn main() {
     };
 
     consume(&{ a.b });
-    consume( a.b );
+    consume(a.b);
     //~^ WARN unnecessary braces
 }
diff --git a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs
new file mode 100644
index 00000000000..0e3ea4bc8c9
--- /dev/null
+++ b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs
@@ -0,0 +1,28 @@
+// Regression test for issue #74918
+// Tests that we don't ICE after emitting an error
+
+struct ChunkingIterator<T, S: 'static + Iterator<Item = T>> {
+    source: S,
+}
+
+impl<T, S: Iterator<Item = T>> Iterator for ChunkingIterator<T, S> {
+    type Item = IteratorChunk<T, S>; //~ ERROR missing lifetime
+
+    fn next(&mut self) -> Option<IteratorChunk<T, S>> { //~ ERROR `impl`
+        todo!()
+    }
+}
+
+struct IteratorChunk<'a, T, S: Iterator<Item = T>> {
+    source: &'a mut S,
+}
+
+impl<T, S: Iterator<Item = T>> Iterator for IteratorChunk<'_, T, S> {
+    type Item = T;
+
+    fn next(&mut self) -> Option<T> {
+        todo!()
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr
new file mode 100644
index 00000000000..d260addef48
--- /dev/null
+++ b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr
@@ -0,0 +1,30 @@
+error[E0106]: missing lifetime specifier
+  --> $DIR/issue-74918-missing-lifetime.rs:9:31
+   |
+LL |     type Item = IteratorChunk<T, S>;
+   |                               ^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL |     type Item<'a> = IteratorChunk<'a, T, S>;
+   |              ^^^^                 ^^^
+
+error: `impl` item signature doesn't match `trait` item signature
+  --> $DIR/issue-74918-missing-lifetime.rs:11:5
+   |
+LL |     fn next(&mut self) -> Option<IteratorChunk<T, S>> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&mut ChunkingIterator<T, S>) -> std::option::Option<IteratorChunk<'_, T, S>>`
+   | 
+  ::: $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+   |
+LL |     fn next(&mut self) -> Option<Self::Item>;
+   |     ----------------------------------------- expected `fn(&mut ChunkingIterator<T, S>) -> std::option::Option<IteratorChunk<'static, _, _>>`
+   |
+   = note: expected `fn(&mut ChunkingIterator<T, S>) -> std::option::Option<IteratorChunk<'static, _, _>>`
+              found `fn(&mut ChunkingIterator<T, S>) -> std::option::Option<IteratorChunk<'_, _, _>>`
+   = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+   = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0106`.
diff --git a/src/test/ui/mismatched_types/issue-75361-mismatched-impl.rs b/src/test/ui/mismatched_types/issue-75361-mismatched-impl.rs
new file mode 100644
index 00000000000..4410514476d
--- /dev/null
+++ b/src/test/ui/mismatched_types/issue-75361-mismatched-impl.rs
@@ -0,0 +1,24 @@
+// Regresison test for issue #75361
+// Tests that we don't ICE on mismatched types with inference variables
+
+
+trait MyTrait {
+    type Item;
+}
+
+pub trait Graph {
+  type EdgeType;
+
+  fn adjacent_edges(&self) -> Box<dyn MyTrait<Item = &Self::EdgeType>>;
+}
+
+impl<T> Graph for T {
+  type EdgeType = T;
+
+  fn adjacent_edges(&self) -> Box<dyn MyTrait<Item = &Self::EdgeType> + '_> { //~ ERROR `impl`
+      panic!()
+  }
+
+}
+
+fn main() {}
diff --git a/src/test/ui/mismatched_types/issue-75361-mismatched-impl.stderr b/src/test/ui/mismatched_types/issue-75361-mismatched-impl.stderr
new file mode 100644
index 00000000000..5be7f5271de
--- /dev/null
+++ b/src/test/ui/mismatched_types/issue-75361-mismatched-impl.stderr
@@ -0,0 +1,19 @@
+error: `impl` item signature doesn't match `trait` item signature
+  --> $DIR/issue-75361-mismatched-impl.rs:18:3
+   |
+LL |   fn adjacent_edges(&self) -> Box<dyn MyTrait<Item = &Self::EdgeType>>;
+   |   --------------------------------------------------------------------- expected `fn(&T) -> std::boxed::Box<(dyn MyTrait<Item = &_> + 'static)>`
+...
+LL |   fn adjacent_edges(&self) -> Box<dyn MyTrait<Item = &Self::EdgeType> + '_> {
+   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&T) -> std::boxed::Box<dyn MyTrait<Item = &_>>`
+   |
+   = note: expected `fn(&T) -> std::boxed::Box<(dyn MyTrait<Item = &T> + 'static)>`
+              found `fn(&T) -> std::boxed::Box<dyn MyTrait<Item = &T>>`
+help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+  --> $DIR/issue-75361-mismatched-impl.rs:12:55
+   |
+LL |   fn adjacent_edges(&self) -> Box<dyn MyTrait<Item = &Self::EdgeType>>;
+   |                                                       ^^^^^^^^^^^^^^ consider borrowing this type parameter in the trait
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/namespace/namespace-mix.stderr b/src/test/ui/namespace/namespace-mix.stderr
index 636789c9cc3..ded3173f45b 100644
--- a/src/test/ui/namespace/namespace-mix.stderr
+++ b/src/test/ui/namespace/namespace-mix.stderr
@@ -53,14 +53,14 @@ LL |         TV(),
 LL |     check(m7::V);
    |           ^^^^^
    |
-help: a tuple variant with a similar name exists
-   |
-LL |     check(m7::TV);
-   |               ^^
 help: use struct literal syntax instead
    |
 LL |     check(m7::V {});
    |           ^^^^^^^^
+help: a tuple variant with a similar name exists
+   |
+LL |     check(m7::TV);
+   |               ^^
 help: consider importing one of these items instead
    |
 LL | use m8::V;
@@ -74,19 +74,21 @@ error[E0423]: expected value, found struct variant `xm7::V`
 LL |     check(xm7::V);
    |           ^^^^^^
    | 
-  ::: $DIR/auxiliary/namespace-mix.rs:7:9
+  ::: $DIR/auxiliary/namespace-mix.rs:6:9
    |
+LL |         V {},
+   |         - `xm7::V` defined here
 LL |         TV(),
    |         ---- similarly named tuple variant `TV` defined here
    |
-help: a tuple variant with a similar name exists
-   |
-LL |     check(xm7::TV);
-   |                ^^
 help: use struct literal syntax instead
    |
 LL |     check(xm7::V { /* fields */ });
    |           ^^^^^^^^^^^^^^^^^^^^^^^
+help: a tuple variant with a similar name exists
+   |
+LL |     check(xm7::TV);
+   |                ^^
 help: consider importing one of these items instead
    |
 LL | use m8::V;
diff --git a/src/test/ui/parser/recover-from-bad-variant.rs b/src/test/ui/parser/recover-from-bad-variant.rs
index 27b03c0c2db..1bcef450bb9 100644
--- a/src/test/ui/parser/recover-from-bad-variant.rs
+++ b/src/test/ui/parser/recover-from-bad-variant.rs
@@ -9,6 +9,7 @@ fn main() {
     match x {
         Enum::Foo(a, b) => {}
         //~^ ERROR expected tuple struct or tuple variant, found struct variant `Enum::Foo`
-        Enum::Bar(a, b) => {}
+        Enum::Bar { a, b } => {}
+        //~^ ERROR tuple variant `Enum::Bar` written as struct variant
     }
 }
diff --git a/src/test/ui/parser/recover-from-bad-variant.stderr b/src/test/ui/parser/recover-from-bad-variant.stderr
index 6986d966d69..89232a519d7 100644
--- a/src/test/ui/parser/recover-from-bad-variant.stderr
+++ b/src/test/ui/parser/recover-from-bad-variant.stderr
@@ -18,6 +18,13 @@ LL |     Foo { a: usize, b: usize },
 LL |         Enum::Foo(a, b) => {}
    |         ^^^^^^^^^^^^^^^ help: use struct pattern syntax instead: `Enum::Foo { a, b }`
 
-error: aborting due to 2 previous errors
+error[E0769]: tuple variant `Enum::Bar` written as struct variant
+  --> $DIR/recover-from-bad-variant.rs:12:9
+   |
+LL |         Enum::Bar { a, b } => {}
+   |         ^^^^^^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `Enum::Bar(a, b)`
+
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0532`.
+Some errors have detailed explanations: E0532, E0769.
+For more information about an error, try `rustc --explain E0532`.
diff --git a/src/test/ui/polymorphization/promoted-function-3.rs b/src/test/ui/polymorphization/promoted-function-3.rs
new file mode 100644
index 00000000000..1c84df13e10
--- /dev/null
+++ b/src/test/ui/polymorphization/promoted-function-3.rs
@@ -0,0 +1,14 @@
+// run-pass
+// compile-flags: -Zpolymorphize=on -Zmir-opt-level=3
+
+fn caller<T, U>() -> &'static usize {
+    callee::<U>()
+}
+
+fn callee<T>() -> &'static usize {
+    &std::mem::size_of::<T>()
+}
+
+fn main() {
+    assert_eq!(caller::<(), ()>(), &0);
+}
diff --git a/src/test/ui/print_type_sizes/niche-filling.stdout b/src/test/ui/print_type_sizes/niche-filling.stdout
index 301edc0d086..1894cd218ee 100644
--- a/src/test/ui/print_type_sizes/niche-filling.stdout
+++ b/src/test/ui/print_type_sizes/niche-filling.stdout
@@ -8,12 +8,12 @@ print-type-size     variant `Some`: 12 bytes
 print-type-size         field `.0`: 12 bytes
 print-type-size     variant `None`: 0 bytes
 print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes
+print-type-size     discriminant: 1 bytes
 print-type-size     variant `Record`: 7 bytes
-print-type-size         field `.val`: 4 bytes
-print-type-size         field `.post`: 2 bytes
 print-type-size         field `.pre`: 1 bytes
+print-type-size         field `.post`: 2 bytes
+print-type-size         field `.val`: 4 bytes
 print-type-size     variant `None`: 0 bytes
-print-type-size     end padding: 1 bytes
 print-type-size type: `MyOption<Union1<std::num::NonZeroU32>>`: 8 bytes, alignment: 4 bytes
 print-type-size     discriminant: 4 bytes
 print-type-size     variant `Some`: 4 bytes
diff --git a/src/test/ui/privacy/legacy-ctor-visibility.stderr b/src/test/ui/privacy/legacy-ctor-visibility.stderr
index 4f0d72de6f1..c8057d85ed1 100644
--- a/src/test/ui/privacy/legacy-ctor-visibility.stderr
+++ b/src/test/ui/privacy/legacy-ctor-visibility.stderr
@@ -1,10 +1,8 @@
 error[E0423]: expected function, tuple struct or tuple variant, found struct `S`
   --> $DIR/legacy-ctor-visibility.rs:9:13
    |
-LL |         fn f() {
-   |         ------ similarly named function `f` defined here
 LL |             S(10);
-   |             ^ help: a function with a similar name exists: `f`
+   |             ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/proc-macro/attributes-on-modules-fail.stderr b/src/test/ui/proc-macro/attributes-on-modules-fail.stderr
index b37f1bd393c..97b2f22e161 100644
--- a/src/test/ui/proc-macro/attributes-on-modules-fail.stderr
+++ b/src/test/ui/proc-macro/attributes-on-modules-fail.stderr
@@ -44,12 +44,8 @@ error[E0412]: cannot find type `Y` in this scope
   --> $DIR/attributes-on-modules-fail.rs:10:14
    |
 LL |     type A = Y;
-   |     ---------^- similarly named type alias `A` defined here
+   |              ^ not found in this scope
    |
-help: a type alias with a similar name exists
-   |
-LL |     type A = A;
-   |              ^
 help: consider importing this struct
    |
 LL |     use Y;
@@ -59,12 +55,8 @@ error[E0412]: cannot find type `X` in this scope
   --> $DIR/attributes-on-modules-fail.rs:14:10
    |
 LL | type A = X;
-   | ---------^- similarly named type alias `A` defined here
-   |
-help: a type alias with a similar name exists
+   |          ^ not found in this scope
    |
-LL | type A = A;
-   |          ^
 help: consider importing this struct
    |
 LL | use m::X;
diff --git a/src/test/ui/resolve/issue-19452.stderr b/src/test/ui/resolve/issue-19452.stderr
index d1690d4eef7..6c519d73480 100644
--- a/src/test/ui/resolve/issue-19452.stderr
+++ b/src/test/ui/resolve/issue-19452.stderr
@@ -12,6 +12,11 @@ error[E0423]: expected value, found struct variant `issue_19452_aux::Homura::Mad
    |
 LL |     let homura = issue_19452_aux::Homura::Madoka;
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `issue_19452_aux::Homura::Madoka { /* fields */ }`
+   | 
+  ::: $DIR/auxiliary/issue-19452-aux.rs:2:5
+   |
+LL |     Madoka { age: u32 }
+   |     ------ `issue_19452_aux::Homura::Madoka` defined here
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/resolve/issue-39226.stderr b/src/test/ui/resolve/issue-39226.stderr
index c9b9aeb45ba..72d66b0f6a2 100644
--- a/src/test/ui/resolve/issue-39226.stderr
+++ b/src/test/ui/resolve/issue-39226.stderr
@@ -7,14 +7,14 @@ LL | struct Handle {}
 LL |         handle: Handle
    |                 ^^^^^^
    |
-help: a local variable with a similar name exists
-   |
-LL |         handle: handle
-   |                 ^^^^^^
 help: use struct literal syntax instead
    |
 LL |         handle: Handle {}
    |                 ^^^^^^^^^
+help: a local variable with a similar name exists
+   |
+LL |         handle: handle
+   |                 ^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr
index 3904a00dde1..f1ed7aaa867 100644
--- a/src/test/ui/resolve/privacy-enum-ctor.stderr
+++ b/src/test/ui/resolve/privacy-enum-ctor.stderr
@@ -16,16 +16,9 @@ LL |         m::Z::Unit;
 error[E0423]: expected value, found enum `Z`
   --> $DIR/privacy-enum-ctor.rs:25:9
    |
-LL |     fn f() {
-   |     ------ similarly named function `f` defined here
-...
 LL |         Z;
    |         ^
    |
-help: a function with a similar name exists
-   |
-LL |         f;
-   |         ^
 help: try using one of the enum's variants
    |
 LL |         m::Z::Fn;
@@ -55,10 +48,6 @@ LL |     fn f() {
 LL |     let _: E = m::E;
    |                ^^^^
    |
-help: a function with a similar name exists
-   |
-LL |     let _: E = m::f;
-   |                   ^
 help: try using one of the enum's variants
    |
 LL |     let _: E = E::Fn;
@@ -67,6 +56,10 @@ LL |     let _: E = E::Struct;
    |                ^^^^^^^^^
 LL |     let _: E = E::Unit;
    |                ^^^^^^^
+help: a function with a similar name exists
+   |
+LL |     let _: E = m::f;
+   |                   ^
 help: consider importing one of these items instead
    |
 LL | use std::f32::consts::E;
diff --git a/src/test/ui/resolve/resolve-hint-macro.stderr b/src/test/ui/resolve/resolve-hint-macro.stderr
index 361da4cc78e..7d35ce7e65e 100644
--- a/src/test/ui/resolve/resolve-hint-macro.stderr
+++ b/src/test/ui/resolve/resolve-hint-macro.stderr
@@ -2,7 +2,7 @@ error[E0423]: expected function, found macro `assert`
   --> $DIR/resolve-hint-macro.rs:2:5
    |
 LL |     assert(true);
-   |     ^^^^^^
+   |     ^^^^^^ not a function
    |
 help: use `!` to invoke the macro
    |
diff --git a/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr b/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr
index 33080340cb6..2d35159ec9a 100644
--- a/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr
+++ b/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr
@@ -31,14 +31,14 @@ LL |     pub const I: i32 = 1;
 LL |     a::b.J
    |     ^^^^
    |
-help: a constant with a similar name exists
-   |
-LL |     a::I.J
-   |        ^
 help: use the path separator to refer to an item
    |
 LL |     a::b::J
    |
+help: a constant with a similar name exists
+   |
+LL |     a::I.J
+   |        ^
 
 error[E0423]: expected value, found module `a`
   --> $DIR/suggest-path-instead-of-mod-dot-item.rs:37:5
@@ -68,14 +68,14 @@ LL |     pub const I: i32 = 1;
 LL |     a::b.f()
    |     ^^^^
    |
-help: a constant with a similar name exists
-   |
-LL |     a::I.f()
-   |        ^
 help: use the path separator to refer to an item
    |
 LL |     a::b::f()
    |     ^^^^^^^
+help: a constant with a similar name exists
+   |
+LL |     a::I.f()
+   |        ^
 
 error[E0423]: expected value, found module `a::b`
   --> $DIR/suggest-path-instead-of-mod-dot-item.rs:50:5
diff --git a/src/test/ui/struct-literal-variant-in-if.stderr b/src/test/ui/struct-literal-variant-in-if.stderr
index 4cd1169cc1b..a2252d4e4d2 100644
--- a/src/test/ui/struct-literal-variant-in-if.stderr
+++ b/src/test/ui/struct-literal-variant-in-if.stderr
@@ -46,7 +46,7 @@ error[E0423]: expected value, found struct variant `E::V`
   --> $DIR/struct-literal-variant-in-if.rs:10:13
    |
 LL |     if x == E::V { field } {}
-   |             ^^^^
+   |             ^^^^ not a value
    |
 help: surround the struct literal with parentheses
    |
diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr
index 45309486db4..9b2febb1393 100644
--- a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr
+++ b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr
@@ -9,14 +9,14 @@ LL |     B { a: usize },
 LL |     let _: E = E::B;
    |                ^^^^
    |
-help: a tuple variant with a similar name exists
-   |
-LL |     let _: E = E::A;
-   |                   ^
 help: use struct literal syntax instead
    |
 LL |     let _: E = E::B { a: val };
    |                ^^^^^^^^^^^^^^^
+help: a tuple variant with a similar name exists
+   |
+LL |     let _: E = E::A;
+   |                   ^
 
 error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:29:20
diff --git a/src/test/ui/suggestions/js-style-comparison-op-separate-eq-token.rs b/src/test/ui/suggestions/js-style-comparison-op-separate-eq-token.rs
new file mode 100644
index 00000000000..b24d256481c
--- /dev/null
+++ b/src/test/ui/suggestions/js-style-comparison-op-separate-eq-token.rs
@@ -0,0 +1,5 @@
+fn main() {
+    if 1 == = 1 { //~ ERROR expected expression
+        println!("yup!");
+    }
+}
diff --git a/src/test/ui/suggestions/js-style-comparison-op-separate-eq-token.stderr b/src/test/ui/suggestions/js-style-comparison-op-separate-eq-token.stderr
new file mode 100644
index 00000000000..6adefe3de37
--- /dev/null
+++ b/src/test/ui/suggestions/js-style-comparison-op-separate-eq-token.stderr
@@ -0,0 +1,8 @@
+error: expected expression, found `=`
+  --> $DIR/js-style-comparison-op-separate-eq-token.rs:2:13
+   |
+LL |     if 1 == = 1 {
+   |             ^ expected expression
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/suggestions/js-style-comparison-op.fixed b/src/test/ui/suggestions/js-style-comparison-op.fixed
new file mode 100644
index 00000000000..f7e977b918d
--- /dev/null
+++ b/src/test/ui/suggestions/js-style-comparison-op.fixed
@@ -0,0 +1,8 @@
+// run-rustfix
+fn main() {
+    if 1 == 1 { //~ ERROR invalid comparison operator `===`
+        println!("yup!");
+    } else if 1 != 1 { //~ ERROR invalid comparison operator `!==`
+        println!("nope!");
+    }
+}
diff --git a/src/test/ui/suggestions/js-style-comparison-op.rs b/src/test/ui/suggestions/js-style-comparison-op.rs
new file mode 100644
index 00000000000..c89c1052ed9
--- /dev/null
+++ b/src/test/ui/suggestions/js-style-comparison-op.rs
@@ -0,0 +1,8 @@
+// run-rustfix
+fn main() {
+    if 1 === 1 { //~ ERROR invalid comparison operator `===`
+        println!("yup!");
+    } else if 1 !== 1 { //~ ERROR invalid comparison operator `!==`
+        println!("nope!");
+    }
+}
diff --git a/src/test/ui/suggestions/js-style-comparison-op.stderr b/src/test/ui/suggestions/js-style-comparison-op.stderr
new file mode 100644
index 00000000000..33f7a0844fd
--- /dev/null
+++ b/src/test/ui/suggestions/js-style-comparison-op.stderr
@@ -0,0 +1,14 @@
+error: invalid comparison operator `===`
+  --> $DIR/js-style-comparison-op.rs:3:10
+   |
+LL |     if 1 === 1 {
+   |          ^^^ help: `===` is not a valid comparison operator, use `==`
+
+error: invalid comparison operator `!==`
+  --> $DIR/js-style-comparison-op.rs:5:17
+   |
+LL |     } else if 1 !== 1 {
+   |                 ^^^ help: `!==` is not a valid comparison operator, use `!=`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.rs b/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.rs
new file mode 100644
index 00000000000..38332627f4c
--- /dev/null
+++ b/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.rs
@@ -0,0 +1,16 @@
+trait ZstAssert: Sized {
+    const A: &str = ""; //~ ERROR missing lifetime specifier
+    const B: S = S { s: &() }; //~ ERROR missing lifetime specifier
+    const C: &'_ str = ""; //~ ERROR missing lifetime specifier
+    const D: T = T { a: &(), b: &() }; //~ ERROR missing lifetime specifier
+}
+
+struct S<'a> {
+    s: &'a (),
+}
+struct T<'a, 'b> {
+    a: &'a (),
+    b: &'b (),
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr b/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr
new file mode 100644
index 00000000000..b20778ce208
--- /dev/null
+++ b/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr
@@ -0,0 +1,73 @@
+error[E0106]: missing lifetime specifier
+  --> $DIR/missing-lifetime-in-assoc-const-type.rs:2:14
+   |
+LL |     const A: &str = "";
+   |              ^ expected named lifetime parameter
+   |
+help: consider using the `'static` lifetime
+   |
+LL |     const A: &'static str = "";
+   |               ^^^^^^^
+help: consider introducing a named lifetime parameter
+   |
+LL | trait ZstAssert<'a>: Sized {
+LL |     const A: &'a str = "";
+   |
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/missing-lifetime-in-assoc-const-type.rs:3:14
+   |
+LL |     const B: S = S { s: &() };
+   |              ^ expected named lifetime parameter
+   |
+help: consider using the `'static` lifetime
+   |
+LL |     const B: S<'static> = S { s: &() };
+   |               ^^^^^^^^^
+help: consider introducing a named lifetime parameter
+   |
+LL | trait ZstAssert<'a>: Sized {
+LL |     const A: &str = "";
+LL |     const B: S<'a> = S { s: &() };
+   |
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/missing-lifetime-in-assoc-const-type.rs:4:15
+   |
+LL |     const C: &'_ str = "";
+   |               ^^ expected named lifetime parameter
+   |
+help: consider using the `'static` lifetime
+   |
+LL |     const C: &'static str = "";
+   |               ^^^^^^^
+help: consider introducing a named lifetime parameter
+   |
+LL | trait ZstAssert<'a>: Sized {
+LL |     const A: &str = "";
+LL |     const B: S = S { s: &() };
+LL |     const C: &'a str = "";
+   |
+
+error[E0106]: missing lifetime specifiers
+  --> $DIR/missing-lifetime-in-assoc-const-type.rs:5:14
+   |
+LL |     const D: T = T { a: &(), b: &() };
+   |              ^ expected 2 lifetime parameters
+   |
+help: consider using the `'static` lifetime
+   |
+LL |     const D: T<'static, 'static> = T { a: &(), b: &() };
+   |               ^^^^^^^^^^^^^^^^^^
+help: consider introducing a named lifetime parameter
+   |
+LL | trait ZstAssert<'a>: Sized {
+LL |     const A: &str = "";
+LL |     const B: S = S { s: &() };
+LL |     const C: &'_ str = "";
+LL |     const D: T<'a, 'a> = T { a: &(), b: &() };
+   |
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0106`.
diff --git a/src/test/ui/suggestions/missing-lt-for-hrtb.rs b/src/test/ui/suggestions/missing-lt-for-hrtb.rs
new file mode 100644
index 00000000000..a90a90122ad
--- /dev/null
+++ b/src/test/ui/suggestions/missing-lt-for-hrtb.rs
@@ -0,0 +1,15 @@
+struct X<'a>(&'a ());
+struct S<'a>(&'a dyn Fn(&X) -> &X);
+//~^ ERROR missing lifetime specifier
+//~| ERROR missing lifetime specifier
+struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X);
+//~^ ERROR missing lifetime specifier
+//~| ERROR missing lifetime specifier
+
+fn main() {
+    let x = S(&|x| {
+        println!("hi");
+        x
+    });
+    x.0(&X(&()));
+}
diff --git a/src/test/ui/suggestions/missing-lt-for-hrtb.stderr b/src/test/ui/suggestions/missing-lt-for-hrtb.stderr
new file mode 100644
index 00000000000..2cb63500e48
--- /dev/null
+++ b/src/test/ui/suggestions/missing-lt-for-hrtb.stderr
@@ -0,0 +1,63 @@
+error[E0106]: missing lifetime specifier
+  --> $DIR/missing-lt-for-hrtb.rs:2:32
+   |
+LL | struct S<'a>(&'a dyn Fn(&X) -> &X);
+   |                         --     ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from
+   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+   |
+LL | struct S<'a>(&'a dyn for<'b> Fn(&'b X) -> &'b X);
+   |                      ^^^^^^^    ^^^^^     ^^^
+help: consider using the `'a` lifetime
+   |
+LL | struct S<'a>(&'a dyn Fn(&X) -> &'a X);
+   |                                ^^^
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/missing-lt-for-hrtb.rs:2:33
+   |
+LL | struct S<'a>(&'a dyn Fn(&X) -> &X);
+   |                         --      ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from
+   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+   |
+LL | struct S<'a>(&'a dyn for<'b> Fn(&'b X) -> &X<'b>);
+   |                      ^^^^^^^    ^^^^^      ^^^^^
+help: consider using the `'a` lifetime
+   |
+LL | struct S<'a>(&'a dyn Fn(&X) -> &X<'a>);
+   |                                 ^^^^^
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/missing-lt-for-hrtb.rs:5:40
+   |
+LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X);
+   |                                 --     ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from
+note: these named lifetimes are available to use
+  --> $DIR/missing-lt-for-hrtb.rs:5:10
+   |
+LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X);
+   |          ^^              ^^
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/missing-lt-for-hrtb.rs:5:41
+   |
+LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X);
+   |                                 --      ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from
+note: these named lifetimes are available to use
+  --> $DIR/missing-lt-for-hrtb.rs:5:10
+   |
+LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X);
+   |          ^^              ^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0106`.
diff --git a/src/test/ui/try-block/try-block-in-edition2015.stderr b/src/test/ui/try-block/try-block-in-edition2015.stderr
index fe870ab737c..78cdfb2cc7f 100644
--- a/src/test/ui/try-block/try-block-in-edition2015.stderr
+++ b/src/test/ui/try-block/try-block-in-edition2015.stderr
@@ -11,7 +11,7 @@ error[E0574]: expected struct, variant or union type, found macro `try`
   --> $DIR/try-block-in-edition2015.rs:4:33
    |
 LL |     let try_result: Option<_> = try {
-   |                                 ^^^
+   |                                 ^^^ not a struct, variant or union type
    |
    = note: if you want the `try` keyword, you need to be in the 2018 edition
 help: use `!` to invoke the macro
diff --git a/src/test/ui/try-block/try-block-unused-delims.fixed b/src/test/ui/try-block/try-block-unused-delims.fixed
index c8b03c20068..756081738c3 100644
--- a/src/test/ui/try-block/try-block-unused-delims.fixed
+++ b/src/test/ui/try-block/try-block-unused-delims.fixed
@@ -11,7 +11,7 @@ fn main() {
     consume(try {});
     //~^ WARN unnecessary parentheses
 
-    consume( try {} );
+    consume(try {});
     //~^ WARN unnecessary braces
 
     match try {} {
diff --git a/src/test/ui/type-sizes.rs b/src/test/ui/type-sizes.rs
index 6a3f3c98f12..73a11a5e743 100644
--- a/src/test/ui/type-sizes.rs
+++ b/src/test/ui/type-sizes.rs
@@ -5,6 +5,7 @@
 #![feature(never_type)]
 
 use std::mem::size_of;
+use std::num::NonZeroU8;
 
 struct t {a: u8, b: i8}
 struct u {a: u8, b: i8, c: u8}
@@ -102,6 +103,23 @@ enum Option2<A, B> {
     None
 }
 
+// Two layouts are considered for `CanBeNicheFilledButShouldnt`:
+//   Niche-filling:
+//     { u32 (4 bytes), NonZeroU8 + tag in niche (1 byte), padding (3 bytes) }
+//   Tagged:
+//     { tag (1 byte), NonZeroU8 (1 byte), padding (2 bytes), u32 (4 bytes) }
+// Both are the same size (due to padding),
+// but the tagged layout is better as the tag creates a niche with 254 invalid values,
+// allowing types like `Option<Option<CanBeNicheFilledButShouldnt>>` to fit into 8 bytes.
+pub enum CanBeNicheFilledButShouldnt {
+    A(NonZeroU8, u32),
+    B
+}
+pub enum AlwaysTaggedBecauseItHasNoNiche {
+    A(u8, u32),
+    B
+}
+
 pub fn main() {
     assert_eq!(size_of::<u8>(), 1 as usize);
     assert_eq!(size_of::<u32>(), 4 as usize);
@@ -145,4 +163,11 @@ pub fn main() {
     assert_eq!(size_of::<Option<Option<(&(), bool)>>>(), size_of::<(bool, &())>());
     assert_eq!(size_of::<Option<Option2<bool, &()>>>(), size_of::<(bool, &())>());
     assert_eq!(size_of::<Option<Option2<&(), bool>>>(), size_of::<(bool, &())>());
+
+    assert_eq!(size_of::<CanBeNicheFilledButShouldnt>(), 8);
+    assert_eq!(size_of::<Option<CanBeNicheFilledButShouldnt>>(), 8);
+    assert_eq!(size_of::<Option<Option<CanBeNicheFilledButShouldnt>>>(), 8);
+    assert_eq!(size_of::<AlwaysTaggedBecauseItHasNoNiche>(), 8);
+    assert_eq!(size_of::<Option<AlwaysTaggedBecauseItHasNoNiche>>(), 8);
+    assert_eq!(size_of::<Option<Option<AlwaysTaggedBecauseItHasNoNiche>>>(), 8);
 }
diff --git a/src/test/ui/type/type-ascription-with-fn-call.stderr b/src/test/ui/type/type-ascription-with-fn-call.stderr
index 5f74724b59e..d78fd08fd60 100644
--- a/src/test/ui/type/type-ascription-with-fn-call.stderr
+++ b/src/test/ui/type/type-ascription-with-fn-call.stderr
@@ -4,10 +4,7 @@ error[E0573]: expected type, found function `f`
 LL |     f()  :
    |          - help: maybe you meant to write `;` here
 LL |     f();
-   |     ^^^
-   |     |
-   |     not a type
-   |     expecting a type here because of type ascription
+   |     ^^^ expecting a type here because of type ascription
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/typeck/issue-74933.rs b/src/test/ui/typeck/issue-74933.rs
new file mode 100644
index 00000000000..4b6c173b8ce
--- /dev/null
+++ b/src/test/ui/typeck/issue-74933.rs
@@ -0,0 +1,38 @@
+// check-pass
+//
+// rust-lang/rust#74933: Lifetime error when indexing with borrowed index
+
+use std::ops::{Index, IndexMut};
+
+struct S(V);
+struct K<'a>(&'a ());
+struct V;
+
+impl<'a> Index<&'a K<'a>> for S {
+    type Output = V;
+
+    fn index(&self, _: &'a K<'a>) -> &V {
+        &self.0
+    }
+}
+
+impl<'a> IndexMut<&'a K<'a>> for S {
+    fn index_mut(&mut self, _: &'a K<'a>) -> &mut V {
+        &mut self.0
+    }
+}
+
+impl V {
+    fn foo(&mut self) {}
+}
+
+fn test(s: &mut S, k: &K<'_>) {
+    s[k] = V;
+    s[k].foo();
+}
+
+fn main() {
+    let mut s = S(V);
+    let k = K(&());
+    test(&mut s, &k);
+}
diff --git a/src/test/ui/ui-testing-optout.stderr b/src/test/ui/ui-testing-optout.stderr
index f562bb74c11..652c472c0bc 100644
--- a/src/test/ui/ui-testing-optout.stderr
+++ b/src/test/ui/ui-testing-optout.stderr
@@ -2,10 +2,7 @@ error[E0412]: cannot find type `B` in this scope
  --> $DIR/ui-testing-optout.rs:4:10
   |
 4 | type A = B;
-  | ---------^-
-  | |        |
-  | |        help: a type alias with a similar name exists: `A`
-  | similarly named type alias `A` defined here
+  |          ^ not found in this scope
 
 error[E0412]: cannot find type `D` in this scope
  --> $DIR/ui-testing-optout.rs:7:10
diff --git a/src/test/ui/xcrate/xcrate-unit-struct.stderr b/src/test/ui/xcrate/xcrate-unit-struct.stderr
index 813d5d4fdb1..3dc8b90795c 100644
--- a/src/test/ui/xcrate/xcrate-unit-struct.stderr
+++ b/src/test/ui/xcrate/xcrate-unit-struct.stderr
@@ -3,6 +3,11 @@ error[E0423]: expected value, found struct `xcrate_unit_struct::StructWithFields
    |
 LL |     let _ = xcrate_unit_struct::StructWithFields;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `xcrate_unit_struct::StructWithFields { foo: val }`
+   | 
+  ::: $DIR/auxiliary/xcrate_unit_struct.rs:20:1
+   |
+LL | pub struct StructWithFields {
+   | --------------------------- `xcrate_unit_struct::StructWithFields` defined here
 
 error: aborting due to previous error
 
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 776b04295f9..5e9ed54c848 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,13 +6,13 @@ document.
 
 ## Unreleased / In Rust Nightly
 
-[c2c07fa...master](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...master)
+[c2c07fa...master](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...master)
 
 ## Rust 1.46
 
 Current beta, release 2020-08-27
 
-[7ea7cd1...c2c07fa](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...master)
+[7ea7cd1...c2c07fa](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...c2c07fa)
 
 ### New lints
 
@@ -1454,6 +1454,7 @@ Released 2018-09-13
 [`deprecated_semver`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_semver
 [`deref_addrof`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_addrof
 [`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
+[`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord
 [`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
 [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
 [`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
@@ -1615,6 +1616,7 @@ Released 2018-09-13
 [`mutex_atomic`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutex_atomic
 [`mutex_integer`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutex_integer
 [`naive_bytecount`]: https://rust-lang.github.io/rust-clippy/master/index.html#naive_bytecount
+[`needless_arbitrary_self_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_arbitrary_self_type
 [`needless_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool
 [`needless_borrow`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
 [`needless_borrowed_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrowed_reference
@@ -1686,6 +1688,7 @@ Released 2018-09-13
 [`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn
 [`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges
 [`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition
+[`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push
 [`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some
 [`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse
 [`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse
@@ -1701,6 +1704,7 @@ Released 2018-09-13
 [`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else
 [`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next
 [`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization
+[`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive
 [`str_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_to_string
 [`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add
 [`string_add_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add_assign
@@ -1723,6 +1727,7 @@ Released 2018-09-13
 [`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments
 [`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines
 [`toplevel_ref_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#toplevel_ref_arg
+[`trait_duplication_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#trait_duplication_in_bounds
 [`transmute_bytes_to_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_bytes_to_str
 [`transmute_float_to_int`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_float_to_int
 [`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool
@@ -1730,6 +1735,7 @@ Released 2018-09-13
 [`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float
 [`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr
 [`transmute_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref
+[`transmutes_expressible_as_ptr_casts`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmutes_expressible_as_ptr_casts
 [`transmuting_null`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmuting_null
 [`trivial_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#trivial_regex
 [`trivially_copy_pass_by_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref
diff --git a/src/tools/clippy/CONTRIBUTING.md b/src/tools/clippy/CONTRIBUTING.md
index 69a734e4ee4..5f7b1e85ee9 100644
--- a/src/tools/clippy/CONTRIBUTING.md
+++ b/src/tools/clippy/CONTRIBUTING.md
@@ -28,11 +28,14 @@ All contributors are expected to follow the [Rust Code of Conduct].
 
 ## Getting started
 
-High level approach:
+**Note: If this is your first time contributing to Clippy, you should
+first read the [Basics docs](doc/basics.md).**
+
+### High level approach
 
 1. Find something to fix/improve
 2. Change code (likely some file in `clippy_lints/src/`)
-3. Follow the instructions in the [docs for writing lints](doc/adding_lints.md) such as running the `setup-toolchain.sh` script
+3. Follow the instructions in the [Basics docs](doc/basics.md) to get set up
 4. Run `cargo test` in the root directory and wiggle code until it passes
 5. Open a PR (also can be done after 2. if you run into problems)
 
@@ -95,16 +98,16 @@ quick read.
 
 ## Getting code-completion for rustc internals to work
 
-Unfortunately, [`rust-analyzer`][ra_homepage] does not (yet?) understand how Clippy uses compiler-internals 
-using `extern crate` and it also needs to be able to read the source files of the rustc-compiler which are not 
-available via a `rustup` component at the time of writing.  
-To work around this, you need to have a copy of the [rustc-repo][rustc_repo] available which can be obtained via  
-`git clone https://github.com/rust-lang/rust/`.  
-Then you can run a `cargo dev` command to automatically make Clippy use the rustc-repo via path-dependencies 
-which rust-analyzer will be able to understand.  
-Run `cargo dev ra-setup --repo-path <repo-path>` where `<repo-path>` is an absolute path to the rustc repo 
-you just cloned.  
-The command will add path-dependencies pointing towards rustc-crates inside the rustc repo to 
+Unfortunately, [`rust-analyzer`][ra_homepage] does not (yet?) understand how Clippy uses compiler-internals
+using `extern crate` and it also needs to be able to read the source files of the rustc-compiler which are not
+available via a `rustup` component at the time of writing.
+To work around this, you need to have a copy of the [rustc-repo][rustc_repo] available which can be obtained via
+`git clone https://github.com/rust-lang/rust/`.
+Then you can run a `cargo dev` command to automatically make Clippy use the rustc-repo via path-dependencies
+which rust-analyzer will be able to understand.
+Run `cargo dev ra-setup --repo-path <repo-path>` where `<repo-path>` is an absolute path to the rustc repo
+you just cloned.
+The command will add path-dependencies pointing towards rustc-crates inside the rustc repo to
 Clippys `Cargo.toml`s and should allow rust-analyzer to understand most of the types that Clippy uses.
 Just make sure to remove the dependencies again before finally making a pull request!
 
diff --git a/src/tools/clippy/clippy_dev/src/ra_setup.rs b/src/tools/clippy/clippy_dev/src/ra_setup.rs
index 8617445c8a6..f2bd651ab25 100644
--- a/src/tools/clippy/clippy_dev/src/ra_setup.rs
+++ b/src/tools/clippy/clippy_dev/src/ra_setup.rs
@@ -68,10 +68,11 @@ fn inject_deps_into_manifest(
     });
 
     // format a new [dependencies]-block with the new deps we need to inject
-    let mut all_deps = String::from("[dependencies]\n");
+    let mut all_deps = String::from("[target.'cfg(NOT_A_PLATFORM)'.dependencies]\n");
     new_deps.for_each(|dep_line| {
         all_deps.push_str(&dep_line);
     });
+    all_deps.push_str("\n[dependencies]\n");
 
     // replace "[dependencies]" with
     // [dependencies]
diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs
index 40af6bb3d7b..376ac55f9c9 100644
--- a/src/tools/clippy/clippy_lints/src/attrs.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs.rs
@@ -1,6 +1,5 @@
 //! checks for attributes
 
-use crate::reexport::Name;
 use crate::utils::{
     first_line_of_span, is_present_in_source, match_def_path, paths, snippet_opt, span_lint, span_lint_and_help,
     span_lint_and_sugg, span_lint_and_then, without_block_comments,
@@ -517,7 +516,7 @@ fn is_relevant_expr(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>
     }
 }
 
-fn check_attrs(cx: &LateContext<'_>, span: Span, name: Name, attrs: &[Attribute]) {
+fn check_attrs(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribute]) {
     if span.from_expansion() {
         return;
     }
@@ -606,7 +605,7 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::as
                         cx,
                         EMPTY_LINE_AFTER_OUTER_ATTR,
                         begin_of_attr_to_item,
-                        "Found an empty line after an outer attribute. \
+                        "found an empty line after an outer attribute. \
                         Perhaps you forgot to add a `!` to make it an inner attribute?",
                     );
                 }
diff --git a/src/tools/clippy/clippy_lints/src/bytecount.rs b/src/tools/clippy/clippy_lints/src/bytecount.rs
index dde799fcae4..cdb49d777d8 100644
--- a/src/tools/clippy/clippy_lints/src/bytecount.rs
+++ b/src/tools/clippy/clippy_lints/src/bytecount.rs
@@ -82,8 +82,8 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount {
                             cx,
                             NAIVE_BYTECOUNT,
                             expr.span,
-                            "You appear to be counting bytes the naive way",
-                            "Consider using the bytecount crate",
+                            "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)),
diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
index 841902943f0..28c1a54d2c5 100644
--- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
@@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for CheckedConversions {
                     cx,
                     CHECKED_CONVERSIONS,
                     item.span,
-                    "Checked cast can be simplified.",
+                    "checked cast can be simplified",
                     "try",
                     format!("{}::try_from({}).is_ok()", to_type, snippet),
                     applicability,
diff --git a/src/tools/clippy/clippy_lints/src/consts.rs b/src/tools/clippy/clippy_lints/src/consts.rs
index 49ff86a205d..c77b80bc237 100644
--- a/src/tools/clippy/clippy_lints/src/consts.rs
+++ b/src/tools/clippy/clippy_lints/src/consts.rs
@@ -517,7 +517,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
         ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty.kind {
             ty::Ref(_, tam, _) => match tam.kind {
                 ty::Str => String::from_utf8(
-                    data.inspect_with_undef_and_ptr_outside_interpreter(start..end)
+                    data.inspect_with_uninit_and_ptr_outside_interpreter(start..end)
                         .to_owned(),
                 )
                 .ok()
@@ -530,7 +530,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
             ty::Array(sub_type, len) => match sub_type.kind {
                 ty::Float(FloatTy::F32) => match miri_to_const(len) {
                     Some(Constant::Int(len)) => alloc
-                        .inspect_with_undef_and_ptr_outside_interpreter(0..(4 * len as usize))
+                        .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * len as usize))
                         .to_owned()
                         .chunks(4)
                         .map(|chunk| {
@@ -544,7 +544,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
                 },
                 ty::Float(FloatTy::F64) => match miri_to_const(len) {
                     Some(Constant::Int(len)) => alloc
-                        .inspect_with_undef_and_ptr_outside_interpreter(0..(8 * len as usize))
+                        .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * len as usize))
                         .to_owned()
                         .chunks(8)
                         .map(|chunk| {
diff --git a/src/tools/clippy/clippy_lints/src/default_trait_access.rs b/src/tools/clippy/clippy_lints/src/default_trait_access.rs
index ea244768129..874e19d9e9f 100644
--- a/src/tools/clippy/clippy_lints/src/default_trait_access.rs
+++ b/src/tools/clippy/clippy_lints/src/default_trait_access.rs
@@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultTraitAccess {
                                 cx,
                                 DEFAULT_TRAIT_ACCESS,
                                 expr.span,
-                                &format!("Calling `{}` is more clear than this expression", replacement),
+                                &format!("calling `{}` is more clear than this expression", replacement),
                                 "try",
                                 replacement,
                                 Applicability::Unspecified, // First resolve the TODO above
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 59c62f1ae94..80a06758982 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -1,6 +1,7 @@
 use crate::utils::paths;
 use crate::utils::{
-    is_automatically_derived, is_copy, match_path, span_lint_and_help, span_lint_and_note, span_lint_and_then,
+    get_trait_def_id, is_allowed, is_automatically_derived, is_copy, match_path, span_lint_and_help,
+    span_lint_and_note, span_lint_and_then,
 };
 use if_chain::if_chain;
 use rustc_hir::def_id::DefId;
@@ -44,6 +45,57 @@ declare_clippy_lint! {
 }
 
 declare_clippy_lint! {
+    /// **What it does:** Checks for deriving `Ord` but implementing `PartialOrd`
+    /// explicitly or vice versa.
+    ///
+    /// **Why is this bad?** The implementation of these traits must agree (for
+    /// example for use with `sort`) so it’s probably a bad idea to use a
+    /// default-generated `Ord` implementation with an explicitly defined
+    /// `PartialOrd`. In particular, the following must hold for any type
+    /// implementing `Ord`:
+    ///
+    /// ```text
+    /// k1.cmp(&k2) == k1.partial_cmp(&k2).unwrap()
+    /// ```
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust,ignore
+    /// #[derive(Ord, PartialEq, Eq)]
+    /// struct Foo;
+    ///
+    /// impl PartialOrd for Foo {
+    ///     ...
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// #[derive(PartialEq, Eq)]
+    /// struct Foo;
+    ///
+    /// impl PartialOrd for Foo {
+    ///     fn partial_cmp(&self, other: &Foo) -> Option<Ordering> {
+    ///        Some(self.cmp(other))
+    ///     }
+    /// }
+    ///
+    /// impl Ord for Foo {
+    ///     ...
+    /// }
+    /// ```
+    /// or, if you don't need a custom ordering:
+    /// ```rust,ignore
+    /// #[derive(Ord, PartialOrd, PartialEq, Eq)]
+    /// struct Foo;
+    /// ```
+    pub DERIVE_ORD_XOR_PARTIAL_ORD,
+    correctness,
+    "deriving `Ord` but implementing `PartialOrd` explicitly"
+}
+
+declare_clippy_lint! {
     /// **What it does:** Checks for explicit `Clone` implementations for `Copy`
     /// types.
     ///
@@ -103,7 +155,12 @@ declare_clippy_lint! {
     "deriving `serde::Deserialize` on a type that has methods using `unsafe`"
 }
 
-declare_lint_pass!(Derive => [EXPL_IMPL_CLONE_ON_COPY, DERIVE_HASH_XOR_EQ, UNSAFE_DERIVE_DESERIALIZE]);
+declare_lint_pass!(Derive => [
+    EXPL_IMPL_CLONE_ON_COPY,
+    DERIVE_HASH_XOR_EQ,
+    DERIVE_ORD_XOR_PARTIAL_ORD,
+    UNSAFE_DERIVE_DESERIALIZE
+]);
 
 impl<'tcx> LateLintPass<'tcx> for Derive {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
@@ -116,6 +173,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive {
             let is_automatically_derived = is_automatically_derived(&*item.attrs);
 
             check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
+            check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived);
 
             if is_automatically_derived {
                 check_unsafe_derive_deserialize(cx, item, trait_ref, ty);
@@ -180,6 +238,60 @@ fn check_hash_peq<'tcx>(
     }
 }
 
+/// Implementation of the `DERIVE_ORD_XOR_PARTIAL_ORD` lint.
+fn check_ord_partial_ord<'tcx>(
+    cx: &LateContext<'tcx>,
+    span: Span,
+    trait_ref: &TraitRef<'_>,
+    ty: Ty<'tcx>,
+    ord_is_automatically_derived: bool,
+) {
+    if_chain! {
+        if let Some(ord_trait_def_id) = get_trait_def_id(cx, &paths::ORD);
+        if let Some(partial_ord_trait_def_id) = cx.tcx.lang_items().partial_ord_trait();
+        if let Some(def_id) = &trait_ref.trait_def_id();
+        if *def_id == ord_trait_def_id;
+        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));
+
+                if partial_ord_is_automatically_derived == ord_is_automatically_derived {
+                    return;
+                }
+
+                let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation");
+
+                // Only care about `impl PartialOrd<Foo> for Foo`
+                // For `impl PartialOrd<B> for A, input_types is [A, B]
+                if trait_ref.substs.type_at(1) == ty {
+                    let mess = if partial_ord_is_automatically_derived {
+                        "you are implementing `Ord` explicitly but have derived `PartialOrd`"
+                    } else {
+                        "you are deriving `Ord` but have implemented `PartialOrd` explicitly"
+                    };
+
+                    span_lint_and_then(
+                        cx,
+                        DERIVE_ORD_XOR_PARTIAL_ORD,
+                        span,
+                        mess,
+                        |diag| {
+                            if let Some(local_def_id) = impl_id.as_local() {
+                                let hir_id = cx.tcx.hir().as_local_hir_id(local_def_id);
+                                diag.span_note(
+                                    cx.tcx.hir().span(hir_id),
+                                    "`PartialOrd` implemented here"
+                                );
+                            }
+                        }
+                    );
+                }
+            });
+        }
+    }
+}
+
 /// 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 match_path(&trait_ref.path, &paths::CLONE_TRAIT) {
@@ -242,7 +354,9 @@ fn check_unsafe_derive_deserialize<'tcx>(
     if_chain! {
         if match_path(&trait_ref.path, &paths::SERDE_DESERIALIZE);
         if let ty::Adt(def, _) = ty.kind;
-        if def.did.is_local();
+        if let Some(local_def_id) = def.did.as_local();
+        let adt_hir_id = cx.tcx.hir().as_local_hir_id(local_def_id);
+        if !is_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id);
         if cx.tcx.inherent_impls(def.did)
             .iter()
             .map(|imp_did| item_from_def_id(cx, *imp_did))
diff --git a/src/tools/clippy/clippy_lints/src/double_comparison.rs b/src/tools/clippy/clippy_lints/src/double_comparison.rs
index 5d16192b754..bae7c4647d4 100644
--- a/src/tools/clippy/clippy_lints/src/double_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/double_comparison.rs
@@ -60,7 +60,7 @@ impl<'tcx> DoubleComparisons {
                     cx,
                     DOUBLE_COMPARISONS,
                     span,
-                    "This binary expression can be simplified",
+                    "this binary expression can be simplified",
                     "try",
                     sugg,
                     applicability,
diff --git a/src/tools/clippy/clippy_lints/src/double_parens.rs b/src/tools/clippy/clippy_lints/src/double_parens.rs
index 1eb380a22cc..abbcaf43f41 100644
--- a/src/tools/clippy/clippy_lints/src/double_parens.rs
+++ b/src/tools/clippy/clippy_lints/src/double_parens.rs
@@ -45,15 +45,12 @@ impl EarlyLintPass for DoubleParens {
             return;
         }
 
+        let msg: &str = "consider removing unnecessary double parentheses";
+
         match expr.kind {
             ExprKind::Paren(ref in_paren) => match in_paren.kind {
                 ExprKind::Paren(_) | ExprKind::Tup(_) => {
-                    span_lint(
-                        cx,
-                        DOUBLE_PARENS,
-                        expr.span,
-                        "Consider removing unnecessary double parentheses",
-                    );
+                    span_lint(cx, DOUBLE_PARENS, expr.span, &msg);
                 },
                 _ => {},
             },
@@ -61,12 +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,
-                            "Consider removing unnecessary double parentheses",
-                        );
+                        span_lint(cx, DOUBLE_PARENS, param.span, &msg);
                     }
                 }
             },
@@ -74,12 +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,
-                            "Consider removing unnecessary double parentheses",
-                        );
+                        span_lint(cx, DOUBLE_PARENS, param.span, &msg);
                     }
                 }
             },
diff --git a/src/tools/clippy/clippy_lints/src/drop_bounds.rs b/src/tools/clippy/clippy_lints/src/drop_bounds.rs
index 4afbd1ed0e5..ec3b6afa630 100644
--- a/src/tools/clippy/clippy_lints/src/drop_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/drop_bounds.rs
@@ -33,11 +33,11 @@ declare_clippy_lint! {
     /// ```
     pub DROP_BOUNDS,
     correctness,
-    "Bounds of the form `T: Drop` are useless"
+    "bounds of the form `T: Drop` are useless"
 }
 
-const DROP_BOUNDS_SUMMARY: &str = "Bounds of the form `T: Drop` are useless. \
-                                   Use `std::mem::needs_drop` to detect if a type has drop glue.";
+const DROP_BOUNDS_SUMMARY: &str = "bounds of the form `T: Drop` are useless, \
+                                   use `std::mem::needs_drop` to detect if a type has drop glue";
 
 declare_lint_pass!(DropBounds => [DROP_BOUNDS]);
 
diff --git a/src/tools/clippy/clippy_lints/src/functions.rs b/src/tools/clippy/clippy_lints/src/functions.rs
index 6a141f1fc78..ac1c7aa9bbb 100644
--- a/src/tools/clippy/clippy_lints/src/functions.rs
+++ b/src/tools/clippy/clippy_lints/src/functions.rs
@@ -294,7 +294,8 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
                 let body = cx.tcx.hir().body(eid);
                 Self::check_raw_ptr(cx, sig.header.unsafety, &sig.decl, body, item.hir_id);
 
-                if attr.is_none() && cx.access_levels.is_exported(item.hir_id) && !is_proc_macro(cx.sess(), &item.attrs) {
+                if attr.is_none() && cx.access_levels.is_exported(item.hir_id) && !is_proc_macro(cx.sess(), &item.attrs)
+                {
                     check_must_use_candidate(
                         cx,
                         &sig.decl,
@@ -373,7 +374,7 @@ impl<'tcx> Functions {
         }
 
         if line_count > self.max_lines {
-            span_lint(cx, TOO_MANY_LINES, span, "This function has a large number of lines.")
+            span_lint(cx, TOO_MANY_LINES, span, "this function has a large number of lines")
         }
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index f371942dbee..6ad525d7620 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -250,6 +250,7 @@ mod mut_mut;
 mod mut_reference;
 mod mutable_debug_assertion;
 mod mutex_atomic;
+mod needless_arbitrary_self_type;
 mod needless_bool;
 mod needless_borrow;
 mod needless_borrowed_ref;
@@ -288,6 +289,7 @@ mod serde_api;
 mod shadow;
 mod single_component_path_imports;
 mod slow_vector_initialization;
+mod stable_sort_primitive;
 mod strings;
 mod suspicious_trait_impl;
 mod swap;
@@ -322,10 +324,6 @@ mod zero_div_zero;
 
 pub use crate::utils::conf::Conf;
 
-mod reexport {
-    pub use rustc_span::Symbol as Name;
-}
-
 /// Register all pre expansion lints
 ///
 /// Pre-expansion lints run before any macro expansion has happened.
@@ -513,6 +511,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &default_trait_access::DEFAULT_TRAIT_ACCESS,
         &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,
         &doc::DOC_MARKDOWN,
@@ -610,6 +609,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &loops::NEEDLESS_COLLECT,
         &loops::NEEDLESS_RANGE_LOOP,
         &loops::NEVER_LOOP,
+        &loops::SAME_ITEM_PUSH,
         &loops::WHILE_IMMUTABLE_CONDITION,
         &loops::WHILE_LET_LOOP,
         &loops::WHILE_LET_ON_ITERATOR,
@@ -719,6 +719,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &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,
@@ -776,6 +777,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &shadow::SHADOW_UNRELATED,
         &single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
         &slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
+        &stable_sort_primitive::STABLE_SORT_PRIMITIVE,
         &strings::STRING_ADD,
         &strings::STRING_ADD_ASSIGN,
         &strings::STRING_LIT_AS_BYTES,
@@ -786,8 +788,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &tabs_in_doc_comments::TABS_IN_DOC_COMMENTS,
         &temporary_assignment::TEMPORARY_ASSIGNMENT,
         &to_digit_is_some::TO_DIGIT_IS_SOME,
+        &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,
@@ -1027,6 +1031,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_early_pass(|| box items_after_statements::ItemsAfterStatements);
     store.register_early_pass(|| box precedence::Precedence);
     store.register_early_pass(|| box needless_continue::NeedlessContinue);
+    store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType);
     store.register_early_pass(|| box redundant_static_lifetimes::RedundantStaticLifetimes);
     store.register_late_pass(|| box cargo_common_metadata::CargoCommonMetadata);
     store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions);
@@ -1078,6 +1083,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box macro_use::MacroUseImports::default());
     store.register_late_pass(|| box map_identity::MapIdentity);
     store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch);
+    store.register_late_pass(|| box stable_sort_primitive::StableSortPrimitive);
     store.register_late_pass(|| box repeat_once::RepeatOnce);
 
     store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
@@ -1174,6 +1180,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&ranges::RANGE_PLUS_ONE),
         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(&trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF),
         LintId::of(&types::CAST_LOSSLESS),
@@ -1230,6 +1237,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         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(&doc::MISSING_SAFETY_DOC),
         LintId::of(&doc::NEEDLESS_DOCTEST_MAIN),
         LintId::of(&double_comparison::DOUBLE_COMPARISONS),
@@ -1292,6 +1300,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         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::WHILE_IMMUTABLE_CONDITION),
         LintId::of(&loops::WHILE_LET_LOOP),
         LintId::of(&loops::WHILE_LET_ON_ITERATOR),
@@ -1368,6 +1377,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&mut_key::MUTABLE_KEY_TYPE),
         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),
@@ -1408,6 +1418,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&serde_api::SERDE_API_MISUSE),
         LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
         LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
+        LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE),
         LintId::of(&strings::STRING_LIT_AS_BYTES),
         LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
         LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
@@ -1417,6 +1428,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT),
         LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME),
         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),
@@ -1493,6 +1505,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         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),
@@ -1598,6 +1611,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         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),
@@ -1617,6 +1631,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         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),
@@ -1648,6 +1663,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         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_bounds::DROP_BOUNDS),
         LintId::of(&drop_forget_ref::DROP_COPY),
         LintId::of(&drop_forget_ref::DROP_REF),
@@ -1723,6 +1739,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         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),
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 168f9f953e4..4df6827d77f 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -13,9 +13,8 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::map::Map;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
-use rustc_span::symbol::kw;
+use rustc_span::symbol::{kw, Symbol};
 
-use crate::reexport::Name;
 use crate::utils::{in_macro, last_path_segment, span_lint, trait_ref_of_method};
 
 declare_clippy_lint! {
@@ -113,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
 enum RefLt {
     Unnamed,
     Static,
-    Named(Name),
+    Named(Symbol),
 }
 
 fn check_fn_inner<'tcx>(
@@ -456,7 +455,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, where_clause: &'tcx WhereCl
 }
 
 struct LifetimeChecker {
-    map: FxHashMap<Name, Span>,
+    map: FxHashMap<Symbol, Span>,
 }
 
 impl<'tcx> Visitor<'tcx> for LifetimeChecker {
diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs
index 7e3876ff49b..8352a8a3d2c 100644
--- a/src/tools/clippy/clippy_lints/src/loops.rs
+++ b/src/tools/clippy/clippy_lints/src/loops.rs
@@ -1,14 +1,14 @@
 use crate::consts::constant;
-use crate::reexport::Name;
 use crate::utils::paths;
+use crate::utils::sugg::Sugg;
 use crate::utils::usage::{is_unused, mutated_variables};
 use crate::utils::{
     get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait,
-    is_integer_const, is_no_std_crate, is_refutable, last_path_segment, match_trait_method, match_type, match_var,
-    multispan_sugg, snippet, snippet_opt, snippet_with_applicability, span_lint, span_lint_and_help,
-    span_lint_and_sugg, span_lint_and_then, SpanlessEq,
+    is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item, last_path_segment, match_trait_method,
+    match_type, match_var, multispan_sugg, qpath_res, snippet, snippet_opt, snippet_with_applicability,
+    snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg,
+    SpanlessEq,
 };
-use crate::utils::{is_type_diagnostic_item, qpath_res, sugg};
 use if_chain::if_chain;
 use rustc_ast::ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -17,7 +17,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{walk_block, walk_expr, walk_pat, walk_stmt, NestedVisitorMap, Visitor};
 use rustc_hir::{
     def_id, BinOpKind, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, GenericArg, HirId, InlineAsmOperand,
-    LoopSource, MatchSource, Mutability, Node, Pat, PatKind, QPath, Stmt, StmtKind,
+    Local, LoopSource, MatchSource, Mutability, Node, Pat, PatKind, QPath, Stmt, StmtKind,
 };
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -27,7 +27,7 @@ use rustc_middle::middle::region;
 use rustc_middle::ty::{self, Ty, TyS};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
-use rustc_span::symbol::Symbol;
+use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 use std::iter::{once, Iterator};
 use std::mem;
@@ -420,6 +420,39 @@ declare_clippy_lint! {
     "variables used within while expression are not mutated in the body"
 }
 
+declare_clippy_lint! {
+    /// **What it does:** Checks whether a for loop is being used to push a constant
+    /// value into a Vec.
+    ///
+    /// **Why is this bad?** This kind of operation can be expressed more succinctly with
+    /// `vec![item;SIZE]` or `vec.resize(NEW_SIZE, item)` and using these alternatives may also
+    /// have better performance.
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let item1 = 2;
+    /// let item2 = 3;
+    /// let mut vec: Vec<u8> = Vec::new();
+    /// for _ in 0..20 {
+    ///    vec.push(item1);
+    /// }
+    /// for _ in 0..30 {
+    ///     vec.push(item2);
+    /// }
+    /// ```
+    /// could be written as
+    /// ```rust
+    /// let item1 = 2;
+    /// let item2 = 3;
+    /// let mut vec: Vec<u8> = vec![item1; 20];
+    /// vec.resize(20 + 30, item2);
+    /// ```
+    pub SAME_ITEM_PUSH,
+    style,
+    "the same item is pushed inside of a for loop"
+}
+
 declare_lint_pass!(Loops => [
     MANUAL_MEMCPY,
     NEEDLESS_RANGE_LOOP,
@@ -436,6 +469,7 @@ declare_lint_pass!(Loops => [
     NEVER_LOOP,
     MUT_RANGE_BOUND,
     WHILE_IMMUTABLE_CONDITION,
+    SAME_ITEM_PUSH,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Loops {
@@ -741,6 +775,7 @@ fn check_for_loop<'tcx>(
     check_for_loop_over_map_kv(cx, pat, arg, body, expr);
     check_for_mut_range_bound(cx, arg, body);
     detect_manual_memcpy(cx, pat, arg, body, expr);
+    detect_same_item_push(cx, pat, arg, body, expr);
 }
 
 fn same_var<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, var: HirId) -> bool {
@@ -1017,6 +1052,117 @@ fn detect_manual_memcpy<'tcx>(
     }
 }
 
+// Scans the body of the for loop and determines whether lint should be given
+struct SameItemPushVisitor<'a, 'tcx> {
+    should_lint: 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>,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> {
+    type Map = Map<'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::Block(block, _) => self.visit_block(block),
+            _ => {},
+        }
+    }
+
+    fn visit_block(&mut self, b: &'tcx Block<'_>) {
+        for stmt in b.stmts.iter() {
+            self.visit_stmt(stmt);
+        }
+    }
+
+    fn visit_stmt(&mut self, s: &'tcx Stmt<'_>) {
+        let vec_push_option = get_vec_push(self.cx, s);
+        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),
+                _ => {},
+            }
+        } else {
+            // Current statement is a push ...check whether another
+            // push had been previously done
+            if self.vec_push.is_none() {
+                self.vec_push = vec_push_option;
+            } else {
+                // There are multiple pushes ... don't lint
+                self.should_lint = false;
+            }
+        }
+    }
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::None
+    }
+}
+
+// Given some statement, determine if that statement is a push on a Vec. If it is, return
+// the Vec being pushed into and the item being pushed
+fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> {
+    if_chain! {
+            // Extract method being called
+            if let StmtKind::Semi(semi_stmt) = &stmt.kind;
+            if let ExprKind::MethodCall(path, _, args, _) = &semi_stmt.kind;
+            // Figure out the parameters for the method call
+            if let Some(self_expr) = args.get(0);
+            if let Some(pushed_item) = args.get(1);
+            // Check that the method being called is push() on a Vec
+            if match_type(cx, cx.typeck_results().expr_ty(self_expr), &paths::VEC);
+            if path.ident.name.as_str() == "push";
+            then {
+                return Some((self_expr, pushed_item))
+            }
+    }
+    None
+}
+
+/// Detects for loop pushing the same item into a Vec
+fn detect_same_item_push<'tcx>(
+    cx: &LateContext<'tcx>,
+    pat: &'tcx Pat<'_>,
+    _: &'tcx Expr<'_>,
+    body: &'tcx Expr<'_>,
+    _: &'tcx Expr<'_>,
+) {
+    // Determine whether it is safe to lint the body
+    let mut same_item_push_visitor = SameItemPushVisitor {
+        should_lint: true,
+        vec_push: None,
+        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 {
+            // Make sure that the push does not involve possibly mutating values
+            if mutated_variables(pushed_item, cx).map_or(false, |mutvars| mutvars.is_empty()) {
+                if let PatKind::Wild = pat.kind {
+                    let vec_str = snippet_with_macro_callsite(cx, vec.span, "");
+                    let item_str = snippet_with_macro_callsite(cx, pushed_item.span, "");
+
+                    span_lint_and_help(
+                        cx,
+                        SAME_ITEM_PUSH,
+                        vec.span,
+                        "it looks like the same item is being pushed into this Vec",
+                        None,
+                        &format!(
+                            "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})",
+                            item_str, vec_str, item_str
+                        ),
+                    )
+                }
+            }
+        }
+    }
+}
+
 /// Checks for looping over a range and then indexing a sequence with it.
 /// The iteratee must be a range literal.
 #[allow(clippy::too_many_lines)]
@@ -1184,7 +1330,7 @@ fn check_for_loop_range<'tcx>(
     }
 }
 
-fn is_len_call(expr: &Expr<'_>, var: Name) -> bool {
+fn is_len_call(expr: &Expr<'_>, var: Symbol) -> bool {
     if_chain! {
         if let ExprKind::MethodCall(ref method, _, ref len_args, _) = expr.kind;
         if len_args.len() == 1;
@@ -1640,15 +1786,15 @@ struct VarVisitor<'a, 'tcx> {
     /// var name to look for as index
     var: HirId,
     /// indexed variables that are used mutably
-    indexed_mut: FxHashSet<Name>,
+    indexed_mut: FxHashSet<Symbol>,
     /// indirectly indexed variables (`v[(i + 4) % N]`), the extend is `None` for global
-    indexed_indirectly: FxHashMap<Name, Option<region::Scope>>,
+    indexed_indirectly: FxHashMap<Symbol, Option<region::Scope>>,
     /// subset of `indexed` of vars that are indexed directly: `v[i]`
     /// this will not contain cases like `v[calc_index(i)]` or `v[(i + 4) % N]`
-    indexed_directly: FxHashMap<Name, (Option<region::Scope>, Ty<'tcx>)>,
+    indexed_directly: FxHashMap<Symbol, (Option<region::Scope>, Ty<'tcx>)>,
     /// Any names that are used outside an index operation.
     /// Used to detect things like `&mut vec` used together with `vec[i]`
-    referenced: FxHashSet<Name>,
+    referenced: FxHashSet<Symbol>,
     /// has the loop variable been used in expressions other than the index of
     /// an index op?
     nonindex: bool,
@@ -2004,7 +2150,7 @@ struct InitializeVisitor<'a, 'tcx> {
     end_expr: &'tcx Expr<'tcx>, // the for loop. Stop scanning here.
     var_id: HirId,
     state: VarState,
-    name: Option<Name>,
+    name: Option<Symbol>,
     depth: u32, // depth of conditional expressions
     past_loop: bool,
 }
@@ -2167,7 +2313,7 @@ use self::Nesting::{LookFurther, RuledOut, Unknown};
 
 struct LoopNestVisitor {
     hir_id: HirId,
-    iterator: Name,
+    iterator: Symbol,
     nesting: Nesting,
 }
 
@@ -2218,7 +2364,7 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor {
     }
 }
 
-fn path_name(e: &Expr<'_>) -> Option<Name> {
+fn path_name(e: &Expr<'_>) -> Option<Symbol> {
     if let ExprKind::Path(QPath::Resolved(_, ref path)) = e.kind {
         let segments = &path.segments;
         if segments.len() == 1 {
@@ -2358,6 +2504,10 @@ impl<'a, 'tcx> Visitor<'tcx> for VarCollectorVisitor<'a, 'tcx> {
 const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed";
 
 fn check_needless_collect<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
+    check_needless_collect_direct_usage(expr, cx);
+    check_needless_collect_indirect_usage(expr, cx);
+}
+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;
@@ -2371,7 +2521,7 @@ fn check_needless_collect<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
                 match_type(cx, ty, &paths::BTREEMAP) ||
                 is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) {
                 if method.ident.name == sym!(len) {
-                    let span = shorten_span(expr, sym!(collect));
+                    let span = shorten_needless_collect_span(expr);
                     span_lint_and_sugg(
                         cx,
                         NEEDLESS_COLLECT,
@@ -2383,20 +2533,20 @@ fn check_needless_collect<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
                     );
                 }
                 if method.ident.name == sym!(is_empty) {
-                    let span = shorten_span(expr, sym!(iter));
+                    let span = shorten_needless_collect_span(expr);
                     span_lint_and_sugg(
                         cx,
                         NEEDLESS_COLLECT,
                         span,
                         NEEDLESS_COLLECT_MSG,
                         "replace with",
-                        "get(0).is_none()".to_string(),
+                        "next().is_none()".to_string(),
                         Applicability::MachineApplicable,
                     );
                 }
                 if method.ident.name == sym!(contains) {
                     let contains_arg = snippet(cx, args[1].span, "??");
-                    let span = shorten_span(expr, sym!(collect));
+                    let span = shorten_needless_collect_span(expr);
                     span_lint_and_then(
                         cx,
                         NEEDLESS_COLLECT,
@@ -2425,13 +2575,164 @@ fn check_needless_collect<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
     }
 }
 
-fn shorten_span(expr: &Expr<'_>, target_fn_name: Symbol) -> Span {
-    let mut current_expr = expr;
-    while let ExprKind::MethodCall(ref path, ref span, ref args, _) = current_expr.kind {
-        if path.ident.name == target_fn_name {
+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_chain! {
+                if let StmtKind::Local(
+                    Local { pat: Pat { kind: PatKind::Binding(_, _, ident, .. ), .. },
+                    init: Some(ref init_expr), .. }
+                ) = stmt.kind;
+                if let ExprKind::MethodCall(ref method_name, _, &[ref iter_source], ..) = init_expr.kind;
+                if method_name.ident.name == sym!(collect) && match_trait_method(cx, &init_expr, &paths::ITERATOR);
+                if let Some(ref 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;
+                then {
+                    // Suggest replacing iter_call with iter_replacement, and removing stmt
+                    let iter_call = &iter_calls[0];
+                    span_lint_and_then(
+                        cx,
+                        NEEDLESS_COLLECT,
+                        stmt.span.until(iter_call.span),
+                        NEEDLESS_COLLECT_MSG,
+                        |diag| {
+                            let iter_replacement = format!("{}{}", Sugg::hir(cx, iter_source, ".."), iter_call.get_iter_method(cx));
+                            diag.multipart_suggestion(
+                                iter_call.get_suggestion_text(),
+                                vec![
+                                    (stmt.span, String::new()),
+                                    (iter_call.span, iter_replacement)
+                                ],
+                                Applicability::MachineApplicable,// MaybeIncorrect,
+                            ).emit();
+                        },
+                    );
+                }
+            }
+        }
+    }
+}
+
+struct IterFunction {
+    func: IterFunctionKind,
+    span: Span,
+}
+impl IterFunction {
+    fn get_iter_method(&self, cx: &LateContext<'_>) -> String {
+        match &self.func {
+            IterFunctionKind::IntoIter => String::new(),
+            IterFunctionKind::Len => String::from(".count()"),
+            IterFunctionKind::IsEmpty => String::from(".next().is_none()"),
+            IterFunctionKind::Contains(span) => format!(".any(|x| x == {})", snippet(cx, *span, "..")),
+        }
+    }
+    fn get_suggestion_text(&self) -> &'static str {
+        match &self.func {
+            IterFunctionKind::IntoIter => {
+                "Use the original Iterator instead of collecting it and then producing a new one"
+            },
+            IterFunctionKind::Len => {
+                "Take the original Iterator's count instead of collecting it and finding the length"
+            },
+            IterFunctionKind::IsEmpty => {
+                "Check if the original Iterator has anything instead of collecting it and seeing if it's empty"
+            },
+            IterFunctionKind::Contains(_) => {
+                "Check if the original Iterator contains an element instead of collecting then checking"
+            },
+        }
+    }
+}
+enum IterFunctionKind {
+    IntoIter,
+    Len,
+    IsEmpty,
+    Contains(Span),
+}
+
+struct IterFunctionVisitor {
+    uses: Vec<IterFunction>,
+    seen_other: bool,
+    target: Ident,
+}
+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 &[name] = &path.segments;
+            if name.ident == self.target;
+            then {
+                let len = sym!(len);
+                let is_empty = sym!(is_empty);
+                let contains = sym!(contains);
+                match method_name.ident.name {
+                    sym::into_iter => self.uses.push(
+                        IterFunction { func: IterFunctionKind::IntoIter, span: expr.span }
+                    ),
+                    name if name == len => self.uses.push(
+                        IterFunction { func: IterFunctionKind::Len, span: expr.span }
+                    ),
+                    name if name == is_empty => self.uses.push(
+                        IterFunction { func: IterFunctionKind::IsEmpty, span: expr.span }
+                    ),
+                    name if name == contains => self.uses.push(
+                        IterFunction { func: IterFunctionKind::Contains(args[1].span), span: expr.span }
+                    ),
+                    _ => self.seen_other = true,
+                }
+                return
+            }
+        }
+        // Check if the collection is used for anything else
+        if_chain! {
+            if let Expr { kind: ExprKind::Path(QPath::Resolved(_, ref path)), .. } = expr;
+            if let &[name] = &path.segments;
+            if name.ident == self.target;
+            then {
+                self.seen_other = true;
+            } else {
+                walk_expr(self, expr);
+            }
+        }
+    }
+
+    type Map = Map<'tcx>;
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::None
+    }
+}
+
+/// Detect the occurences of calls to `iter` or `into_iter` for the
+/// given identifier
+fn detect_iter_and_into_iters<'tcx>(block: &'tcx Block<'tcx>, identifier: Ident) -> Option<Vec<IterFunction>> {
+    let mut visitor = IterFunctionVisitor {
+        uses: Vec::new(),
+        target: identifier,
+        seen_other: false,
+    };
+    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());
         }
-        current_expr = &args[0];
     }
-    unreachable!()
+    unreachable!();
 }
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
index c19fb148cda..864d1ea87f5 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -4,8 +4,8 @@ use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
-    AsyncGeneratorKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericBound, HirId, IsAsync,
-    ItemKind, TraitRef, Ty, TyKind, TypeBindingKind,
+    AsyncGeneratorKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, HirId,
+    IsAsync, ItemKind, LifetimeName, TraitRef, Ty, TyKind, TypeBindingKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -27,8 +27,6 @@ declare_clippy_lint! {
     /// ```
     /// Use instead:
     /// ```rust
-    /// use std::future::Future;
-    ///
     /// async fn foo() -> i32 { 42 }
     /// ```
     pub MANUAL_ASYNC_FN,
@@ -53,8 +51,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
             if let IsAsync::NotAsync = header.asyncness;
             // Check that this function returns `impl Future`
             if let FnRetTy::Return(ret_ty) = decl.output;
-            if let Some(trait_ref) = future_trait_ref(cx, ret_ty);
+            if let Some((trait_ref, output_lifetimes)) = future_trait_ref(cx, ret_ty);
             if let Some(output) = future_output_ty(trait_ref);
+            if captures_all_lifetimes(decl.inputs, &output_lifetimes);
             // Check that the body of the function consists of one async block
             if let ExprKind::Block(block, _) = body.value.kind;
             if block.stmts.is_empty();
@@ -97,16 +96,35 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
     }
 }
 
-fn future_trait_ref<'tcx>(cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) -> Option<&'tcx TraitRef<'tcx>> {
+fn future_trait_ref<'tcx>(
+    cx: &LateContext<'tcx>,
+    ty: &'tcx Ty<'tcx>,
+) -> Option<(&'tcx TraitRef<'tcx>, Vec<LifetimeName>)> {
     if_chain! {
-        if let TyKind::OpaqueDef(item_id, _) = ty.kind;
+        if let TyKind::OpaqueDef(item_id, bounds) = ty.kind;
         let item = cx.tcx.hir().item(item_id.id);
         if let ItemKind::OpaqueTy(opaque) = &item.kind;
-        if opaque.bounds.len() == 1;
-        if let GenericBound::Trait(poly, _) = &opaque.bounds[0];
-        if poly.trait_ref.trait_def_id() == cx.tcx.lang_items().future_trait();
+        if let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| {
+            if let GenericBound::Trait(poly, _) = bound {
+                Some(&poly.trait_ref)
+            } else {
+                None
+            }
+        });
+        if trait_ref.trait_def_id() == cx.tcx.lang_items().future_trait();
         then {
-            return Some(&poly.trait_ref);
+            let output_lifetimes = bounds
+                .iter()
+                .filter_map(|bound| {
+                    if let GenericArg::Lifetime(lt) = bound {
+                        Some(lt.name)
+                    } else {
+                        None
+                    }
+                })
+                .collect();
+
+            return Some((trait_ref, output_lifetimes));
         }
     }
 
@@ -129,6 +147,29 @@ fn future_output_ty<'tcx>(trait_ref: &'tcx TraitRef<'tcx>) -> Option<&'tcx Ty<'t
     None
 }
 
+fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName]) -> bool {
+    let input_lifetimes: Vec<LifetimeName> = inputs
+        .iter()
+        .filter_map(|ty| {
+            if let TyKind::Rptr(lt, _) = ty.kind {
+                Some(lt.name)
+            } else {
+                None
+            }
+        })
+        .collect();
+
+    // The lint should trigger in one of these cases:
+    // - There are no input lifetimes
+    // - There's only one output lifetime bound using `+ '_`
+    // - All input lifetimes are explicitly bound to the output
+    input_lifetimes.is_empty()
+        || (output_lifetimes.len() == 1 && matches!(output_lifetimes[0], LifetimeName::Underscore))
+        || input_lifetimes
+            .iter()
+            .all(|in_lt| output_lifetimes.iter().any(|out_lt| in_lt == out_lt))
+}
+
 fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> {
     if_chain! {
         if let Some(block_expr) = block.expr;
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 2c70183d876..570ae66d595 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -1052,8 +1052,7 @@ declare_clippy_lint! {
     ///
     /// **Why is this bad?** Readability.
     ///
-    /// **Known problems:** False positive in pattern guards. Will be resolved once
-    /// non-lexical lifetimes are stable.
+    /// **Known problems:** None.
     ///
     /// **Example:**
     /// ```rust
@@ -1408,7 +1407,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             ["nth", "iter_mut"] => lint_iter_nth(cx, expr, &arg_lists, true),
             ["nth", ..] => lint_iter_nth_zero(cx, expr, arg_lists[0]),
             ["step_by", ..] => lint_step_by(cx, expr, arg_lists[0]),
-            ["next", "skip"] => lint_iter_skip_next(cx, expr),
+            ["next", "skip"] => lint_iter_skip_next(cx, expr, arg_lists[1]),
             ["collect", "cloned"] => lint_iter_cloned_collect(cx, expr, arg_lists[1]),
             ["as_ref"] => lint_asref(cx, expr, "as_ref", arg_lists[0]),
             ["as_mut"] => lint_asref(cx, expr, "as_mut", arg_lists[0]),
@@ -2433,17 +2432,21 @@ fn lint_get_unwrap<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args:
     );
 }
 
-fn lint_iter_skip_next(cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
+fn lint_iter_skip_next(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[hir::Expr<'_>]) {
     // lint if caller of skip is an Iterator
     if match_trait_method(cx, expr, &paths::ITERATOR) {
-        span_lint_and_help(
-            cx,
-            ITER_SKIP_NEXT,
-            expr.span,
-            "called `skip(x).next()` on an iterator",
-            None,
-            "this is more succinctly expressed by calling `nth(x)`",
-        );
+        if let [caller, n] = skip_args {
+            let hint = format!(".nth({})", snippet(cx, n.span, ".."));
+            span_lint_and_sugg(
+                cx,
+                ITER_SKIP_NEXT,
+                expr.span.trim_start(caller.span).unwrap(),
+                "called `skip(x).next()` on an iterator",
+                "use `nth` instead",
+                hint,
+                Applicability::MachineApplicable,
+            );
+        }
     }
 }
 
@@ -2565,17 +2568,34 @@ fn lint_ok_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ok_args: &[hir::Ex
 fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_args: &'tcx [hir::Expr<'_>]) {
     // lint if caller of `.map().flatten()` is an Iterator
     if match_trait_method(cx, expr, &paths::ITERATOR) {
-        let msg = "called `map(..).flatten()` on an `Iterator`. \
-                    This is more succinctly expressed by calling `.flat_map(..)`";
-        let self_snippet = snippet(cx, map_args[0].span, "..");
+        let map_closure_ty = cx.typeck_results().expr_ty(&map_args[1]);
+        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 {
+                    ty::Closure(_, substs) => substs.as_closure().sig(),
+                    _ => map_closure_ty.fn_sig(cx.tcx),
+                };
+                let map_closure_return_ty = cx.tcx.erase_late_bound_regions(&map_closure_sig.output());
+                is_type_diagnostic_item(cx, map_closure_return_ty, sym!(option_type))
+            },
+            _ => false,
+        };
+
+        let method_to_use = if is_map_to_option {
+            // `(...).map(...)` has type `impl Iterator<Item=Option<...>>
+            "filter_map"
+        } else {
+            // `(...).map(...)` has type `impl Iterator<Item=impl Iterator<...>>
+            "flat_map"
+        };
         let func_snippet = snippet(cx, map_args[1].span, "..");
-        let hint = format!("{0}.flat_map({1})", self_snippet, func_snippet);
+        let hint = format!(".{0}({1})", method_to_use, func_snippet);
         span_lint_and_sugg(
             cx,
             MAP_FLATTEN,
-            expr.span,
-            msg,
-            "try using `flat_map` instead",
+            expr.span.with_lo(map_args[0].span.hi()),
+            "called `map(..).flatten()` on an `Iterator`",
+            &format!("try using `{}` instead", method_to_use),
             hint,
             Applicability::MachineApplicable,
         );
@@ -2583,16 +2603,13 @@ fn lint_map_flatten<'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 msg = "called `map(..).flatten()` on an `Option`. \
-                    This is more succinctly expressed by calling `.and_then(..)`";
-        let self_snippet = snippet(cx, map_args[0].span, "..");
         let func_snippet = snippet(cx, map_args[1].span, "..");
-        let hint = format!("{0}.and_then({1})", self_snippet, func_snippet);
+        let hint = format!(".and_then({})", func_snippet);
         span_lint_and_sugg(
             cx,
             MAP_FLATTEN,
-            expr.span,
-            msg,
+            expr.span.with_lo(map_args[0].span.hi()),
+            "called `map(..).flatten()` on an `Option`",
             "try using `and_then` instead",
             hint,
             Applicability::MachineApplicable,
diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs
index dae39aaf5e2..004dd50a31b 100644
--- a/src/tools/clippy/clippy_lints/src/minmax.rs
+++ b/src/tools/clippy/clippy_lints/src/minmax.rs
@@ -1,5 +1,6 @@
 use crate::consts::{constant_simple, Constant};
-use crate::utils::{match_def_path, paths, span_lint};
+use crate::utils::{match_def_path, match_trait_method, paths, span_lint};
+use if_chain::if_chain;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -18,6 +19,10 @@ declare_clippy_lint! {
     /// ```ignore
     /// min(0, max(100, x))
     /// ```
+    /// or
+    /// ```ignore
+    /// x.max(100).min(0)
+    /// ```
     /// It will always be equal to `0`. Probably the author meant to clamp the value
     /// between 0 and 100, but has erroneously swapped `min` and `max`.
     pub MIN_MAX,
@@ -60,25 +65,43 @@ enum MinMax {
 }
 
 fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Constant, &'a Expr<'a>)> {
-    if let ExprKind::Call(ref path, ref args) = expr.kind {
-        if let ExprKind::Path(ref qpath) = path.kind {
-            cx.typeck_results()
-                .qpath_res(qpath, path.hir_id)
-                .opt_def_id()
-                .and_then(|def_id| {
-                    if match_def_path(cx, def_id, &paths::CMP_MIN) {
-                        fetch_const(cx, args, MinMax::Min)
-                    } else if match_def_path(cx, def_id, &paths::CMP_MAX) {
+    match expr.kind {
+        ExprKind::Call(ref path, ref args) => {
+            if let ExprKind::Path(ref qpath) = path.kind {
+                cx.typeck_results()
+                    .qpath_res(qpath, path.hir_id)
+                    .opt_def_id()
+                    .and_then(|def_id| {
+                        if match_def_path(cx, def_id, &paths::CMP_MIN) {
+                            fetch_const(cx, args, MinMax::Min)
+                        } else if match_def_path(cx, def_id, &paths::CMP_MAX) {
+                            fetch_const(cx, args, MinMax::Max)
+                        } else {
+                            None
+                        }
+                    })
+            } else {
+                None
+            }
+        },
+        ExprKind::MethodCall(ref path, _, ref args, _) => {
+            if_chain! {
+                if let [obj, _] = args;
+                if cx.typeck_results().expr_ty(obj).is_floating_point() || match_trait_method(cx, expr, &paths::ORD);
+                then {
+                    if path.ident.as_str() == sym!(max).as_str() {
                         fetch_const(cx, args, MinMax::Max)
+                    } else if path.ident.as_str() == sym!(min).as_str() {
+                        fetch_const(cx, args, MinMax::Min)
                     } else {
                         None
                     }
-                })
-        } else {
-            None
-        }
-    } else {
-        None
+                } else {
+                    None
+                }
+            }
+        },
+        _ => None,
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/misc_early.rs b/src/tools/clippy/clippy_lints/src/misc_early.rs
index 29aba7c1218..02789735c17 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early.rs
@@ -271,7 +271,7 @@ impl EarlyLintPass for MiscEarlyLints {
                         cx,
                         BUILTIN_TYPE_SHADOW,
                         param.ident.span,
-                        &format!("This generic shadows the built-in type `{}`", name),
+                        &format!("this generic shadows the built-in type `{}`", name),
                     );
                 }
             }
@@ -298,9 +298,9 @@ impl EarlyLintPass for MiscEarlyLints {
                     cx,
                     UNNEEDED_FIELD_PATTERN,
                     pat.span,
-                    "All the struct fields are matched to a wildcard pattern, consider using `..`.",
+                    "all the struct fields are matched to a wildcard pattern, consider using `..`",
                     None,
-                    &format!("Try with `{} {{ .. }}` instead", type_name),
+                    &format!("try with `{} {{ .. }}` instead", type_name),
                 );
                 return;
             }
@@ -313,7 +313,7 @@ impl EarlyLintPass for MiscEarlyLints {
                                 cx,
                                 UNNEEDED_FIELD_PATTERN,
                                 field.span,
-                                "You matched a field with a wildcard pattern. Consider using `..` instead",
+                                "you matched a field with a wildcard pattern, consider using `..` instead",
                             );
                         } else {
                             let mut normal = vec![];
@@ -333,10 +333,10 @@ impl EarlyLintPass for MiscEarlyLints {
                                 cx,
                                 UNNEEDED_FIELD_PATTERN,
                                 field.span,
-                                "You matched a field with a wildcard pattern. Consider using `..` \
+                                "you matched a field with a wildcard pattern, consider using `..` \
                                  instead",
                                 None,
-                                &format!("Try with `{} {{ {}, .. }}`", type_name, normal[..].join(", ")),
+                                &format!("try with `{} {{ {}, .. }}`", type_name, normal[..].join(", ")),
                             );
                         }
                     }
diff --git a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
new file mode 100644
index 00000000000..38bdd0f7ed2
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
@@ -0,0 +1,118 @@
+use crate::utils::span_lint_and_sugg;
+use if_chain::if_chain;
+use rustc_ast::ast::{BindingMode, Lifetime, Mutability, Param, PatKind, Path, TyKind};
+use rustc_errors::Applicability;
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::symbol::kw;
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// **What it does:** The lint checks for `self` in fn parameters that
+    /// specify the `Self`-type explicitly
+    /// **Why is this bad?** Increases the amount and decreases the readability of code
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    /// ```rust
+    /// enum ValType {
+    ///     I32,
+    ///     I64,
+    ///     F32,
+    ///     F64,
+    /// }
+    ///
+    /// impl ValType {
+    ///     pub fn bytes(self: Self) -> usize {
+    ///         match self {
+    ///             Self::I32 | Self::F32 => 4,
+    ///             Self::I64 | Self::F64 => 8,
+    ///         }
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// Could be rewritten as
+    ///
+    /// ```rust
+    /// enum ValType {
+    ///     I32,
+    ///     I64,
+    ///     F32,
+    ///     F64,
+    /// }
+    ///
+    /// impl ValType {
+    ///     pub fn bytes(self) -> usize {
+    ///         match self {
+    ///             Self::I32 | Self::F32 => 4,
+    ///             Self::I64 | Self::F64 => 8,
+    ///         }
+    ///     }
+    /// }
+    /// ```
+    pub NEEDLESS_ARBITRARY_SELF_TYPE,
+    complexity,
+    "type of `self` parameter is already by default `Self`"
+}
+
+declare_lint_pass!(NeedlessArbitrarySelfType => [NEEDLESS_ARBITRARY_SELF_TYPE]);
+
+enum Mode {
+    Ref(Option<Lifetime>),
+    Value,
+}
+
+fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mode: &Mode, mutbl: Mutability) {
+    if_chain! {
+        if let [segment] = &path.segments[..];
+        if segment.ident.name == kw::SelfUpper;
+        then {
+            let self_param = match (binding_mode, mutbl) {
+                (Mode::Ref(None), Mutability::Mut) => "&mut self".to_string(),
+                (Mode::Ref(Some(lifetime)), Mutability::Mut) => format!("&{} mut self", &lifetime.ident.name),
+                (Mode::Ref(None), Mutability::Not) => "&self".to_string(),
+                (Mode::Ref(Some(lifetime)), Mutability::Not) => format!("&{} self", &lifetime.ident.name),
+                (Mode::Value, Mutability::Mut) => "mut self".to_string(),
+                (Mode::Value, Mutability::Not) => "self".to_string(),
+            };
+
+            span_lint_and_sugg(
+                cx,
+                NEEDLESS_ARBITRARY_SELF_TYPE,
+                span,
+                "the type of the `self` parameter does not need to be arbitrary",
+                "consider to change this parameter to",
+                self_param,
+                Applicability::MachineApplicable,
+            )
+        }
+    }
+}
+
+impl EarlyLintPass for NeedlessArbitrarySelfType {
+    fn check_param(&mut self, cx: &EarlyContext<'_>, p: &Param) {
+        if !p.is_self() {
+            return;
+        }
+
+        match &p.ty.kind {
+            TyKind::Path(None, path) => {
+                if let PatKind::Ident(BindingMode::ByValue(mutbl), _, _) = p.pat.kind {
+                    check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl)
+                }
+            },
+            TyKind::Rptr(lifetime, mut_ty) => {
+                if_chain! {
+                if let TyKind::Path(None, path) = &mut_ty.ty.kind;
+                if let PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, _) = p.pat.kind;
+                    then {
+                        check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl)
+                    }
+                }
+            },
+            _ => {},
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs
index 8e44f2ec240..dc5aa669139 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs
@@ -243,7 +243,7 @@ fn check_comparison<'a, 'tcx>(
                         cx,
                         BOOL_COMPARISON,
                         e.span,
-                        "This comparison might be written more concisely",
+                        "this comparison might be written more concisely",
                         "try simplifying it as shown",
                         format!(
                             "{} != {}",
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 a7f7c97fc48..047a78b0878 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
@@ -40,9 +40,8 @@ declare_clippy_lint! {
     ///     assert_eq!(v.len(), 42);
     /// }
     /// ```
-    ///
+    /// should be
     /// ```rust
-    /// // should be
     /// fn foo(v: &[i32]) {
     ///     assert_eq!(v.len(), 42);
     /// }
@@ -159,26 +158,19 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                 }
             }
 
+            //
             // * Exclude a type that is specifically bounded by `Borrow`.
             // * Exclude a type whose reference also fulfills its bound. (e.g., `std::convert::AsRef`,
             //   `serde::Serialize`)
             let (implements_borrow_trait, all_borrowable_trait) = {
-                let preds = preds
-                    .iter()
-                    .filter(|t| t.self_ty() == ty)
-                    .collect::<Vec<_>>();
+                let preds = preds.iter().filter(|t| t.self_ty() == ty).collect::<Vec<_>>();
 
                 (
                     preds.iter().any(|t| t.def_id() == borrow_trait),
                     !preds.is_empty() && {
                         let ty_empty_region = cx.tcx.mk_imm_ref(cx.tcx.lifetimes.re_root_empty, ty);
                         preds.iter().all(|t| {
-                            let ty_params = t
-                                .trait_ref
-                                .substs
-                                .iter()
-                                .skip(1)
-                                .collect::<Vec<_>>();
+                            let ty_params = t.trait_ref.substs.iter().skip(1).collect::<Vec<_>>();
                             implements_trait(cx, ty_empty_region, t.def_id(), &ty_params)
                         })
                     },
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 95613a1b82e..4fb899125e8 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
@@ -79,10 +79,10 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd {
                         cx,
                         NEG_CMP_OP_ON_PARTIAL_ORD,
                         expr.span,
-                        "The use of negated comparison operators on partially ordered \
-                        types produces code that is hard to read and refactor. Please \
+                        "the use of negated comparison operators on partially ordered \
+                        types produces code that is hard to read and refactor, please \
                         consider using the `partial_cmp` method instead, to make it \
-                        clear that the two values could be incomparable."
+                        clear that the two values could be incomparable"
                     )
                 }
             }
diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
index 6b6c950e0ab..aa550510867 100644
--- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
@@ -47,7 +47,7 @@ fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) {
         if let Constant::Int(1) = consts::lit_to_constant(&l.node, cx.typeck_results().expr_ty_opt(lit));
         if cx.typeck_results().expr_ty(exp).is_integral();
         then {
-            span_lint(cx, NEG_MULTIPLY, span, "Negation by multiplying with `-1`");
+            span_lint(cx, NEG_MULTIPLY, span, "negation by multiplying with `-1`");
         }
     }
 }
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 4d4a9676654..3c041bac234 100644
--- a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs
+++ b/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs
@@ -42,13 +42,13 @@ impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional {
                 if let BinOpKind::Lt = op.node {
                     if let BinOpKind::Add = op2.node {
                         span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span,
-                            "You are trying to use classic C overflow conditions that will fail in Rust.");
+                            "you are trying to use classic C overflow conditions that will fail in Rust");
                     }
                 }
                 if let BinOpKind::Gt = op.node {
                     if let BinOpKind::Sub = op2.node {
                         span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span,
-                            "You are trying to use classic C underflow conditions that will fail in Rust.");
+                            "you are trying to use classic C underflow conditions that will fail in Rust");
                     }
                 }
             }
@@ -67,13 +67,13 @@ impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional {
                 if let BinOpKind::Gt = op.node {
                     if let BinOpKind::Add = op2.node {
                         span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span,
-                            "You are trying to use classic C overflow conditions that will fail in Rust.");
+                            "you are trying to use classic C overflow conditions that will fail in Rust");
                     }
                 }
                 if let BinOpKind::Lt = op.node {
                     if let BinOpKind::Sub = op2.node {
                         span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span,
-                            "You are trying to use classic C underflow conditions that will fail in Rust.");
+                            "you are trying to use classic C underflow conditions that will fail in Rust");
                     }
                 }
             }
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 66a145a7f14..b8583402928 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
@@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for PathBufPushOverwrite {
                     cx,
                     PATH_BUF_PUSH_OVERWRITE,
                     lit.span,
-                    "Calling `push` with '/' or '\\' (file system root) will overwrite the previous path definition",
+                    "calling `push` with '/' or '\\' (file system root) will overwrite the previous path definition",
                     "try",
                     format!("\"{}\"", pushed_path_lit.trim_start_matches(|c| c == '/' || c == '\\')),
                     Applicability::MachineApplicable,
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 7b6bd69ffca..460d631fab0 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -145,7 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
                     cx,
                     CMP_NULL,
                     expr.span,
-                    "Comparing with null is better expressed by the `.is_null()` method",
+                    "comparing with null is better expressed by the `.is_null()` method",
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index 4c1f2e8e01a..f88075798ca 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -160,7 +160,7 @@ impl<'tcx> LateLintPass<'tcx> for Ranges {
                          span_lint(cx,
                                    RANGE_ZIP_WITH_LEN,
                                    expr.span,
-                                   &format!("It is more idiomatic to use `{}.iter().enumerate()`",
+                                   &format!("it is more idiomatic to use `{}.iter().enumerate()`",
                                             snippet(cx, iter_args[0].span, "_")));
                     }
                 }
diff --git a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
index c6f57298c26..7bbcc67aa2d 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
@@ -86,13 +86,13 @@ impl EarlyLintPass for RedundantStaticLifetimes {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
         if !item.span.from_expansion() {
             if let ItemKind::Const(_, ref var_type, _) = item.kind {
-                self.visit_type(var_type, cx, "Constants have by default a `'static` lifetime");
+                self.visit_type(var_type, cx, "constants have by default a `'static` lifetime");
                 // Don't check associated consts because `'static` cannot be elided on those (issue
                 // #2438)
             }
 
             if let ItemKind::Static(ref var_type, _, _) = item.kind {
-                self.visit_type(var_type, cx, "Statics have by default a `'static` lifetime");
+                self.visit_type(var_type, cx, "statics have by default a `'static` lifetime");
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/reference.rs b/src/tools/clippy/clippy_lints/src/reference.rs
index fe457aad50e..3fda00403c6 100644
--- a/src/tools/clippy/clippy_lints/src/reference.rs
+++ b/src/tools/clippy/clippy_lints/src/reference.rs
@@ -92,7 +92,7 @@ impl EarlyLintPass for RefInDeref {
                     cx,
                     REF_IN_DEREF,
                     object.span,
-                    "Creating a reference that is immediately dereferenced.",
+                    "creating a reference that is immediately dereferenced",
                     "try this",
                     snippet_with_applicability(cx, inner.span, "_", &mut applicability).to_string(),
                     applicability,
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index 6f03e92bde3..2610157763a 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -1,4 +1,3 @@
-use crate::reexport::Name;
 use crate::utils::{contains_name, higher, iter_input_pats, snippet, span_lint_and_then};
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
@@ -10,6 +9,7 @@ use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
+use rustc_span::symbol::Symbol;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for bindings that shadow other bindings already in
@@ -123,7 +123,7 @@ fn check_fn<'tcx>(cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'_>, body: &'tcx Bo
     check_expr(cx, &body.value, &mut bindings);
 }
 
-fn check_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'_>, bindings: &mut Vec<(Name, Span)>) {
+fn check_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'_>, bindings: &mut Vec<(Symbol, Span)>) {
     let len = bindings.len();
     for stmt in block.stmts {
         match stmt.kind {
@@ -138,7 +138,7 @@ fn check_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'_>, bindings: &
     bindings.truncate(len);
 }
 
-fn check_local<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>, bindings: &mut Vec<(Name, Span)>) {
+fn check_local<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>, bindings: &mut Vec<(Symbol, Span)>) {
     if in_external_macro(cx.sess(), local.span) {
         return;
     }
@@ -173,7 +173,7 @@ fn check_pat<'tcx>(
     pat: &'tcx Pat<'_>,
     init: Option<&'tcx Expr<'_>>,
     span: Span,
-    bindings: &mut Vec<(Name, Span)>,
+    bindings: &mut Vec<(Symbol, Span)>,
 ) {
     // TODO: match more stuff / destructuring
     match pat.kind {
@@ -254,7 +254,7 @@ fn check_pat<'tcx>(
 
 fn lint_shadow<'tcx>(
     cx: &LateContext<'tcx>,
-    name: Name,
+    name: Symbol,
     span: Span,
     pattern_span: Span,
     init: Option<&'tcx Expr<'_>>,
@@ -315,7 +315,7 @@ fn lint_shadow<'tcx>(
     }
 }
 
-fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut Vec<(Name, Span)>) {
+fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut Vec<(Symbol, Span)>) {
     if in_external_macro(cx.sess(), expr.span) {
         return;
     }
@@ -351,7 +351,7 @@ 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<(Name, Span)>) {
+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) => {
@@ -371,7 +371,7 @@ fn check_ty<'tcx>(cx: &LateContext<'tcx>, ty: &'tcx Ty<'_>, bindings: &mut Vec<(
     }
 }
 
-fn is_self_shadow(name: Name, expr: &Expr<'_>) -> bool {
+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, _) => {
@@ -383,6 +383,6 @@ fn is_self_shadow(name: Name, expr: &Expr<'_>) -> bool {
     }
 }
 
-fn path_eq_name(name: Name, path: &Path<'_>) -> bool {
+fn path_eq_name(name: Symbol, path: &Path<'_>) -> bool {
     !path.is_global() && path.segments.len() == 1 && path.segments[0].ident.as_str() == name.as_str()
 }
diff --git a/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs b/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs
new file mode 100644
index 00000000000..cd7056620a2
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs
@@ -0,0 +1,130 @@
+use crate::utils::{is_slice_of_primitives, span_lint_and_sugg, sugg::Sugg};
+
+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:**
+    /// When sorting primitive values (integers, bools, chars, as well
+    /// as arrays, slices, and tuples of such items), it is better to
+    /// use an unstable sort than a stable sort.
+    ///
+    /// **Why is this bad?**
+    /// Using a stable sort consumes more memory and cpu cycles. Because
+    /// values which compare equal are identical, preserving their
+    /// relative order (the guarantee that a stable sort provides) means
+    /// nothing, while the extra costs still apply.
+    ///
+    /// **Known problems:**
+    /// None
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let mut vec = vec![2, 1, 3];
+    /// vec.sort();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let mut vec = vec![2, 1, 3];
+    /// vec.sort_unstable();
+    /// ```
+    pub STABLE_SORT_PRIMITIVE,
+    perf,
+    "use of sort() when sort_unstable() is equivalent"
+}
+
+declare_lint_pass!(StableSortPrimitive => [STABLE_SORT_PRIMITIVE]);
+
+/// The three "kinds" of sorts
+enum SortingKind {
+    Vanilla,
+    /* The other kinds of lint are currently commented out because they
+     * can map distinct values to equal ones. If the key function is
+     * provably one-to-one, or if the Cmp function conserves equality,
+     * then they could be linted on, but I don't know if we can check
+     * for that. */
+
+    /* ByKey,
+     * ByCmp, */
+}
+impl SortingKind {
+    /// The name of the stable version of this kind of sort
+    fn stable_name(&self) -> &str {
+        match self {
+            SortingKind::Vanilla => "sort",
+            /* SortingKind::ByKey => "sort_by_key",
+             * SortingKind::ByCmp => "sort_by", */
+        }
+    }
+    /// The name of the unstable version of this kind of sort
+    fn unstable_name(&self) -> &str {
+        match self {
+            SortingKind::Vanilla => "sort_unstable",
+            /* SortingKind::ByKey => "sort_unstable_by_key",
+             * SortingKind::ByCmp => "sort_unstable_by", */
+        }
+    }
+    /// Takes the name of a function call and returns the kind of sort
+    /// that corresponds to that function name (or None if it isn't)
+    fn from_stable_name(name: &str) -> Option<SortingKind> {
+        match name {
+            "sort" => Some(SortingKind::Vanilla),
+            // "sort_by" => Some(SortingKind::ByCmp),
+            // "sort_by_key" => Some(SortingKind::ByKey),
+            _ => None,
+        }
+    }
+}
+
+/// A detected instance of this lint
+struct LintDetection {
+    slice_name: String,
+    method: SortingKind,
+    method_args: String,
+}
+
+fn detect_stable_sort_primitive(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintDetection> {
+    if_chain! {
+        if let ExprKind::MethodCall(method_name, _, args, _) = &expr.kind;
+        if let Some(slice) = &args.get(0);
+        if let Some(method) = SortingKind::from_stable_name(&method_name.ident.name.as_str());
+        if is_slice_of_primitives(cx, slice);
+        then {
+            let args_str = args.iter().skip(1).map(|arg| Sugg::hir(cx, arg, "..").to_string()).collect::<Vec<String>>().join(", ");
+            Some(LintDetection { slice_name: Sugg::hir(cx, slice, "..").to_string(), method, method_args: args_str })
+        } else {
+            None
+        }
+    }
+}
+
+impl LateLintPass<'_> for StableSortPrimitive {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        if let Some(detection) = detect_stable_sort_primitive(cx, expr) {
+            span_lint_and_sugg(
+                cx,
+                STABLE_SORT_PRIMITIVE,
+                expr.span,
+                format!(
+                    "Use {} instead of {}",
+                    detection.method.unstable_name(),
+                    detection.method.stable_name()
+                )
+                .as_str(),
+                "try",
+                format!(
+                    "{}.{}({})",
+                    detection.slice_name,
+                    detection.method.unstable_name(),
+                    detection.method_args
+                ),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
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 6d1d083fa8d..4e335a0222f 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
@@ -64,26 +64,22 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl {
                 | hir::BinOpKind::Gt => return,
                 _ => {},
             }
-            // Check if the binary expression is part of another bi/unary expression
-            // or operator assignment as a child node
-            let mut parent_expr = cx.tcx.hir().get_parent_node(expr.hir_id);
-            while parent_expr != hir::CRATE_HIR_ID {
-                if let hir::Node::Expr(e) = cx.tcx.hir().get(parent_expr) {
-                    match e.kind {
-                        hir::ExprKind::Binary(..)
-                        | hir::ExprKind::Unary(hir::UnOp::UnNot | hir::UnOp::UnNeg, _)
-                        | hir::ExprKind::AssignOp(..) => return,
-                        _ => {},
+
+            // Check for more than one binary operation in the implemented function
+            // Linting when multiple operations are involved can result in false positives
+            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 {
+                    walk_expr(&mut visitor, &body.value);
+                    if visitor.nb_binops > 1 {
+                        return;
                     }
                 }
-                parent_expr = cx.tcx.hir().get_parent_node(parent_expr);
-            }
-            // as a parent node
-            let mut visitor = BinaryExprVisitor { in_binary_expr: false };
-            walk_expr(&mut visitor, expr);
-
-            if visitor.in_binary_expr {
-                return;
             }
 
             if let Some(impl_trait) = check_binop(
@@ -102,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl {
                     cx,
                     SUSPICIOUS_ARITHMETIC_IMPL,
                     binop.span,
-                    &format!(r#"Suspicious use of binary operator in `{}` impl"#, impl_trait),
+                    &format!("suspicious use of binary operator in `{}` impl", impl_trait),
                 );
             }
 
@@ -139,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl {
                     cx,
                     SUSPICIOUS_OP_ASSIGN_IMPL,
                     binop.span,
-                    &format!(r#"Suspicious use of binary operator in `{}` impl"#, impl_trait),
+                    &format!("suspicious use of binary operator in `{}` impl", impl_trait),
                 );
             }
         }
@@ -181,7 +177,7 @@ fn check_binop(
 }
 
 struct BinaryExprVisitor {
-    in_binary_expr: bool,
+    nb_binops: u32,
 }
 
 impl<'tcx> Visitor<'tcx> for BinaryExprVisitor {
@@ -191,12 +187,13 @@ impl<'tcx> Visitor<'tcx> for BinaryExprVisitor {
         match expr.kind {
             hir::ExprKind::Binary(..)
             | hir::ExprKind::Unary(hir::UnOp::UnNot | hir::UnOp::UnNeg, _)
-            | hir::ExprKind::AssignOp(..) => self.in_binary_expr = true,
+            | hir::ExprKind::AssignOp(..) => self.nb_binops += 1,
             _ => {},
         }
 
         walk_expr(self, expr);
     }
+
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
         NestedVisitorMap::None
     }
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index 0ef70311fb1..d4acf8df46d 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -2,9 +2,10 @@ use crate::utils::{in_macro, snippet, snippet_with_applicability, span_lint_and_
 use if_chain::if_chain;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Applicability;
-use rustc_hir::{GenericBound, Generics, WherePredicate};
+use rustc_hir::{def::Res, GenericBound, Generics, ParamName, Path, QPath, TyKind, WherePredicate};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::Span;
 
 declare_clippy_lint! {
     /// **What it does:** This lint warns about unnecessary type repetitions in trait bounds
@@ -29,6 +30,35 @@ declare_clippy_lint! {
     "Types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`"
 }
 
+declare_clippy_lint! {
+    /// **What it does:** Checks for cases where generics are being used and multiple
+    /// syntax specifications for trait bounds are used simultaneously.
+    ///
+    /// **Why is this bad?** Duplicate bounds makes the code
+    /// less readable than specifing them only once.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// fn func<T: Clone + Default>(arg: T) where T: Clone + Default {}
+    /// ```
+    ///
+    /// Could be written as:
+    ///
+    /// ```rust
+    /// fn func<T: Clone + Default>(arg: T) {}
+    /// ```
+    /// or
+    ///
+    /// ```rust
+    /// fn func<T>(arg: T) where T: Clone + Default {}
+    /// ```
+    pub TRAIT_DUPLICATION_IN_BOUNDS,
+    pedantic,
+    "Check if the same trait bounds are specified twice during a function declaration"
+}
+
 #[derive(Copy, Clone)]
 pub struct TraitBounds {
     max_trait_bounds: u64,
@@ -41,10 +71,25 @@ impl TraitBounds {
     }
 }
 
-impl_lint_pass!(TraitBounds => [TYPE_REPETITION_IN_BOUNDS]);
+impl_lint_pass!(TraitBounds => [TYPE_REPETITION_IN_BOUNDS, TRAIT_DUPLICATION_IN_BOUNDS]);
 
 impl<'tcx> LateLintPass<'tcx> for TraitBounds {
     fn check_generics(&mut self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) {
+        self.check_type_repetition(cx, gen);
+        check_trait_bound_duplication(cx, gen);
+    }
+}
+
+fn get_trait_res_span_from_bound(bound: &GenericBound<'_>) -> Option<(Res, Span)> {
+    if let GenericBound::Trait(t, _) = bound {
+        Some((t.trait_ref.path.res, t.span))
+    } else {
+        None
+    }
+}
+
+impl TraitBounds {
+    fn check_type_repetition(self, cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
         if in_macro(gen.span) {
             return;
         }
@@ -101,3 +146,48 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
         }
     }
 }
+
+fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
+    if in_macro(gen.span) || gen.params.is_empty() || gen.where_clause.predicates.is_empty() {
+        return;
+    }
+
+    let mut map = FxHashMap::default();
+    for param in gen.params {
+        if let ParamName::Plain(ref ident) = param.name {
+            let res = param
+                .bounds
+                .iter()
+                .filter_map(get_trait_res_span_from_bound)
+                .collect::<Vec<_>>();
+            map.insert(*ident, res);
+        }
+    }
+
+    for predicate in gen.where_clause.predicates {
+        if_chain! {
+            if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
+            if !in_macro(bound_predicate.span);
+            if let TyKind::Path(ref path) = bound_predicate.bounded_ty.kind;
+            if let QPath::Resolved(_, Path { ref segments, .. }) = path;
+            if let Some(segment) = segments.first();
+            if let Some(trait_resolutions_direct) = map.get(&segment.ident);
+            then {
+                for (res_where, _) in bound_predicate.bounds.iter().filter_map(get_trait_res_span_from_bound) {
+                    if let Some((_, span_direct)) = trait_resolutions_direct
+                                                .iter()
+                                                .find(|(res_direct, _)| *res_direct == res_where) {
+                        span_lint_and_help(
+                            cx,
+                            TRAIT_DUPLICATION_IN_BOUNDS,
+                            *span_direct,
+                            "this trait bound is already specified in the where clause",
+                            None,
+                            "consider removing this trait bound",
+                        );
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/transmute.rs b/src/tools/clippy/clippy_lints/src/transmute.rs
index d55eb1a0c93..7b5e92eb5ee 100644
--- a/src/tools/clippy/clippy_lints/src/transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute.rs
@@ -7,8 +7,10 @@ use rustc_ast::ast;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, GenericArg, Mutability, QPath, TyKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, cast::CastKind, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::DUMMY_SP;
+use rustc_typeck::check::{cast::CastCheck, FnCtxt, Inherited};
 use std::borrow::Cow;
 
 declare_clippy_lint! {
@@ -48,6 +50,31 @@ declare_clippy_lint! {
     "transmutes that have the same to and from types or could be a cast/coercion"
 }
 
+// FIXME: Merge this lint with USELESS_TRANSMUTE once that is out of the nursery.
+declare_clippy_lint! {
+    /// **What it does:**Checks for transmutes that could be a pointer cast.
+    ///
+    /// **Why is this bad?** Readability. The code tricks people into thinking that
+    /// something complex is going on.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// # let p: *const [i32] = &[];
+    /// unsafe { std::mem::transmute::<*const [i32], *const [u16]>(p) };
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # let p: *const [i32] = &[];
+    /// p as *const [u16];
+    /// ```
+    pub TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
+    complexity,
+    "transmutes that could be a pointer cast"
+}
+
 declare_clippy_lint! {
     /// **What it does:** Checks for transmutes between a type `T` and `*T`.
     ///
@@ -269,6 +296,7 @@ declare_clippy_lint! {
     correctness,
     "transmute between collections of layout-incompatible types"
 }
+
 declare_lint_pass!(Transmute => [
     CROSSPOINTER_TRANSMUTE,
     TRANSMUTE_PTR_TO_REF,
@@ -281,6 +309,7 @@ declare_lint_pass!(Transmute => [
     TRANSMUTE_INT_TO_FLOAT,
     TRANSMUTE_FLOAT_TO_INT,
     UNSOUND_COLLECTION_TRANSMUTE,
+    TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
 ]);
 
 // used to check for UNSOUND_COLLECTION_TRANSMUTE
@@ -601,7 +630,25 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
                             );
                         }
                     },
-                    _ => return,
+                    (_, _) if can_be_expressed_as_pointer_cast(cx, e, from_ty, to_ty) => span_lint_and_then(
+                        cx,
+                        TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
+                        e.span,
+                        &format!(
+                            "transmute from `{}` to `{}` which could be expressed as a pointer cast instead",
+                            from_ty,
+                            to_ty
+                        ),
+                        |diag| {
+                            if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
+                                let sugg = arg.as_ty(&to_ty.to_string()).to_string();
+                                diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable);
+                            }
+                        }
+                    ),
+                    _ => {
+                        return;
+                    },
                 }
             }
         }
@@ -648,3 +695,59 @@ fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx>, to: Ty<'
         false
     }
 }
+
+/// Check if the type conversion can be expressed as a pointer cast, instead of
+/// a transmute. In certain cases, including some invalid casts from array
+/// references to pointers, this may cause additional errors to be emitted and/or
+/// ICE error messages. This function will panic if that occurs.
+fn can_be_expressed_as_pointer_cast<'tcx>(
+    cx: &LateContext<'tcx>,
+    e: &'tcx Expr<'_>,
+    from_ty: Ty<'tcx>,
+    to_ty: Ty<'tcx>,
+) -> bool {
+    use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast};
+    matches!(
+        check_cast(cx, e, from_ty, to_ty),
+        Some(PtrPtrCast | PtrAddrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast)
+    )
+}
+
+/// If a cast from `from_ty` to `to_ty` is valid, returns an Ok containing the kind of
+/// the cast. In certain cases, including some invalid casts from array references
+/// to pointers, this may cause additional errors to be emitted and/or ICE error
+/// messages. This function will panic if that occurs.
+fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> Option<CastKind> {
+    let hir_id = e.hir_id;
+    let local_def_id = hir_id.owner;
+
+    Inherited::build(cx.tcx, local_def_id).enter(|inherited| {
+        let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, hir_id);
+
+        // If we already have errors, we can't be sure we can pointer cast.
+        assert!(
+            !fn_ctxt.errors_reported_since_creation(),
+            "Newly created FnCtxt contained errors"
+        );
+
+        if let Ok(check) = CastCheck::new(
+            &fn_ctxt, e, from_ty, to_ty,
+            // We won't show any error to the user, so we don't care what the span is here.
+            DUMMY_SP, DUMMY_SP,
+        ) {
+            let res = check.do_check(&fn_ctxt);
+
+            // do_check's documentation says that it might return Ok and create
+            // errors in the fcx instead of returing Err in some cases. Those cases
+            // should be filtered out before getting here.
+            assert!(
+                !fn_ctxt.errors_reported_since_creation(),
+                "`fn_ctxt` contained errors after cast check!"
+            );
+
+            res.ok()
+        } else {
+            None
+        }
+    })
+}
diff --git a/src/tools/clippy/clippy_lints/src/try_err.rs b/src/tools/clippy/clippy_lints/src/try_err.rs
index d3b351f30ef..3bd73d9f21a 100644
--- a/src/tools/clippy/clippy_lints/src/try_err.rs
+++ b/src/tools/clippy/clippy_lints/src/try_err.rs
@@ -1,10 +1,13 @@
-use crate::utils::{match_qpath, paths, snippet, snippet_with_macro_callsite, span_lint_and_sugg};
+use crate::utils::{
+    is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet, snippet_with_macro_callsite,
+    span_lint_and_sugg,
+};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{Arm, Expr, ExprKind, MatchSource};
+use rustc_hir::{Expr, ExprKind, MatchSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_clippy_lint! {
@@ -65,19 +68,39 @@ impl<'tcx> LateLintPass<'tcx> for TryErr {
             if let Some(ref 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_type) = find_err_return_type(cx, &expr.kind);
-
+            if let Some(return_ty) = find_return_type(cx, &expr.kind);
             then {
-                let err_type = cx.typeck_results().expr_ty(err_arg);
+                let prefix;
+                let suffix;
+                let err_ty;
+
+                if let Some(ty) = result_error_type(cx, return_ty) {
+                    prefix = "Err(";
+                    suffix = ")";
+                    err_ty = ty;
+                } else if let Some(ty) = poll_result_error_type(cx, return_ty) {
+                    prefix = "Poll::Ready(Err(";
+                    suffix = "))";
+                    err_ty = ty;
+                } else if let Some(ty) = poll_option_result_error_type(cx, return_ty) {
+                    prefix = "Poll::Ready(Some(Err(";
+                    suffix = ")))";
+                    err_ty = ty;
+                } else {
+                    return;
+                };
+
+                let expr_err_ty = cx.typeck_results().expr_ty(err_arg);
+
                 let origin_snippet = if err_arg.span.from_expansion() {
                     snippet_with_macro_callsite(cx, err_arg.span, "_")
                 } else {
                     snippet(cx, err_arg.span, "_")
                 };
-                let suggestion = if err_type == return_type {
-                    format!("return Err({})", origin_snippet)
+                let suggestion = if err_ty == expr_err_ty {
+                    format!("return {}{}{}", prefix, origin_snippet, suffix)
                 } else {
-                    format!("return Err({}.into())", origin_snippet)
+                    format!("return {}{}.into(){}", prefix, origin_snippet, suffix)
                 };
 
                 span_lint_and_sugg(
@@ -94,27 +117,68 @@ impl<'tcx> LateLintPass<'tcx> for TryErr {
     }
 }
 
-// In order to determine whether to suggest `.into()` or not, we need to find the error type the
-// function returns. To do that, we look for the From::from call (see tree above), and capture
-// its output type.
-fn find_err_return_type<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx ExprKind<'_>) -> Option<Ty<'tcx>> {
+/// 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 {
-        arms.iter().find_map(|ty| find_err_return_type_arm(cx, ty))
-    } else {
-        None
+        for arm in arms.iter() {
+            if let ExprKind::Ret(Some(ref ret)) = arm.body.kind {
+                return Some(cx.typeck_results().expr_ty(ret));
+            }
+        }
     }
+    None
 }
 
-// Check for From::from in one of the match arms.
-fn find_err_return_type_arm<'tcx>(cx: &LateContext<'tcx>, arm: &'tcx Arm<'_>) -> Option<Ty<'tcx>> {
+/// Extracts the error type from Result<T, E>.
+fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
     if_chain! {
-        if let ExprKind::Ret(Some(ref err_ret)) = arm.body.kind;
-        if let ExprKind::Call(ref from_error_path, ref from_error_args) = err_ret.kind;
-        if let ExprKind::Path(ref from_error_fn) = from_error_path.kind;
-        if match_qpath(from_error_fn, &paths::TRY_FROM_ERROR);
-        if let Some(from_error_arg) = from_error_args.get(0);
+        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)
+        } else {
+            None
+        }
+    }
+}
+
+/// Extracts the error type from Poll<Result<T, E>>.
+fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+    if_chain! {
+        if let ty::Adt(def, subst) = ty.kind;
+        if match_def_path(cx, def.did, &paths::POLL);
+        let ready_ty = subst.type_at(0);
+
+        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)
+        } else {
+            None
+        }
+    }
+}
+
+/// Extracts the error type from Poll<Option<Result<T, E>>>.
+fn poll_option_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+    if_chain! {
+        if let ty::Adt(def, subst) = ty.kind;
+        if match_def_path(cx, def.did, &paths::POLL);
+        let ready_ty = subst.type_at(0);
+
+        if let ty::Adt(ready_def, ready_subst) = ready_ty.kind;
+        if cx.tcx.is_diagnostic_item(sym!(option_type), ready_def.did);
+        let some_ty = ready_subst.type_at(0);
+
+        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(cx.typeck_results().expr_ty(from_error_arg))
+            Some(err_ty)
         } else {
             None
         }
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index f2bbde28c2a..ea4b8172c9c 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -181,8 +181,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
                             self.cx,
                             UNNECESSARY_UNWRAP,
                             expr.span,
-                            &format!("You checked before that `{}()` cannot fail. \
-                            Instead of checking and unwrapping, it's better to use `if let` or `match`.",
+                            &format!("you checked before that `{}()` cannot fail, \
+                            instead of checking and unwrapping, it's better to use `if let` or `match`",
                             method_name.ident.name),
                             |diag| { diag.span_label(unwrappable.check.span, "the check is happening here"); },
                         );
@@ -191,7 +191,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
                             self.cx,
                             PANICKING_UNWRAP,
                             expr.span,
-                            &format!("This call to `{}()` will always panic.",
+                            &format!("this call to `{}()` will always panic",
                             method_name.ident.name),
                             |diag| { diag.span_label(unwrappable.check.span, "because of this check"); },
                         );
diff --git a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs
index ad02bc5fd8e..ad02bc5fd8e 100755..100644
--- a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs
diff --git a/src/tools/clippy/clippy_lints/src/utils/attrs.rs b/src/tools/clippy/clippy_lints/src/utils/attrs.rs
index 407527251da..a3975683cb3 100644
--- a/src/tools/clippy/clippy_lints/src/utils/attrs.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/attrs.rs
@@ -75,12 +75,12 @@ pub fn get_attr<'a>(
                 })
                 .map_or_else(
                     || {
-                        sess.span_err(attr_segments[1].ident.span, "Usage of unknown attribute");
+                        sess.span_err(attr_segments[1].ident.span, "usage of unknown attribute");
                         false
                     },
                     |deprecation_status| {
                         let mut diag =
-                            sess.struct_span_err(attr_segments[1].ident.span, "Usage of deprecated attribute");
+                            sess.struct_span_err(attr_segments[1].ident.span, "usage of deprecated attribute");
                         match *deprecation_status {
                             DeprecationStatus::Deprecated => {
                                 diag.emit();
diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs
index 95a12fe1935..223628cc610 100644
--- a/src/tools/clippy/clippy_lints/src/utils/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs
@@ -43,6 +43,7 @@ use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty::{self, layout::IntegerExt, subst::GenericArg, Ty, TyCtxt, TypeFoldable};
+use rustc_mir::const_eval;
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::original_sp;
 use rustc_span::symbol::{self, kw, Symbol};
@@ -52,7 +53,6 @@ use rustc_trait_selection::traits::query::normalize::AtExt;
 use smallvec::SmallVec;
 
 use crate::consts::{constant, Constant};
-use crate::reexport::Name;
 
 /// Returns `true` if the two spans come from differing expansions (i.e., one is
 /// from a macro and one isn't).
@@ -150,7 +150,7 @@ pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str])
 }
 
 /// Checks if an expression references a variable of the given name.
-pub fn match_var(expr: &Expr<'_>, var: Name) -> bool {
+pub fn match_var(expr: &Expr<'_>, var: Symbol) -> bool {
     if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind {
         if let [p] = path.segments {
             return p.ident.name == var;
@@ -420,7 +420,7 @@ pub fn is_entrypoint_fn(cx: &LateContext<'_>, def_id: DefId) -> bool {
 }
 
 /// Gets the name of the item the expression is in, if available.
-pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Name> {
+pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
     let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id);
     match cx.tcx.hir().find(parent_id) {
         Some(
@@ -433,7 +433,7 @@ pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Name> {
 }
 
 /// Gets the name of a `Pat`, if any.
-pub fn get_pat_name(pat: &Pat<'_>) -> Option<Name> {
+pub fn get_pat_name(pat: &Pat<'_>) -> Option<Symbol> {
     match pat.kind {
         PatKind::Binding(.., ref spname, _) => Some(spname.name),
         PatKind::Path(ref qpath) => single_segment_path(qpath).map(|ps| ps.ident.name),
@@ -443,14 +443,14 @@ pub fn get_pat_name(pat: &Pat<'_>) -> Option<Name> {
 }
 
 struct ContainsName {
-    name: Name,
+    name: Symbol,
     result: bool,
 }
 
 impl<'tcx> Visitor<'tcx> for ContainsName {
     type Map = Map<'tcx>;
 
-    fn visit_name(&mut self, _: Span, name: Name) {
+    fn visit_name(&mut self, _: Span, name: Symbol) {
         if self.name == name {
             self.result = true;
         }
@@ -461,7 +461,7 @@ impl<'tcx> Visitor<'tcx> for ContainsName {
 }
 
 /// Checks if an `Expr` contains a certain name.
-pub fn contains_name(name: Name, expr: &Expr<'_>) -> bool {
+pub fn contains_name(name: Symbol, expr: &Expr<'_>) -> bool {
     let mut cn = ContainsName { name, result: false };
     cn.visit_expr(expr);
     cn.result
@@ -869,11 +869,19 @@ pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 
 /// Checks if an expression is constructing a tuple-like enum variant or struct
 pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    fn has_no_arguments(cx: &LateContext<'_>, def_id: DefId) -> bool {
+        cx.tcx.fn_sig(def_id).skip_binder().inputs().is_empty()
+    }
+
     if let ExprKind::Call(ref fun, _) = expr.kind {
         if let ExprKind::Path(ref qp) = fun.kind {
             let res = cx.qpath_res(qp, fun.hir_id);
             return match res {
                 def::Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true,
+                // FIXME: check the constness of the arguments, see https://github.com/rust-lang/rust-clippy/pull/5682#issuecomment-638681210
+                def::Res::Def(DefKind::Fn, def_id) if has_no_arguments(cx, def_id) => {
+                    const_eval::is_const_fn(cx.tcx, def_id)
+                },
                 def::Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id),
                 _ => false,
             };
@@ -1027,7 +1035,7 @@ pub fn is_allowed(cx: &LateContext<'_>, lint: &'static Lint, id: HirId) -> bool
     cx.tcx.lint_level_at_node(lint, id).0 == Level::Allow
 }
 
-pub fn get_arg_name(pat: &Pat<'_>) -> Option<Name> {
+pub fn get_arg_name(pat: &Pat<'_>) -> Option<Symbol> {
     match pat.kind {
         PatKind::Binding(.., ident, None) => Some(ident.name),
         PatKind::Ref(ref subpat, _) => get_arg_name(subpat),
@@ -1378,6 +1386,36 @@ pub fn run_lints(cx: &LateContext<'_>, lints: &[&'static Lint], id: HirId) -> bo
     })
 }
 
+/// Returns true iff the given type is a primitive (a bool or char, any integer or floating-point
+/// number type, a str, or an array, slice, or tuple of those types).
+pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool {
+    match ty.kind {
+        ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true,
+        ty::Ref(_, inner, _) if inner.kind == ty::Str => true,
+        ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type),
+        ty::Tuple(inner_types) => inner_types.types().all(is_recursively_primitive_type),
+        _ => false,
+    }
+}
+
+/// Returns true iff the given expression is a slice of primitives (as defined in the
+/// `is_recursively_primitive_type` function).
+pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    let expr_type = cx.typeck_results().expr_ty_adjusted(expr);
+    match expr_type.kind {
+        ty::Slice(ref element_type)
+        | ty::Ref(
+            _,
+            ty::TyS {
+                kind: ty::Slice(ref element_type),
+                ..
+            },
+            _,
+        ) => is_recursively_primitive_type(element_type),
+        _ => false,
+    }
+}
+
 #[macro_export]
 macro_rules! unwrap_cargo_metadata {
     ($cx: ident, $lint: ident, $deps: expr) => {{
diff --git a/src/tools/clippy/clippy_lints/src/utils/paths.rs b/src/tools/clippy/clippy_lints/src/utils/paths.rs
index a515ee29c82..923b319d777 100644
--- a/src/tools/clippy/clippy_lints/src/utils/paths.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/paths.rs
@@ -80,6 +80,7 @@ pub const PATH: [&str; 3] = ["std", "path", "Path"];
 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 POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
 pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
 pub const PTR_NULL: [&str; 2] = ["ptr", "null"];
 pub const PTR_NULL_MUT: [&str; 2] = ["ptr", "null_mut"];
@@ -129,7 +130,6 @@ pub const TO_STRING: [&str; 3] = ["alloc", "string", "ToString"];
 pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"];
 pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"];
 pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"];
-pub const TRY_FROM_ERROR: [&str; 4] = ["std", "ops", "Try", "from_error"];
 pub const TRY_INTO_RESULT: [&str; 4] = ["std", "ops", "Try", "into_result"];
 pub const TRY_INTO_TRAIT: [&str; 3] = ["core", "convert", "TryInto"];
 pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"];
diff --git a/src/tools/clippy/doc/adding_lints.md b/src/tools/clippy/doc/adding_lints.md
index 8092be277cc..168092f7329 100644
--- a/src/tools/clippy/doc/adding_lints.md
+++ b/src/tools/clippy/doc/adding_lints.md
@@ -27,10 +27,7 @@ because that's clearly a non-descriptive name.
 
 ## Setup
 
-When working on Clippy, you will need the current git master version of rustc,
-which can change rapidly. Make sure you're working near rust-clippy's master,
-and use the `setup-toolchain.sh` script to configure the appropriate toolchain
-for the Clippy directory.
+See the [Basics](basics.md#get-the-code) documentation.
 
 ## Getting Started
 
@@ -38,12 +35,14 @@ There is a bit of boilerplate code that needs to be set up when creating a new
 lint. Fortunately, you can use the clippy dev tools to handle this for you. We
 are naming our new lint `foo_functions` (lints are generally written in snake
 case), and we don't need type information so it will have an early pass type
-(more on this later on). To get started on this lint you can run
-`cargo dev new_lint --name=foo_functions --pass=early --category=pedantic`
-(category will default to nursery if not provided). This command will create
-two files: `tests/ui/foo_functions.rs` and `clippy_lints/src/foo_functions.rs`,
-as well as run `cargo dev update_lints` to register the new lint. For cargo lints,
-two project hierarchies (fail/pass) will be created by default under `tests/ui-cargo`.
+(more on this later on). If you're not sure if the name you chose fits the lint,
+take a look at our [lint naming guidelines][lint_naming]. To get started on this
+lint you can run `cargo dev new_lint --name=foo_functions --pass=early
+--category=pedantic` (category will default to nursery if not provided). This
+command will create two files: `tests/ui/foo_functions.rs` and
+`clippy_lints/src/foo_functions.rs`, as well as run `cargo dev update_lints` to
+register the new lint. For cargo lints, two project hierarchies (fail/pass) will
+be created by default under `tests/ui-cargo`.
 
 Next, we'll open up these files and add our lint!
 
@@ -113,7 +112,7 @@ For cargo lints, the process of testing differs in that we are interested in
 the `Cargo.toml` manifest file. We also need a minimal crate associated
 with that manifest.
 
-If our new lint is named e.g. `foo_categories`, after running `cargo dev new_lint` 
+If our new lint is named e.g. `foo_categories`, after running `cargo dev new_lint`
 we will find by default two new crates, each with its manifest file:
 
 * `tests/ui-cargo/foo_categories/fail/Cargo.toml`: this file should cause the new lint to raise an error.
diff --git a/src/tools/clippy/doc/basics.md b/src/tools/clippy/doc/basics.md
new file mode 100644
index 00000000000..c81e7f6e069
--- /dev/null
+++ b/src/tools/clippy/doc/basics.md
@@ -0,0 +1,112 @@
+# Basics for hacking on Clippy
+
+This document explains the basics for hacking on Clippy. Besides others, this
+includes how to set-up the development environment, how to build and how to test
+Clippy. For a more in depth description on the codebase take a look at [Adding
+Lints] or [Common Tools].
+
+[Adding Lints]: https://github.com/rust-lang/rust-clippy/blob/master/doc/adding_lints.md
+[Common Tools]: https://github.com/rust-lang/rust-clippy/blob/master/doc/common_tools_writing_lints.md
+
+- [Basics for hacking on Clippy](#basics-for-hacking-on-clippy)
+  - [Get the code](#get-the-code)
+  - [Setup](#setup)
+  - [Building and Testing](#building-and-testing)
+  - [`cargo dev`](#cargo-dev)
+
+## Get the Code
+
+First, make sure you have checked out the latest version of Clippy. If this is
+your first time working on Clippy, create a fork of the repository and clone it
+afterwards with the following command:
+
+```bash
+git clone git@github.com:<your-username>/rust-clippy
+```
+
+If you've already cloned Clippy in the past, update it to the latest version:
+
+```bash
+# upstream has to be the remote of the rust-lang/rust-clippy repo
+git fetch upstream
+# make sure that you are on the master branch
+git checkout master
+# rebase your master branch on the upstream master
+git rebase upstream/master
+# push to the master branch of your fork
+git push
+```
+
+## Setup
+
+Next we need to setup the toolchain to compile Clippy. Since Clippy heavily
+relies on compiler internals it is build with the latest rustc master. To get
+this toolchain, you can just use the `setup-toolchain.sh` script or use
+`rustup-toolchain-install-master`:
+
+```bash
+sh setup-toolchain.sh
+# OR
+cargo install rustup-toolchain-install-master
+# For better IDE integration also add `-c rustfmt -c rust-src` (optional)
+rustup-toolchain-install-master -f -n master -c rustc-dev -c llvm-tools
+rustup override set master
+```
+
+_Note:_ Sometimes you may get compiler errors when building Clippy, even if you
+didn't change anything. Normally those will be fixed by a maintainer in a few hours. 
+
+## Building and Testing
+
+Once the `master` toolchain is installed, you can build and test Clippy like
+every other Rust project:
+
+```bash
+cargo build  # builds Clippy
+cargo test   # tests Clippy
+```
+
+Since Clippy's test suite is pretty big, there are some commands that only run a
+subset of Clippy's tests:
+
+```bash
+# only run UI tests
+cargo uitest
+# only run UI tests starting with `test_`
+TESTNAME="test_" cargo uitest
+# only run dogfood tests
+cargo test --test dogfood
+```
+
+If the output of a [UI test] differs from the expected output, you can update the
+reference file with:
+
+```bash
+sh tests/ui/update-all-references.sh
+```
+
+For example, this is necessary, if you fix a typo in an error message of a lint
+or if you modify a test file to add a test case.
+
+_Note:_ This command may update more files than you intended. In that case only
+commit the files you wanted to update.
+
+[UI test]: https://rustc-dev-guide.rust-lang.org/tests/adding.html#guide-to-the-ui-tests
+
+## `cargo dev`
+
+Clippy has some dev tools to make working on Clippy more convenient. These tools
+can be accessed through the `cargo dev` command. Available tools are listed
+below. To get more information about these commands, just call them with
+`--help`.
+
+```bash
+# formats the whole Clippy codebase and all tests
+cargo dev fmt
+# register or update lint names/groups/...
+cargo dev update_lints
+# create a new lint and register it
+cargo dev new_lint
+# (experimental) Setup Clippy to work with rust-analyzer
+cargo dev ra-setup
+```
diff --git a/src/tools/clippy/src/lintlist/mod.rs b/src/tools/clippy/src/lintlist/mod.rs
index 1879aae77fb..bbb300296be 100644
--- a/src/tools/clippy/src/lintlist/mod.rs
+++ b/src/tools/clippy/src/lintlist/mod.rs
@@ -361,6 +361,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "derive",
     },
     Lint {
+        name: "derive_ord_xor_partial_ord",
+        group: "correctness",
+        desc: "deriving `Ord` but implementing `PartialOrd` explicitly",
+        deprecation: None,
+        module: "derive",
+    },
+    Lint {
         name: "diverging_sub_expression",
         group: "complexity",
         desc: "whether an expression contains a diverging sub expression",
@@ -405,7 +412,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
     Lint {
         name: "drop_bounds",
         group: "correctness",
-        desc: "Bounds of the form `T: Drop` are useless",
+        desc: "bounds of the form `T: Drop` are useless",
         deprecation: None,
         module: "drop_bounds",
     },
@@ -1453,6 +1460,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "bytecount",
     },
     Lint {
+        name: "needless_arbitrary_self_type",
+        group: "complexity",
+        desc: "type of `self` parameter is already by default `Self`",
+        deprecation: None,
+        module: "needless_arbitrary_self_type",
+    },
+    Lint {
         name: "needless_bool",
         group: "complexity",
         desc: "if-statements with plain booleans in the then- and else-clause, e.g., `if p { true } else { false }`",
@@ -1929,6 +1943,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "copies",
     },
     Lint {
+        name: "same_item_push",
+        group: "style",
+        desc: "the same item is pushed inside of a for loop",
+        deprecation: None,
+        module: "loops",
+    },
+    Lint {
         name: "search_is_some",
         group: "complexity",
         desc: "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`",
@@ -2027,6 +2048,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "slow_vector_initialization",
     },
     Lint {
+        name: "stable_sort_primitive",
+        group: "perf",
+        desc: "use of sort() when sort_unstable() is equivalent",
+        deprecation: None,
+        module: "stable_sort_primitive",
+    },
+    Lint {
         name: "string_add",
         group: "restriction",
         desc: "using `x + ..` where x is a `String` instead of `push_str()`",
@@ -2167,6 +2195,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "misc",
     },
     Lint {
+        name: "trait_duplication_in_bounds",
+        group: "pedantic",
+        desc: "Check if the same trait bounds are specified twice during a function declaration",
+        deprecation: None,
+        module: "trait_bounds",
+    },
+    Lint {
         name: "transmute_bytes_to_str",
         group: "complexity",
         desc: "transmutes from a `&[u8]` to a `&str`",
@@ -2216,6 +2251,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "transmute",
     },
     Lint {
+        name: "transmutes_expressible_as_ptr_casts",
+        group: "complexity",
+        desc: "transmutes that could be a pointer cast",
+        deprecation: None,
+        module: "transmute",
+    },
+    Lint {
         name: "transmuting_null",
         group: "correctness",
         desc: "transmutes from a null pointer to a reference, which is undefined behavior",
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index 26a47d23706..697823712bf 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -3,7 +3,7 @@
 use compiletest_rs as compiletest;
 use compiletest_rs::common::Mode as TestMode;
 
-use std::env::{self, set_var};
+use std::env::{self, set_var, var};
 use std::ffi::OsStr;
 use std::fs;
 use std::io;
@@ -136,7 +136,9 @@ fn run_ui_toml(config: &mut compiletest::Config) {
 
     let tests = compiletest::make_tests(&config);
 
+    let manifest_dir = var("CARGO_MANIFEST_DIR").unwrap_or_default();
     let res = run_tests(&config, tests);
+    set_var("CARGO_MANIFEST_DIR", &manifest_dir);
     match res {
         Ok(true) => {},
         Ok(false) => panic!("Some tests failed"),
@@ -147,9 +149,6 @@ fn run_ui_toml(config: &mut compiletest::Config) {
 }
 
 fn run_ui_cargo(config: &mut compiletest::Config) {
-    if cargo::is_rustc_test_suite() {
-        return;
-    }
     fn run_tests(
         config: &compiletest::Config,
         filter: &Option<String>,
@@ -217,6 +216,10 @@ fn run_ui_cargo(config: &mut compiletest::Config) {
         Ok(result)
     }
 
+    if cargo::is_rustc_test_suite() {
+        return;
+    }
+
     config.mode = TestMode::Ui;
     config.src_base = Path::new("tests").join("ui-cargo").canonicalize().unwrap();
 
diff --git a/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr b/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr
index 4b77ac551e7..fb12257021a 100644
--- a/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr
+++ b/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr
@@ -1,4 +1,4 @@
-error: This function has a large number of lines.
+error: this function has a large number of lines
   --> $DIR/test.rs:18:1
    |
 LL | / fn too_many_lines() {
@@ -9,7 +9,7 @@ LL | | }
    |
    = note: `-D clippy::too-many-lines` implied by `-D warnings`
 
-error: This function has a large number of lines.
+error: this function has a large number of lines
   --> $DIR/test.rs:38:1
    |
 LL | / fn comment_before_code() {
diff --git a/src/tools/clippy/tests/ui/await_holding_lock.rs b/src/tools/clippy/tests/ui/await_holding_lock.rs
index 5c1fdd83efb..0458950edee 100644
--- a/src/tools/clippy/tests/ui/await_holding_lock.rs
+++ b/src/tools/clippy/tests/ui/await_holding_lock.rs
@@ -47,6 +47,7 @@ async fn not_good(x: &Mutex<u32>) -> u32 {
     first + second + third
 }
 
+#[allow(clippy::manual_async_fn)]
 fn block_bad(x: &Mutex<u32>) -> impl std::future::Future<Output = u32> + '_ {
     async move {
         let guard = x.lock().unwrap();
diff --git a/src/tools/clippy/tests/ui/await_holding_lock.stderr b/src/tools/clippy/tests/ui/await_holding_lock.stderr
index 8c47cb37d8c..21bf49d16f0 100644
--- a/src/tools/clippy/tests/ui/await_holding_lock.stderr
+++ b/src/tools/clippy/tests/ui/await_holding_lock.stderr
@@ -46,13 +46,13 @@ LL | |     };
    | |_____^
 
 error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await.
-  --> $DIR/await_holding_lock.rs:52:13
+  --> $DIR/await_holding_lock.rs:53:13
    |
 LL |         let guard = x.lock().unwrap();
    |             ^^^^^
    |
 note: these are all the await points this lock is held through
-  --> $DIR/await_holding_lock.rs:52:9
+  --> $DIR/await_holding_lock.rs:53:9
    |
 LL | /         let guard = x.lock().unwrap();
 LL | |         baz().await
diff --git a/src/tools/clippy/tests/ui/bool_comparison.stderr b/src/tools/clippy/tests/ui/bool_comparison.stderr
index eeb1f20ee89..55d94b8257d 100644
--- a/src/tools/clippy/tests/ui/bool_comparison.stderr
+++ b/src/tools/clippy/tests/ui/bool_comparison.stderr
@@ -84,25 +84,25 @@ error: order comparisons between booleans can be simplified
 LL |     if x > y {
    |        ^^^^^ help: try simplifying it as shown: `x & !y`
 
-error: This comparison might be written more concisely
+error: this comparison might be written more concisely
   --> $DIR/bool_comparison.rs:120:8
    |
 LL |     if a == !b {};
    |        ^^^^^^^ help: try simplifying it as shown: `a != b`
 
-error: This comparison might be written more concisely
+error: this comparison might be written more concisely
   --> $DIR/bool_comparison.rs:121:8
    |
 LL |     if !a == b {};
    |        ^^^^^^^ help: try simplifying it as shown: `a != b`
 
-error: This comparison might be written more concisely
+error: this comparison might be written more concisely
   --> $DIR/bool_comparison.rs:125:8
    |
 LL |     if b == !a {};
    |        ^^^^^^^ help: try simplifying it as shown: `b != a`
 
-error: This comparison might be written more concisely
+error: this comparison might be written more concisely
   --> $DIR/bool_comparison.rs:126:8
    |
 LL |     if !b == a {};
diff --git a/src/tools/clippy/tests/ui/builtin-type-shadow.stderr b/src/tools/clippy/tests/ui/builtin-type-shadow.stderr
index bc785b075e0..f42b246afd2 100644
--- a/src/tools/clippy/tests/ui/builtin-type-shadow.stderr
+++ b/src/tools/clippy/tests/ui/builtin-type-shadow.stderr
@@ -1,4 +1,4 @@
-error: This generic shadows the built-in type `u32`
+error: this generic shadows the built-in type `u32`
   --> $DIR/builtin-type-shadow.rs:4:8
    |
 LL | fn foo<u32>(a: u32) -> u32 {
diff --git a/src/tools/clippy/tests/ui/bytecount.stderr b/src/tools/clippy/tests/ui/bytecount.stderr
index 436f5d86a06..1dc37fc8b25 100644
--- a/src/tools/clippy/tests/ui/bytecount.stderr
+++ b/src/tools/clippy/tests/ui/bytecount.stderr
@@ -1,8 +1,8 @@
-error: You appear to be counting bytes the naive way
+error: you appear to be counting bytes the naive way
   --> $DIR/bytecount.rs:5:13
    |
 LL |     let _ = x.iter().filter(|&&a| a == 0).count(); // naive byte count
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider using the bytecount crate: `bytecount::count(x, 0)`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the bytecount crate: `bytecount::count(x, 0)`
    |
 note: the lint level is defined here
   --> $DIR/bytecount.rs:1:8
@@ -10,17 +10,17 @@ note: the lint level is defined here
 LL | #[deny(clippy::naive_bytecount)]
    |        ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: You appear to be counting bytes the naive way
+error: you appear to be counting bytes the naive way
   --> $DIR/bytecount.rs:7:13
    |
 LL |     let _ = (&x[..]).iter().filter(|&a| *a == 0).count(); // naive byte count
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider using the bytecount crate: `bytecount::count((&x[..]), 0)`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the bytecount crate: `bytecount::count((&x[..]), 0)`
 
-error: You appear to be counting bytes the naive way
+error: you appear to be counting bytes the naive way
   --> $DIR/bytecount.rs:19:13
    |
 LL |     let _ = x.iter().filter(|a| b + 1 == **a).count(); // naive byte count
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider using the bytecount crate: `bytecount::count(x, b + 1)`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the bytecount crate: `bytecount::count(x, b + 1)`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/checked_conversions.stderr b/src/tools/clippy/tests/ui/checked_conversions.stderr
index 648ba3ccd01..18518def0ac 100644
--- a/src/tools/clippy/tests/ui/checked_conversions.stderr
+++ b/src/tools/clippy/tests/ui/checked_conversions.stderr
@@ -1,4 +1,4 @@
-error: Checked cast can be simplified.
+error: checked cast can be simplified
   --> $DIR/checked_conversions.rs:17:13
    |
 LL |     let _ = value <= (u32::max_value() as i64) && value >= 0;
@@ -6,91 +6,91 @@ LL |     let _ = value <= (u32::max_value() as i64) && value >= 0;
    |
    = note: `-D clippy::checked-conversions` implied by `-D warnings`
 
-error: Checked cast can be simplified.
+error: checked cast can be simplified
   --> $DIR/checked_conversions.rs:18:13
    |
 LL |     let _ = value <= (u32::MAX as i64) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
 
-error: Checked cast can be simplified.
+error: checked cast can be simplified
   --> $DIR/checked_conversions.rs:22:13
    |
 LL |     let _ = value <= i64::from(u16::max_value()) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
 
-error: Checked cast can be simplified.
+error: checked cast can be simplified
   --> $DIR/checked_conversions.rs:23:13
    |
 LL |     let _ = value <= i64::from(u16::MAX) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
 
-error: Checked cast can be simplified.
+error: checked cast can be simplified
   --> $DIR/checked_conversions.rs:27:13
    |
 LL |     let _ = value <= (u8::max_value() as isize) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()`
 
-error: Checked cast can be simplified.
+error: checked cast can be simplified
   --> $DIR/checked_conversions.rs:28:13
    |
 LL |     let _ = value <= (u8::MAX as isize) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()`
 
-error: Checked cast can be simplified.
+error: checked cast can be simplified
   --> $DIR/checked_conversions.rs:34:13
    |
 LL |     let _ = value <= (i32::max_value() as i64) && value >= (i32::min_value() as i64);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
 
-error: Checked cast can be simplified.
+error: checked cast can be simplified
   --> $DIR/checked_conversions.rs:35:13
    |
 LL |     let _ = value <= (i32::MAX as i64) && value >= (i32::MIN as i64);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
 
-error: Checked cast can be simplified.
+error: checked cast can be simplified
   --> $DIR/checked_conversions.rs:39:13
    |
 LL |     let _ = value <= i64::from(i16::max_value()) && value >= i64::from(i16::min_value());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()`
 
-error: Checked cast can be simplified.
+error: checked cast can be simplified
   --> $DIR/checked_conversions.rs:40:13
    |
 LL |     let _ = value <= i64::from(i16::MAX) && value >= i64::from(i16::MIN);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()`
 
-error: Checked cast can be simplified.
+error: checked cast can be simplified
   --> $DIR/checked_conversions.rs:46:13
    |
 LL |     let _ = value <= i32::max_value() as u32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
 
-error: Checked cast can be simplified.
+error: checked cast can be simplified
   --> $DIR/checked_conversions.rs:47:13
    |
 LL |     let _ = value <= i32::MAX as u32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
 
-error: Checked cast can be simplified.
+error: checked cast can be simplified
   --> $DIR/checked_conversions.rs:51:13
    |
 LL |     let _ = value <= isize::max_value() as usize && value as i32 == 5;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()`
 
-error: Checked cast can be simplified.
+error: checked cast can be simplified
   --> $DIR/checked_conversions.rs:52:13
    |
 LL |     let _ = value <= isize::MAX as usize && value as i32 == 5;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()`
 
-error: Checked cast can be simplified.
+error: checked cast can be simplified
   --> $DIR/checked_conversions.rs:56:13
    |
 LL |     let _ = value <= u16::max_value() as u32 && value as i32 == 5;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
 
-error: Checked cast can be simplified.
+error: checked cast can be simplified
   --> $DIR/checked_conversions.rs:57:13
    |
 LL |     let _ = value <= u16::MAX as u32 && value as i32 == 5;
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr
index dc666bab460..33bb5136ef8 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr
+++ b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr
@@ -1,4 +1,4 @@
-error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+error: you checked before that `unwrap()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match`
   --> $DIR/complex_conditionals.rs:8:9
    |
 LL |     if x.is_ok() && y.is_err() {
@@ -12,7 +12,7 @@ note: the lint level is defined here
 LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: This call to `unwrap_err()` will always panic.
+error: this call to `unwrap_err()` will always panic
   --> $DIR/complex_conditionals.rs:9:9
    |
 LL |     if x.is_ok() && y.is_err() {
@@ -27,7 +27,7 @@ note: the lint level is defined here
 LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: This call to `unwrap()` will always panic.
+error: this call to `unwrap()` will always panic
   --> $DIR/complex_conditionals.rs:10:9
    |
 LL |     if x.is_ok() && y.is_err() {
@@ -36,7 +36,7 @@ LL |     if x.is_ok() && y.is_err() {
 LL |         y.unwrap(); // will panic
    |         ^^^^^^^^^^
 
-error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+error: you checked before that `unwrap_err()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match`
   --> $DIR/complex_conditionals.rs:11:9
    |
 LL |     if x.is_ok() && y.is_err() {
@@ -45,7 +45,7 @@ LL |     if x.is_ok() && y.is_err() {
 LL |         y.unwrap_err(); // unnecessary
    |         ^^^^^^^^^^^^^^
 
-error: This call to `unwrap()` will always panic.
+error: this call to `unwrap()` will always panic
   --> $DIR/complex_conditionals.rs:25:9
    |
 LL |     if x.is_ok() || y.is_ok() {
@@ -54,7 +54,7 @@ LL |     if x.is_ok() || y.is_ok() {
 LL |         x.unwrap(); // will panic
    |         ^^^^^^^^^^
 
-error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+error: you checked before that `unwrap_err()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match`
   --> $DIR/complex_conditionals.rs:26:9
    |
 LL |     if x.is_ok() || y.is_ok() {
@@ -63,7 +63,7 @@ LL |     if x.is_ok() || y.is_ok() {
 LL |         x.unwrap_err(); // unnecessary
    |         ^^^^^^^^^^^^^^
 
-error: This call to `unwrap()` will always panic.
+error: this call to `unwrap()` will always panic
   --> $DIR/complex_conditionals.rs:27:9
    |
 LL |     if x.is_ok() || y.is_ok() {
@@ -72,7 +72,7 @@ LL |     if x.is_ok() || y.is_ok() {
 LL |         y.unwrap(); // will panic
    |         ^^^^^^^^^^
 
-error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+error: you checked before that `unwrap_err()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match`
   --> $DIR/complex_conditionals.rs:28:9
    |
 LL |     if x.is_ok() || y.is_ok() {
@@ -81,7 +81,7 @@ LL |     if x.is_ok() || y.is_ok() {
 LL |         y.unwrap_err(); // unnecessary
    |         ^^^^^^^^^^^^^^
 
-error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+error: you checked before that `unwrap()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match`
   --> $DIR/complex_conditionals.rs:32:9
    |
 LL |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
@@ -89,7 +89,7 @@ LL |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
 LL |         x.unwrap(); // unnecessary
    |         ^^^^^^^^^^
 
-error: This call to `unwrap_err()` will always panic.
+error: this call to `unwrap_err()` will always panic
   --> $DIR/complex_conditionals.rs:33:9
    |
 LL |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
@@ -98,7 +98,7 @@ LL |         x.unwrap(); // unnecessary
 LL |         x.unwrap_err(); // will panic
    |         ^^^^^^^^^^^^^^
 
-error: This call to `unwrap()` will always panic.
+error: this call to `unwrap()` will always panic
   --> $DIR/complex_conditionals.rs:34:9
    |
 LL |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
@@ -107,7 +107,7 @@ LL |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
 LL |         y.unwrap(); // will panic
    |         ^^^^^^^^^^
 
-error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+error: you checked before that `unwrap_err()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match`
   --> $DIR/complex_conditionals.rs:35:9
    |
 LL |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
@@ -116,7 +116,7 @@ LL |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
 LL |         y.unwrap_err(); // unnecessary
    |         ^^^^^^^^^^^^^^
 
-error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+error: you checked before that `unwrap()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match`
   --> $DIR/complex_conditionals.rs:36:9
    |
 LL |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
@@ -125,7 +125,7 @@ LL |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
 LL |         z.unwrap(); // unnecessary
    |         ^^^^^^^^^^
 
-error: This call to `unwrap_err()` will always panic.
+error: this call to `unwrap_err()` will always panic
   --> $DIR/complex_conditionals.rs:37:9
    |
 LL |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
@@ -134,7 +134,7 @@ LL |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
 LL |         z.unwrap_err(); // will panic
    |         ^^^^^^^^^^^^^^
 
-error: This call to `unwrap()` will always panic.
+error: this call to `unwrap()` will always panic
   --> $DIR/complex_conditionals.rs:45:9
    |
 LL |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
@@ -143,7 +143,7 @@ LL |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
 LL |         x.unwrap(); // will panic
    |         ^^^^^^^^^^
 
-error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+error: you checked before that `unwrap_err()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match`
   --> $DIR/complex_conditionals.rs:46:9
    |
 LL |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
@@ -152,7 +152,7 @@ LL |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
 LL |         x.unwrap_err(); // unnecessary
    |         ^^^^^^^^^^^^^^
 
-error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+error: you checked before that `unwrap()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match`
   --> $DIR/complex_conditionals.rs:47:9
    |
 LL |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
@@ -161,7 +161,7 @@ LL |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
 LL |         y.unwrap(); // unnecessary
    |         ^^^^^^^^^^
 
-error: This call to `unwrap_err()` will always panic.
+error: this call to `unwrap_err()` will always panic
   --> $DIR/complex_conditionals.rs:48:9
    |
 LL |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
@@ -170,7 +170,7 @@ LL |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
 LL |         y.unwrap_err(); // will panic
    |         ^^^^^^^^^^^^^^
 
-error: This call to `unwrap()` will always panic.
+error: this call to `unwrap()` will always panic
   --> $DIR/complex_conditionals.rs:49:9
    |
 LL |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
@@ -179,7 +179,7 @@ LL |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
 LL |         z.unwrap(); // will panic
    |         ^^^^^^^^^^
 
-error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+error: you checked before that `unwrap_err()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match`
   --> $DIR/complex_conditionals.rs:50:9
    |
 LL |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.stderr b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.stderr
index e4d085470c3..a01f7f956f6 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.stderr
+++ b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.stderr
@@ -1,4 +1,4 @@
-error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+error: you checked before that `unwrap()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match`
   --> $DIR/complex_conditionals_nested.rs:8:13
    |
 LL |         if x.is_some() {
@@ -12,7 +12,7 @@ note: the lint level is defined here
 LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: This call to `unwrap()` will always panic.
+error: this call to `unwrap()` will always panic
   --> $DIR/complex_conditionals_nested.rs:10:13
    |
 LL |         if x.is_some() {
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
index 4013d1ed667..416ec1a01ab 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
+++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
@@ -1,4 +1,4 @@
-error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+error: you checked before that `unwrap()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match`
   --> $DIR/simple_conditionals.rs:39:9
    |
 LL |     if x.is_some() {
@@ -12,7 +12,7 @@ note: the lint level is defined here
 LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: This call to `unwrap()` will always panic.
+error: this call to `unwrap()` will always panic
   --> $DIR/simple_conditionals.rs:41:9
    |
 LL |     if x.is_some() {
@@ -27,7 +27,7 @@ note: the lint level is defined here
 LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: This call to `unwrap()` will always panic.
+error: this call to `unwrap()` will always panic
   --> $DIR/simple_conditionals.rs:44:9
    |
 LL |     if x.is_none() {
@@ -35,7 +35,7 @@ LL |     if x.is_none() {
 LL |         x.unwrap(); // will panic
    |         ^^^^^^^^^^
 
-error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+error: you checked before that `unwrap()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match`
   --> $DIR/simple_conditionals.rs:46:9
    |
 LL |     if x.is_none() {
@@ -44,7 +44,7 @@ LL |     if x.is_none() {
 LL |         x.unwrap(); // unnecessary
    |         ^^^^^^^^^^
 
-error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+error: you checked before that `unwrap()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match`
   --> $DIR/simple_conditionals.rs:7:13
    |
 LL |         if $a.is_some() {
@@ -57,7 +57,7 @@ LL |     m!(x);
    |
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+error: you checked before that `unwrap()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match`
   --> $DIR/simple_conditionals.rs:54:9
    |
 LL |     if x.is_ok() {
@@ -65,7 +65,7 @@ LL |     if x.is_ok() {
 LL |         x.unwrap(); // unnecessary
    |         ^^^^^^^^^^
 
-error: This call to `unwrap_err()` will always panic.
+error: this call to `unwrap_err()` will always panic
   --> $DIR/simple_conditionals.rs:55:9
    |
 LL |     if x.is_ok() {
@@ -74,7 +74,7 @@ LL |         x.unwrap(); // unnecessary
 LL |         x.unwrap_err(); // will panic
    |         ^^^^^^^^^^^^^^
 
-error: This call to `unwrap()` will always panic.
+error: this call to `unwrap()` will always panic
   --> $DIR/simple_conditionals.rs:57:9
    |
 LL |     if x.is_ok() {
@@ -83,7 +83,7 @@ LL |     if x.is_ok() {
 LL |         x.unwrap(); // will panic
    |         ^^^^^^^^^^
 
-error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+error: you checked before that `unwrap_err()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match`
   --> $DIR/simple_conditionals.rs:58:9
    |
 LL |     if x.is_ok() {
@@ -92,7 +92,7 @@ LL |     if x.is_ok() {
 LL |         x.unwrap_err(); // unnecessary
    |         ^^^^^^^^^^^^^^
 
-error: This call to `unwrap()` will always panic.
+error: this call to `unwrap()` will always panic
   --> $DIR/simple_conditionals.rs:61:9
    |
 LL |     if x.is_err() {
@@ -100,7 +100,7 @@ LL |     if x.is_err() {
 LL |         x.unwrap(); // will panic
    |         ^^^^^^^^^^
 
-error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+error: you checked before that `unwrap_err()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match`
   --> $DIR/simple_conditionals.rs:62:9
    |
 LL |     if x.is_err() {
@@ -109,7 +109,7 @@ LL |         x.unwrap(); // will panic
 LL |         x.unwrap_err(); // unnecessary
    |         ^^^^^^^^^^^^^^
 
-error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+error: you checked before that `unwrap()` cannot fail, instead of checking and unwrapping, it's better to use `if let` or `match`
   --> $DIR/simple_conditionals.rs:64:9
    |
 LL |     if x.is_err() {
@@ -118,7 +118,7 @@ LL |     if x.is_err() {
 LL |         x.unwrap(); // unnecessary
    |         ^^^^^^^^^^
 
-error: This call to `unwrap_err()` will always panic.
+error: this call to `unwrap_err()` will always panic
   --> $DIR/simple_conditionals.rs:65:9
    |
 LL |     if x.is_err() {
diff --git a/src/tools/clippy/tests/ui/cmp_null.stderr b/src/tools/clippy/tests/ui/cmp_null.stderr
index b563a2ebec2..a1f4c70fb27 100644
--- a/src/tools/clippy/tests/ui/cmp_null.stderr
+++ b/src/tools/clippy/tests/ui/cmp_null.stderr
@@ -1,4 +1,4 @@
-error: Comparing with null is better expressed by the `.is_null()` method
+error: comparing with null is better expressed by the `.is_null()` method
   --> $DIR/cmp_null.rs:9:8
    |
 LL |     if p == ptr::null() {
@@ -6,7 +6,7 @@ LL |     if p == ptr::null() {
    |
    = note: `-D clippy::cmp-null` implied by `-D warnings`
 
-error: Comparing with null is better expressed by the `.is_null()` method
+error: comparing with null is better expressed by the `.is_null()` method
   --> $DIR/cmp_null.rs:14:8
    |
 LL |     if m == ptr::null_mut() {
diff --git a/src/tools/clippy/tests/ui/crashes/ice-5872.rs b/src/tools/clippy/tests/ui/crashes/ice-5872.rs
new file mode 100644
index 00000000000..68afa8f8c3a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-5872.rs
@@ -0,0 +1,5 @@
+#![warn(clippy::needless_collect)]
+
+fn main() {
+    let _ = vec![1, 2, 3].into_iter().collect::<Vec<_>>().is_empty();
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-5872.stderr b/src/tools/clippy/tests/ui/crashes/ice-5872.stderr
new file mode 100644
index 00000000000..a60ca345cf7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-5872.stderr
@@ -0,0 +1,10 @@
+error: avoid using `collect()` when not needed
+  --> $DIR/ice-5872.rs:4:39
+   |
+LL |     let _ = vec![1, 2, 3].into_iter().collect::<Vec<_>>().is_empty();
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()`
+   |
+   = note: `-D clippy::needless-collect` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/default_trait_access.stderr b/src/tools/clippy/tests/ui/default_trait_access.stderr
index 453760c6b92..26b2057548b 100644
--- a/src/tools/clippy/tests/ui/default_trait_access.stderr
+++ b/src/tools/clippy/tests/ui/default_trait_access.stderr
@@ -1,4 +1,4 @@
-error: Calling `std::string::String::default()` is more clear than this expression
+error: calling `std::string::String::default()` is more clear than this expression
   --> $DIR/default_trait_access.rs:8:22
    |
 LL |     let s1: String = Default::default();
@@ -6,43 +6,43 @@ LL |     let s1: String = Default::default();
    |
    = note: `-D clippy::default-trait-access` implied by `-D warnings`
 
-error: Calling `std::string::String::default()` is more clear than this expression
+error: calling `std::string::String::default()` is more clear than this expression
   --> $DIR/default_trait_access.rs:12:22
    |
 LL |     let s3: String = D2::default();
    |                      ^^^^^^^^^^^^^ help: try: `std::string::String::default()`
 
-error: Calling `std::string::String::default()` is more clear than this expression
+error: calling `std::string::String::default()` is more clear than this expression
   --> $DIR/default_trait_access.rs:14:22
    |
 LL |     let s4: String = std::default::Default::default();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
 
-error: Calling `std::string::String::default()` is more clear than this expression
+error: calling `std::string::String::default()` is more clear than this expression
   --> $DIR/default_trait_access.rs:18:22
    |
 LL |     let s6: String = default::Default::default();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
 
-error: Calling `GenericDerivedDefault<std::string::String>::default()` is more clear than this expression
+error: calling `GenericDerivedDefault<std::string::String>::default()` is more clear than this expression
   --> $DIR/default_trait_access.rs:28:46
    |
 LL |     let s11: GenericDerivedDefault<String> = Default::default();
    |                                              ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault<std::string::String>::default()`
 
-error: Calling `TupleDerivedDefault::default()` is more clear than this expression
+error: calling `TupleDerivedDefault::default()` is more clear than this expression
   --> $DIR/default_trait_access.rs:34:36
    |
 LL |     let s14: TupleDerivedDefault = Default::default();
    |                                    ^^^^^^^^^^^^^^^^^^ help: try: `TupleDerivedDefault::default()`
 
-error: Calling `ArrayDerivedDefault::default()` is more clear than this expression
+error: calling `ArrayDerivedDefault::default()` is more clear than this expression
   --> $DIR/default_trait_access.rs:36:36
    |
 LL |     let s15: ArrayDerivedDefault = Default::default();
    |                                    ^^^^^^^^^^^^^^^^^^ help: try: `ArrayDerivedDefault::default()`
 
-error: Calling `TupleStructDerivedDefault::default()` is more clear than this expression
+error: calling `TupleStructDerivedDefault::default()` is more clear than this expression
   --> $DIR/default_trait_access.rs:40:42
    |
 LL |     let s17: TupleStructDerivedDefault = Default::default();
diff --git a/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.rs b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.rs
new file mode 100644
index 00000000000..b82dc518a3b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.rs
@@ -0,0 +1,68 @@
+#![warn(clippy::derive_ord_xor_partial_ord)]
+
+use std::cmp::Ordering;
+
+#[derive(PartialOrd, Ord, PartialEq, Eq)]
+struct DeriveBoth;
+
+impl PartialEq<u64> for DeriveBoth {
+    fn eq(&self, _: &u64) -> bool {
+        true
+    }
+}
+
+impl PartialOrd<u64> for DeriveBoth {
+    fn partial_cmp(&self, _: &u64) -> Option<Ordering> {
+        Some(Ordering::Equal)
+    }
+}
+
+#[derive(Ord, PartialEq, Eq)]
+struct DeriveOrd;
+
+impl PartialOrd for DeriveOrd {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(other.cmp(self))
+    }
+}
+
+#[derive(Ord, PartialEq, Eq)]
+struct DeriveOrdWithExplicitTypeVariable;
+
+impl PartialOrd<DeriveOrdWithExplicitTypeVariable> for DeriveOrdWithExplicitTypeVariable {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(other.cmp(self))
+    }
+}
+
+#[derive(PartialOrd, PartialEq, Eq)]
+struct DerivePartialOrd;
+
+impl std::cmp::Ord for DerivePartialOrd {
+    fn cmp(&self, other: &Self) -> Ordering {
+        Ordering::Less
+    }
+}
+
+#[derive(PartialOrd, PartialEq, Eq)]
+struct ImplUserOrd;
+
+trait Ord {}
+
+// We don't want to lint on user-defined traits called `Ord`
+impl Ord for ImplUserOrd {}
+
+mod use_ord {
+    use std::cmp::{Ord, Ordering};
+
+    #[derive(PartialOrd, PartialEq, Eq)]
+    struct DerivePartialOrdInUseOrd;
+
+    impl Ord for DerivePartialOrdInUseOrd {
+        fn cmp(&self, other: &Self) -> Ordering {
+            Ordering::Less
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr
new file mode 100644
index 00000000000..66bc4d42ce8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr
@@ -0,0 +1,71 @@
+error: you are deriving `Ord` but have implemented `PartialOrd` explicitly
+  --> $DIR/derive_ord_xor_partial_ord.rs:20:10
+   |
+LL | #[derive(Ord, PartialEq, Eq)]
+   |          ^^^
+   |
+   = note: `-D clippy::derive-ord-xor-partial-ord` implied by `-D warnings`
+note: `PartialOrd` implemented here
+  --> $DIR/derive_ord_xor_partial_ord.rs:23:1
+   |
+LL | / impl PartialOrd for DeriveOrd {
+LL | |     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+LL | |         Some(other.cmp(self))
+LL | |     }
+LL | | }
+   | |_^
+   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: you are deriving `Ord` but have implemented `PartialOrd` explicitly
+  --> $DIR/derive_ord_xor_partial_ord.rs:29:10
+   |
+LL | #[derive(Ord, PartialEq, Eq)]
+   |          ^^^
+   |
+note: `PartialOrd` implemented here
+  --> $DIR/derive_ord_xor_partial_ord.rs:32:1
+   |
+LL | / impl PartialOrd<DeriveOrdWithExplicitTypeVariable> for DeriveOrdWithExplicitTypeVariable {
+LL | |     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+LL | |         Some(other.cmp(self))
+LL | |     }
+LL | | }
+   | |_^
+   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: you are implementing `Ord` explicitly but have derived `PartialOrd`
+  --> $DIR/derive_ord_xor_partial_ord.rs:41:1
+   |
+LL | / impl std::cmp::Ord for DerivePartialOrd {
+LL | |     fn cmp(&self, other: &Self) -> Ordering {
+LL | |         Ordering::Less
+LL | |     }
+LL | | }
+   | |_^
+   |
+note: `PartialOrd` implemented here
+  --> $DIR/derive_ord_xor_partial_ord.rs:38:10
+   |
+LL | #[derive(PartialOrd, PartialEq, Eq)]
+   |          ^^^^^^^^^^
+   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: you are implementing `Ord` explicitly but have derived `PartialOrd`
+  --> $DIR/derive_ord_xor_partial_ord.rs:61:5
+   |
+LL | /     impl Ord for DerivePartialOrdInUseOrd {
+LL | |         fn cmp(&self, other: &Self) -> Ordering {
+LL | |             Ordering::Less
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+note: `PartialOrd` implemented here
+  --> $DIR/derive_ord_xor_partial_ord.rs:58:14
+   |
+LL |     #[derive(PartialOrd, PartialEq, Eq)]
+   |              ^^^^^^^^^^
+   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/double_comparison.stderr b/src/tools/clippy/tests/ui/double_comparison.stderr
index 5dcda7b3af4..05ef4e25f7f 100644
--- a/src/tools/clippy/tests/ui/double_comparison.stderr
+++ b/src/tools/clippy/tests/ui/double_comparison.stderr
@@ -1,4 +1,4 @@
-error: This binary expression can be simplified
+error: this binary expression can be simplified
   --> $DIR/double_comparison.rs:6:8
    |
 LL |     if x == y || x < y {
@@ -6,43 +6,43 @@ LL |     if x == y || x < y {
    |
    = note: `-D clippy::double-comparisons` implied by `-D warnings`
 
-error: This binary expression can be simplified
+error: this binary expression can be simplified
   --> $DIR/double_comparison.rs:9:8
    |
 LL |     if x < y || x == y {
    |        ^^^^^^^^^^^^^^^ help: try: `x <= y`
 
-error: This binary expression can be simplified
+error: this binary expression can be simplified
   --> $DIR/double_comparison.rs:12:8
    |
 LL |     if x == y || x > y {
    |        ^^^^^^^^^^^^^^^ help: try: `x >= y`
 
-error: This binary expression can be simplified
+error: this binary expression can be simplified
   --> $DIR/double_comparison.rs:15:8
    |
 LL |     if x > y || x == y {
    |        ^^^^^^^^^^^^^^^ help: try: `x >= y`
 
-error: This binary expression can be simplified
+error: this binary expression can be simplified
   --> $DIR/double_comparison.rs:18:8
    |
 LL |     if x < y || x > y {
    |        ^^^^^^^^^^^^^^ help: try: `x != y`
 
-error: This binary expression can be simplified
+error: this binary expression can be simplified
   --> $DIR/double_comparison.rs:21:8
    |
 LL |     if x > y || x < y {
    |        ^^^^^^^^^^^^^^ help: try: `x != y`
 
-error: This binary expression can be simplified
+error: this binary expression can be simplified
   --> $DIR/double_comparison.rs:24:8
    |
 LL |     if x <= y && x >= y {
    |        ^^^^^^^^^^^^^^^^ help: try: `x == y`
 
-error: This binary expression can be simplified
+error: this binary expression can be simplified
   --> $DIR/double_comparison.rs:27:8
    |
 LL |     if x >= y && x <= y {
diff --git a/src/tools/clippy/tests/ui/double_parens.stderr b/src/tools/clippy/tests/ui/double_parens.stderr
index 0e4c9b5682d..40fcad2ab1d 100644
--- a/src/tools/clippy/tests/ui/double_parens.stderr
+++ b/src/tools/clippy/tests/ui/double_parens.stderr
@@ -1,4 +1,4 @@
-error: Consider removing unnecessary double parentheses
+error: consider removing unnecessary double parentheses
   --> $DIR/double_parens.rs:15:5
    |
 LL |     ((0))
@@ -6,31 +6,31 @@ LL |     ((0))
    |
    = note: `-D clippy::double-parens` implied by `-D warnings`
 
-error: Consider removing unnecessary double parentheses
+error: consider removing unnecessary double parentheses
   --> $DIR/double_parens.rs:19:14
    |
 LL |     dummy_fn((0));
    |              ^^^
 
-error: Consider removing unnecessary double parentheses
+error: consider removing unnecessary double parentheses
   --> $DIR/double_parens.rs:23:20
    |
 LL |     x.dummy_method((0));
    |                    ^^^
 
-error: Consider removing unnecessary double parentheses
+error: consider removing unnecessary double parentheses
   --> $DIR/double_parens.rs:27:5
    |
 LL |     ((1, 2))
    |     ^^^^^^^^
 
-error: Consider removing unnecessary double parentheses
+error: consider removing unnecessary double parentheses
   --> $DIR/double_parens.rs:31:5
    |
 LL |     (())
    |     ^^^^
 
-error: Consider removing unnecessary double parentheses
+error: consider removing unnecessary double parentheses
   --> $DIR/double_parens.rs:53:16
    |
 LL |     assert_eq!(((1, 2)), (1, 2), "Error");
diff --git a/src/tools/clippy/tests/ui/drop_bounds.stderr b/src/tools/clippy/tests/ui/drop_bounds.stderr
index 5d360ef30a1..8208c0ed7e3 100644
--- a/src/tools/clippy/tests/ui/drop_bounds.stderr
+++ b/src/tools/clippy/tests/ui/drop_bounds.stderr
@@ -1,4 +1,4 @@
-error: Bounds of the form `T: Drop` are useless. Use `std::mem::needs_drop` to detect if a type has drop glue.
+error: bounds of the form `T: Drop` are useless, use `std::mem::needs_drop` to detect if a type has drop glue
   --> $DIR/drop_bounds.rs:2:11
    |
 LL | fn foo<T: Drop>() {}
@@ -6,7 +6,7 @@ LL | fn foo<T: Drop>() {}
    |
    = note: `#[deny(clippy::drop_bounds)]` on by default
 
-error: Bounds of the form `T: Drop` are useless. Use `std::mem::needs_drop` to detect if a type has drop glue.
+error: bounds of the form `T: Drop` are useless, use `std::mem::needs_drop` to detect if a type has drop glue
   --> $DIR/drop_bounds.rs:5:8
    |
 LL |     T: Drop,
diff --git a/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.stderr b/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.stderr
index bf753a732f0..594fca44a32 100644
--- a/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.stderr
+++ b/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.stderr
@@ -1,4 +1,4 @@
-error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
+error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
   --> $DIR/empty_line_after_outer_attribute.rs:11:1
    |
 LL | / #[crate_type = "lib"]
@@ -9,7 +9,7 @@ LL | | fn with_one_newline_and_comment() { assert!(true) }
    |
    = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings`
 
-error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
+error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
   --> $DIR/empty_line_after_outer_attribute.rs:23:1
    |
 LL | / #[crate_type = "lib"]
@@ -17,7 +17,7 @@ LL | |
 LL | | fn with_one_newline() { assert!(true) }
    | |_
 
-error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
+error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
   --> $DIR/empty_line_after_outer_attribute.rs:28:1
    |
 LL | / #[crate_type = "lib"]
@@ -26,7 +26,7 @@ LL | |
 LL | | fn with_two_newlines() { assert!(true) }
    | |_
 
-error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
+error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
   --> $DIR/empty_line_after_outer_attribute.rs:35:1
    |
 LL | / #[crate_type = "lib"]
@@ -34,7 +34,7 @@ LL | |
 LL | | enum Baz {
    | |_
 
-error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
+error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
   --> $DIR/empty_line_after_outer_attribute.rs:43:1
    |
 LL | / #[crate_type = "lib"]
@@ -42,7 +42,7 @@ LL | |
 LL | | struct Foo {
    | |_
 
-error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
+error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
   --> $DIR/empty_line_after_outer_attribute.rs:51:1
    |
 LL | / #[crate_type = "lib"]
diff --git a/src/tools/clippy/tests/ui/extra_unused_lifetimes.rs b/src/tools/clippy/tests/ui/extra_unused_lifetimes.rs
index ddbf4e98c51..150acfbfee7 100644
--- a/src/tools/clippy/tests/ui/extra_unused_lifetimes.rs
+++ b/src/tools/clippy/tests/ui/extra_unused_lifetimes.rs
@@ -1,4 +1,10 @@
-#![allow(unused, dead_code, clippy::needless_lifetimes, clippy::needless_pass_by_value)]
+#![allow(
+    unused,
+    dead_code,
+    clippy::needless_lifetimes,
+    clippy::needless_pass_by_value,
+    clippy::needless_arbitrary_self_type
+)]
 #![warn(clippy::extra_unused_lifetimes)]
 
 fn empty() {}
diff --git a/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr b/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr
index 16bbb1c037d..ebdb8e74952 100644
--- a/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr
+++ b/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr
@@ -1,5 +1,5 @@
 error: this lifetime isn't used in the function definition
-  --> $DIR/extra_unused_lifetimes.rs:8:14
+  --> $DIR/extra_unused_lifetimes.rs:14:14
    |
 LL | fn unused_lt<'a>(x: u8) {}
    |              ^^
@@ -7,19 +7,19 @@ LL | fn unused_lt<'a>(x: u8) {}
    = note: `-D clippy::extra-unused-lifetimes` implied by `-D warnings`
 
 error: this lifetime isn't used in the function definition
-  --> $DIR/extra_unused_lifetimes.rs:10:25
+  --> $DIR/extra_unused_lifetimes.rs:16:25
    |
 LL | fn unused_lt_transitive<'a, 'b: 'a>(x: &'b u8) {
    |                         ^^
 
 error: this lifetime isn't used in the function definition
-  --> $DIR/extra_unused_lifetimes.rs:35:10
+  --> $DIR/extra_unused_lifetimes.rs:41:10
    |
 LL |     fn x<'a>(&self) {}
    |          ^^
 
 error: this lifetime isn't used in the function definition
-  --> $DIR/extra_unused_lifetimes.rs:61:22
+  --> $DIR/extra_unused_lifetimes.rs:67:22
    |
 LL |         fn unused_lt<'a>(x: u8) {}
    |                      ^^
diff --git a/src/tools/clippy/tests/ui/functions_maxlines.stderr b/src/tools/clippy/tests/ui/functions_maxlines.stderr
index 9b0e7550cc3..c640c82d6d7 100644
--- a/src/tools/clippy/tests/ui/functions_maxlines.stderr
+++ b/src/tools/clippy/tests/ui/functions_maxlines.stderr
@@ -1,4 +1,4 @@
-error: This function has a large number of lines.
+error: this function has a large number of lines
   --> $DIR/functions_maxlines.rs:58:1
    |
 LL | / fn bad_lines() {
diff --git a/src/tools/clippy/tests/ui/iter_skip_next.fixed b/src/tools/clippy/tests/ui/iter_skip_next.fixed
new file mode 100644
index 00000000000..928b6acb951
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_skip_next.fixed
@@ -0,0 +1,22 @@
+// run-rustfix
+// aux-build:option_helpers.rs
+
+#![warn(clippy::iter_skip_next)]
+#![allow(clippy::blacklisted_name)]
+#![allow(clippy::iter_nth)]
+
+extern crate option_helpers;
+
+use option_helpers::IteratorFalsePositives;
+
+/// Checks implementation of `ITER_SKIP_NEXT` lint
+fn main() {
+    let some_vec = vec![0, 1, 2, 3];
+    let _ = some_vec.iter().nth(42);
+    let _ = some_vec.iter().cycle().nth(42);
+    let _ = (1..10).nth(10);
+    let _ = &some_vec[..].iter().nth(3);
+    let foo = IteratorFalsePositives { foo: 0 };
+    let _ = foo.skip(42).next();
+    let _ = foo.filter().skip(42).next();
+}
diff --git a/src/tools/clippy/tests/ui/iter_skip_next.rs b/src/tools/clippy/tests/ui/iter_skip_next.rs
index a65ca3bbb13..7075e2598eb 100644
--- a/src/tools/clippy/tests/ui/iter_skip_next.rs
+++ b/src/tools/clippy/tests/ui/iter_skip_next.rs
@@ -1,15 +1,17 @@
+// run-rustfix
 // aux-build:option_helpers.rs
 
 #![warn(clippy::iter_skip_next)]
 #![allow(clippy::blacklisted_name)]
+#![allow(clippy::iter_nth)]
 
 extern crate option_helpers;
 
 use option_helpers::IteratorFalsePositives;
 
 /// Checks implementation of `ITER_SKIP_NEXT` lint
-fn iter_skip_next() {
-    let mut some_vec = vec![0, 1, 2, 3];
+fn main() {
+    let some_vec = vec![0, 1, 2, 3];
     let _ = some_vec.iter().skip(42).next();
     let _ = some_vec.iter().cycle().skip(42).next();
     let _ = (1..10).skip(10).next();
@@ -18,5 +20,3 @@ fn iter_skip_next() {
     let _ = foo.skip(42).next();
     let _ = foo.filter().skip(42).next();
 }
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/iter_skip_next.stderr b/src/tools/clippy/tests/ui/iter_skip_next.stderr
index 5709f335529..feedc2f288a 100644
--- a/src/tools/clippy/tests/ui/iter_skip_next.stderr
+++ b/src/tools/clippy/tests/ui/iter_skip_next.stderr
@@ -1,35 +1,28 @@
 error: called `skip(x).next()` on an iterator
-  --> $DIR/iter_skip_next.rs:13:13
+  --> $DIR/iter_skip_next.rs:15:28
    |
 LL |     let _ = some_vec.iter().skip(42).next();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                            ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(42)`
    |
    = note: `-D clippy::iter-skip-next` implied by `-D warnings`
-   = help: this is more succinctly expressed by calling `nth(x)`
 
 error: called `skip(x).next()` on an iterator
-  --> $DIR/iter_skip_next.rs:14:13
+  --> $DIR/iter_skip_next.rs:16:36
    |
 LL |     let _ = some_vec.iter().cycle().skip(42).next();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: this is more succinctly expressed by calling `nth(x)`
+   |                                    ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(42)`
 
 error: called `skip(x).next()` on an iterator
-  --> $DIR/iter_skip_next.rs:15:13
+  --> $DIR/iter_skip_next.rs:17:20
    |
 LL |     let _ = (1..10).skip(10).next();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: this is more succinctly expressed by calling `nth(x)`
+   |                    ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(10)`
 
 error: called `skip(x).next()` on an iterator
-  --> $DIR/iter_skip_next.rs:16:14
+  --> $DIR/iter_skip_next.rs:18:33
    |
 LL |     let _ = &some_vec[..].iter().skip(3).next();
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: this is more succinctly expressed by calling `nth(x)`
+   |                                 ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(3)`
 
 error: aborting due to 4 previous errors
 
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 3ef29dd6388..b5211318a15 100644
--- a/src/tools/clippy/tests/ui/len_without_is_empty.rs
+++ b/src/tools/clippy/tests/ui/len_without_is_empty.rs
@@ -4,14 +4,14 @@
 pub struct PubOne;
 
 impl PubOne {
-    pub fn len(self: &Self) -> isize {
+    pub fn len(&self) -> isize {
         1
     }
 }
 
 impl PubOne {
     // A second impl for this struct -- the error span shouldn't mention this.
-    pub fn irrelevant(self: &Self) -> bool {
+    pub fn irrelevant(&self) -> bool {
         false
     }
 }
@@ -21,7 +21,7 @@ pub struct PubAllowed;
 
 #[allow(clippy::len_without_is_empty)]
 impl PubAllowed {
-    pub fn len(self: &Self) -> isize {
+    pub fn len(&self) -> isize {
         1
     }
 }
@@ -29,17 +29,17 @@ impl PubAllowed {
 // No `allow` attribute on this impl block, but that doesn't matter -- we only require one on the
 // impl containing `len`.
 impl PubAllowed {
-    pub fn irrelevant(self: &Self) -> bool {
+    pub fn irrelevant(&self) -> bool {
         false
     }
 }
 
 pub trait PubTraitsToo {
-    fn len(self: &Self) -> isize;
+    fn len(&self) -> isize;
 }
 
 impl PubTraitsToo for One {
-    fn len(self: &Self) -> isize {
+    fn len(&self) -> isize {
         0
     }
 }
@@ -47,11 +47,11 @@ impl PubTraitsToo for One {
 pub struct HasIsEmpty;
 
 impl HasIsEmpty {
-    pub fn len(self: &Self) -> isize {
+    pub fn len(&self) -> isize {
         1
     }
 
-    fn is_empty(self: &Self) -> bool {
+    fn is_empty(&self) -> bool {
         false
     }
 }
@@ -59,11 +59,11 @@ impl HasIsEmpty {
 pub struct HasWrongIsEmpty;
 
 impl HasWrongIsEmpty {
-    pub fn len(self: &Self) -> isize {
+    pub fn len(&self) -> isize {
         1
     }
 
-    pub fn is_empty(self: &Self, x: u32) -> bool {
+    pub fn is_empty(&self, x: u32) -> bool {
         false
     }
 }
@@ -71,7 +71,7 @@ impl HasWrongIsEmpty {
 struct NotPubOne;
 
 impl NotPubOne {
-    pub fn len(self: &Self) -> isize {
+    pub fn len(&self) -> isize {
         // No error; `len` is pub but `NotPubOne` is not exported anyway.
         1
     }
@@ -80,19 +80,19 @@ impl NotPubOne {
 struct One;
 
 impl One {
-    fn len(self: &Self) -> isize {
+    fn len(&self) -> isize {
         // No error; `len` is private; see issue #1085.
         1
     }
 }
 
 trait TraitsToo {
-    fn len(self: &Self) -> isize;
+    fn len(&self) -> isize;
     // No error; `len` is private; see issue #1085.
 }
 
 impl TraitsToo for One {
-    fn len(self: &Self) -> isize {
+    fn len(&self) -> isize {
         0
     }
 }
@@ -100,11 +100,11 @@ impl TraitsToo for One {
 struct HasPrivateIsEmpty;
 
 impl HasPrivateIsEmpty {
-    pub fn len(self: &Self) -> isize {
+    pub fn len(&self) -> isize {
         1
     }
 
-    fn is_empty(self: &Self) -> bool {
+    fn is_empty(&self) -> bool {
         false
     }
 }
@@ -112,16 +112,16 @@ impl HasPrivateIsEmpty {
 struct Wither;
 
 pub trait WithIsEmpty {
-    fn len(self: &Self) -> isize;
-    fn is_empty(self: &Self) -> bool;
+    fn len(&self) -> isize;
+    fn is_empty(&self) -> bool;
 }
 
 impl WithIsEmpty for Wither {
-    fn len(self: &Self) -> isize {
+    fn len(&self) -> isize {
         1
     }
 
-    fn is_empty(self: &Self) -> bool {
+    fn is_empty(&self) -> bool {
         false
     }
 }
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 4493b17a4b4..d79c300c074 100644
--- a/src/tools/clippy/tests/ui/len_without_is_empty.stderr
+++ b/src/tools/clippy/tests/ui/len_without_is_empty.stderr
@@ -2,7 +2,7 @@ error: item `PubOne` has a public `len` method but no corresponding `is_empty` m
   --> $DIR/len_without_is_empty.rs:6:1
    |
 LL | / impl PubOne {
-LL | |     pub fn len(self: &Self) -> isize {
+LL | |     pub fn len(&self) -> isize {
 LL | |         1
 LL | |     }
 LL | | }
@@ -14,7 +14,7 @@ error: trait `PubTraitsToo` has a `len` method but no (possibly inherited) `is_e
   --> $DIR/len_without_is_empty.rs:37:1
    |
 LL | / pub trait PubTraitsToo {
-LL | |     fn len(self: &Self) -> isize;
+LL | |     fn len(&self) -> isize;
 LL | | }
    | |_^
 
@@ -22,7 +22,7 @@ error: item `HasIsEmpty` has a public `len` method but a private `is_empty` meth
   --> $DIR/len_without_is_empty.rs:49:1
    |
 LL | / impl HasIsEmpty {
-LL | |     pub fn len(self: &Self) -> isize {
+LL | |     pub fn len(&self) -> isize {
 LL | |         1
 LL | |     }
 ...  |
@@ -34,7 +34,7 @@ error: item `HasWrongIsEmpty` has a public `len` method but no corresponding `is
   --> $DIR/len_without_is_empty.rs:61:1
    |
 LL | / impl HasWrongIsEmpty {
-LL | |     pub fn len(self: &Self) -> isize {
+LL | |     pub fn len(&self) -> isize {
 LL | |         1
 LL | |     }
 ...  |
diff --git a/src/tools/clippy/tests/ui/len_zero.fixed b/src/tools/clippy/tests/ui/len_zero.fixed
index a29b832eb60..d81676a3d9f 100644
--- a/src/tools/clippy/tests/ui/len_zero.fixed
+++ b/src/tools/clippy/tests/ui/len_zero.fixed
@@ -7,12 +7,12 @@ pub struct One;
 struct Wither;
 
 trait TraitsToo {
-    fn len(self: &Self) -> isize;
+    fn len(&self) -> isize;
     // No error; `len` is private; see issue #1085.
 }
 
 impl TraitsToo for One {
-    fn len(self: &Self) -> isize {
+    fn len(&self) -> isize {
         0
     }
 }
@@ -20,11 +20,11 @@ impl TraitsToo for One {
 pub struct HasIsEmpty;
 
 impl HasIsEmpty {
-    pub fn len(self: &Self) -> isize {
+    pub fn len(&self) -> isize {
         1
     }
 
-    fn is_empty(self: &Self) -> bool {
+    fn is_empty(&self) -> bool {
         false
     }
 }
@@ -32,26 +32,26 @@ impl HasIsEmpty {
 pub struct HasWrongIsEmpty;
 
 impl HasWrongIsEmpty {
-    pub fn len(self: &Self) -> isize {
+    pub fn len(&self) -> isize {
         1
     }
 
-    pub fn is_empty(self: &Self, x: u32) -> bool {
+    pub fn is_empty(&self, x: u32) -> bool {
         false
     }
 }
 
 pub trait WithIsEmpty {
-    fn len(self: &Self) -> isize;
-    fn is_empty(self: &Self) -> bool;
+    fn len(&self) -> isize;
+    fn is_empty(&self) -> bool;
 }
 
 impl WithIsEmpty for Wither {
-    fn len(self: &Self) -> isize {
+    fn len(&self) -> isize {
         1
     }
 
-    fn is_empty(self: &Self) -> bool {
+    fn is_empty(&self) -> bool {
         false
     }
 }
diff --git a/src/tools/clippy/tests/ui/len_zero.rs b/src/tools/clippy/tests/ui/len_zero.rs
index 8fd0093f4fd..ecdba921a5d 100644
--- a/src/tools/clippy/tests/ui/len_zero.rs
+++ b/src/tools/clippy/tests/ui/len_zero.rs
@@ -7,12 +7,12 @@ pub struct One;
 struct Wither;
 
 trait TraitsToo {
-    fn len(self: &Self) -> isize;
+    fn len(&self) -> isize;
     // No error; `len` is private; see issue #1085.
 }
 
 impl TraitsToo for One {
-    fn len(self: &Self) -> isize {
+    fn len(&self) -> isize {
         0
     }
 }
@@ -20,11 +20,11 @@ impl TraitsToo for One {
 pub struct HasIsEmpty;
 
 impl HasIsEmpty {
-    pub fn len(self: &Self) -> isize {
+    pub fn len(&self) -> isize {
         1
     }
 
-    fn is_empty(self: &Self) -> bool {
+    fn is_empty(&self) -> bool {
         false
     }
 }
@@ -32,26 +32,26 @@ impl HasIsEmpty {
 pub struct HasWrongIsEmpty;
 
 impl HasWrongIsEmpty {
-    pub fn len(self: &Self) -> isize {
+    pub fn len(&self) -> isize {
         1
     }
 
-    pub fn is_empty(self: &Self, x: u32) -> bool {
+    pub fn is_empty(&self, x: u32) -> bool {
         false
     }
 }
 
 pub trait WithIsEmpty {
-    fn len(self: &Self) -> isize;
-    fn is_empty(self: &Self) -> bool;
+    fn len(&self) -> isize;
+    fn is_empty(&self) -> bool;
 }
 
 impl WithIsEmpty for Wither {
-    fn len(self: &Self) -> isize {
+    fn len(&self) -> isize {
         1
     }
 
-    fn is_empty(self: &Self) -> bool {
+    fn is_empty(&self) -> bool {
         false
     }
 }
diff --git a/src/tools/clippy/tests/ui/manual_async_fn.fixed b/src/tools/clippy/tests/ui/manual_async_fn.fixed
index 27222cc0869..4f551690c43 100644
--- a/src/tools/clippy/tests/ui/manual_async_fn.fixed
+++ b/src/tools/clippy/tests/ui/manual_async_fn.fixed
@@ -43,10 +43,6 @@ impl S {
         42
     }
 
-    async fn meth_fut(&self) -> i32 { 42 }
-
-    async fn empty_fut(&self)  {}
-
     // should be ignored
     fn not_fut(&self) -> i32 {
         42
@@ -64,4 +60,40 @@ impl S {
     }
 }
 
+// Tests related to lifetime capture
+
+async fn elided(_: &i32) -> i32 { 42 }
+
+// should be ignored
+fn elided_not_bound(_: &i32) -> impl Future<Output = i32> {
+    async { 42 }
+}
+
+async fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> i32 { 42 }
+
+// should be ignored
+#[allow(clippy::needless_lifetimes)]
+fn explicit_not_bound<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> {
+    async { 42 }
+}
+
+// should be ignored
+mod issue_5765 {
+    use std::future::Future;
+
+    struct A;
+    impl A {
+        fn f(&self) -> impl Future<Output = ()> {
+            async {}
+        }
+    }
+
+    fn test() {
+        let _future = {
+            let a = A;
+            a.f()
+        };
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/manual_async_fn.rs b/src/tools/clippy/tests/ui/manual_async_fn.rs
index 6a0f1b26c88..6ed60309947 100644
--- a/src/tools/clippy/tests/ui/manual_async_fn.rs
+++ b/src/tools/clippy/tests/ui/manual_async_fn.rs
@@ -51,14 +51,6 @@ impl S {
         }
     }
 
-    fn meth_fut(&self) -> impl Future<Output = i32> {
-        async { 42 }
-    }
-
-    fn empty_fut(&self) -> impl Future<Output = ()> {
-        async {}
-    }
-
     // should be ignored
     fn not_fut(&self) -> i32 {
         42
@@ -76,4 +68,44 @@ impl S {
     }
 }
 
+// Tests related to lifetime capture
+
+fn elided(_: &i32) -> impl Future<Output = i32> + '_ {
+    async { 42 }
+}
+
+// should be ignored
+fn elided_not_bound(_: &i32) -> impl Future<Output = i32> {
+    async { 42 }
+}
+
+fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> + 'a + 'b {
+    async { 42 }
+}
+
+// should be ignored
+#[allow(clippy::needless_lifetimes)]
+fn explicit_not_bound<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> {
+    async { 42 }
+}
+
+// should be ignored
+mod issue_5765 {
+    use std::future::Future;
+
+    struct A;
+    impl A {
+        fn f(&self) -> impl Future<Output = ()> {
+            async {}
+        }
+    }
+
+    fn test() {
+        let _future = {
+            let a = A;
+            a.f()
+        };
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/manual_async_fn.stderr b/src/tools/clippy/tests/ui/manual_async_fn.stderr
index a1904c904d0..ccd82867427 100644
--- a/src/tools/clippy/tests/ui/manual_async_fn.stderr
+++ b/src/tools/clippy/tests/ui/manual_async_fn.stderr
@@ -65,34 +65,34 @@ LL |             let c = 21;
  ...
 
 error: this function can be simplified using the `async fn` syntax
-  --> $DIR/manual_async_fn.rs:54:5
+  --> $DIR/manual_async_fn.rs:73:1
    |
-LL |     fn meth_fut(&self) -> impl Future<Output = i32> {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn elided(_: &i32) -> impl Future<Output = i32> + '_ {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: make the function `async` and return the output of the future directly
    |
-LL |     async fn meth_fut(&self) -> i32 {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | async fn elided(_: &i32) -> i32 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: move the body of the async block to the enclosing function
    |
-LL |     fn meth_fut(&self) -> impl Future<Output = i32> { 42 }
-   |                                                     ^^^^^^
+LL | fn elided(_: &i32) -> impl Future<Output = i32> + '_ { 42 }
+   |                                                      ^^^^^^
 
 error: this function can be simplified using the `async fn` syntax
-  --> $DIR/manual_async_fn.rs:58:5
+  --> $DIR/manual_async_fn.rs:82:1
    |
-LL |     fn empty_fut(&self) -> impl Future<Output = ()> {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> + 'a + 'b {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: make the function `async` and remove the return type
+help: make the function `async` and return the output of the future directly
    |
-LL |     async fn empty_fut(&self)  {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | async fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> i32 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: move the body of the async block to the enclosing function
    |
-LL |     fn empty_fut(&self) -> impl Future<Output = ()> {}
-   |                                                     ^^
+LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> + 'a + 'b { 42 }
+   |                                                                                    ^^^^^^
 
 error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/map_flatten.fixed b/src/tools/clippy/tests/ui/map_flatten.fixed
index 4171d80f48a..a5fdf7df613 100644
--- a/src/tools/clippy/tests/ui/map_flatten.fixed
+++ b/src/tools/clippy/tests/ui/map_flatten.fixed
@@ -5,6 +5,20 @@
 #![allow(clippy::map_identity)]
 
 fn main() {
+    // mapping to Option on Iterator
+    fn option_id(x: i8) -> Option<i8> {
+        Some(x)
+    }
+    let option_id_ref: fn(i8) -> Option<i8> = option_id;
+    let option_id_closure = |x| Some(x);
+    let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id).collect();
+    let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id_ref).collect();
+    let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id_closure).collect();
+    let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(|x| x.checked_add(1)).collect();
+
+    // mapping to Iterator on Iterator
     let _: Vec<_> = vec![5_i8; 6].into_iter().flat_map(|x| 0..x).collect();
+
+    // mapping to Option on Option
     let _: Option<_> = (Some(Some(1))).and_then(|x| x);
 }
diff --git a/src/tools/clippy/tests/ui/map_flatten.rs b/src/tools/clippy/tests/ui/map_flatten.rs
index 16a0fd090ad..abbc4e16e56 100644
--- a/src/tools/clippy/tests/ui/map_flatten.rs
+++ b/src/tools/clippy/tests/ui/map_flatten.rs
@@ -5,6 +5,20 @@
 #![allow(clippy::map_identity)]
 
 fn main() {
+    // mapping to Option on Iterator
+    fn option_id(x: i8) -> Option<i8> {
+        Some(x)
+    }
+    let option_id_ref: fn(i8) -> Option<i8> = option_id;
+    let option_id_closure = |x| Some(x);
+    let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect();
+    let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect();
+    let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect();
+    let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect();
+
+    // mapping to Iterator on Iterator
     let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
+
+    // mapping to Option on Option
     let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
 }
diff --git a/src/tools/clippy/tests/ui/map_flatten.stderr b/src/tools/clippy/tests/ui/map_flatten.stderr
index 00bc41c15e9..b6479cd69ea 100644
--- a/src/tools/clippy/tests/ui/map_flatten.stderr
+++ b/src/tools/clippy/tests/ui/map_flatten.stderr
@@ -1,16 +1,40 @@
-error: called `map(..).flatten()` on an `Iterator`. This is more succinctly expressed by calling `.flat_map(..)`
-  --> $DIR/map_flatten.rs:8:21
+error: called `map(..).flatten()` on an `Iterator`
+  --> $DIR/map_flatten.rs:14:46
    |
-LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `flat_map` instead: `vec![5_i8; 6].into_iter().flat_map(|x| 0..x)`
+LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect();
+   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id)`
    |
    = note: `-D clippy::map-flatten` implied by `-D warnings`
 
-error: called `map(..).flatten()` on an `Option`. This is more succinctly expressed by calling `.and_then(..)`
-  --> $DIR/map_flatten.rs:9:24
+error: called `map(..).flatten()` on an `Iterator`
+  --> $DIR/map_flatten.rs:15:46
+   |
+LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect();
+   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_ref)`
+
+error: called `map(..).flatten()` on an `Iterator`
+  --> $DIR/map_flatten.rs:16:46
+   |
+LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect();
+   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_closure)`
+
+error: called `map(..).flatten()` on an `Iterator`
+  --> $DIR/map_flatten.rs:17:46
+   |
+LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect();
+   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(|x| x.checked_add(1))`
+
+error: called `map(..).flatten()` on an `Iterator`
+  --> $DIR/map_flatten.rs:20:46
+   |
+LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
+   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `flat_map` instead: `.flat_map(|x| 0..x)`
+
+error: called `map(..).flatten()` on an `Option`
+  --> $DIR/map_flatten.rs:23:39
    |
 LL |     let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
-   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `(Some(Some(1))).and_then(|x| x)`
+   |                                       ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `.and_then(|x| x)`
 
-error: aborting due to 2 previous errors
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/min_max.rs b/src/tools/clippy/tests/ui/min_max.rs
index 8307d4b3019..f7ed72a11cf 100644
--- a/src/tools/clippy/tests/ui/min_max.rs
+++ b/src/tools/clippy/tests/ui/min_max.rs
@@ -6,6 +6,18 @@ use std::cmp::{max, min};
 
 const LARGE: usize = 3;
 
+struct NotOrd(u64);
+
+impl NotOrd {
+    fn min(self, x: u64) -> NotOrd {
+        NotOrd(x)
+    }
+
+    fn max(self, x: u64) -> NotOrd {
+        NotOrd(x)
+    }
+}
+
 fn main() {
     let x;
     x = 2usize;
@@ -30,4 +42,24 @@ fn main() {
     max(min(s, "Apple"), "Zoo");
 
     max("Apple", min(s, "Zoo")); // ok
+
+    let f = 3f32;
+    x.min(1).max(3);
+    x.max(3).min(1);
+    f.max(3f32).min(1f32);
+
+    x.max(1).min(3); // ok
+    x.min(3).max(1); // ok
+    f.min(3f32).max(1f32); // ok
+
+    max(x.min(1), 3);
+    min(x.max(1), 3); // ok
+
+    s.max("Zoo").min("Apple");
+    s.min("Apple").max("Zoo");
+
+    s.min("Zoo").max("Apple"); // ok
+
+    let not_ord = NotOrd(1);
+    not_ord.min(1).max(3); // ok
 }
diff --git a/src/tools/clippy/tests/ui/min_max.stderr b/src/tools/clippy/tests/ui/min_max.stderr
index b552c137f7c..9f8e26fa406 100644
--- a/src/tools/clippy/tests/ui/min_max.stderr
+++ b/src/tools/clippy/tests/ui/min_max.stderr
@@ -1,5 +1,5 @@
 error: this `min`/`max` combination leads to constant result
-  --> $DIR/min_max.rs:12:5
+  --> $DIR/min_max.rs:24:5
    |
 LL |     min(1, max(3, x));
    |     ^^^^^^^^^^^^^^^^^
@@ -7,40 +7,76 @@ LL |     min(1, max(3, x));
    = note: `-D clippy::min-max` implied by `-D warnings`
 
 error: this `min`/`max` combination leads to constant result
-  --> $DIR/min_max.rs:13:5
+  --> $DIR/min_max.rs:25:5
    |
 LL |     min(max(3, x), 1);
    |     ^^^^^^^^^^^^^^^^^
 
 error: this `min`/`max` combination leads to constant result
-  --> $DIR/min_max.rs:14:5
+  --> $DIR/min_max.rs:26:5
    |
 LL |     max(min(x, 1), 3);
    |     ^^^^^^^^^^^^^^^^^
 
 error: this `min`/`max` combination leads to constant result
-  --> $DIR/min_max.rs:15:5
+  --> $DIR/min_max.rs:27:5
    |
 LL |     max(3, min(x, 1));
    |     ^^^^^^^^^^^^^^^^^
 
 error: this `min`/`max` combination leads to constant result
-  --> $DIR/min_max.rs:17:5
+  --> $DIR/min_max.rs:29:5
    |
 LL |     my_max(3, my_min(x, 1));
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this `min`/`max` combination leads to constant result
-  --> $DIR/min_max.rs:29:5
+  --> $DIR/min_max.rs:41:5
    |
 LL |     min("Apple", max("Zoo", s));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this `min`/`max` combination leads to constant result
-  --> $DIR/min_max.rs:30:5
+  --> $DIR/min_max.rs:42:5
    |
 LL |     max(min(s, "Apple"), "Zoo");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 7 previous errors
+error: this `min`/`max` combination leads to constant result
+  --> $DIR/min_max.rs:47:5
+   |
+LL |     x.min(1).max(3);
+   |     ^^^^^^^^^^^^^^^
+
+error: this `min`/`max` combination leads to constant result
+  --> $DIR/min_max.rs:48:5
+   |
+LL |     x.max(3).min(1);
+   |     ^^^^^^^^^^^^^^^
+
+error: this `min`/`max` combination leads to constant result
+  --> $DIR/min_max.rs:49:5
+   |
+LL |     f.max(3f32).min(1f32);
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: this `min`/`max` combination leads to constant result
+  --> $DIR/min_max.rs:55:5
+   |
+LL |     max(x.min(1), 3);
+   |     ^^^^^^^^^^^^^^^^
+
+error: this `min`/`max` combination leads to constant result
+  --> $DIR/min_max.rs:58:5
+   |
+LL |     s.max("Zoo").min("Apple");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this `min`/`max` combination leads to constant result
+  --> $DIR/min_max.rs:59:5
+   |
+LL |     s.min("Apple").max("Zoo");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed
new file mode 100644
index 00000000000..9da21eb6b29
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed
@@ -0,0 +1,69 @@
+// run-rustfix
+
+#![warn(clippy::needless_arbitrary_self_type)]
+#![allow(unused_mut, clippy::needless_lifetimes)]
+
+pub enum ValType {
+    A,
+    B,
+}
+
+impl ValType {
+    pub fn bad(self) {
+        unimplemented!();
+    }
+
+    pub fn good(self) {
+        unimplemented!();
+    }
+
+    pub fn mut_bad(mut self) {
+        unimplemented!();
+    }
+
+    pub fn mut_good(mut self) {
+        unimplemented!();
+    }
+
+    pub fn ref_bad(&self) {
+        unimplemented!();
+    }
+
+    pub fn ref_good(&self) {
+        unimplemented!();
+    }
+
+    pub fn ref_bad_with_lifetime<'a>(&'a self) {
+        unimplemented!();
+    }
+
+    pub fn ref_good_with_lifetime<'a>(&'a self) {
+        unimplemented!();
+    }
+
+    pub fn mut_ref_bad(&mut self) {
+        unimplemented!();
+    }
+
+    pub fn mut_ref_good(&mut self) {
+        unimplemented!();
+    }
+
+    pub fn mut_ref_bad_with_lifetime<'a>(&'a mut self) {
+        unimplemented!();
+    }
+
+    pub fn mut_ref_good_with_lifetime<'a>(&'a mut self) {
+        unimplemented!();
+    }
+
+    pub fn mut_ref_mut_good(mut self: &mut Self) {
+        unimplemented!();
+    }
+
+    pub fn mut_ref_mut_ref_good(self: &&mut &mut Self) {
+        unimplemented!();
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs
new file mode 100644
index 00000000000..17aeaaf97ac
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs
@@ -0,0 +1,69 @@
+// run-rustfix
+
+#![warn(clippy::needless_arbitrary_self_type)]
+#![allow(unused_mut, clippy::needless_lifetimes)]
+
+pub enum ValType {
+    A,
+    B,
+}
+
+impl ValType {
+    pub fn bad(self: Self) {
+        unimplemented!();
+    }
+
+    pub fn good(self) {
+        unimplemented!();
+    }
+
+    pub fn mut_bad(mut self: Self) {
+        unimplemented!();
+    }
+
+    pub fn mut_good(mut self) {
+        unimplemented!();
+    }
+
+    pub fn ref_bad(self: &Self) {
+        unimplemented!();
+    }
+
+    pub fn ref_good(&self) {
+        unimplemented!();
+    }
+
+    pub fn ref_bad_with_lifetime<'a>(self: &'a Self) {
+        unimplemented!();
+    }
+
+    pub fn ref_good_with_lifetime<'a>(&'a self) {
+        unimplemented!();
+    }
+
+    pub fn mut_ref_bad(self: &mut Self) {
+        unimplemented!();
+    }
+
+    pub fn mut_ref_good(&mut self) {
+        unimplemented!();
+    }
+
+    pub fn mut_ref_bad_with_lifetime<'a>(self: &'a mut Self) {
+        unimplemented!();
+    }
+
+    pub fn mut_ref_good_with_lifetime<'a>(&'a mut self) {
+        unimplemented!();
+    }
+
+    pub fn mut_ref_mut_good(mut self: &mut Self) {
+        unimplemented!();
+    }
+
+    pub fn mut_ref_mut_ref_good(self: &&mut &mut Self) {
+        unimplemented!();
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr
new file mode 100644
index 00000000000..f4c645d35c8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr
@@ -0,0 +1,40 @@
+error: the type of the `self` parameter does not need to be arbitrary
+  --> $DIR/needless_arbitrary_self_type.rs:12:16
+   |
+LL |     pub fn bad(self: Self) {
+   |                ^^^^^^^^^^ help: consider to change this parameter to: `self`
+   |
+   = note: `-D clippy::needless-arbitrary-self-type` implied by `-D warnings`
+
+error: the type of the `self` parameter does not need to be arbitrary
+  --> $DIR/needless_arbitrary_self_type.rs:20:20
+   |
+LL |     pub fn mut_bad(mut self: Self) {
+   |                    ^^^^^^^^^^^^^^ help: consider to change this parameter to: `mut self`
+
+error: the type of the `self` parameter does not need to be arbitrary
+  --> $DIR/needless_arbitrary_self_type.rs:28:20
+   |
+LL |     pub fn ref_bad(self: &Self) {
+   |                    ^^^^^^^^^^^ help: consider to change this parameter to: `&self`
+
+error: the type of the `self` parameter does not need to be arbitrary
+  --> $DIR/needless_arbitrary_self_type.rs:36:38
+   |
+LL |     pub fn ref_bad_with_lifetime<'a>(self: &'a Self) {
+   |                                      ^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'a self`
+
+error: the type of the `self` parameter does not need to be arbitrary
+  --> $DIR/needless_arbitrary_self_type.rs:44:24
+   |
+LL |     pub fn mut_ref_bad(self: &mut Self) {
+   |                        ^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&mut self`
+
+error: the type of the `self` parameter does not need to be arbitrary
+  --> $DIR/needless_arbitrary_self_type.rs:52:42
+   |
+LL |     pub fn mut_ref_bad_with_lifetime<'a>(self: &'a mut Self) {
+   |                                          ^^^^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'a mut self`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_collect.fixed b/src/tools/clippy/tests/ui/needless_collect.fixed
index be37dc16b9a..7f2fcf02f6b 100644
--- a/src/tools/clippy/tests/ui/needless_collect.fixed
+++ b/src/tools/clippy/tests/ui/needless_collect.fixed
@@ -5,11 +5,11 @@
 use std::collections::{BTreeSet, HashMap, HashSet};
 
 #[warn(clippy::needless_collect)]
-#[allow(unused_variables, clippy::iter_cloned_collect)]
+#[allow(unused_variables, clippy::iter_cloned_collect, clippy::iter_next_slice)]
 fn main() {
     let sample = [1; 5];
     let len = sample.iter().count();
-    if sample.get(0).is_none() {
+    if sample.iter().next().is_none() {
         // Empty
     }
     sample.iter().cloned().any(|x| x == 1);
diff --git a/src/tools/clippy/tests/ui/needless_collect.rs b/src/tools/clippy/tests/ui/needless_collect.rs
index 7ee603afeb0..788a9eb3264 100644
--- a/src/tools/clippy/tests/ui/needless_collect.rs
+++ b/src/tools/clippy/tests/ui/needless_collect.rs
@@ -5,7 +5,7 @@
 use std::collections::{BTreeSet, HashMap, HashSet};
 
 #[warn(clippy::needless_collect)]
-#[allow(unused_variables, clippy::iter_cloned_collect)]
+#[allow(unused_variables, clippy::iter_cloned_collect, clippy::iter_next_slice)]
 fn main() {
     let sample = [1; 5];
     let len = sample.iter().collect::<Vec<_>>().len();
diff --git a/src/tools/clippy/tests/ui/needless_collect.stderr b/src/tools/clippy/tests/ui/needless_collect.stderr
index 9113aad90dd..2a9539d5975 100644
--- a/src/tools/clippy/tests/ui/needless_collect.stderr
+++ b/src/tools/clippy/tests/ui/needless_collect.stderr
@@ -7,10 +7,10 @@ LL |     let len = sample.iter().collect::<Vec<_>>().len();
    = note: `-D clippy::needless-collect` implied by `-D warnings`
 
 error: avoid using `collect()` when not needed
-  --> $DIR/needless_collect.rs:12:15
+  --> $DIR/needless_collect.rs:12:22
    |
 LL |     if sample.iter().collect::<Vec<_>>().is_empty() {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get(0).is_none()`
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()`
 
 error: avoid using `collect()` when not needed
   --> $DIR/needless_collect.rs:15:28
diff --git a/src/tools/clippy/tests/ui/needless_collect_indirect.rs b/src/tools/clippy/tests/ui/needless_collect_indirect.rs
new file mode 100644
index 00000000000..4cf03e82035
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_collect_indirect.rs
@@ -0,0 +1,19 @@
+use std::collections::{HashMap, VecDeque};
+
+fn main() {
+    let sample = [1; 5];
+    let indirect_iter = sample.iter().collect::<Vec<_>>();
+    indirect_iter.into_iter().map(|x| (x, x + 1)).collect::<HashMap<_, _>>();
+    let indirect_len = sample.iter().collect::<VecDeque<_>>();
+    indirect_len.len();
+    let indirect_empty = sample.iter().collect::<VecDeque<_>>();
+    indirect_empty.is_empty();
+    let indirect_contains = sample.iter().collect::<VecDeque<_>>();
+    indirect_contains.contains(&&5);
+    let indirect_negative = sample.iter().collect::<Vec<_>>();
+    indirect_negative.len();
+    indirect_negative
+        .into_iter()
+        .map(|x| (*x, *x + 1))
+        .collect::<HashMap<_, _>>();
+}
diff --git a/src/tools/clippy/tests/ui/needless_collect_indirect.stderr b/src/tools/clippy/tests/ui/needless_collect_indirect.stderr
new file mode 100644
index 00000000000..0c1e61d7496
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_collect_indirect.stderr
@@ -0,0 +1,55 @@
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect_indirect.rs:5:5
+   |
+LL | /     let indirect_iter = sample.iter().collect::<Vec<_>>();
+LL | |     indirect_iter.into_iter().map(|x| (x, x + 1)).collect::<HashMap<_, _>>();
+   | |____^
+   |
+   = note: `-D clippy::needless-collect` implied by `-D warnings`
+help: Use the original Iterator instead of collecting it and then producing a new one
+   |
+LL |     
+LL |     sample.iter().map(|x| (x, x + 1)).collect::<HashMap<_, _>>();
+   |
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect_indirect.rs:7:5
+   |
+LL | /     let indirect_len = sample.iter().collect::<VecDeque<_>>();
+LL | |     indirect_len.len();
+   | |____^
+   |
+help: Take the original Iterator's count instead of collecting it and finding the length
+   |
+LL |     
+LL |     sample.iter().count();
+   |
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect_indirect.rs:9:5
+   |
+LL | /     let indirect_empty = sample.iter().collect::<VecDeque<_>>();
+LL | |     indirect_empty.is_empty();
+   | |____^
+   |
+help: Check if the original Iterator has anything instead of collecting it and seeing if it's empty
+   |
+LL |     
+LL |     sample.iter().next().is_none();
+   |
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect_indirect.rs:11:5
+   |
+LL | /     let indirect_contains = sample.iter().collect::<VecDeque<_>>();
+LL | |     indirect_contains.contains(&&5);
+   | |____^
+   |
+help: Check if the original Iterator contains an element instead of collecting then checking
+   |
+LL |     
+LL |     sample.iter().any(|x| x == &&5);
+   |
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr b/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr
index 8c5d548222e..c7856000721 100644
--- a/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr
+++ b/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr
@@ -1,4 +1,4 @@
-error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable.
+error: the use of negated comparison operators on partially ordered types produces code that is hard to read and refactor, please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable
   --> $DIR/neg_cmp_op_on_partial_ord.rs:16:21
    |
 LL |     let _not_less = !(a_value < another_value);
@@ -6,19 +6,19 @@ LL |     let _not_less = !(a_value < another_value);
    |
    = note: `-D clippy::neg-cmp-op-on-partial-ord` implied by `-D warnings`
 
-error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable.
+error: the use of negated comparison operators on partially ordered types produces code that is hard to read and refactor, please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable
   --> $DIR/neg_cmp_op_on_partial_ord.rs:19:30
    |
 LL |     let _not_less_or_equal = !(a_value <= another_value);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable.
+error: the use of negated comparison operators on partially ordered types produces code that is hard to read and refactor, please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable
   --> $DIR/neg_cmp_op_on_partial_ord.rs:22:24
    |
 LL |     let _not_greater = !(a_value > another_value);
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable.
+error: the use of negated comparison operators on partially ordered types produces code that is hard to read and refactor, please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable
   --> $DIR/neg_cmp_op_on_partial_ord.rs:25:33
    |
 LL |     let _not_greater_or_equal = !(a_value >= another_value);
diff --git a/src/tools/clippy/tests/ui/neg_multiply.stderr b/src/tools/clippy/tests/ui/neg_multiply.stderr
index f08bbd6a12c..ad677f6d6fb 100644
--- a/src/tools/clippy/tests/ui/neg_multiply.stderr
+++ b/src/tools/clippy/tests/ui/neg_multiply.stderr
@@ -1,4 +1,4 @@
-error: Negation by multiplying with `-1`
+error: negation by multiplying with `-1`
   --> $DIR/neg_multiply.rs:27:5
    |
 LL |     x * -1;
@@ -6,7 +6,7 @@ LL |     x * -1;
    |
    = note: `-D clippy::neg-multiply` implied by `-D warnings`
 
-error: Negation by multiplying with `-1`
+error: negation by multiplying with `-1`
   --> $DIR/neg_multiply.rs:29:5
    |
 LL |     -1 * x;
diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed
index 9a0da404cb6..96d1c54946c 100644
--- a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed
+++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed
@@ -22,9 +22,9 @@ struct HasOption {
 }
 
 impl HasOption {
-    fn do_option_nothing(self: &Self, value: usize) {}
+    fn do_option_nothing(&self, value: usize) {}
 
-    fn do_option_plus_one(self: &Self, value: usize) -> usize {
+    fn do_option_plus_one(&self, value: usize) -> usize {
         value + 1
     }
 }
diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs
index 58041b62df3..931ffc18665 100644
--- a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs
+++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs
@@ -22,9 +22,9 @@ struct HasOption {
 }
 
 impl HasOption {
-    fn do_option_nothing(self: &Self, value: usize) {}
+    fn do_option_nothing(&self, value: usize) {}
 
-    fn do_option_plus_one(self: &Self, value: usize) -> usize {
+    fn do_option_plus_one(&self, value: usize) -> usize {
         value + 1
     }
 }
diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed
index 2045ffdb5f0..67faa8bd4a0 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.fixed
+++ b/src/tools/clippy/tests/ui/or_fun_call.fixed
@@ -116,4 +116,12 @@ fn f() -> Option<()> {
     Some(())
 }
 
+// Issue 5886 - const fn (with no arguments)
+pub fn skip_const_fn_with_no_args() {
+    const fn foo() -> Option<i32> {
+        Some(42)
+    }
+    let _ = None.or(foo());
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs
index 522f31b72d0..9867e2eedcf 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.rs
+++ b/src/tools/clippy/tests/ui/or_fun_call.rs
@@ -116,4 +116,12 @@ fn f() -> Option<()> {
     Some(())
 }
 
+// Issue 5886 - const fn (with no arguments)
+pub fn skip_const_fn_with_no_args() {
+    const fn foo() -> Option<i32> {
+        Some(42)
+    }
+    let _ = None.or(foo());
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/overflow_check_conditional.stderr b/src/tools/clippy/tests/ui/overflow_check_conditional.stderr
index ad66135d326..19e843c2c0a 100644
--- a/src/tools/clippy/tests/ui/overflow_check_conditional.stderr
+++ b/src/tools/clippy/tests/ui/overflow_check_conditional.stderr
@@ -1,4 +1,4 @@
-error: You are trying to use classic C overflow conditions that will fail in Rust.
+error: you are trying to use classic C overflow conditions that will fail in Rust
   --> $DIR/overflow_check_conditional.rs:8:8
    |
 LL |     if a + b < a {}
@@ -6,43 +6,43 @@ LL |     if a + b < a {}
    |
    = note: `-D clippy::overflow-check-conditional` implied by `-D warnings`
 
-error: You are trying to use classic C overflow conditions that will fail in Rust.
+error: you are trying to use classic C overflow conditions that will fail in Rust
   --> $DIR/overflow_check_conditional.rs:9:8
    |
 LL |     if a > a + b {}
    |        ^^^^^^^^^
 
-error: You are trying to use classic C overflow conditions that will fail in Rust.
+error: you are trying to use classic C overflow conditions that will fail in Rust
   --> $DIR/overflow_check_conditional.rs:10:8
    |
 LL |     if a + b < b {}
    |        ^^^^^^^^^
 
-error: You are trying to use classic C overflow conditions that will fail in Rust.
+error: you are trying to use classic C overflow conditions that will fail in Rust
   --> $DIR/overflow_check_conditional.rs:11:8
    |
 LL |     if b > a + b {}
    |        ^^^^^^^^^
 
-error: You are trying to use classic C underflow conditions that will fail in Rust.
+error: you are trying to use classic C underflow conditions that will fail in Rust
   --> $DIR/overflow_check_conditional.rs:12:8
    |
 LL |     if a - b > b {}
    |        ^^^^^^^^^
 
-error: You are trying to use classic C underflow conditions that will fail in Rust.
+error: you are trying to use classic C underflow conditions that will fail in Rust
   --> $DIR/overflow_check_conditional.rs:13:8
    |
 LL |     if b < a - b {}
    |        ^^^^^^^^^
 
-error: You are trying to use classic C underflow conditions that will fail in Rust.
+error: you are trying to use classic C underflow conditions that will fail in Rust
   --> $DIR/overflow_check_conditional.rs:14:8
    |
 LL |     if a - b > a {}
    |        ^^^^^^^^^
 
-error: You are trying to use classic C underflow conditions that will fail in Rust.
+error: you are trying to use classic C underflow conditions that will fail in Rust
   --> $DIR/overflow_check_conditional.rs:15:8
    |
 LL |     if a < a - b {}
diff --git a/src/tools/clippy/tests/ui/path_buf_push_overwrite.stderr b/src/tools/clippy/tests/ui/path_buf_push_overwrite.stderr
index 09b18d71baf..bb8dce2bbba 100644
--- a/src/tools/clippy/tests/ui/path_buf_push_overwrite.stderr
+++ b/src/tools/clippy/tests/ui/path_buf_push_overwrite.stderr
@@ -1,4 +1,4 @@
-error: Calling `push` with '/' or '/' (file system root) will overwrite the previous path definition
+error: calling `push` with '/' or '/' (file system root) will overwrite the previous path definition
   --> $DIR/path_buf_push_overwrite.rs:7:12
    |
 LL |     x.push("/bar");
diff --git a/src/tools/clippy/tests/ui/range.stderr b/src/tools/clippy/tests/ui/range.stderr
index d53c1edecac..dcb5061371f 100644
--- a/src/tools/clippy/tests/ui/range.stderr
+++ b/src/tools/clippy/tests/ui/range.stderr
@@ -1,4 +1,4 @@
-error: It is more idiomatic to use `v1.iter().enumerate()`
+error: it is more idiomatic to use `v1.iter().enumerate()`
   --> $DIR/range.rs:5:14
    |
 LL |     let _x = v1.iter().zip(0..v1.len());
diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr b/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr
index 3c3d2eacd8d..649831f9c06 100644
--- a/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr
+++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr
@@ -1,4 +1,4 @@
-error: Constants have by default a `'static` lifetime
+error: constants have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes.rs:8:17
    |
 LL | const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removing 'static.
@@ -6,91 +6,91 @@ LL | const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removin
    |
    = note: `-D clippy::redundant-static-lifetimes` implied by `-D warnings`
 
-error: Constants have by default a `'static` lifetime
+error: constants have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes.rs:12:21
    |
 LL | const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
    |                    -^^^^^^^---- help: consider removing `'static`: `&str`
 
-error: Constants have by default a `'static` lifetime
+error: constants have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes.rs:14:32
    |
 LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
    |                               -^^^^^^^---- help: consider removing `'static`: `&str`
 
-error: Constants have by default a `'static` lifetime
+error: constants have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes.rs:14:47
    |
 LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
    |                                              -^^^^^^^---- help: consider removing `'static`: `&str`
 
-error: Constants have by default a `'static` lifetime
+error: constants have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes.rs:16:17
    |
 LL | const VAR_SIX: &'static u8 = &5;
    |                -^^^^^^^--- help: consider removing `'static`: `&u8`
 
-error: Constants have by default a `'static` lifetime
+error: constants have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes.rs:18:20
    |
 LL | const VAR_HEIGHT: &'static Foo = &Foo {};
    |                   -^^^^^^^---- help: consider removing `'static`: `&Foo`
 
-error: Constants have by default a `'static` lifetime
+error: constants have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes.rs:20:19
    |
 LL | const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR Consider removing 'static.
    |                  -^^^^^^^----- help: consider removing `'static`: `&[u8]`
 
-error: Constants have by default a `'static` lifetime
+error: constants have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes.rs:22:19
    |
 LL | const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
    |                  -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)`
 
-error: Constants have by default a `'static` lifetime
+error: constants have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes.rs:24:19
    |
 LL | const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
    |                  -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]`
 
-error: Statics have by default a `'static` lifetime
+error: statics have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes.rs:26:25
    |
 LL | static STATIC_VAR_ONE: &'static str = "Test static #1"; // ERROR Consider removing 'static.
    |                        -^^^^^^^---- help: consider removing `'static`: `&str`
 
-error: Statics have by default a `'static` lifetime
+error: statics have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes.rs:30:29
    |
 LL | static STATIC_VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
    |                            -^^^^^^^---- help: consider removing `'static`: `&str`
 
-error: Statics have by default a `'static` lifetime
+error: statics have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes.rs:32:25
    |
 LL | static STATIC_VAR_SIX: &'static u8 = &5;
    |                        -^^^^^^^--- help: consider removing `'static`: `&u8`
 
-error: Statics have by default a `'static` lifetime
+error: statics have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes.rs:34:28
    |
 LL | static STATIC_VAR_HEIGHT: &'static Foo = &Foo {};
    |                           -^^^^^^^---- help: consider removing `'static`: `&Foo`
 
-error: Statics have by default a `'static` lifetime
+error: statics have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes.rs:36:27
    |
 LL | static STATIC_VAR_SLICE: &'static [u8] = b"Test static #3"; // ERROR Consider removing 'static.
    |                          -^^^^^^^----- help: consider removing `'static`: `&[u8]`
 
-error: Statics have by default a `'static` lifetime
+error: statics have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes.rs:38:27
    |
 LL | static STATIC_VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
    |                          -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)`
 
-error: Statics have by default a `'static` lifetime
+error: statics have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes.rs:40:27
    |
 LL | static STATIC_VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.stderr b/src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.stderr
index afc853dcfce..cc7e55a757a 100644
--- a/src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.stderr
+++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.stderr
@@ -1,4 +1,4 @@
-error: Constants have by default a `'static` lifetime
+error: constants have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes_multiple.rs:3:18
    |
 LL | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static
@@ -6,55 +6,55 @@ LL | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]];
    |
    = note: `-D clippy::redundant-static-lifetimes` implied by `-D warnings`
 
-error: Constants have by default a `'static` lifetime
+error: constants have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes_multiple.rs:3:30
    |
 LL | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static
    |                             -^^^^^^^---- help: consider removing `'static`: `&str`
 
-error: Constants have by default a `'static` lifetime
+error: constants have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes_multiple.rs:5:29
    |
 LL | const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])];
    |                            -^^^^^^^--------------- help: consider removing `'static`: `&[&'static str]`
 
-error: Constants have by default a `'static` lifetime
+error: constants have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes_multiple.rs:5:39
    |
 LL | const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])];
    |                                      -^^^^^^^---- help: consider removing `'static`: `&str`
 
-error: Statics have by default a `'static` lifetime
+error: statics have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes_multiple.rs:7:40
    |
 LL | static STATIC_VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
    |                                       -^^^^^^^---- help: consider removing `'static`: `&str`
 
-error: Statics have by default a `'static` lifetime
+error: statics have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes_multiple.rs:7:55
    |
 LL | static STATIC_VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
    |                                                      -^^^^^^^---- help: consider removing `'static`: `&str`
 
-error: Statics have by default a `'static` lifetime
+error: statics have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes_multiple.rs:9:26
    |
 LL | static STATIC_VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static
    |                         -^^^^^^^------------------ help: consider removing `'static`: `&[&[&'static str]]`
 
-error: Statics have by default a `'static` lifetime
+error: statics have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes_multiple.rs:9:38
    |
 LL | static STATIC_VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static
    |                                     -^^^^^^^---- help: consider removing `'static`: `&str`
 
-error: Statics have by default a `'static` lifetime
+error: statics have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes_multiple.rs:11:37
    |
 LL | static STATIC_VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])];
    |                                    -^^^^^^^--------------- help: consider removing `'static`: `&[&'static str]`
 
-error: Statics have by default a `'static` lifetime
+error: statics have by default a `'static` lifetime
   --> $DIR/redundant_static_lifetimes_multiple.rs:11:47
    |
 LL | static STATIC_VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])];
diff --git a/src/tools/clippy/tests/ui/renamed_builtin_attr.stderr b/src/tools/clippy/tests/ui/renamed_builtin_attr.stderr
index a399ff52fb8..88046762483 100644
--- a/src/tools/clippy/tests/ui/renamed_builtin_attr.stderr
+++ b/src/tools/clippy/tests/ui/renamed_builtin_attr.stderr
@@ -1,4 +1,4 @@
-error: Usage of deprecated attribute
+error: usage of deprecated attribute
   --> $DIR/renamed_builtin_attr.rs:3:11
    |
 LL | #[clippy::cyclomatic_complexity = "1"]
diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.fixed b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.fixed
index 1d0a3ecd0ff..631042c616b 100644
--- a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.fixed
+++ b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.fixed
@@ -18,9 +18,9 @@ struct HasResult {
 }
 
 impl HasResult {
-    fn do_result_nothing(self: &Self, value: usize) {}
+    fn do_result_nothing(&self, value: usize) {}
 
-    fn do_result_plus_one(self: &Self, value: usize) -> usize {
+    fn do_result_plus_one(&self, value: usize) -> usize {
         value + 1
     }
 }
diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.rs b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.rs
index 2fe18f923f0..679eb232626 100644
--- a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.rs
+++ b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.rs
@@ -18,9 +18,9 @@ struct HasResult {
 }
 
 impl HasResult {
-    fn do_result_nothing(self: &Self, value: usize) {}
+    fn do_result_nothing(&self, value: usize) {}
 
-    fn do_result_plus_one(self: &Self, value: usize) -> usize {
+    fn do_result_plus_one(&self, value: usize) -> usize {
         value + 1
     }
 }
diff --git a/src/tools/clippy/tests/ui/same_item_push.rs b/src/tools/clippy/tests/ui/same_item_push.rs
new file mode 100644
index 00000000000..ff1088f86f6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/same_item_push.rs
@@ -0,0 +1,89 @@
+#![warn(clippy::same_item_push)]
+
+fn mutate_increment(x: &mut u8) -> u8 {
+    *x += 1;
+    *x
+}
+
+fn increment(x: u8) -> u8 {
+    x + 1
+}
+
+fn main() {
+    // Test for basic case
+    let mut spaces = Vec::with_capacity(10);
+    for _ in 0..10 {
+        spaces.push(vec![b' ']);
+    }
+
+    let mut vec2: Vec<u8> = Vec::new();
+    let item = 2;
+    for _ in 5..=20 {
+        vec2.push(item);
+    }
+
+    let mut vec3: Vec<u8> = Vec::new();
+    for _ in 0..15 {
+        let item = 2;
+        vec3.push(item);
+    }
+
+    let mut vec4: Vec<u8> = Vec::new();
+    for _ in 0..15 {
+        vec4.push(13);
+    }
+
+    // Suggestion should not be given as pushed variable can mutate
+    let mut vec5: Vec<u8> = Vec::new();
+    let mut item: u8 = 2;
+    for _ in 0..30 {
+        vec5.push(mutate_increment(&mut item));
+    }
+
+    let mut vec6: Vec<u8> = Vec::new();
+    let mut item: u8 = 2;
+    let mut item2 = &mut mutate_increment(&mut item);
+    for _ in 0..30 {
+        vec6.push(mutate_increment(item2));
+    }
+
+    let mut vec7: Vec<usize> = Vec::new();
+    for (a, b) in [0, 1, 4, 9, 16].iter().enumerate() {
+        vec7.push(a);
+    }
+
+    let mut vec8: Vec<u8> = Vec::new();
+    for i in 0..30 {
+        vec8.push(increment(i));
+    }
+
+    let mut vec9: Vec<u8> = Vec::new();
+    for i in 0..30 {
+        vec9.push(i + i * i);
+    }
+
+    // Suggestion should not be given as there are multiple pushes that are not the same
+    let mut vec10: Vec<u8> = Vec::new();
+    let item: u8 = 2;
+    for _ in 0..30 {
+        vec10.push(item);
+        vec10.push(item * 2);
+    }
+
+    // Suggestion should not be given as Vec is not involved
+    for _ in 0..5 {
+        println!("Same Item Push");
+    }
+
+    struct A {
+        kind: u32,
+    }
+    let mut vec_a: Vec<A> = Vec::new();
+    for i in 0..30 {
+        vec_a.push(A { kind: i });
+    }
+    let mut vec12: Vec<u8> = Vec::new();
+    for a in vec_a {
+        vec12.push(2u8.pow(a.kind));
+    }
+}
diff --git a/src/tools/clippy/tests/ui/same_item_push.stderr b/src/tools/clippy/tests/ui/same_item_push.stderr
new file mode 100644
index 00000000000..ddc5d48cd41
--- /dev/null
+++ b/src/tools/clippy/tests/ui/same_item_push.stderr
@@ -0,0 +1,35 @@
+error: it looks like the same item is being pushed into this Vec
+  --> $DIR/same_item_push.rs:16:9
+   |
+LL |         spaces.push(vec![b' ']);
+   |         ^^^^^^
+   |
+   = note: `-D clippy::same-item-push` implied by `-D warnings`
+   = help: try using vec![vec![b' '];SIZE] or spaces.resize(NEW_SIZE, vec![b' '])
+
+error: it looks like the same item is being pushed into this Vec
+  --> $DIR/same_item_push.rs:22:9
+   |
+LL |         vec2.push(item);
+   |         ^^^^
+   |
+   = help: try using vec![item;SIZE] or vec2.resize(NEW_SIZE, item)
+
+error: it looks like the same item is being pushed into this Vec
+  --> $DIR/same_item_push.rs:28:9
+   |
+LL |         vec3.push(item);
+   |         ^^^^
+   |
+   = help: try using vec![item;SIZE] or vec3.resize(NEW_SIZE, item)
+
+error: it looks like the same item is being pushed into this Vec
+  --> $DIR/same_item_push.rs:33:9
+   |
+LL |         vec4.push(13);
+   |         ^^^^
+   |
+   = help: try using vec![13;SIZE] or vec4.resize(NEW_SIZE, 13)
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/stable_sort_primitive.fixed b/src/tools/clippy/tests/ui/stable_sort_primitive.fixed
new file mode 100644
index 00000000000..8f8f5665931
--- /dev/null
+++ b/src/tools/clippy/tests/ui/stable_sort_primitive.fixed
@@ -0,0 +1,32 @@
+// run-rustfix
+#![warn(clippy::stable_sort_primitive)]
+
+fn main() {
+    // positive examples
+    let mut vec = vec![1, 3, 2];
+    vec.sort_unstable();
+    let mut vec = vec![false, false, true];
+    vec.sort_unstable();
+    let mut vec = vec!['a', 'A', 'c'];
+    vec.sort_unstable();
+    let mut vec = vec!["ab", "cd", "ab", "bc"];
+    vec.sort_unstable();
+    let mut vec = vec![(2, 1), (1, 2), (2, 5)];
+    vec.sort_unstable();
+    let mut vec = vec![[2, 1], [1, 2], [2, 5]];
+    vec.sort_unstable();
+    let mut arr = [1, 3, 2];
+    arr.sort_unstable();
+    // 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));
+    // negative examples - Not of a primitive type
+    let mut vec_of_complex = vec![String::from("hello"), String::from("world!")];
+    vec_of_complex.sort();
+    vec_of_complex.sort_by_key(String::len);
+    let mut vec = vec![(String::from("hello"), String::from("world"))];
+    vec.sort();
+    let mut vec = vec![[String::from("hello"), String::from("world")]];
+    vec.sort();
+}
diff --git a/src/tools/clippy/tests/ui/stable_sort_primitive.rs b/src/tools/clippy/tests/ui/stable_sort_primitive.rs
new file mode 100644
index 00000000000..f9bd9779067
--- /dev/null
+++ b/src/tools/clippy/tests/ui/stable_sort_primitive.rs
@@ -0,0 +1,32 @@
+// run-rustfix
+#![warn(clippy::stable_sort_primitive)]
+
+fn main() {
+    // positive examples
+    let mut vec = vec![1, 3, 2];
+    vec.sort();
+    let mut vec = vec![false, false, true];
+    vec.sort();
+    let mut vec = vec!['a', 'A', 'c'];
+    vec.sort();
+    let mut vec = vec!["ab", "cd", "ab", "bc"];
+    vec.sort();
+    let mut vec = vec![(2, 1), (1, 2), (2, 5)];
+    vec.sort();
+    let mut vec = vec![[2, 1], [1, 2], [2, 5]];
+    vec.sort();
+    let mut arr = [1, 3, 2];
+    arr.sort();
+    // 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));
+    // negative examples - Not of a primitive type
+    let mut vec_of_complex = vec![String::from("hello"), String::from("world!")];
+    vec_of_complex.sort();
+    vec_of_complex.sort_by_key(String::len);
+    let mut vec = vec![(String::from("hello"), String::from("world"))];
+    vec.sort();
+    let mut vec = vec![[String::from("hello"), String::from("world")]];
+    vec.sort();
+}
diff --git a/src/tools/clippy/tests/ui/stable_sort_primitive.stderr b/src/tools/clippy/tests/ui/stable_sort_primitive.stderr
new file mode 100644
index 00000000000..b0b729ede48
--- /dev/null
+++ b/src/tools/clippy/tests/ui/stable_sort_primitive.stderr
@@ -0,0 +1,46 @@
+error: Use sort_unstable instead of sort
+  --> $DIR/stable_sort_primitive.rs:7:5
+   |
+LL |     vec.sort();
+   |     ^^^^^^^^^^ help: try: `vec.sort_unstable()`
+   |
+   = note: `-D clippy::stable-sort-primitive` implied by `-D warnings`
+
+error: Use sort_unstable instead of sort
+  --> $DIR/stable_sort_primitive.rs:9:5
+   |
+LL |     vec.sort();
+   |     ^^^^^^^^^^ help: try: `vec.sort_unstable()`
+
+error: Use sort_unstable instead of sort
+  --> $DIR/stable_sort_primitive.rs:11:5
+   |
+LL |     vec.sort();
+   |     ^^^^^^^^^^ help: try: `vec.sort_unstable()`
+
+error: Use sort_unstable instead of sort
+  --> $DIR/stable_sort_primitive.rs:13:5
+   |
+LL |     vec.sort();
+   |     ^^^^^^^^^^ help: try: `vec.sort_unstable()`
+
+error: Use sort_unstable instead of sort
+  --> $DIR/stable_sort_primitive.rs:15:5
+   |
+LL |     vec.sort();
+   |     ^^^^^^^^^^ help: try: `vec.sort_unstable()`
+
+error: Use sort_unstable instead of sort
+  --> $DIR/stable_sort_primitive.rs:17:5
+   |
+LL |     vec.sort();
+   |     ^^^^^^^^^^ help: try: `vec.sort_unstable()`
+
+error: Use sort_unstable instead of sort
+  --> $DIR/stable_sort_primitive.rs:19:5
+   |
+LL |     arr.sort();
+   |     ^^^^^^^^^^ help: try: `arr.sort_unstable()`
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.rs b/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.rs
index 1f5b9811887..60c2f3ec9b6 100644
--- a/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.rs
+++ b/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.rs
@@ -88,3 +88,33 @@ fn main() {}
 fn do_nothing(x: u32) -> u32 {
     x
 }
+
+struct MultipleBinops(u32);
+
+impl Add for MultipleBinops {
+    type Output = MultipleBinops;
+
+    // OK: multiple Binops in `add` impl
+    fn add(self, other: Self) -> Self::Output {
+        let mut result = self.0 + other.0;
+        if result >= u32::max_value() {
+            result -= u32::max_value();
+        }
+        MultipleBinops(result)
+    }
+}
+
+impl Mul for MultipleBinops {
+    type Output = MultipleBinops;
+
+    // OK: multiple Binops in `mul` impl
+    fn mul(self, other: Self) -> Self::Output {
+        let mut result: u32 = 0;
+        let size = std::cmp::max(self.0, other.0) as usize;
+        let mut v = vec![0; size + 1];
+        for i in 0..size + 1 {
+            result *= i as u32;
+        }
+        MultipleBinops(result)
+    }
+}
diff --git a/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr b/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr
index 7e42d72c30b..23d47e3f1ff 100644
--- a/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr
+++ b/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr
@@ -1,4 +1,4 @@
-error: Suspicious use of binary operator in `Add` impl
+error: suspicious use of binary operator in `Add` impl
   --> $DIR/suspicious_arithmetic_impl.rs:11:20
    |
 LL |         Foo(self.0 - other.0)
@@ -6,7 +6,7 @@ LL |         Foo(self.0 - other.0)
    |
    = note: `-D clippy::suspicious-arithmetic-impl` implied by `-D warnings`
 
-error: Suspicious use of binary operator in `AddAssign` impl
+error: suspicious use of binary operator in `AddAssign` impl
   --> $DIR/suspicious_arithmetic_impl.rs:17:23
    |
 LL |         *self = *self - other;
@@ -14,7 +14,7 @@ LL |         *self = *self - other;
    |
    = note: `#[deny(clippy::suspicious_op_assign_impl)]` on by default
 
-error: Suspicious use of binary operator in `MulAssign` impl
+error: suspicious use of binary operator in `MulAssign` impl
   --> $DIR/suspicious_arithmetic_impl.rs:30:16
    |
 LL |         self.0 /= other.0;
diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs
new file mode 100644
index 00000000000..cb2b0054e35
--- /dev/null
+++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs
@@ -0,0 +1,31 @@
+#![deny(clippy::trait_duplication_in_bounds)]
+
+use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
+
+fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
+where
+    T: Clone,
+    T: Default,
+{
+    unimplemented!();
+}
+
+fn good_bar<T: Clone + Default>(arg: T) {
+    unimplemented!();
+}
+
+fn good_foo<T>(arg: T)
+where
+    T: Clone + Default,
+{
+    unimplemented!();
+}
+
+fn good_foobar<T: Default>(arg: T)
+where
+    T: Clone,
+{
+    unimplemented!();
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr
new file mode 100644
index 00000000000..027e1c75204
--- /dev/null
+++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr
@@ -0,0 +1,23 @@
+error: this trait bound is already specified in the where clause
+  --> $DIR/trait_duplication_in_bounds.rs:5:15
+   |
+LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
+   |               ^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/trait_duplication_in_bounds.rs:1:9
+   |
+LL | #![deny(clippy::trait_duplication_in_bounds)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: consider removing this trait bound
+
+error: this trait bound is already specified in the where clause
+  --> $DIR/trait_duplication_in_bounds.rs:5:23
+   |
+LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
+   |                       ^^^^^^^
+   |
+   = help: consider removing this trait bound
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed
new file mode 100644
index 00000000000..b6f1e83181c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed
@@ -0,0 +1,78 @@
+// run-rustfix
+#![warn(clippy::transmutes_expressible_as_ptr_casts)]
+// These two warnings currrently cover the cases transmutes_expressible_as_ptr_casts
+// would otherwise be responsible for
+#![warn(clippy::useless_transmute)]
+#![warn(clippy::transmute_ptr_to_ptr)]
+#![allow(unused_unsafe)]
+#![allow(dead_code)]
+
+use std::mem::{size_of, transmute};
+
+// rustc_typeck::check::cast contains documentation about when a cast `e as U` is
+// valid, which we quote from below.
+fn main() {
+    // We should see an error message for each transmute, and no error messages for
+    // the casts, since the casts are the recommended fixes.
+
+    // e is an integer and U is *U_0, while U_0: Sized; addr-ptr-cast
+    let _ptr_i32_transmute = unsafe { usize::MAX as *const i32 };
+    let ptr_i32 = usize::MAX as *const i32;
+
+    // e has type *T, U is *U_0, and either U_0: Sized ...
+    let _ptr_i8_transmute = unsafe { ptr_i32 as *const i8 };
+    let _ptr_i8 = ptr_i32 as *const i8;
+
+    let slice_ptr = &[0, 1, 2, 3] as *const [i32];
+
+    // ... or pointer_kind(T) = pointer_kind(U_0); ptr-ptr-cast
+    let _ptr_to_unsized_transmute = unsafe { slice_ptr as *const [u16] };
+    let _ptr_to_unsized = slice_ptr as *const [u16];
+    // TODO: We could try testing vtable casts here too, but maybe
+    // we should wait until std::raw::TraitObject is stabilized?
+
+    // e has type *T and U is a numeric type, while T: Sized; ptr-addr-cast
+    let _usize_from_int_ptr_transmute = unsafe { ptr_i32 as usize };
+    let _usize_from_int_ptr = ptr_i32 as usize;
+
+    let array_ref: &[i32; 4] = &[1, 2, 3, 4];
+
+    // e has type &[T; n] and U is *const T; array-ptr-cast
+    let _array_ptr_transmute = unsafe { array_ref as *const [i32; 4] };
+    let _array_ptr = array_ref as *const [i32; 4];
+
+    fn foo(_: usize) -> u8 {
+        42
+    }
+
+    // e is a function pointer type and U has type *T, while T: Sized; fptr-ptr-cast
+    let _usize_ptr_transmute = unsafe { foo as *const usize };
+    let _usize_ptr_transmute = foo as *const usize;
+
+    // e is a function pointer type and U is an integer; fptr-addr-cast
+    let _usize_from_fn_ptr_transmute = unsafe { foo as usize };
+    let _usize_from_fn_ptr = foo as *const usize;
+}
+
+// If a ref-to-ptr cast of this form where the pointer type points to a type other
+// than the referenced type, calling `CastCheck::do_check` has been observed to
+// cause an ICE error message. `do_check` is currently called inside the
+// `transmutes_expressible_as_ptr_casts` check, but other, more specific lints
+// currently prevent it from being called in these cases. This test is meant to
+// fail if the ordering of the checks ever changes enough to cause these cases to
+// fall through into `do_check`.
+fn trigger_do_check_to_emit_error(in_param: &[i32; 1]) -> *const u8 {
+    unsafe { in_param as *const [i32; 1] as *const u8 }
+}
+
+#[repr(C)]
+struct Single(u64);
+
+#[repr(C)]
+struct Pair(u32, u32);
+
+fn cannot_be_expressed_as_pointer_cast(in_param: Single) -> Pair {
+    assert_eq!(size_of::<Single>(), size_of::<Pair>());
+
+    unsafe { transmute::<Single, Pair>(in_param) }
+}
diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs
new file mode 100644
index 00000000000..0205d1ece60
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs
@@ -0,0 +1,78 @@
+// run-rustfix
+#![warn(clippy::transmutes_expressible_as_ptr_casts)]
+// These two warnings currrently cover the cases transmutes_expressible_as_ptr_casts
+// would otherwise be responsible for
+#![warn(clippy::useless_transmute)]
+#![warn(clippy::transmute_ptr_to_ptr)]
+#![allow(unused_unsafe)]
+#![allow(dead_code)]
+
+use std::mem::{size_of, transmute};
+
+// rustc_typeck::check::cast contains documentation about when a cast `e as U` is
+// valid, which we quote from below.
+fn main() {
+    // We should see an error message for each transmute, and no error messages for
+    // the casts, since the casts are the recommended fixes.
+
+    // e is an integer and U is *U_0, while U_0: Sized; addr-ptr-cast
+    let _ptr_i32_transmute = unsafe { transmute::<usize, *const i32>(usize::MAX) };
+    let ptr_i32 = usize::MAX as *const i32;
+
+    // e has type *T, U is *U_0, and either U_0: Sized ...
+    let _ptr_i8_transmute = unsafe { transmute::<*const i32, *const i8>(ptr_i32) };
+    let _ptr_i8 = ptr_i32 as *const i8;
+
+    let slice_ptr = &[0, 1, 2, 3] as *const [i32];
+
+    // ... or pointer_kind(T) = pointer_kind(U_0); ptr-ptr-cast
+    let _ptr_to_unsized_transmute = unsafe { transmute::<*const [i32], *const [u16]>(slice_ptr) };
+    let _ptr_to_unsized = slice_ptr as *const [u16];
+    // TODO: We could try testing vtable casts here too, but maybe
+    // we should wait until std::raw::TraitObject is stabilized?
+
+    // e has type *T and U is a numeric type, while T: Sized; ptr-addr-cast
+    let _usize_from_int_ptr_transmute = unsafe { transmute::<*const i32, usize>(ptr_i32) };
+    let _usize_from_int_ptr = ptr_i32 as usize;
+
+    let array_ref: &[i32; 4] = &[1, 2, 3, 4];
+
+    // e has type &[T; n] and U is *const T; array-ptr-cast
+    let _array_ptr_transmute = unsafe { transmute::<&[i32; 4], *const [i32; 4]>(array_ref) };
+    let _array_ptr = array_ref as *const [i32; 4];
+
+    fn foo(_: usize) -> u8 {
+        42
+    }
+
+    // e is a function pointer type and U has type *T, while T: Sized; fptr-ptr-cast
+    let _usize_ptr_transmute = unsafe { transmute::<fn(usize) -> u8, *const usize>(foo) };
+    let _usize_ptr_transmute = foo as *const usize;
+
+    // e is a function pointer type and U is an integer; fptr-addr-cast
+    let _usize_from_fn_ptr_transmute = unsafe { transmute::<fn(usize) -> u8, usize>(foo) };
+    let _usize_from_fn_ptr = foo as *const usize;
+}
+
+// If a ref-to-ptr cast of this form where the pointer type points to a type other
+// than the referenced type, calling `CastCheck::do_check` has been observed to
+// cause an ICE error message. `do_check` is currently called inside the
+// `transmutes_expressible_as_ptr_casts` check, but other, more specific lints
+// currently prevent it from being called in these cases. This test is meant to
+// fail if the ordering of the checks ever changes enough to cause these cases to
+// fall through into `do_check`.
+fn trigger_do_check_to_emit_error(in_param: &[i32; 1]) -> *const u8 {
+    unsafe { transmute::<&[i32; 1], *const u8>(in_param) }
+}
+
+#[repr(C)]
+struct Single(u64);
+
+#[repr(C)]
+struct Pair(u32, u32);
+
+fn cannot_be_expressed_as_pointer_cast(in_param: Single) -> Pair {
+    assert_eq!(size_of::<Single>(), size_of::<Pair>());
+
+    unsafe { transmute::<Single, Pair>(in_param) }
+}
diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr
new file mode 100644
index 00000000000..1157b179317
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr
@@ -0,0 +1,56 @@
+error: transmute from an integer to a pointer
+  --> $DIR/transmutes_expressible_as_ptr_casts.rs:19:39
+   |
+LL |     let _ptr_i32_transmute = unsafe { transmute::<usize, *const i32>(usize::MAX) };
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `usize::MAX as *const i32`
+   |
+   = note: `-D clippy::useless-transmute` implied by `-D warnings`
+
+error: transmute from a pointer to a pointer
+  --> $DIR/transmutes_expressible_as_ptr_casts.rs:23:38
+   |
+LL |     let _ptr_i8_transmute = unsafe { transmute::<*const i32, *const i8>(ptr_i32) };
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr_i32 as *const i8`
+   |
+   = note: `-D clippy::transmute-ptr-to-ptr` implied by `-D warnings`
+
+error: transmute from a pointer to a pointer
+  --> $DIR/transmutes_expressible_as_ptr_casts.rs:29:46
+   |
+LL |     let _ptr_to_unsized_transmute = unsafe { transmute::<*const [i32], *const [u16]>(slice_ptr) };
+   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `slice_ptr as *const [u16]`
+
+error: transmute from `*const i32` to `usize` which could be expressed as a pointer cast instead
+  --> $DIR/transmutes_expressible_as_ptr_casts.rs:35:50
+   |
+LL |     let _usize_from_int_ptr_transmute = unsafe { transmute::<*const i32, usize>(ptr_i32) };
+   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr_i32 as usize`
+   |
+   = note: `-D clippy::transmutes-expressible-as-ptr-casts` implied by `-D warnings`
+
+error: transmute from a reference to a pointer
+  --> $DIR/transmutes_expressible_as_ptr_casts.rs:41:41
+   |
+LL |     let _array_ptr_transmute = unsafe { transmute::<&[i32; 4], *const [i32; 4]>(array_ref) };
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `array_ref as *const [i32; 4]`
+
+error: transmute from `fn(usize) -> u8 {main::foo}` to `*const usize` which could be expressed as a pointer cast instead
+  --> $DIR/transmutes_expressible_as_ptr_casts.rs:49:41
+   |
+LL |     let _usize_ptr_transmute = unsafe { transmute::<fn(usize) -> u8, *const usize>(foo) };
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `foo as *const usize`
+
+error: transmute from `fn(usize) -> u8 {main::foo}` to `usize` which could be expressed as a pointer cast instead
+  --> $DIR/transmutes_expressible_as_ptr_casts.rs:53:49
+   |
+LL |     let _usize_from_fn_ptr_transmute = unsafe { transmute::<fn(usize) -> u8, usize>(foo) };
+   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `foo as usize`
+
+error: transmute from a reference to a pointer
+  --> $DIR/transmutes_expressible_as_ptr_casts.rs:65:14
+   |
+LL |     unsafe { transmute::<&[i32; 1], *const u8>(in_param) }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `in_param as *const [i32; 1] as *const u8`
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/try_err.fixed b/src/tools/clippy/tests/ui/try_err.fixed
index 29d9139d3e3..9e77dcd8731 100644
--- a/src/tools/clippy/tests/ui/try_err.fixed
+++ b/src/tools/clippy/tests/ui/try_err.fixed
@@ -6,6 +6,9 @@
 #[macro_use]
 extern crate macro_rules;
 
+use std::io;
+use std::task::Poll;
+
 // Tests that a simple case works
 // Should flag `Err(err)?`
 pub fn basic_test() -> Result<i32, i32> {
@@ -104,3 +107,21 @@ pub fn macro_inside(fail: bool) -> Result<i32, String> {
     }
     Ok(0)
 }
+
+pub fn poll_write(n: usize) -> Poll<io::Result<usize>> {
+    if n == 0 {
+        return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))
+    } else if n == 1 {
+        return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))
+    };
+
+    Poll::Ready(Ok(n))
+}
+
+pub fn poll_next(ready: bool) -> Poll<Option<io::Result<()>>> {
+    if !ready {
+        return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))
+    }
+
+    Poll::Ready(None)
+}
diff --git a/src/tools/clippy/tests/ui/try_err.rs b/src/tools/clippy/tests/ui/try_err.rs
index 5e85d091a2a..41bcb0a189e 100644
--- a/src/tools/clippy/tests/ui/try_err.rs
+++ b/src/tools/clippy/tests/ui/try_err.rs
@@ -6,6 +6,9 @@
 #[macro_use]
 extern crate macro_rules;
 
+use std::io;
+use std::task::Poll;
+
 // Tests that a simple case works
 // Should flag `Err(err)?`
 pub fn basic_test() -> Result<i32, i32> {
@@ -104,3 +107,21 @@ pub fn macro_inside(fail: bool) -> Result<i32, String> {
     }
     Ok(0)
 }
+
+pub fn poll_write(n: usize) -> Poll<io::Result<usize>> {
+    if n == 0 {
+        Err(io::ErrorKind::WriteZero)?
+    } else if n == 1 {
+        Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))?
+    };
+
+    Poll::Ready(Ok(n))
+}
+
+pub fn poll_next(ready: bool) -> Poll<Option<io::Result<()>>> {
+    if !ready {
+        Err(io::ErrorKind::NotFound)?
+    }
+
+    Poll::Ready(None)
+}
diff --git a/src/tools/clippy/tests/ui/try_err.stderr b/src/tools/clippy/tests/ui/try_err.stderr
index 21e9d4048a5..3f1cbc17e72 100644
--- a/src/tools/clippy/tests/ui/try_err.stderr
+++ b/src/tools/clippy/tests/ui/try_err.stderr
@@ -1,5 +1,5 @@
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:15:9
+  --> $DIR/try_err.rs:18:9
    |
 LL |         Err(err)?;
    |         ^^^^^^^^^ help: try this: `return Err(err)`
@@ -11,28 +11,46 @@ LL | #![deny(clippy::try_err)]
    |         ^^^^^^^^^^^^^^^
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:25:9
+  --> $DIR/try_err.rs:28:9
    |
 LL |         Err(err)?;
    |         ^^^^^^^^^ help: try this: `return Err(err.into())`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:45:17
+  --> $DIR/try_err.rs:48:17
    |
 LL |                 Err(err)?;
    |                 ^^^^^^^^^ help: try this: `return Err(err)`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:64:17
+  --> $DIR/try_err.rs:67:17
    |
 LL |                 Err(err)?;
    |                 ^^^^^^^^^ help: try this: `return Err(err.into())`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:103:9
+  --> $DIR/try_err.rs:106:9
    |
 LL |         Err(foo!())?;
    |         ^^^^^^^^^^^^ help: try this: `return Err(foo!())`
 
-error: aborting due to 5 previous errors
+error: returning an `Err(_)` with the `?` operator
+  --> $DIR/try_err.rs:113:9
+   |
+LL |         Err(io::ErrorKind::WriteZero)?
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))`
+
+error: returning an `Err(_)` with the `?` operator
+  --> $DIR/try_err.rs:115:9
+   |
+LL |         Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))?
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))`
+
+error: returning an `Err(_)` with the `?` operator
+  --> $DIR/try_err.rs:123:9
+   |
+LL |         Err(io::ErrorKind::NotFound)?
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))`
+
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unknown_attribute.stderr b/src/tools/clippy/tests/ui/unknown_attribute.stderr
index 47e37aed246..618c5980d64 100644
--- a/src/tools/clippy/tests/ui/unknown_attribute.stderr
+++ b/src/tools/clippy/tests/ui/unknown_attribute.stderr
@@ -1,4 +1,4 @@
-error: Usage of unknown attribute
+error: usage of unknown attribute
   --> $DIR/unknown_attribute.rs:1:11
    |
 LL | #[clippy::unknown]
diff --git a/src/tools/clippy/tests/ui/unnecessary_ref.stderr b/src/tools/clippy/tests/ui/unnecessary_ref.stderr
index 34ba167a947..d0a0f219097 100644
--- a/src/tools/clippy/tests/ui/unnecessary_ref.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_ref.stderr
@@ -1,4 +1,4 @@
-error: Creating a reference that is immediately dereferenced.
+error: creating a reference that is immediately dereferenced
   --> $DIR/unnecessary_ref.rs:13:17
    |
 LL |     let inner = (&outer).inner;
diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed b/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed
index c017d1cf9a4..31c2ba0f9c5 100644
--- a/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed
@@ -1,5 +1,7 @@
 // run-rustfix
 
+#![allow(clippy::stable_sort_primitive)]
+
 use std::cmp::Reverse;
 
 fn unnecessary_sort_by() {
diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.rs b/src/tools/clippy/tests/ui/unnecessary_sort_by.rs
index 1929c72b2f2..a3c8ae468ed 100644
--- a/src/tools/clippy/tests/ui/unnecessary_sort_by.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.rs
@@ -1,5 +1,7 @@
 // run-rustfix
 
+#![allow(clippy::stable_sort_primitive)]
+
 use std::cmp::Reverse;
 
 fn unnecessary_sort_by() {
diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr b/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr
index 903b6e5099c..70c6cf0a3b6 100644
--- a/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr
@@ -1,5 +1,5 @@
 error: use Vec::sort here instead
-  --> $DIR/unnecessary_sort_by.rs:12:5
+  --> $DIR/unnecessary_sort_by.rs:14:5
    |
 LL |     vec.sort_by(|a, b| a.cmp(b));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort()`
@@ -7,37 +7,37 @@ LL |     vec.sort_by(|a, b| a.cmp(b));
    = note: `-D clippy::unnecessary-sort-by` implied by `-D warnings`
 
 error: use Vec::sort here instead
-  --> $DIR/unnecessary_sort_by.rs:13:5
+  --> $DIR/unnecessary_sort_by.rs:15:5
    |
 LL |     vec.sort_unstable_by(|a, b| a.cmp(b));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable()`
 
 error: use Vec::sort_by_key here instead
-  --> $DIR/unnecessary_sort_by.rs:14:5
+  --> $DIR/unnecessary_sort_by.rs:16:5
    |
 LL |     vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs()));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&a| (a + 5).abs())`
 
 error: use Vec::sort_by_key here instead
-  --> $DIR/unnecessary_sort_by.rs:15:5
+  --> $DIR/unnecessary_sort_by.rs:17:5
    |
 LL |     vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b)));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|&a| id(-a))`
 
 error: use Vec::sort_by_key here instead
-  --> $DIR/unnecessary_sort_by.rs:17:5
+  --> $DIR/unnecessary_sort_by.rs:19:5
    |
 LL |     vec.sort_by(|a, b| b.cmp(a));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse(b))`
 
 error: use Vec::sort_by_key here instead
-  --> $DIR/unnecessary_sort_by.rs:18:5
+  --> $DIR/unnecessary_sort_by.rs:20:5
    |
 LL |     vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs()));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse((b + 5).abs()))`
 
 error: use Vec::sort_by_key here instead
-  --> $DIR/unnecessary_sort_by.rs:19:5
+  --> $DIR/unnecessary_sort_by.rs:21:5
    |
 LL |     vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a)));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|&b| Reverse(id(-b)))`
diff --git a/src/tools/clippy/tests/ui/unneeded_field_pattern.stderr b/src/tools/clippy/tests/ui/unneeded_field_pattern.stderr
index e7b92ce1e19..b8d3c294532 100644
--- a/src/tools/clippy/tests/ui/unneeded_field_pattern.stderr
+++ b/src/tools/clippy/tests/ui/unneeded_field_pattern.stderr
@@ -1,19 +1,19 @@
-error: You matched a field with a wildcard pattern. Consider using `..` instead
+error: you matched a field with a wildcard pattern, consider using `..` instead
   --> $DIR/unneeded_field_pattern.rs:14:15
    |
 LL |         Foo { a: _, b: 0, .. } => {},
    |               ^^^^
    |
    = note: `-D clippy::unneeded-field-pattern` implied by `-D warnings`
-   = help: Try with `Foo { b: 0, .. }`
+   = help: try with `Foo { b: 0, .. }`
 
-error: All the struct fields are matched to a wildcard pattern, consider using `..`.
+error: all the struct fields are matched to a wildcard pattern, consider using `..`
   --> $DIR/unneeded_field_pattern.rs:16:9
    |
 LL |         Foo { a: _, b: _, c: _ } => {},
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: Try with `Foo { .. }` instead
+   = help: try with `Foo { .. }` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs
index 7bee9c499e1..690d705573d 100644
--- a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs
+++ b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs
@@ -57,4 +57,14 @@ impl E {
 #[derive(Deserialize)]
 pub struct F {}
 
+// Check that we honor the `allow` attribute on the ADT
+#[allow(clippy::unsafe_derive_deserialize)]
+#[derive(Deserialize)]
+pub struct G {}
+impl G {
+    pub fn unsafe_block(&self) {
+        unsafe {}
+    }
+}
+
 fn main() {}
diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py
index 55e2d7cf827..72b3df8377a 100755
--- a/src/tools/publish_toolstate.py
+++ b/src/tools/publish_toolstate.py
@@ -31,10 +31,7 @@ MAINTAINERS = {
     'nomicon': {'frewsxcv', 'Gankra'},
     'reference': {'steveklabnik', 'Havvy', 'matthewjasper', 'ehuss'},
     'rust-by-example': {'steveklabnik', 'marioidival'},
-    'embedded-book': {
-        'adamgreig', 'andre-richter', 'jamesmunns', 'korken89',
-        'ryankurte', 'thejpster', 'therealprof',
-    },
+    'embedded-book': {'adamgreig', 'andre-richter', 'jamesmunns', 'therealprof'},
     'edition-guide': {'ehuss', 'steveklabnik'},
     'rustc-dev-guide': {'mark-i-m', 'spastorino', 'amanjeev', 'JohnTitor'},
 }
diff --git a/src/tools/rls b/src/tools/rls
-Subproject a0e80a9783b1485fe8935d5de4dec34fe6bb5f1
+Subproject 942aa2b5d729a63f8b81592ab7b2720b63a884e
diff --git a/src/tools/rustfmt b/src/tools/rustfmt
-Subproject cef1c0d5ebde015d72d830e655ca1b4079a0849
+Subproject 48f6c32ec1dd370f3157a27b48a000fd8c1185a
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index 9c27a8a6f88..bce3cf06b07 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -263,7 +263,7 @@ pub fn check(path: &Path, bad: &mut bool) {
                     suppressible_tidy_err!(err, skip_undocumented_unsafe, "undocumented unsafe");
                 }
             }
-            if line.contains("// SAFETY: ") || line.contains("// Safety: ") {
+            if line.contains("// SAFETY:") || line.contains("// Safety:") {
                 last_safety_comment = true;
             } else if line.trim().starts_with("//") || line.trim().is_empty() {
                 // keep previous value